概述
以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。
前言
博文fb驱动框架分析(核心层)已经对内核驱动维护者编写的fb驱动框架进行讲解。
接下来将对具体的fb驱动文件进行分析。这些驱动文件是驱动工程师要完成的部分。
root@ubuntu:省略部分路径/x210_kernel/drivers/video# cd samsung/ root@ubuntu:省略部分路径/x210_kernel/drivers/video/samsung# ls *.o built-in.o s3cfb_fimd6x.o s3cfb.o root@ubuntu:省略部分路径/x210_kernel/drivers/video/samsung#
通过检查内核编译结果相应目录中的.o文件,得知具体操作层主要涉及的文件:
(1)drivers/video/samsung/s3cfb.c,这是驱动主要文件。
(2)drivers/video/samsung/s3cfb_fimd6x.c,里面有很多LCD硬件操作的函数。
(3)arch/arm/mach-s5pv210/mach-x210.c,负责提供platform_device。
(4)arch/arm/plat-s5p/devs.c,为platform_device提供一些硬件描述信息。
这里主要分析drivers/video/samsung/s3cfb.c文件。
1、实现方式为平台总线
这是因为使用到SoC内部的LCD控制器,它属于内部外设,故而可以借用平台总线实现一些机制。
static int __init s3cfb_register(void) { platform_driver_register(&s3cfb_driver); return 0; } static void __exit s3cfb_unregister(void) { platform_driver_unregister(&s3cfb_driver); } module_init(s3cfb_register); module_exit(s3cfb_unregister);
2、平台驱动结构体变量:s3cfb_driver
static struct platform_driver s3cfb_driver = { .probe = s3cfb_probe, .remove = __devexit_p(s3cfb_remove), .driver = { .name = S3CFB_NAME, //#define S3CFB_NAME "s3cfb" .owner = THIS_MODULE, }, };
由于平台总线下,驱动与设备是根据name来进行匹配的,这里驱动的名字是“s3cfb”,因此和驱动匹配的设备的名字应该也叫“s3cfb”。
3、s3c_device_fb设备
(1)我们找一下名字叫“s3cfb”的平台设备。在linux系统x210_kernel目录下,使用“ grep -nr “s3cfb” ./ ”命令查找贴切的设备定义,得知其位于arch/arm/plat-s5p/devs.c文件中,内容如下所示。由此可知,s3c_device_fb这个平台设备的名字叫做“s3cfb”。
struct platform_device s3c_device_fb = { .name = "s3cfb", //定义在这里 .id = -1, //id表示次设备号,-1表示自动分配次设备号 .num_resources = ARRAY_SIZE(s3cfb_resource), .resource = s3cfb_resource, .dev = { .dma_mask = &fb_dma_mask, .coherent_dma_mask = 0xffffffffUL } };
(2)在板级文件mach-x210.c中,s3c_device_fb这个平台设备与其他平台设备一样,被写入平台设备数组smdkc110_devices[ ]中,然后再利用smdkc110_machine_init()函数对这些平台设备进行注册,过程如下所示。
static struct platform_device *smdkc110_devices[] __initdata = { #ifdef CONFIG_FIQ_DEBUGGER &s5pv210_device_fiqdbg_uart2, #endif //省略部分代码 #ifdef CONFIG_FB_S3C &s3c_device_fb, //这里 #endif //省略部分代码 }
static void __init smdkc110_machine_init(void) { //省略部分代码 platform_add_devices(smdkc110_devices, ARRAY_SIZE(smdkc110_devices)); //省略部分代码 }
(3)我们再看一下s3cfb_resource,其内容如下。
static struct resource s3cfb_resource[] = { [0] = { .start = S5P_PA_LCD, .end = S5P_PA_LCD + S5P_SZ_LCD - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_LCD1, .end = IRQ_LCD1, .flags = IORESOURCE_IRQ, }, [2] = { .start = IRQ_LCD0, .end = IRQ_LCD0, .flags = IORESOURCE_IRQ, }, };
4、s3cfb_probe()函数分析
s3cfb_probe()函数内容如下:
static int __devinit s3cfb_probe(struct platform_device *pdev) { struct s3c_platform_fb *pdata; struct s3cfb_global *fbdev; struct resource *res; int i, j, ret = 0; fbdev = kzalloc(sizeof(struct s3cfb_global), GFP_KERNEL); if (!fbdev) { dev_err(&pdev->dev, "failed to allocate for " "global fb structuren"); ret = -ENOMEM; goto err_global; } fbdev->dev = &pdev->dev; fbdev->regulator = regulator_get(&pdev->dev, "pd"); if (!fbdev->regulator) { dev_err(fbdev->dev, "failed to get regulatorn"); ret = -EINVAL; goto err_regulator; } ret = regulator_enable(fbdev->regulator); if (ret < 0) { dev_err(fbdev->dev, "failed to enable regulatorn"); ret = -EINVAL; goto err_regulator; } pdata = to_fb_plat(&pdev->dev); if (!pdata) { dev_err(fbdev->dev, "failed to get platform datan"); ret = -EINVAL; goto err_pdata; } fbdev->lcd = (struct s3cfb_lcd *)pdata->lcd; if (pdata->cfg_gpio) pdata->cfg_gpio(pdev); if (pdata->clk_on) pdata->clk_on(pdev, &fbdev->clock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(fbdev->dev, "failed to get io memory regionn"); ret = -EINVAL; goto err_io; } res = request_mem_region(res->start, res->end - res->start + 1, pdev->name); if (!res) { dev_err(fbdev->dev, "failed to request io memory regionn"); ret = -EINVAL; goto err_io; } fbdev->regs = ioremap(res->start, res->end - res->start + 1); if (!fbdev->regs) { dev_err(fbdev->dev, "failed to remap io regionn"); ret = -EINVAL; goto err_mem; } s3cfb_set_vsync_interrupt(fbdev, 1); s3cfb_set_global_interrupt(fbdev, 1); s3cfb_init_global(fbdev); if (s3cfb_alloc_framebuffer(fbdev)) { ret = -ENOMEM; goto err_alloc; } if (s3cfb_register_framebuffer(fbdev)) { ret = -EINVAL; goto err_register; } s3cfb_set_clock(fbdev); s3cfb_set_window(fbdev, pdata->default_win, 1); s3cfb_display_on(fbdev); fbdev->irq = platform_get_irq(pdev, 0); if (request_irq(fbdev->irq, s3cfb_irq_frame, IRQF_SHARED, pdev->name, fbdev)) { dev_err(fbdev->dev, "request_irq failedn"); ret = -EINVAL; goto err_irq; } #ifdef CONFIG_FB_S3C_LCD_INIT if (pdata->backlight_on) pdata->backlight_on(pdev); if (!bootloaderfb && pdata->reset_lcd) pdata->reset_lcd(pdev); #endif #ifdef CONFIG_HAS_EARLYSUSPEND fbdev->early_suspend.suspend = s3cfb_early_suspend; fbdev->early_suspend.resume = s3cfb_late_resume; fbdev->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; register_early_suspend(&fbdev->early_suspend); #endif ret = device_create_file(&(pdev->dev), &dev_attr_win_power); if (ret < 0) dev_err(fbdev->dev, "failed to add sysfs entriesn"); dev_info(fbdev->dev, "registered successfullyn"); #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) if (fb_prepare_logo( fbdev->fb[pdata->default_win], FB_ROTATE_UR)) { printk("Start display and show logon"); /* Start display and show logo on boot */ fb_set_cmap(&fbdev->fb[pdata->default_win]->cmap, fbdev->fb[pdata->default_win]); fb_show_logo(fbdev->fb[pdata->default_win], FB_ROTATE_UR); } #endif mdelay(100); if (pdata->backlight_on) pdata->backlight_on(pdev); return 0; err_irq: s3cfb_display_off(fbdev); s3cfb_set_window(fbdev, pdata->default_win, 0); for (i = pdata->default_win; i < pdata->nr_wins + pdata->default_win; i++) { j = i % pdata->nr_wins; unregister_framebuffer(fbdev->fb[j]); } err_register: for (i = 0; i < pdata->nr_wins; i++) { if (i == pdata->default_win) s3cfb_unmap_default_video_memory(fbdev->fb[i]); framebuffer_release(fbdev->fb[i]); } kfree(fbdev->fb); err_alloc: iounmap(fbdev->regs); err_mem: release_mem_region(res->start, res->end - res->start + 1); err_io: pdata->clk_off(pdev, &fbdev->clock); err_pdata: regulator_disable(fbdev->regulator); err_regulator: kfree(fbdev); err_global: return ret; }
(1)struct s3c_platform_fb 结构体
这个结构体是fb的platform_data结构体,这个结构体变量就是platform设备的私有数据,这个数据在platform_device.device.platform_data中存储。在mach文件中去准备并填充这些数据,在probe函数中通过传参的platform_device指针取出来。
(2)struct s3cfb_global 结构体
在具体操作层的两个文件(s3cfb.c和s3cfb_fimd6x.c)的函数中传递数据。
(3)struct resource 结构体
(4)struct regulator 结构体
(5)platform_data的传递过程1)to_fb_plat
2)s3cfb_set_platdata
3)smdkc110_machine_init
4)struct s3cfb_lcd
5)pdata->cfg_gpio
6)pdata->clk_on
(6)resource的处理板级文件mach-x210.c中提供resource结构体数组,s3cfb_probe()函数的platform_get_resource函数取出resource并且按FLAG分头处理。
(7)一些硬件操作
1)s3cfb_set_vsync_interrupt
2)s3cfb_set_global_interrupt
(8)s3cfb_init_global
(9)向框架注册该fb设备1)s3cfb_alloc_framebuffer
2)s3cfb_register_framebuffer
(10)一些硬件操作
1)s3cfb_set_clock2)s3cfb_set_window
3)s3cfb_display_on
(11)驱动中处理中断
1)platform_get_irq
2)request_irq
(12)logo显示
fb_show_logo
(13)backlight点亮
5、更多分析
与LCD有关的更多内容,参见以下博客:
修改内核的启动logo_天糊土的博客-CSDN博客
应用层为何不能设置分辨率_天糊土的博客-CSDN博客
最后
以上就是动人毛豆为你收集整理的framebuffer驱动详解3——fb驱动分析(具体操作层)前言1、实现方式为平台总线2、平台驱动结构体变量:s3cfb_driver3、s3c_device_fb设备4、s3cfb_probe()函数分析5、更多分析的全部内容,希望文章能够帮你解决framebuffer驱动详解3——fb驱动分析(具体操作层)前言1、实现方式为平台总线2、平台驱动结构体变量:s3cfb_driver3、s3c_device_fb设备4、s3cfb_probe()函数分析5、更多分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复