diff options
Diffstat (limited to 'drivers/video/fbconsole.c')
-rw-r--r-- | drivers/video/fbconsole.c | 93 |
1 files changed, 76 insertions, 17 deletions
diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c index 693c21f547..b261f17048 100644 --- a/drivers/video/fbconsole.c +++ b/drivers/video/fbconsole.c @@ -11,6 +11,7 @@ enum state_t { LIT, /* Literal input */ ESC, /* Start of escape sequence */ CSI, /* Reading arguments in "CSI Pn ;...*/ + CSI_CNT, }; struct fbc_priv { @@ -34,10 +35,12 @@ struct fbc_priv { #define ANSI_FLAG_INVERT (1 << 0) #define ANSI_FLAG_BRIGHT (1 << 1) +#define HIDE_CURSOR (1 << 2) unsigned flags; int csipos; u8 csi[256]; + unsigned char csi_cmd; int active; int in_console; @@ -144,6 +147,12 @@ static void video_invertchar(struct fbc_priv *priv, int x, int y) priv->font->width, priv->font->height); } +static void show_cursor(struct fbc_priv *priv, int x, int y) +{ + if (!(priv->flags & HIDE_CURSOR)) + video_invertchar(priv, x, y); +} + static void printchar(struct fbc_priv *priv, int c) { video_invertchar(priv, priv->x, priv->y); @@ -200,7 +209,7 @@ static void printchar(struct fbc_priv *priv, int c) priv->y = priv->rows; } - video_invertchar(priv, priv->x, priv->y); + show_cursor(priv, priv->x, priv->y); return; } @@ -258,17 +267,51 @@ static void fbc_parse_csi(struct fbc_priv *priv) case 'm': fbc_parse_colors(priv); return; + case '?': /* vt100: show/hide cursor */ + priv->csi_cmd = last; + priv->state = CSI_CNT; + return; + case 'h': + /* suffix for vt100 "[?25h" */ + switch (priv->csi_cmd) { + case '?': /* cursor visible */ + priv->csi_cmd = -1; + if (!(priv->flags & HIDE_CURSOR)) + break; + + priv->flags &= ~HIDE_CURSOR; + /* show cursor now */ + show_cursor(priv, priv->x, priv->y); + break; + } + break; + case 'l': + /* suffix for vt100 "[?25l" */ + switch (priv->csi_cmd) { + case '?': /* cursor invisible */ + priv->csi_cmd = -1; + + /* hide cursor now */ + video_invertchar(priv, priv->x, priv->y); + priv->flags |= HIDE_CURSOR; + + break; + } + break; case 'J': cls(priv); - video_invertchar(priv, priv->x, priv->y); + show_cursor(priv, priv->x, priv->y); return; case 'H': - video_invertchar(priv, priv->x, priv->y); + show_cursor(priv, priv->x, priv->y); + pos = simple_strtoul(priv->csi, &end, 10); - priv->y = pos ? pos - 1 : 0; + priv->y = clamp(pos - 1, 0, (int) priv->rows); + pos = simple_strtoul(end + 1, NULL, 10); - priv->x = pos ? pos - 1 : 0; - video_invertchar(priv, priv->x, priv->y); + priv->x = clamp(pos - 1, 0, (int) priv->cols); + + show_cursor(priv, priv->x, priv->y); case 'K': pos = simple_strtoul(priv->csi, &end, 10); video_invertchar(priv, priv->x, priv->y); @@ -292,6 +335,7 @@ static void fbc_putc(struct console_device *cdev, char c) { struct fbc_priv *priv = container_of(cdev, struct fbc_priv, cdev); + struct fb_info *fb = priv->fb; if (priv->in_console) return; @@ -340,11 +384,18 @@ static void fbc_putc(struct console_device *cdev, char c) break; default: fbc_parse_csi(priv); - priv->state = LIT; + if (priv->state != CSI_CNT) + priv->state = LIT; } break; + case CSI_CNT: + priv->state = CSI; + break; + } priv->in_console = 0; + + fb_flush(fb); } static int setup_font(struct fbc_priv *priv) @@ -365,21 +416,13 @@ static int setup_font(struct fbc_priv *priv) return 0; } -static int fbc_set_active(struct console_device *cdev, unsigned flags) +static int fbc_open(struct console_device *cdev) { struct fbc_priv *priv = container_of(cdev, struct fbc_priv, cdev); struct fb_info *fb = priv->fb; int ret; - if (priv->active) { - fb_close(priv->sc); - priv->active = false; - } - - if (!(flags & (CONSOLE_STDOUT | CONSOLE_STDERR))) - return 0; - ret = setup_font(priv); if (ret) return ret; @@ -400,6 +443,21 @@ static int fbc_set_active(struct console_device *cdev, unsigned flags) return 0; } +static int fbc_close(struct console_device *cdev) +{ + struct fbc_priv *priv = container_of(cdev, + struct fbc_priv, cdev); + + if (priv->active) { + fb_close(priv->sc); + priv->active = false; + + return 0; + } + + return -EINVAL; +} + static int set_font(struct param_d *p, void *vpriv) { struct fbc_priv *priv = vpriv; @@ -434,7 +492,8 @@ int register_fbconsole(struct fb_info *fb) cdev->getc = fbc_getc; cdev->devname = "fbconsole"; cdev->devid = DEVICE_ID_DYNAMIC; - cdev->set_active = fbc_set_active; + cdev->open = fbc_open; + cdev->close = fbc_close; ret = console_register(cdev); if (ret) { |