framebuffer驱动分析

framebuffer帧缓冲(简称fb)是linux内核中虚拟出的一个设备,framebuffer向应用层提供一个统一标准接口的显示设备,从驱动来看,fb是一个典型的字符设备,而且创建了一个类/sys/class/graphics,设备文件 /dev/fb0
在应用层中如果要使用的话需要包含头文件 #include <linux/fb.h>然后使用mmap做映射

1、核心层的代码fbmem.c

这个代码是内核实现的,我们只是分析一下,并不需要我们去做什么改动

① 入口函数fbmem_init:

fbmem_init(void)  
{  
    create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);  
    if (register_chrdev(FB_MAJOR,"fb",&fb_fops))  
           printk("unable to get major %d for fb devs\n", FB_MAJOR);  
    fb_class = class_create(THIS_MODULE, "graphics");  
    if (IS_ERR(fb_class)) {  
            printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));  
    fb_class = NULL;  
    }  
return 0;  
}  

fbmem_init里面注册字符设备fb,其主设备号为29.并且创建了类class_create,注意在此没有创建设备节点

② file_operations fb_fops:

static const struct file_operations fb_fops = {
    .owner =    THIS_MODULE,
    .read =     fb_read,
    .write =    fb_write,
    .ioctl =    fb_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl = fb_compat_ioctl,
#endif
    .mmap =     fb_mmap,
    .open =     fb_open,
    .release =  fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
    .get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
    .fsync =    fb_deferred_io_fsync,
#endif
};

我们假设 app: open(“/dev/fb0”, …) 主设备号: 29, 次设备号: 0 //应用程序打开 /dev/fb0,主设备号29 次设备号0;那么就会调用内核中的 fb_open:

fb_open(struct inode *inode, struct file *file)
{
 int fbidx = iminor(inode);     // 得到次设备号 0 
 struct fb_info *info = registered_fb[fbidx(0)];         //fb_info 这个结构体等于registered_fb数组里面的次设备号检索出来。
}

我们假设 app: read() //应用程序read的时候;那么就会调用内核中的 fb_read:

fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
            int fbidx = iminor(inode);//得到次设备号0
            struct fb_info *info = registered_fb[fbidx];//在registered_fb数组里得到一个fb_info 结构体
}

由此可知open read都依赖fb_info结构体,从registered_fb数组中得到fb_info结构体。也就是说内核中主设备号为29的设备可能有很多,open的时候根据次设备号从registered_fb数组得到一个fb_info。

2、注册函数

register_framebuffer(struct fb_info*fb_info)
{
    fb_info->dev = device_create(fb_class, fb_info->device,MKDEV(FB_MAJOR, i), "fb%d", i); //创建设备节点
       registered_fb[i]= fb_info;
}

registered_fb数组在register_framebuffer被设置

现在应该已经可以很清晰看出LCD的框架。首先内核帮助我们实现了一个主设备号为29的设备,此时只创建了类,并没有在类下创建设备节点。 当我们的下层硬件驱动调用注册函数的时候,会初始化registered_fb结构体,并创建设备节点。此时应用程序可以来打开一个设备节点了,比如open(“/dev/fb0”, …),最终会调用到fbmem核心层提供的open函数,这个open函数中根据次设备号,registered_fb数组中取出硬件注册进来的结构体,调用里面的open函数,或者使用一些属性。这样内核可以方便管理类似的设备了。fbmem.c系统实现并抽象出来的,使用的时候依赖于底层框架实现,那么我们来写底层框架实现函数xxxfb.c上层fbmem.c内核已经写好,并完成上层驱动注册。我们要做的是写出硬件部分的函数,来初始化registered_fb:步骤

1.分配一个fb_info结构体: 怎么分配:framebuffer_alloc

2.设置fb_info里面的相关参数

3.注册:register_framebuffer

4.硬件相关的设置

3、底层框架函数将用到的结构体

fb_info 结构体:

fb_info

struct fb_info {  
    int node;/*  序号索引值,/dev/fb0,/dev/fb1  其中0,1 就是从这里获得的*/  
    int flags;  
    struct fb_var_screeninfo var;   /* Current var  可变参数,很重要 */  
    struct fb_fix_screeninfo fix;   /* Current fix  固定参数,很重要 */  
    struct fb_monspecs monspecs;    /* Current Monitor specs */  
    struct work_struct queue;   /* Framebuffer event queue */  
    struct fb_pixmap pixmap;    /* Image hardware mapper */  
    struct fb_pixmap sprite;    /* Cursor hardware mapper */  
    struct fb_cmap cmap;        /* Current cmap */  
    struct list_head modelist;      /* mode list */  
    struct fb_videomode *mode;  /* current mode */  

#ifdef CONFIG_FB_BACKLIGHT  
    /* assigned backlight device */  
    /* set before framebuffer registration,  
       remove after unregister */  
    struct backlight_device *bl_dev;  
    /* Backlight level curve */  
    struct mutex bl_curve_mutex;      
    u8 bl_curve[FB_BACKLIGHT_LEVELS];  
#endif  
#ifdef CONFIG_FB_DEFERRED_IO  
    struct delayed_work deferred_work;  
    struct fb_deferred_io *fbdefio;  
#endif  
    struct fb_ops *fbops;/* fb_ops,各种帧缓冲操作函数,很重要 */  
    struct device *device;      /* This is the parent */  
    struct device *dev;     /* This is this fb device */  
    int class_flag;                    /* private sysfs flags */  
#ifdef CONFIG_FB_TILEBLITTING  
    struct fb_tile_ops *tileops;    /* Tile Blitting */  
#endif  
    char __iomem *screen_base;  /* Virtual address  "显存“的基地址 */  
    unsigned long screen_size;  /* Amount of ioremapped VRAM or 0 ”显存“的大小,重要 */   
    void *pseudo_palette;       /* Fake palette of 16 colors */ /* 16位假的调色板,重要 */   
#define FBINFO_STATE_RUNNING    0  
#define FBINFO_STATE_SUSPENDED  1  
    u32 state;          /* Hardware state i.e suspend */  
    void *fbcon_par;                /* fbcon use-only private area */  
    /* From here on everything is device dependent */  
    void *par;   /* 这个用来存放私有数据 */  
};  


将用到下面6个结构体:

struct fb_var_screeninfo var; /*Current var 可变参数,很重要 * /
struct fb_fix_screeninfo fix; /* Current fix 固定参数,很重要 */
struct fb_ops fbops;/ fb_ops,各种帧缓冲操作函数,很重要 */
char __iomem screen_base; / Virtual address “显存“的基地址 */
unsigned long screen_size; /* Amount of ioremapped VRAM or 0 ”显存“的大小,重要 */
void pseudo_palette; / Fake palette of 16 colors / / 16位假的调色板,重要 */

fb_var_screeninfo 结构体:

fb_info

struct fb_var_screeninfo {  
    __u32 xres;         /* visible resolution       */  
    __u32 yres;  
    __u32 xres_virtual;     /* virtual resolution       */  
    __u32 yres_virtual;  
    __u32 xoffset;          /* offset from virtual to visible */  
    __u32 yoffset;          /* resolution           */  

    __u32 bits_per_pixel;       /* guess what           */  
    __u32 grayscale;        /* != 0 Graylevels instead of colors */  

    struct fb_bitfield red;     /* bitfield in fb mem if true color, */  
    struct fb_bitfield green;   /* else only length is significant */  
    struct fb_bitfield blue;  
    struct fb_bitfield transp;  /* transparency         */    

    __u32 nonstd;           /* != 0 Non standard pixel format */  

    __u32 activate;         /* see FB_ACTIVATE_*        */  

    __u32 height;           /* height of picture in mm    */  
    __u32 width;            /* width of picture in mm     */  

    __u32 accel_flags;      /* (OBSOLETE) see fb_info.flags */  

    /* Timing: All values in pixclocks, except pixclock (of course) */  
    __u32 pixclock;         /* pixel clock in ps (pico seconds) */  
    __u32 left_margin;      /* time from sync to picture    */  
    __u32 right_margin;     /* time from picture to sync    */  
    __u32 upper_margin;     /* time from sync to picture    */  
    __u32 lower_margin;  
    __u32 hsync_len;        /* length of horizontal sync    */  
    __u32 vsync_len;        /* length of vertical sync  */  
    __u32 sync;         /* see FB_SYNC_*        */  
    __u32 vmode;            /* see FB_VMODE_*       */  
    __u32 rotate;           /* angle we rotate counter clockwise */  
    __u32 reserved[5];      /* Reserved for future compatibility */  
};  

fb_fix_screeninfo fix结构体:

fb_info

struct fb_fix_screeninfo {  
    char id[16];            /* identification string eg "TT Builtin" */  
    unsigned long smem_start;   /* Start of frame buffer mem */  
                    /* (physical address) */  
    __u32 smem_len;         /* Length of frame buffer mem */  
    __u32 type;         /* see FB_TYPE_*        */  
    __u32 type_aux;         /* Interleave for interleaved Planes */  
    __u32 visual;           /* see FB_VISUAL_*      */   
    __u16 xpanstep;         /* zero if no hardware panning  */  
    __u16 ypanstep;         /* zero if no hardware panning  */  
    __u16 ywrapstep;        /* zero if no hardware ywrap    */  
    __u32 line_length;      /* length of a line in bytes    */  
    unsigned long mmio_start;   /* Start of Memory Mapped I/O   */  
                    /* (physical address) */  
    __u32 mmio_len;         /* Length of Memory Mapped I/O  */  
    __u32 accel;            /* Indicate to driver which */  
                    /*  specific chip/card we have  */  
    __u16 reserved[3];      /* Reserved for future compatibility */  
};

fb_ops 结构体

fb_info

struct fb_ops {
    struct module *owner;
    /* 打开/释放 */
    int (*fb_open)(struct fb_info *info, int user);
    int (*fb_release)(struct fb_info *info, int user);
    /* 对于非线性布局的/常规内存映射无法工作的帧缓冲设备需要 */
        ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
                   size_t count, loff_t *ppos);
        ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
                    size_t count, loff_t *ppos);
    /* 检测可变参数,并调整到支持的值*/
    int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
    /* 根据 info->var 设置 video 模式 */
    int (*fb_set_par)(struct fb_info *info);
    /* 设置 color 寄存器 */
    int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
                unsigned blue, unsigned transp, struct fb_info *info);
    /* 批量设置 color 寄存器,设置颜色表 */
    int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
    /*显示空白 */
    int (*fb_blank)(int blank, struct fb_info *info);
    /* pan 显示 */
    int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
    /* 矩形填充 */
    void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
    /* 数据复制 */
    void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
    /* 图形填充 */
    void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
    /* 绘制光标 */
    int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
    /* 旋转显示 */
    void (*fb_rotate)(struct fb_info *info, int angle);
    /* 等待 blit 空闲 (可选) */
    int (*fb_sync)(struct fb_info *info);
    /* fb 特定的 ioctl (可选) */
    int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
            unsigned long arg);
    /* 处理 32 位的 compat ioctl (可选) */
    int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
            unsigned long arg);
     /* fb 特定的 mmap */
    int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
    /* 保存目前的硬件状态 */
    void (*fb_save_state)(struct fb_info *info);
    /* 恢复被保存的硬件状态 */
    void (*fb_restore_state)(struct fb_info *info);
    /* get capability given var */
    void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
                struct fb_var_screeninfo *var);
};

3、注册驱动时要做的事

先定义好各个结构体,framebufferUI使用platform总线注册,注册好device和driver,然后在probe函数中去填充好各个结构体,然后再分别去实现各个file_operations中的各个函数。最后注销

Last modification:November 18th, 2019 at 09:01 pm
如果觉得我的文章对你有用,请随意赞赏

Leave a Comment

One comment

  1. myls Google Chrome 78.0.3904.108 Windows 7 中国 广西 桂林

    免费快递单号、淘宝快递单号、空包www.01kd.com