📄 pm2fb.c
字号:
WAIT_FIFO(par, 4); pm2_WR(par, PM2R_RD_CURSOR_X_LSB, x & 0xff); pm2_WR(par, PM2R_RD_CURSOR_X_MSB, (x >> 8) & 0x7); pm2_WR(par, PM2R_RD_CURSOR_Y_LSB, y & 0xff); pm2_WR(par, PM2R_RD_CURSOR_Y_MSB, (y >> 8) & 0x7); } if (cursor->set & FB_CUR_SETCMAP) { u32 fg_idx = cursor->image.fg_color; u32 bg_idx = cursor->image.bg_color; WAIT_FIFO(par, 7); pm2_WR(par, PM2R_RD_CURSOR_COLOR_ADDRESS, 1); pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, info->cmap.red[bg_idx] >> 8); pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, info->cmap.green[bg_idx] >> 8); pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, info->cmap.blue[bg_idx] >> 8); pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, info->cmap.red[fg_idx] >> 8); pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, info->cmap.green[fg_idx] >> 8); pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA, info->cmap.blue[fg_idx] >> 8); } if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { u8 *bitmap = (u8 *)cursor->image.data; u8 *mask = (u8 *)cursor->mask; int i; WAIT_FIFO(par, 1); pm2_WR(par, PM2R_RD_PALETTE_WRITE_ADDRESS, 0); for (i = 0; i < cursor->image.height; i++) { int j = (cursor->image.width + 7) >> 3; int k = 8 - j; WAIT_FIFO(par, 8); for (; j > 0; j--) { u8 data = *bitmap ^ *mask; if (cursor->rop == ROP_COPY) data = *mask & *bitmap; /* bitmap data */ pm2_WR(par, PM2R_RD_CURSOR_DATA, data); bitmap++; mask++; } for (; k > 0; k--) pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); } for (; i < 64; i++) { int j = 8; WAIT_FIFO(par, 8); while (j-- > 0) pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); } mask = (u8 *)cursor->mask; for (i = 0; i < cursor->image.height; i++) { int j = (cursor->image.width + 7) >> 3; int k = 8 - j; WAIT_FIFO(par, 8); for (; j > 0; j--) { /* mask */ pm2_WR(par, PM2R_RD_CURSOR_DATA, *mask); mask++; } for (; k > 0; k--) pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); } for (; i < 64; i++) { int j = 8; WAIT_FIFO(par, 8); while (j-- > 0) pm2_WR(par, PM2R_RD_CURSOR_DATA, 0); } } return 0;}/* ------------ Hardware Independent Functions ------------ *//* * Frame buffer operations */static struct fb_ops pm2fb_ops = { .owner = THIS_MODULE, .fb_check_var = pm2fb_check_var, .fb_set_par = pm2fb_set_par, .fb_setcolreg = pm2fb_setcolreg, .fb_blank = pm2fb_blank, .fb_pan_display = pm2fb_pan_display, .fb_fillrect = pm2fb_fillrect, .fb_copyarea = pm2fb_copyarea, .fb_imageblit = pm2fb_imageblit, .fb_sync = pm2fb_sync, .fb_cursor = pm2fb_cursor,};/* * PCI stuff *//** * Device initialisation * * Initialise and allocate resource for PCI device. * * @param pdev PCI device. * @param id PCI device ID. */static int __devinit 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_nocache(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_nocache(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; }#ifdef CONFIG_MTRR default_par->mtrr_handle = -1; if (!nomtrr) default_par->mtrr_handle = mtrr_add(pm2fb_fix.smem_start, pm2fb_fix.smem_len, MTRR_TYPE_WRCOMB, 1);#endif 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; printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.\n", info->node, 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;}/** * Device removal. * * Release all device resources. * * @param pdev PCI device to clean up. */static void __devexit pm2fb_remove(struct pci_dev *pdev){ struct fb_info *info = pci_get_drvdata(pdev); struct fb_fix_screeninfo *fix = &info->fix; struct pm2fb_par *par = info->par; unregister_framebuffer(info);#ifdef CONFIG_MTRR if (par->mtrr_handle >= 0) mtrr_del(par->mtrr_handle, info->fix.smem_start, info->fix.smem_len);#endif /* CONFIG_MTRR */ iounmap(info->screen_base); release_mem_region(fix->smem_start, fix->smem_len); iounmap(par->v_regs); release_mem_region(fix->mmio_start, fix->mmio_len); pci_set_drvdata(pdev, NULL); fb_dealloc_cmap(&info->cmap); kfree(info->pixmap.addr); kfree(info);}static struct pci_device_id pm2fb_id_table[] = { { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0, }};static struct pci_driver pm2fb_driver = { .name = "pm2fb", .id_table = pm2fb_id_table, .probe = pm2fb_probe, .remove = __devexit_p(pm2fb_remove),};MODULE_DEVICE_TABLE(pci, pm2fb_id_table);#ifndef MODULE/** * Parse user speficied options. * * This is, comma-separated options following `video=pm2fb:'. */static int __init pm2fb_setup(char *options){ char *this_opt; if (!options || !*options) return 0; while ((this_opt = strsep(&options, ",")) != NULL) { if (!*this_opt) continue; if (!strcmp(this_opt, "lowhsync")) lowhsync = 1; else if (!strcmp(this_opt, "lowvsync")) lowvsync = 1; else if (!strncmp(this_opt, "hwcursor=", 9)) hwcursor = simple_strtoul(this_opt + 9, NULL, 0);#ifdef CONFIG_MTRR else if (!strncmp(this_opt, "nomtrr", 6)) nomtrr = 1;#endif else if (!strncmp(this_opt, "noaccel", 7)) noaccel = 1; else mode_option = this_opt; } return 0;}#endifstatic int __init pm2fb_init(void){#ifndef MODULE char *option = NULL; if (fb_get_options("pm2fb", &option)) return -ENODEV; pm2fb_setup(option);#endif return pci_register_driver(&pm2fb_driver);}module_init(pm2fb_init);#ifdef MODULE/* * Cleanup */static void __exit pm2fb_exit(void){ pci_unregister_driver(&pm2fb_driver);}#endif#ifdef MODULEmodule_exit(pm2fb_exit);module_param(mode_option, charp, 0);MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");module_param_named(mode, mode_option, charp, 0);MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)");module_param(lowhsync, bool, 0);MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode");module_param(lowvsync, bool, 0);MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode");module_param(noaccel, bool, 0);MODULE_PARM_DESC(noaccel, "Disable acceleration");module_param(hwcursor, int, 0644);MODULE_PARM_DESC(hwcursor, "Enable hardware cursor " "(1=enable, 0=disable, default=1)");#ifdef CONFIG_MTRRmodule_param(nomtrr, bool, 0);MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");#endifMODULE_AUTHOR("Jim Hague <jim.hague@acm.org>");MODULE_DESCRIPTION("Permedia2 framebuffer device driver");MODULE_LICENSE("GPL");#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -