概述
以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。
前言
博文fb驱动框架分析(核心层)已经对内核驱动维护者编写的fb驱动框架进行讲解。
接下来将对具体的fb驱动文件进行分析。这些驱动文件是驱动工程师要完成的部分。
复制代码1
2
3
4root@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控制器,它属于内部外设,故而可以借用平台总线实现一些机制。
复制代码1
2
3
4
5
6
7
8
9
10
11
12
13static 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
复制代码1
2
3
4
5
6
7
8static 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”。
复制代码1
2
3
4
5
6
7
8
9
10struct 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()函数对这些平台设备进行注册,过程如下所示。
复制代码1
2
3
4
5
6
7
8
9
10
11
12static struct platform_device *smdkc110_devices[] __initdata = { #ifdef CONFIG_FIQ_DEBUGGER &s5pv210_device_fiqdbg_uart2, #endif //省略部分代码 #ifdef CONFIG_FB_S3C &s3c_device_fb, //这里 #endif //省略部分代码 }
复制代码1
2
3
4
5
6static void __init smdkc110_machine_init(void) { //省略部分代码 platform_add_devices(smdkc110_devices, ARRAY_SIZE(smdkc110_devices)); //省略部分代码 }
(3)我们再看一下s3cfb_resource,其内容如下。
复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17static 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()函数内容如下:
复制代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163static 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、更多分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复