📄 savagefb_driver.c
字号:
if (cr6b & ActiveLCD) { /* * If the LCD is active and panel expansion is enabled, * we probably want to kill the HW cursor. */ printk(KERN_INFO "savagefb: Limiting video mode to " "%dx%d\n", panelX, panelY); par->SavagePanelWidth = panelX; par->SavagePanelHeight = panelY; } else par->display_type = DISP_CRT; } savage_get_default_par(par, &par->state); par->save = par->state; if (S3_SAVAGE4_SERIES(par->chip)) { /* * The Savage4 and ProSavage have COB coherency bugs which * render the buffer useless. We disable it. */ par->cob_index = 2; par->cob_size = 0x8000 << par->cob_index; par->cob_offset = videoRambytes; } else { /* We use 128kB for the COB on all chips. */ par->cob_index = 7; par->cob_size = 0x400 << par->cob_index; par->cob_offset = videoRambytes - par->cob_size; } return videoRambytes;}static int __devinit savage_init_fb_info(struct fb_info *info, struct pci_dev *dev, const struct pci_device_id *id){ struct savagefb_par *par = info->par; int err = 0; par->pcidev = dev; info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.type_aux = 0; info->fix.ypanstep = 1; info->fix.ywrapstep = 0; info->fix.accel = id->driver_data; switch (info->fix.accel) { case FB_ACCEL_SUPERSAVAGE: par->chip = S3_SUPERSAVAGE; snprintf(info->fix.id, 16, "SuperSavage"); break; case FB_ACCEL_SAVAGE4: par->chip = S3_SAVAGE4; snprintf(info->fix.id, 16, "Savage4"); break; case FB_ACCEL_SAVAGE3D: par->chip = S3_SAVAGE3D; snprintf(info->fix.id, 16, "Savage3D"); break; case FB_ACCEL_SAVAGE3D_MV: par->chip = S3_SAVAGE3D; snprintf(info->fix.id, 16, "Savage3D-MV"); break; case FB_ACCEL_SAVAGE2000: par->chip = S3_SAVAGE2000; snprintf(info->fix.id, 16, "Savage2000"); break; case FB_ACCEL_SAVAGE_MX_MV: par->chip = S3_SAVAGE_MX; snprintf(info->fix.id, 16, "Savage/MX-MV"); break; case FB_ACCEL_SAVAGE_MX: par->chip = S3_SAVAGE_MX; snprintf(info->fix.id, 16, "Savage/MX"); break; case FB_ACCEL_SAVAGE_IX_MV: par->chip = S3_SAVAGE_MX; snprintf(info->fix.id, 16, "Savage/IX-MV"); break; case FB_ACCEL_SAVAGE_IX: par->chip = S3_SAVAGE_MX; snprintf(info->fix.id, 16, "Savage/IX"); break; case FB_ACCEL_PROSAVAGE_PM: par->chip = S3_PROSAVAGE; snprintf(info->fix.id, 16, "ProSavagePM"); break; case FB_ACCEL_PROSAVAGE_KM: par->chip = S3_PROSAVAGE; snprintf(info->fix.id, 16, "ProSavageKM"); break; case FB_ACCEL_S3TWISTER_P: par->chip = S3_PROSAVAGE; snprintf(info->fix.id, 16, "TwisterP"); break; case FB_ACCEL_S3TWISTER_K: par->chip = S3_PROSAVAGE; snprintf(info->fix.id, 16, "TwisterK"); break; case FB_ACCEL_PROSAVAGE_DDR: par->chip = S3_PROSAVAGE; snprintf(info->fix.id, 16, "ProSavageDDR"); break; case FB_ACCEL_PROSAVAGE_DDRK: par->chip = S3_PROSAVAGE; snprintf(info->fix.id, 16, "ProSavage8"); break; } if (S3_SAVAGE3D_SERIES(par->chip)) { par->SavageWaitIdle = savage3D_waitidle; par->SavageWaitFifo = savage3D_waitfifo; } else if (S3_SAVAGE4_SERIES(par->chip) || S3_SUPERSAVAGE == par->chip) { par->SavageWaitIdle = savage4_waitidle; par->SavageWaitFifo = savage4_waitfifo; } else { par->SavageWaitIdle = savage2000_waitidle; par->SavageWaitFifo = savage2000_waitfifo; } info->var.nonstd = 0; info->var.activate = FB_ACTIVATE_NOW; info->var.width = -1; info->var.height = -1; info->var.accel_flags = 0; info->fbops = &savagefb_ops; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | FBINFO_HWACCEL_XPAN; info->pseudo_palette = par->pseudo_palette;#if defined(CONFIG_FB_SAVAGE_ACCEL) /* FIFO size + padding for commands */ info->pixmap.addr = kcalloc(8, 1024, GFP_KERNEL); err = -ENOMEM; if (info->pixmap.addr) { info->pixmap.size = 8*1024; info->pixmap.scan_align = 4; info->pixmap.buf_align = 4; info->pixmap.access_align = 32; err = fb_alloc_cmap(&info->cmap, NR_PALETTE, 0); if (!err) info->flags |= FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_IMAGEBLIT; }#endif return err;}/* --------------------------------------------------------------------- */static int __devinit savagefb_probe(struct pci_dev* dev, const struct pci_device_id* id){ struct fb_info *info; struct savagefb_par *par; u_int h_sync, v_sync; int err, lpitch; int video_len; DBG("savagefb_probe"); info = framebuffer_alloc(sizeof(struct savagefb_par), &dev->dev); if (!info) return -ENOMEM; par = info->par; mutex_init(&par->open_lock); err = pci_enable_device(dev); if (err) goto failed_enable; if ((err = pci_request_regions(dev, "savagefb"))) { printk(KERN_ERR "cannot request PCI regions\n"); goto failed_enable; } err = -ENOMEM; if ((err = savage_init_fb_info(info, dev, id))) goto failed_init; err = savage_map_mmio(info); if (err) goto failed_mmio; video_len = savage_init_hw(par); /* FIXME: cant be negative */ if (video_len < 0) { err = video_len; goto failed_mmio; } err = savage_map_video(info, video_len); if (err) goto failed_video; INIT_LIST_HEAD(&info->modelist);#if defined(CONFIG_FB_SAVAGE_I2C) savagefb_create_i2c_busses(info); savagefb_probe_i2c_connector(info, &par->edid); fb_edid_to_monspecs(par->edid, &info->monspecs); kfree(par->edid); fb_videomode_to_modelist(info->monspecs.modedb, info->monspecs.modedb_len, &info->modelist);#endif info->var = savagefb_var800x600x8; if (mode_option) { fb_find_mode(&info->var, info, mode_option, info->monspecs.modedb, info->monspecs.modedb_len, NULL, 8); } else if (info->monspecs.modedb != NULL) { const struct fb_videomode *mode; mode = fb_find_best_display(&info->monspecs, &info->modelist); savage_update_var(&info->var, mode); } /* 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 failed;#if defined(CONFIG_FB_SAVAGE_ACCEL) /* * The clipping coordinates are masked with 0xFFF, so limit our * virtual resolutions to these sizes. */ if (info->var.yres_virtual > 0x1000) info->var.yres_virtual = 0x1000; if (info->var.xres_virtual > 0x1000) info->var.xres_virtual = 0x1000;#endif savagefb_check_var(&info->var, info); savagefb_set_fix(info); /* * Calculate the hsync and vsync frequencies. Note that * we split the 1e12 constant up so that we can preserve * the precision and fit the results into 32-bit registers. * (1953125000 * 512 = 1e12) */ h_sync = 1953125000 / info->var.pixclock; h_sync = h_sync * 512 / (info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len); v_sync = h_sync / (info->var.yres + info->var.upper_margin + info->var.lower_margin + info->var.vsync_len); printk(KERN_INFO "savagefb v" SAVAGEFB_VERSION ": " "%dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", info->fix.smem_len >> 10, info->var.xres, info->var.yres, h_sync / 1000, h_sync % 1000, v_sync); fb_destroy_modedb(info->monspecs.modedb); info->monspecs.modedb = NULL; err = register_framebuffer(info); if (err < 0) goto failed; printk(KERN_INFO "fb: S3 %s frame buffer device\n", info->fix.id); /* * Our driver data */ pci_set_drvdata(dev, info); return 0; failed:#ifdef CONFIG_FB_SAVAGE_I2C savagefb_delete_i2c_busses(info);#endif fb_alloc_cmap(&info->cmap, 0, 0); savage_unmap_video(info); failed_video: savage_unmap_mmio(info); failed_mmio: kfree(info->pixmap.addr); failed_init: pci_release_regions(dev); failed_enable: framebuffer_release(info); return err;}static void __devexit savagefb_remove(struct pci_dev *dev){ struct fb_info *info = pci_get_drvdata(dev); DBG("savagefb_remove"); if (info) { /* * If unregister_framebuffer fails, then * we will be leaving hooks that could cause * oopsen laying around. */ if (unregister_framebuffer(info)) printk(KERN_WARNING "savagefb: danger danger! " "Oopsen imminent!\n");#ifdef CONFIG_FB_SAVAGE_I2C savagefb_delete_i2c_busses(info);#endif fb_alloc_cmap(&info->cmap, 0, 0); savage_unmap_video(info); savage_unmap_mmio(info); kfree(info->pixmap.addr); pci_release_regions(dev); framebuffer_release(info); /* * Ensure that the driver data is no longer * valid. */ pci_set_drvdata(dev, NULL); }}static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg){ struct fb_info *info = pci_get_drvdata(dev); struct savagefb_par *par = info->par; DBG("savagefb_suspend"); if (mesg.event == PM_EVENT_PRETHAW) mesg.event = PM_EVENT_FREEZE; par->pm_state = mesg.event; dev->dev.power.power_state = mesg; /* * For PM_EVENT_FREEZE, do not power down so the console * can remain active. */ if (mesg.event == PM_EVENT_FREEZE) return 0; acquire_console_sem(); fb_set_suspend(info, 1); if (info->fbops->fb_sync) info->fbops->fb_sync(info); savagefb_blank(FB_BLANK_POWERDOWN, info); savage_set_default_par(par, &par->save); savage_disable_mmio(par); pci_save_state(dev); pci_disable_device(dev); pci_set_power_state(dev, pci_choose_state(dev, mesg)); release_console_sem(); return 0;}static int savagefb_resume(struct pci_dev* dev){ struct fb_info *info = pci_get_drvdata(dev); struct savagefb_par *par = info->par; int cur_state = par->pm_state; DBG("savage_resume"); par->pm_state = PM_EVENT_ON; /* * The adapter was not powered down coming back from a * PM_EVENT_FREEZE. */ if (cur_state == PM_EVENT_FREEZE) { pci_set_power_state(dev, PCI_D0); return 0; } acquire_console_sem(); pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); if (pci_enable_device(dev)) DBG("err"); pci_set_master(dev); savage_enable_mmio(par); savage_init_hw(par); savagefb_set_par(info); fb_set_suspend(info, 0); savagefb_blank(FB_BLANK_UNBLANK, info); release_console_sem(); return 0;}static struct pci_device_id savagefb_devices[] __devinitdata = { {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX128, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128SDR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128DDR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64SDR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64DDR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCSDR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCDDR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE4}, {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D}, {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D_MV, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D_MV}, {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE2000}, {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX_MV, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX_MV}, {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX}, {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX_MV, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX_MV}, {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX}, {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_PM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_PM}, {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_KM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_KM}, {PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_P, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_P}, {PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_K, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_K}, {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDR}, {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDRK, PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDRK}, {0, 0, 0, 0, 0, 0, 0}};MODULE_DEVICE_TABLE(pci, savagefb_devices);static struct pci_driver savagefb_driver = { .name = "savagefb", .id_table = savagefb_devices, .probe = savagefb_probe, .suspend = savagefb_suspend, .resume = savagefb_resume, .remove = __devexit_p(savagefb_remove)};/* **************************** exit-time only **************************** */static void __exit savage_done(void){ DBG("savage_done"); pci_unregister_driver(&sa
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -