[U-Boot] [PATCH] dm: video: Add basic ANSI escape sequence support

Simon Glass sjg at chromium.org
Mon Sep 11 06:18:00 UTC 2017


On 7 September 2017 at 14:28, Rob Clark <robdclark at gmail.com> wrote:
> 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 at gmail.com>
> ---
>  drivers/video/vidconsole-uclass.c | 112 ++++++++++++++++++++++++++++++++++++++
>  drivers/video/video-uclass.c      |   4 +-
>  include/video.h                   |   7 +++
>  include/video_console.h           |  11 ++++
>  4 files changed, 131 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
> index e081d5a0ee..7998b4cf5f 100644
> --- a/drivers/video/vidconsole-uclass.c
> +++ b/drivers/video/vidconsole-uclass.c
> @@ -9,6 +9,7 @@
>   */
>
>  #include <common.h>
> +#include <linux/ctype.h>
>  #include <dm.h>
>  #include <video.h>
>  #include <video_console.h>
> @@ -107,12 +108,123 @@ static void vidconsole_newline(struct udevice *dev)
>         video_sync(dev->parent);
>  }
>
> +/*
> + * Parse a number from string that ends in a non-numeric character..
> + * sscanf() would be nice.  This is just enough for parsing ANSI escape
> + * sequences.
> + */
> +static char *parsenum(char *s, int *num)

Can you use simple_strtoul() or similar?

> +{
> +       int n = 0;
> +
> +       while (isdigit(*s)) {
> +               n = (10 * n) + (*s - '0');
> +               s++;
> +       }
> +
> +       *num = n;
> +       return s;
> +}
> +
> +static void vidconsole_escape_char(struct udevice *dev, char ch)

Please add a function comment

> +{
> +       struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
> +
> +       /* 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;
> +       return;
> +}
> +
>  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;
> +       }

Is it possible to add a CONFIG_VIDEO_ANSI option to enable this?
Perhaps it could be on by default. Then:

if (CONFIG_IS_ENABLED(VIDEO_ANSI) && priv-escape) {
...

This helps to reduce base code size.

> +
>         switch (ch) {
> +       case '\x1b':
> +               priv->escape_len = 0;
> +               priv->escape = 1;
> +               break;
>         case '\a':
>                 /* beep */
>                 break;
> diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
> index dfa39b0d1b..dcaceed42c 100644
> --- a/drivers/video/video-uclass.c
> +++ b/drivers/video/video-uclass.c
> @@ -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 */
> diff --git a/include/video.h b/include/video.h
> index 5b4e78b182..61ff653121 100644
> --- a/include/video.h
> +++ b/include/video.h
> @@ -115,6 +115,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
>   *
>   * Some frame buffers are cached or have a secondary frame buffer. This
> diff --git a/include/video_console.h b/include/video_console.h
> index 26047934da..9dce234bd9 100644
> --- a/include/video_console.h
> +++ b/include/video_console.h
> @@ -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];
>  };
>
>  /**
> --
> 2.13.5
>


More information about the U-Boot mailing list