我是靠谱客的博主 优秀导师,这篇文章主要介绍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,现在分享给大家,希望可以做个参考。

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
12
struct fb_cmap { __u32 start; /* 颜色板的第一个元素的入口地址 */ __u32 len; /* 元素的个数 */ __u16 *red; /* 表示红色分量的值 */ __u16 *green; __u16 *blue; __u16 *transp; /* 透明度分量的值, can be NULL */ };

 

 

4. fb_var_screeninfo

fb_var_screeninfo结构体中存储了用户可以修改的显示控制器参数,例如屏幕分辨率、每个像素的比特数、透明度等。

  1. 该结构体中有几个重要成员需要注意。
  2. xres表示屏幕一行有多少个像素点。
  3. yres表示屏幕一列有多少个像素点。
  4. bits_per_pixel表示每个像素点占用多少个字节。

fb_var_screeninfo结构体的定义如下:

 

5.fb_fix_screeninfo

fb_fix_screeninfo结构体中,记录了用户不能修改的固定显示控制器参数。这些固定参数如缓冲区的物理地址、缓冲区的长度、显示色彩模式、内存映射的开始位置等。

  1. 需要注意的是,
  2. 第07行的visual表示屏幕使用的色彩模式,在Linux下,支持多种色彩模式。
  3. 第11行,表示显存中一行占用的内存字节数,具体占用多少字节由显示模式来决定。
  4. 第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
31
struct 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
35
struct 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
7
struct 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
14
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; 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
24
void __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
14
static void __init smdkc110_machine_init(void) { /************* 部分省略 **************/ #ifdef CONFIG_FB_S3C_LTE480WV s3cfb_set_platdata(&lte480wv_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
13
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


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
37
fbdev->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
32
if (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
45
fbdev->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
15
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; }


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内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(85)

评论列表共有 0 条评论

立即
投稿
返回
顶部