in fbdev/pm2fb.c [1514:1711]
static int pm2fb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct pm2fb_par *default_par;
struct fb_info *info;
int err;
int retval = -ENXIO;
err = pci_enable_device(pdev);
if (err) {
printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err);
return err;
}
info = framebuffer_alloc(sizeof(struct pm2fb_par), &pdev->dev);
if (!info)
return -ENOMEM;
default_par = info->par;
switch (pdev->device) {
case PCI_DEVICE_ID_TI_TVP4020:
strcpy(pm2fb_fix.id, "TVP4020");
default_par->type = PM2_TYPE_PERMEDIA2;
break;
case PCI_DEVICE_ID_3DLABS_PERMEDIA2:
strcpy(pm2fb_fix.id, "Permedia2");
default_par->type = PM2_TYPE_PERMEDIA2;
break;
case PCI_DEVICE_ID_3DLABS_PERMEDIA2V:
strcpy(pm2fb_fix.id, "Permedia2v");
default_par->type = PM2_TYPE_PERMEDIA2V;
break;
}
pm2fb_fix.mmio_start = pci_resource_start(pdev, 0);
pm2fb_fix.mmio_len = PM2_REGS_SIZE;
#if defined(__BIG_ENDIAN)
/*
* PM2 has a 64k register file, mapped twice in 128k. Lower
* map is little-endian, upper map is big-endian.
*/
pm2fb_fix.mmio_start += PM2_REGS_SIZE;
DPRINTK("Adjusting register base for big-endian.\n");
#endif
DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start);
/* Registers - request region and map it. */
if (!request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len,
"pm2fb regbase")) {
printk(KERN_WARNING "pm2fb: Can't reserve regbase.\n");
goto err_exit_neither;
}
default_par->v_regs =
ioremap(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
if (!default_par->v_regs) {
printk(KERN_WARNING "pm2fb: Can't remap %s register area.\n",
pm2fb_fix.id);
release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
goto err_exit_neither;
}
/* Stash away memory register info for use when we reset the board */
default_par->mem_control = pm2_RD(default_par, PM2R_MEM_CONTROL);
default_par->boot_address = pm2_RD(default_par, PM2R_BOOT_ADDRESS);
default_par->mem_config = pm2_RD(default_par, PM2R_MEM_CONFIG);
DPRINTK("MemControl 0x%x BootAddress 0x%x MemConfig 0x%x\n",
default_par->mem_control, default_par->boot_address,
default_par->mem_config);
if (default_par->mem_control == 0 &&
default_par->boot_address == 0x31 &&
default_par->mem_config == 0x259fffff) {
default_par->memclock = CVPPC_MEMCLOCK;
default_par->mem_control = 0;
default_par->boot_address = 0x20;
default_par->mem_config = 0xe6002021;
if (pdev->subsystem_vendor == 0x1048 &&
pdev->subsystem_device == 0x0a31) {
DPRINTK("subsystem_vendor: %04x, "
"subsystem_device: %04x\n",
pdev->subsystem_vendor, pdev->subsystem_device);
DPRINTK("We have not been initialized by VGA BIOS and "
"are running on an Elsa Winner 2000 Office\n");
DPRINTK("Initializing card timings manually...\n");
default_par->memclock = 100000;
}
if (pdev->subsystem_vendor == 0x3d3d &&
pdev->subsystem_device == 0x0100) {
DPRINTK("subsystem_vendor: %04x, "
"subsystem_device: %04x\n",
pdev->subsystem_vendor, pdev->subsystem_device);
DPRINTK("We have not been initialized by VGA BIOS and "
"are running on an 3dlabs reference board\n");
DPRINTK("Initializing card timings manually...\n");
default_par->memclock = 74894;
}
}
/* Now work out how big lfb is going to be. */
switch (default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
case PM2F_MEM_BANKS_1:
pm2fb_fix.smem_len = 0x200000;
break;
case PM2F_MEM_BANKS_2:
pm2fb_fix.smem_len = 0x400000;
break;
case PM2F_MEM_BANKS_3:
pm2fb_fix.smem_len = 0x600000;
break;
case PM2F_MEM_BANKS_4:
pm2fb_fix.smem_len = 0x800000;
break;
}
pm2fb_fix.smem_start = pci_resource_start(pdev, 1);
/* Linear frame buffer - request region and map it. */
if (!request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len,
"pm2fb smem")) {
printk(KERN_WARNING "pm2fb: Can't reserve smem.\n");
goto err_exit_mmio;
}
info->screen_base =
ioremap_wc(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
if (!info->screen_base) {
printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n");
release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
goto err_exit_mmio;
}
if (!nomtrr)
default_par->wc_cookie = arch_phys_wc_add(pm2fb_fix.smem_start,
pm2fb_fix.smem_len);
info->fbops = &pm2fb_ops;
info->fix = pm2fb_fix;
info->pseudo_palette = default_par->palette;
info->flags = FBINFO_DEFAULT |
FBINFO_HWACCEL_YPAN |
FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_FILLRECT;
info->pixmap.addr = kmalloc(PM2_PIXMAP_SIZE, GFP_KERNEL);
if (!info->pixmap.addr) {
retval = -ENOMEM;
goto err_exit_pixmap;
}
info->pixmap.size = PM2_PIXMAP_SIZE;
info->pixmap.buf_align = 4;
info->pixmap.scan_align = 4;
info->pixmap.access_align = 32;
info->pixmap.flags = FB_PIXMAP_SYSTEM;
if (noaccel) {
printk(KERN_DEBUG "disabling acceleration\n");
info->flags |= FBINFO_HWACCEL_DISABLED;
info->pixmap.scan_align = 1;
}
if (!mode_option)
mode_option = "640x480@60";
err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
if (!err || err == 4)
info->var = pm2fb_var;
retval = fb_alloc_cmap(&info->cmap, 256, 0);
if (retval < 0)
goto err_exit_both;
retval = register_framebuffer(info);
if (retval < 0)
goto err_exit_all;
fb_info(info, "%s frame buffer device, memory = %dK\n",
info->fix.id, pm2fb_fix.smem_len / 1024);
/*
* Our driver data
*/
pci_set_drvdata(pdev, info);
return 0;
err_exit_all:
fb_dealloc_cmap(&info->cmap);
err_exit_both:
kfree(info->pixmap.addr);
err_exit_pixmap:
iounmap(info->screen_base);
release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
err_exit_mmio:
iounmap(default_par->v_regs);
release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
err_exit_neither:
framebuffer_release(info);
return retval;
}