From 8a4be8093637445b358c72149a3fd40d47116ba5 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 14 Jul 2015 16:18:58 +0200 Subject: fb: Add fb_enable/disable functions Signed-off-by: Sascha Hauer --- drivers/video/fb.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fb.c b/drivers/video/fb.c index e30ab59377..25f089a18a 100644 --- a/drivers/video/fb.c +++ b/drivers/video/fb.c @@ -29,6 +29,30 @@ static int fb_ioctl(struct cdev* cdev, int req, void *data) return 0; } +int fb_enable(struct fb_info *info) +{ + if (info->enabled) + return 0; + + info->fbops->fb_enable(info); + + info->enabled = true; + + return 0; +} + +int fb_disable(struct fb_info *info) +{ + if (!info->enabled) + return 0; + + info->fbops->fb_disable(info); + + info->enabled = false; + + return 0; +} + static int fb_enable_set(struct param_d *param, void *priv) { struct fb_info *info = priv; @@ -36,16 +60,11 @@ static int fb_enable_set(struct param_d *param, void *priv) enable = info->p_enable; - if (enable == info->enabled) - return 0; - if (enable) info->fbops->fb_enable(info); else info->fbops->fb_disable(info); - info->enabled = enable; - return 0; } -- cgit v1.2.3 From 772ab4f1722c5d166fe0677aa779e7b8628f0a79 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 15 Jul 2015 23:12:10 +0200 Subject: fb: sdl: create graphics window on enabling The framebuffer should be enabled on the fb_enable callback and disabled in the fb_disable callback. In SDL context this means the grapics window has to be created / destroyed in fb_enable / fb_disable. With this change the framebuffer has to be enabled explicitly with fb0.enable=1 like with other framebuffer driver aswell. Signed-off-by: Sascha Hauer --- drivers/video/sdl.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sdl.c b/drivers/video/sdl.c index a56834004c..5e1dc8e579 100644 --- a/drivers/video/sdl.c +++ b/drivers/video/sdl.c @@ -15,12 +15,21 @@ static void sdlfb_enable(struct fb_info *info) { + int ret; + + ret = sdl_open(info->xres, info->yres, info->bits_per_pixel, + info->screen_base); + if (ret) + return; + sdl_get_bitfield_rgba(&info->red, &info->green, &info->blue, &info->transp); + sdl_start_timer(); } static void sdlfb_disable(struct fb_info *info) { sdl_stop_timer(); + sdl_close(); } static struct fb_ops sdlfb_ops = { @@ -50,12 +59,6 @@ static int sdlfb_probe(struct device_d *dev) fb->screen_base = xzalloc(fb->xres * fb->yres * fb->bits_per_pixel >> 3); - if (sdl_open(fb->xres, fb->yres, fb->bits_per_pixel, - fb->screen_base)) - goto err; - - sdl_get_bitfield_rgba(&fb->red, &fb->green, &fb->blue, &fb->transp); - dev_dbg(dev, "red: length = %d, offset = %d\n", fb->red.length, fb->red.offset); dev_dbg(dev, "green: length = %d, offset = %d\n", @@ -72,7 +75,6 @@ static int sdlfb_probe(struct device_d *dev) if (!ret) return 0; -err: kfree(fb->screen_base); kfree(fb); sdl_close(); -- cgit v1.2.3 From 27f79c05ab4256007ae5096452c543c2bf5f2347 Mon Sep 17 00:00:00 2001 From: Antony Pavlov Date: Wed, 8 Jul 2015 12:15:39 +0300 Subject: video: implement framebuffer console This patch realizes framebuffer console support for barebox. It supports colors and enough escape sequences to show the barebox console and editor properly. fbconsole mini-HOWTO ==================== 1. compile sandbox barebox with CONFIG_VIDEO=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_DRIVER_VIDEO_SDL=y 2. run barebox 3. test fbconsole fbconsole0.active=oe Signed-off-by: Antony Pavlov Signed-off-by: Sascha Hauer --- Documentation/user/framebuffer.rst | 8 + drivers/video/Kconfig | 6 + drivers/video/Makefile | 1 + drivers/video/fb.c | 3 + drivers/video/fbconsole.c | 440 +++++++++++++++++++++++++++++++++++++ include/fb.h | 2 + 6 files changed, 460 insertions(+) create mode 100644 drivers/video/fbconsole.c (limited to 'drivers') diff --git a/Documentation/user/framebuffer.rst b/Documentation/user/framebuffer.rst index 0065e7b42f..7d004fa1cf 100644 --- a/Documentation/user/framebuffer.rst +++ b/Documentation/user/framebuffer.rst @@ -41,3 +41,11 @@ A typical script to enable the framebuffer could look like this: # finally enable backlight gpio_direction_output 42 1 +Framebuffer console +------------------- + +barebox has framebuffer console support which can be enabled with CONFIG_FRAMEBUFFER_CONSOLE. +When registered each framebuffer device gets a corresponding fbconsole device. The console +can be activated with ``fbconsolex.active=oe``. Depending on compile time options there are +different fonts available. These can be selected with the fbconsolex.font variable. To get a +list of fonts use ``devinfo fbconsolex``. diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 8e6ae99b95..fe334e5d34 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -5,6 +5,12 @@ menuconfig VIDEO if VIDEO +config FRAMEBUFFER_CONSOLE + bool + select IMAGE_RENDERER + select FONTS + prompt "framebuffer console support" + config DRIVER_VIDEO_ATMEL bool "Atmel LCDC framebuffer driver" depends on ARCH_AT91 diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 76fad5c8e8..359135ea5e 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_DRIVER_VIDEO_EDID) += edid.o obj-$(CONFIG_OFDEVICE) += of_display_timing.o obj-$(CONFIG_DRIVER_VIDEO_BACKLIGHT) += backlight.o obj-$(CONFIG_DRIVER_VIDEO_BACKLIGHT_PWM) += backlight-pwm.o +obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbconsole.o obj-$(CONFIG_DRIVER_VIDEO_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o obj-$(CONFIG_DRIVER_VIDEO_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o diff --git a/drivers/video/fb.c b/drivers/video/fb.c index 25f089a18a..a4f1734996 100644 --- a/drivers/video/fb.c +++ b/drivers/video/fb.c @@ -238,6 +238,9 @@ int register_framebuffer(struct fb_info *info) strerror(-ret)); } + if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE)) + register_fbconsole(info); + return 0; err_unregister: diff --git a/drivers/video/fbconsole.c b/drivers/video/fbconsole.c new file mode 100644 index 0000000000..b368079992 --- /dev/null +++ b/drivers/video/fbconsole.c @@ -0,0 +1,440 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +enum state_t { + LIT, /* Literal input */ + ESC, /* Start of escape sequence */ + CSI, /* Reading arguments in "CSI Pn ;...*/ +}; + +struct fbc_priv { + struct console_device cdev; + struct fb_info *fb; + + struct screen *sc; + + struct param_d *par_font; + int par_font_val; + + int font_width, font_height; + const u8 *fontdata; + unsigned int cols, rows; + unsigned int x, y; /* cursor position */ + + enum state_t state; + + int color; + int bgcolor; + +#define ANSI_FLAG_INVERT (1 << 0) +#define ANSI_FLAG_BRIGHT (1 << 1) + unsigned flags; + + int csipos; + u8 csi[256]; + + int active; +}; + +static int fbc_getc(struct console_device *cdev) +{ + return 0; +} + +static int fbc_tstc(struct console_device *cdev) +{ + return 0; +} + +static void cls(struct fbc_priv *priv) +{ + void *buf = gui_screen_render_buffer(priv->sc); + + memset(buf, 0, priv->fb->line_length * priv->fb->yres); +} + +struct rgb { + u8 r, g, b; +}; + +static struct rgb colors[] = { + { 0, 0, 0 }, + { 205, 0, 0 }, + { 0, 205, 0 }, + { 205, 205, 0 }, + { 0, 0, 238 }, + { 205, 0, 205 }, + { 0, 205, 205 }, + { 229, 229, 229 }, + { 127, 127, 127 }, + { 255, 0, 0 }, + { 0, 255, 0 }, + { 255, 255, 0 }, + { 92, 92, 255 }, + { 255, 0, 255 }, + { 0, 255, 255 }, + { 255, 255, 255 }, +}; + +static void drawchar(struct fbc_priv *priv, int x, int y, char c) +{ + void *buf; + int bpp = priv->fb->bits_per_pixel >> 3; + void *adr; + int i; + const char *inbuf; + int line_length; + u32 color, bgcolor; + struct rgb *rgb; + + buf = gui_screen_render_buffer(priv->sc); + + inbuf = &priv->fontdata[c * priv->font_height]; + + line_length = priv->fb->line_length; + + color = priv->flags & ANSI_FLAG_INVERT ? priv->bgcolor : priv->color; + bgcolor = priv->flags & ANSI_FLAG_INVERT ? priv->color : priv->bgcolor; + + if (priv->flags & ANSI_FLAG_BRIGHT) + color += 8; + + rgb = &colors[color]; + color = gu_rgb_to_pixel(priv->fb, rgb->r, rgb->g, rgb->b, 0xff); + + rgb = &colors[bgcolor]; + bgcolor = gu_rgb_to_pixel(priv->fb, rgb->r, rgb->g, rgb->b, 0xff); + + for (i = 0; i < priv->font_height; i++) { + uint8_t t = inbuf[i]; + int j; + + adr = buf + line_length * (y * priv->font_height + i) + x * priv->font_width * bpp; + + for (j = 0; j < priv->font_width; j++) { + if (t & 0x80) + gu_set_pixel(priv->fb, adr, color); + else + gu_set_pixel(priv->fb, adr, bgcolor); + + adr += priv->fb->bits_per_pixel >> 3; + t <<= 1; + } + } +} + +static void video_invertchar(struct fbc_priv *priv, int x, int y) +{ + void *buf; + + buf = gui_screen_render_buffer(priv->sc); + + gu_invert_area(priv->fb, buf, x * priv->font_width, y * priv->font_height, + priv->font_width, priv->font_height); +} + +static void printchar(struct fbc_priv *priv, int c) +{ + video_invertchar(priv, priv->x, priv->y); + + switch (c) { + case '\007': /* bell: ignore */ + break; + case '\b': + if (priv->x > 0) { + priv->x--; + } else if (priv->y > 0) { + priv->x = priv->cols; + priv->y--; + } + break; + case '\n': + case '\013': /* Vertical tab is the same as Line Feed */ + priv->y++; + break; + + case '\r': + priv->x = 0; + break; + + case '\t': + priv->x = (priv->x + 8) & ~0x3; + break; + + default: + drawchar(priv, priv->x, priv->y, c); + gu_screen_blit(priv->sc); + + priv->x++; + if (priv->x > priv->cols) { + priv->y++; + priv->x = 0; + } + } + + if (priv->y > priv->rows) { + void *buf; + u32 line_length = priv->fb->line_length; + int line_height = line_length * priv->font_height; + + buf = gui_screen_render_buffer(priv->sc); + + memcpy(buf, buf + line_height, line_height * (priv->rows + 1)); + memset(buf + line_height * priv->rows, 0, line_height); + priv->y = priv->rows; + } + + video_invertchar(priv, priv->x, priv->y); + + return; +} + +static void fbc_parse_colors(struct fbc_priv *priv) +{ + int code; + char *str; + + str = priv->csi; + + while (1) { + code = simple_strtoul(str, &str, 10); + switch (code) { + case 0: + priv->flags = 0; + priv->color = 8; + priv->bgcolor = 0; + break; + case 1: + priv->flags |= ANSI_FLAG_BRIGHT; + break; + case 7: + priv->flags |= ANSI_FLAG_INVERT; + break; + case 30 ... 37: + priv->color = code - 30; + break; + case 39: + priv->color = 7; + break; + case 40 ... 47: + priv->bgcolor = code - 40; + break; + case 49: + priv->bgcolor = 0; + break; + } + + if (*str != ';') + break; + str++; + } +} + +static void fbc_parse_csi(struct fbc_priv *priv) +{ + char *end; + unsigned char last; + int pos, i; + + last = priv->csi[priv->csipos - 1]; + + switch (last) { + case 'm': + fbc_parse_colors(priv); + return; + case 'J': + cls(priv); + return; + case 'H': + video_invertchar(priv, priv->x, priv->y); + pos = simple_strtoul(priv->csi, &end, 10); + priv->y = pos ? pos - 1 : 0; + pos = simple_strtoul(end + 1, NULL, 10); + priv->x = pos ? pos - 1 : 0; + video_invertchar(priv, priv->x, priv->y); + case 'K': + pos = simple_strtoul(priv->csi, &end, 10); + video_invertchar(priv, priv->x, priv->y); + switch (pos) { + case 0: + for (i = priv->x; i < priv->cols; i++) + drawchar(priv, i, priv->y, ' '); + break; + case 1: + for (i = 0; i <= priv->x; i++) + drawchar(priv, i, priv->y, ' '); + break; + } + video_invertchar(priv, priv->x, priv->y); + + break; + } +} + +static void fbc_putc(struct console_device *cdev, char c) +{ + struct fbc_priv *priv = container_of(cdev, + struct fbc_priv, cdev); + + switch (priv->state) { + case LIT: + switch (c) { + case '\033': + priv->state = ESC; + break; + default: + printchar(priv, c); + } + break; + case ESC: + switch (c) { + case '[': + priv->state = CSI; + priv->csipos = 0; + memset(priv->csi, 0, 6); + break; + } + break; + case CSI: + priv->csi[priv->csipos++] = c; + if (priv->csipos == 255) { + priv->csipos = 0; + priv->state = LIT; + return; + } + + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case ';': + case ':': + break; + default: + fbc_parse_csi(priv); + priv->state = LIT; + } + break; + } +} + +static int setup_font(struct fbc_priv *priv) +{ + struct fb_info *fb = priv->fb; + const struct font_desc *font; + + font = find_font_enum(priv->par_font_val); + if (!font) { + return -ENOENT; + } + + priv->font_width = font->width; + priv->font_height = font->height; + priv->fontdata = font->data; + + priv->rows = fb->yres / priv->font_height - 1; + priv->cols = fb->xres / priv->font_width - 1; + + return 0; +} + +static int fbc_set_active(struct console_device *cdev, unsigned flags) +{ + 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; + + priv->sc = fb_create_screen(fb, 0); + if (IS_ERR(priv->sc)) + return PTR_ERR(priv->sc); + + fb_enable(fb); + + priv->state = LIT; + + dev_info(priv->cdev.dev, "framebuffer console %dx%d activated\n", + priv->cols + 1, priv->rows + 1); + + priv->active = true; + + return 0; +} + +static int set_font(struct param_d *p, void *vpriv) +{ + struct fbc_priv *priv = vpriv; + struct console_device *cdev = &priv->cdev; + + if (cdev->f_active & (CONSOLE_STDOUT | CONSOLE_STDERR)) { + cls(priv); + setup_font(priv); + } + + return 0; +} + +int register_fbconsole(struct fb_info *fb) +{ + struct fbc_priv *priv; + struct console_device *cdev; + int ret; + + priv = xzalloc(sizeof(*priv)); + + priv->fb = fb; + priv->x = 0; + priv->y = 0; + priv->color = 7; + priv->bgcolor = 0; + + cdev = &priv->cdev; + cdev->dev = &fb->dev; + cdev->tstc = fbc_tstc; + cdev->putc = fbc_putc; + cdev->getc = fbc_getc; + cdev->devname = "fbconsole"; + cdev->devid = DEVICE_ID_DYNAMIC; + cdev->set_active = fbc_set_active; + + ret = console_register(cdev); + if (ret) { + pr_err("registering failed with %s\n", strerror(-ret)); + kfree(priv); + return ret; + } + + priv->par_font_val = 0; + priv->par_font = add_param_font(&cdev->class_dev, + set_font, NULL, + &priv->par_font_val, priv); + + pr_info("registered as %s%d\n", cdev->class_dev.name, cdev->class_dev.id); + + return 0; +} diff --git a/include/fb.h b/include/fb.h index 92216188f2..27894db981 100644 --- a/include/fb.h +++ b/include/fb.h @@ -163,4 +163,6 @@ int edid_to_display_timings(struct display_timings *, unsigned char *edid); void *edid_read_i2c(struct i2c_adapter *adapter); void fb_edid_add_modes(struct fb_info *info); +int register_fbconsole(struct fb_info *fb); + #endif /* __FB_H */ -- cgit v1.2.3