]>
Commit | Line | Data |
---|---|---|
83510766 SG |
1 | /* |
2 | * Copyright (c) 2015 Google, Inc | |
3 | * (C) Copyright 2001-2015 | |
4 | * DENX Software Engineering -- wd@denx.de | |
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 | ||
58c733a7 SG |
50 | static int vidconsole_entry_start(struct udevice *dev) |
51 | { | |
52 | struct vidconsole_ops *ops = vidconsole_get_ops(dev); | |
53 | ||
54 | if (!ops->entry_start) | |
55 | return -ENOSYS; | |
56 | return ops->entry_start(dev); | |
57 | } | |
58 | ||
83510766 | 59 | /* Move backwards one space */ |
7b9f7e44 | 60 | static int vidconsole_back(struct udevice *dev) |
83510766 SG |
61 | { |
62 | struct vidconsole_priv *priv = dev_get_uclass_priv(dev); | |
7b9f7e44 SG |
63 | struct vidconsole_ops *ops = vidconsole_get_ops(dev); |
64 | int ret; | |
65 | ||
66 | if (ops->backspace) { | |
67 | ret = ops->backspace(dev); | |
68 | if (ret != -ENOSYS) | |
69 | return ret; | |
70 | } | |
83510766 | 71 | |
f2661786 | 72 | priv->xcur_frac -= VID_TO_POS(priv->x_charsize); |
c5b77d01 | 73 | if (priv->xcur_frac < priv->xstart_frac) { |
f2661786 SG |
74 | priv->xcur_frac = (priv->cols - 1) * |
75 | VID_TO_POS(priv->x_charsize); | |
76 | priv->ycur -= priv->y_charsize; | |
77 | if (priv->ycur < 0) | |
78 | priv->ycur = 0; | |
83510766 | 79 | } |
7b9f7e44 SG |
80 | |
81 | return 0; | |
83510766 SG |
82 | } |
83 | ||
84 | /* Move to a newline, scrolling the display if necessary */ | |
85 | static void vidconsole_newline(struct udevice *dev) | |
86 | { | |
87 | struct vidconsole_priv *priv = dev_get_uclass_priv(dev); | |
88 | struct udevice *vid_dev = dev->parent; | |
89 | struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); | |
90 | const int rows = CONFIG_CONSOLE_SCROLL_LINES; | |
91 | int i; | |
92 | ||
c5b77d01 | 93 | priv->xcur_frac = priv->xstart_frac; |
f2661786 | 94 | priv->ycur += priv->y_charsize; |
83510766 SG |
95 | |
96 | /* Check if we need to scroll the terminal */ | |
f2661786 | 97 | if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) { |
83510766 SG |
98 | vidconsole_move_rows(dev, 0, rows, priv->rows - rows); |
99 | for (i = 0; i < rows; i++) | |
100 | vidconsole_set_row(dev, priv->rows - i - 1, | |
101 | vid_priv->colour_bg); | |
f2661786 | 102 | priv->ycur -= rows * priv->y_charsize; |
83510766 | 103 | } |
58c733a7 SG |
104 | priv->last_ch = 0; |
105 | ||
83510766 SG |
106 | video_sync(dev->parent); |
107 | } | |
108 | ||
109 | int vidconsole_put_char(struct udevice *dev, char ch) | |
110 | { | |
111 | struct vidconsole_priv *priv = dev_get_uclass_priv(dev); | |
112 | int ret; | |
113 | ||
114 | switch (ch) { | |
5508f10a SG |
115 | case '\a': |
116 | /* beep */ | |
117 | break; | |
83510766 | 118 | case '\r': |
c5b77d01 | 119 | priv->xcur_frac = priv->xstart_frac; |
83510766 SG |
120 | break; |
121 | case '\n': | |
122 | vidconsole_newline(dev); | |
58c733a7 | 123 | vidconsole_entry_start(dev); |
83510766 SG |
124 | break; |
125 | case '\t': /* Tab (8 chars alignment) */ | |
f2661786 SG |
126 | priv->xcur_frac = ((priv->xcur_frac / priv->tab_width_frac) |
127 | + 1) * priv->tab_width_frac; | |
83510766 | 128 | |
f2661786 | 129 | if (priv->xcur_frac >= priv->xsize_frac) |
83510766 SG |
130 | vidconsole_newline(dev); |
131 | break; | |
132 | case '\b': | |
133 | vidconsole_back(dev); | |
58c733a7 | 134 | priv->last_ch = 0; |
83510766 SG |
135 | break; |
136 | default: | |
137 | /* | |
138 | * Failure of this function normally indicates an unsupported | |
139 | * colour depth. Check this and return an error to help with | |
140 | * diagnosis. | |
141 | */ | |
f2661786 SG |
142 | ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch); |
143 | if (ret == -EAGAIN) { | |
144 | vidconsole_newline(dev); | |
145 | ret = vidconsole_putc_xy(dev, priv->xcur_frac, | |
146 | priv->ycur, ch); | |
147 | } | |
148 | if (ret < 0) | |
83510766 | 149 | return ret; |
f2661786 | 150 | priv->xcur_frac += ret; |
58c733a7 | 151 | priv->last_ch = ch; |
f2661786 | 152 | if (priv->xcur_frac >= priv->xsize_frac) |
83510766 SG |
153 | vidconsole_newline(dev); |
154 | break; | |
155 | } | |
156 | ||
157 | return 0; | |
158 | } | |
159 | ||
160 | static void vidconsole_putc(struct stdio_dev *sdev, const char ch) | |
161 | { | |
162 | struct udevice *dev = sdev->priv; | |
163 | ||
164 | vidconsole_put_char(dev, ch); | |
165 | } | |
166 | ||
167 | static void vidconsole_puts(struct stdio_dev *sdev, const char *s) | |
168 | { | |
169 | struct udevice *dev = sdev->priv; | |
170 | ||
171 | while (*s) | |
172 | vidconsole_put_char(dev, *s++); | |
bbc8a8b4 | 173 | video_sync(dev->parent); |
83510766 SG |
174 | } |
175 | ||
176 | /* Set up the number of rows and colours (rotated drivers override this) */ | |
177 | static int vidconsole_pre_probe(struct udevice *dev) | |
178 | { | |
179 | struct vidconsole_priv *priv = dev_get_uclass_priv(dev); | |
180 | struct udevice *vid = dev->parent; | |
181 | struct video_priv *vid_priv = dev_get_uclass_priv(vid); | |
182 | ||
f2661786 | 183 | priv->xsize_frac = VID_TO_POS(vid_priv->xsize); |
83510766 SG |
184 | |
185 | return 0; | |
186 | } | |
187 | ||
188 | /* Register the device with stdio */ | |
189 | static int vidconsole_post_probe(struct udevice *dev) | |
190 | { | |
191 | struct vidconsole_priv *priv = dev_get_uclass_priv(dev); | |
192 | struct stdio_dev *sdev = &priv->sdev; | |
193 | int ret; | |
194 | ||
f2661786 SG |
195 | if (!priv->tab_width_frac) |
196 | priv->tab_width_frac = VID_TO_POS(priv->x_charsize) * 8; | |
197 | ||
f1a1247d SG |
198 | if (dev->seq) { |
199 | snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d", | |
200 | dev->seq); | |
201 | } else { | |
202 | strcpy(sdev->name, "vidconsole"); | |
203 | } | |
f2661786 | 204 | |
83510766 SG |
205 | sdev->flags = DEV_FLAGS_OUTPUT; |
206 | sdev->putc = vidconsole_putc; | |
207 | sdev->puts = vidconsole_puts; | |
208 | sdev->priv = dev; | |
209 | ret = stdio_register(sdev); | |
210 | if (ret) | |
211 | return ret; | |
212 | ||
213 | return 0; | |
214 | } | |
215 | ||
216 | UCLASS_DRIVER(vidconsole) = { | |
217 | .id = UCLASS_VIDEO_CONSOLE, | |
218 | .name = "vidconsole0", | |
219 | .pre_probe = vidconsole_pre_probe, | |
220 | .post_probe = vidconsole_post_probe, | |
221 | .per_device_auto_alloc_size = sizeof(struct vidconsole_priv), | |
222 | }; | |
223 | ||
224 | void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row) | |
225 | { | |
226 | struct vidconsole_priv *priv = dev_get_uclass_priv(dev); | |
f2661786 SG |
227 | struct udevice *vid_dev = dev->parent; |
228 | struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); | |
83510766 | 229 | |
f2661786 SG |
230 | priv->xcur_frac = VID_TO_POS(min_t(short, col, vid_priv->xsize - 1)); |
231 | priv->ycur = min_t(short, row, vid_priv->ysize - 1); | |
83510766 SG |
232 | } |
233 | ||
234 | static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc, | |
235 | char *const argv[]) | |
236 | { | |
237 | unsigned int col, row; | |
238 | struct udevice *dev; | |
239 | ||
240 | if (argc != 3) | |
241 | return CMD_RET_USAGE; | |
242 | ||
243 | uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev); | |
244 | if (!dev) | |
245 | return CMD_RET_FAILURE; | |
246 | col = simple_strtoul(argv[1], NULL, 10); | |
247 | row = simple_strtoul(argv[2], NULL, 10); | |
248 | vidconsole_position_cursor(dev, col, row); | |
249 | ||
250 | return 0; | |
251 | } | |
252 | ||
253 | static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc, | |
254 | char *const argv[]) | |
255 | { | |
256 | struct udevice *dev; | |
257 | const char *s; | |
258 | ||
259 | if (argc != 2) | |
260 | return CMD_RET_USAGE; | |
261 | ||
262 | uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev); | |
263 | if (!dev) | |
264 | return CMD_RET_FAILURE; | |
265 | for (s = argv[1]; *s; s++) | |
266 | vidconsole_put_char(dev, *s); | |
267 | ||
268 | return 0; | |
269 | } | |
270 | ||
271 | U_BOOT_CMD( | |
272 | setcurs, 3, 1, do_video_setcursor, | |
273 | "set cursor position within screen", | |
274 | " <col> <row> in character" | |
275 | ); | |
276 | ||
277 | U_BOOT_CMD( | |
278 | lcdputs, 2, 1, do_video_puts, | |
279 | "print string on video framebuffer", | |
280 | " <string>" | |
281 | ); |