]>
Commit | Line | Data |
---|---|---|
83510766 SG |
1 | /* |
2 | * Copyright (c) 2015 Google, Inc | |
3 | * (C) Copyright 2001-2015 | |
4 | * DENX Software Engineering -- [email protected] | |
5 | * Compulab Ltd - http://compulab.co.il/ | |
6 | * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com | |
7 | * | |
8 | * SPDX-License-Identifier: GPL-2.0+ | |
9 | */ | |
10 | ||
11 | #include <common.h> | |
12 | #include <dm.h> | |
13 | #include <video.h> | |
14 | #include <video_console.h> | |
15 | #include <video_font.h> /* Get font data, width and height */ | |
16 | ||
17 | /* By default we scroll by a single line */ | |
18 | #ifndef CONFIG_CONSOLE_SCROLL_LINES | |
19 | #define CONFIG_CONSOLE_SCROLL_LINES 1 | |
20 | #endif | |
21 | ||
22 | int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char ch) | |
23 | { | |
24 | struct vidconsole_ops *ops = vidconsole_get_ops(dev); | |
25 | ||
26 | if (!ops->putc_xy) | |
27 | return -ENOSYS; | |
28 | return ops->putc_xy(dev, x, y, ch); | |
29 | } | |
30 | ||
31 | int vidconsole_move_rows(struct udevice *dev, uint rowdst, uint rowsrc, | |
32 | uint count) | |
33 | { | |
34 | struct vidconsole_ops *ops = vidconsole_get_ops(dev); | |
35 | ||
36 | if (!ops->move_rows) | |
37 | return -ENOSYS; | |
38 | return ops->move_rows(dev, rowdst, rowsrc, count); | |
39 | } | |
40 | ||
41 | int vidconsole_set_row(struct udevice *dev, uint row, int clr) | |
42 | { | |
43 | struct vidconsole_ops *ops = vidconsole_get_ops(dev); | |
44 | ||
45 | if (!ops->set_row) | |
46 | return -ENOSYS; | |
47 | return ops->set_row(dev, row, clr); | |
48 | } | |
49 | ||
50 | /* Move backwards one space */ | |
51 | static void vidconsole_back(struct udevice *dev) | |
52 | { | |
53 | struct vidconsole_priv *priv = dev_get_uclass_priv(dev); | |
54 | ||
55 | if (--priv->curr_col < 0) { | |
56 | priv->curr_col = priv->cols - 1; | |
57 | if (--priv->curr_row < 0) | |
58 | priv->curr_row = 0; | |
59 | } | |
60 | ||
61 | vidconsole_putc_xy(dev, priv->curr_col * VIDEO_FONT_WIDTH, | |
62 | priv->curr_row * VIDEO_FONT_HEIGHT, ' '); | |
63 | } | |
64 | ||
65 | /* Move to a newline, scrolling the display if necessary */ | |
66 | static void vidconsole_newline(struct udevice *dev) | |
67 | { | |
68 | struct vidconsole_priv *priv = dev_get_uclass_priv(dev); | |
69 | struct udevice *vid_dev = dev->parent; | |
70 | struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); | |
71 | const int rows = CONFIG_CONSOLE_SCROLL_LINES; | |
72 | int i; | |
73 | ||
74 | priv->curr_col = 0; | |
75 | ||
76 | /* Check if we need to scroll the terminal */ | |
77 | if (++priv->curr_row >= priv->rows) { | |
78 | vidconsole_move_rows(dev, 0, rows, priv->rows - rows); | |
79 | for (i = 0; i < rows; i++) | |
80 | vidconsole_set_row(dev, priv->rows - i - 1, | |
81 | vid_priv->colour_bg); | |
82 | priv->curr_row -= rows; | |
83 | } | |
84 | video_sync(dev->parent); | |
85 | } | |
86 | ||
87 | int vidconsole_put_char(struct udevice *dev, char ch) | |
88 | { | |
89 | struct vidconsole_priv *priv = dev_get_uclass_priv(dev); | |
90 | int ret; | |
91 | ||
92 | switch (ch) { | |
93 | case '\r': | |
94 | priv->curr_col = 0; | |
95 | break; | |
96 | case '\n': | |
97 | vidconsole_newline(dev); | |
98 | break; | |
99 | case '\t': /* Tab (8 chars alignment) */ | |
100 | priv->curr_col += 8; | |
101 | priv->curr_col &= ~7; | |
102 | ||
103 | if (priv->curr_col >= priv->cols) | |
104 | vidconsole_newline(dev); | |
105 | break; | |
106 | case '\b': | |
107 | vidconsole_back(dev); | |
108 | break; | |
109 | default: | |
110 | /* | |
111 | * Failure of this function normally indicates an unsupported | |
112 | * colour depth. Check this and return an error to help with | |
113 | * diagnosis. | |
114 | */ | |
115 | ret = vidconsole_putc_xy(dev, | |
116 | priv->curr_col * VIDEO_FONT_WIDTH, | |
117 | priv->curr_row * VIDEO_FONT_HEIGHT, | |
118 | ch); | |
119 | if (ret) | |
120 | return ret; | |
121 | if (++priv->curr_col >= priv->cols) | |
122 | vidconsole_newline(dev); | |
123 | break; | |
124 | } | |
125 | ||
126 | return 0; | |
127 | } | |
128 | ||
129 | static void vidconsole_putc(struct stdio_dev *sdev, const char ch) | |
130 | { | |
131 | struct udevice *dev = sdev->priv; | |
132 | ||
133 | vidconsole_put_char(dev, ch); | |
134 | } | |
135 | ||
136 | static void vidconsole_puts(struct stdio_dev *sdev, const char *s) | |
137 | { | |
138 | struct udevice *dev = sdev->priv; | |
139 | ||
140 | while (*s) | |
141 | vidconsole_put_char(dev, *s++); | |
142 | } | |
143 | ||
144 | /* Set up the number of rows and colours (rotated drivers override this) */ | |
145 | static int vidconsole_pre_probe(struct udevice *dev) | |
146 | { | |
147 | struct vidconsole_priv *priv = dev_get_uclass_priv(dev); | |
148 | struct udevice *vid = dev->parent; | |
149 | struct video_priv *vid_priv = dev_get_uclass_priv(vid); | |
150 | ||
151 | priv->rows = vid_priv->ysize / VIDEO_FONT_HEIGHT; | |
152 | priv->cols = vid_priv->xsize / VIDEO_FONT_WIDTH; | |
153 | ||
154 | return 0; | |
155 | } | |
156 | ||
157 | /* Register the device with stdio */ | |
158 | static int vidconsole_post_probe(struct udevice *dev) | |
159 | { | |
160 | struct vidconsole_priv *priv = dev_get_uclass_priv(dev); | |
161 | struct stdio_dev *sdev = &priv->sdev; | |
162 | int ret; | |
163 | ||
f1a1247d SG |
164 | if (dev->seq) { |
165 | snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d", | |
166 | dev->seq); | |
167 | } else { | |
168 | strcpy(sdev->name, "vidconsole"); | |
169 | } | |
83510766 SG |
170 | sdev->flags = DEV_FLAGS_OUTPUT; |
171 | sdev->putc = vidconsole_putc; | |
172 | sdev->puts = vidconsole_puts; | |
173 | sdev->priv = dev; | |
174 | ret = stdio_register(sdev); | |
175 | if (ret) | |
176 | return ret; | |
177 | ||
178 | return 0; | |
179 | } | |
180 | ||
181 | UCLASS_DRIVER(vidconsole) = { | |
182 | .id = UCLASS_VIDEO_CONSOLE, | |
183 | .name = "vidconsole0", | |
184 | .pre_probe = vidconsole_pre_probe, | |
185 | .post_probe = vidconsole_post_probe, | |
186 | .per_device_auto_alloc_size = sizeof(struct vidconsole_priv), | |
187 | }; | |
188 | ||
189 | void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row) | |
190 | { | |
191 | struct vidconsole_priv *priv = dev_get_uclass_priv(dev); | |
192 | ||
193 | priv->curr_col = min_t(short, col, priv->cols - 1); | |
194 | priv->curr_row = min_t(short, row, priv->rows - 1); | |
195 | } | |
196 | ||
197 | static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc, | |
198 | char *const argv[]) | |
199 | { | |
200 | unsigned int col, row; | |
201 | struct udevice *dev; | |
202 | ||
203 | if (argc != 3) | |
204 | return CMD_RET_USAGE; | |
205 | ||
206 | uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev); | |
207 | if (!dev) | |
208 | return CMD_RET_FAILURE; | |
209 | col = simple_strtoul(argv[1], NULL, 10); | |
210 | row = simple_strtoul(argv[2], NULL, 10); | |
211 | vidconsole_position_cursor(dev, col, row); | |
212 | ||
213 | return 0; | |
214 | } | |
215 | ||
216 | static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc, | |
217 | char *const argv[]) | |
218 | { | |
219 | struct udevice *dev; | |
220 | const char *s; | |
221 | ||
222 | if (argc != 2) | |
223 | return CMD_RET_USAGE; | |
224 | ||
225 | uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev); | |
226 | if (!dev) | |
227 | return CMD_RET_FAILURE; | |
228 | for (s = argv[1]; *s; s++) | |
229 | vidconsole_put_char(dev, *s); | |
230 | ||
231 | return 0; | |
232 | } | |
233 | ||
234 | U_BOOT_CMD( | |
235 | setcurs, 3, 1, do_video_setcursor, | |
236 | "set cursor position within screen", | |
237 | " <col> <row> in character" | |
238 | ); | |
239 | ||
240 | U_BOOT_CMD( | |
241 | lcdputs, 2, 1, do_video_puts, | |
242 | "print string on video framebuffer", | |
243 | " <string>" | |
244 | ); |