diff options
| -rw-r--r-- | fbdev.c | 529 | 
1 files changed, 405 insertions, 124 deletions
@@ -33,6 +33,7 @@  #include <sys/time.h>  #include <linux/fb.h> +#include <linux/videodev2.h>  #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 { @@ -61,6 +64,212 @@ enum fb_fill_pattern {  };  /* ----------------------------------------------------------------------------- + * 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);  | 
