mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
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>
This commit is contained in:
parent
889808da9b
commit
a085aa1f27
5 changed files with 135 additions and 3 deletions
|
@ -65,6 +65,14 @@ config VIDEO_BPP32
|
||||||
this option, such displays will not be supported and console output
|
this option, such displays will not be supported and console output
|
||||||
will be empty.
|
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
|
config CONSOLE_NORMAL
|
||||||
bool "Support a simple text console"
|
bool "Support a simple text console"
|
||||||
depends on DM_VIDEO
|
depends on DM_VIDEO
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
#include <dm.h>
|
#include <dm.h>
|
||||||
#include <video.h>
|
#include <video.h>
|
||||||
#include <video_console.h>
|
#include <video_console.h>
|
||||||
|
@ -107,12 +108,119 @@ static void vidconsole_newline(struct udevice *dev)
|
||||||
video_sync(dev->parent);
|
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)
|
int vidconsole_put_char(struct udevice *dev, char ch)
|
||||||
{
|
{
|
||||||
struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
|
struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (priv->escape) {
|
||||||
|
vidconsole_escape_char(dev, ch);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
|
case '\x1b':
|
||||||
|
priv->escape_len = 0;
|
||||||
|
priv->escape = 1;
|
||||||
|
break;
|
||||||
case '\a':
|
case '\a':
|
||||||
/* beep */
|
/* beep */
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -87,7 +87,7 @@ int video_reserve(ulong *addrp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int video_clear(struct udevice *dev)
|
void video_clear(struct udevice *dev)
|
||||||
{
|
{
|
||||||
struct video_priv *priv = dev_get_uclass_priv(dev);
|
struct video_priv *priv = dev_get_uclass_priv(dev);
|
||||||
|
|
||||||
|
@ -100,8 +100,6 @@ static int video_clear(struct udevice *dev)
|
||||||
} else {
|
} else {
|
||||||
memset(priv->fb, priv->colour_bg, priv->fb_size);
|
memset(priv->fb, priv->colour_bg, priv->fb_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Flush video activity to the caches */
|
/* Flush video activity to the caches */
|
||||||
|
|
|
@ -114,6 +114,13 @@ struct video_ops {
|
||||||
*/
|
*/
|
||||||
int video_reserve(ulong *addrp);
|
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
|
* video_sync() - Sync a device's frame buffer with its hardware
|
||||||
*
|
*
|
||||||
|
|
|
@ -29,6 +29,9 @@
|
||||||
* @xsize_frac: Width of the display in fractional units
|
* @xsize_frac: Width of the display in fractional units
|
||||||
* @xstart_frac: Left margin for the text console 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
|
* @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 vidconsole_priv {
|
||||||
struct stdio_dev sdev;
|
struct stdio_dev sdev;
|
||||||
|
@ -42,6 +45,14 @@ struct vidconsole_priv {
|
||||||
int xsize_frac;
|
int xsize_frac;
|
||||||
int xstart_frac;
|
int xstart_frac;
|
||||||
int last_ch;
|
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];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue