Linux驱动开发(9)——- framebuffer驱动详解

目录

  • 一,framebuffer介绍
  • 二,framebuffer驱动源码分析
    • 1.framebuffer驱动框架总览
    • 2.framebuffer驱动框架分析
    • 3.framebuffer驱动分析
  • 三,framebuffer应用编程实践

一,framebuffer介绍


1、什么是framebuffer
(1)很多人都会说操纵lcd显示就是操纵framebuffer,表面上来看是这样的。实际上是frambuffer就是linux内核驱动申请的一片内存空间,然后lcd内有一片sram,cpu内部有个lcd控制器,它有个单独的dma用来将frambuffer中的数据拷贝到lcd的sram中去 拷贝到lcd的sram中的数据就会显示在lcd上,LCD驱动和framebuffer驱动没有必然的联系,它只是驱动LCD正常工作的,比如有信号传过来,那么LCD驱动负责把信号转成显示屏上的内容,至于什么内容这就是应用层要处理的。
(2)framebuffer帧缓冲(简称fb)是linux内核中虚拟出的一个设备
(3)framebuffer向应用层提供一个统一标准接口的显示设备
(4)从驱动来看,fb是一个典型的字符设备,而且创建了一个类/sys/class/graphics

2、帧缓冲设备驱动的结构
在这里插入图片描述
3、framebuffer的使用步骤
(1)打开设备文件 /dev/fb0
(2)获取当前设备信息 #include (3)mmap做映射
(4)填充framebuffer


二,framebuffer驱动源码分析



1.framebuffer驱动框架总览


1、驱动框架部分

  • drivers/video/fbmem.c主要任务:fbmen_init()函数负责创建graphics类、注册FB的字符设备驱动、register_framebuffer()函数提供接口给具体framebuffer驱动编写着来注册fb设备。本文件相对于fb来说,地位和作用和misc.c文件相对于杂散类设备来说一样的,结构和分析方法也是类似的。
  • drivers/video/fbsys.c这个文件是处理fb在/sys目录下的一些属性文件的
  • drivers/video/modedb.c这个文件是管理显示模式(譬如VGA、720P等就是显示模式)的。
  • drivers/video/fb_notify.c这个文件是frame buff用来管理相关通知的

2、驱动部分

  • drivers/video/samsung/s3cfb.c驱动主体
  • drivers/video/samsung/s3cfb_fimd6x.c里面有很多LCD硬件操作的函数
  • arch/arm/mach-s5pv210/mach-x210.c负责提供platform_device的
  • arch/arm/plat-s5p/devs.c为platform_device提供一些硬件描述信息的

3、如何分析
(1)经验
(2)分析menuconfig、Makefile、Kconfig等
(3)内核编译后检查编译结果中的.o文件


2.framebuffer驱动框架分析


1、fbmem_init函数
(1)#ifdef MODULE

在这里插入图片描述
(2)fb_proc_fops和fb在proc文件系统中的表现

在这里插入图片描述

(3)register_chrdev注册fb设备
(4)class_create创建graphics类
(5)fbmem_exit的对应
在这里插入图片描述

2、fb_fops
(1)read/write/mmap/ioctl
(2)registered_fb和num_registered_fb
(3)struct fb_info
在这里插入图片描述

3、register_framebuffer和unregister_framebuffer

在这里插入图片描述


3.framebuffer驱动分析


1、s3cfb.c

在这里插入图片描述

2、s3c_device_fb

在这里插入图片描述

3、probe函数分析
(1)struct s3c_platform_fb这个结构体是fb的platform_data结构体,这个结构体变量就是platform设备的私有数据,这个数据在platform_device.device.platform_data中存储。在mach文件中去准备并填充这些数据,在probe函数中通过传参的platform_device指针取出来。
(2)struct s3cfb_global这个结构体主要作用是在驱动部分的2个文件(s3cfb.c和s3cfb_fimd6x.c)的函数中做数据传递用的
在这里插入图片描述

4、
在这里插入图片描述
在这里插入图片描述

5、

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

三,framebuffer应用编程实践

实验步骤

1、打开设备
2、获取设备信息
(1)不可变信息FSCREENINFO,使用ioctl的FBIOGET_FSCREENINFO名
(2)可变信息VSCREENINFO,使用ioctl的FBIOGET_VSCREENINFO名

在这里插入图片描述

3、mmap做映射
做完了mmap后fb在当前进程中就已经就绪了,随时可以去读写LCD显示器了。

4、fb显示之刷背景和画横线

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
#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       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;
    }
    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);

   
    // 第3步:进行mmap
    unsigned long len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel / 8;
    printf("len = %ld\n", len);
    pfb = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (NULL == pfb)
    {
        perror("mmap");
        return -1;
    }
    printf("pfb = %p.\n", pfb);
   
    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;
    }
}