blob: 61f4216750f2ea8dbfe5f67438f4d9675733ff38 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass83510762016-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 Glass83510762016-01-18 19:52:17 -07008 */
9
Patrick Delaunayb953ec22021-04-27 11:02:19 +020010#define LOG_CATEGORY UCLASS_VIDEO_CONSOLE
11
Simon Glass83510762016-01-18 19:52:17 -070012#include <common.h>
Simon Glass09140112020-05-10 11:40:03 -060013#include <command.h>
Simon Glass8b763df2020-07-02 21:12:14 -060014#include <console.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060015#include <log.h>
Simon Glass83510762016-01-18 19:52:17 -070016#include <dm.h>
17#include <video.h>
18#include <video_console.h>
Heinrich Schuchardt5fba5322018-03-02 20:50:17 +010019#include <video_font.h> /* Bitmap font for code page 437 */
Simon Glass8b763df2020-07-02 21:12:14 -060020#include <linux/ctype.h>
Simon Glass83510762016-01-18 19:52:17 -070021
Simon Glass83510762016-01-18 19:52:17 -070022int 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
31int 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
41int 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
Simon Glass58c733a2016-01-14 18:10:40 -070050static 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
Simon Glass83510762016-01-18 19:52:17 -070059/* Move backwards one space */
Simon Glass7b9f7e42016-01-14 18:10:41 -070060static int vidconsole_back(struct udevice *dev)
Simon Glass83510762016-01-18 19:52:17 -070061{
62 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
Simon Glass7b9f7e42016-01-14 18:10:41 -070063 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 }
Simon Glass83510762016-01-18 19:52:17 -070071
Simon Glassf2661782016-01-14 18:10:37 -070072 priv->xcur_frac -= VID_TO_POS(priv->x_charsize);
Simon Glassc5b77d02016-01-14 18:10:39 -070073 if (priv->xcur_frac < priv->xstart_frac) {
Simon Glassf2661782016-01-14 18:10:37 -070074 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;
Simon Glass83510762016-01-18 19:52:17 -070079 }
Michal Simek9de731f2020-12-14 08:47:52 +010080 return video_sync(dev->parent, false);
Simon Glass83510762016-01-18 19:52:17 -070081}
82
83/* Move to a newline, scrolling the display if necessary */
84static void vidconsole_newline(struct udevice *dev)
85{
86 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
87 struct udevice *vid_dev = dev->parent;
88 struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
89 const int rows = CONFIG_CONSOLE_SCROLL_LINES;
Michal Simek9de731f2020-12-14 08:47:52 +010090 int i, ret;
Simon Glass83510762016-01-18 19:52:17 -070091
Simon Glassc5b77d02016-01-14 18:10:39 -070092 priv->xcur_frac = priv->xstart_frac;
Simon Glassf2661782016-01-14 18:10:37 -070093 priv->ycur += priv->y_charsize;
Simon Glass83510762016-01-18 19:52:17 -070094
95 /* Check if we need to scroll the terminal */
Simon Glassf2661782016-01-14 18:10:37 -070096 if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) {
Simon Glass83510762016-01-18 19:52:17 -070097 vidconsole_move_rows(dev, 0, rows, priv->rows - rows);
98 for (i = 0; i < rows; i++)
99 vidconsole_set_row(dev, priv->rows - i - 1,
100 vid_priv->colour_bg);
Simon Glassf2661782016-01-14 18:10:37 -0700101 priv->ycur -= rows * priv->y_charsize;
Simon Glass83510762016-01-18 19:52:17 -0700102 }
Simon Glass58c733a2016-01-14 18:10:40 -0700103 priv->last_ch = 0;
104
Michal Simek9de731f2020-12-14 08:47:52 +0100105 ret = video_sync(dev->parent, false);
106 if (ret) {
107#ifdef DEBUG
108 console_puts_select_stderr(true, "[vc err: video_sync]");
109#endif
110 }
Simon Glass83510762016-01-18 19:52:17 -0700111}
112
Rob Clarka085aa12017-09-13 18:12:21 -0400113static char *parsenum(char *s, int *num)
114{
115 char *end;
116 *num = simple_strtol(s, &end, 10);
117 return end;
118}
119
Simon Glass6b6dc0d2022-10-06 08:36:04 -0600120void vidconsole_set_cursor_pos(struct udevice *dev, int x, int y)
121{
122 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
123
124 priv->xcur_frac = VID_TO_POS(x);
125 priv->xstart_frac = priv->xcur_frac;
126 priv->ycur = y;
127}
128
Simon Glass9f62a472023-03-10 12:47:20 -0800129void vidconsole_position_cursor(struct udevice *dev, uint col, uint row)
Heinrich Schuchardt662f3812018-09-19 21:31:48 +0200130{
Simon Glass9f62a472023-03-10 12:47:20 -0800131 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
132 short x, y;
Heinrich Schuchardt662f3812018-09-19 21:31:48 +0200133
Simon Glass9f62a472023-03-10 12:47:20 -0800134 x = min_t(short, col, priv->cols - 1) * priv->x_charsize;
135 y = min_t(short, row, priv->rows - 1) * priv->y_charsize;
136 vidconsole_set_cursor_pos(dev, x, y);
Heinrich Schuchardt662f3812018-09-19 21:31:48 +0200137}
138
139/**
140 * get_cursor_position() - get cursor position
141 *
142 * @priv: private data of the video console
143 * @row: row
144 * @col: column
145 */
146static void get_cursor_position(struct vidconsole_priv *priv,
147 int *row, int *col)
148{
149 *row = priv->ycur / priv->y_charsize;
150 *col = VID_TO_PIXEL(priv->xcur_frac - priv->xstart_frac) /
151 priv->x_charsize;
152}
153
Rob Clarka085aa12017-09-13 18:12:21 -0400154/*
155 * Process a character while accumulating an escape string. Chars are
156 * accumulated into escape_buf until the end of escape sequence is
157 * found, at which point the sequence is parsed and processed.
158 */
159static void vidconsole_escape_char(struct udevice *dev, char ch)
160{
161 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
162
163 if (!IS_ENABLED(CONFIG_VIDEO_ANSI))
164 goto error;
165
166 /* Sanity checking for bogus ESC sequences: */
167 if (priv->escape_len >= sizeof(priv->escape_buf))
168 goto error;
Heinrich Schuchardt662f3812018-09-19 21:31:48 +0200169 if (priv->escape_len == 0) {
170 switch (ch) {
171 case '7':
172 /* Save cursor position */
173 get_cursor_position(priv, &priv->row_saved,
174 &priv->col_saved);
175 priv->escape = 0;
176
177 return;
178 case '8': {
179 /* Restore cursor position */
180 int row = priv->row_saved;
181 int col = priv->col_saved;
182
Simon Glass9f62a472023-03-10 12:47:20 -0800183 vidconsole_position_cursor(dev, col, row);
Heinrich Schuchardt662f3812018-09-19 21:31:48 +0200184 priv->escape = 0;
185 return;
186 }
187 case '[':
188 break;
189 default:
190 goto error;
191 }
192 }
Rob Clarka085aa12017-09-13 18:12:21 -0400193
194 priv->escape_buf[priv->escape_len++] = ch;
195
196 /*
197 * Escape sequences are terminated by a letter, so keep
198 * accumulating until we get one:
199 */
200 if (!isalpha(ch))
201 return;
202
203 /*
204 * clear escape mode first, otherwise things will get highly
205 * surprising if you hit any debug prints that come back to
206 * this console.
207 */
208 priv->escape = 0;
209
210 switch (ch) {
Andre Przywara29c158b2019-03-23 01:29:57 +0000211 case 'A':
212 case 'B':
213 case 'C':
214 case 'D':
215 case 'E':
216 case 'F': {
217 int row, col, num;
218 char *s = priv->escape_buf;
219
220 /*
221 * Cursor up/down: [%dA, [%dB, [%dE, [%dF
222 * Cursor left/right: [%dD, [%dC
223 */
224 s++; /* [ */
225 s = parsenum(s, &num);
226 if (num == 0) /* No digit in sequence ... */
227 num = 1; /* ... means "move by 1". */
228
229 get_cursor_position(priv, &row, &col);
230 if (ch == 'A' || ch == 'F')
231 row -= num;
232 if (ch == 'C')
233 col += num;
234 if (ch == 'D')
235 col -= num;
236 if (ch == 'B' || ch == 'E')
237 row += num;
238 if (ch == 'E' || ch == 'F')
239 col = 0;
240 if (col < 0)
241 col = 0;
242 if (row < 0)
243 row = 0;
244 /* Right and bottom overflows are handled in the callee. */
Simon Glass9f62a472023-03-10 12:47:20 -0800245 vidconsole_position_cursor(dev, col, row);
Andre Przywara29c158b2019-03-23 01:29:57 +0000246 break;
247 }
Rob Clarka085aa12017-09-13 18:12:21 -0400248 case 'H':
249 case 'f': {
250 int row, col;
251 char *s = priv->escape_buf;
252
253 /*
254 * Set cursor position: [%d;%df or [%d;%dH
255 */
256 s++; /* [ */
257 s = parsenum(s, &row);
258 s++; /* ; */
259 s = parsenum(s, &col);
260
Heinrich Schuchardt118f0202018-11-10 19:55:48 +0100261 /*
262 * Video origin is [0, 0], terminal origin is [1, 1].
263 */
264 if (row)
265 --row;
266 if (col)
267 --col;
268
Simon Glass9f62a472023-03-10 12:47:20 -0800269 vidconsole_position_cursor(dev, col, row);
Rob Clarka085aa12017-09-13 18:12:21 -0400270
271 break;
272 }
273 case 'J': {
274 int mode;
275
276 /*
277 * Clear part/all screen:
278 * [J or [0J - clear screen from cursor down
279 * [1J - clear screen from cursor up
280 * [2J - clear entire screen
281 *
282 * TODO we really only handle entire-screen case, others
283 * probably require some additions to video-uclass (and
284 * are not really needed yet by efi_console)
285 */
286 parsenum(priv->escape_buf + 1, &mode);
287
288 if (mode == 2) {
Michal Simek9de731f2020-12-14 08:47:52 +0100289 int ret;
290
Rob Clarka085aa12017-09-13 18:12:21 -0400291 video_clear(dev->parent);
Michal Simek9de731f2020-12-14 08:47:52 +0100292 ret = video_sync(dev->parent, false);
293 if (ret) {
294#ifdef DEBUG
295 console_puts_select_stderr(true, "[vc err: video_sync]");
296#endif
297 }
Rob Clarka085aa12017-09-13 18:12:21 -0400298 priv->ycur = 0;
299 priv->xcur_frac = priv->xstart_frac;
300 } else {
301 debug("unsupported clear mode: %d\n", mode);
302 }
303 break;
304 }
Andre Przywara44222942019-03-23 01:29:58 +0000305 case 'K': {
306 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
307 int mode;
308
309 /*
310 * Clear (parts of) current line
311 * [0K - clear line to end
312 * [2K - clear entire line
313 */
314 parsenum(priv->escape_buf + 1, &mode);
315
316 if (mode == 2) {
317 int row, col;
318
319 get_cursor_position(priv, &row, &col);
320 vidconsole_set_row(dev, row, vid_priv->colour_bg);
321 }
322 break;
323 }
Rob Clark703d8852017-09-13 18:12:22 -0400324 case 'm': {
325 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
326 char *s = priv->escape_buf;
327 char *end = &priv->escape_buf[priv->escape_len];
328
329 /*
330 * Set graphics mode: [%d;...;%dm
331 *
332 * Currently only supports the color attributes:
333 *
334 * Foreground Colors:
335 *
336 * 30 Black
337 * 31 Red
338 * 32 Green
339 * 33 Yellow
340 * 34 Blue
341 * 35 Magenta
342 * 36 Cyan
343 * 37 White
344 *
345 * Background Colors:
346 *
347 * 40 Black
348 * 41 Red
349 * 42 Green
350 * 43 Yellow
351 * 44 Blue
352 * 45 Magenta
353 * 46 Cyan
354 * 47 White
355 */
356
357 s++; /* [ */
358 while (s < end) {
359 int val;
360
361 s = parsenum(s, &val);
362 s++;
363
364 switch (val) {
Heinrich Schuchardt9ffa4d12018-02-08 21:47:12 +0100365 case 0:
366 /* all attributes off */
Simon Glassb9f210a2018-11-06 15:21:36 -0700367 video_set_default_colors(dev->parent, false);
Heinrich Schuchardt9ffa4d12018-02-08 21:47:12 +0100368 break;
369 case 1:
370 /* bold */
371 vid_priv->fg_col_idx |= 8;
Simon Glassa032e4b2022-10-06 08:36:03 -0600372 vid_priv->colour_fg = video_index_to_colour(
Heinrich Schuchardt9ffa4d12018-02-08 21:47:12 +0100373 vid_priv, vid_priv->fg_col_idx);
374 break;
Andre Przywaraeabb0722019-03-23 01:29:56 +0000375 case 7:
376 /* reverse video */
Simon Glassa032e4b2022-10-06 08:36:03 -0600377 vid_priv->colour_fg = video_index_to_colour(
Andre Przywaraeabb0722019-03-23 01:29:56 +0000378 vid_priv, vid_priv->bg_col_idx);
Simon Glassa032e4b2022-10-06 08:36:03 -0600379 vid_priv->colour_bg = video_index_to_colour(
Andre Przywaraeabb0722019-03-23 01:29:56 +0000380 vid_priv, vid_priv->fg_col_idx);
381 break;
Rob Clark703d8852017-09-13 18:12:22 -0400382 case 30 ... 37:
Heinrich Schuchardt5c30fbb2018-02-08 21:47:11 +0100383 /* foreground color */
Heinrich Schuchardt9ffa4d12018-02-08 21:47:12 +0100384 vid_priv->fg_col_idx &= ~7;
385 vid_priv->fg_col_idx |= val - 30;
Simon Glassa032e4b2022-10-06 08:36:03 -0600386 vid_priv->colour_fg = video_index_to_colour(
Heinrich Schuchardt9ffa4d12018-02-08 21:47:12 +0100387 vid_priv, vid_priv->fg_col_idx);
Rob Clark703d8852017-09-13 18:12:22 -0400388 break;
389 case 40 ... 47:
Andre Przywaraeabb0722019-03-23 01:29:56 +0000390 /* background color, also mask the bold bit */
391 vid_priv->bg_col_idx &= ~0xf;
392 vid_priv->bg_col_idx |= val - 40;
Simon Glassa032e4b2022-10-06 08:36:03 -0600393 vid_priv->colour_bg = video_index_to_colour(
Andre Przywaraeabb0722019-03-23 01:29:56 +0000394 vid_priv, vid_priv->bg_col_idx);
Rob Clark703d8852017-09-13 18:12:22 -0400395 break;
396 default:
Heinrich Schuchardt5c30fbb2018-02-08 21:47:11 +0100397 /* ignore unsupported SGR parameter */
Rob Clark703d8852017-09-13 18:12:22 -0400398 break;
399 }
400 }
401
402 break;
403 }
Rob Clarka085aa12017-09-13 18:12:21 -0400404 default:
405 debug("unrecognized escape sequence: %*s\n",
406 priv->escape_len, priv->escape_buf);
407 }
408
409 return;
410
411error:
412 /* something went wrong, just revert to normal mode: */
413 priv->escape = 0;
414}
415
Andre Przywara7035ec32019-03-23 01:29:59 +0000416/* Put that actual character on the screen (using the CP437 code page). */
417static int vidconsole_output_glyph(struct udevice *dev, char ch)
418{
419 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
420 int ret;
421
422 /*
423 * Failure of this function normally indicates an unsupported
424 * colour depth. Check this and return an error to help with
425 * diagnosis.
426 */
427 ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch);
428 if (ret == -EAGAIN) {
429 vidconsole_newline(dev);
430 ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch);
431 }
432 if (ret < 0)
433 return ret;
434 priv->xcur_frac += ret;
435 priv->last_ch = ch;
436 if (priv->xcur_frac >= priv->xsize_frac)
437 vidconsole_newline(dev);
438
439 return 0;
440}
441
Simon Glass83510762016-01-18 19:52:17 -0700442int vidconsole_put_char(struct udevice *dev, char ch)
443{
444 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
445 int ret;
446
Rob Clarka085aa12017-09-13 18:12:21 -0400447 if (priv->escape) {
448 vidconsole_escape_char(dev, ch);
449 return 0;
450 }
451
Simon Glass83510762016-01-18 19:52:17 -0700452 switch (ch) {
Rob Clarka085aa12017-09-13 18:12:21 -0400453 case '\x1b':
454 priv->escape_len = 0;
455 priv->escape = 1;
456 break;
Simon Glass5508f102016-01-14 18:10:38 -0700457 case '\a':
458 /* beep */
459 break;
Simon Glass83510762016-01-18 19:52:17 -0700460 case '\r':
Simon Glassc5b77d02016-01-14 18:10:39 -0700461 priv->xcur_frac = priv->xstart_frac;
Simon Glass83510762016-01-18 19:52:17 -0700462 break;
463 case '\n':
464 vidconsole_newline(dev);
Simon Glass58c733a2016-01-14 18:10:40 -0700465 vidconsole_entry_start(dev);
Simon Glass83510762016-01-18 19:52:17 -0700466 break;
467 case '\t': /* Tab (8 chars alignment) */
Simon Glassf2661782016-01-14 18:10:37 -0700468 priv->xcur_frac = ((priv->xcur_frac / priv->tab_width_frac)
469 + 1) * priv->tab_width_frac;
Simon Glass83510762016-01-18 19:52:17 -0700470
Simon Glassf2661782016-01-14 18:10:37 -0700471 if (priv->xcur_frac >= priv->xsize_frac)
Simon Glass83510762016-01-18 19:52:17 -0700472 vidconsole_newline(dev);
473 break;
474 case '\b':
475 vidconsole_back(dev);
Simon Glass58c733a2016-01-14 18:10:40 -0700476 priv->last_ch = 0;
Simon Glass83510762016-01-18 19:52:17 -0700477 break;
478 default:
Andre Przywara7035ec32019-03-23 01:29:59 +0000479 ret = vidconsole_output_glyph(dev, ch);
Simon Glassf2661782016-01-14 18:10:37 -0700480 if (ret < 0)
Simon Glass83510762016-01-18 19:52:17 -0700481 return ret;
Simon Glass83510762016-01-18 19:52:17 -0700482 break;
483 }
484
485 return 0;
486}
487
Marek Vasute63168a2019-05-17 20:22:31 +0200488int vidconsole_put_string(struct udevice *dev, const char *str)
489{
490 const char *s;
491 int ret;
492
493 for (s = str; *s; s++) {
494 ret = vidconsole_put_char(dev, *s);
495 if (ret)
496 return ret;
497 }
498
499 return 0;
500}
501
Simon Glass83510762016-01-18 19:52:17 -0700502static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
503{
504 struct udevice *dev = sdev->priv;
Simon Glass8b763df2020-07-02 21:12:14 -0600505 int ret;
Simon Glass83510762016-01-18 19:52:17 -0700506
Simon Glass8b763df2020-07-02 21:12:14 -0600507 ret = vidconsole_put_char(dev, ch);
508 if (ret) {
509#ifdef DEBUG
510 console_puts_select_stderr(true, "[vc err: putc]");
511#endif
512 }
Michal Simek9de731f2020-12-14 08:47:52 +0100513 ret = video_sync(dev->parent, false);
514 if (ret) {
515#ifdef DEBUG
516 console_puts_select_stderr(true, "[vc err: video_sync]");
517#endif
518 }
Simon Glass83510762016-01-18 19:52:17 -0700519}
520
521static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
522{
523 struct udevice *dev = sdev->priv;
Simon Glass8b763df2020-07-02 21:12:14 -0600524 int ret;
Simon Glass83510762016-01-18 19:52:17 -0700525
Simon Glass8b763df2020-07-02 21:12:14 -0600526 ret = vidconsole_put_string(dev, s);
527 if (ret) {
528#ifdef DEBUG
529 char str[30];
530
531 snprintf(str, sizeof(str), "[vc err: puts %d]", ret);
532 console_puts_select_stderr(true, str);
533#endif
534 }
Michal Simek9de731f2020-12-14 08:47:52 +0100535 ret = video_sync(dev->parent, false);
536 if (ret) {
537#ifdef DEBUG
538 console_puts_select_stderr(true, "[vc err: video_sync]");
539#endif
540 }
Simon Glass83510762016-01-18 19:52:17 -0700541}
542
Simon Glass0e38bd82023-01-06 08:52:32 -0600543void vidconsole_list_fonts(struct udevice *dev)
544{
545 struct vidfont_info info;
546 int ret, i;
547
548 for (i = 0, ret = 0; !ret; i++) {
549 ret = vidconsole_get_font(dev, i, &info);
550 if (!ret)
551 printf("%s\n", info.name);
552 }
553}
554
555int vidconsole_get_font(struct udevice *dev, int seq,
556 struct vidfont_info *info)
557{
558 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
559
560 if (!ops->get_font)
561 return -ENOSYS;
562
563 return ops->get_font(dev, seq, info);
564}
565
Dzmitry Sankouski4f6e3482023-03-07 13:21:15 +0300566int vidconsole_get_font_size(struct udevice *dev, const char **name, uint *sizep)
567{
568 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
569
570 if (!ops->get_font_size)
571 return -ENOSYS;
572
573 *name = ops->get_font_size(dev, sizep);
574 return 0;
575}
576
Simon Glass0e38bd82023-01-06 08:52:32 -0600577int vidconsole_select_font(struct udevice *dev, const char *name, uint size)
578{
579 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
580
581 if (!ops->select_font)
582 return -ENOSYS;
583
584 return ops->select_font(dev, name, size);
585}
586
Simon Glass83510762016-01-18 19:52:17 -0700587/* Set up the number of rows and colours (rotated drivers override this) */
588static int vidconsole_pre_probe(struct udevice *dev)
589{
590 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
591 struct udevice *vid = dev->parent;
592 struct video_priv *vid_priv = dev_get_uclass_priv(vid);
593
Simon Glassf2661782016-01-14 18:10:37 -0700594 priv->xsize_frac = VID_TO_POS(vid_priv->xsize);
Simon Glass83510762016-01-18 19:52:17 -0700595
596 return 0;
597}
598
599/* Register the device with stdio */
600static int vidconsole_post_probe(struct udevice *dev)
601{
602 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
603 struct stdio_dev *sdev = &priv->sdev;
Simon Glass83510762016-01-18 19:52:17 -0700604
Simon Glassf2661782016-01-14 18:10:37 -0700605 if (!priv->tab_width_frac)
606 priv->tab_width_frac = VID_TO_POS(priv->x_charsize) * 8;
607
Simon Glass8b85dfc2020-12-16 21:20:07 -0700608 if (dev_seq(dev)) {
Simon Glassf1a12472016-01-21 19:44:51 -0700609 snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d",
Simon Glass8b85dfc2020-12-16 21:20:07 -0700610 dev_seq(dev));
Simon Glassf1a12472016-01-21 19:44:51 -0700611 } else {
612 strcpy(sdev->name, "vidconsole");
613 }
Simon Glassf2661782016-01-14 18:10:37 -0700614
Simon Glass83510762016-01-18 19:52:17 -0700615 sdev->flags = DEV_FLAGS_OUTPUT;
616 sdev->putc = vidconsole_putc;
617 sdev->puts = vidconsole_puts;
618 sdev->priv = dev;
Simon Glass83510762016-01-18 19:52:17 -0700619
Masahiro Yamada720873b2016-09-06 22:17:33 +0900620 return stdio_register(sdev);
Simon Glass83510762016-01-18 19:52:17 -0700621}
622
623UCLASS_DRIVER(vidconsole) = {
624 .id = UCLASS_VIDEO_CONSOLE,
625 .name = "vidconsole0",
626 .pre_probe = vidconsole_pre_probe,
627 .post_probe = vidconsole_post_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700628 .per_device_auto = sizeof(struct vidconsole_priv),
Simon Glass83510762016-01-18 19:52:17 -0700629};
630
Simon Glass8c0b5d22020-07-02 21:12:23 -0600631#ifdef CONFIG_VIDEO_COPY
632int vidconsole_sync_copy(struct udevice *dev, void *from, void *to)
633{
634 struct udevice *vid = dev_get_parent(dev);
635
636 return video_sync_copy(vid, from, to);
637}
638
639int vidconsole_memmove(struct udevice *dev, void *dst, const void *src,
640 int size)
641{
642 memmove(dst, src, size);
643 return vidconsole_sync_copy(dev, dst, dst + size);
644}
645#endif
Simon Glassa76b60f2023-03-10 12:47:21 -0800646
647int vidconsole_clear_and_reset(struct udevice *dev)
648{
649 int ret;
650
651 ret = video_clear(dev_get_parent(dev));
652 if (ret)
653 return ret;
654 vidconsole_position_cursor(dev, 0, 0);
655
656 return 0;
657}