blob: 80e7adf6a1a4fd42ec00e56fd1254ece1382e42d [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass84c7fb32016-01-18 19:52:17 -07002/*
3 * Copyright (c) 2015 Google, Inc
4 * (C) Copyright 2001-2015
5 * DENX Software Engineering -- wd@denx.de
6 * Compulab Ltd - http://compulab.co.il/
7 * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
Simon Glass84c7fb32016-01-18 19:52:17 -07008 */
9
Patrick Delaunay81313352021-04-27 11:02:19 +020010#define LOG_CATEGORY UCLASS_VIDEO_CONSOLE
11
Simon Glass34b5c252023-10-01 19:13:19 -060012#include <abuf.h>
Janne Grunau5548c362024-03-16 22:50:19 +010013#include <charset.h>
Simon Glassed38aef2020-05-10 11:40:03 -060014#include <command.h>
Simon Glassf97beb72020-07-02 21:12:14 -060015#include <console.h>
Simon Glass0f2af882020-05-10 11:40:05 -060016#include <log.h>
Simon Glass84c7fb32016-01-18 19:52:17 -070017#include <dm.h>
18#include <video.h>
19#include <video_console.h>
Heinrich Schuchardt2172fa42018-03-02 20:50:17 +010020#include <video_font.h> /* Bitmap font for code page 437 */
Simon Glassf97beb72020-07-02 21:12:14 -060021#include <linux/ctype.h>
Simon Glass84c7fb32016-01-18 19:52:17 -070022
Janne Grunau5548c362024-03-16 22:50:19 +010023int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, int ch)
Simon Glass84c7fb32016-01-18 19:52:17 -070024{
25 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
26
27 if (!ops->putc_xy)
28 return -ENOSYS;
29 return ops->putc_xy(dev, x, y, ch);
30}
31
32int vidconsole_move_rows(struct udevice *dev, uint rowdst, uint rowsrc,
33 uint count)
34{
35 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
36
37 if (!ops->move_rows)
38 return -ENOSYS;
39 return ops->move_rows(dev, rowdst, rowsrc, count);
40}
41
42int vidconsole_set_row(struct udevice *dev, uint row, int clr)
43{
44 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
45
46 if (!ops->set_row)
47 return -ENOSYS;
48 return ops->set_row(dev, row, clr);
49}
50
Simon Glass4446c4b2023-10-01 19:13:20 -060051int vidconsole_entry_start(struct udevice *dev)
Simon Glassafee7432016-01-14 18:10:40 -070052{
53 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
54
55 if (!ops->entry_start)
56 return -ENOSYS;
57 return ops->entry_start(dev);
58}
59
Simon Glass84c7fb32016-01-18 19:52:17 -070060/* Move backwards one space */
Simon Glass33bd3b62016-01-14 18:10:41 -070061static int vidconsole_back(struct udevice *dev)
Simon Glass84c7fb32016-01-18 19:52:17 -070062{
63 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
Simon Glass33bd3b62016-01-14 18:10:41 -070064 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
65 int ret;
66
67 if (ops->backspace) {
68 ret = ops->backspace(dev);
69 if (ret != -ENOSYS)
70 return ret;
71 }
Simon Glass84c7fb32016-01-18 19:52:17 -070072
Simon Glass52c10c52016-01-14 18:10:37 -070073 priv->xcur_frac -= VID_TO_POS(priv->x_charsize);
Simon Glassa74451d2016-01-14 18:10:39 -070074 if (priv->xcur_frac < priv->xstart_frac) {
Simon Glass52c10c52016-01-14 18:10:37 -070075 priv->xcur_frac = (priv->cols - 1) *
76 VID_TO_POS(priv->x_charsize);
77 priv->ycur -= priv->y_charsize;
78 if (priv->ycur < 0)
79 priv->ycur = 0;
Simon Glass84c7fb32016-01-18 19:52:17 -070080 }
Michal Simek632e3d42020-12-14 08:47:52 +010081 return video_sync(dev->parent, false);
Simon Glass84c7fb32016-01-18 19:52:17 -070082}
83
84/* Move to a newline, scrolling the display if necessary */
85static 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);
Nikhil M Jain9e3301d2023-04-20 17:41:08 +053090 const int rows = CONFIG_VAL(CONSOLE_SCROLL_LINES);
Michal Simek632e3d42020-12-14 08:47:52 +010091 int i, ret;
Simon Glass84c7fb32016-01-18 19:52:17 -070092
Simon Glassa74451d2016-01-14 18:10:39 -070093 priv->xcur_frac = priv->xstart_frac;
Simon Glass52c10c52016-01-14 18:10:37 -070094 priv->ycur += priv->y_charsize;
Simon Glass84c7fb32016-01-18 19:52:17 -070095
96 /* Check if we need to scroll the terminal */
Simon Glass52c10c52016-01-14 18:10:37 -070097 if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) {
Simon Glass84c7fb32016-01-18 19:52:17 -070098 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);
Simon Glass52c10c52016-01-14 18:10:37 -0700102 priv->ycur -= rows * priv->y_charsize;
Simon Glass84c7fb32016-01-18 19:52:17 -0700103 }
Simon Glassafee7432016-01-14 18:10:40 -0700104 priv->last_ch = 0;
105
Michal Simek632e3d42020-12-14 08:47:52 +0100106 ret = video_sync(dev->parent, false);
107 if (ret) {
108#ifdef DEBUG
109 console_puts_select_stderr(true, "[vc err: video_sync]");
110#endif
111 }
Simon Glass84c7fb32016-01-18 19:52:17 -0700112}
113
Rob Clark06e7a0d2017-09-13 18:12:21 -0400114static char *parsenum(char *s, int *num)
115{
116 char *end;
117 *num = simple_strtol(s, &end, 10);
118 return end;
119}
120
Simon Glassd622c5b2022-10-06 08:36:04 -0600121void vidconsole_set_cursor_pos(struct udevice *dev, int x, int y)
122{
123 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
124
125 priv->xcur_frac = VID_TO_POS(x);
126 priv->xstart_frac = priv->xcur_frac;
127 priv->ycur = y;
Simon Glass2425d4f2024-01-04 08:10:37 -0700128 vidconsole_entry_start(dev);
Simon Glassd622c5b2022-10-06 08:36:04 -0600129}
130
Tom Rini2b99fd82023-03-15 11:58:58 -0400131/**
132 * set_cursor_position() - set cursor position
133 *
134 * @priv: private data of the video console
135 * @row: new row
136 * @col: new column
137 */
Simon Glass2425d4f2024-01-04 08:10:37 -0700138static void set_cursor_position(struct udevice *dev, int row, int col)
Heinrich Schuchardt9e933f12018-09-19 21:31:48 +0200139{
Simon Glass2425d4f2024-01-04 08:10:37 -0700140 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
141
Tom Rini2b99fd82023-03-15 11:58:58 -0400142 /*
143 * Ensure we stay in the bounds of the screen.
144 */
145 if (row >= priv->rows)
146 row = priv->rows - 1;
147 if (col >= priv->cols)
148 col = priv->cols - 1;
Heinrich Schuchardt9e933f12018-09-19 21:31:48 +0200149
Simon Glass2425d4f2024-01-04 08:10:37 -0700150 vidconsole_position_cursor(dev, col, row);
Heinrich Schuchardt9e933f12018-09-19 21:31:48 +0200151}
152
153/**
154 * get_cursor_position() - get cursor position
155 *
156 * @priv: private data of the video console
157 * @row: row
158 * @col: column
159 */
160static void get_cursor_position(struct vidconsole_priv *priv,
161 int *row, int *col)
162{
163 *row = priv->ycur / priv->y_charsize;
164 *col = VID_TO_PIXEL(priv->xcur_frac - priv->xstart_frac) /
165 priv->x_charsize;
166}
167
Rob Clark06e7a0d2017-09-13 18:12:21 -0400168/*
169 * Process a character while accumulating an escape string. Chars are
170 * accumulated into escape_buf until the end of escape sequence is
171 * found, at which point the sequence is parsed and processed.
172 */
173static void vidconsole_escape_char(struct udevice *dev, char ch)
174{
175 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
176
177 if (!IS_ENABLED(CONFIG_VIDEO_ANSI))
178 goto error;
179
180 /* Sanity checking for bogus ESC sequences: */
181 if (priv->escape_len >= sizeof(priv->escape_buf))
182 goto error;
Heinrich Schuchardt9e933f12018-09-19 21:31:48 +0200183 if (priv->escape_len == 0) {
184 switch (ch) {
185 case '7':
186 /* Save cursor position */
187 get_cursor_position(priv, &priv->row_saved,
188 &priv->col_saved);
189 priv->escape = 0;
190
191 return;
192 case '8': {
193 /* Restore cursor position */
194 int row = priv->row_saved;
195 int col = priv->col_saved;
196
Simon Glass2425d4f2024-01-04 08:10:37 -0700197 set_cursor_position(dev, row, col);
Heinrich Schuchardt9e933f12018-09-19 21:31:48 +0200198 priv->escape = 0;
199 return;
200 }
201 case '[':
202 break;
203 default:
204 goto error;
205 }
206 }
Rob Clark06e7a0d2017-09-13 18:12:21 -0400207
208 priv->escape_buf[priv->escape_len++] = ch;
209
210 /*
211 * Escape sequences are terminated by a letter, so keep
212 * accumulating until we get one:
213 */
214 if (!isalpha(ch))
215 return;
216
217 /*
218 * clear escape mode first, otherwise things will get highly
219 * surprising if you hit any debug prints that come back to
220 * this console.
221 */
222 priv->escape = 0;
223
224 switch (ch) {
Andre Przywarad4a294c2019-03-23 01:29:57 +0000225 case 'A':
226 case 'B':
227 case 'C':
228 case 'D':
229 case 'E':
230 case 'F': {
231 int row, col, num;
232 char *s = priv->escape_buf;
233
234 /*
235 * Cursor up/down: [%dA, [%dB, [%dE, [%dF
236 * Cursor left/right: [%dD, [%dC
237 */
238 s++; /* [ */
239 s = parsenum(s, &num);
240 if (num == 0) /* No digit in sequence ... */
241 num = 1; /* ... means "move by 1". */
242
243 get_cursor_position(priv, &row, &col);
244 if (ch == 'A' || ch == 'F')
245 row -= num;
246 if (ch == 'C')
247 col += num;
248 if (ch == 'D')
249 col -= num;
250 if (ch == 'B' || ch == 'E')
251 row += num;
252 if (ch == 'E' || ch == 'F')
253 col = 0;
254 if (col < 0)
255 col = 0;
256 if (row < 0)
257 row = 0;
258 /* Right and bottom overflows are handled in the callee. */
Simon Glass2425d4f2024-01-04 08:10:37 -0700259 set_cursor_position(dev, row, col);
Andre Przywarad4a294c2019-03-23 01:29:57 +0000260 break;
261 }
Rob Clark06e7a0d2017-09-13 18:12:21 -0400262 case 'H':
263 case 'f': {
264 int row, col;
265 char *s = priv->escape_buf;
266
267 /*
268 * Set cursor position: [%d;%df or [%d;%dH
269 */
270 s++; /* [ */
271 s = parsenum(s, &row);
272 s++; /* ; */
273 s = parsenum(s, &col);
274
Heinrich Schuchardtc3c69302018-11-10 19:55:48 +0100275 /*
276 * Video origin is [0, 0], terminal origin is [1, 1].
277 */
278 if (row)
279 --row;
280 if (col)
281 --col;
282
Simon Glass2425d4f2024-01-04 08:10:37 -0700283 set_cursor_position(dev, row, col);
Rob Clark06e7a0d2017-09-13 18:12:21 -0400284
285 break;
286 }
287 case 'J': {
288 int mode;
289
290 /*
291 * Clear part/all screen:
292 * [J or [0J - clear screen from cursor down
293 * [1J - clear screen from cursor up
294 * [2J - clear entire screen
295 *
296 * TODO we really only handle entire-screen case, others
297 * probably require some additions to video-uclass (and
298 * are not really needed yet by efi_console)
299 */
300 parsenum(priv->escape_buf + 1, &mode);
301
302 if (mode == 2) {
Michal Simek632e3d42020-12-14 08:47:52 +0100303 int ret;
304
Rob Clark06e7a0d2017-09-13 18:12:21 -0400305 video_clear(dev->parent);
Michal Simek632e3d42020-12-14 08:47:52 +0100306 ret = video_sync(dev->parent, false);
307 if (ret) {
308#ifdef DEBUG
309 console_puts_select_stderr(true, "[vc err: video_sync]");
310#endif
311 }
Rob Clark06e7a0d2017-09-13 18:12:21 -0400312 priv->ycur = 0;
313 priv->xcur_frac = priv->xstart_frac;
314 } else {
315 debug("unsupported clear mode: %d\n", mode);
316 }
317 break;
318 }
Andre Przywara918622a2019-03-23 01:29:58 +0000319 case 'K': {
320 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
321 int mode;
322
323 /*
324 * Clear (parts of) current line
325 * [0K - clear line to end
326 * [2K - clear entire line
327 */
328 parsenum(priv->escape_buf + 1, &mode);
329
330 if (mode == 2) {
331 int row, col;
332
333 get_cursor_position(priv, &row, &col);
334 vidconsole_set_row(dev, row, vid_priv->colour_bg);
335 }
336 break;
337 }
Rob Clark50509bb2017-09-13 18:12:22 -0400338 case 'm': {
339 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
340 char *s = priv->escape_buf;
341 char *end = &priv->escape_buf[priv->escape_len];
342
343 /*
344 * Set graphics mode: [%d;...;%dm
345 *
346 * Currently only supports the color attributes:
347 *
348 * Foreground Colors:
349 *
350 * 30 Black
351 * 31 Red
352 * 32 Green
353 * 33 Yellow
354 * 34 Blue
355 * 35 Magenta
356 * 36 Cyan
357 * 37 White
358 *
359 * Background Colors:
360 *
361 * 40 Black
362 * 41 Red
363 * 42 Green
364 * 43 Yellow
365 * 44 Blue
366 * 45 Magenta
367 * 46 Cyan
368 * 47 White
369 */
370
371 s++; /* [ */
372 while (s < end) {
373 int val;
374
375 s = parsenum(s, &val);
376 s++;
377
378 switch (val) {
Heinrich Schuchardt2a436db2018-02-08 21:47:12 +0100379 case 0:
380 /* all attributes off */
Simon Glass2b063b82018-11-06 15:21:36 -0700381 video_set_default_colors(dev->parent, false);
Heinrich Schuchardt2a436db2018-02-08 21:47:12 +0100382 break;
383 case 1:
384 /* bold */
385 vid_priv->fg_col_idx |= 8;
Simon Glass2a006332022-10-06 08:36:03 -0600386 vid_priv->colour_fg = video_index_to_colour(
Heinrich Schuchardt2a436db2018-02-08 21:47:12 +0100387 vid_priv, vid_priv->fg_col_idx);
388 break;
Andre Przywara4ed5bc82019-03-23 01:29:56 +0000389 case 7:
390 /* reverse video */
Simon Glass2a006332022-10-06 08:36:03 -0600391 vid_priv->colour_fg = video_index_to_colour(
Andre Przywara4ed5bc82019-03-23 01:29:56 +0000392 vid_priv, vid_priv->bg_col_idx);
Simon Glass2a006332022-10-06 08:36:03 -0600393 vid_priv->colour_bg = video_index_to_colour(
Andre Przywara4ed5bc82019-03-23 01:29:56 +0000394 vid_priv, vid_priv->fg_col_idx);
395 break;
Rob Clark50509bb2017-09-13 18:12:22 -0400396 case 30 ... 37:
Heinrich Schuchardt290e1d82018-02-08 21:47:11 +0100397 /* foreground color */
Heinrich Schuchardt2a436db2018-02-08 21:47:12 +0100398 vid_priv->fg_col_idx &= ~7;
399 vid_priv->fg_col_idx |= val - 30;
Simon Glass2a006332022-10-06 08:36:03 -0600400 vid_priv->colour_fg = video_index_to_colour(
Heinrich Schuchardt2a436db2018-02-08 21:47:12 +0100401 vid_priv, vid_priv->fg_col_idx);
Rob Clark50509bb2017-09-13 18:12:22 -0400402 break;
403 case 40 ... 47:
Andre Przywara4ed5bc82019-03-23 01:29:56 +0000404 /* background color, also mask the bold bit */
405 vid_priv->bg_col_idx &= ~0xf;
406 vid_priv->bg_col_idx |= val - 40;
Simon Glass2a006332022-10-06 08:36:03 -0600407 vid_priv->colour_bg = video_index_to_colour(
Andre Przywara4ed5bc82019-03-23 01:29:56 +0000408 vid_priv, vid_priv->bg_col_idx);
Rob Clark50509bb2017-09-13 18:12:22 -0400409 break;
410 default:
Heinrich Schuchardt290e1d82018-02-08 21:47:11 +0100411 /* ignore unsupported SGR parameter */
Rob Clark50509bb2017-09-13 18:12:22 -0400412 break;
413 }
414 }
415
416 break;
417 }
Rob Clark06e7a0d2017-09-13 18:12:21 -0400418 default:
419 debug("unrecognized escape sequence: %*s\n",
420 priv->escape_len, priv->escape_buf);
421 }
422
423 return;
424
425error:
426 /* something went wrong, just revert to normal mode: */
427 priv->escape = 0;
428}
429
Janne Grunau5548c362024-03-16 22:50:19 +0100430/* Put that actual character on the screen (using the UTF-32 code points). */
431static int vidconsole_output_glyph(struct udevice *dev, int ch)
Andre Przywarade86baf2019-03-23 01:29:59 +0000432{
433 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
434 int ret;
435
436 /*
437 * Failure of this function normally indicates an unsupported
438 * colour depth. Check this and return an error to help with
439 * diagnosis.
440 */
441 ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch);
442 if (ret == -EAGAIN) {
443 vidconsole_newline(dev);
444 ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch);
445 }
446 if (ret < 0)
447 return ret;
448 priv->xcur_frac += ret;
449 priv->last_ch = ch;
450 if (priv->xcur_frac >= priv->xsize_frac)
451 vidconsole_newline(dev);
452
453 return 0;
454}
455
Simon Glass84c7fb32016-01-18 19:52:17 -0700456int vidconsole_put_char(struct udevice *dev, char ch)
457{
458 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
Janne Grunau5548c362024-03-16 22:50:19 +0100459 int cp, ret;
Simon Glass84c7fb32016-01-18 19:52:17 -0700460
Rob Clark06e7a0d2017-09-13 18:12:21 -0400461 if (priv->escape) {
462 vidconsole_escape_char(dev, ch);
463 return 0;
464 }
465
Simon Glass84c7fb32016-01-18 19:52:17 -0700466 switch (ch) {
Rob Clark06e7a0d2017-09-13 18:12:21 -0400467 case '\x1b':
468 priv->escape_len = 0;
469 priv->escape = 1;
470 break;
Simon Glass37b80202016-01-14 18:10:38 -0700471 case '\a':
472 /* beep */
473 break;
Simon Glass84c7fb32016-01-18 19:52:17 -0700474 case '\r':
Simon Glassa74451d2016-01-14 18:10:39 -0700475 priv->xcur_frac = priv->xstart_frac;
Simon Glass84c7fb32016-01-18 19:52:17 -0700476 break;
477 case '\n':
478 vidconsole_newline(dev);
Simon Glassafee7432016-01-14 18:10:40 -0700479 vidconsole_entry_start(dev);
Simon Glass84c7fb32016-01-18 19:52:17 -0700480 break;
481 case '\t': /* Tab (8 chars alignment) */
Simon Glass52c10c52016-01-14 18:10:37 -0700482 priv->xcur_frac = ((priv->xcur_frac / priv->tab_width_frac)
483 + 1) * priv->tab_width_frac;
Simon Glass84c7fb32016-01-18 19:52:17 -0700484
Simon Glass52c10c52016-01-14 18:10:37 -0700485 if (priv->xcur_frac >= priv->xsize_frac)
Simon Glass84c7fb32016-01-18 19:52:17 -0700486 vidconsole_newline(dev);
487 break;
488 case '\b':
489 vidconsole_back(dev);
Simon Glassafee7432016-01-14 18:10:40 -0700490 priv->last_ch = 0;
Simon Glass84c7fb32016-01-18 19:52:17 -0700491 break;
492 default:
Janne Grunau5548c362024-03-16 22:50:19 +0100493 if (CONFIG_IS_ENABLED(CHARSET)) {
494 cp = utf8_to_utf32_stream(ch, priv->utf8_buf);
495 if (cp == 0)
496 return 0;
497 } else {
498 cp = ch;
499 }
500 ret = vidconsole_output_glyph(dev, cp);
Simon Glass52c10c52016-01-14 18:10:37 -0700501 if (ret < 0)
Simon Glass84c7fb32016-01-18 19:52:17 -0700502 return ret;
Simon Glass84c7fb32016-01-18 19:52:17 -0700503 break;
504 }
505
506 return 0;
507}
508
Marek Vasuta89f9cb2019-05-17 20:22:31 +0200509int vidconsole_put_string(struct udevice *dev, const char *str)
510{
511 const char *s;
512 int ret;
513
514 for (s = str; *s; s++) {
515 ret = vidconsole_put_char(dev, *s);
516 if (ret)
517 return ret;
518 }
519
520 return 0;
521}
522
Simon Glass84c7fb32016-01-18 19:52:17 -0700523static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
524{
525 struct udevice *dev = sdev->priv;
Simon Glassf97beb72020-07-02 21:12:14 -0600526 int ret;
Simon Glass84c7fb32016-01-18 19:52:17 -0700527
Simon Glassf97beb72020-07-02 21:12:14 -0600528 ret = vidconsole_put_char(dev, ch);
529 if (ret) {
530#ifdef DEBUG
531 console_puts_select_stderr(true, "[vc err: putc]");
532#endif
533 }
Michal Simek632e3d42020-12-14 08:47:52 +0100534 ret = video_sync(dev->parent, false);
535 if (ret) {
536#ifdef DEBUG
537 console_puts_select_stderr(true, "[vc err: video_sync]");
538#endif
539 }
Simon Glass84c7fb32016-01-18 19:52:17 -0700540}
541
542static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
543{
544 struct udevice *dev = sdev->priv;
Simon Glassf97beb72020-07-02 21:12:14 -0600545 int ret;
546
547 ret = vidconsole_put_string(dev, s);
548 if (ret) {
549#ifdef DEBUG
550 char str[30];
Simon Glass84c7fb32016-01-18 19:52:17 -0700551
Simon Glassf97beb72020-07-02 21:12:14 -0600552 snprintf(str, sizeof(str), "[vc err: puts %d]", ret);
553 console_puts_select_stderr(true, str);
554#endif
555 }
Michal Simek632e3d42020-12-14 08:47:52 +0100556 ret = video_sync(dev->parent, false);
557 if (ret) {
558#ifdef DEBUG
559 console_puts_select_stderr(true, "[vc err: video_sync]");
560#endif
561 }
Simon Glass84c7fb32016-01-18 19:52:17 -0700562}
563
Simon Glass3b175ba2023-01-06 08:52:32 -0600564void vidconsole_list_fonts(struct udevice *dev)
565{
566 struct vidfont_info info;
567 int ret, i;
568
569 for (i = 0, ret = 0; !ret; i++) {
570 ret = vidconsole_get_font(dev, i, &info);
571 if (!ret)
572 printf("%s\n", info.name);
573 }
574}
575
576int vidconsole_get_font(struct udevice *dev, int seq,
577 struct vidfont_info *info)
578{
579 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
580
581 if (!ops->get_font)
582 return -ENOSYS;
583
584 return ops->get_font(dev, seq, info);
585}
586
Dzmitry Sankouski86c6a532023-03-07 13:21:15 +0300587int vidconsole_get_font_size(struct udevice *dev, const char **name, uint *sizep)
588{
589 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
590
591 if (!ops->get_font_size)
592 return -ENOSYS;
593
594 *name = ops->get_font_size(dev, sizep);
595 return 0;
596}
597
Simon Glass3b175ba2023-01-06 08:52:32 -0600598int vidconsole_select_font(struct udevice *dev, const char *name, uint size)
599{
600 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
601
602 if (!ops->select_font)
603 return -ENOSYS;
604
605 return ops->select_font(dev, name, size);
606}
607
Simon Glass5caf1252023-06-01 10:22:46 -0600608int vidconsole_measure(struct udevice *dev, const char *name, uint size,
609 const char *text, struct vidconsole_bbox *bbox)
610{
611 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
612 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
613 int ret;
614
Bin Meng31aef742023-08-03 17:32:41 +0800615 if (ops->measure) {
Simon Glass5caf1252023-06-01 10:22:46 -0600616 ret = ops->measure(dev, name, size, text, bbox);
617 if (ret != -ENOSYS)
618 return ret;
619 }
620
621 bbox->valid = true;
622 bbox->x0 = 0;
623 bbox->y0 = 0;
624 bbox->x1 = priv->x_charsize * strlen(text);
625 bbox->y1 = priv->y_charsize;
626
627 return 0;
628}
629
Simon Glass8b82e592023-10-01 19:13:18 -0600630int vidconsole_nominal(struct udevice *dev, const char *name, uint size,
631 uint num_chars, struct vidconsole_bbox *bbox)
632{
633 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
634 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
635 int ret;
636
637 if (ops->measure) {
638 ret = ops->nominal(dev, name, size, num_chars, bbox);
639 if (ret != -ENOSYS)
640 return ret;
641 }
642
643 bbox->valid = true;
644 bbox->x0 = 0;
645 bbox->y0 = 0;
646 bbox->x1 = priv->x_charsize * num_chars;
647 bbox->y1 = priv->y_charsize;
648
649 return 0;
650}
651
Simon Glass34b5c252023-10-01 19:13:19 -0600652int vidconsole_entry_save(struct udevice *dev, struct abuf *buf)
653{
654 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
655 int ret;
656
657 if (ops->measure) {
658 ret = ops->entry_save(dev, buf);
659 if (ret != -ENOSYS)
660 return ret;
661 }
662
663 /* no data so make sure the buffer is empty */
664 abuf_realloc(buf, 0);
665
666 return 0;
667}
668
669int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf)
670{
671 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
672 int ret;
673
674 if (ops->measure) {
675 ret = ops->entry_restore(dev, buf);
676 if (ret != -ENOSYS)
677 return ret;
678 }
679
680 return 0;
681}
682
Simon Glass377f79aa2023-10-01 19:13:21 -0600683int vidconsole_set_cursor_visible(struct udevice *dev, bool visible,
684 uint x, uint y, uint index)
685{
686 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
687 int ret;
688
689 if (ops->set_cursor_visible) {
690 ret = ops->set_cursor_visible(dev, visible, x, y, index);
691 if (ret != -ENOSYS)
692 return ret;
693 }
694
695 return 0;
696}
697
Simon Glassa73a8b82023-06-01 10:22:45 -0600698void vidconsole_push_colour(struct udevice *dev, enum colour_idx fg,
699 enum colour_idx bg, struct vidconsole_colour *old)
700{
701 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
702
703 old->colour_fg = vid_priv->colour_fg;
704 old->colour_bg = vid_priv->colour_bg;
705
706 vid_priv->colour_fg = video_index_to_colour(vid_priv, fg);
707 vid_priv->colour_bg = video_index_to_colour(vid_priv, bg);
708}
709
710void vidconsole_pop_colour(struct udevice *dev, struct vidconsole_colour *old)
711{
712 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
713
714 vid_priv->colour_fg = old->colour_fg;
715 vid_priv->colour_bg = old->colour_bg;
716}
717
Simon Glass84c7fb32016-01-18 19:52:17 -0700718/* Set up the number of rows and colours (rotated drivers override this) */
719static int vidconsole_pre_probe(struct udevice *dev)
720{
721 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
722 struct udevice *vid = dev->parent;
723 struct video_priv *vid_priv = dev_get_uclass_priv(vid);
724
Simon Glass52c10c52016-01-14 18:10:37 -0700725 priv->xsize_frac = VID_TO_POS(vid_priv->xsize);
Simon Glass84c7fb32016-01-18 19:52:17 -0700726
727 return 0;
728}
729
730/* Register the device with stdio */
731static int vidconsole_post_probe(struct udevice *dev)
732{
733 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
734 struct stdio_dev *sdev = &priv->sdev;
Simon Glass84c7fb32016-01-18 19:52:17 -0700735
Simon Glass52c10c52016-01-14 18:10:37 -0700736 if (!priv->tab_width_frac)
737 priv->tab_width_frac = VID_TO_POS(priv->x_charsize) * 8;
738
Simon Glass75e534b2020-12-16 21:20:07 -0700739 if (dev_seq(dev)) {
Simon Glass798ff502016-01-21 19:44:51 -0700740 snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d",
Simon Glass75e534b2020-12-16 21:20:07 -0700741 dev_seq(dev));
Simon Glass798ff502016-01-21 19:44:51 -0700742 } else {
743 strcpy(sdev->name, "vidconsole");
744 }
Simon Glass52c10c52016-01-14 18:10:37 -0700745
Simon Glass84c7fb32016-01-18 19:52:17 -0700746 sdev->flags = DEV_FLAGS_OUTPUT;
747 sdev->putc = vidconsole_putc;
748 sdev->puts = vidconsole_puts;
749 sdev->priv = dev;
Simon Glass84c7fb32016-01-18 19:52:17 -0700750
Masahiro Yamadabf528cd2016-09-06 22:17:33 +0900751 return stdio_register(sdev);
Simon Glass84c7fb32016-01-18 19:52:17 -0700752}
753
754UCLASS_DRIVER(vidconsole) = {
755 .id = UCLASS_VIDEO_CONSOLE,
756 .name = "vidconsole0",
757 .pre_probe = vidconsole_pre_probe,
758 .post_probe = vidconsole_post_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700759 .per_device_auto = sizeof(struct vidconsole_priv),
Simon Glass84c7fb32016-01-18 19:52:17 -0700760};
761
Simon Glass31a7e232020-07-02 21:12:23 -0600762#ifdef CONFIG_VIDEO_COPY
763int vidconsole_sync_copy(struct udevice *dev, void *from, void *to)
764{
765 struct udevice *vid = dev_get_parent(dev);
766
767 return video_sync_copy(vid, from, to);
768}
769
770int vidconsole_memmove(struct udevice *dev, void *dst, const void *src,
771 int size)
772{
773 memmove(dst, src, size);
774 return vidconsole_sync_copy(dev, dst, dst + size);
775}
776#endif
Simon Glass90679c62023-03-10 12:47:21 -0800777
778int vidconsole_clear_and_reset(struct udevice *dev)
779{
780 int ret;
781
782 ret = video_clear(dev_get_parent(dev));
783 if (ret)
784 return ret;
785 vidconsole_position_cursor(dev, 0, 0);
786
787 return 0;
788}
Tom Rini2b99fd82023-03-15 11:58:58 -0400789
790void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row)
791{
792 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
793 struct udevice *vid_dev = dev->parent;
794 struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
795 short x, y;
796
797 x = min_t(short, col * priv->x_charsize, vid_priv->xsize - 1);
798 y = min_t(short, row * priv->y_charsize, vid_priv->ysize - 1);
799 vidconsole_set_cursor_pos(dev, x, y);
800}