int video_display_bitmap()

in drivers/video/cfb_console.c [1306:1681]


int video_display_bitmap(ulong bmp_image, int x, int y)
{
	ushort xcount, ycount;
	uchar *fb;
	struct bmp_image *bmp = (struct bmp_image *)bmp_image;
	uchar *bmap;
	ushort padded_line;
	unsigned long width, height, bpp;
	unsigned colors;
	unsigned long compression;
	struct bmp_color_table_entry cte;

#ifdef CONFIG_VIDEO_BMP_GZIP
	unsigned char *dst = NULL;
	ulong len;
#endif

	WATCHDOG_RESET();

	if (!((bmp->header.signature[0] == 'B') &&
	      (bmp->header.signature[1] == 'M'))) {

#ifdef CONFIG_VIDEO_BMP_GZIP
		/*
		 * Could be a gzipped bmp image, try to decrompress...
		 */
		len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
		dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
		if (dst == NULL) {
			printf("Error: malloc in gunzip failed!\n");
			return 1;
		}
		/*
		 * NB: we need to force offset of +2
		 * See doc/README.displaying-bmps
		 */
		if (gunzip(dst+2, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE-2,
			   (uchar *) bmp_image,
			   &len) != 0) {
			printf("Error: no valid bmp or bmp.gz image at %lx\n",
			       bmp_image);
			free(dst);
			return 1;
		}
		if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
			printf("Image could be truncated "
				"(increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
		}

		/*
		 * Set addr to decompressed image
		 */
		bmp = (struct bmp_image *)(dst+2);

		if (!((bmp->header.signature[0] == 'B') &&
		      (bmp->header.signature[1] == 'M'))) {
			printf("Error: no valid bmp.gz image at %lx\n",
			       bmp_image);
			free(dst);
			return 1;
		}
#else
		printf("Error: no valid bmp image at %lx\n", bmp_image);
		return 1;
#endif /* CONFIG_VIDEO_BMP_GZIP */
	}

	width = le32_to_cpu(bmp->header.width);
	height = le32_to_cpu(bmp->header.height);
	bpp = le16_to_cpu(bmp->header.bit_count);
	colors = le32_to_cpu(bmp->header.colors_used);
	compression = le32_to_cpu(bmp->header.compression);

	debug("Display-bmp: %ld x %ld  with %d colors\n",
	      width, height, colors);

	if (compression != BMP_BI_RGB
#ifdef CONFIG_VIDEO_BMP_RLE8
	    && compression != BMP_BI_RLE8
#endif
		) {
		printf("Error: compression type %ld not supported\n",
		       compression);
#ifdef CONFIG_VIDEO_BMP_GZIP
		if (dst)
			free(dst);
#endif
		return 1;
	}

	padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3;

#ifdef CONFIG_SPLASH_SCREEN_ALIGN
	if (x == BMP_ALIGN_CENTER)
		x = max(0, (int)(VIDEO_VISIBLE_COLS - width) / 2);
	else if (x < 0)
		x = max(0, (int)(VIDEO_VISIBLE_COLS - width + x + 1));

	if (y == BMP_ALIGN_CENTER)
		y = max(0, (int)(VIDEO_VISIBLE_ROWS - height) / 2);
	else if (y < 0)
		y = max(0, (int)(VIDEO_VISIBLE_ROWS - height + y + 1));
#endif /* CONFIG_SPLASH_SCREEN_ALIGN */

	/*
	 * Just ignore elements which are completely beyond screen
	 * dimensions.
	 */
	if ((x >= VIDEO_VISIBLE_COLS) || (y >= VIDEO_VISIBLE_ROWS))
		return 0;

	if ((x + width) > VIDEO_VISIBLE_COLS)
		width = VIDEO_VISIBLE_COLS - x;
	if ((y + height) > VIDEO_VISIBLE_ROWS)
		height = VIDEO_VISIBLE_ROWS - y;

	bmap = (uchar *) bmp + le32_to_cpu(bmp->header.data_offset);
	fb = (uchar *) (video_fb_address +
			((y + height - 1) * VIDEO_LINE_LEN) +
			x * VIDEO_PIXEL_SIZE);

#ifdef CONFIG_VIDEO_BMP_RLE8
	if (compression == BMP_BI_RLE8) {
		return display_rle8_bitmap(bmp, x, y, width, height);
	}
#endif

	/* We handle only 4, 8, or 24 bpp bitmaps */
	switch (le16_to_cpu(bmp->header.bit_count)) {
	case 4:
		padded_line -= width / 2;
		ycount = height;

		switch (VIDEO_DATA_FORMAT) {
		case GDF_32BIT_X888RGB:
			while (ycount--) {
				WATCHDOG_RESET();
				/*
				 * Don't assume that 'width' is an
				 * even number
				 */
				for (xcount = 0; xcount < width; xcount++) {
					uchar idx;

					if (xcount & 1) {
						idx = *bmap & 0xF;
						bmap++;
					} else
						idx = *bmap >> 4;
					cte = bmp->color_table[idx];
					FILL_32BIT_X888RGB(cte.red, cte.green,
							   cte.blue);
				}
				bmap += padded_line;
				fb -= VIDEO_LINE_LEN + width *
					VIDEO_PIXEL_SIZE;
			}
			break;
		default:
			puts("4bpp bitmap unsupported with current "
			     "video mode\n");
			break;
		}
		break;

	case 8:
		padded_line -= width;
		if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
			/* Copy colormap */
			for (xcount = 0; xcount < colors; ++xcount) {
				cte = bmp->color_table[xcount];
				video_set_lut(xcount, cte.red, cte.green,
					      cte.blue);
			}
		}
		ycount = height;
		switch (VIDEO_DATA_FORMAT) {
		case GDF__8BIT_INDEX:
			while (ycount--) {
				WATCHDOG_RESET();
				xcount = width;
				while (xcount--) {
					*fb++ = *bmap++;
				}
				bmap += padded_line;
				fb -= VIDEO_LINE_LEN + width *
					VIDEO_PIXEL_SIZE;
			}
			break;
		case GDF__8BIT_332RGB:
			while (ycount--) {
				WATCHDOG_RESET();
				xcount = width;
				while (xcount--) {
					cte = bmp->color_table[*bmap++];
					FILL_8BIT_332RGB(cte.red, cte.green,
							 cte.blue);
				}
				bmap += padded_line;
				fb -= VIDEO_LINE_LEN + width *
					VIDEO_PIXEL_SIZE;
			}
			break;
		case GDF_15BIT_555RGB:
			while (ycount--) {
#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
				int xpos = x;
#endif
				WATCHDOG_RESET();
				xcount = width;
				while (xcount--) {
					cte = bmp->color_table[*bmap++];
#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
					fill_555rgb_pswap(fb, xpos++, cte.red,
							  cte.green,
							  cte.blue);
					fb += 2;
#else
					FILL_15BIT_555RGB(cte.red, cte.green,
							  cte.blue);
#endif
				}
				bmap += padded_line;
				fb -= VIDEO_LINE_LEN + width *
					VIDEO_PIXEL_SIZE;
			}
			break;
		case GDF_16BIT_565RGB:
			while (ycount--) {
				WATCHDOG_RESET();
				xcount = width;
				while (xcount--) {
					cte = bmp->color_table[*bmap++];
					FILL_16BIT_565RGB(cte.red, cte.green,
							  cte.blue);
				}
				bmap += padded_line;
				fb -= VIDEO_LINE_LEN + width *
					VIDEO_PIXEL_SIZE;
			}
			break;
		case GDF_32BIT_X888RGB:
			while (ycount--) {
				WATCHDOG_RESET();
				xcount = width;
				while (xcount--) {
					cte = bmp->color_table[*bmap++];
					FILL_32BIT_X888RGB(cte.red, cte.green,
							   cte.blue);
				}
				bmap += padded_line;
				fb -= VIDEO_LINE_LEN + width *
					VIDEO_PIXEL_SIZE;
			}
			break;
		case GDF_24BIT_888RGB:
			while (ycount--) {
				WATCHDOG_RESET();
				xcount = width;
				while (xcount--) {
					cte = bmp->color_table[*bmap++];
					FILL_24BIT_888RGB(cte.red, cte.green,
							  cte.blue);
				}
				bmap += padded_line;
				fb -= VIDEO_LINE_LEN + width *
					VIDEO_PIXEL_SIZE;
			}
			break;
		}
		break;
	case 24:
		padded_line -= 3 * width;
		ycount = height;
		switch (VIDEO_DATA_FORMAT) {
		case GDF__8BIT_332RGB:
			while (ycount--) {
				WATCHDOG_RESET();
				xcount = width;
				while (xcount--) {
					FILL_8BIT_332RGB(bmap[2], bmap[1],
							 bmap[0]);
					bmap += 3;
				}
				bmap += padded_line;
				fb -= VIDEO_LINE_LEN + width *
					VIDEO_PIXEL_SIZE;
			}
			break;
		case GDF_15BIT_555RGB:
			while (ycount--) {
#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
				int xpos = x;
#endif
				WATCHDOG_RESET();
				xcount = width;
				while (xcount--) {
#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
					fill_555rgb_pswap(fb, xpos++, bmap[2],
							  bmap[1], bmap[0]);
					fb += 2;
#else
					FILL_15BIT_555RGB(bmap[2], bmap[1],
							  bmap[0]);
#endif
					bmap += 3;
				}
				bmap += padded_line;
				fb -= VIDEO_LINE_LEN + width *
					VIDEO_PIXEL_SIZE;
			}
			break;
		case GDF_16BIT_565RGB:
			while (ycount--) {
				WATCHDOG_RESET();
				xcount = width;
				while (xcount--) {
					FILL_16BIT_565RGB(bmap[2], bmap[1],
							  bmap[0]);
					bmap += 3;
				}
				bmap += padded_line;
				fb -= VIDEO_LINE_LEN + width *
					VIDEO_PIXEL_SIZE;
			}
			break;
		case GDF_32BIT_X888RGB:
			while (ycount--) {
				WATCHDOG_RESET();
				xcount = width;
				while (xcount--) {
					FILL_32BIT_X888RGB(bmap[2], bmap[1],
							   bmap[0]);
					bmap += 3;
				}
				bmap += padded_line;
				fb -= VIDEO_LINE_LEN + width *
					VIDEO_PIXEL_SIZE;
			}
			break;
		case GDF_24BIT_888RGB:
			while (ycount--) {
				WATCHDOG_RESET();
				xcount = width;
				while (xcount--) {
					FILL_24BIT_888RGB(bmap[2], bmap[1],
							  bmap[0]);
					bmap += 3;
				}
				bmap += padded_line;
				fb -= VIDEO_LINE_LEN + width *
					VIDEO_PIXEL_SIZE;
			}
			break;
		default:
			printf("Error: 24 bits/pixel bitmap incompatible "
				"with current video mode\n");
			break;
		}
		break;
	default:
		printf("Error: %d bit/pixel bitmaps not supported by U-Boot\n",
			le16_to_cpu(bmp->header.bit_count));
		break;
	}

#ifdef CONFIG_VIDEO_BMP_GZIP
	if (dst) {
		free(dst);
	}
#endif

	if (cfb_do_flush_cache)
		flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
	return (0);
}