blob: a312a1985242c2a5374f5b391630d5940e7c56a1 [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 Glass9899eef2023-10-01 19:13:19 -060013#include <abuf.h>
Simon Glass09140112020-05-10 11:40:03 -060014#include <command.h>
Simon Glass8b763df2020-07-02 21:12:14 -060015#include <console.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060016#include <log.h>
Simon Glass83510762016-01-18 19:52:17 -070017#include <dm.h>
18#include <video.h>
19#include <video_console.h>
Heinrich Schuchardt5fba5322018-03-02 20:50:17 +010020#include <video_font.h> /* Bitmap font for code page 437 */
Simon Glass8b763df2020-07-02 21:12:14 -060021#include <linux/ctype.h>
Simon Glass83510762016-01-18 19:52:17 -070022
Simon Glass83510762016-01-18 19:52:17 -070023int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char 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
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 Glass617d7b52023-10-01 19:13:20 -060051int vidconsole_entry_start(struct udevice *dev)
Simon Glass58c733a2016-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 Glass83510762016-01-18 19:52:17 -070060/* Move backwards one space */
Simon Glass7b9f7e42016-01-14 18:10:41 -070061static int vidconsole_back(struct udevice *dev)
Simon Glass83510762016-01-18 19:52:17 -070062{
63 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
Simon Glass7b9f7e42016-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 Glass83510762016-01-18 19:52:17 -070072
Simon Glassf2661782016-01-14 18:10:37 -070073 priv->xcur_frac -= VID_TO_POS(priv->x_charsize);
Simon Glassc5b77d02016-01-14 18:10:39 -070074 if (priv->xcur_frac < priv->xstart_frac) {
Simon Glassf2661782016-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 Glass83510762016-01-18 19:52:17 -070080 }
Michal Simek9de731f2020-12-14 08:47:52 +010081 return video_sync(dev->parent, false);
Simon Glass83510762016-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 Jain86fbee62023-04-20 17:41:08 +053090 const int rows = CONFIG_VAL(CONSOLE_SCROLL_LINES);
Michal Simek9de731f2020-12-14 08:47:52 +010091 int i, ret;
Simon Glass83510762016-01-18 19:52:17 -070092
Simon Glassc5b77d02016-01-14 18:10:39 -070093 priv->xcur_frac = priv->xstart_frac;
Simon Glassf2661782016-01-14 18:10:37 -070094 priv->ycur += priv->y_charsize;
Simon Glass83510762016-01-18 19:52:17 -070095
96 /* Check if we need to scroll the terminal */
Simon Glassf2661782016-01-14 18:10:37 -070097 if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) {
Simon Glass83510762016-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 Glassf2661782016-01-14 18:10:37 -0700102 priv->ycur -= rows * priv->y_charsize;
Simon Glass83510762016-01-18 19:52:17 -0700103 }
Simon Glass58c733a2016-01-14 18:10:40 -0700104 priv->last_ch = 0;
105
Michal Simek9de731f2020-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 Glass83510762016-01-18 19:52:17 -0700112}
113
Rob Clarka085aa12017-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 Glass6b6dc0d2022-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 Glass9e95e902024-01-04 08:10:37 -0700128 vidconsole_entry_start(dev);
Simon Glass6b6dc0d2022-10-06 08:36:04 -0600129}
130
Tom Rinif6546c72023-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 Glass9e95e902024-01-04 08:10:37 -0700138static void set_cursor_position(struct udevice *dev, int row, int col)
Heinrich Schuchardt662f3812018-09-19 21:31:48 +0200139{
Simon Glass9e95e902024-01-04 08:10:37 -0700140 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
141
Tom Rinif6546c72023-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 Schuchardt662f3812018-09-19 21:31:48 +0200149
Simon Glass9e95e902024-01-04 08:10:37 -0700150 vidconsole_position_cursor(dev, col, row);
Heinrich Schuchardt662f3812018-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 Clarka085aa12017-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 Schuchardt662f3812018-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 Glass9e95e902024-01-04 08:10:37 -0700197 set_cursor_position(dev, row, col);
Heinrich Schuchardt662f3812018-09-19 21:31:48 +0200198 priv->escape = 0;
199 return;
200 }
201 case '[':
202 break;
203 default:
204 goto error;
205 }
206 }
Rob Clarka085aa12017-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 Przywara29c158b2019-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 Glass9e95e902024-01-04 08:10:37 -0700259 set_cursor_position(dev, row, col);
Andre Przywara29c158b2019-03-23 01:29:57 +0000260 break;
261 }
Rob Clarka085aa12017-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 Schuchardt118f0202018-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 Glass9e95e902024-01-04 08:10:37 -0700283 set_cursor_position(dev, row, col);
Rob Clarka085aa12017-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 Simek9de731f2020-12-14 08:47:52 +0100303 int ret;
304
Rob Clarka085aa12017-09-13 18:12:21 -0400305 video_clear(dev->parent);
Michal Simek9de731f2020-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 Clarka085aa12017-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 Przywara44222942019-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 Clark703d8852017-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 Schuchardt9ffa4d12018-02-08 21:47:12 +0100379 case 0:
380 /* all attributes off */
Simon Glassb9f210a2018-11-06 15:21:36 -0700381 video_set_default_colors(dev->parent, false);
Heinrich Schuchardt9ffa4d12018-02-08 21:47:12 +0100382 break;
383 case 1:
384 /* bold */
385 vid_priv->fg_col_idx |= 8;
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);
388 break;
Andre Przywaraeabb0722019-03-23 01:29:56 +0000389 case 7:
390 /* reverse video */
Simon Glassa032e4b2022-10-06 08:36:03 -0600391 vid_priv->colour_fg = video_index_to_colour(
Andre Przywaraeabb0722019-03-23 01:29:56 +0000392 vid_priv, vid_priv->bg_col_idx);
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->fg_col_idx);
395 break;
Rob Clark703d8852017-09-13 18:12:22 -0400396 case 30 ... 37:
Heinrich Schuchardt5c30fbb2018-02-08 21:47:11 +0100397 /* foreground color */
Heinrich Schuchardt9ffa4d12018-02-08 21:47:12 +0100398 vid_priv->fg_col_idx &= ~7;
399 vid_priv->fg_col_idx |= val - 30;
Simon Glassa032e4b2022-10-06 08:36:03 -0600400 vid_priv->colour_fg = video_index_to_colour(
Heinrich Schuchardt9ffa4d12018-02-08 21:47:12 +0100401 vid_priv, vid_priv->fg_col_idx);
Rob Clark703d8852017-09-13 18:12:22 -0400402 break;
403 case 40 ... 47:
Andre Przywaraeabb0722019-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 Glassa032e4b2022-10-06 08:36:03 -0600407 vid_priv->colour_bg = video_index_to_colour(
Andre Przywaraeabb0722019-03-23 01:29:56 +0000408 vid_priv, vid_priv->bg_col_idx);
Rob Clark703d8852017-09-13 18:12:22 -0400409 break;
410 default:
Heinrich Schuchardt5c30fbb2018-02-08 21:47:11 +0100411 /* ignore unsupported SGR parameter */
Rob Clark703d8852017-09-13 18:12:22 -0400412 break;
413 }
414 }
415
416 break;
417 }
Rob Clarka085aa12017-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
Andre Przywara7035ec32019-03-23 01:29:59 +0000430/* Put that actual character on the screen (using the CP437 code page). */
431static int vidconsole_output_glyph(struct udevice *dev, char ch)
432{
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 Glass83510762016-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);
459 int ret;
460
Rob Clarka085aa12017-09-13 18:12:21 -0400461 if (priv->escape) {
462 vidconsole_escape_char(dev, ch);
463 return 0;
464 }
465
Simon Glass83510762016-01-18 19:52:17 -0700466 switch (ch) {
Rob Clarka085aa12017-09-13 18:12:21 -0400467 case '\x1b':
468 priv->escape_len = 0;
469 priv->escape = 1;
470 break;
Simon Glass5508f102016-01-14 18:10:38 -0700471 case '\a':
472 /* beep */
473 break;
Simon Glass83510762016-01-18 19:52:17 -0700474 case '\r':
Simon Glassc5b77d02016-01-14 18:10:39 -0700475 priv->xcur_frac = priv->xstart_frac;
Simon Glass83510762016-01-18 19:52:17 -0700476 break;
477 case '\n':
478 vidconsole_newline(dev);
Simon Glass58c733a2016-01-14 18:10:40 -0700479 vidconsole_entry_start(dev);
Simon Glass83510762016-01-18 19:52:17 -0700480 break;
481 case '\t': /* Tab (8 chars alignment) */
Simon Glassf2661782016-01-14 18:10:37 -0700482 priv->xcur_frac = ((priv->xcur_frac / priv->tab_width_frac)
483 + 1) * priv->tab_width_frac;
Simon Glass83510762016-01-18 19:52:17 -0700484
Simon Glassf2661782016-01-14 18:10:37 -0700485 if (priv->xcur_frac >= priv->xsize_frac)
Simon Glass83510762016-01-18 19:52:17 -0700486 vidconsole_newline(dev);
487 break;
488 case '\b':
489 vidconsole_back(dev);
Simon Glass58c733a2016-01-14 18:10:40 -0700490 priv->last_ch = 0;
Simon Glass83510762016-01-18 19:52:17 -0700491 break;
492 default:
Andre Przywara7035ec32019-03-23 01:29:59 +0000493 ret = vidconsole_output_glyph(dev, ch);
Simon Glassf2661782016-01-14 18:10:37 -0700494 if (ret < 0)
Simon Glass83510762016-01-18 19:52:17 -0700495 return ret;
Simon Glass83510762016-01-18 19:52:17 -0700496 break;
497 }
498
499 return 0;
500}
501
Marek Vasute63168a2019-05-17 20:22:31 +0200502int vidconsole_put_string(struct udevice *dev, const char *str)
503{
504 const char *s;
505 int ret;
506
507 for (s = str; *s; s++) {
508 ret = vidconsole_put_char(dev, *s);
509 if (ret)
510 return ret;
511 }
512
513 return 0;
514}
515
Simon Glass83510762016-01-18 19:52:17 -0700516static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
517{
518 struct udevice *dev = sdev->priv;
Simon Glass8b763df2020-07-02 21:12:14 -0600519 int ret;
Simon Glass83510762016-01-18 19:52:17 -0700520
Simon Glass8b763df2020-07-02 21:12:14 -0600521 ret = vidconsole_put_char(dev, ch);
522 if (ret) {
523#ifdef DEBUG
524 console_puts_select_stderr(true, "[vc err: putc]");
525#endif
526 }
Michal Simek9de731f2020-12-14 08:47:52 +0100527 ret = video_sync(dev->parent, false);
528 if (ret) {
529#ifdef DEBUG
530 console_puts_select_stderr(true, "[vc err: video_sync]");
531#endif
532 }
Simon Glass83510762016-01-18 19:52:17 -0700533}
534
535static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
536{
537 struct udevice *dev = sdev->priv;
Simon Glass8b763df2020-07-02 21:12:14 -0600538 int ret;
Simon Glass83510762016-01-18 19:52:17 -0700539
Simon Glass8b763df2020-07-02 21:12:14 -0600540 ret = vidconsole_put_string(dev, s);
541 if (ret) {
542#ifdef DEBUG
543 char str[30];
544
545 snprintf(str, sizeof(str), "[vc err: puts %d]", ret);
546 console_puts_select_stderr(true, str);
547#endif
548 }
Michal Simek9de731f2020-12-14 08:47:52 +0100549 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 }
Simon Glass83510762016-01-18 19:52:17 -0700555}
556
Simon Glass0e38bd82023-01-06 08:52:32 -0600557void vidconsole_list_fonts(struct udevice *dev)
558{
559 struct vidfont_info info;
560 int ret, i;
561
562 for (i = 0, ret = 0; !ret; i++) {
563 ret = vidconsole_get_font(dev, i, &info);
564 if (!ret)
565 printf("%s\n", info.name);
566 }
567}
568
569int vidconsole_get_font(struct udevice *dev, int seq,
570 struct vidfont_info *info)
571{
572 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
573
574 if (!ops->get_font)
575 return -ENOSYS;
576
577 return ops->get_font(dev, seq, info);
578}
579
Dzmitry Sankouski4f6e3482023-03-07 13:21:15 +0300580int vidconsole_get_font_size(struct udevice *dev, const char **name, uint *sizep)
581{
582 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
583
584 if (!ops->get_font_size)
585 return -ENOSYS;
586
587 *name = ops->get_font_size(dev, sizep);
588 return 0;
589}
590
Simon Glass0e38bd82023-01-06 08:52:32 -0600591int vidconsole_select_font(struct udevice *dev, const char *name, uint size)
592{
593 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
594
595 if (!ops->select_font)
596 return -ENOSYS;
597
598 return ops->select_font(dev, name, size);
599}
600
Simon Glassb828ed72023-06-01 10:22:46 -0600601int vidconsole_measure(struct udevice *dev, const char *name, uint size,
602 const char *text, struct vidconsole_bbox *bbox)
603{
604 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
605 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
606 int ret;
607
Bin Meng01c76f12023-08-03 17:32:41 +0800608 if (ops->measure) {
Simon Glassb828ed72023-06-01 10:22:46 -0600609 ret = ops->measure(dev, name, size, text, bbox);
610 if (ret != -ENOSYS)
611 return ret;
612 }
613
614 bbox->valid = true;
615 bbox->x0 = 0;
616 bbox->y0 = 0;
617 bbox->x1 = priv->x_charsize * strlen(text);
618 bbox->y1 = priv->y_charsize;
619
620 return 0;
621}
622
Simon Glass9e55d092023-10-01 19:13:18 -0600623int vidconsole_nominal(struct udevice *dev, const char *name, uint size,
624 uint num_chars, struct vidconsole_bbox *bbox)
625{
626 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
627 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
628 int ret;
629
630 if (ops->measure) {
631 ret = ops->nominal(dev, name, size, num_chars, bbox);
632 if (ret != -ENOSYS)
633 return ret;
634 }
635
636 bbox->valid = true;
637 bbox->x0 = 0;
638 bbox->y0 = 0;
639 bbox->x1 = priv->x_charsize * num_chars;
640 bbox->y1 = priv->y_charsize;
641
642 return 0;
643}
644
Simon Glass9899eef2023-10-01 19:13:19 -0600645int vidconsole_entry_save(struct udevice *dev, struct abuf *buf)
646{
647 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
648 int ret;
649
650 if (ops->measure) {
651 ret = ops->entry_save(dev, buf);
652 if (ret != -ENOSYS)
653 return ret;
654 }
655
656 /* no data so make sure the buffer is empty */
657 abuf_realloc(buf, 0);
658
659 return 0;
660}
661
662int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf)
663{
664 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
665 int ret;
666
667 if (ops->measure) {
668 ret = ops->entry_restore(dev, buf);
669 if (ret != -ENOSYS)
670 return ret;
671 }
672
673 return 0;
674}
675
Simon Glass37db20d2023-10-01 19:13:21 -0600676int vidconsole_set_cursor_visible(struct udevice *dev, bool visible,
677 uint x, uint y, uint index)
678{
679 struct vidconsole_ops *ops = vidconsole_get_ops(dev);
680 int ret;
681
682 if (ops->set_cursor_visible) {
683 ret = ops->set_cursor_visible(dev, visible, x, y, index);
684 if (ret != -ENOSYS)
685 return ret;
686 }
687
688 return 0;
689}
690
Simon Glass648a4992023-06-01 10:22:45 -0600691void vidconsole_push_colour(struct udevice *dev, enum colour_idx fg,
692 enum colour_idx bg, struct vidconsole_colour *old)
693{
694 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
695
696 old->colour_fg = vid_priv->colour_fg;
697 old->colour_bg = vid_priv->colour_bg;
698
699 vid_priv->colour_fg = video_index_to_colour(vid_priv, fg);
700 vid_priv->colour_bg = video_index_to_colour(vid_priv, bg);
701}
702
703void vidconsole_pop_colour(struct udevice *dev, struct vidconsole_colour *old)
704{
705 struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
706
707 vid_priv->colour_fg = old->colour_fg;
708 vid_priv->colour_bg = old->colour_bg;
709}
710
Simon Glass83510762016-01-18 19:52:17 -0700711/* Set up the number of rows and colours (rotated drivers override this) */
712static int vidconsole_pre_probe(struct udevice *dev)
713{
714 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
715 struct udevice *vid = dev->parent;
716 struct video_priv *vid_priv = dev_get_uclass_priv(vid);
717
Simon Glassf2661782016-01-14 18:10:37 -0700718 priv->xsize_frac = VID_TO_POS(vid_priv->xsize);
Simon Glass83510762016-01-18 19:52:17 -0700719
720 return 0;
721}
722
723/* Register the device with stdio */
724static int vidconsole_post_probe(struct udevice *dev)
725{
726 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
727 struct stdio_dev *sdev = &priv->sdev;
Simon Glass83510762016-01-18 19:52:17 -0700728
Simon Glassf2661782016-01-14 18:10:37 -0700729 if (!priv->tab_width_frac)
730 priv->tab_width_frac = VID_TO_POS(priv->x_charsize) * 8;
731
Simon Glass8b85dfc2020-12-16 21:20:07 -0700732 if (dev_seq(dev)) {
Simon Glassf1a12472016-01-21 19:44:51 -0700733 snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d",
Simon Glass8b85dfc2020-12-16 21:20:07 -0700734 dev_seq(dev));
Simon Glassf1a12472016-01-21 19:44:51 -0700735 } else {
736 strcpy(sdev->name, "vidconsole");
737 }
Simon Glassf2661782016-01-14 18:10:37 -0700738
Simon Glass83510762016-01-18 19:52:17 -0700739 sdev->flags = DEV_FLAGS_OUTPUT;
740 sdev->putc = vidconsole_putc;
741 sdev->puts = vidconsole_puts;
742 sdev->priv = dev;
Simon Glass83510762016-01-18 19:52:17 -0700743
Masahiro Yamada720873b2016-09-06 22:17:33 +0900744 return stdio_register(sdev);
Simon Glass83510762016-01-18 19:52:17 -0700745}
746
747UCLASS_DRIVER(vidconsole) = {
748 .id = UCLASS_VIDEO_CONSOLE,
749 .name = "vidconsole0",
750 .pre_probe = vidconsole_pre_probe,
751 .post_probe = vidconsole_post_probe,
Simon Glass41575d82020-12-03 16:55:17 -0700752 .per_device_auto = sizeof(struct vidconsole_priv),
Simon Glass83510762016-01-18 19:52:17 -0700753};
754
Simon Glass8c0b5d22020-07-02 21:12:23 -0600755#ifdef CONFIG_VIDEO_COPY
756int vidconsole_sync_copy(struct udevice *dev, void *from, void *to)
757{
758 struct udevice *vid = dev_get_parent(dev);
759
760 return video_sync_copy(vid, from, to);
761}
762
763int vidconsole_memmove(struct udevice *dev, void *dst, const void *src,
764 int size)
765{
766 memmove(dst, src, size);
767 return vidconsole_sync_copy(dev, dst, dst + size);
768}
769#endif
Simon Glassa76b60f2023-03-10 12:47:21 -0800770
771int vidconsole_clear_and_reset(struct udevice *dev)
772{
773 int ret;
774
775 ret = video_clear(dev_get_parent(dev));
776 if (ret)
777 return ret;
778 vidconsole_position_cursor(dev, 0, 0);
779
780 return 0;
781}
Tom Rinif6546c72023-03-15 11:58:58 -0400782
783void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row)
784{
785 struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
786 struct udevice *vid_dev = dev->parent;
787 struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
788 short x, y;
789
790 x = min_t(short, col * priv->x_charsize, vid_priv->xsize - 1);
791 y = min_t(short, row * priv->y_charsize, vid_priv->ysize - 1);
792 vidconsole_set_cursor_pos(dev, x, y);
793}