diff -Naur linux-2.5.50-js/drivers/video/console/fbcon.c linux/drivers/video/console/fbcon.c --- linux-2.5.50-js/drivers/video/console/fbcon.c 2002-12-03 10:55:55.000000000 +0000 +++ linux/drivers/video/console/fbcon.c 2002-12-03 10:56:26.000000000 +0000 @@ -317,18 +317,16 @@ if (newidx != con2fb_map[unit]) { oldfb = registered_fb[oldidx]; newfb = registered_fb[newidx]; - if (newfb->fbops->owner) - __MOD_INC_USE_COUNT(newfb->fbops->owner); + if (!try_module_get(newfb->fbops->owner)) + return; if (newfb->fbops->fb_open && newfb->fbops->fb_open(newfb, 0)) { - if (newfb->fbops->owner) - __MOD_DEC_USE_COUNT(newfb->fbops->owner); + module_put(newfb->fbops->owner); return; } if (oldfb->fbops->fb_release) oldfb->fbops->fb_release(oldfb, 0); - if (oldfb->fbops->owner) - __MOD_DEC_USE_COUNT(oldfb->fbops->owner); + module_put(oldfb->fbops->owner); vc = fb_display[unit].conp; fontdata = fb_display[unit].fontdata; userfont = fb_display[unit].userfont; @@ -596,10 +594,10 @@ info->currcon = -1; owner = info->fbops->owner; - if (owner) - __MOD_INC_USE_COUNT(owner); - if (info->fbops->fb_open && info->fbops->fb_open(info, 0) && owner) - __MOD_DEC_USE_COUNT(owner); + if (!try_module_get(owner)) + return NULL; + if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) + module_put(owner); if (info->fix.type != FB_TYPE_TEXT) { if (fbcon_softback_size) { @@ -2549,111 +2547,226 @@ return n < 0 ? d >> -n : d << n; } -static int __init fbcon_show_logo(void) +static void __init fbcon_set_logocmap(struct fb_info *info) +{ + int i, j, n; + + for (i = 0; i < LINUX_LOGO_COLORS; i += n) { + n = LINUX_LOGO_COLORS - i; + if (n > 16) + /* palette_cmap provides space for only 16 colors at once */ + n = 16; + palette_cmap.start = 32 + i; + palette_cmap.len = n; + for (j = 0; j < n; ++j) { + palette_cmap.red[j] = + (linux_logo_red[i + j] << 8) | + linux_logo_red[i + j]; + palette_cmap.green[j] = + (linux_logo_green[i + j] << 8) | + linux_logo_green[i + j]; + palette_cmap.blue[j] = + (linux_logo_blue[i + j] << 8) | + linux_logo_blue[i + j]; + } + fb_set_cmap(&palette_cmap, 1, info); + } +} + +static void __init fbcon_set_logo_truepalette(struct fb_info *info, u32 *palette) +{ + unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff }; + unsigned char redmask, greenmask, bluemask; + int redshift, greenshift, blueshift; + int i; + + /* + * We have to create a temporary palette since console palette is only + * 16 colors long. + */ + /* Bug: Doesn't obey msb_right ... (who needs that?) */ + redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8]; + greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8]; + bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8]; + redshift = info->var.red.offset - (8 - info->var.red.length); + greenshift = info->var.green.offset - (8 - info->var.green.length); + blueshift = info->var.blue.offset - (8 - info->var.blue.length); + + + for ( i = 0; i < LINUX_LOGO_COLORS; i++) { + palette[i+32] = (safe_shift((linux_logo_red[i] & redmask), redshift) | + safe_shift((linux_logo_green[i] & greenmask), greenshift) | + safe_shift((linux_logo_blue[i] & bluemask), blueshift)); + } +} + +static void __init fbcon_set_logo_directpalette(struct fb_info *info, u32 *palette) +{ + int redshift, greenshift, blueshift; + int i; + + redshift = info->var.red.offset; + greenshift = info->var.green.offset; + blueshift = info->var.blue.offset; + + for (i = 32; i < LINUX_LOGO_COLORS; i++) + palette[i] = i << redshift | i << greenshift | i << blueshift; + +} + +static void __init fbcon_set_logo(struct fb_info *info, u8 *logo, int needs_logo) { - struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */ + int i, j; + + switch (needs_logo) { + case 4: + for (i = 0; i < (LOGO_W * LOGO_H)/2; i++) { + logo[i*2] = linux_logo16[i] >> 4; + logo[(i*2)+1] = linux_logo16[i] & 0xf; + } + break; + case 1: + case ~1: + default: + for (i = 0; i < (LOGO_W * LOGO_H)/8; i++) + for (j = 0; j < 8; j++) + logo[i*2] = (linux_logo_bw[i] & (7 - j)) ? + ((needs_logo == 1) ? 1 : 0) : + ((needs_logo == 1) ? 0 : 1); + + break; + } +} + +/* + * Three (3) kinds of logo maps exist. linux_logo (>16 colors), linux_logo_16 + * (16 colors) and linux_logo_bw (2 colors). Depending on the visual format and + * color depth of the framebuffer, the DAC, the pseudo_palette, and the logo data + * will be adjusted accordingly. + * + * Case 1 - linux_logo: + * Color exceeds the number of console colors (16), thus we set the hardware DAC + * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set. + * + * For visuals that require color info from the pseudo_palette, we also construct + * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags + * will be set. + * + * Case 2 - linux_logo_16: + * The number of colors just matches the console colors, thus there is no need + * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie, + * each byte contains color information for two pixels (upper and lower nibble). + * To be consistent with fb_imageblit() usage, we therefore separate the two + * nibbles into separate bytes. The "needs_logo" flag will be set to 4. + * + * Case 3 - linux_logo_bw: + * This is similar with Case 2. Each byte contains information for 8 pixels. + * We isolate each bit and expand each into a byte. The "needs_logo" flag will + * be set to 1. + */ +static int __init fbcon_show_logo(void) + { + struct display *p = &fb_display[fg_console]; /* draw to vt in foreground */ struct fb_info *info = p->fb_info; struct vc_data *vc = info->display_fg; struct fb_image image; u32 *palette = NULL, *saved_palette = NULL; - int depth = info->var.bits_per_pixel; - unsigned char *fb = info->screen_base; - unsigned char *logo; - int i, j, n, x; - int logo_depth, done = 0; + unsigned char *fb = info->screen_base, *logo_new = NULL; + int done = 0, x; + int needs_cmapreset = 0; + int needs_truepalette = 0; + int needs_directpalette = 0; + int needs_logo = 0; /* Return if the frame buffer is not mapped */ - if (!fb) + if (!fb || !info->fbops->fb_imageblit) return 0; - /* - * Set colors if visual is PSEUDOCOLOR and we have enough colors, or for - * DIRECTCOLOR - * We don't have to set the colors for the 16-color logo, since that logo - * uses the standard VGA text console palette - */ - if ((info->fix.visual == FB_VISUAL_PSEUDOCOLOR && depth >= 8) || - (info->fix.visual == FB_VISUAL_DIRECTCOLOR && depth >= 24)) - for (i = 0; i < LINUX_LOGO_COLORS; i += n) { - n = LINUX_LOGO_COLORS - i; - if (n > 16) - /* palette_cmap provides space for only 16 colors at once */ - n = 16; - palette_cmap.start = 32 + i; - palette_cmap.len = n; - for (j = 0; j < n; ++j) { - palette_cmap.red[j] = - (linux_logo_red[i + j] << 8) | - linux_logo_red[i + j]; - palette_cmap.green[j] = - (linux_logo_green[i + j] << 8) | - linux_logo_green[i + j]; - palette_cmap.blue[j] = - (linux_logo_blue[i + j] << 8) | - linux_logo_blue[i + j]; - } - fb_set_cmap(&palette_cmap, 1, info); - } - - if (depth >= 8) { - logo = linux_logo; - logo_depth = 8; - } else if (depth >= 4) { - logo = linux_logo16; - logo_depth = 4; - } else { - logo = linux_logo_bw; - logo_depth = 1; - } - - if (info->fix.visual == FB_VISUAL_TRUECOLOR) { - unsigned char mask[9] = - { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; - unsigned char redmask, greenmask, bluemask; - int redshift, greenshift, blueshift; - - /* Bug: Doesn't obey msb_right ... (who needs that?) */ - redmask = - mask[info->var.red.length < - 8 ? info->var.red.length : 8]; - greenmask = - mask[info->var.green.length < - 8 ? info->var.green.length : 8]; - bluemask = - mask[info->var.blue.length < - 8 ? info->var.blue.length : 8]; - redshift = - info->var.red.offset - (8 - info->var.red.length); - greenshift = - info->var.green.offset - (8 - info->var.green.length); - blueshift = - info->var.blue.offset - (8 - info->var.blue.length); + image.depth = info->var.bits_per_pixel; - /* - * We have to create a temporary palette since console palette is only - * 16 colors long. - */ + /* reasonable default */ + if (image.depth >= 8) + image.data = linux_logo; + else if (image.depth >= 4) + image.data = linux_logo16; + else + image.data = linux_logo_bw; + + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + needs_truepalette = 1; + if (image.depth >= 4 && image.depth <= 8) + needs_logo = 4; + else if (image.depth < 4) + needs_logo = 1; + break; + case FB_VISUAL_DIRECTCOLOR: + if (image.depth >= 24) { + needs_directpalette = 1; + needs_cmapreset = 1; + } + /* 16 colors */ + else if (image.depth >= 16) + needs_logo = 4; + /* 2 colors */ + else + needs_logo = 1; + break; + case FB_VISUAL_MONO01: + /* reversed 0 = fg, 1 = bg */ + needs_logo = ~1; + break; + case FB_VISUAL_MONO10: + needs_logo = 1; + break; + case FB_VISUAL_PSEUDOCOLOR: + default: + if (image.depth >= 8) + needs_cmapreset = 1; + /* fall through */ + case FB_VISUAL_STATIC_PSEUDOCOLOR: + /* 16 colors */ + if (image.depth >= 4 && image.depth < 8) + needs_logo = 4; + /* 2 colors */ + else if (image.depth < 4) + needs_logo = 1; + break; + } + + if (needs_cmapreset) + fbcon_set_logocmap(info); + + if (needs_truepalette || needs_directpalette) { palette = kmalloc(256 * 4, GFP_KERNEL); if (palette == NULL) - return (LOGO_H + vc->vc_font.height - 1)/vc->vc_font.height; + return 1; + + if (needs_truepalette) + fbcon_set_logo_truepalette(info, palette); + else + fbcon_set_logo_directpalette(info, palette); - for (i = 0; i < LINUX_LOGO_COLORS; i++) { - palette[i + 32] = - (safe_shift - ((linux_logo_red[i] & redmask), - redshift) | safe_shift((linux_logo_green[i] & - greenmask), - greenshift) | - safe_shift((linux_logo_blue[i] & bluemask), - blueshift)); - } saved_palette = info->pseudo_palette; info->pseudo_palette = palette; } + + if (needs_logo) { + logo_new = kmalloc(LOGO_W * LOGO_H, GFP_KERNEL); + if (logo_new == NULL) { + if (palette) + kfree(palette); + if (saved_palette) + info->pseudo_palette = saved_palette; + return 1; + } + + image.data = logo_new; + fbcon_set_logo(info, logo_new, needs_logo); + } + image.width = LOGO_W; image.height = LOGO_H; - image.depth = depth; - image.data = logo; image.dy = 0; for (x = 0; x < num_online_cpus() * (LOGO_W + 8) && @@ -2667,6 +2780,8 @@ kfree(palette); if (saved_palette != NULL) info->pseudo_palette = saved_palette; + if (logo_new != NULL) + kfree(logo_new); /* * Modes not yet supported: packed pixels with depth != 8 (does such a * thing exist in reality?) @@ -2701,7 +2816,10 @@ int __init fb_console_init(void) { + if (!num_registered_fb) + return -ENODEV; take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default); + __unsafe(THIS_MODULE); return 0; } diff -Naur linux-2.5.50-js/drivers/video/fbmem.c linux/drivers/video/fbmem.c --- linux-2.5.50-js/drivers/video/fbmem.c 2002-12-03 10:55:42.000000000 +0000 +++ linux/drivers/video/fbmem.c 2002-12-03 10:57:29.000000000 +0000 @@ -730,12 +730,12 @@ #endif /* CONFIG_KMOD */ if (!(info = registered_fb[fbidx])) return -ENODEV; - if (info->fbops->owner) - __MOD_INC_USE_COUNT(info->fbops->owner); + if (!try_module_get(info->fbops->owner)) + return -ENODEV; if (info->fbops->fb_open) { res = info->fbops->fb_open(info,1); - if (res && info->fbops->owner) - __MOD_DEC_USE_COUNT(info->fbops->owner); + if (res) + module_put(info->fbops->owner); } return res; } @@ -750,8 +750,7 @@ info = registered_fb[fbidx]; if (info->fbops->fb_release) info->fbops->fb_release(info,1); - if (info->fbops->owner) - __MOD_DEC_USE_COUNT(info->fbops->owner); + module_put(info->fbops->owner); unlock_kernel(); return 0; }