X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fvideo%2Ftdfxfb.c;h=503ecc3569e88dcbebbd60cf22122c0be0dca94a;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=2873877622e3388b71161301725cf60a200f635c;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 287387762..503ecc356 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -1,4 +1,3 @@ - /* * * tdfxfb.c @@ -126,8 +125,9 @@ static struct fb_var_screeninfo tdfx_var __initdata = { /* * PCI driver prototypes */ -static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id); -static void tdfxfb_remove(struct pci_dev *pdev); +static int __devinit tdfxfb_probe(struct pci_dev *pdev, + const struct pci_device_id *id); +static void __devexit tdfxfb_remove(struct pci_dev *pdev); static struct pci_device_id tdfxfb_id_table[] = { { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE, @@ -155,7 +155,7 @@ MODULE_DEVICE_TABLE(pci, tdfxfb_id_table); * Frame buffer device API */ int tdfxfb_init(void); -void tdfxfb_setup(char *options, int *ints); +void tdfxfb_setup(char *options); static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb); static int tdfxfb_set_par(struct fb_info *info); @@ -163,15 +163,12 @@ static int tdfxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info); static int tdfxfb_blank(int blank, struct fb_info *info); static int tdfxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); +static int banshee_wait_idle(struct fb_info *info); +#ifdef CONFIG_FB_3DFX_ACCEL static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image); -#ifdef CONFIG_FB_3DFX_ACCEL -static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor); -#else /* !CONFIG_FB_3DFX_ACCEL */ -#define tdfxfb_cursor soft_cursor #endif /* CONFIG_FB_3DFX_ACCEL */ -static int banshee_wait_idle(struct fb_info *info); static struct fb_ops tdfxfb_ops = { .owner = THIS_MODULE, @@ -180,11 +177,17 @@ static struct fb_ops tdfxfb_ops = { .fb_setcolreg = tdfxfb_setcolreg, .fb_blank = tdfxfb_blank, .fb_pan_display = tdfxfb_pan_display, + .fb_sync = banshee_wait_idle, +#ifdef CONFIG_FB_3DFX_ACCEL .fb_fillrect = tdfxfb_fillrect, .fb_copyarea = tdfxfb_copyarea, .fb_imageblit = tdfxfb_imageblit, - .fb_sync = banshee_wait_idle, - .fb_cursor = tdfxfb_cursor, +#else + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +#endif + .fb_cursor = soft_cursor, }; /* @@ -497,23 +500,21 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info) return -EINVAL; } - if (var->xres != var->xres_virtual) { - DPRINTK("virtual x resolution != physical x resolution not supported\n"); - return -EINVAL; - } + if (var->xres != var->xres_virtual) + var->xres_virtual = var->xres; - if (var->yres > var->yres_virtual) { - DPRINTK("virtual y resolution < physical y resolution not possible\n"); - return -EINVAL; - } + if (var->yres > var->yres_virtual) + var->yres_virtual = var->yres; if (var->xoffset) { DPRINTK("xoffset not supported\n"); return -EINVAL; } - /* fixme: does Voodoo3 support interlace? Banshee doesn't */ - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { + /* Banshee doesn't support interlace, but Voodoo4/5 and probably Voodoo3 do. */ + /* no direct information about device id now? use max_pixclock for this... */ + if (((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) && + (par->max_pixclock < VOODOO3_MAX_PIXCLOCK)) { DPRINTK("interlace not supported\n"); return -EINVAL; } @@ -532,9 +533,12 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info) } if (lpitch * var->yres_virtual > info->fix.smem_len) { - DPRINTK("no memory for screen (%ux%ux%u)\n", - var->xres, var->yres_virtual, var->bits_per_pixel); - return -EINVAL; + var->yres_virtual = info->fix.smem_len/lpitch; + if (var->yres_virtual < var->yres) { + DPRINTK("no memory for screen (%ux%ux%u)\n", + var->xres, var->yres_virtual, var->bits_per_pixel); + return -EINVAL; + } } if (PICOS2KHZ(var->pixclock) > par->max_pixclock) { @@ -584,7 +588,6 @@ static int tdfxfb_set_par(struct fb_info *info) int fout, freq; u32 wd, cpp; - info->cmap.len = (info->var.bits_per_pixel == 8) ? 256 : 16; par->baseline = 0; memset(®, 0, sizeof(reg)); @@ -620,10 +623,17 @@ static int tdfxfb_set_par(struct fb_info *info) hbs = hd; hbe = ht; - vbs = vd = info->var.yres - 1; - vs = vd + info->var.lower_margin; - ve = vs + info->var.vsync_len; - vbe = vt = ve + info->var.upper_margin - 1; + if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + vbs = vd = (info->var.yres << 1) - 1; + vs = vd + (info->var.lower_margin << 1); + ve = vs + (info->var.vsync_len << 1); + vbe = vt = ve + (info->var.upper_margin << 1) - 1; + } else { + vbs = vd = info->var.yres - 1; + vs = vd + info->var.lower_margin; + ve = vs + info->var.vsync_len; + vbe = vt = ve + info->var.upper_margin - 1; + } /* this is all pretty standard VGA register stuffing */ reg.misc[0x00] = 0x0f | @@ -746,8 +756,16 @@ static int tdfxfb_set_par(struct fb_info *info) reg.gfxpll = do_calc_pll(..., &fout); #endif - reg.screensize = info->var.xres | (info->var.yres << 12); - reg.vidcfg &= ~VIDCFG_HALF_MODE; + if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + reg.screensize = info->var.xres | (info->var.yres << 13); + reg.vidcfg |= VIDCFG_HALF_MODE; + reg.crt[0x09] |= 0x80; + } else { + reg.screensize = info->var.xres | (info->var.yres << 12); + reg.vidcfg &= ~VIDCFG_HALF_MODE; + } + if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + reg.vidcfg |= VIDCFG_INTERLACE; reg.miscinit0 = tdfx_inl(par, MISCINIT0); #if defined(__BIG_ENDIAN) @@ -787,7 +805,7 @@ static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct tdfx_par *par = (struct tdfx_par *) info->par; u32 rgbcol; - if (regno >= info->cmap.len) return 1; + if (regno >= info->cmap.len || regno > 255) return 1; switch (info->fix.visual) { case FB_VISUAL_PSEUDOCOLOR: @@ -876,6 +894,7 @@ static int tdfxfb_pan_display(struct fb_var_screeninfo *var, return 0; } +#ifdef CONFIG_FB_3DFX_ACCEL /* * FillRect 2D command (solidfill or invert (via ROP_XOR)) */ @@ -894,7 +913,11 @@ static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect banshee_make_room(par, 5); tdfx_outl(par, DSTFORMAT, fmt); - tdfx_outl(par, COLORFORE, rect->color); + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { + tdfx_outl(par, COLORFORE, rect->color); + } else { /* FB_VISUAL_TRUECOLOR */ + tdfx_outl(par, COLORFORE, ((u32*)(info->pseudo_palette))[rect->color]); + } tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24)); tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16)); tdfx_outl(par, LAUNCH_2D, rect->dx | (rect->dy << 16)); @@ -1004,8 +1027,9 @@ static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image) } banshee_wait_idle(info); } +#endif /* CONFIG_FB_3DFX_ACCEL */ -#ifdef CONFIG_FB_3DFX_ACCEL +#ifdef TDFX_HARDWARE_CURSOR static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) { struct tdfx_par *par = (struct tdfx_par *) info->par; @@ -1043,7 +1067,7 @@ static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) struct fb_cmap cmap = cursor->image.cmap; unsigned long bg_color, fg_color; - cmap.len = 2;/* Voodoo 3+ only support 2 color cursors*/ + cmap.len = 2; /* Voodoo 3+ only support 2 color cursors */ fg_color = ((cmap.red[cmap.start] << 16) | (cmap.green[cmap.start] << 8) | (cmap.blue[cmap.start])); @@ -1101,7 +1125,7 @@ static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) */ u8 *cursorbase = (u8 *) info->cursor.image.data; char *bitmap = (char *)cursor->image.data; - const char *mask = cursor->mask; + char *mask = (char *) cursor->mask; int i, j, k, h = 0; for (i = 0; i < 64; i++) { @@ -1142,7 +1166,7 @@ static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) spin_unlock_irqrestore(&par->DAClock, flags); return 0; } -#endif /* CONFIG_FB_3DFX_ACCEL */ +#endif /** * tdfxfb_probe - Device Initializiation @@ -1158,22 +1182,20 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, { struct tdfx_par *default_par; struct fb_info *info; - int size, err; + int size, err, lpitch; if ((err = pci_enable_device(pdev))) { printk(KERN_WARNING "tdfxfb: Can't enable pdev: %d\n", err); return err; } - size = sizeof(struct fb_info)+sizeof(struct tdfx_par)+16*sizeof(u32); + size = sizeof(struct tdfx_par)+256*sizeof(u32); - info = kmalloc(size, GFP_KERNEL); + info = framebuffer_alloc(size, &pdev->dev); if (!info) return -ENOMEM; - memset(info, 0, size); - - default_par = (struct tdfx_par *) (info + 1); + default_par = info->par; /* Configure the default fb_fix_screeninfo first */ switch (pdev->device) { @@ -1251,24 +1273,44 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, info->fbops = &tdfxfb_ops; info->fix = tdfx_fix; - info->par = default_par; info->pseudo_palette = (void *)(default_par + 1); - info->flags = FBINFO_FLAG_DEFAULT; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; +#ifdef CONFIG_FB_3DFX_ACCEL + info->flags |= FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_IMAGEBLIT; +#endif -#ifndef MODULE if (!mode_option) mode_option = "640x480@60"; err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); if (!err || err == 4) -#endif info->var = tdfx_var; - size = (info->var.bits_per_pixel == 8) ? 256 : 16; - fb_alloc_cmap(&info->cmap, size, 0); + /* maximize virtual vertical length */ + lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3); + info->var.yres_virtual = info->fix.smem_len/lpitch; + if (info->var.yres_virtual < info->var.yres) + goto out_err; + +#ifdef CONFIG_FB_3DFX_ACCEL + /* + * FIXME: Limit var->yres_virtual to 4096 because of screen artifacts + * during scrolling. This is only present if 2D acceleration is + * enabled. + */ + if (info->var.yres_virtual > 4096) + info->var.yres_virtual = 4096; +#endif /* CONFIG_FB_3DFX_ACCEL */ + + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + printk(KERN_WARNING "tdfxfb: Can't allocate color map\n"); + goto out_err; + } if (register_framebuffer(info) < 0) { printk("tdfxfb: can't register framebuffer\n"); + fb_dealloc_cmap(&info->cmap); goto out_err; } /* @@ -1285,7 +1327,7 @@ out_err: iounmap(default_par->regbase_virt); if (info->screen_base) iounmap(info->screen_base); - kfree(info); + framebuffer_release(info); return -ENXIO; } @@ -1315,11 +1357,19 @@ static void __devexit tdfxfb_remove(struct pci_dev *pdev) release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); pci_set_drvdata(pdev, NULL); - kfree(info); + framebuffer_release(info); } int __init tdfxfb_init(void) { +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("tdfxfb", &option)) + return -ENODEV; + + tdfxfb_setup(option); +#endif return pci_module_init(&tdfxfb_driver); } @@ -1332,14 +1382,12 @@ MODULE_AUTHOR("Hannu Mallat "); MODULE_DESCRIPTION("3Dfx framebuffer device driver"); MODULE_LICENSE("GPL"); -#ifdef MODULE module_init(tdfxfb_init); -#endif module_exit(tdfxfb_exit); #ifndef MODULE -void tdfxfb_setup(char *options, int *ints) +void tdfxfb_setup(char *options) { char* this_opt;