Commit a085aa1f2737baf60d322296f02c066ee3c6a53e

Authored by Rob Clark
Committed by Anatolij Gustschin
1 parent 889808da9b

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 */
... ... @@ -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 /**