1 // SPDX-License-Identifier: GPL-2.0+
2 /*
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
8 */
9
10 #define LOG_CATEGORY UCLASS_VIDEO_CONSOLE
11
12 #include <abuf.h>
13 #include <charset.h>
14 #include <command.h>
15 #include <console.h>
16 #include <log.h>
17 #include <dm.h>
18 #include <video.h>
19 #include <video_console.h>
20 #include <video_font.h> /* Bitmap font for code page 437 */
21 #include <linux/ctype.h>
22
vidconsole_putc_xy(struct udevice * dev,uint x,uint y,int ch)23 int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, int ch)
24 {
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
vidconsole_move_rows(struct udevice * dev,uint rowdst,uint rowsrc,uint count)32 int 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
vidconsole_set_row(struct udevice * dev,uint row,int clr)42 int 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
vidconsole_entry_start(struct udevice * dev)51 int vidconsole_entry_start(struct udevice *dev)
52 {
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
60 /* Move backwards one space */
vidconsole_back(struct udevice * dev)61 static int vidconsole_back(struct udevice *dev)
62 {
63 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
64 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 }
72
73 priv->xcur_frac -= VID_TO_POS(priv->x_charsize);
74 if (priv->xcur_frac < priv->xstart_frac) {
75 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;
80 }
81 return video_sync(dev->parent, false);
82 }
83
84 /* Move to a newline, scrolling the display if necessary */
vidconsole_newline(struct udevice * dev)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_VAL(CONSOLE_SCROLL_LINES);
91 int i, ret;
92
93 priv->xcur_frac = priv->xstart_frac;
94 priv->ycur += priv->y_charsize;
95
96 /* Check if we need to scroll the terminal */
97 if (vid_priv->rot % 2 ?
98 priv->ycur + priv->x_charsize > vid_priv->xsize :
99 priv->ycur + priv->y_charsize > vid_priv->ysize) {
100 vidconsole_move_rows(dev, 0, rows, priv->rows - rows);
101 for (i = 0; i < rows; i++)
102 vidconsole_set_row(dev, priv->rows - i - 1,
103 vid_priv->colour_bg);
104 priv->ycur -= rows * priv->y_charsize;
105 }
106 priv->last_ch = 0;
107
108 ret = video_sync(dev->parent, false);
109 if (ret) {
110 #ifdef DEBUG
111 console_puts_select_stderr(true, "[vc err: video_sync]");
112 #endif
113 }
114 }
115
parsenum(char * s,int * num)116 static char *parsenum(char *s, int *num)
117 {
118 char *end;
119 *num = simple_strtol(s, &end, 10);
120 return end;
121 }
122
vidconsole_set_cursor_pos(struct udevice * dev,int x,int y)123 void vidconsole_set_cursor_pos(struct udevice *dev, int x, int y)
124 {
125 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
126
127 priv->xcur_frac = VID_TO_POS(x);
128 priv->xstart_frac = priv->xcur_frac;
129 priv->ycur = y;
130
131 /* make sure not to kern against the previous character */
132 priv->last_ch = 0;
133 vidconsole_entry_start(dev);
134 }
135
136 /**
137 * set_cursor_position() - set cursor position
138 *
139 * @priv: private data of the video console
140 * @row: new row
141 * @col: new column
142 */
set_cursor_position(struct udevice * dev,int row,int col)143 static void set_cursor_position(struct udevice *dev, int row, int col)
144 {
145 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
146
147 /*
148 * Ensure we stay in the bounds of the screen.
149 */
150 if (row >= priv->rows)
151 row = priv->rows - 1;
152 if (col >= priv->cols)
153 col = priv->cols - 1;
154
155 vidconsole_position_cursor(dev, col, row);
156 }
157
158 /**
159 * get_cursor_position() - get cursor position
160 *
161 * @priv: private data of the video console
162 * @row: row
163 * @col: column
164 */
get_cursor_position(struct vidconsole_priv * priv,int * row,int * col)165 static void get_cursor_position(struct vidconsole_priv *priv,
166 int *row, int *col)
167 {
168 *row = priv->ycur / priv->y_charsize;
169 *col = VID_TO_PIXEL(priv->xcur_frac - priv->xstart_frac) /
170 priv->x_charsize;
171 }
172
173 /*
174 * Process a character while accumulating an escape string. Chars are
175 * accumulated into escape_buf until the end of escape sequence is
176 * found, at which point the sequence is parsed and processed.
177 */
vidconsole_escape_char(struct udevice * dev,char ch)178 static void vidconsole_escape_char(struct udevice *dev, char ch)
179 {
180 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
181
182 if (!IS_ENABLED(CONFIG_VIDEO_ANSI))
183 goto error;
184
185 /* Sanity checking for bogus ESC sequences: */
186 if (priv->escape_len >= sizeof(priv->escape_buf))
187 goto error;
188 if (priv->escape_len == 0) {
189 switch (ch) {
190 case '7':
191 /* Save cursor position */
192 get_cursor_position(priv, &priv->row_saved,
193 &priv->col_saved);
194 priv->escape = 0;
195
196 return;
197 case '8': {
198 /* Restore cursor position */
199 int row = priv->row_saved;
200 int col = priv->col_saved;
201
202 set_cursor_position(dev, row, col);
203 priv->escape = 0;
204 return;
205 }
206 case '[':
207 break;
208 default:
209 goto error;
210 }
211 }
212
213 priv->escape_buf[priv->escape_len++] = ch;
214
215 /*
216 * Escape sequences are terminated by a letter, so keep
217 * accumulating until we get one:
218 */
219 if (!isalpha(ch))
220 return;
221
222 /*
223 * clear escape mode first, otherwise things will get highly
224 * surprising if you hit any debug prints that come back to
225 * this console.
226 */
227 priv->escape = 0;
228
229 switch (ch) {
230 case 'A':
231 case 'B':
232 case 'C':
233 case 'D':
234 case 'E':
235 case 'F': {
236 int row, col, num;
237 char *s = priv->escape_buf;
238
239 /*
240 * Cursor up/down: [%dA, [%dB, [%dE, [%dF
241 * Cursor left/right: [%dD, [%dC
242 */
243 s++; /* [ */
244 s = parsenum(s, &num);
245 if (num == 0) /* No digit in sequence ... */
246 num = 1; /* ... means "move by 1". */
247
248 get_cursor_position(priv, &row, &col);
249 if (ch == 'A' || ch == 'F')
250 row -= num;
251 if (ch == 'C')
252 col += num;
253 if (ch == 'D')
254 col -= num;
255 if (ch == 'B' || ch == 'E')
256 row += num;
257 if (ch == 'E' || ch == 'F')
258 col = 0;
259 if (col < 0)
260 col = 0;
261 if (row < 0)
262 row = 0;
263 /* Right and bottom overflows are handled in the callee. */
264 set_cursor_position(dev, row, col);
265 break;
266 }
267 case 'H':
268 case 'f': {
269 int row, col;
270 char *s = priv->escape_buf;
271
272 /*
273 * Set cursor position: [%d;%df or [%d;%dH
274 */
275 s++; /* [ */
276 s = parsenum(s, &row);
277 s++; /* ; */
278 s = parsenum(s, &col);
279
280 /*
281 * Video origin is [0, 0], terminal origin is [1, 1].
282 */
283 if (row)
284 --row;
285 if (col)
286 --col;
287
288 set_cursor_position(dev, row, col);
289
290 break;
291 }
292 case 'J': {
293 int mode;
294
295 /*
296 * Clear part/all screen:
297 * [J or [0J - clear screen from cursor down
298 * [1J - clear screen from cursor up
299 * [2J - clear entire screen
300 *
301 * TODO we really only handle entire-screen case, others
302 * probably require some additions to video-uclass (and
303 * are not really needed yet by efi_console)
304 */
305 parsenum(priv->escape_buf + 1, &mode);
306
307 if (mode == 2) {
308 int ret;
309
310 video_clear(dev->parent);
311 ret = video_sync(dev->parent, false);
312 if (ret) {
313 #ifdef DEBUG
314 console_puts_select_stderr(true, "[vc err: video_sync]");
315 #endif
316 }
317 priv->ycur = 0;
318 priv->xcur_frac = priv->xstart_frac;
319 } else {
320 debug("unsupported clear mode: %d\n", mode);
321 }
322 break;
323 }
324 case 'K': {
325 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
326 int mode;
327
328 /*
329 * Clear (parts of) current line
330 * [0K - clear line to end
331 * [2K - clear entire line
332 */
333 parsenum(priv->escape_buf + 1, &mode);
334
335 if (mode == 2) {
336 int row, col;
337
338 get_cursor_position(priv, &row, &col);
339 vidconsole_set_row(dev, row, vid_priv->colour_bg);
340 }
341 break;
342 }
343 case 'm': {
344 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
345 char *s = priv->escape_buf;
346 char *end = &priv->escape_buf[priv->escape_len];
347
348 /*
349 * Set graphics mode: [%d;...;%dm
350 *
351 * Currently only supports the color attributes:
352 *
353 * Foreground Colors:
354 *
355 * 30 Black
356 * 31 Red
357 * 32 Green
358 * 33 Yellow
359 * 34 Blue
360 * 35 Magenta
361 * 36 Cyan
362 * 37 White
363 *
364 * Background Colors:
365 *
366 * 40 Black
367 * 41 Red
368 * 42 Green
369 * 43 Yellow
370 * 44 Blue
371 * 45 Magenta
372 * 46 Cyan
373 * 47 White
374 */
375
376 s++; /* [ */
377 while (s < end) {
378 int val;
379
380 s = parsenum(s, &val);
381 s++;
382
383 switch (val) {
384 case 0:
385 /* all attributes off */
386 video_set_default_colors(dev->parent, false);
387 break;
388 case 1:
389 /* bold */
390 vid_priv->fg_col_idx |= 8;
391 vid_priv->colour_fg = video_index_to_colour(
392 vid_priv, vid_priv->fg_col_idx);
393 break;
394 case 7:
395 /* reverse video */
396 vid_priv->colour_fg = video_index_to_colour(
397 vid_priv, vid_priv->bg_col_idx);
398 vid_priv->colour_bg = video_index_to_colour(
399 vid_priv, vid_priv->fg_col_idx);
400 break;
401 case 30 ... 37:
402 /* foreground color */
403 vid_priv->fg_col_idx &= ~7;
404 vid_priv->fg_col_idx |= val - 30;
405 vid_priv->colour_fg = video_index_to_colour(
406 vid_priv, vid_priv->fg_col_idx);
407 break;
408 case 40 ... 47:
409 /* background color, also mask the bold bit */
410 vid_priv->bg_col_idx &= ~0xf;
411 vid_priv->bg_col_idx |= val - 40;
412 vid_priv->colour_bg = video_index_to_colour(
413 vid_priv, vid_priv->bg_col_idx);
414 break;
415 default:
416 /* ignore unsupported SGR parameter */
417 break;
418 }
419 }
420
421 break;
422 }
423 default:
424 debug("unrecognized escape sequence: %*s\n",
425 priv->escape_len, priv->escape_buf);
426 }
427
428 return;
429
430 error:
431 /* something went wrong, just revert to normal mode: */
432 priv->escape = 0;
433 }
434
435 /* Put that actual character on the screen (using the UTF-32 code points). */
vidconsole_output_glyph(struct udevice * dev,int ch)436 static int vidconsole_output_glyph(struct udevice *dev, int ch)
437 {
438 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
439 int ret;
440
441 /*
442 * Failure of this function normally indicates an unsupported
443 * colour depth. Check this and return an error to help with
444 * diagnosis.
445 */
446 ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch);
447 if (ret == -EAGAIN) {
448 vidconsole_newline(dev);
449 ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch);
450 }
451 if (ret < 0)
452 return ret;
453 priv->xcur_frac += ret;
454 priv->last_ch = ch;
455 if (priv->xcur_frac >= priv->xsize_frac)
456 vidconsole_newline(dev);
457
458 return 0;
459 }
460
vidconsole_put_char(struct udevice * dev,char ch)461 int vidconsole_put_char(struct udevice *dev, char ch)
462 {
463 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
464 int cp, ret;
465
466 if (priv->escape) {
467 vidconsole_escape_char(dev, ch);
468 return 0;
469 }
470
471 switch (ch) {
472 case '\x1b':
473 priv->escape_len = 0;
474 priv->escape = 1;
475 break;
476 case '\a':
477 /* beep */
478 break;
479 case '\r':
480 priv->xcur_frac = priv->xstart_frac;
481 break;
482 case '\n':
483 vidconsole_newline(dev);
484 vidconsole_entry_start(dev);
485 break;
486 case '\t': /* Tab (8 chars alignment) */
487 priv->xcur_frac = ((priv->xcur_frac / priv->tab_width_frac)
488 + 1) * priv->tab_width_frac;
489
490 if (priv->xcur_frac >= priv->xsize_frac)
491 vidconsole_newline(dev);
492 break;
493 case '\b':
494 vidconsole_back(dev);
495 priv->last_ch = 0;
496 break;
497 default:
498 if (CONFIG_IS_ENABLED(CHARSET)) {
499 cp = utf8_to_utf32_stream(ch, priv->utf8_buf);
500 if (cp == 0)
501 return 0;
502 } else {
503 cp = ch;
504 }
505 ret = vidconsole_output_glyph(dev, cp);
506 if (ret < 0)
507 return ret;
508 break;
509 }
510
511 return 0;
512 }
513
vidconsole_put_stringn(struct udevice * dev,const char * str,int maxlen)514 int vidconsole_put_stringn(struct udevice *dev, const char *str, int maxlen)
515 {
516 const char *s, *end = NULL;
517 int ret;
518
519 if (maxlen != -1)
520 end = str + maxlen;
521 for (s = str; *s && (maxlen == -1 || s < end); s++) {
522 ret = vidconsole_put_char(dev, *s);
523 if (ret)
524 return ret;
525 }
526
527 return 0;
528 }
529
vidconsole_put_string(struct udevice * dev,const char * str)530 int vidconsole_put_string(struct udevice *dev, const char *str)
531 {
532 return vidconsole_put_stringn(dev, str, -1);
533 }
534
vidconsole_putc(struct stdio_dev * sdev,const char ch)535 static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
536 {
537 struct udevice *dev = sdev->priv;
538 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
539 int ret;
540
541 if (priv->quiet)
542 return;
543 ret = vidconsole_put_char(dev, ch);
544 if (ret) {
545 #ifdef DEBUG
546 console_puts_select_stderr(true, "[vc err: putc]");
547 #endif
548 }
549 ret = video_sync(dev->parent, false);
550 if (ret) {
551 #ifdef DEBUG
552 console_puts_select_stderr(true, "[vc err: video_sync]");
553 #endif
554 }
555 }
556
vidconsole_puts(struct stdio_dev * sdev,const char * s)557 static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
558 {
559 struct udevice *dev = sdev->priv;
560 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
561 int ret;
562
563 if (priv->quiet)
564 return;
565 ret = vidconsole_put_string(dev, s);
566 if (ret) {
567 #ifdef DEBUG
568 char str[30];
569
570 snprintf(str, sizeof(str), "[vc err: puts %d]", ret);
571 console_puts_select_stderr(true, str);
572 #endif
573 }
574 ret = video_sync(dev->parent, false);
575 if (ret) {
576 #ifdef DEBUG
577 console_puts_select_stderr(true, "[vc err: video_sync]");
578 #endif
579 }
580 }
581
vidconsole_list_fonts(struct udevice * dev)582 void vidconsole_list_fonts(struct udevice *dev)
583 {
584 struct vidfont_info info;
585 int ret, i;
586
587 for (i = 0, ret = 0; !ret; i++) {
588 ret = vidconsole_get_font(dev, i, &info);
589 if (!ret)
590 printf("%s\n", info.name);
591 }
592 }
593
vidconsole_get_font(struct udevice * dev,int seq,struct vidfont_info * info)594 int vidconsole_get_font(struct udevice *dev, int seq,
595 struct vidfont_info *info)
596 {
597 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
598
599 if (!ops->get_font)
600 return -ENOSYS;
601
602 return ops->get_font(dev, seq, info);
603 }
604
vidconsole_get_font_size(struct udevice * dev,const char ** name,uint * sizep)605 int vidconsole_get_font_size(struct udevice *dev, const char **name, uint *sizep)
606 {
607 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
608
609 if (!ops->get_font_size)
610 return -ENOSYS;
611
612 *name = ops->get_font_size(dev, sizep);
613 return 0;
614 }
615
vidconsole_select_font(struct udevice * dev,const char * name,uint size)616 int vidconsole_select_font(struct udevice *dev, const char *name, uint size)
617 {
618 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
619
620 if (!ops->select_font)
621 return -ENOSYS;
622
623 return ops->select_font(dev, name, size);
624 }
625
vidconsole_measure(struct udevice * dev,const char * name,uint size,const char * text,int limit,struct vidconsole_bbox * bbox,struct alist * lines)626 int vidconsole_measure(struct udevice *dev, const char *name, uint size,
627 const char *text, int limit,
628 struct vidconsole_bbox *bbox, struct alist *lines)
629 {
630 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
631 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
632 int ret;
633
634 if (ops->measure) {
635 if (lines)
636 alist_empty(lines);
637 ret = ops->measure(dev, name, size, text, limit, bbox, lines);
638 if (ret != -ENOSYS)
639 return ret;
640 }
641
642 bbox->valid = true;
643 bbox->x0 = 0;
644 bbox->y0 = 0;
645 bbox->x1 = priv->x_charsize * strlen(text);
646 bbox->y1 = priv->y_charsize;
647
648 return 0;
649 }
650
vidconsole_nominal(struct udevice * dev,const char * name,uint size,uint num_chars,struct vidconsole_bbox * bbox)651 int vidconsole_nominal(struct udevice *dev, const char *name, uint size,
652 uint num_chars, struct vidconsole_bbox *bbox)
653 {
654 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
655 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
656 int ret;
657
658 if (ops->measure) {
659 ret = ops->nominal(dev, name, size, num_chars, bbox);
660 if (ret != -ENOSYS)
661 return ret;
662 }
663
664 bbox->valid = true;
665 bbox->x0 = 0;
666 bbox->y0 = 0;
667 bbox->x1 = priv->x_charsize * num_chars;
668 bbox->y1 = priv->y_charsize;
669
670 return 0;
671 }
672
vidconsole_entry_save(struct udevice * dev,struct abuf * buf)673 int vidconsole_entry_save(struct udevice *dev, struct abuf *buf)
674 {
675 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
676 int ret;
677
678 if (ops->measure) {
679 ret = ops->entry_save(dev, buf);
680 if (ret != -ENOSYS)
681 return ret;
682 }
683
684 /* no data so make sure the buffer is empty */
685 abuf_realloc(buf, 0);
686
687 return 0;
688 }
689
vidconsole_entry_restore(struct udevice * dev,struct abuf * buf)690 int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf)
691 {
692 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
693 int ret;
694
695 if (ops->measure) {
696 ret = ops->entry_restore(dev, buf);
697 if (ret != -ENOSYS)
698 return ret;
699 }
700
701 return 0;
702 }
703
vidconsole_set_cursor_visible(struct udevice * dev,bool visible,uint x,uint y,uint index)704 int vidconsole_set_cursor_visible(struct udevice *dev, bool visible,
705 uint x, uint y, uint index)
706 {
707 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
708 int ret;
709
710 if (ops->set_cursor_visible) {
711 ret = ops->set_cursor_visible(dev, visible, x, y, index);
712 if (ret != -ENOSYS)
713 return ret;
714 }
715
716 return 0;
717 }
718
vidconsole_push_colour(struct udevice * dev,enum colour_idx fg,enum colour_idx bg,struct vidconsole_colour * old)719 void vidconsole_push_colour(struct udevice *dev, enum colour_idx fg,
720 enum colour_idx bg, struct vidconsole_colour *old)
721 {
722 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
723
724 old->colour_fg = vid_priv->colour_fg;
725 old->colour_bg = vid_priv->colour_bg;
726
727 vid_priv->colour_fg = video_index_to_colour(vid_priv, fg);
728 vid_priv->colour_bg = video_index_to_colour(vid_priv, bg);
729 }
730
vidconsole_pop_colour(struct udevice * dev,struct vidconsole_colour * old)731 void vidconsole_pop_colour(struct udevice *dev, struct vidconsole_colour *old)
732 {
733 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
734
735 vid_priv->colour_fg = old->colour_fg;
736 vid_priv->colour_bg = old->colour_bg;
737 }
738
739 /* Set up the number of rows and colours (rotated drivers override this) */
vidconsole_pre_probe(struct udevice * dev)740 static int vidconsole_pre_probe(struct udevice *dev)
741 {
742 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
743 struct udevice *vid = dev->parent;
744 struct video_priv *vid_priv = dev_get_uclass_priv(vid);
745
746 priv->xsize_frac = VID_TO_POS(vid_priv->xsize);
747
748 return 0;
749 }
750
751 /* Register the device with stdio */
vidconsole_post_probe(struct udevice * dev)752 static int vidconsole_post_probe(struct udevice *dev)
753 {
754 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
755 struct stdio_dev *sdev = &priv->sdev;
756
757 if (!priv->tab_width_frac)
758 priv->tab_width_frac = VID_TO_POS(priv->x_charsize) * 8;
759
760 if (dev_seq(dev)) {
761 snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d",
762 dev_seq(dev));
763 } else {
764 strcpy(sdev->name, "vidconsole");
765 }
766
767 sdev->flags = DEV_FLAGS_OUTPUT;
768 sdev->putc = vidconsole_putc;
769 sdev->puts = vidconsole_puts;
770 sdev->priv = dev;
771
772 return stdio_register(sdev);
773 }
774
775 UCLASS_DRIVER(vidconsole) = {
776 .id = UCLASS_VIDEO_CONSOLE,
777 .name = "vidconsole0",
778 .pre_probe = vidconsole_pre_probe,
779 .post_probe = vidconsole_post_probe,
780 .per_device_auto = sizeof(struct vidconsole_priv),
781 };
782
vidconsole_clear_and_reset(struct udevice * dev)783 int vidconsole_clear_and_reset(struct udevice *dev)
784 {
785 int ret;
786
787 ret = video_clear(dev_get_parent(dev));
788 if (ret)
789 return ret;
790 vidconsole_position_cursor(dev, 0, 0);
791
792 return 0;
793 }
794
vidconsole_position_cursor(struct udevice * dev,unsigned col,unsigned row)795 void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row)
796 {
797 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
798 struct udevice *vid_dev = dev->parent;
799 struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
800 short x, y;
801
802 x = min_t(short, col * priv->x_charsize, vid_priv->xsize - 1);
803 y = min_t(short, row * priv->y_charsize, vid_priv->ysize - 1);
804 vidconsole_set_cursor_pos(dev, x, y);
805 }
806
vidconsole_set_quiet(struct udevice * dev,bool quiet)807 void vidconsole_set_quiet(struct udevice *dev, bool quiet)
808 {
809 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
810
811 priv->quiet = quiet;
812 }
813