⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sm501fb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (ret < 0)		return ret;	/* initialise the colour registers */	writel(par->cursor.sm_addr, par->cursor_regs + SM501_OFF_HWC_ADDR);	writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC);	writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2);	writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3);	sm501fb_sync_regs(info);	return 0;}/* sm501fb_info_start * * fills the par structure claiming resources and remapping etc.*/static int sm501fb_start(struct sm501fb_info *info,			 struct platform_device *pdev){	struct resource	*res;	struct device *dev = &pdev->dev;	int k;	int ret;	info->irq = ret = platform_get_irq(pdev, 0);	if (ret < 0) {		/* we currently do not use the IRQ */		dev_warn(dev, "no irq for device\n");	}	/* allocate, reserve and remap resources for registers */	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);	if (res == NULL) {		dev_err(dev, "no resource definition for registers\n");		ret = -ENOENT;		goto err_release;	}	info->regs_res = request_mem_region(res->start,					    res->end - res->start,					    pdev->name);	if (info->regs_res == NULL) {		dev_err(dev, "cannot claim registers\n");		ret = -ENXIO;		goto err_release;	}	info->regs = ioremap(res->start, (res->end - res->start)+1);	if (info->regs == NULL) {		dev_err(dev, "cannot remap registers\n");		ret = -ENXIO;		goto err_regs_res;	}	/* allocate, reserve resources for framebuffer */	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);	if (res == NULL) {		dev_err(dev, "no memory resource defined\n");		ret = -ENXIO;		goto err_regs_map;	}	info->fbmem_res = request_mem_region(res->start,					     (res->end - res->start)+1,					     pdev->name);	if (info->fbmem_res == NULL) {		dev_err(dev, "cannot claim framebuffer\n");		ret = -ENXIO;		goto err_regs_map;	}	info->fbmem = ioremap(res->start, (res->end - res->start)+1);	if (info->fbmem == NULL) {		dev_err(dev, "cannot remap framebuffer\n");		goto err_mem_res;	}	info->fbmem_len = (res->end - res->start)+1;	/* clear framebuffer memory - avoids garbage data on unused fb */	memset(info->fbmem, 0, info->fbmem_len);	/* clear palette ram - undefined at power on */	for (k = 0; k < (256 * 3); k++)		writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4));	/* enable display controller */	sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);	/* setup cursors */	sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR);	sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR);	return 0; /* everything is setup */ err_mem_res:	release_resource(info->fbmem_res);	kfree(info->fbmem_res); err_regs_map:	iounmap(info->regs); err_regs_res:	release_resource(info->regs_res);	kfree(info->regs_res); err_release:	return ret;}static void sm501fb_stop(struct sm501fb_info *info){	/* disable display controller */	sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);	iounmap(info->fbmem);	release_resource(info->fbmem_res);	kfree(info->fbmem_res);	iounmap(info->regs);	release_resource(info->regs_res);	kfree(info->regs_res);}static int sm501fb_init_fb(struct fb_info *fb,			   enum sm501_controller head,			   const char *fbname){	struct sm501_platdata_fbsub *pd;	struct sm501fb_par *par = fb->par;	struct sm501fb_info *info = par->info;	unsigned long ctrl;	unsigned int enable;	int ret;	switch (head) {	case HEAD_CRT:		pd = info->pdata->fb_crt;		ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);		enable = (ctrl & SM501_DC_CRT_CONTROL_ENABLE) ? 1 : 0;		/* ensure we set the correct source register */		if (info->pdata->fb_route != SM501_FB_CRT_PANEL) {			ctrl |= SM501_DC_CRT_CONTROL_SEL;			writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);		}		break;	case HEAD_PANEL:		pd = info->pdata->fb_pnl;		ctrl = readl(info->regs + SM501_DC_PANEL_CONTROL);		enable = (ctrl & SM501_DC_PANEL_CONTROL_EN) ? 1 : 0;		break;	default:		pd = NULL;		/* stop compiler warnings */		ctrl = 0;		enable = 0;		BUG();	}	dev_info(info->dev, "fb %s %sabled at start\n",		 fbname, enable ? "en" : "dis");	/* check to see if our routing allows this */	if (head == HEAD_CRT && info->pdata->fb_route == SM501_FB_CRT_PANEL) {		ctrl &= ~SM501_DC_CRT_CONTROL_SEL;		writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);		enable = 0;	}	strlcpy(fb->fix.id, fbname, sizeof(fb->fix.id));	memcpy(&par->ops,	       (head == HEAD_CRT) ? &sm501fb_ops_crt : &sm501fb_ops_pnl,	       sizeof(struct fb_ops));	/* update ops dependant on what we've been passed */	if ((pd->flags & SM501FB_FLAG_USE_HWCURSOR) == 0)		par->ops.fb_cursor = NULL;	fb->fbops = &par->ops;	fb->flags = FBINFO_FLAG_DEFAULT |		FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;	/* fixed data */	fb->fix.type		= FB_TYPE_PACKED_PIXELS;	fb->fix.type_aux	= 0;	fb->fix.xpanstep	= 1;	fb->fix.ypanstep	= 1;	fb->fix.ywrapstep	= 0;	fb->fix.accel		= FB_ACCEL_NONE;	/* screenmode */	fb->var.nonstd		= 0;	fb->var.activate	= FB_ACTIVATE_NOW;	fb->var.accel_flags	= 0;	fb->var.vmode		= FB_VMODE_NONINTERLACED;	fb->var.bits_per_pixel  = 16;	if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) {		/* TODO read the mode from the current display */	} else {		if (pd->def_mode) {			dev_info(info->dev, "using supplied mode\n");			fb_videomode_to_var(&fb->var, pd->def_mode);			fb->var.bits_per_pixel = pd->def_bpp ? pd->def_bpp : 8;			fb->var.xres_virtual = fb->var.xres;			fb->var.yres_virtual = fb->var.yres;		} else {			ret = fb_find_mode(&fb->var, fb,					   NULL, NULL, 0, NULL, 8);			if (ret == 0 || ret == 4) {				dev_err(info->dev,					"failed to get initial mode\n");				return -EINVAL;			}		}	}	/* initialise and set the palette */	fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0);	fb_set_cmap(&fb->cmap, fb);	ret = (fb->fbops->fb_check_var)(&fb->var, fb);	if (ret)		dev_err(info->dev, "check_var() failed on initial setup?\n");	/* ensure we've activated our new configuration */	(fb->fbops->fb_set_par)(fb);	return 0;}/* default platform data if none is supplied (ie, PCI device) */static struct sm501_platdata_fbsub sm501fb_pdata_crt = {	.flags		= (SM501FB_FLAG_USE_INIT_MODE |			   SM501FB_FLAG_USE_HWCURSOR |			   SM501FB_FLAG_USE_HWACCEL |			   SM501FB_FLAG_DISABLE_AT_EXIT),};static struct sm501_platdata_fbsub sm501fb_pdata_pnl = {	.flags		= (SM501FB_FLAG_USE_INIT_MODE |			   SM501FB_FLAG_USE_HWCURSOR |			   SM501FB_FLAG_USE_HWACCEL |			   SM501FB_FLAG_DISABLE_AT_EXIT),};static struct sm501_platdata_fb sm501fb_def_pdata = {	.fb_route		= SM501_FB_OWN,	.fb_crt			= &sm501fb_pdata_crt,	.fb_pnl			= &sm501fb_pdata_pnl,};static char driver_name_crt[] = "sm501fb-crt";static char driver_name_pnl[] = "sm501fb-panel";static int __devinit sm501fb_probe_one(struct sm501fb_info *info,				       enum sm501_controller head){	unsigned char *name = (head == HEAD_CRT) ? "crt" : "panel";	struct sm501_platdata_fbsub *pd;	struct sm501fb_par *par;	struct fb_info *fbi;	pd = (head == HEAD_CRT) ? info->pdata->fb_crt : info->pdata->fb_pnl;	/* Do not initialise if we've not been given any platform data */	if (pd == NULL) {		dev_info(info->dev, "no data for fb %s (disabled)\n", name);		return 0;	}	fbi = framebuffer_alloc(sizeof(struct sm501fb_par), info->dev);	if (fbi == NULL) {		dev_err(info->dev, "cannot allocate %s framebuffer\n", name);		return -ENOMEM;	}	par = fbi->par;	par->info = info;	par->head = head;	fbi->pseudo_palette = &par->pseudo_palette;	info->fb[head] = fbi;	return 0;}/* Free up anything allocated by sm501fb_init_fb */static void sm501_free_init_fb(struct sm501fb_info *info,				enum sm501_controller head){	struct fb_info *fbi = info->fb[head];	fb_dealloc_cmap(&fbi->cmap);}static int __devinit sm501fb_start_one(struct sm501fb_info *info,				       enum sm501_controller head,				       const char *drvname){	struct fb_info *fbi = info->fb[head];	int ret;	if (!fbi)		return 0;	ret = sm501fb_init_fb(info->fb[head], head, drvname);	if (ret) {		dev_err(info->dev, "cannot initialise fb %s\n", drvname);		return ret;	}	ret = register_framebuffer(info->fb[head]);	if (ret) {		dev_err(info->dev, "failed to register fb %s\n", drvname);		sm501_free_init_fb(info, head);		return ret;	}	dev_info(info->dev, "fb%d: %s frame buffer\n", fbi->node, fbi->fix.id);	return 0;}static int __devinit sm501fb_probe(struct platform_device *pdev){	struct sm501fb_info *info;	struct device *dev = &pdev->dev;	int ret;	/* allocate our framebuffers */	info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL);	if (!info) {		dev_err(dev, "failed to allocate state\n");		return -ENOMEM;	}	info->dev = dev = &pdev->dev;	platform_set_drvdata(pdev, info);	if (dev->parent->platform_data) {		struct sm501_platdata *pd = dev->parent->platform_data;		info->pdata = pd->fb;	}	if (info->pdata == NULL) {		dev_info(dev, "using default configuration data\n");		info->pdata = &sm501fb_def_pdata;	}	/* probe for the presence of each panel */	ret = sm501fb_probe_one(info, HEAD_CRT);	if (ret < 0) {		dev_err(dev, "failed to probe CRT\n");		goto err_alloc;	}	ret = sm501fb_probe_one(info, HEAD_PANEL);	if (ret < 0) {		dev_err(dev, "failed to probe PANEL\n");		goto err_probed_crt;	}	if (info->fb[HEAD_PANEL] == NULL &&	    info->fb[HEAD_CRT] == NULL) {		dev_err(dev, "no framebuffers found\n");		goto err_alloc;	}	/* get the resources for both of the framebuffers */	ret = sm501fb_start(info, pdev);	if (ret) {		dev_err(dev, "cannot initialise SM501\n");		goto err_probed_panel;	}	ret = sm501fb_start_one(info, HEAD_CRT, driver_name_crt);	if (ret) {		dev_err(dev, "failed to start CRT\n");		goto err_started;	}	ret = sm501fb_start_one(info, HEAD_PANEL, driver_name_pnl);	if (ret) {		dev_err(dev, "failed to start Panel\n");		goto err_started_crt;	}	/* create device files */	ret = device_create_file(dev, &dev_attr_crt_src);	if (ret)		goto err_started_panel;	ret = device_create_file(dev, &dev_attr_fbregs_pnl);	if (ret)		goto err_attached_crtsrc_file;	ret = device_create_file(dev, &dev_attr_fbregs_crt);	if (ret)		goto err_attached_pnlregs_file;	/* we registered, return ok */	return 0;err_attached_pnlregs_file:	device_remove_file(dev, &dev_attr_fbregs_pnl);err_attached_crtsrc_file:	device_remove_file(dev, &dev_attr_crt_src);err_started_panel:	unregister_framebuffer(info->fb[HEAD_PANEL]);	sm501_free_init_fb(info, HEAD_PANEL);err_started_crt:	unregister_framebuffer(info->fb[HEAD_CRT]);	sm501_free_init_fb(info, HEAD_CRT);err_started:	sm501fb_stop(info);err_probed_panel:	framebuffer_release(info->fb[HEAD_PANEL]);err_probed_crt:	framebuffer_release(info->fb[HEAD_CRT]);err_alloc:	kfree(info);	return ret;}/* *  Cleanup */static int sm501fb_remove(struct platform_device *pdev){	struct sm501fb_info *info = platform_get_drvdata(pdev);	struct fb_info	   *fbinfo_crt = info->fb[0];	struct fb_info	   *fbinfo_pnl = info->fb[1];	device_remove_file(&pdev->dev, &dev_attr_fbregs_crt);	device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl);	device_remove_file(&pdev->dev, &dev_attr_crt_src);	sm501_free_init_fb(info, HEAD_CRT);	sm501_free_init_fb(info, HEAD_PANEL);	unregister_framebuffer(fbinfo_crt);	unregister_framebuffer(fbinfo_pnl);	sm501fb_stop(info);	kfree(info);	framebuffer_release(fbinfo_pnl);	framebuffer_release(fbinfo_crt);	return 0;}#ifdef CONFIG_PMstatic int sm501fb_suspend_fb(struct sm501fb_info *info,			      enum sm501_controller head){	struct fb_info *fbi = info->fb[head];	struct sm501fb_par *par = fbi->par;	if (par->screen.size == 0)		return 0;	/* blank the relevant interface to ensure unit power minimised */	(par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);	/* tell console/fb driver we are suspending */	acquire_console_sem();	fb_set_suspend(fbi, 1);	release_console_sem();	/* backup copies in case chip is powered down over suspend */	par->store_fb = vmalloc(par->screen.size);	if (par->store_fb == NULL) {		dev_err(info->dev, "no memory to store screen\n");		return -ENOMEM;	}	par->store_cursor = vmalloc(par->cursor.size);	if (par->store_cursor == NULL) {		dev_err(info->dev, "no memory to store cursor\n");		goto err_nocursor;	}	dev_dbg(info->dev, "suspending screen to %p\n", par->store_fb);	dev_dbg(info->dev, "suspending cursor to %p\n", par->store_cursor);	memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size);	memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size);	return 0; err_nocursor:	vfree(par->store_fb);	par->store_fb = NULL;	return -ENOMEM;}static void sm501fb_resume_fb(struct sm501fb_info *info,			      enum sm501_controller head){	struct fb_info *fbi = info->fb[head];	struct sm501fb_par *par = fbi->par;	if (par->screen.size == 0)		return;	/* re-activate the configuration */	(par->ops.fb_set_par)(fbi);	/* restore the data */	dev_dbg(info->dev, "restoring screen from %p\n", par->store_fb);	dev_dbg(info->dev, "restoring cursor from %p\n", par->store_cursor);	if (par->store_fb)		memcpy_toio(par->screen.k_addr, par->store_fb,			    par->screen.size);	if (par->store_cursor)		memcpy_toio(par->cursor.k_addr, par->store_cursor,			    par->cursor.size);	acquire_console_sem();	fb_set_suspend(fbi, 0);	release_console_sem();	vfree(par->store_fb);	vfree(par->store_cursor);}/* suspend and resume support */static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state){	struct sm501fb_info *info = platform_get_drvdata(pdev);	/* store crt control to resume with */	info->pm_crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);	sm501fb_suspend_fb(info, HEAD_CRT);	sm501fb_suspend_fb(info, HEAD_PANEL);	/* turn off the clocks, in case the device is not powered down */	sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);	return 0;}#define SM501_CRT_CTRL_SAVE (SM501_DC_CRT_CONTROL_TVP |        \			     SM501_DC_CRT_CONTROL_SEL)static int sm501fb_resume(struct platform_device *pdev){	struct sm501fb_info *info = platform_get_drvdata(pdev);	unsigned long crt_ctrl;	sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1);	/* restore the items we want to be saved for crt control */	crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);	crt_ctrl &= ~SM501_CRT_CTRL_SAVE;	crt_ctrl |= info->pm_crt_ctrl & SM501_CRT_CTRL_SAVE;	writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL);	sm501fb_resume_fb(info, HEAD_CRT);	sm501fb_resume_fb(info, HEAD_PANEL);	return 0;}#else#define sm501fb_suspend NULL#define sm501fb_resume  NULL#endifstatic struct platform_driver sm501fb_driver = {	.probe		= sm501fb_probe,	.remove		= sm501fb_remove,	.suspend	= sm501fb_suspend,	.resume		= sm501fb_resume,	.driver		= {		.name	= "sm501-fb",		.owner	= THIS_MODULE,	},};static int __devinit sm501fb_init(void){	return platform_driver_register(&sm501fb_driver);}static void __exit sm501fb_cleanup(void){	platform_driver_unregister(&sm501fb_driver);}module_init(sm501fb_init);module_exit(sm501fb_cleanup);MODULE_AUTHOR("Ben Dooks, Vincent Sanders");MODULE_DESCRIPTION("SM501 Framebuffer driver");MODULE_LICENSE("GPL v2");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -