From fefa2bf71af1de4e9faaf9efee2c11b79c170760 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 17 Aug 2011 16:17:21 +0200 Subject: Add support for fourcc-based format API Use the new API by default, and automatically fall back to the legacy RGB API when the new API isn't supported. Signed-off-by: Laurent Pinchart --- fbdev.c | 529 +++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 405 insertions(+), 124 deletions(-) diff --git a/fbdev.c b/fbdev.c index 6bce2b0..4b83f29 100644 --- a/fbdev.c +++ b/fbdev.c @@ -33,6 +33,7 @@ #include #include +#include #define min(a, b) ((a) < (b) ? (a) : (b)) #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) @@ -47,6 +48,8 @@ struct device { struct fb_bitfield red; struct fb_bitfield green; struct fb_bitfield blue; + + unsigned int fourcc; }; enum fb_fill_mode { @@ -60,6 +63,212 @@ enum fb_fill_pattern { FB_PATTERN_LINES = 1, }; +/* ----------------------------------------------------------------------------- + * Format helpers + */ + +struct fb_format_info { + unsigned int fourcc; + const char *name; +}; + +static const struct fb_format_info formats[] = { + { V4L2_PIX_FMT_BGR24, "BGR24" }, + { V4L2_PIX_FMT_BGR32, "BGR32" }, + { V4L2_PIX_FMT_RGB24, "RGB24" }, + { V4L2_PIX_FMT_RGB32, "RGB32" }, + { V4L2_PIX_FMT_RGB565, "RGB565" }, +}; + +#ifdef FB_VISUAL_FOURCC +static const char *fb_format_name(unsigned int fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); ++i) { + if (formats[i].fourcc == fourcc) + return formats[i].name; + } + + return "Unknown"; +} +#endif + +/* + * fb_var_to_fourcc - Return the format fourcc associated with the var info + * @dev: FB device + * @var_info: Variable screen information + * + * If the device doesn't support the fourcc-based API, or if the format is a + * legacy RGB format, emulate fourcc support based on the bits per pixel value. + * + * Return the format fourcc or 0 if the format isn't known. + */ +static unsigned int fb_var_to_fourcc(const struct device *dev, + const struct fb_var_screeninfo *var_info) +{ +#ifdef FB_VISUAL_FOURCC + if (dev->fix_info.visual == FB_VISUAL_FOURCC) + return var_info->grayscale; +#else + (void)dev; +#endif + + switch (var_info->bits_per_pixel) { + case 16: + return V4L2_PIX_FMT_RGB565; + case 24: + if (var_info->red.offset == 0) + return V4L2_PIX_FMT_RGB24; + else + return V4L2_PIX_FMT_BGR24; + case 32: + if (var_info->red.offset == 0) + return V4L2_PIX_FMT_RGB32; + else + return V4L2_PIX_FMT_BGR32; + default: + return 0; + } +} + +/* + * fb_fourcc_to_rgba - Fill the given var info RGBA bitfields based on a fourcc + * @dev: FB device + * @fourcc: Format fourcc + * @var_info: Variable screen information + * + * Fill the bits_per_pixel, red, green, blue and transp fields based on the + * fourcc. + * + * Return -EINVAL if the fourcc doesn't correspond to an RGB format or 0 + * otherwise. + */ +static int fb_fourcc_to_rgba(unsigned int fourcc, + struct fb_var_screeninfo *var_info) +{ + var_info->grayscale = 0; + + switch (fourcc) { + case V4L2_PIX_FMT_BGR24: + case 24: + var_info->bits_per_pixel = 24; + var_info->red.offset = 16; + var_info->red.length = 8; + var_info->red.msb_right = 0; + var_info->green.offset = 8; + var_info->green.length = 8; + var_info->green.msb_right = 0; + var_info->blue.offset = 0; + var_info->blue.length = 8; + var_info->blue.msb_right = 0; + var_info->transp.offset = 0; + var_info->transp.length = 0; + var_info->transp.msb_right = 0; + break; + case V4L2_PIX_FMT_BGR32: + case 32: + var_info->bits_per_pixel = 32; + var_info->red.offset = 16; + var_info->red.length = 8; + var_info->red.msb_right = 0; + var_info->green.offset = 8; + var_info->green.length = 8; + var_info->green.msb_right = 0; + var_info->blue.offset = 0; + var_info->blue.length = 8; + var_info->blue.msb_right = 0; + var_info->transp.offset = 24; + var_info->transp.length = 8; + var_info->transp.msb_right = 0; + break; + case V4L2_PIX_FMT_RGB24: + var_info->bits_per_pixel = 24; + var_info->red.offset = 0; + var_info->red.length = 8; + var_info->red.msb_right = 0; + var_info->green.offset = 8; + var_info->green.length = 8; + var_info->green.msb_right = 0; + var_info->blue.offset = 16; + var_info->blue.length = 8; + var_info->blue.msb_right = 0; + var_info->transp.offset = 0; + var_info->transp.length = 0; + var_info->transp.msb_right = 0; + break; + case V4L2_PIX_FMT_RGB32: + var_info->bits_per_pixel = 32; + var_info->red.offset = 0; + var_info->red.length = 8; + var_info->red.msb_right = 0; + var_info->green.offset = 8; + var_info->green.length = 8; + var_info->green.msb_right = 0; + var_info->blue.offset = 16; + var_info->blue.length = 8; + var_info->blue.msb_right = 0; + var_info->transp.offset = 24; + var_info->transp.length = 8; + var_info->transp.msb_right = 0; + break; + case V4L2_PIX_FMT_RGB565: + case 16: + var_info->bits_per_pixel = 16; + var_info->red.offset = 11; + var_info->red.length = 5; + var_info->red.msb_right = 0; + var_info->green.offset = 5; + var_info->green.length = 6; + var_info->green.msb_right = 0; + var_info->blue.offset = 0; + var_info->blue.length = 5; + var_info->blue.msb_right = 0; + var_info->transp.offset = 0; + var_info->transp.length = 0; + var_info->transp.msb_right = 0; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* + * fb_fourcc_to_var - Fill the given var info format based on a fourcc + * @dev: FB device + * @var_info: Variable screen information + * @fourcc: Format fourcc + * + * If the device doesn't support the fourcc-based API, fill the red, green, blue + * and transp components fields based on the fourcc. + * + * If the fourcc is smaller than or equal to 32, it will be interpreted as a bpp + * value and the legacy API will be used. + * + * Return -EINVAL if the device doesn't support the fourcc-based API and the + * given fourcc isn't an RGB format. + */ +static int fb_fourcc_to_var(const struct device *dev, unsigned int fourcc, + struct fb_var_screeninfo *var_info) +{ +#ifdef FB_CAP_FOURCC + if (dev->fix_info.capabilities & FB_CAP_FOURCC && fourcc > 32) { + memset(&var_info->red, 0, sizeof var_info->red); + memset(&var_info->green, 0, sizeof var_info->green); + memset(&var_info->blue, 0, sizeof var_info->blue); + memset(&var_info->transp, 0, sizeof var_info->transp); + var_info->grayscale = fourcc; + return 0; + } +#else + (void)dev; +#endif + + return fb_fourcc_to_rgba(fourcc, var_info); +} + /* ----------------------------------------------------------------------------- * FB information display */ @@ -75,6 +284,9 @@ static const struct fb_value_name fb_type_names[] = { { FB_TYPE_INTERLEAVED_PLANES, "Interleaved Planes" }, { FB_TYPE_TEXT, "Text/Attributes" }, { FB_TYPE_VGA_PLANES, "EGA/VGA Planes" }, +#ifdef FB_TYPE_FOURCC + { FB_TYPE_FOURCC, "FourCC" }, +#endif }; static const struct fb_value_name fb_visual_names[] = { @@ -84,6 +296,9 @@ static const struct fb_value_name fb_visual_names[] = { { FB_VISUAL_PSEUDOCOLOR, "Pseudo Color" }, { FB_VISUAL_DIRECTCOLOR, "Direct Color" }, { FB_VISUAL_STATIC_PSEUDOCOLOR, "Pseudo Color (read-only)" }, +#ifdef FB_VISUAL_FOURCC + { FB_VISUAL_FOURCC, "FourCC" }, +#endif }; static const struct fb_value_name fb_accel_names[] = { @@ -278,6 +493,12 @@ static void fb_print_var(struct device *dev, struct fb_var_screeninfo *var) } printf("\n"); } +#ifdef FB_VISUAL_FOURCC + else if (dev->fix_info.visual == FB_VISUAL_FOURCC) { + printf(" Format:\t\t%s (%08x)\n", fb_format_name(var->grayscale), + var->grayscale); + } +#endif } /* ----------------------------------------------------------------------------- @@ -322,6 +543,7 @@ static void fb_unmap_memory(struct device *dev) static int fb_update_info(struct device *dev) { + struct fb_var_screeninfo var_info; int ret; ret = ioctl(dev->fd, FBIOGET_FSCREENINFO, &dev->fix_info); @@ -336,9 +558,18 @@ static int fb_update_info(struct device *dev) return ret; } - dev->red = dev->var_info.red; - dev->green = dev->var_info.green; - dev->blue = dev->var_info.blue; + dev->fourcc = fb_var_to_fourcc(dev, &dev->var_info); + + ret = fb_fourcc_to_rgba(dev->fourcc, &var_info); + if (ret < 0) { + memset(&dev->red, 0, sizeof dev->red); + memset(&dev->green, 0, sizeof dev->green); + memset(&dev->blue, 0, sizeof dev->blue); + } else { + dev->red = var_info.red; + dev->green = var_info.green; + dev->blue = var_info.blue; + } return 0; } @@ -484,24 +715,29 @@ static int fb_wait_for_vsync(struct device *dev, unsigned int screen) } /* ----------------------------------------------------------------------------- - * Resolution and pan + * Formats, resolution and pan */ /* * fb_set_format - Set the frame buffer pixel format * @dev: FB device - * @bpp: Bits per pixel + * @fourcc: Format code */ -static int fb_set_format(struct device *dev, unsigned int bpp) +static int fb_set_format(struct device *dev, unsigned int fourcc) { struct fb_var_screeninfo var_info; int ret; var_info = dev->var_info; - - var_info.bits_per_pixel = bpp; var_info.activate = FB_ACTIVATE_NOW; + ret = fb_fourcc_to_var(dev, fourcc, &var_info); + if (ret < 0) { + printf("Error: device doesn't support non-RGB format %08x\n", + fourcc); + return ret; + } + ret = ioctl(dev->fd, FBIOPUT_VSCREENINFO, &var_info); if (ret < 0) { printf("Error: set format failed: %s (%d)\n", @@ -514,11 +750,11 @@ static int fb_set_format(struct device *dev, unsigned int bpp) printf("Format set to %u bits per pixel\n\n", var_info.bits_per_pixel); - fb_print_var(dev, &var_info); - /* Fixed screen information might have changed, re-read it. */ fb_update_info(dev); + fb_print_var(dev, &var_info); + return 0; } @@ -572,11 +808,11 @@ static int fb_set_resolution(struct device *dev, int xres, int yres, var_info.xres, var_info.yres, var_info.xres_virtual, var_info.yres_virtual); - fb_print_var(dev, &var_info); - /* Fixed screen information might have changed, re-read it. */ fb_update_info(dev); + fb_print_var(dev, &var_info); + return 0; } @@ -614,7 +850,7 @@ static int fb_pan(struct device *dev, unsigned int x, unsigned int y) * Test pattern */ -#define FB_MAKE_COLOR(dev, r, g, b) \ +#define FB_MAKE_RGB(dev, r, g, b) \ ((((r) >> (8 - (dev)->red.length)) << (dev)->red.offset) | \ (((g) >> (8 - (dev)->green.length)) << (dev)->green.offset) | \ (((b) >> (8 - (dev)->blue.length)) << (dev)->blue.offset)) @@ -624,32 +860,32 @@ fb_fill_smpte_rgb16(struct device *dev, unsigned int xoffset, unsigned int yoffset, unsigned int xres, unsigned int yres) { const uint16_t colors_top[] = { - FB_MAKE_COLOR(dev, 192, 192, 192), /* grey */ - FB_MAKE_COLOR(dev, 192, 192, 0), /* yellow */ - FB_MAKE_COLOR(dev, 0, 192, 192), /* cyan */ - FB_MAKE_COLOR(dev, 0, 192, 0), /* green */ - FB_MAKE_COLOR(dev, 192, 0, 192), /* magenta */ - FB_MAKE_COLOR(dev, 192, 0, 0), /* red */ - FB_MAKE_COLOR(dev, 0, 0, 192), /* blue */ + FB_MAKE_RGB(dev, 192, 192, 192), /* grey */ + FB_MAKE_RGB(dev, 192, 192, 0), /* yellow */ + FB_MAKE_RGB(dev, 0, 192, 192), /* cyan */ + FB_MAKE_RGB(dev, 0, 192, 0), /* green */ + FB_MAKE_RGB(dev, 192, 0, 192), /* magenta */ + FB_MAKE_RGB(dev, 192, 0, 0), /* red */ + FB_MAKE_RGB(dev, 0, 0, 192), /* blue */ }; const uint16_t colors_middle[] = { - FB_MAKE_COLOR(dev, 0, 0, 192), /* blue */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 192, 0, 192), /* magenta */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 0, 192, 192), /* cyan */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 192, 192, 192), /* grey */ + FB_MAKE_RGB(dev, 0, 0, 192), /* blue */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 192, 0, 192), /* magenta */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 0, 192, 192), /* cyan */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 192, 192, 192), /* grey */ }; const uint16_t colors_bottom[] = { - FB_MAKE_COLOR(dev, 0, 33, 76), /* in-phase */ - FB_MAKE_COLOR(dev, 255, 255, 255), /* super white */ - FB_MAKE_COLOR(dev, 50, 0, 106), /* quadrature */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 9, 9, 9), /* 3.5% */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* 7.5% */ - FB_MAKE_COLOR(dev, 29, 29, 29), /* 11.5% */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 0, 33, 76), /* in-phase */ + FB_MAKE_RGB(dev, 255, 255, 255), /* super white */ + FB_MAKE_RGB(dev, 50, 0, 106), /* quadrature */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 9, 9, 9), /* 3.5% */ + FB_MAKE_RGB(dev, 19, 19, 19), /* 7.5% */ + FB_MAKE_RGB(dev, 29, 29, 29), /* 11.5% */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ }; void *mem = dev->mem + dev->fix_info.line_length * yoffset + xoffset * dev->var_info.bits_per_pixel / 8; @@ -686,40 +922,40 @@ struct fb_color24 { unsigned int value:24; } __attribute__((__packed__)); -#define FB_MAKE_COLOR24(dev, r, g, b) \ - { .value = FB_MAKE_COLOR(dev, r, g, b) } +#define FB_MAKE_RGB24(dev, r, g, b) \ + { .value = FB_MAKE_RGB(dev, r, g, b) } static void fb_fill_smpte_rgb24(struct device *dev, unsigned int xoffset, unsigned int yoffset, unsigned int xres, unsigned int yres) { const struct fb_color24 colors_top[] = { - FB_MAKE_COLOR24(dev, 192, 192, 192), /* grey */ - FB_MAKE_COLOR24(dev, 192, 192, 0), /* yellow */ - FB_MAKE_COLOR24(dev, 0, 192, 192), /* cyan */ - FB_MAKE_COLOR24(dev, 0, 192, 0), /* green */ - FB_MAKE_COLOR24(dev, 192, 0, 192), /* magenta */ - FB_MAKE_COLOR24(dev, 192, 0, 0), /* red */ - FB_MAKE_COLOR24(dev, 0, 0, 192), /* blue */ + FB_MAKE_RGB24(dev, 192, 192, 192), /* grey */ + FB_MAKE_RGB24(dev, 192, 192, 0), /* yellow */ + FB_MAKE_RGB24(dev, 0, 192, 192), /* cyan */ + FB_MAKE_RGB24(dev, 0, 192, 0), /* green */ + FB_MAKE_RGB24(dev, 192, 0, 192), /* magenta */ + FB_MAKE_RGB24(dev, 192, 0, 0), /* red */ + FB_MAKE_RGB24(dev, 0, 0, 192), /* blue */ }; const struct fb_color24 colors_middle[] = { - FB_MAKE_COLOR24(dev, 0, 0, 192), /* blue */ - FB_MAKE_COLOR24(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR24(dev, 192, 0, 192), /* magenta */ - FB_MAKE_COLOR24(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR24(dev, 0, 192, 192), /* cyan */ - FB_MAKE_COLOR24(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR24(dev, 192, 192, 192), /* grey */ + FB_MAKE_RGB24(dev, 0, 0, 192), /* blue */ + FB_MAKE_RGB24(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB24(dev, 192, 0, 192), /* magenta */ + FB_MAKE_RGB24(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB24(dev, 0, 192, 192), /* cyan */ + FB_MAKE_RGB24(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB24(dev, 192, 192, 192), /* grey */ }; const struct fb_color24 colors_bottom[] = { - FB_MAKE_COLOR24(dev, 0, 33, 76), /* in-phase */ - FB_MAKE_COLOR24(dev, 255, 255, 255), /* super white */ - FB_MAKE_COLOR24(dev, 50, 0, 106), /* quadrature */ - FB_MAKE_COLOR24(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR24(dev, 9, 9, 9), /* 3.5% */ - FB_MAKE_COLOR24(dev, 19, 19, 19), /* 7.5% */ - FB_MAKE_COLOR24(dev, 29, 29, 29), /* 11.5% */ - FB_MAKE_COLOR24(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB24(dev, 0, 33, 76), /* in-phase */ + FB_MAKE_RGB24(dev, 255, 255, 255), /* super white */ + FB_MAKE_RGB24(dev, 50, 0, 106), /* quadrature */ + FB_MAKE_RGB24(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB24(dev, 9, 9, 9), /* 3.5% */ + FB_MAKE_RGB24(dev, 19, 19, 19), /* 7.5% */ + FB_MAKE_RGB24(dev, 29, 29, 29), /* 11.5% */ + FB_MAKE_RGB24(dev, 19, 19, 19), /* black */ }; void *mem = dev->mem + dev->fix_info.line_length * yoffset + xoffset * dev->var_info.bits_per_pixel / 8; @@ -759,32 +995,32 @@ fb_fill_smpte_rgb32(struct device *dev, unsigned int xoffset, unsigned int yoffset, unsigned int xres, unsigned int yres) { const uint32_t colors_top[] = { - FB_MAKE_COLOR(dev, 192, 192, 192), /* grey */ - FB_MAKE_COLOR(dev, 192, 192, 0), /* yellow */ - FB_MAKE_COLOR(dev, 0, 192, 192), /* cyan */ - FB_MAKE_COLOR(dev, 0, 192, 0), /* green */ - FB_MAKE_COLOR(dev, 192, 0, 192), /* magenta */ - FB_MAKE_COLOR(dev, 192, 0, 0), /* red */ - FB_MAKE_COLOR(dev, 0, 0, 192), /* blue */ + FB_MAKE_RGB(dev, 192, 192, 192), /* grey */ + FB_MAKE_RGB(dev, 192, 192, 0), /* yellow */ + FB_MAKE_RGB(dev, 0, 192, 192), /* cyan */ + FB_MAKE_RGB(dev, 0, 192, 0), /* green */ + FB_MAKE_RGB(dev, 192, 0, 192), /* magenta */ + FB_MAKE_RGB(dev, 192, 0, 0), /* red */ + FB_MAKE_RGB(dev, 0, 0, 192), /* blue */ }; const uint32_t colors_middle[] = { - FB_MAKE_COLOR(dev, 0, 0, 192), /* blue */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 192, 0, 192), /* magenta */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 0, 192, 192), /* cyan */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 192, 192, 192), /* grey */ + FB_MAKE_RGB(dev, 0, 0, 192), /* blue */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 192, 0, 192), /* magenta */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 0, 192, 192), /* cyan */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 192, 192, 192), /* grey */ }; const uint32_t colors_bottom[] = { - FB_MAKE_COLOR(dev, 0, 33, 76), /* in-phase */ - FB_MAKE_COLOR(dev, 255, 255, 255), /* super white */ - FB_MAKE_COLOR(dev, 50, 0, 106), /* quadrature */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 9, 9, 9), /* 3.5% */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* 7.5% */ - FB_MAKE_COLOR(dev, 29, 29, 29), /* 11.5% */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 0, 33, 76), /* in-phase */ + FB_MAKE_RGB(dev, 255, 255, 255), /* super white */ + FB_MAKE_RGB(dev, 50, 0, 106), /* quadrature */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 9, 9, 9), /* 3.5% */ + FB_MAKE_RGB(dev, 19, 19, 19), /* 7.5% */ + FB_MAKE_RGB(dev, 29, 29, 29), /* 11.5% */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ }; void *mem = dev->mem + dev->fix_info.line_length * yoffset + xoffset * dev->var_info.bits_per_pixel / 8; @@ -832,12 +1068,14 @@ static void fb_fill_smpte(struct device *dev, unsigned int xoffset, unsigned int yoffset, unsigned int xres, unsigned int yres) { - switch (dev->var_info.bits_per_pixel) { - case 16: + switch (dev->fourcc) { + case V4L2_PIX_FMT_RGB565: return fb_fill_smpte_rgb16(dev, xoffset, yoffset, xres, yres); - case 24: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB24: return fb_fill_smpte_rgb24(dev, xoffset, yoffset, xres, yres); - case 32: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB32: return fb_fill_smpte_rgb32(dev, xoffset, yoffset, xres, yres); } } @@ -847,14 +1085,14 @@ fb_fill_lines_rgb16(struct device *dev, unsigned int xoffset, unsigned int yoffset, unsigned int xres, unsigned int yres) { const uint16_t colors[] = { - FB_MAKE_COLOR(dev, 192, 192, 0), /* yellow */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 0, 192, 0), /* green */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 192, 0, 0), /* red */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 0, 0, 192), /* blue */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 192, 192, 0), /* yellow */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 0, 192, 0), /* green */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 192, 0, 0), /* red */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 0, 0, 192), /* blue */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ }; void *mem = dev->mem + dev->fix_info.line_length * yoffset + xoffset * dev->var_info.bits_per_pixel / 8; @@ -879,14 +1117,14 @@ fb_fill_lines_rgb24(struct device *dev, unsigned int xoffset, unsigned int yoffset, unsigned int xres, unsigned int yres) { const struct fb_color24 colors[] = { - FB_MAKE_COLOR24(dev, 192, 192, 0), /* yellow */ - FB_MAKE_COLOR24(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR24(dev, 0, 192, 0), /* green */ - FB_MAKE_COLOR24(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR24(dev, 192, 0, 0), /* red */ - FB_MAKE_COLOR24(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR24(dev, 0, 0, 192), /* blue */ - FB_MAKE_COLOR24(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB24(dev, 192, 192, 0), /* yellow */ + FB_MAKE_RGB24(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB24(dev, 0, 192, 0), /* green */ + FB_MAKE_RGB24(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB24(dev, 192, 0, 0), /* red */ + FB_MAKE_RGB24(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB24(dev, 0, 0, 192), /* blue */ + FB_MAKE_RGB24(dev, 19, 19, 19), /* black */ }; void *mem = dev->mem + dev->fix_info.line_length * yoffset + xoffset * dev->var_info.bits_per_pixel / 8; @@ -911,14 +1149,14 @@ fb_fill_lines_rgb32(struct device *dev, unsigned int xoffset, unsigned int yoffset, unsigned int xres, unsigned int yres) { const uint32_t colors[] = { - FB_MAKE_COLOR(dev, 192, 192, 0), /* yellow */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 0, 192, 0), /* green */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 192, 0, 0), /* red */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ - FB_MAKE_COLOR(dev, 0, 0, 192), /* blue */ - FB_MAKE_COLOR(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 192, 192, 0), /* yellow */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 0, 192, 0), /* green */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 192, 0, 0), /* red */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ + FB_MAKE_RGB(dev, 0, 0, 192), /* blue */ + FB_MAKE_RGB(dev, 19, 19, 19), /* black */ }; void *mem = dev->mem + dev->fix_info.line_length * yoffset + xoffset * dev->var_info.bits_per_pixel / 8; @@ -953,12 +1191,14 @@ static void fb_fill_lines(struct device *dev, unsigned int xoffset, unsigned int yoffset, unsigned int xres, unsigned int yres) { - switch (dev->var_info.bits_per_pixel) { - case 16: + switch (dev->fourcc) { + case V4L2_PIX_FMT_RGB565: return fb_fill_lines_rgb16(dev, xoffset, yoffset, xres, yres); - case 24: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB24: return fb_fill_lines_rgb24(dev, xoffset, yoffset, xres, yres); - case 32: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB32: return fb_fill_lines_rgb32(dev, xoffset, yoffset, xres, yres); } } @@ -979,17 +1219,23 @@ fb_fill(struct device *dev, enum fb_fill_mode mode, enum fb_fill_pattern pattern unsigned int xoffset, yoffset; unsigned int xres, yres; - if (dev->fix_info.visual != FB_VISUAL_TRUECOLOR) { + if (dev->fix_info.visual != FB_VISUAL_TRUECOLOR +#ifdef FB_VISUAL_FOURCC + && dev->fix_info.visual != FB_VISUAL_FOURCC +#endif + ) { printf("Error: test pattern is only supported for true color " - "visuals.\n"); + "and fourcc visuals.\n"); return; } - if (dev->var_info.bits_per_pixel != 16 && - dev->var_info.bits_per_pixel != 24 && - dev->var_info.bits_per_pixel != 32) { - printf("Error: display depth %u bpp not supported.\n", - dev->var_info.bits_per_pixel); + if (dev->fourcc != V4L2_PIX_FMT_BGR24 && + dev->fourcc != V4L2_PIX_FMT_BGR32 && + dev->fourcc != V4L2_PIX_FMT_RGB24 && + dev->fourcc != V4L2_PIX_FMT_RGB32 && + dev->fourcc != V4L2_PIX_FMT_RGB565) { + printf("Error: display format %08x (%u bpp) not supported.\n", + dev->fourcc, dev->var_info.bits_per_pixel); return; } @@ -1026,11 +1272,13 @@ fb_fill(struct device *dev, enum fb_fill_mode mode, enum fb_fill_pattern pattern static void usage(const char *argv0) { + unsigned int i; + printf("Usage: %s [options] device\n", argv0); printf("Supported options:\n"); printf("-b, --blank mode Set blanking mode\n"); printf("-f, --fill[=mode] Fill the frame buffer with a test pattern\n"); - printf("-F, --format bpp Set the number of bits per pixel\n"); + printf("-F, --format fourcc Set the frame buffer format\n"); printf("-h, --help Show this help screen\n"); printf("-p, --pan x,y Pan the display to position (x,y)\n"); printf("-P, --pattern name Test pattern name\n"); @@ -1041,6 +1289,11 @@ static void usage(const char *argv0) printf("Support fill modes are:\n"); printf(" display Fill the displayed frame buffer only\n"); printf(" virtual Fill the whole virtual frame buffer\n"); + printf("Support formats:\n "); + for (i = 0; i < ARRAY_SIZE(formats); ++i) + printf("%s ", formats[i].name); + printf("\n"); + printf(" 16 24 32 (bpp value, will use the legacy API)\n"); printf("Support test pattern are:\n"); printf(" smpte SMPTE color bars\n"); printf(" lines Color lines\n"); @@ -1086,6 +1339,30 @@ static int fb_blank_parse(const char *arg, int *value) return -1; } +static int fb_format_parse(const char *arg, unsigned int *fourcc) +{ + unsigned int bpp; + unsigned int i; + char *endp; + + for (i = 0; i < ARRAY_SIZE(formats); ++i) { + if (strcasecmp(formats[i].name, arg) == 0) { + *fourcc = formats[i].fourcc; + return 0; + } + } + + bpp = strtoul(arg, &endp, 10); + if (*endp != '\0') + return -1; + + if (bpp != 16 && bpp != 24 && bpp != 32) + return -1; + + *fourcc = bpp; + return 0; +} + static int fb_point_parse(const char *arg, unsigned int *x, unsigned int *y) { unsigned long value; @@ -1137,7 +1414,7 @@ int main(int argc, char *argv[]) enum fb_fill_pattern fill_pattern = FB_PATTERN_SMPTE; bool do_format = false; - unsigned int bpp = 0; + unsigned int fourcc = 0; bool do_pan = false; unsigned int pan_x = 0; @@ -1181,7 +1458,11 @@ int main(int argc, char *argv[]) break; case 'F': do_format = true; - bpp = atoi(optarg); + if (fb_format_parse(optarg, &fourcc) < 0) { + printf("Invalid format `%s'\n", optarg); + printf("Run %s -h for help.\n", argv[0]); + return 1; + } break; case 'h': usage(argv[0]); @@ -1246,7 +1527,7 @@ int main(int argc, char *argv[]) fb_blank(&dev, blank); if (do_format) - fb_set_format(&dev, bpp); + fb_set_format(&dev, fourcc); if (do_resolution) fb_set_resolution(&dev, xres, yres, xres_virtual, yres_virtual); -- cgit v1.2.3