]> git.sur5r.net Git - u-boot/commitdiff
dm: video: Add basic ANSI escape sequence support
authorRob Clark <robdclark@gmail.com>
Wed, 13 Sep 2017 22:12:21 +0000 (18:12 -0400)
committerAnatolij Gustschin <agust@denx.de>
Fri, 29 Sep 2017 15:53:21 +0000 (17:53 +0200)
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>
drivers/video/Kconfig
drivers/video/vidconsole-uclass.c
drivers/video/video-uclass.c
include/video.h
include/video_console.h

index 7ba7b580db1158f5ee4acaa8b004f603e7519efe..e6b7f11dc9d33401a3fefdfd49a59b0e4066d2b6 100644 (file)
@@ -65,6 +65,14 @@ config VIDEO_BPP32
          this option, such displays will not be supported and console output
          will be empty.
 
+config VIDEO_ANSI
+       bool "Support ANSI escape sequences in video console"
+       depends on DM_VIDEO
+       default y if DM_VIDEO
+       help
+         Enable ANSI escape sequence decoding for a more fully functional
+         console.
+
 config CONSOLE_NORMAL
        bool "Support a simple text console"
        depends on DM_VIDEO
index e081d5a0eeb3e9473a9e67c98453645bf07d0f87..37eb2a0ef46da513f6565b9706545a9ec9a6be15 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <common.h>
+#include <linux/ctype.h>
 #include <dm.h>
 #include <video.h>
 #include <video_console.h>
@@ -107,12 +108,119 @@ static void vidconsole_newline(struct udevice *dev)
        video_sync(dev->parent);
 }
 
+static char *parsenum(char *s, int *num)
+{
+       char *end;
+       *num = simple_strtol(s, &end, 10);
+       return end;
+}
+
+/*
+ * Process a character while accumulating an escape string.  Chars are
+ * accumulated into escape_buf until the end of escape sequence is
+ * found, at which point the sequence is parsed and processed.
+ */
+static void vidconsole_escape_char(struct udevice *dev, char ch)
+{
+       struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+
+       if (!IS_ENABLED(CONFIG_VIDEO_ANSI))
+               goto error;
+
+       /* Sanity checking for bogus ESC sequences: */
+       if (priv->escape_len >= sizeof(priv->escape_buf))
+               goto error;
+       if (priv->escape_len == 0 && ch != '[')
+               goto error;
+
+       priv->escape_buf[priv->escape_len++] = ch;
+
+       /*
+        * Escape sequences are terminated by a letter, so keep
+        * accumulating until we get one:
+        */
+       if (!isalpha(ch))
+               return;
+
+       /*
+        * clear escape mode first, otherwise things will get highly
+        * surprising if you hit any debug prints that come back to
+        * this console.
+        */
+       priv->escape = 0;
+
+       switch (ch) {
+       case 'H':
+       case 'f': {
+               int row, col;
+               char *s = priv->escape_buf;
+
+               /*
+                * Set cursor position: [%d;%df or [%d;%dH
+                */
+               s++;    /* [ */
+               s = parsenum(s, &row);
+               s++;    /* ; */
+               s = parsenum(s, &col);
+
+               priv->ycur = row * priv->y_charsize;
+               priv->xcur_frac = priv->xstart_frac +
+                       VID_TO_POS(col * priv->x_charsize);
+
+               break;
+       }
+       case 'J': {
+               int mode;
+
+               /*
+                * Clear part/all screen:
+                *   [J or [0J - clear screen from cursor down
+                *   [1J       - clear screen from cursor up
+                *   [2J       - clear entire screen
+                *
+                * TODO we really only handle entire-screen case, others
+                * probably require some additions to video-uclass (and
+                * are not really needed yet by efi_console)
+                */
+               parsenum(priv->escape_buf + 1, &mode);
+
+               if (mode == 2) {
+                       video_clear(dev->parent);
+                       video_sync(dev->parent);
+                       priv->ycur = 0;
+                       priv->xcur_frac = priv->xstart_frac;
+               } else {
+                       debug("unsupported clear mode: %d\n", mode);
+               }
+               break;
+       }
+       default:
+               debug("unrecognized escape sequence: %*s\n",
+                     priv->escape_len, priv->escape_buf);
+       }
+
+       return;
+
+error:
+       /* something went wrong, just revert to normal mode: */
+       priv->escape = 0;
+}
+
 int vidconsole_put_char(struct udevice *dev, char ch)
 {
        struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
        int ret;
 
+       if (priv->escape) {
+               vidconsole_escape_char(dev, ch);
+               return 0;
+       }
+
        switch (ch) {
+       case '\x1b':
+               priv->escape_len = 0;
+               priv->escape = 1;
+               break;
        case '\a':
                /* beep */
                break;
index dfa39b0d1b893ad774e0fa35bb57760b34bf8973..dcaceed42c4e66821133fad83136c9aaf1b78b69 100644 (file)
@@ -87,7 +87,7 @@ int video_reserve(ulong *addrp)
        return 0;
 }
 
-static int video_clear(struct udevice *dev)
+void video_clear(struct udevice *dev)
 {
        struct video_priv *priv = dev_get_uclass_priv(dev);
 
@@ -100,8 +100,6 @@ static int video_clear(struct udevice *dev)
        } else {
                memset(priv->fb, priv->colour_bg, priv->fb_size);
        }
-
-       return 0;
 }
 
 /* Flush video activity to the caches */
index 5b4e78b18257b40805ff3e84ddb3fec52ac14186..61ff6531215aca9b083431f1c800f4ce222ea830 100644 (file)
@@ -114,6 +114,13 @@ struct video_ops {
  */
 int video_reserve(ulong *addrp);
 
+/**
+ * video_clear() - Clear a device's frame buffer to background color.
+ *
+ * @dev:       Device to clear
+ */
+void video_clear(struct udevice *dev);
+
 /**
  * video_sync() - Sync a device's frame buffer with its hardware
  *
index 26047934da8c59b4646caa6cb9f8a631d1ce0561..9dce234bd928cf24372532c0923f868f44b1a326 100644 (file)
@@ -29,6 +29,9 @@
  * @xsize_frac:        Width of the display in fractional units
  * @xstart_frac:       Left margin for the text console in fractional units
  * @last_ch:   Last character written to the text console on this line
+ * @escape:    TRUE if currently accumulating an ANSI escape sequence
+ * @escape_len:        Length of accumulated escape sequence so far
+ * @escape_buf:        Buffer to accumulate escape sequence
  */
 struct vidconsole_priv {
        struct stdio_dev sdev;
@@ -42,6 +45,14 @@ struct vidconsole_priv {
        int xsize_frac;
        int xstart_frac;
        int last_ch;
+       /*
+        * ANSI escape sequences are accumulated character by character,
+        * starting after the ESC char (0x1b) until the entire sequence
+        * is consumed at which point it is acted upon.
+        */
+       int escape;
+       int escape_len;
+       char escape_buf[32];
 };
 
 /**