]> git.sur5r.net Git - u-boot/blob - drivers/video/vidconsole-uclass.c
Merge branch 'master' of git://git.denx.de/u-boot-net
[u-boot] / drivers / video / vidconsole-uclass.c
1 /*
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
7  *
8  * SPDX-License-Identifier:     GPL-2.0+
9  */
10
11 #include <common.h>
12 #include <dm.h>
13 #include <video.h>
14 #include <video_console.h>
15 #include <video_font.h>         /* Get font data, width and height */
16
17 /* By default we scroll by a single line */
18 #ifndef CONFIG_CONSOLE_SCROLL_LINES
19 #define CONFIG_CONSOLE_SCROLL_LINES 1
20 #endif
21
22 int 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
31 int 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
41 int 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
50 /* Move backwards one space */
51 static void vidconsole_back(struct udevice *dev)
52 {
53         struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
54
55         if (--priv->curr_col < 0) {
56                 priv->curr_col = priv->cols - 1;
57                 if (--priv->curr_row < 0)
58                         priv->curr_row = 0;
59         }
60
61         vidconsole_putc_xy(dev, priv->curr_col * VIDEO_FONT_WIDTH,
62                            priv->curr_row * VIDEO_FONT_HEIGHT, ' ');
63 }
64
65 /* Move to a newline, scrolling the display if necessary */
66 static void vidconsole_newline(struct udevice *dev)
67 {
68         struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
69         struct udevice *vid_dev = dev->parent;
70         struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
71         const int rows = CONFIG_CONSOLE_SCROLL_LINES;
72         int i;
73
74         priv->curr_col = 0;
75
76         /* Check if we need to scroll the terminal */
77         if (++priv->curr_row >= priv->rows) {
78                 vidconsole_move_rows(dev, 0, rows, priv->rows - rows);
79                 for (i = 0; i < rows; i++)
80                         vidconsole_set_row(dev, priv->rows - i - 1,
81                                            vid_priv->colour_bg);
82                 priv->curr_row -= rows;
83         }
84         video_sync(dev->parent);
85 }
86
87 int vidconsole_put_char(struct udevice *dev, char ch)
88 {
89         struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
90         int ret;
91
92         switch (ch) {
93         case '\r':
94                 priv->curr_col = 0;
95                 break;
96         case '\n':
97                 vidconsole_newline(dev);
98                 break;
99         case '\t':      /* Tab (8 chars alignment) */
100                 priv->curr_col +=  8;
101                 priv->curr_col &= ~7;
102
103                 if (priv->curr_col >= priv->cols)
104                         vidconsole_newline(dev);
105                 break;
106         case '\b':
107                 vidconsole_back(dev);
108                 break;
109         default:
110                 /*
111                  * Failure of this function normally indicates an unsupported
112                  * colour depth. Check this and return an error to help with
113                  * diagnosis.
114                  */
115                 ret = vidconsole_putc_xy(dev,
116                                          priv->curr_col * VIDEO_FONT_WIDTH,
117                                          priv->curr_row * VIDEO_FONT_HEIGHT,
118                                          ch);
119                 if (ret)
120                         return ret;
121                 if (++priv->curr_col >= priv->cols)
122                         vidconsole_newline(dev);
123                 break;
124         }
125
126         return 0;
127 }
128
129 static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
130 {
131         struct udevice *dev = sdev->priv;
132
133         vidconsole_put_char(dev, ch);
134 }
135
136 static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
137 {
138         struct udevice *dev = sdev->priv;
139
140         while (*s)
141                 vidconsole_put_char(dev, *s++);
142 }
143
144 /* Set up the number of rows and colours (rotated drivers override this) */
145 static int vidconsole_pre_probe(struct udevice *dev)
146 {
147         struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
148         struct udevice *vid = dev->parent;
149         struct video_priv *vid_priv = dev_get_uclass_priv(vid);
150
151         priv->rows = vid_priv->ysize / VIDEO_FONT_HEIGHT;
152         priv->cols = vid_priv->xsize / VIDEO_FONT_WIDTH;
153
154         return 0;
155 }
156
157 /* Register the device with stdio */
158 static int vidconsole_post_probe(struct udevice *dev)
159 {
160         struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
161         struct stdio_dev *sdev = &priv->sdev;
162         int ret;
163
164         if (dev->seq) {
165                 snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d",
166                          dev->seq);
167         } else {
168                 strcpy(sdev->name, "vidconsole");
169         }
170         sdev->flags = DEV_FLAGS_OUTPUT;
171         sdev->putc = vidconsole_putc;
172         sdev->puts = vidconsole_puts;
173         sdev->priv = dev;
174         ret = stdio_register(sdev);
175         if (ret)
176                 return ret;
177
178         return 0;
179 }
180
181 UCLASS_DRIVER(vidconsole) = {
182         .id             = UCLASS_VIDEO_CONSOLE,
183         .name           = "vidconsole0",
184         .pre_probe      = vidconsole_pre_probe,
185         .post_probe     = vidconsole_post_probe,
186         .per_device_auto_alloc_size     = sizeof(struct vidconsole_priv),
187 };
188
189 void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row)
190 {
191         struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
192
193         priv->curr_col = min_t(short, col, priv->cols - 1);
194         priv->curr_row = min_t(short, row, priv->rows - 1);
195 }
196
197 static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc,
198                               char *const argv[])
199 {
200         unsigned int col, row;
201         struct udevice *dev;
202
203         if (argc != 3)
204                 return CMD_RET_USAGE;
205
206         uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev);
207         if (!dev)
208                 return CMD_RET_FAILURE;
209         col = simple_strtoul(argv[1], NULL, 10);
210         row = simple_strtoul(argv[2], NULL, 10);
211         vidconsole_position_cursor(dev, col, row);
212
213         return 0;
214 }
215
216 static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc,
217                          char *const argv[])
218 {
219         struct udevice *dev;
220         const char *s;
221
222         if (argc != 2)
223                 return CMD_RET_USAGE;
224
225         uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev);
226         if (!dev)
227                 return CMD_RET_FAILURE;
228         for (s = argv[1]; *s; s++)
229                 vidconsole_put_char(dev, *s);
230
231         return 0;
232 }
233
234 U_BOOT_CMD(
235         setcurs, 3,     1,      do_video_setcursor,
236         "set cursor position within screen",
237         "    <col> <row> in character"
238 );
239
240 U_BOOT_CMD(
241         lcdputs, 2,     1,      do_video_puts,
242         "print string on video framebuffer",
243         "    <string>"
244 );