Commit a085aa1f2737baf60d322296f02c066ee3c6a53e
Committed by
Anatolij Gustschin
1 parent
889808da9b
Exists in
smarc_8mq_lf_v2020.04
and in
17 other branches
dm: video: Add basic ANSI escape sequence support
Really just the subset that is needed by efi_console. Perhaps more will be added later, for example color support would be useful to implement efi_cout_set_attribute(). Signed-off-by: Rob Clark <robdclark@gmail.com> Reviewed-by: Simon Glass <sjg@chromium.org>
Showing 5 changed files with 135 additions and 3 deletions Side-by-side Diff
drivers/video/Kconfig
... | ... | @@ -65,6 +65,14 @@ |
65 | 65 | this option, such displays will not be supported and console output |
66 | 66 | will be empty. |
67 | 67 | |
68 | +config VIDEO_ANSI | |
69 | + bool "Support ANSI escape sequences in video console" | |
70 | + depends on DM_VIDEO | |
71 | + default y if DM_VIDEO | |
72 | + help | |
73 | + Enable ANSI escape sequence decoding for a more fully functional | |
74 | + console. | |
75 | + | |
68 | 76 | config CONSOLE_NORMAL |
69 | 77 | bool "Support a simple text console" |
70 | 78 | depends on DM_VIDEO |
drivers/video/vidconsole-uclass.c
... | ... | @@ -9,6 +9,7 @@ |
9 | 9 | */ |
10 | 10 | |
11 | 11 | #include <common.h> |
12 | +#include <linux/ctype.h> | |
12 | 13 | #include <dm.h> |
13 | 14 | #include <video.h> |
14 | 15 | #include <video_console.h> |
15 | 16 | |
16 | 17 | |
... | ... | @@ -107,12 +108,119 @@ |
107 | 108 | video_sync(dev->parent); |
108 | 109 | } |
109 | 110 | |
111 | +static char *parsenum(char *s, int *num) | |
112 | +{ | |
113 | + char *end; | |
114 | + *num = simple_strtol(s, &end, 10); | |
115 | + return end; | |
116 | +} | |
117 | + | |
118 | +/* | |
119 | + * Process a character while accumulating an escape string. Chars are | |
120 | + * accumulated into escape_buf until the end of escape sequence is | |
121 | + * found, at which point the sequence is parsed and processed. | |
122 | + */ | |
123 | +static void vidconsole_escape_char(struct udevice *dev, char ch) | |
124 | +{ | |
125 | + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); | |
126 | + | |
127 | + if (!IS_ENABLED(CONFIG_VIDEO_ANSI)) | |
128 | + goto error; | |
129 | + | |
130 | + /* Sanity checking for bogus ESC sequences: */ | |
131 | + if (priv->escape_len >= sizeof(priv->escape_buf)) | |
132 | + goto error; | |
133 | + if (priv->escape_len == 0 && ch != '[') | |
134 | + goto error; | |
135 | + | |
136 | + priv->escape_buf[priv->escape_len++] = ch; | |
137 | + | |
138 | + /* | |
139 | + * Escape sequences are terminated by a letter, so keep | |
140 | + * accumulating until we get one: | |
141 | + */ | |
142 | + if (!isalpha(ch)) | |
143 | + return; | |
144 | + | |
145 | + /* | |
146 | + * clear escape mode first, otherwise things will get highly | |
147 | + * surprising if you hit any debug prints that come back to | |
148 | + * this console. | |
149 | + */ | |
150 | + priv->escape = 0; | |
151 | + | |
152 | + switch (ch) { | |
153 | + case 'H': | |
154 | + case 'f': { | |
155 | + int row, col; | |
156 | + char *s = priv->escape_buf; | |
157 | + | |
158 | + /* | |
159 | + * Set cursor position: [%d;%df or [%d;%dH | |
160 | + */ | |
161 | + s++; /* [ */ | |
162 | + s = parsenum(s, &row); | |
163 | + s++; /* ; */ | |
164 | + s = parsenum(s, &col); | |
165 | + | |
166 | + priv->ycur = row * priv->y_charsize; | |
167 | + priv->xcur_frac = priv->xstart_frac + | |
168 | + VID_TO_POS(col * priv->x_charsize); | |
169 | + | |
170 | + break; | |
171 | + } | |
172 | + case 'J': { | |
173 | + int mode; | |
174 | + | |
175 | + /* | |
176 | + * Clear part/all screen: | |
177 | + * [J or [0J - clear screen from cursor down | |
178 | + * [1J - clear screen from cursor up | |
179 | + * [2J - clear entire screen | |
180 | + * | |
181 | + * TODO we really only handle entire-screen case, others | |
182 | + * probably require some additions to video-uclass (and | |
183 | + * are not really needed yet by efi_console) | |
184 | + */ | |
185 | + parsenum(priv->escape_buf + 1, &mode); | |
186 | + | |
187 | + if (mode == 2) { | |
188 | + video_clear(dev->parent); | |
189 | + video_sync(dev->parent); | |
190 | + priv->ycur = 0; | |
191 | + priv->xcur_frac = priv->xstart_frac; | |
192 | + } else { | |
193 | + debug("unsupported clear mode: %d\n", mode); | |
194 | + } | |
195 | + break; | |
196 | + } | |
197 | + default: | |
198 | + debug("unrecognized escape sequence: %*s\n", | |
199 | + priv->escape_len, priv->escape_buf); | |
200 | + } | |
201 | + | |
202 | + return; | |
203 | + | |
204 | +error: | |
205 | + /* something went wrong, just revert to normal mode: */ | |
206 | + priv->escape = 0; | |
207 | +} | |
208 | + | |
110 | 209 | int vidconsole_put_char(struct udevice *dev, char ch) |
111 | 210 | { |
112 | 211 | struct vidconsole_priv *priv = dev_get_uclass_priv(dev); |
113 | 212 | int ret; |
114 | 213 | |
214 | + if (priv->escape) { | |
215 | + vidconsole_escape_char(dev, ch); | |
216 | + return 0; | |
217 | + } | |
218 | + | |
115 | 219 | switch (ch) { |
220 | + case '\x1b': | |
221 | + priv->escape_len = 0; | |
222 | + priv->escape = 1; | |
223 | + break; | |
116 | 224 | case '\a': |
117 | 225 | /* beep */ |
118 | 226 | break; |
drivers/video/video-uclass.c
... | ... | @@ -87,7 +87,7 @@ |
87 | 87 | return 0; |
88 | 88 | } |
89 | 89 | |
90 | -static int video_clear(struct udevice *dev) | |
90 | +void video_clear(struct udevice *dev) | |
91 | 91 | { |
92 | 92 | struct video_priv *priv = dev_get_uclass_priv(dev); |
93 | 93 | |
... | ... | @@ -100,8 +100,6 @@ |
100 | 100 | } else { |
101 | 101 | memset(priv->fb, priv->colour_bg, priv->fb_size); |
102 | 102 | } |
103 | - | |
104 | - return 0; | |
105 | 103 | } |
106 | 104 | |
107 | 105 | /* Flush video activity to the caches */ |
include/video.h
... | ... | @@ -115,6 +115,13 @@ |
115 | 115 | int video_reserve(ulong *addrp); |
116 | 116 | |
117 | 117 | /** |
118 | + * video_clear() - Clear a device's frame buffer to background color. | |
119 | + * | |
120 | + * @dev: Device to clear | |
121 | + */ | |
122 | +void video_clear(struct udevice *dev); | |
123 | + | |
124 | +/** | |
118 | 125 | * video_sync() - Sync a device's frame buffer with its hardware |
119 | 126 | * |
120 | 127 | * Some frame buffers are cached or have a secondary frame buffer. This |
include/video_console.h
... | ... | @@ -29,6 +29,9 @@ |
29 | 29 | * @xsize_frac: Width of the display in fractional units |
30 | 30 | * @xstart_frac: Left margin for the text console in fractional units |
31 | 31 | * @last_ch: Last character written to the text console on this line |
32 | + * @escape: TRUE if currently accumulating an ANSI escape sequence | |
33 | + * @escape_len: Length of accumulated escape sequence so far | |
34 | + * @escape_buf: Buffer to accumulate escape sequence | |
32 | 35 | */ |
33 | 36 | struct vidconsole_priv { |
34 | 37 | struct stdio_dev sdev; |
... | ... | @@ -42,6 +45,14 @@ |
42 | 45 | int xsize_frac; |
43 | 46 | int xstart_frac; |
44 | 47 | int last_ch; |
48 | + /* | |
49 | + * ANSI escape sequences are accumulated character by character, | |
50 | + * starting after the ESC char (0x1b) until the entire sequence | |
51 | + * is consumed at which point it is acted upon. | |
52 | + */ | |
53 | + int escape; | |
54 | + int escape_len; | |
55 | + char escape_buf[32]; | |
45 | 56 | }; |
46 | 57 | |
47 | 58 | /** |