2 * Copyright (c) 2015 Google, Inc
3 * (C) Copyright 2001-2015
4 * DENX Software Engineering -- wd@denx.de
5 * Compulab Ltd - http://compulab.co.il/
6 * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
8 * SPDX-License-Identifier: GPL-2.0+
14 #include <video_console.h>
15 #include <video_font.h> /* Get font data, width and height */
17 /* By default we scroll by a single line */
18 #ifndef CONFIG_CONSOLE_SCROLL_LINES
19 #define CONFIG_CONSOLE_SCROLL_LINES 1
22 int vidconsole_putc_xy(struct udevice
*dev
, uint x
, uint y
, char ch
)
24 struct vidconsole_ops
*ops
= vidconsole_get_ops(dev
);
28 return ops
->putc_xy(dev
, x
, y
, ch
);
31 int vidconsole_move_rows(struct udevice
*dev
, uint rowdst
, uint rowsrc
,
34 struct vidconsole_ops
*ops
= vidconsole_get_ops(dev
);
38 return ops
->move_rows(dev
, rowdst
, rowsrc
, count
);
41 int vidconsole_set_row(struct udevice
*dev
, uint row
, int clr
)
43 struct vidconsole_ops
*ops
= vidconsole_get_ops(dev
);
47 return ops
->set_row(dev
, row
, clr
);
50 static int vidconsole_entry_start(struct udevice
*dev
)
52 struct vidconsole_ops
*ops
= vidconsole_get_ops(dev
);
54 if (!ops
->entry_start
)
56 return ops
->entry_start(dev
);
59 /* Move backwards one space */
60 static int vidconsole_back(struct udevice
*dev
)
62 struct vidconsole_priv
*priv
= dev_get_uclass_priv(dev
);
63 struct vidconsole_ops
*ops
= vidconsole_get_ops(dev
);
67 ret
= ops
->backspace(dev
);
72 priv
->xcur_frac
-= VID_TO_POS(priv
->x_charsize
);
73 if (priv
->xcur_frac
< priv
->xstart_frac
) {
74 priv
->xcur_frac
= (priv
->cols
- 1) *
75 VID_TO_POS(priv
->x_charsize
);
76 priv
->ycur
-= priv
->y_charsize
;
84 /* Move to a newline, scrolling the display if necessary */
85 static void vidconsole_newline(struct udevice
*dev
)
87 struct vidconsole_priv
*priv
= dev_get_uclass_priv(dev
);
88 struct udevice
*vid_dev
= dev
->parent
;
89 struct video_priv
*vid_priv
= dev_get_uclass_priv(vid_dev
);
90 const int rows
= CONFIG_CONSOLE_SCROLL_LINES
;
93 priv
->xcur_frac
= priv
->xstart_frac
;
94 priv
->ycur
+= priv
->y_charsize
;
96 /* Check if we need to scroll the terminal */
97 if ((priv
->ycur
+ priv
->y_charsize
) / priv
->y_charsize
> priv
->rows
) {
98 vidconsole_move_rows(dev
, 0, rows
, priv
->rows
- rows
);
99 for (i
= 0; i
< rows
; i
++)
100 vidconsole_set_row(dev
, priv
->rows
- i
- 1,
101 vid_priv
->colour_bg
);
102 priv
->ycur
-= rows
* priv
->y_charsize
;
106 video_sync(dev
->parent
);
109 int vidconsole_put_char(struct udevice
*dev
, char ch
)
111 struct vidconsole_priv
*priv
= dev_get_uclass_priv(dev
);
119 priv
->xcur_frac
= priv
->xstart_frac
;
122 vidconsole_newline(dev
);
123 vidconsole_entry_start(dev
);
125 case '\t': /* Tab (8 chars alignment) */
126 priv
->xcur_frac
= ((priv
->xcur_frac
/ priv
->tab_width_frac
)
127 + 1) * priv
->tab_width_frac
;
129 if (priv
->xcur_frac
>= priv
->xsize_frac
)
130 vidconsole_newline(dev
);
133 vidconsole_back(dev
);
138 * Failure of this function normally indicates an unsupported
139 * colour depth. Check this and return an error to help with
142 ret
= vidconsole_putc_xy(dev
, priv
->xcur_frac
, priv
->ycur
, ch
);
143 if (ret
== -EAGAIN
) {
144 vidconsole_newline(dev
);
145 ret
= vidconsole_putc_xy(dev
, priv
->xcur_frac
,
150 priv
->xcur_frac
+= ret
;
152 if (priv
->xcur_frac
>= priv
->xsize_frac
)
153 vidconsole_newline(dev
);
160 static void vidconsole_putc(struct stdio_dev
*sdev
, const char ch
)
162 struct udevice
*dev
= sdev
->priv
;
164 vidconsole_put_char(dev
, ch
);
167 static void vidconsole_puts(struct stdio_dev
*sdev
, const char *s
)
169 struct udevice
*dev
= sdev
->priv
;
172 vidconsole_put_char(dev
, *s
++);
173 video_sync(dev
->parent
);
176 /* Set up the number of rows and colours (rotated drivers override this) */
177 static int vidconsole_pre_probe(struct udevice
*dev
)
179 struct vidconsole_priv
*priv
= dev_get_uclass_priv(dev
);
180 struct udevice
*vid
= dev
->parent
;
181 struct video_priv
*vid_priv
= dev_get_uclass_priv(vid
);
183 priv
->xsize_frac
= VID_TO_POS(vid_priv
->xsize
);
188 /* Register the device with stdio */
189 static int vidconsole_post_probe(struct udevice
*dev
)
191 struct vidconsole_priv
*priv
= dev_get_uclass_priv(dev
);
192 struct stdio_dev
*sdev
= &priv
->sdev
;
194 if (!priv
->tab_width_frac
)
195 priv
->tab_width_frac
= VID_TO_POS(priv
->x_charsize
) * 8;
198 snprintf(sdev
->name
, sizeof(sdev
->name
), "vidconsole%d",
201 strcpy(sdev
->name
, "vidconsole");
204 sdev
->flags
= DEV_FLAGS_OUTPUT
;
205 sdev
->putc
= vidconsole_putc
;
206 sdev
->puts
= vidconsole_puts
;
209 return stdio_register(sdev
);
212 UCLASS_DRIVER(vidconsole
) = {
213 .id
= UCLASS_VIDEO_CONSOLE
,
214 .name
= "vidconsole0",
215 .pre_probe
= vidconsole_pre_probe
,
216 .post_probe
= vidconsole_post_probe
,
217 .per_device_auto_alloc_size
= sizeof(struct vidconsole_priv
),
220 void vidconsole_position_cursor(struct udevice
*dev
, unsigned col
, unsigned row
)
222 struct vidconsole_priv
*priv
= dev_get_uclass_priv(dev
);
223 struct udevice
*vid_dev
= dev
->parent
;
224 struct video_priv
*vid_priv
= dev_get_uclass_priv(vid_dev
);
226 priv
->xcur_frac
= VID_TO_POS(min_t(short, col
, vid_priv
->xsize
- 1));
227 priv
->ycur
= min_t(short, row
, vid_priv
->ysize
- 1);
230 static int do_video_setcursor(cmd_tbl_t
*cmdtp
, int flag
, int argc
,
233 unsigned int col
, row
;
237 return CMD_RET_USAGE
;
239 if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE
, &dev
))
240 return CMD_RET_FAILURE
;
241 col
= simple_strtoul(argv
[1], NULL
, 10);
242 row
= simple_strtoul(argv
[2], NULL
, 10);
243 vidconsole_position_cursor(dev
, col
, row
);
248 static int do_video_puts(cmd_tbl_t
*cmdtp
, int flag
, int argc
,
255 return CMD_RET_USAGE
;
257 if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE
, &dev
))
258 return CMD_RET_FAILURE
;
259 for (s
= argv
[1]; *s
; s
++)
260 vidconsole_put_char(dev
, *s
);
266 setcurs
, 3, 1, do_video_setcursor
,
267 "set cursor position within screen",
268 " <col> <row> in character"
272 lcdputs
, 2, 1, do_video_puts
,
273 "print string on video framebuffer",