pm2fb.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,289 行 · 第 1/3 页
C
1,289 行
* cmap is not used * DAC[X] is programmed to (red, green, blue) * Truecolor: * does not use RAMDAC (usually has 3 of them). * var->{color}.offset contains start of bitfield * var->{color}.length contains length of bitfield * cmap is programmed to * (red << red.offset) | (green << green.offset) | * (blue << blue.offset) | (transp << transp.offset) * RAMDAC does not exist */#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) switch (info->fix.visual) { case FB_VISUAL_TRUECOLOR: case FB_VISUAL_PSEUDOCOLOR: red = CNVT_TOHW(red, info->var.red.length); green = CNVT_TOHW(green, info->var.green.length); blue = CNVT_TOHW(blue, info->var.blue.length); transp = CNVT_TOHW(transp, info->var.transp.length); set_color(par, regno, red, green, blue); break; case FB_VISUAL_DIRECTCOLOR: /* example here assumes 8 bit DAC. Might be different * for your hardware */ red = CNVT_TOHW(red, 8); green = CNVT_TOHW(green, 8); blue = CNVT_TOHW(blue, 8); /* hey, there is bug in transp handling... */ transp = CNVT_TOHW(transp, 8); break; }#undef CNVT_TOHW /* Truecolor has hardware independent palette */ if (info->fix.visual == FB_VISUAL_TRUECOLOR) { u32 v; if (regno >= 16) return 1; v = (red << info->var.red.offset) | (green << info->var.green.offset) | (blue << info->var.blue.offset) | (transp << info->var.transp.offset); switch (info->var.bits_per_pixel) { case 8: /* Yes some hand held devices have this. */ ((u8*)(info->pseudo_palette))[regno] = v; break; case 16: ((u16*)(info->pseudo_palette))[regno] = v; break; case 24: case 32: ((u32*)(info->pseudo_palette))[regno] = v; break; } return 0; } /* ... */ return 0;}/** * pm2fb_pan_display - Pans the display. * @var: frame buffer variable screen structure * @info: frame buffer structure that represents a single frame buffer * * Pan (or wrap, depending on the `vmode' field) the display using the * `xoffset' and `yoffset' fields of the `var' structure. * If the values don't fit, return -EINVAL. * * Returns negative errno on error, or zero on success. * */static int pm2fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info){ struct pm2fb_par *p = (struct pm2fb_par *) info->par; u32 base; u32 depth; u32 xres; xres = (var->xres + 31) & ~31; depth = (var->bits_per_pixel + 7) & ~7; depth = (depth > 32) ? 32 : depth; base = to3264(var->yoffset * xres + var->xoffset, depth, 1); WAIT_FIFO(p, 1); pm2_WR(p, PM2R_SCREEN_BASE, base); return 0;}/** * pm2fb_blank - Blanks the display. * @blank_mode: the blank mode we want. * @info: frame buffer structure that represents a single frame buffer * * Blank the screen if blank_mode != 0, else unblank. Return 0 if * blanking succeeded, != 0 if un-/blanking failed due to e.g. a * video mode which doesn't support it. Implements VESA suspend * and powerdown modes on hardware that supports disabling hsync/vsync: * blank_mode == 2: suspend vsync * blank_mode == 3: suspend hsync * blank_mode == 4: powerdown * * Returns negative errno on error, or zero on success. * */static int pm2fb_blank(int blank_mode, struct fb_info *info){ struct pm2fb_par *par = (struct pm2fb_par *) info->par; u32 video = par->video; DPRINTK("blank_mode %d\n", blank_mode); /* Turn everything on, then disable as requested. */ video |= (PM2F_VIDEO_ENABLE | PM2F_HSYNC_MASK | PM2F_VSYNC_MASK); switch (blank_mode) { case 0: /* Screen: On; HSync: On, VSync: On */ break; case 1: /* Screen: Off; HSync: On, VSync: On */ video &= ~PM2F_VIDEO_ENABLE; break; case 2: /* Screen: Off; HSync: On, VSync: Off */ video &= ~(PM2F_VIDEO_ENABLE | PM2F_VSYNC_MASK | PM2F_BLANK_LOW ); break; case 3: /* Screen: Off; HSync: Off, VSync: On */ video &= ~(PM2F_VIDEO_ENABLE | PM2F_HSYNC_MASK | PM2F_BLANK_LOW ); break; case 4: /* Screen: Off; HSync: Off, VSync: Off */ video &= ~(PM2F_VIDEO_ENABLE | PM2F_VSYNC_MASK | PM2F_HSYNC_MASK| PM2F_BLANK_LOW); break; } set_video(par, video); 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 = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_cursor = soft_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 size, err; u32 pci_mem_config; int err_retval = -ENXIO; err = pci_enable_device(pdev); if ( err ) { printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err); return err; } size = sizeof(struct pm2fb_par) + 256 * sizeof(u32); info = framebuffer_alloc(size, &pdev->dev); if ( !info ) return -ENOMEM; default_par = (struct pm2fb_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;#ifdef PM2FB_BE_APERTURE pm2fb_fix.mmio_start += PM2_REGS_SIZE;#endif /* 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; } /* Now work out how big lfb is going to be. */ pci_mem_config = RD32(default_par->v_regs, PM2R_MEM_CONFIG); switch(pci_mem_config & PM2F_MEM_CONFIG_RAM_MASK) { case PM2F_MEM_BANKS_1: default_par->fb_size=0x200000; break; case PM2F_MEM_BANKS_2: default_par->fb_size=0x400000; break; case PM2F_MEM_BANKS_3: default_par->fb_size=0x600000; break; case PM2F_MEM_BANKS_4: default_par->fb_size=0x800000; break; } default_par->memclock = CVPPC_MEMCLOCK; pm2fb_fix.smem_start = pci_resource_start(pdev, 1); pm2fb_fix.smem_len = default_par->fb_size; /* 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 = default_par->v_fb = ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len); if ( !default_par->v_fb ) { 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; } info->fbops = &pm2fb_ops; info->fix = pm2fb_fix; info->pseudo_palette = (void *)(default_par + 1); info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;#ifndef MODULE if (!mode) mode = "640x480@60"; err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8); if (!err || err == 4)#endif info->var = pm2fb_var; if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) goto err_exit_all; if (register_framebuffer(info) < 0) goto err_exit_both; printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.\n", info->node, info->fix.id, default_par->fb_size / 1024); /* * Our driver data */ pci_set_drvdata(pdev, info); return 0; err_exit_all: fb_dealloc_cmap(&info->cmap); err_exit_both: iounmap((void*) pm2fb_fix.smem_start); release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); err_exit_mmio: iounmap((void*) pm2fb_fix.mmio_start); release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); err_exit_neither: framebuffer_release(info); return err_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; unregister_framebuffer(info); iounmap((void*) fix->smem_start); release_mem_region(fix->smem_start, fix->smem_len); iounmap((void*) fix->mmio_start); release_mem_region(fix->mmio_start, fix->mmio_len); pci_set_drvdata(pdev, NULL); 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, PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0 }, { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0 }, { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 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);/* * Initialization */int __init pm2fb_setup(char *options);int __init pm2fb_init(void){#ifndef MODULE char *option = NULL; if (fb_get_options("pm2fb", &option)) return -ENODEV; pm2fb_setup(option);#endif return pci_module_init(&pm2fb_driver);}/* * Cleanup */static void __exit pm2fb_exit(void){ pci_unregister_driver(&pm2fb_driver);}/* * Setup *//** * Parse user speficied options. * * This is, comma-separated options following `video=pm2fb:'. */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 { mode = this_opt; } } return 0;}/* ------------------------------------------------------------------------- *//* ------------------------------------------------------------------------- */module_init(pm2fb_init);module_exit(pm2fb_exit);MODULE_PARM(mode,"s");MODULE_PARM(lowhsync,"i");MODULE_PARM(lowvsync,"i");MODULE_AUTHOR("Jim Hague <jim.hague@acm.org>");MODULE_DESCRIPTION("Permedia2 framebuffer device driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?