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 + -
显示快捷键?