七.framebuffer驱动详解
5.7.1.framebuffer介绍
//驱动是造车,应用是开车。开发板内部已有驱动。
5.7.1.1、什么是framebuffer
(1)裸机中如何操作LCD
//图291 
(2)OS下操作LCD的难点
//与裸机时类似,区别是有OS时干活的成有两段(两大部分)代码:
内核部分--做初始化寄存器、内存,建立让DDR显存与LCD建立映射关系
应用部分--做和LCD屏幕显示具体内容的操作(显示的东西丢到显存里去让对应的LCD显示;申请内存的等)
DDR显存与LCD的两部分不同的虚拟地址(驱动里的显存和应用里的显存)却对应同一段物理地址应用里的显存可以读写、驱动里的显存也可以同步操作,至这一段物理内存。这样做提升效率!framebuffer由此诞生。。。

(3)framebuffer帧缓冲(简称fb)是linux内核中虚拟(软件层面用代码构建)出的一个设备
//LCD显示领域里的一帧数据就是一屏数据
(4)framebuffer向应用层提供一个统一标准接口的显示设备
//向应用层屏蔽了驱动层的一些细节;驱动层把复杂困难和细节留给自己,把简单的留给应用层,应用层只需拿驱动层提供好的统一的接口去操作即可。
(5)从驱动来看,fb是一个典型的字符设备,而且创建了一个类/sys/class/graphics
//[root@localhost ~]# ls /sys/class/graphics/
fb0 fbcon
[root@localhost ~]# ls /dev/fb* -l
lrwxrwxrwx. 1 root root 3 9月 19 10:44 /dev/fb -> fb0
crw-rw----. 1 root video 29, 0 9月 19 10:45 /dev/fb0
5.7.1.2、framebuffer的使用
(1)设备文件 /dev/fb0
(2)获取设备信息 #include <linux/fb.h>
(3)mmap做映射
//两个LCD应用进程会出现叠加、覆盖现象。
(4)填充framebuffer
5.7.2.framebuffer应用编程实践1
5.7.2.1、打开设备
5.7.2.2、获取设备信息
(1)不可变信息FSCREENINFO,使用ioctl的FBIOGET_FSCREENINFO名
(2)可变信息VSCREENINFO,使用ioctl的FBIOGET_VSCREENINFO名
//[root@localhost ~]# vim /linux-3.5/include/linux/fb.h
图293
//161 struct fb_fix_screeninfo { //不可变信息,应用程序没法设置它,偶尔读出来查阅!
162 char id[16]; /* identification string eg "TT Bui ltin" */
//framebuffer在显存中的物理地址:
163 unsigned long smem_start; /* Start of frame buffer mem */
164 /* (physical address) */
165 __u32 smem_len; /* Length of frame buffer mem */
166 __u32 type; /* see FB_TYPE_* */
167 __u32 type_aux; /* Interleave for interleaved Plane s */
168 __u32 visual; /* see FB_VISUAL_* */
169 __u16 xpanstep; /* zero if no hardware panning */
170 __u16 ypanstep; /* zero if no hardware panning */
171 __u16 ywrapstep; /* zero if no hardware ywrap */
172 __u32 line_length; /* length of a line in bytes */
173 unsigned long mmio_start; /* Start of Memory Mapped I/O */
174 /* (physical address) */
175 __u32 mmio_len; /* Length of Memory Mapped I/O */
176 __u32 accel; /* Indicate to driver which */
177 /* specific chip/card we have */
178 __u16 capabilities; /* see FB_CAP_* */
179 __u16 reserved[2]; /* Reserved for future compatibilit y */
180 };
//
245 struct fb_var_screeninfo { //可变信息,应用程序可以设置它,较多的可关注。
246 __u32 xres;//可视分辨率 /* visible resolution */
247 __u32 yres;
248 __u32 xres_virtual;//虚拟分辨率 /* virtual resolution */
249 __u32 yres_virtual;
250 __u32 xoffset;//参考点坐标 /* offset from virtual to visible */
251 __u32 yoffset; /* resolution */
252
253 __u32 bits_per_pixel;//bpp /* guess what */
254 __u32 grayscale;//灰度级图 /* 0 = color, 1 = grayscale, */
255 /* >1 = FOURCC */
256 struct fb_bitfield red;//描述红色/* bitfield in fb mem if true color, */
257 struct fb_bitfield green;//描述绿色/* else only length is significant */
258 struct fb_bitfield blue;//描述蓝色
259 struct fb_bitfield transp;//描述透明度/* transparency */
260
261 __u32 nonstd; /* != 0 Non standard pixel format */
262
263 __u32 activate; /* see FB_ACTIVATE_* */
264
265 __u32 height;//物理尺寸大小 /* height of picture in mm */
266 __u32 width; /* width of picture in mm */
267
268 __u32 accel_flags; /* (OBSOLETE) see fb_info.flags */
270 /* Timing: All values in pixclocks, except pixclock (of course) */
271 __u32 pixclock;//像素时钟 /* pixel clock in ps (pico seconds) */
272 __u32 left_margin;//初始化时序要用 /* time from sync to picture */
273 __u32 right_margin; /* time from picture to sync */
274 __u32 upper_margin; /* time from sync to picture */
275 __u32 lower_margin;
276 __u32 hsync_len; /* length of horizontal sync */
277 __u32 vsync_len; /* length of vertical sync */
278 __u32 sync; /* see FB_SYNC_* */
279 __u32 vmode; /* see FB_VMODE_* */
280 __u32 rotate; /* angle we rotate counter clockwise */
281 __u32 colorspace; /* colorspace for FOURCC-based modes */
282 __u32 reserved[4]; /* Reserved for future compatibility */
283 };
//图294
5.7.3.framebuffer应用编程实践2
5.7.3.1、mmap做映射
做完了mmap后fb在当前进程中就已经就绪了,随时可以去读写LCD显示器了。
5.7.3.2、fb显示之刷背景
5.7.4.framebuffer应用编程实践3
5.7.4.1、设置分辨率
(1)实验失败,实验结果是只能修改虚拟分辨率,不能修改可视分辨率。原因要去驱动里找。
(2)正确的做法是在驱动中去修改参数,然后重新编译运行,才能解决。
5.7.4.2、写字、画线、图片显示等在此适用。
//appfb.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/ioctl.h> #include <sys/mman.h> // 宏定义 #define FBDEVICE "/dev/fb0" // 旧开发板 //#define WIDTH 800 //#define HEIGHT 480 // 新开发板 #define WIDTH 1024 #define HEIGHT 600 #define WHITE 0xffffffff // test ok #define BLACK 0x00000000 #define RED 0xffff0000 #define GREEN 0xff00ff00 // test ok #define BLUE 0xff0000ff #define GREENP 0x0000ff00 // 一样,说明前2个ff透明位不起作用 // 函数声明 void draw_back(unsigned int width, unsigned int height, unsigned int color); void draw_line(unsigned int color); // 全局变量 unsigned int *pfb = NULL; int main(void) { int fd = -1, ret = -1; struct fb_fix_screeninfo finfo = {0}; struct fb_var_screeninfo vinfo = {0}; // 第1步:打开设备 fd = open(FBDEVICE, O_RDWR); if (fd < 0) { perror("open"); return -1; } printf("open %s success.\n", FBDEVICE); // 第2步:获取设备的硬件信息 ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo); if (ret < 0) { perror("ioctl"); return -1; } //framebuffer在显存中的物理地址: printf("smem_start = 0x%x, smem_len = %u.\n", finfo.smem_start, finfo.smem_len); ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo); if (ret < 0) { perror("ioctl"); return -1; } printf("xres = %u, yres = %u.\n", vinfo.xres, vinfo.yres);//可视分辨率 printf("xres_virtual = %u, yres_virtual = %u.\n", vinfo.xres_virtual, vinfo.yres_virtual);//虚拟分辨率 printf("bpp = %u.\n", vinfo.bits_per_pixel);//bpp //5.7.4.framebuffer应用编程实践3 //5.7.4.1、设置分辨率 // 尝试修改驱动中屏幕的分辨率 vinfo.xres = 1024; vinfo.yres = 600; vinfo.xres_virtual = 1024; vinfo.yres_virtual = 1200; ret = ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo); if (ret < 0) { perror("ioctl"); return -1; } // 再次读出来检验一下 ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo); if (ret < 0) { perror("ioctl"); return -1; } printf("修改过之后的参数:\n"); printf("xres = %u, yres = %u.\n", vinfo.xres, vinfo.yres);//修改分辨率失败! printf("xres_virtual = %u, yres_virtual = %u.\n", vinfo.xres_virtual, vinfo.yres_virtual);//可以修改! printf("bpp = %u.\n", vinfo.bits_per_pixel); unsigned long len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel / 8; printf("len = %ld\n", len); // 第3步:进行mmap //5.7.3.framebuffer应用编程实践2 //5.7.3.2、fb显示之刷背景 pfb = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (NULL == pfb) { perror("mmap"); return -1; } printf("pfb = %p.\n", pfb);//当前进程的地址空间的相对应的framebuffer的显示缓冲区 //4个字节表示一个像素(怎么表示呢?RGB),将每个像素的内容写进缓冲区中去 draw_back(WIDTH, HEIGHT, WHITE); draw_line(RED); close(fd); return 0; } //刷背景函数 void draw_back(unsigned int width, unsigned int height, unsigned int color) { unsigned int x, y; for (y=0; y<height; y++) { for (x=0; x<width; x++) { *(pfb + y * WIDTH + x) = color; } } } void draw_line(unsigned int color)//举例:画线函数测试一下! { unsigned int x, y; for (x=50; x<600; x++) { *(pfb + 200 * WIDTH + x) = color; } }
5.7.5.framebuffer驱动框架总览
5.7.5.1、驱动框架部分:
//内核开发人员编写,我们需要看懂。
(1)drivers/video/fbmem.c。//重要!牵扯出其他三个
主要任务:1、创建graphics类、注册FB的字符设备驱动、提供register_framebuffer接口给具体framebuffer驱动编写着来注册fb设备的。本文件相对于fb来说,地位和作用和misc.c文件相对于杂散类设备来说一样的,结构和分析方法也是类似的。
(2)drivers/video/fbsys.c。这个文件是处理fb在/sys目录下的一些属性文件的。
//[root@localhost fb0]# ls
bits_per_pixel console device name rotate subsystem
blank cursor mode pan state uevent
bl_curve dev modes power stride virtual_size
(3)drivers/video/modedb.c。这个文件是管理显示模式(譬如VGA、720P等就是显示模式)的
(4)drivers/video/fb_notify.c //某个fb添加到链表后内核进行通知
//drivers/video/fbmem.c
1799 static int __init fbmem_init(void) //1
1801 {
1802 proc_create("fb", 0, NULL, &fb_proc_fops); //
1803
1804 if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) //
1805 printk("unable to get major %d for fb devs\n", FB_MAJOR);
1806
1807 fb_class = class_create(THIS_MODULE, "graphics"); //
1808 if (IS_ERR(fb_class)) {
1809 printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class ));
1810 fb_class = NULL;
1811 }
1812 return 0;
1813 }
[root@localhost ~]# cd /sys/class/graphics/ //eg:centos
[root@localhost graphics]# ls
fb0 fbcon
[root@localhost graphics]# cd fb0/
[root@localhost fb0]# ls
bits_per_pixel console device name rotate subsystem
blank cursor mode pan state uevent
bl_curve dev modes power stride virtual_size
[root@localhost fb0]# cat bits_per_pixel
32
[root@localhost fb0]# cat /proc/fb
0 svgadrmfb //次设备号 设备名
1593 static int do_register_framebuffer(struct fb_info *fb_info) //2
1594 {
1595 int i;
1596 struct fb_event event;
1597 struct fb_videomode mode;
1598
1599 if (fb_check_foreignness(fb_info))
1600 return -ENOSYS;
1601
1602 do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
1603 fb_is_primary_device(fb_info));
1604
1605 if (num_registered_fb == FB_MAX)
1606 return -ENXIO;
1607
1608 num_registered_fb++;
1609 for (i = 0 ; i < FB_MAX; i++)
1610 if (!registered_fb[i])
1611 break;
1612 fb_info->node = i;
1613 atomic_set(&fb_info->count, 1);
1614 mutex_init(&fb_info->lock);
1615 mutex_init(&fb_info->mm_lock);
1616
1617 fb_info->dev = device_create(fb_class, fb_info->device,
1618 MKDEV(FB_MAJOR, i), NULL, "fb%d", i);//
5.7.5.2、驱动部分:
//具体驱动工程师做移植到开发板时可能需要编写。
(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提供一些硬件描述信息的
//
浙公网安备 33010602011771号