七.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提供一些硬件描述信息的
//

posted @ 2017-09-29 15:22  bkycrmn  阅读(857)  评论(0)    收藏  举报