in fbdev/tridentfb.c [1459:1718]
static int trident_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
int err;
unsigned char revision;
struct fb_info *info;
struct tridentfb_par *default_par;
int chip3D;
int chip_id;
bool found = false;
err = pci_enable_device(dev);
if (err)
return err;
info = framebuffer_alloc(sizeof(struct tridentfb_par), &dev->dev);
if (!info)
return -ENOMEM;
default_par = info->par;
chip_id = id->device;
/* If PCI id is 0x9660 then further detect chip type */
if (chip_id == TGUI9660) {
revision = vga_io_rseq(RevisionID);
switch (revision) {
case 0x21:
chip_id = PROVIDIA9685;
break;
case 0x22:
case 0x23:
chip_id = CYBER9397;
break;
case 0x2A:
chip_id = CYBER9397DVD;
break;
case 0x30:
case 0x33:
case 0x34:
case 0x35:
case 0x38:
case 0x3A:
case 0xB3:
chip_id = CYBER9385;
break;
case 0x40 ... 0x43:
chip_id = CYBER9382;
break;
case 0x4A:
chip_id = CYBER9388;
break;
default:
break;
}
}
chip3D = is3Dchip(chip_id);
if (is_xp(chip_id)) {
default_par->init_accel = xp_init_accel;
default_par->wait_engine = xp_wait_engine;
default_par->fill_rect = xp_fill_rect;
default_par->copy_rect = xp_copy_rect;
tridentfb_fix.accel = FB_ACCEL_TRIDENT_BLADEXP;
} else if (is_blade(chip_id)) {
default_par->init_accel = blade_init_accel;
default_par->wait_engine = blade_wait_engine;
default_par->fill_rect = blade_fill_rect;
default_par->copy_rect = blade_copy_rect;
default_par->image_blit = blade_image_blit;
tridentfb_fix.accel = FB_ACCEL_TRIDENT_BLADE3D;
} else if (chip3D) { /* 3DImage family left */
default_par->init_accel = image_init_accel;
default_par->wait_engine = image_wait_engine;
default_par->fill_rect = image_fill_rect;
default_par->copy_rect = image_copy_rect;
tridentfb_fix.accel = FB_ACCEL_TRIDENT_3DIMAGE;
} else { /* TGUI 9440/96XX family */
default_par->init_accel = tgui_init_accel;
default_par->wait_engine = xp_wait_engine;
default_par->fill_rect = tgui_fill_rect;
default_par->copy_rect = tgui_copy_rect;
tridentfb_fix.accel = FB_ACCEL_TRIDENT_TGUI;
}
default_par->chip_id = chip_id;
/* setup MMIO region */
tridentfb_fix.mmio_start = pci_resource_start(dev, 1);
tridentfb_fix.mmio_len = pci_resource_len(dev, 1);
if (!request_mem_region(tridentfb_fix.mmio_start,
tridentfb_fix.mmio_len, "tridentfb")) {
debug("request_region failed!\n");
framebuffer_release(info);
return -1;
}
default_par->io_virt = ioremap(tridentfb_fix.mmio_start,
tridentfb_fix.mmio_len);
if (!default_par->io_virt) {
debug("ioremap failed\n");
err = -1;
goto out_unmap1;
}
enable_mmio(default_par);
/* setup framebuffer memory */
tridentfb_fix.smem_start = pci_resource_start(dev, 0);
tridentfb_fix.smem_len = get_memsize(default_par);
if (!request_mem_region(tridentfb_fix.smem_start,
tridentfb_fix.smem_len, "tridentfb")) {
debug("request_mem_region failed!\n");
disable_mmio(info->par);
err = -1;
goto out_unmap1;
}
info->screen_base = ioremap(tridentfb_fix.smem_start,
tridentfb_fix.smem_len);
if (!info->screen_base) {
debug("ioremap failed\n");
err = -1;
goto out_unmap2;
}
default_par->flatpanel = is_flatpanel(default_par);
if (default_par->flatpanel)
nativex = get_nativex(default_par);
info->fix = tridentfb_fix;
info->fbops = &tridentfb_ops;
info->pseudo_palette = default_par->pseudo_pal;
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
if (!noaccel && default_par->init_accel) {
info->flags &= ~FBINFO_HWACCEL_DISABLED;
info->flags |= FBINFO_HWACCEL_COPYAREA;
info->flags |= FBINFO_HWACCEL_FILLRECT;
} else
info->flags |= FBINFO_HWACCEL_DISABLED;
if (is_blade(chip_id) && chip_id != BLADE3D)
info->flags |= FBINFO_READS_FAST;
info->pixmap.addr = kmalloc(4096, GFP_KERNEL);
if (!info->pixmap.addr) {
err = -ENOMEM;
goto out_unmap2;
}
info->pixmap.size = 4096;
info->pixmap.buf_align = 4;
info->pixmap.scan_align = 1;
info->pixmap.access_align = 32;
info->pixmap.flags = FB_PIXMAP_SYSTEM;
info->var.bits_per_pixel = 8;
if (default_par->image_blit) {
info->flags |= FBINFO_HWACCEL_IMAGEBLIT;
info->pixmap.scan_align = 4;
}
if (noaccel) {
printk(KERN_DEBUG "disabling acceleration\n");
info->flags |= FBINFO_HWACCEL_DISABLED;
info->pixmap.scan_align = 1;
}
if (tridentfb_setup_ddc_bus(info) == 0) {
u8 *edid = fb_ddc_read(&default_par->ddc_adapter);
default_par->ddc_registered = true;
if (edid) {
fb_edid_to_monspecs(edid, &info->monspecs);
kfree(edid);
if (!info->monspecs.modedb)
dev_err(info->device, "error getting mode database\n");
else {
const struct fb_videomode *m;
fb_videomode_to_modelist(info->monspecs.modedb,
info->monspecs.modedb_len,
&info->modelist);
m = fb_find_best_display(&info->monspecs,
&info->modelist);
if (m) {
fb_videomode_to_var(&info->var, m);
/* fill all other info->var's fields */
if (tridentfb_check_var(&info->var,
info) == 0)
found = true;
}
}
}
}
if (!mode_option && !found)
mode_option = "640x480-8@60";
/* Prepare startup mode */
if (mode_option) {
err = fb_find_mode(&info->var, info, mode_option,
info->monspecs.modedb,
info->monspecs.modedb_len,
NULL, info->var.bits_per_pixel);
if (!err || err == 4) {
err = -EINVAL;
dev_err(info->device, "mode %s not found\n",
mode_option);
fb_destroy_modedb(info->monspecs.modedb);
info->monspecs.modedb = NULL;
goto out_unmap2;
}
}
fb_destroy_modedb(info->monspecs.modedb);
info->monspecs.modedb = NULL;
err = fb_alloc_cmap(&info->cmap, 256, 0);
if (err < 0)
goto out_unmap2;
info->var.activate |= FB_ACTIVATE_NOW;
info->device = &dev->dev;
if (register_framebuffer(info) < 0) {
printk(KERN_ERR "tridentfb: could not register framebuffer\n");
fb_dealloc_cmap(&info->cmap);
err = -EINVAL;
goto out_unmap2;
}
output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
info->node, info->fix.id, info->var.xres,
info->var.yres, info->var.bits_per_pixel);
pci_set_drvdata(dev, info);
return 0;
out_unmap2:
if (default_par->ddc_registered)
i2c_del_adapter(&default_par->ddc_adapter);
kfree(info->pixmap.addr);
if (info->screen_base)
iounmap(info->screen_base);
release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
disable_mmio(info->par);
out_unmap1:
if (default_par->io_virt)
iounmap(default_par->io_virt);
release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
framebuffer_release(info);
return err;
}