This series further enhances the bootsplash code. The last patch enables it by default (for coreboot users).
Kevin O'Connor (5): Avoid using BSS variables in jpeg.c. Breakup jpeg_decode into parsing and displaying phases. Rename "decdata" to "jpeg" in bootsplash - to be consistent with jpeg.c. Autodetect video mode based on bootsplash jpeg dimensions. Default bootsplash on (for coreboot users).
src/bootsplash.c | 117 +++++++++++++------- src/config.h | 10 +-- src/jpeg.c | 307 +++++++++++++++++++++++++++++------------------------- src/jpeg.h | 37 +------ 4 files changed, 248 insertions(+), 223 deletions(-)
Using BSS increases the rom size (and reduce space for option roms). So, move BSS variables in the jpeg.c code to malloc'd memory.
Also, move struct and error declarations from jpeg.h to jpeg.c. --- src/bootsplash.c | 2 +- src/jpeg.c | 283 +++++++++++++++++++++++++++++------------------------- src/jpeg.h | 36 +------ 3 files changed, 158 insertions(+), 163 deletions(-)
diff --git a/src/bootsplash.c b/src/bootsplash.c index ed10415..2c45406 100644 --- a/src/bootsplash.c +++ b/src/bootsplash.c @@ -127,7 +127,7 @@ void enable_vga_console(void) picture = malloc_tmphigh(imagesize); vesa_info = malloc_tmplow(sizeof(*vesa_info)); mode_info = malloc_tmplow(sizeof(*mode_info)); - decdata = malloc_tmphigh(sizeof(*decdata)); + decdata = jpeg_alloc(); if (!jpeg || !picture || !vesa_info || !mode_info || !decdata) { warn_noalloc(); goto gotext; diff --git a/src/jpeg.c b/src/jpeg.c index 711f810..b204345 100644 --- a/src/jpeg.c +++ b/src/jpeg.c @@ -97,11 +97,9 @@ struct dec_hufftbl { unsigned int llvals[1 << DECBITS]; };
-static void decode_mcus -__P((struct in *, int *, int, struct scan *, int *)); +static void decode_mcus __P((struct in *, int *, int, struct scan *, int *)); static int dec_readmarker __P((struct in *)); -static void dec_makehuff -__P((struct dec_hufftbl *, int *, unsigned char *)); +static void dec_makehuff __P((struct dec_hufftbl *, int *, unsigned char *));
static void setinput __P((struct in *, unsigned char *)); /*********************************/ @@ -123,6 +121,24 @@ static void col221111_32 __P((int *, unsigned char *, int));
/*********************************/
+#define ERR_NO_SOI 1 +#define ERR_NOT_8BIT 2 +#define ERR_HEIGHT_MISMATCH 3 +#define ERR_WIDTH_MISMATCH 4 +#define ERR_BAD_WIDTH_OR_HEIGHT 5 +#define ERR_TOO_MANY_COMPPS 6 +#define ERR_ILLEGAL_HV 7 +#define ERR_QUANT_TABLE_SELECTOR 8 +#define ERR_NOT_YCBCR_221111 9 +#define ERR_UNKNOWN_CID_IN_SCAN 10 +#define ERR_NOT_SEQUENTIAL_DCT 11 +#define ERR_WRONG_MARKER 12 +#define ERR_NO_EOI 13 +#define ERR_BAD_TABLES 14 +#define ERR_DEPTH_MISMATCH 15 + +/*********************************/ + #define M_SOI 0xd8 #define M_APP0 0xe0 #define M_DQT 0xdb @@ -134,21 +150,6 @@ static void col221111_32 __P((int *, unsigned char *, int)); #define M_EOI 0xd9 #define M_COM 0xfe
-static unsigned char *datap; - -static int getbyte(void) -{ - return *datap++; -} - -static int getword(void) -{ - int c1, c2; - c1 = *datap++; - c2 = *datap++; - return c1 << 8 | c2; -} - struct comp { int cid; int hv; @@ -164,29 +165,42 @@ struct jpginfo { int rm; /* next restart marker */ };
-static struct jpginfo info; -static struct comp comps[MAXCOMP]; - -static struct scan dscans[MAXCOMP]; - -static unsigned char quant[4][64]; - -static struct dec_hufftbl dhuff[4]; +struct jpeg_decdata { + int dcts[6 * 64 + 16]; + int out[64 * 6]; + int dquant[3][64]; + + unsigned char *datap; + struct jpginfo info; + struct comp comps[MAXCOMP]; + struct scan dscans[MAXCOMP]; + unsigned char quant[4][64]; + struct dec_hufftbl dhuff[4]; + struct in in; +};
-#define dec_huffdc (dhuff + 0) -#define dec_huffac (dhuff + 2) +static int getbyte(struct jpeg_decdata *jpeg) +{ + return *jpeg->datap++; +}
-static struct in in; +static int getword(struct jpeg_decdata *jpeg) +{ + int c1, c2; + c1 = *jpeg->datap++; + c2 = *jpeg->datap++; + return c1 << 8 | c2; +}
-static int readtables(int till) +static int readtables(struct jpeg_decdata *jpeg, int till) { int m, l, i, j, lq, pq, tq; int tc, th, tt;
for (;;) { - if (getbyte() != 0xff) + if (getbyte(jpeg) != 0xff) return -1; - if ((m = getbyte()) == till) + if ((m = getbyte(jpeg)) == till) break;
switch (m) { @@ -194,9 +208,9 @@ static int readtables(int till) return 0;
case M_DQT: - lq = getword(); + lq = getword(jpeg); while (lq > 2) { - pq = getbyte(); + pq = getbyte(jpeg); tq = pq & 15; if (tq > 3) return -1; @@ -204,176 +218,184 @@ static int readtables(int till) if (pq != 0) return -1; for (i = 0; i < 64; i++) - quant[tq][i] = getbyte(); + jpeg->quant[tq][i] = getbyte(jpeg); lq -= 64 + 1; } break;
case M_DHT: - l = getword(); + l = getword(jpeg); while (l > 2) { int hufflen[16], k; unsigned char huffvals[256];
- tc = getbyte(); + tc = getbyte(jpeg); th = tc & 15; tc >>= 4; tt = tc * 2 + th; if (tc > 1 || th > 1) return -1; for (i = 0; i < 16; i++) - hufflen[i] = getbyte(); + hufflen[i] = getbyte(jpeg); l -= 1 + 16; k = 0; for (i = 0; i < 16; i++) { for (j = 0; j < hufflen[i]; j++) - huffvals[k++] = getbyte(); + huffvals[k++] = getbyte(jpeg); l -= hufflen[i]; } - dec_makehuff(dhuff + tt, hufflen, huffvals); + dec_makehuff(jpeg->dhuff + tt, hufflen, huffvals); } break;
case M_DRI: - l = getword(); - info.dri = getword(); + l = getword(jpeg); + jpeg->info.dri = getword(jpeg); break;
default: - l = getword(); + l = getword(jpeg); while (l-- > 2) - getbyte(); + getbyte(jpeg); break; } } return 0; }
-static void dec_initscans(void) +static void dec_initscans(struct jpeg_decdata *jpeg) { int i;
- info.nm = info.dri + 1; - info.rm = M_RST0; - for (i = 0; i < info.ns; i++) - dscans[i].dc = 0; + jpeg->info.nm = jpeg->info.dri + 1; + jpeg->info.rm = M_RST0; + for (i = 0; i < jpeg->info.ns; i++) + jpeg->dscans[i].dc = 0; }
-static int dec_checkmarker(void) +static int dec_checkmarker(struct jpeg_decdata *jpeg) { int i;
- if (dec_readmarker(&in) != info.rm) + if (dec_readmarker(&jpeg->in) != jpeg->info.rm) return -1; - info.nm = info.dri; - info.rm = (info.rm + 1) & ~0x08; - for (i = 0; i < info.ns; i++) - dscans[i].dc = 0; + jpeg->info.nm = jpeg->info.dri; + jpeg->info.rm = (jpeg->info.rm + 1) & ~0x08; + for (i = 0; i < jpeg->info.ns; i++) + jpeg->dscans[i].dc = 0; return 0; }
-int jpeg_check_size(unsigned char *buf, int width, int height) +struct jpeg_decdata *jpeg_alloc(void) +{ + struct jpeg_decdata *jpeg = malloc_tmphigh(sizeof(*jpeg)); + return jpeg; +} + +int jpeg_check_size(struct jpeg_decdata *jpeg, unsigned char *buf + , int width, int height) { - datap = buf; - getbyte(); - getbyte(); - readtables(M_SOF0); - getword(); - getbyte(); - if (height != getword() || width != getword()) + jpeg->datap = buf; + getbyte(jpeg); + getbyte(jpeg); + readtables(jpeg, M_SOF0); + getword(jpeg); + getbyte(jpeg); + if (height != getword(jpeg) || width != getword(jpeg)) return 0; return 1; }
int jpeg_decode(unsigned char *buf, unsigned char *pic, int width, int height, int depth, - struct jpeg_decdata *decdata) + struct jpeg_decdata *jpeg) { int i, j, m, tac, tdc; int mcusx, mcusy, mx, my; int max[6];
- if (!decdata || !buf || !pic) + if (!jpeg || !buf || !pic) return -1; - datap = buf; - if (getbyte() != 0xff) + jpeg->datap = buf; + if (getbyte(jpeg) != 0xff) return ERR_NO_SOI; - if (getbyte() != M_SOI) + if (getbyte(jpeg) != M_SOI) return ERR_NO_SOI; - if (readtables(M_SOF0)) + if (readtables(jpeg, M_SOF0)) return ERR_BAD_TABLES; - getword(); - i = getbyte(); + getword(jpeg); + i = getbyte(jpeg); if (i != 8) return ERR_NOT_8BIT; - if (((getword() + 15) & ~15) != height) + if (((getword(jpeg) + 15) & ~15) != height) return ERR_HEIGHT_MISMATCH; - if (((getword() + 15) & ~15) != width) + if (((getword(jpeg) + 15) & ~15) != width) return ERR_WIDTH_MISMATCH; if ((height & 15) || (width & 15)) return ERR_BAD_WIDTH_OR_HEIGHT; - info.nc = getbyte(); - if (info.nc > MAXCOMP) + jpeg->info.nc = getbyte(jpeg); + if (jpeg->info.nc > MAXCOMP) return ERR_TOO_MANY_COMPPS; - for (i = 0; i < info.nc; i++) { + for (i = 0; i < jpeg->info.nc; i++) { int h, v; - comps[i].cid = getbyte(); - comps[i].hv = getbyte(); - v = comps[i].hv & 15; - h = comps[i].hv >> 4; - comps[i].tq = getbyte(); + jpeg->comps[i].cid = getbyte(jpeg); + jpeg->comps[i].hv = getbyte(jpeg); + v = jpeg->comps[i].hv & 15; + h = jpeg->comps[i].hv >> 4; + jpeg->comps[i].tq = getbyte(jpeg); if (h > 3 || v > 3) return ERR_ILLEGAL_HV; - if (comps[i].tq > 3) + if (jpeg->comps[i].tq > 3) return ERR_QUANT_TABLE_SELECTOR; } - if (readtables(M_SOS)) + if (readtables(jpeg, M_SOS)) return ERR_BAD_TABLES; - getword(); - info.ns = getbyte(); - if (info.ns != 3) + getword(jpeg); + jpeg->info.ns = getbyte(jpeg); + if (jpeg->info.ns != 3) return ERR_NOT_YCBCR_221111; for (i = 0; i < 3; i++) { - dscans[i].cid = getbyte(); - tdc = getbyte(); + jpeg->dscans[i].cid = getbyte(jpeg); + tdc = getbyte(jpeg); tac = tdc & 15; tdc >>= 4; if (tdc > 1 || tac > 1) return ERR_QUANT_TABLE_SELECTOR; - for (j = 0; j < info.nc; j++) - if (comps[j].cid == dscans[i].cid) + for (j = 0; j < jpeg->info.nc; j++) + if (jpeg->comps[j].cid == jpeg->dscans[i].cid) break; - if (j == info.nc) + if (j == jpeg->info.nc) return ERR_UNKNOWN_CID_IN_SCAN; - dscans[i].hv = comps[j].hv; - dscans[i].tq = comps[j].tq; - dscans[i].hudc.dhuff = dec_huffdc + tdc; - dscans[i].huac.dhuff = dec_huffac + tac; + jpeg->dscans[i].hv = jpeg->comps[j].hv; + jpeg->dscans[i].tq = jpeg->comps[j].tq; + jpeg->dscans[i].hudc.dhuff = &jpeg->dhuff[tdc]; + jpeg->dscans[i].huac.dhuff = &jpeg->dhuff[2 + tac]; }
- i = getbyte(); - j = getbyte(); - m = getbyte(); + i = getbyte(jpeg); + j = getbyte(jpeg); + m = getbyte(jpeg);
if (i != 0 || j != 63 || m != 0) return ERR_NOT_SEQUENTIAL_DCT;
- if (dscans[0].cid != 1 || dscans[1].cid != 2 || dscans[2].cid != 3) + if (jpeg->dscans[0].cid != 1 || jpeg->dscans[1].cid != 2 + || jpeg->dscans[2].cid != 3) return ERR_NOT_YCBCR_221111;
- if (dscans[0].hv != 0x22 || dscans[1].hv != 0x11 - || dscans[2].hv != 0x11) + if (jpeg->dscans[0].hv != 0x22 || jpeg->dscans[1].hv != 0x11 + || jpeg->dscans[2].hv != 0x11) return ERR_NOT_YCBCR_221111;
mcusx = width >> 4; mcusy = height >> 4;
- idctqtab(quant[dscans[0].tq], decdata->dquant[0]); - idctqtab(quant[dscans[1].tq], decdata->dquant[1]); - idctqtab(quant[dscans[2].tq], decdata->dquant[2]); - initcol(decdata->dquant); - setinput(&in, datap); + idctqtab(jpeg->quant[jpeg->dscans[0].tq], jpeg->dquant[0]); + idctqtab(jpeg->quant[jpeg->dscans[1].tq], jpeg->dquant[1]); + idctqtab(jpeg->quant[jpeg->dscans[2].tq], jpeg->dquant[2]); + initcol(jpeg->dquant); + setinput(&jpeg->in, jpeg->datap);
#if 0 /* landing zone */ @@ -382,44 +404,44 @@ int jpeg_decode(unsigned char *buf, unsigned char *pic, img[len + 2] = M_EOF; #endif
- dec_initscans(); + dec_initscans(jpeg);
- dscans[0].next = 6 - 4; - dscans[1].next = 6 - 4 - 1; - dscans[2].next = 6 - 4 - 1 - 1; /* 411 encoding */ + jpeg->dscans[0].next = 6 - 4; + jpeg->dscans[1].next = 6 - 4 - 1; + jpeg->dscans[2].next = 6 - 4 - 1 - 1; /* 411 encoding */ for (my = 0; my < mcusy; my++) { for (mx = 0; mx < mcusx; mx++) { - if (info.dri && !--info.nm) - if (dec_checkmarker()) + if (jpeg->info.dri && !--jpeg->info.nm) + if (dec_checkmarker(jpeg)) return ERR_WRONG_MARKER;
- decode_mcus(&in, decdata->dcts, 6, dscans, max); - idct(decdata->dcts, decdata->out, decdata->dquant[0], + decode_mcus(&jpeg->in, jpeg->dcts, 6, jpeg->dscans, max); + idct(jpeg->dcts, jpeg->out, jpeg->dquant[0], IFIX(128.5), max[0]); - idct(decdata->dcts + 64, decdata->out + 64, decdata->dquant[0], + idct(jpeg->dcts + 64, jpeg->out + 64, jpeg->dquant[0], IFIX(128.5), max[1]); - idct(decdata->dcts + 128, decdata->out + 128, - decdata->dquant[0], IFIX(128.5), max[2]); - idct(decdata->dcts + 192, decdata->out + 192, - decdata->dquant[0], IFIX(128.5), max[3]); - idct(decdata->dcts + 256, decdata->out + 256, - decdata->dquant[1], IFIX(0.5), max[4]); - idct(decdata->dcts + 320, decdata->out + 320, - decdata->dquant[2], IFIX(0.5), max[5]); + idct(jpeg->dcts + 128, jpeg->out + 128, + jpeg->dquant[0], IFIX(128.5), max[2]); + idct(jpeg->dcts + 192, jpeg->out + 192, + jpeg->dquant[0], IFIX(128.5), max[3]); + idct(jpeg->dcts + 256, jpeg->out + 256, + jpeg->dquant[1], IFIX(0.5), max[4]); + idct(jpeg->dcts + 320, jpeg->out + 320, + jpeg->dquant[2], IFIX(0.5), max[5]);
switch (depth) { case 32: - col221111_32(decdata->out, + col221111_32(jpeg->out, pic + (my * 16 * mcusx + mx) * 16 * 4, mcusx * 16 * 4); break; case 24: - col221111(decdata->out, + col221111(jpeg->out, pic + (my * 16 * mcusx + mx) * 16 * 3, mcusx * 16 * 3); break; case 16: - col221111_16(decdata->out, + col221111_16(jpeg->out, pic + (my * 16 * mcusx + mx) * (16 * 2), mcusx * (16 * 2)); break; @@ -430,7 +452,7 @@ int jpeg_decode(unsigned char *buf, unsigned char *pic, } }
- m = dec_readmarker(&in); + m = dec_readmarker(&jpeg->in); if (m != M_EOI) return ERR_NO_EOI;
@@ -442,8 +464,7 @@ int jpeg_decode(unsigned char *buf, unsigned char *pic, /****************************************************************/
static int fillbits __P((struct in *, int, unsigned int)); -static int dec_rec2 -__P((struct in *, struct dec_hufftbl *, int *, int, int)); +static int dec_rec2 __P((struct in *, struct dec_hufftbl *, int *, int, int));
static void setinput(struct in *in, unsigned char *p) { @@ -696,7 +717,7 @@ static unsigned char zig2[64] = { 6, 13, 17, 24, 32, 38, 47, 49 };
-void idct(int *in, int *out, PREC * quant, PREC off, int max) +static void idct(int *in, int *out, PREC * quant, PREC off, int max) { PREC t0, t1, t2, t3, t4, t5, t6, t7, t; PREC tmp[64], *tmpp; diff --git a/src/jpeg.h b/src/jpeg.h index d55f1a7..44c83d7 100644 --- a/src/jpeg.h +++ b/src/jpeg.h @@ -1,36 +1,10 @@ -/* - * a tiny jpeg decoder. - * - * written in August 2001 by Michael Schroeder mls@suse.de - */ - #ifndef __JPEG_H #define __JPEG_H
-#define ERR_NO_SOI 1 -#define ERR_NOT_8BIT 2 -#define ERR_HEIGHT_MISMATCH 3 -#define ERR_WIDTH_MISMATCH 4 -#define ERR_BAD_WIDTH_OR_HEIGHT 5 -#define ERR_TOO_MANY_COMPPS 6 -#define ERR_ILLEGAL_HV 7 -#define ERR_QUANT_TABLE_SELECTOR 8 -#define ERR_NOT_YCBCR_221111 9 -#define ERR_UNKNOWN_CID_IN_SCAN 10 -#define ERR_NOT_SEQUENTIAL_DCT 11 -#define ERR_WRONG_MARKER 12 -#define ERR_NO_EOI 13 -#define ERR_BAD_TABLES 14 -#define ERR_DEPTH_MISMATCH 15 - -struct jpeg_decdata { - int dcts[6 * 64 + 16]; - int out[64 * 6]; - int dquant[3][64]; -}; - -extern int jpeg_decode(unsigned char *, unsigned char *, int, int, int, - struct jpeg_decdata *); -extern int jpeg_check_size(unsigned char *, int, int); +struct jpeg_decdata; +struct jpeg_decdata *jpeg_alloc(void); +int jpeg_decode(unsigned char *, unsigned char *, int, int, int, + struct jpeg_decdata *); +int jpeg_check_size(struct jpeg_decdata *, unsigned char *, int, int);
#endif
Split the screen display code out of the jpeg parsing code.
Allow ability for caller to obtain jpeg dimensions. --- src/bootsplash.c | 9 ++++++- src/jpeg.c | 60 +++++++++++++++++++++++++++-------------------------- src/jpeg.h | 7 +++-- 3 files changed, 42 insertions(+), 34 deletions(-)
diff --git a/src/bootsplash.c b/src/bootsplash.c index 2c45406..b381935 100644 --- a/src/bootsplash.c +++ b/src/bootsplash.c @@ -187,12 +187,17 @@ void enable_vga_console(void) dprintf(8, "Copying boot splash screen...\n"); cbfs_copyfile(file, jpeg, filesize); dprintf(8, "Decompressing boot splash screen...\n"); - int ret = jpeg_decode(jpeg, picture, CONFIG_BOOTSPLASH_X, - CONFIG_BOOTSPLASH_Y, CONFIG_BOOTSPLASH_DEPTH, decdata); + int ret = jpeg_decode(decdata, jpeg); if (ret) { dprintf(1, "jpeg_decode failed with return code %d...\n", ret); goto gotext; } + ret = jpeg_show(decdata, picture, CONFIG_BOOTSPLASH_X, CONFIG_BOOTSPLASH_Y + , CONFIG_BOOTSPLASH_DEPTH); + if (ret) { + dprintf(1, "jpeg_show failed with return code %d...\n", ret); + goto gotext; + }
/* Show the picture */ iomemcpy(framebuffer, picture, imagesize); diff --git a/src/jpeg.c b/src/jpeg.c index b204345..0831c5b 100644 --- a/src/jpeg.c +++ b/src/jpeg.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2001, Novell Inc. + * Copyright (C) 2010 Kevin O'Connor kevin@koconnor.net * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -177,6 +178,8 @@ struct jpeg_decdata { unsigned char quant[4][64]; struct dec_hufftbl dhuff[4]; struct in in; + + int height, width; };
static int getbyte(struct jpeg_decdata *jpeg) @@ -292,29 +295,11 @@ struct jpeg_decdata *jpeg_alloc(void) return jpeg; }
-int jpeg_check_size(struct jpeg_decdata *jpeg, unsigned char *buf - , int width, int height) -{ - jpeg->datap = buf; - getbyte(jpeg); - getbyte(jpeg); - readtables(jpeg, M_SOF0); - getword(jpeg); - getbyte(jpeg); - if (height != getword(jpeg) || width != getword(jpeg)) - return 0; - return 1; -} - -int jpeg_decode(unsigned char *buf, unsigned char *pic, - int width, int height, int depth, - struct jpeg_decdata *jpeg) +int jpeg_decode(struct jpeg_decdata *jpeg, unsigned char *buf) { int i, j, m, tac, tdc; - int mcusx, mcusy, mx, my; - int max[6];
- if (!jpeg || !buf || !pic) + if (!jpeg || !buf) return -1; jpeg->datap = buf; if (getbyte(jpeg) != 0xff) @@ -327,11 +312,9 @@ int jpeg_decode(unsigned char *buf, unsigned char *pic, i = getbyte(jpeg); if (i != 8) return ERR_NOT_8BIT; - if (((getword(jpeg) + 15) & ~15) != height) - return ERR_HEIGHT_MISMATCH; - if (((getword(jpeg) + 15) & ~15) != width) - return ERR_WIDTH_MISMATCH; - if ((height & 15) || (width & 15)) + jpeg->height = getword(jpeg); + jpeg->width = getword(jpeg); + if ((jpeg->height & 15) || (jpeg->width & 15)) return ERR_BAD_WIDTH_OR_HEIGHT; jpeg->info.nc = getbyte(jpeg); if (jpeg->info.nc > MAXCOMP) @@ -387,10 +370,6 @@ int jpeg_decode(unsigned char *buf, unsigned char *pic, || jpeg->dscans[2].hv != 0x11) return ERR_NOT_YCBCR_221111;
- mcusx = width >> 4; - mcusy = height >> 4; - - idctqtab(jpeg->quant[jpeg->dscans[0].tq], jpeg->dquant[0]); idctqtab(jpeg->quant[jpeg->dscans[1].tq], jpeg->dquant[1]); idctqtab(jpeg->quant[jpeg->dscans[2].tq], jpeg->dquant[2]); @@ -406,6 +385,29 @@ int jpeg_decode(unsigned char *buf, unsigned char *pic,
dec_initscans(jpeg);
+ return 0; +} + +void jpeg_get_size(struct jpeg_decdata *jpeg, int *width, int *height) +{ + *width = jpeg->width; + *height = jpeg->height; +} + +int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic + , int width, int height, int depth) +{ + int m, mcusx, mcusy, mx, my; + int max[6]; + + if (jpeg->height != height) + return ERR_HEIGHT_MISMATCH; + if (jpeg->width != width) + return ERR_WIDTH_MISMATCH; + + mcusx = jpeg->width >> 4; + mcusy = jpeg->height >> 4; + jpeg->dscans[0].next = 6 - 4; jpeg->dscans[1].next = 6 - 4 - 1; jpeg->dscans[2].next = 6 - 4 - 1 - 1; /* 411 encoding */ diff --git a/src/jpeg.h b/src/jpeg.h index 44c83d7..a2ac501 100644 --- a/src/jpeg.h +++ b/src/jpeg.h @@ -3,8 +3,9 @@
struct jpeg_decdata; struct jpeg_decdata *jpeg_alloc(void); -int jpeg_decode(unsigned char *, unsigned char *, int, int, int, - struct jpeg_decdata *); -int jpeg_check_size(struct jpeg_decdata *, unsigned char *, int, int); +int jpeg_decode(struct jpeg_decdata *jpeg, unsigned char *buf); +void jpeg_get_size(struct jpeg_decdata *jpeg, int *width, int *height); +int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic + , int width, int height, int depth);
#endif
Also rename "jpeg" to "filedata" to avoid a conflict. --- src/bootsplash.c | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/bootsplash.c b/src/bootsplash.c index b381935..f7ca6f7 100644 --- a/src/bootsplash.c +++ b/src/bootsplash.c @@ -110,8 +110,8 @@ void enable_vga_console(void) { struct vesa_info *vesa_info = NULL; struct vesa_mode_info *mode_info = NULL; - struct jpeg_decdata *decdata = NULL; - u8 *jpeg = NULL, *picture = NULL; + struct jpeg_decdata *jpeg = NULL; + u8 *filedata = NULL, *picture = NULL;
/* Needs coreboot support for CBFS */ if (!CONFIG_BOOTSPLASH || !CONFIG_COREBOOT) @@ -123,12 +123,12 @@ void enable_vga_console(void)
int imagesize = (CONFIG_BOOTSPLASH_X * CONFIG_BOOTSPLASH_Y * (CONFIG_BOOTSPLASH_DEPTH / 8)); - jpeg = malloc_tmphigh(filesize); + filedata = malloc_tmphigh(filesize); picture = malloc_tmphigh(imagesize); vesa_info = malloc_tmplow(sizeof(*vesa_info)); mode_info = malloc_tmplow(sizeof(*mode_info)); - decdata = jpeg_alloc(); - if (!jpeg || !picture || !vesa_info || !mode_info || !decdata) { + jpeg = jpeg_alloc(); + if (!filedata || !picture || !vesa_info || !mode_info || !jpeg) { warn_noalloc(); goto gotext; } @@ -185,14 +185,14 @@ void enable_vga_console(void)
/* Decompress jpeg */ dprintf(8, "Copying boot splash screen...\n"); - cbfs_copyfile(file, jpeg, filesize); + cbfs_copyfile(file, filedata, filesize); dprintf(8, "Decompressing boot splash screen...\n"); - int ret = jpeg_decode(decdata, jpeg); + int ret = jpeg_decode(jpeg, filedata); if (ret) { dprintf(1, "jpeg_decode failed with return code %d...\n", ret); goto gotext; } - ret = jpeg_show(decdata, picture, CONFIG_BOOTSPLASH_X, CONFIG_BOOTSPLASH_Y + ret = jpeg_show(jpeg, picture, CONFIG_BOOTSPLASH_X, CONFIG_BOOTSPLASH_Y , CONFIG_BOOTSPLASH_DEPTH); if (ret) { dprintf(1, "jpeg_show failed with return code %d...\n", ret); @@ -204,11 +204,11 @@ void enable_vga_console(void) SET_EBDA(bootsplash_active, 1);
cleanup: - free(jpeg); + free(filedata); free(picture); free(vesa_info); free(mode_info); - free(decdata); + free(jpeg); return; gotext: enable_vga_text_console();
Replace video mode settings in config.h with a system to auto-detect a video mode for the given bootsplash.jpg file. --- src/bootsplash.c | 108 ++++++++++++++++++++++++++++++++++------------------- src/config.h | 8 ---- 2 files changed, 69 insertions(+), 47 deletions(-)
diff --git a/src/bootsplash.c b/src/bootsplash.c index f7ca6f7..f070d7d 100644 --- a/src/bootsplash.c +++ b/src/bootsplash.c @@ -67,7 +67,7 @@ struct vesa_mode_info u8 reserved_mask_size; u8 reserved_mask_pos; u8 direct_color_mode_info; - u32 phys_base_ptr; + void *phys_base_ptr; u32 offscreen_mem_offset; u16 offscreen_mem_size; u8 reserved[206]; @@ -106,6 +106,40 @@ static void enable_vga_text_console(void) printf("SeaBIOS (version %s)\n\n", VERSION); }
+static int +find_videomode(struct vesa_info *vesa_info, struct vesa_mode_info *mode_info + , int width, int height) +{ + dprintf(3, "Finding vesa mode with dimensions %d/%d\n", width, height); + u16 *videomodes = SEGOFF_TO_FLATPTR(vesa_info->video_mode_ptr); + for (;; videomodes++) { + u16 videomode = *videomodes; + if (videomode == 0xffff) { + dprintf(1, "Unable to find vesa video mode dimensions %d/%d\n" + , width, height); + return -1; + } + struct bregs br; + memset(&br, 0, sizeof(br)); + br.ax = 0x4f01; + br.cx = (1 << 14) | videomode; + br.di = FLATPTR_TO_OFFSET(mode_info); + br.es = FLATPTR_TO_SEG(mode_info); + call16_int10(&br); + if (br.ax != 0x4f) { + dprintf(1, "get_mode failed.\n"); + continue; + } + if (mode_info->x_resolution != width + || mode_info->y_resolution != height) + continue; + u8 depth = mode_info->bits_per_pixel; + if (depth != 16 && depth != 24 && depth != 32) + continue; + return videomode; + } +} + void enable_vga_console(void) { struct vesa_info *vesa_info = NULL; @@ -121,14 +155,11 @@ void enable_vga_console(void) goto gotext; int filesize = cbfs_datasize(file);
- int imagesize = (CONFIG_BOOTSPLASH_X * CONFIG_BOOTSPLASH_Y * - (CONFIG_BOOTSPLASH_DEPTH / 8)); filedata = malloc_tmphigh(filesize); - picture = malloc_tmphigh(imagesize); vesa_info = malloc_tmplow(sizeof(*vesa_info)); mode_info = malloc_tmplow(sizeof(*mode_info)); jpeg = jpeg_alloc(); - if (!filedata || !picture || !vesa_info || !mode_info || !jpeg) { + if (!filedata || !jpeg || !vesa_info || !mode_info) { warn_noalloc(); goto gotext; } @@ -150,55 +181,54 @@ void enable_vga_console(void) /* Print some debugging information about our card. */ char *vendor = SEGOFF_TO_FLATPTR(vesa_info->oem_vendor_name_ptr); char *product = SEGOFF_TO_FLATPTR(vesa_info->oem_product_name_ptr); - dprintf(8, "VESA %d.%d\nVENDOR: %s\nPRODUCT: %s\n", + dprintf(3, "VESA %d.%d\nVENDOR: %s\nPRODUCT: %s\n", vesa_info->vesa_version>>8, vesa_info->vesa_version&0xff, vendor, product);
- /* Get information about our graphics mode, like the - * framebuffer start address - */ - memset(&br, 0, sizeof(br)); - br.ax = 0x4f01; - br.cx = (1 << 14) | CONFIG_BOOTSPLASH_VESA_MODE; - br.di = FLATPTR_TO_OFFSET(mode_info); - br.es = FLATPTR_TO_SEG(mode_info); - call16_int10(&br); - if (br.ax != 0x4f) { - dprintf(1, "get_mode failed.\n"); + // Parse jpeg and get image size. + cbfs_copyfile(file, filedata, filesize); + int ret = jpeg_decode(jpeg, filedata); + if (ret) { + dprintf(1, "jpeg_decode failed with return code %d...\n", ret); + goto gotext; + } + int width, height; + jpeg_get_size(jpeg, &width, &height); + + // Try to find a graphics mode with the corresponding dimensions. + int videomode = find_videomode(vesa_info, mode_info, width, height); + if (videomode < 0) + goto gotext; + void *framebuffer = mode_info->phys_base_ptr; + int depth = mode_info->bits_per_pixel; + dprintf(3, "mode: %04x\n", videomode); + dprintf(3, "framebuffer: %p\n", framebuffer); + dprintf(3, "bytes per scanline: %d\n", mode_info->bytes_per_scanline); + dprintf(3, "bits per pixel: %d\n", depth); + + // Allocate space for image and decompress it. + int imagesize = width * height * (depth / 8); + picture = malloc_tmphigh(imagesize); + if (!picture) { + warn_noalloc(); + goto gotext; + } + ret = jpeg_show(jpeg, picture, width, height, depth); + if (ret) { + dprintf(1, "jpeg_show failed with return code %d...\n", ret); goto gotext; } - unsigned char *framebuffer = (unsigned char *) (mode_info->phys_base_ptr);
/* Switch to graphics mode */ memset(&br, 0, sizeof(br)); br.ax = 0x4f02; - br.bx = (1 << 14) | CONFIG_BOOTSPLASH_VESA_MODE; + br.bx = (1 << 14) | videomode; call16_int10(&br); if (br.ax != 0x4f) { dprintf(1, "set_mode failed.\n"); goto gotext; }
- dprintf(8, "framebuffer: %x\n", (u32)framebuffer); - dprintf(8, "bytes per scanline: %d\n", mode_info->bytes_per_scanline); - dprintf(8, "bits per pixel: %d\n", mode_info->bits_per_pixel); - - /* Decompress jpeg */ - dprintf(8, "Copying boot splash screen...\n"); - cbfs_copyfile(file, filedata, filesize); - dprintf(8, "Decompressing boot splash screen...\n"); - int ret = jpeg_decode(jpeg, filedata); - if (ret) { - dprintf(1, "jpeg_decode failed with return code %d...\n", ret); - goto gotext; - } - ret = jpeg_show(jpeg, picture, CONFIG_BOOTSPLASH_X, CONFIG_BOOTSPLASH_Y - , CONFIG_BOOTSPLASH_DEPTH); - if (ret) { - dprintf(1, "jpeg_show failed with return code %d...\n", ret); - goto gotext; - } - /* Show the picture */ iomemcpy(framebuffer, picture, imagesize); SET_EBDA(bootsplash_active, 1); diff --git a/src/config.h b/src/config.h index a7a6ccc..3dcbcf5 100644 --- a/src/config.h +++ b/src/config.h @@ -123,14 +123,6 @@ #define CONFIG_S3_RESUME_VGA_INIT 0 // Support boot splash #define CONFIG_BOOTSPLASH 0 -// boot splash X resolution -#define CONFIG_BOOTSPLASH_X 1024 -// boot splash Y resolution -#define CONFIG_BOOTSPLASH_Y 768 -// boot splash color depth -#define CONFIG_BOOTSPLASH_DEPTH 16 -// boot splash VESA mode (could be generated) -#define CONFIG_BOOTSPLASH_VESA_MODE 0x117 // define it if the (emulated) hardware supports SMM mode #define CONFIG_USE_SMM 1 // Maximum number of map entries in the e820 map
--- src/bootsplash.c | 2 +- src/config.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/bootsplash.c b/src/bootsplash.c index f070d7d..676ece3 100644 --- a/src/bootsplash.c +++ b/src/bootsplash.c @@ -248,7 +248,7 @@ gotext: void disable_bootsplash(void) { - if (! CONFIG_BOOTSPLASH || !GET_EBDA(bootsplash_active)) + if (!CONFIG_BOOTSPLASH || !CONFIG_COREBOOT || !GET_EBDA(bootsplash_active)) return; SET_EBDA(bootsplash_active, 0); enable_vga_text_console(); diff --git a/src/config.h b/src/config.h index 3dcbcf5..4572ee5 100644 --- a/src/config.h +++ b/src/config.h @@ -122,7 +122,7 @@ // Run the vga rom during S3 resume. #define CONFIG_S3_RESUME_VGA_INIT 0 // Support boot splash -#define CONFIG_BOOTSPLASH 0 +#define CONFIG_BOOTSPLASH 1 // define it if the (emulated) hardware supports SMM mode #define CONFIG_USE_SMM 1 // Maximum number of map entries in the e820 map
Kevin O'Connor wrote:
This series further enhances the bootsplash code. The last patch enables it by default (for coreboot users).
What about adding some wrappers to "paravirt.h" like bootsplash_file_find, bootsplash_file_size and bootsplash_file_copy (along the lines of romfile_*) ? This should allow qemu to use the bootsplash screen.
Sebastian
On Fri, Jul 30, 2010 at 09:13:32PM +0200, Sebastian Herbszt wrote:
Kevin O'Connor wrote:
This series further enhances the bootsplash code. The last patch enables it by default (for coreboot users).
What about adding some wrappers to "paravirt.h" like bootsplash_file_find, bootsplash_file_size and bootsplash_file_copy (along the lines of romfile_*) ? This should allow qemu to use the bootsplash screen.
The romfile_* wrappers could likely serve this purpose. (See patch below.) Of course, this needs changes to qemu, which I was going to look at next.
-Kevin
diff --git a/src/bootsplash.c b/src/bootsplash.c index 676ece3..00bb921 100644 --- a/src/bootsplash.c +++ b/src/bootsplash.c @@ -11,6 +11,7 @@ #include "util.h" // dprintf #include "jpeg.h" // splash #include "biosvar.h" // SET_EBDA +#include "paravirt.h" // romfile_find
/**************************************************************** @@ -148,12 +149,12 @@ void enable_vga_console(void) u8 *filedata = NULL, *picture = NULL;
/* Needs coreboot support for CBFS */ - if (!CONFIG_BOOTSPLASH || !CONFIG_COREBOOT) + if (!CONFIG_BOOTSPLASH) goto gotext; - struct cbfs_file *file = cbfs_finddatafile("bootsplash.jpg"); + u32 file = romfile_find("bootsplash.jpg"); if (!file) goto gotext; - int filesize = cbfs_datasize(file); + int filesize = romfile_size(file);
filedata = malloc_tmphigh(filesize); vesa_info = malloc_tmplow(sizeof(*vesa_info)); @@ -186,7 +187,7 @@ void enable_vga_console(void) vendor, product);
// Parse jpeg and get image size. - cbfs_copyfile(file, filedata, filesize); + romfile_copy(file, filedata, filesize); int ret = jpeg_decode(jpeg, filedata); if (ret) { dprintf(1, "jpeg_decode failed with return code %d...\n", ret); @@ -248,7 +249,7 @@ gotext: void disable_bootsplash(void) { - if (!CONFIG_BOOTSPLASH || !CONFIG_COREBOOT || !GET_EBDA(bootsplash_active)) + if (!CONFIG_BOOTSPLASH || !GET_EBDA(bootsplash_active)) return; SET_EBDA(bootsplash_active, 0); enable_vga_text_console();
Kevin O'Connor wrote:
On Fri, Jul 30, 2010 at 09:13:32PM +0200, Sebastian Herbszt wrote:
Kevin O'Connor wrote:
This series further enhances the bootsplash code. The last patch enables it by default (for coreboot users).
What about adding some wrappers to "paravirt.h" like bootsplash_file_find, bootsplash_file_size and bootsplash_file_copy (along the lines of romfile_*) ? This should allow qemu to use the bootsplash screen.
The romfile_* wrappers could likely serve this purpose. (See patch below.) Of course, this needs changes to qemu, which I was going to look at next.
-Kevin
Yes, but maybe rename them. Strip the "rom" part because a generic use is possible?
Sebastian
On 07/30/2010 02:19 PM, Kevin O'Connor wrote:
On Fri, Jul 30, 2010 at 09:13:32PM +0200, Sebastian Herbszt wrote:
Kevin O'Connor wrote:
This series further enhances the bootsplash code. The last patch enables it by default (for coreboot users).
What about adding some wrappers to "paravirt.h" like bootsplash_file_find, bootsplash_file_size and bootsplash_file_copy (along the lines of romfile_*) ? This should allow qemu to use the bootsplash screen.
The romfile_* wrappers could likely serve this purpose. (See patch below.) Of course, this needs changes to qemu, which I was going to look at next.
Would be a really nice feature to have.
Regards,
Anthony Liguori
-Kevin
diff --git a/src/bootsplash.c b/src/bootsplash.c index 676ece3..00bb921 100644 --- a/src/bootsplash.c +++ b/src/bootsplash.c @@ -11,6 +11,7 @@ #include "util.h" // dprintf #include "jpeg.h" // splash #include "biosvar.h" // SET_EBDA +#include "paravirt.h" // romfile_find
/**************************************************************** @@ -148,12 +149,12 @@ void enable_vga_console(void) u8 *filedata = NULL, *picture = NULL;
/* Needs coreboot support for CBFS */
- if (!CONFIG_BOOTSPLASH || !CONFIG_COREBOOT)
- if (!CONFIG_BOOTSPLASH) goto gotext;
- struct cbfs_file *file = cbfs_finddatafile("bootsplash.jpg");
- u32 file = romfile_find("bootsplash.jpg"); if (!file) goto gotext;
- int filesize = cbfs_datasize(file);
int filesize = romfile_size(file);
filedata = malloc_tmphigh(filesize); vesa_info = malloc_tmplow(sizeof(*vesa_info));
@@ -186,7 +187,7 @@ void enable_vga_console(void) vendor, product);
// Parse jpeg and get image size.
- cbfs_copyfile(file, filedata, filesize);
- romfile_copy(file, filedata, filesize); int ret = jpeg_decode(jpeg, filedata); if (ret) { dprintf(1, "jpeg_decode failed with return code %d...\n", ret);
@@ -248,7 +249,7 @@ gotext: void disable_bootsplash(void) {
- if (!CONFIG_BOOTSPLASH || !CONFIG_COREBOOT || !GET_EBDA(bootsplash_active))
- if (!CONFIG_BOOTSPLASH || !GET_EBDA(bootsplash_active)) return; SET_EBDA(bootsplash_active, 0); enable_vga_text_console();
SeaBIOS mailing list SeaBIOS@seabios.org http://www.seabios.org/mailman/listinfo/seabios