2 * linux/drivers/video/rockchip/bmp_helper.c
4 * Copyright (C) 2012 Rockchip Corporation
5 * Author: Mark Yao <mark.yao@rock-chips.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <linux/sysfs.h>
21 #include <linux/uaccess.h>
22 #include <linux/kernel.h>
23 #include <linux/rk_fb.h>
25 #include "bmp_helper.h"
27 static void draw_unencoded_bitmap(uint16_t **dst, uint8_t *bmap, uint16_t *cmap,
31 *(*dst)++ = cmap[*bmap++];
36 static void draw_encoded_bitmap(uint16_t **dst, uint16_t c, uint32_t cnt)
39 int cnt_8copy = cnt >> 3;
41 cnt -= cnt_8copy << 3;
42 while (cnt_8copy > 0) {
60 static void yuv_to_rgb(int y, int u, int v, int *r, int *g, int *b)
62 int rdif, invgdif, bdif;
66 rdif = v + ((v * 103) >> 8);
67 invgdif = ((u * 88) >> 8) + ((v * 183) >> 8);
68 bdif = u + ((u*198) >> 8);
69 *r = range(y + rdif, 0, 0xff);
70 *g = range(y - invgdif, 0, 0xff);
71 *b = range(y + bdif, 0, 0xff);
74 int bmpencoder(void *__iomem *vaddr, int width, int height, u8 data_format,
75 void *data, void (*fn)(void *, void *, int))
77 uint32_t *d, *d1, *d2;
78 uint8_t *dst, *yrgb, *uv, *y1, *y2;
81 int yu = width * 4 % 4;
85 BITMAPINFOHEADER infoheader;
89 yu = yu != 0 ? 4 - yu : yu;
90 byteperline = width * 4 + yu;
91 size = byteperline * height + 54;
92 memset(&header, 0, sizeof(header));
93 memset(&infoheader, 0, sizeof(infoheader));
94 header.type = 'M'<<8|'B';
99 infoheader.width = width;
100 infoheader.height = 0 - height;
101 infoheader.bitcount = 4 * 8;
102 infoheader.compression = 0;
103 infoheader.imagesize = byteperline * height;
104 infoheader.xpelspermeter = 0;
105 infoheader.ypelspermeter = 0;
106 infoheader.colors = 0;
107 infoheader.colorsimportant = 0;
108 fn(data, (void *)&header, sizeof(header));
109 fn(data, (void *)&infoheader, sizeof(infoheader));
112 * if data_format is ARGB888 or XRGB888, not need convert.
114 if (data_format == ARGB888 || data_format == XRGB888) {
115 fn(data, (char *)vaddr, width * height * 4);
119 * alloc 2 line buffer.
121 buf = kmalloc(width * 2 * 4, GFP_KERNEL);
124 yrgb = (uint8_t *)vaddr;
125 uv = yrgb + width * height;
126 for (j = 0; j < height; j++) {
129 y1 = yrgb + j * width;
135 for (i = 0; i < width; i++) {
136 switch (data_format) {
155 dst[0] = (yrgb[0] & 0x1f) << 3;
156 dst[1] = (yrgb[0] & 0xe0) >> 3 |
157 (yrgb[1] & 0x7) << 5;
158 dst[2] = yrgb[1] & 0xf8;
166 if (data_format == YUV420) {
178 } else if (data_format == YUV422) {
189 yuv_to_rgb(y, u, v, &r, &g, &b);
190 *d = 0xff<<24 | r << 16 | g << 8 | b;
195 pr_err("unsupport now\n");
200 fn(data, (char *)buf, 2 * width * 4);
206 static void decode_rle8_bitmap(uint8_t *psrc, uint8_t *pdst, uint16_t *cmap,
207 unsigned int width, unsigned int height,
208 int bits, int x_off, int y_off, bool flip)
210 uint32_t cnt, runlen;
213 uint8_t *bmap = psrc;
215 int linesize = width * 2;
219 dst = pdst + y * linesize;
223 if (bmap[0] == BMP_RLE8_ESCAPE) {
245 dst -= bmap[3] * linesize;
249 dst += bmap[3] * linesize;
258 if (y >= height || x >= width) {
262 if (x + runlen > width)
266 draw_unencoded_bitmap((uint16_t **)&dst, bmap,
278 /* aggregate the same code */
279 while (bmap[0] == 0xff &&
280 bmap[2] != BMP_RLE8_ESCAPE &&
281 bmap[1] == bmap[3]) {
285 if (x + runlen > width)
289 draw_encoded_bitmap((uint16_t **)&dst,
299 int bmpdecoder(void *bmp_addr, void *pdst, int *width, int *height, int *bits)
302 BITMAPINFOHEADER infoheader;
303 uint16_t *bmp_logo_palette;
307 char *src = bmp_addr;
312 memcpy(&header, src, sizeof(header));
313 src += sizeof(header);
315 if (header.type != 0x4d42) {
316 pr_err("not bmp file type[%x], can't support\n", header.type);
319 memcpy(&infoheader, src, sizeof(infoheader));
320 *width = infoheader.width;
321 *height = infoheader.height;
324 *height = 0 - *height;
328 size = header.size - header.offset;
329 linesize = *width * infoheader.bitcount >> 3;
330 cmap_base = src + sizeof(infoheader);
331 src = bmp_addr + header.offset;
333 switch (infoheader.bitcount) {
335 bmp_logo_palette = kmalloc(sizeof(bmp_logo_palette) * 256, GFP_KERNEL);
338 for (i = 0; i < 256; i++) {
339 ushort colreg = ((cmap_base[2] << 8) & 0xf800) |
340 ((cmap_base[1] << 3) & 0x07e0) |
341 ((cmap_base[0] >> 3) & 0x001f) ;
343 bmp_logo_palette[i] = colreg;
347 * only support convert 8bit bmap file to RGB565.
349 decode_rle8_bitmap(src, dst, bmp_logo_palette,
350 infoheader.width, infoheader.height,
351 infoheader.bitcount, 0, 0, flip);
352 kfree(bmp_logo_palette);
359 pr_info("unsupport bit=%d now\n", infoheader.bitcount);
363 src += (*width) * (*height - 1) * 3;
365 for (i = 0; i < *height; i++) {
366 memcpy(dst, src, 3 * (*width));
370 src -= *width * 3 * 2;
379 pr_info("unsupport bit=%d now\n", infoheader.bitcount);
382 pr_info("unsupport bit=%d now\n", infoheader.bitcount);