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

Rob Clark robdclark at gmail.com
Mon Sep 11 09:42:01 UTC 2017


On Mon, Sep 11, 2017 at 2:18 AM, Simon Glass <sjg at chromium.org> wrote:
> 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?

Possibly, but I'm not sure it is a good idea.. I don't think escape
sequences are meant to be encoded with hex or octal number strings.
>From a quick look, I don't see any escape code terminated with 'x', so
maybe it would end up working ok.. but something like ESC[0x1234m
should be an escape sequence terminated with x followed by normal
chars 1234m and strtoul would get that wrong..

BR,
-R

>> +{
>> +       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