1.framebuffer介绍
1.1、什么是framebuffer
(1)裸机中如何操作LCD
(2)OS下操作LCD的难点
(3)framebuffer帧缓冲(简称fb)是linux内核中虚拟出的一个设备
(4)framebuffer向应用层提供一个统一标准接口的显示设备
(5)从驱动来看,fb是一个典型的字符设备,而且创建了一个类/sys/class/graphics
1.2、framebuffer的使用
(1)设备文件 /dev/fb0
(2)获取设备信息 #include <linux/fb.h>
(3)mmap做映射
(4)填充framebuffer
FrameBuffer的显示缓冲区位于Linux的内核态地址空间中。
而在Linux中,每个应用程序都有自己的虚拟地址空间,在应用程序中是不能直接访问物理,缓冲区地址的。
为此, Linux在文件操作file operations结构中提供了mmap()函数,可将文件的内容映射到用户空间。
对于帧缓冲设备,则可通过映射操作,将屏幕缓冲区(FrameBuffer)的物理地址映射到用户空间的一段虚拟地址中,之后用户就可以通过读写这段虚拟地址访问屏幕缓冲区,在屏幕上绘图。
FrameBuffer与应用程序的交互如图15.1所示。
2.framebuffer应用编程实践1
2.1、打开设备
2.2、获取设备信息
(1)不可变信息FSCREENINFO,使用ioctl的FBIOGET_FSCREENINFO名
(2)可变信息VSCREENINFO,使用ioctl的FBIOGET_VSCREENINFO名
3.framebuffer应用编程实践2
3.1、mmap做映射
做完了mmap后fb在当前进程中就已经就绪了,随时可以去读写LCD显示器了。
3.2、fb显示之刷背景
4.framebuffer应用编程实践3
4.1、设置分辨率
(1)实验失败,实验结果是只能修改虚拟分辨率,不能修改可视分辨率。原因要去驱动里找。
(2)正确的做法是在驱动中去修改参数,然后重新编译运行,才能解决。
4.2、写字、画线、图片显示等
5.framebuffer驱动框架总览
5.1、驱动框架部分
(1)drivers/video/fbmem.c。主要任务:1、创建graphics类、注册FB的字符设备驱动、提供register_framebuffer接口给具体framebuffer驱动编写着来注册fb设备的。本文件相对于fb来说,地位和作用和misc.c文件相对于杂散类设备来说一样的,结构和分析方法也是类似的。
(2)drivers/video/fbsys.c。这个文件是处理fb在/sys目录下的一些属性文件的。
(3)drivers/video/modedb.c。这个文件是管理显示模式(譬如VGA、720P等就是显示模式)的
(4)drivers/video/fb_notify.c
5.2、驱动部分
(1)drivers/video/samsung/s3cfb.c,驱动主体
(2)drivers/video/samsung/s3cfb_fimd6x.c,里面有很多LCD硬件操作的函数
(2)arch/arm/mach-s5pv210/mach-x210.c,负责提供platform_device的
(3)arch/arm/plat-s5p/devs.c,为platform_device提供一些硬件描述信息的
5.3、如何分析
(1)经验
(2)分析menuconfig、Makefile、Kconfig等
(3)内核编译后检查编译结果中的.o文件
6.framebuffer驱动框架分析1
重要结构体:----------------------------------
1. fb_fops
用来实现帧缓冲设备的操作
2. fb_info:
包含了驱动实现的底层函数和设备状态的数据
3. fb_cmap
结构体记录了一个颜色板信息,也可以叫调色板信息。
用户空间程序可以使明ioctl()函数的FBIOGETCMAP和FBIOPUTCMAP命令读取和设置颜色表的值。struct fb cmap结构体的定义如下:
1
2
3
4
5
6
7
8
9
10
11
12struct fb_cmap { __u32 start; /* 颜色板的第一个元素的入口地址 */ __u32 len; /* 元素的个数 */ __u16 *red; /* 表示红色分量的值 */ __u16 *green; __u16 *blue; __u16 *transp; /* 透明度分量的值, can be NULL */ };
4. fb_var_screeninfo
fb_var_screeninfo结构体中存储了用户可以修改的显示控制器参数,例如屏幕分辨率、每个像素的比特数、透明度等。
- 该结构体中有几个重要成员需要注意。
- xres表示屏幕一行有多少个像素点。
- yres表示屏幕一列有多少个像素点。
- bits_per_pixel表示每个像素点占用多少个字节。
fb_var_screeninfo结构体的定义如下:
5.fb_fix_screeninfo
fb_fix_screeninfo结构体中,记录了用户不能修改的固定显示控制器参数。这些固定参数如缓冲区的物理地址、缓冲区的长度、显示色彩模式、内存映射的开始位置等。
- 需要注意的是,
- 第07行的visual表示屏幕使用的色彩模式,在Linux下,支持多种色彩模式。
- 第11行,表示显存中一行占用的内存字节数,具体占用多少字节由显示模式来决定。
- 第15行,保留了6个字节为以后扩充使用。
这个结构体的成员都需要在驱动程序初始化时设置,该结构体的定义代码如下:
参考:
https://blog.csdn.net/jmq_0000/article/details/7104824
7.framebuffer驱动框架分析2
7.1、register_framebuffer
(1)fb驱动框架开放给驱动编写着的注册接口
(2)fb_check_foreignness
(3)remove_conflicting_framebuffers
(4)device_create
(5)fb_init_device
7.2、fb在sysfs中的接口
(1)device_attrs
(2)dev_set_drvdata和dev_get_drvdata
8.framebuffer驱动框架分析3
8.1、fb的mode
(1)什么是mode
(2)fb_var_to_videomode
(3)fb_add_videomode
8.2、注册登记该fb设备
(1)registered_fb[i] = fb_info;
(2)结合fb_read等函数中对fb_info的使用
(3)关键点:数据如何封装、数据由谁准备由谁消费、数据如何传递
8.3、fb_notifier_call_chain
9.framebuffer驱动分析1
9.1、s3cfb.c
(1)注意目录结构的组织
(2)s3cfb_driver
9.2、s3c_device_fb
(1)mach-x210.c中,被使用
(2)devs.c中
(3)resource的定义和作用
10.framebuffer驱动分析1
10.1、probe函数分析
(1)struct s3c_platform_fb 这个结构体是fb的platform_data结构体,这个结构体变量就是platform设备的私有数据,这个数据在platform_device.device.platform_data中存储。在mach文件中去准备并填充这些数据,在probe函数中通过传参的platform_device指针取出来。
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
31struct s3c_platform_fb { int hw_ver; char clk_name[16]; int nr_wins; int nr_buffers[5]; int default_win; int swap; phys_addr_t pmem_start; /* starting physical address of memory region */ size_t pmem_size; /* size of memory region */ void *lcd; void (*cfg_gpio)(struct platform_device *dev); int (*backlight_on)(struct platform_device *dev); int (*backlight_onoff)(struct platform_device *dev, int onoff); int (*reset_lcd)(struct platform_device *dev); int (*clk_on)(struct platform_device *pdev, struct clk **s3cfb_clk); int (*clk_off)(struct platform_device *pdev, struct clk **clk); };
(2)struct s3cfb_global 这个结构体主要作用是在驱动部分的2个文件(s3cfb.c和s3cfb_fimd6x.c)的函数中做数据传递用的。
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
35struct s3cfb_global { /* general */ void __iomem *regs; struct mutex lock; struct device *dev; struct clk *clock; struct regulator *regulator; int irq; struct fb_info **fb; struct completion fb_complete; /* fimd */ int enabled; int dsi; int interlace; enum s3cfb_output_t output; enum s3cfb_rgb_mode_t rgb_mode; struct s3cfb_lcd *lcd; #ifdef CONFIG_HAS_WAKELOCK struct early_suspend early_suspend; struct wake_lock idle_lock; #endif #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; struct notifier_block freq_policy; #endif };
(3)struct resource
1
2
3
4
5
6
7struct resource { resource_size_t start; resource_size_t end; const char *name; unsigned long flags; struct resource *parent, *sibling, *child; };
(4)regulator 电源监控
10.2、重要的platform_data
platform_data的传递过程
(1)to_fb_plat
1
2
3
4
5
6
7
8
9
10
11
12
13
14static 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; pdata = to_fb_plat(&pdev->dev);//取出挂接再device上的私有变量void *platform_data; if (!pdata) { dev_err(fbdev->dev, "failed to get platform datan"); ret = -EINVAL; goto err_pdata; } }
(2)s3cfb_set_platdata archarmplat-s5pdevs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24void __init s3cfb_set_platdata(struct s3c_platform_fb *pd) { struct s3c_platform_fb *npd; int i; if (!pd) pd = &default_fb_data; npd = kmemdup(pd, sizeof(struct s3c_platform_fb), GFP_KERNEL); if (!npd) printk(KERN_ERR "%s: no memory for platform datan", __func__); else { for (i = 0; i < npd->nr_wins; i++) npd->nr_buffers[i] = 1; npd->nr_buffers[npd->default_win] = CONFIG_FB_S3C_NR_BUFFERS; s3cfb_get_clk_name(npd->clk_name); npd->clk_on = s3cfb_clk_on; npd->clk_off = s3cfb_clk_off; /* starting physical address of memory region */ npd->pmem_start = s5p_get_media_memory_bank(S5P_MDEV_FIMD, 1); /* size of memory region */ npd->pmem_size = s5p_get_media_memsize_bank(S5P_MDEV_FIMD, 1); s3c_device_fb.dev.platform_data = npd; //设置了platform_data } }
(3)smdkc110_machine_init archarmmach-s5pv210mach-x210.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14static void __init smdkc110_machine_init(void) { /************* 部分省略 **************/ #ifdef CONFIG_FB_S3C_LTE480WV s3cfb_set_platdata(<e480wv_fb_data); #endif #ifdef CONFIG_FB_S3C_EK070TN93 //我们使用的是这款lcd smdkv210_backlight_off(); s3cfb_set_platdata(&ek070tn93_fb_data);//调用函数 #endif }
(4)真正的Platform_data archarmmach-s5pv210mach-x210.c
1
2
3
4
5
6
7
8
9
10
11
12
13static struct s3c_platform_fb ek070tn93_fb_data __initdata = { .hw_ver = 0x62, .nr_wins = 5, .default_win = CONFIG_FB_S3C_DEFAULT_WINDOW, .swap = FB_SWAP_WORD | FB_SWAP_HWORD, .lcd = &ek070tn93, .cfg_gpio = ek070tn93_cfg_gpio, .backlight_on = ek070tn93_backlight_on, .backlight_onoff = ek070tn93_backlight_off, .reset_lcd = ek070tn93_reset_lcd, }; #endif
11.framebuffer驱动分析2
11.1、struct s3cfb_lcd
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
37fbdev->lcd = (struct s3cfb_lcd *)pdata->lcd; static struct s3c_platform_fb ek070tn93_fb_data __initdata = { .hw_ver = 0x62, .nr_wins = 5, .default_win = CONFIG_FB_S3C_DEFAULT_WINDOW, .swap = FB_SWAP_WORD | FB_SWAP_HWORD, .lcd = &ek070tn93, .cfg_gpio = ek070tn93_cfg_gpio, .backlight_on = ek070tn93_backlight_on, .backlight_onoff = ek070tn93_backlight_off, .reset_lcd = ek070tn93_reset_lcd, }; #endif static struct s3cfb_lcd ek070tn93 = { .width = S5PV210_LCD_WIDTH, //1024 .height = S5PV210_LCD_HEIGHT, //600 .bpp = 32, .freq = 60, .timing = { .h_fp = 160, .h_bp = 140, .h_sw = 20, .v_fp = 12, .v_fpe = 1, .v_bp = 20, .v_bpe = 1, .v_sw = 3, }, .polarity = { .rise_vclk = 0, .inv_hsync = 1, .inv_vsync = 1, .inv_vden = 0, }, };
11.2、pdata->cfg_gpio
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
32if (pdata->cfg_gpio) pdata->cfg_gpio(pdev); static void ek070tn93_cfg_gpio(struct platform_device *pdev) { int i; for (i = 0; i < 8; i++) { s3c_gpio_cfgpin(S5PV210_GPF0(i), S3C_GPIO_SFN(2)); //设置CON为0x2 s3c_gpio_setpull(S5PV210_GPF0(i), S3C_GPIO_PULL_NONE); //设置上升 } for (i = 0; i < 8; i++) { s3c_gpio_cfgpin(S5PV210_GPF1(i), S3C_GPIO_SFN(2)); s3c_gpio_setpull(S5PV210_GPF1(i), S3C_GPIO_PULL_NONE); } for (i = 0; i < 8; i++) { s3c_gpio_cfgpin(S5PV210_GPF2(i), S3C_GPIO_SFN(2)); s3c_gpio_setpull(S5PV210_GPF2(i), S3C_GPIO_PULL_NONE); } for (i = 0; i < 4; i++) { s3c_gpio_cfgpin(S5PV210_GPF3(i), S3C_GPIO_SFN(2)); s3c_gpio_setpull(S5PV210_GPF3(i), S3C_GPIO_PULL_NONE); } /* mDNIe SEL: why we shall write 0x2 ? */ writel(0x2, S5P_MDNIE_SEL); /* drive strength to max */ writel(0xffffffff, S5PV210_GPF0_BASE + 0xc); //将强度提升至最大 writel(0xffffffff, S5PV210_GPF1_BASE + 0xc); writel(0xffffffff, S5PV210_GPF2_BASE + 0xc); writel(0x000000ff, S5PV210_GPF3_BASE + 0xc); }
11.3、pdata->clk_on
if (pdata->clk_on) //为空
pdata->clk_on(pdev, &fbdev->clock);
11.4、resource的处理
(1)platform_device中提供resource结构体数组
(2)probe中platform_get_resource取出resource并且按FLAG分头处理
取出资源:
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
45fbdev->regulator = regulator_get(&pdev->dev, "pd"); if (!fbdev->regulator) { dev_err(fbdev->dev, "failed to get regulatorn"); ret = -EINVAL; goto err_regulator; } struct platform_device s3c_device_fb = { .name = "s3cfb", .id = -1, .num_resources = ARRAY_SIZE(s3cfb_resource), .resource = s3cfb_resource, .dev = { .dma_mask = &fb_dma_mask, .coherent_dma_mask = 0xffffffffUL } }; static struct resource s3cfb_resource[] = { [0] = { .start = S5P_PA_LCD, //0xf800 0000 .end = S5P_PA_LCD + S5P_SZ_LCD - 1, //0xf800 0000 - SZ_1M -1 .flags = IORESOURCE_MEM, //0000 0020 }, [1] = { .start = IRQ_LCD1, .end = IRQ_LCD1, .flags = IORESOURCE_IRQ, }, [2] = { .start = IRQ_LCD0, .end = IRQ_LCD0, .flags = IORESOURCE_IRQ, }, };
使用资源:动态分配虚拟内存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15res = 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; }
12.framebuffer驱动分析3
12.1、一些硬件操作
(1)s3cfb_set_vsync_interrupt
(2)s3cfb_set_global_interrupt
12.2、s3cfb_init_global
12.3、向框架注册该fb设备
(1)s3cfb_alloc_framebuffer
(2)s3cfb_register_framebuffer
13.framebuffer驱动分析4
13.1、一些硬件操作
(1)s3cfb_set_clock
(2)s3cfb_set_window
(3)s3cfb_display_on
13.2、驱动中处理中断
(1)platform_get_irq
(2)request_irq
13.3、logo显示
13.4、backlight点亮
14.应用层为何不能设置分辨率
14.1、问题描述
(1)第4节时试图在应用层设置分辨率失败了,原因何在?
(2)定位问题:肯定是驱动的事儿
(3)进一步驱动中定位:ioctl部分的事儿
14.2、fb的ioctl部分
(1)fb是典型的字符设备驱动
(2)ioctl分为2部分,在驱动框架部分和驱动部分各有一半
(3)一路追踪找问题
15.折腾内核的启动logo
15.1、让logo显示在屏幕中央
15.2、自定义内核启动logo
最后
以上就是优秀导师最近收集整理的关于7.framebuffer驱动详解1.framebuffer介绍3.framebuffer应用编程实践24.framebuffer应用编程实践35.framebuffer驱动框架总览6.framebuffer驱动框架分析17.framebuffer驱动框架分析28.framebuffer驱动框架分析39.framebuffer驱动分析110.framebuffer驱动分析111.framebuffer驱动分析2使用资源:动态分配虚拟内存12.framebuffer驱动分析313.framebuf的全部内容,更多相关7内容请搜索靠谱客的其他文章。
发表评论 取消回复