Jimmy Chen

A Programmer

(转载)Framebuffer驱动程序分析

  FrameBuffer通常作为LCD控制器或者其他显示设备的驱动,FrameBuffer驱动是一个字符设备,设备节点是/dev/fbX,主设备号为29,次设备号递增,用户可以将Framebuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由Framebuffer设备驱动来完成的。Framebuffer设备为上层应用程序提供系统调用,也为下一层的特定硬件驱动提供接口;那些底层硬件驱动需要用到这儿的接口来向系统内核注册它们自己。

《(转载)Framebuffer驱动程序分析》

  Linux中的PCI设备可以将其控制寄存器映射到物理内存空间,而后,对这些控制寄存器的访问变成了对物理内存的访问,因此,这些寄存器又被称为”memio”。一旦被映射到物理内存,Linux的普通进程就可以通过mmap将这些内存I/O映射到进程地址空间,这样就可以直接访问这些寄存器了。

  FrameBuffer设备属于字符设备,采用了文件层—驱动层的接口方式,Linux为帧缓冲设备定义了驱动层的接口fb_info结构,在文件层上,用户调用file_operations的函数操作,间接调用fb_info中的fb_ops函数集来操作硬件。

Framebuffer数据结构

kernel\include\linux\fb.h

  fb_info是Linux为帧缓冲设备定义的驱动层接口。它不仅包含了底层函数,而且还有记录设备状态的数据。每个帧缓冲设备都与一个fb_info结构相对应。

struct fb_info {
    atomic_t count;
    int node;  /*一个FrameBuffer设备的次设备号*/
    int flags;
    struct mutex lock;      /* Lock for open/release/ioctl funcs */
    struct mutex mm_lock;       /* Lock for fb_mmap and smem_* fields */
    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
    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;
    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 */ 
#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 */
    void *par;
    struct apertures_struct {
        unsigned int count;
        struct aperture {
            resource_size_t base;
            resource_size_t size;
        } ranges[0];
    } *apertures;
};

fb_var_screeninfo:用于记录用户可修改的显示控制器参数,包括屏幕分辨率、每个像素点的比特数等

struct fb_var_screeninfo {  
    __u32 xres;         /* 行可见像素*/  
    __u32 yres;         /* 列可见像素*/  
    __u32 xres_virtual; /* 行虚拟像素*/  
    __u32 yres_virtual; /* 列虚拟像素*/  
    __u32 xoffset;      /* 水平偏移量*/  
    __u32 yoffset;      /* 垂直偏移量*/  
    __u32 bits_per_pixel;/*每个像素所占bit位数*/  
    __u32 grayscale;    /* 灰色刻度*/  
    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;           /* 图像高度*/  
    __u32 width;            /* 图像宽度*/  
    __u32 accel_flags;      /* (OBSOLETE) see fb_info.flags */  
    __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:记录了用户不能修改的显示控制器的参数,这些参数是在驱动初始化时设置的

struct fb_fix_screeninfo {  
    char id[16];            /* identification string eg "TT Builtin" */  
    unsigned long smem_start;/* Start of frame buffer mem */  
    __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   */  
    __u32 mmio_len;         /* Length of Memory Mapped I/O  */  
    __u32 accel;            /* Indicate to driver which */  
    __u16 reserved[3];      /* Reserved for future compatibility */  
};  

fb_ops是提供给底层设备驱动的一个接口。当我们编写一个FrameBuffer的时候,就要依照Linux FrameBuffer编程的套路,填写fb_ops结构体。

struct fb_ops {  
    /* open/release and usage marking */  
    struct module *owner;  
    int (*fb_open)(struct fb_info *info, int user);  
    int (*fb_release)(struct fb_info *info, int user);  
  
    /* For framebuffers with strange non linear layouts or that do not 
     * work with normal memory mapped access 
     */  
    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);  
  
    /* checks var and eventually tweaks it to something supported, 
     * DO NOT MODIFY PAR */  
    int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);  
  
    /* set the video mode according to info->var */  
    int (*fb_set_par)(struct fb_info *info);  
  
    /* set color register */  
    int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,  
                unsigned blue, unsigned transp, struct fb_info *info);  
  
    /* set color registers in batch */  
    int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);  
  
    /* blank display */  
    int (*fb_blank)(int blank, struct fb_info *info);  
  
    /* pan display */  
    int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);  
  
    /* Draws a rectangle */  
    void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);  
    /* Copy data from area to another */  
    void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);  
    /* Draws a image to the display */  
    void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);  
  
    /* Draws cursor */  
    int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);  
  
    /* Rotates the display */  
    void (*fb_rotate)(struct fb_info *info, int angle);  
  
    /* wait for blit idle, optional */  
    int (*fb_sync)(struct fb_info *info);  
  
    /* perform fb specific ioctl (optional) */  
    int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,  
            unsigned long arg);  
  
    /* Handle 32bit compat ioctl (optional) */  
    int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,  
            unsigned long arg);  
  
    /* perform fb specific mmap */  
    int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);  
  
    /* get capability given var */  
    void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,  
                struct fb_var_screeninfo *var);  
  
    /* teardown any resources to do with this framebuffer */  
    void (*fb_destroy)(struct fb_info *info);  
  
    /* called at KDB enter and leave time to prepare the console */  
    int (*fb_debug_enter)(struct fb_info *info);  
    int (*fb_debug_leave)(struct fb_info *info);  
};  

《(转载)Framebuffer驱动程序分析》

Framebuffer模块初始化过程

  FrameBuffer驱动是以模块的形式注册到系统中,在模块初始化时,创建FrameBuffer对应的设备文件及proc文件,并注册FrameBuffer设备操作接口函数。

kernel\drivers\video\Fbmem.c

module_init(fbmem_init);  
static int __init fbmem_init(void)  
{  
  //在proc文件系统中创建/proc/fb文件,并注册proc接口函数  
    proc_create("fb", 0, NULL, &fb_proc_fops);  
  //注册字符设备fb,并注册fb设备文件的操作接口函数,主设备号为29,  
  //#define FB_MAJOR        29    
  if (register_chrdev(FB_MAJOR,"fb",&fb_fops))  
        printk("unable to get major %d for fb devs\n", FB_MAJOR);  
    //创建sys/class/graphics目录  
    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;  
} 

首先在proc文件系统中创建fb文件,同时注册操作该文件的接口函数:

static const struct file_operations fb_proc_fops = {  
    .owner      = THIS_MODULE,  
    .open       = proc_fb_open,  
    .read       = seq_read,  
    .llseek     = seq_lseek,  
    .release    = seq_release,  
}; 

因此可以对/proc/fb文件进行打开,读写操作。然后注册一个主设备号为29的字符设备,fbmem_init函数中注册了字符设备的文件操作接口函数fb_fops,定义如下:

static const struct file_operations fb_fops = {  
    .owner =THIS_MODULE,  
    .read = fb_read,  
    .write = fb_write,  
    .unlocked_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  
    .llseek =default_llseek,  
};  

Framebuffer驱动注册过程

变量定义:

//保存注册的所有Framebuffer驱动  
extern struct fb_info *registered_fb[FB_MAX];  
//已注册的Framebuffer驱动的个数  
extern int num_registered_fb; 

任何一个特定硬件Framebuffer驱动在初始化时都必须向fbmem.c注册,FrameBuffer模块提供了驱动注册接口函数register_framebuffer:

int register_framebuffer(struct fb_info *fb_info)  
{  
    int ret;  
    mutex_lock(istration_lock);  
    ret = do_register_framebuffer(fb_info);  
    mutex_unlock(istration_lock);  
    return ret;  
}  

参数fb_info描述特定硬件的FrameBuffer驱动信息

static int do_register_framebuffer(struct fb_info *fb_info)  
{  
    int i;  
    struct fb_event event;  
    struct fb_videomode mode;  
    if (fb_check_foreignness(fb_info))  
        return -ENOSYS;  
    //根据当前注册的fb_info的apertures属性从FrameBuffer驱动数组registered_fb中查询是否存在冲突  
    do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,  
                     fb_is_primary_device(fb_info));  
    //判断已注册的驱动是否超过32个FrameBuffer驱动  
    if (num_registered_fb == FB_MAX)  
        return -ENXIO;  
    //增加已注册的驱动个数  
    num_registered_fb++;  
    //从数组registered_fb中查找空闲元素,用于存储当前注册的fb_info  
    for (i = 0 ; i < FB_MAX; i++)  
        if (!registered_fb[i])  
            break;  
    //将当前注册的fb_info在数组registered_fb中的索引位置保存到fb_info->node  
    fb_info->node = i;  
    //初始化当前注册的fb_info的成员信息  
    atomic_set(&fb_info->count, 1);  
    mutex_init(&fb_info->lock);  
    mutex_init(&fb_info->mm_lock);  
    //在/dev目录下创建一个fbx的设备文件,次设备号就是该fb_info在数组registered_fb中的索引  
    fb_info->dev = device_create(fb_class, fb_info->device,MKDEV(FB_MAJOR, i), NULL, "fb%d", i);  
    if (IS_ERR(fb_info->dev)) {  
        printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));  
        fb_info->dev = NULL;  
    } else  
        //初始化fb_info  
        fb_init_device(fb_info);  
    if (fb_info->pixmap.addr == NULL) {  
        fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);  
        if (fb_info->pixmap.addr) {  
            fb_info->pixmap.size = FBPIXMAPSIZE;  
            fb_info->pixmap.buf_align = 1;  
            fb_info->pixmap.scan_align = 1;  
            fb_info->pixmap.access_align = 32;  
            fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;  
        }  
    }     
    fb_info->pixmap.offset = 0;  
    if (!fb_info->pixmap.blit_x)  
        fb_info->pixmap.blit_x = ~(u32)0;  
    if (!fb_info->pixmap.blit_y)  
        fb_info->pixmap.blit_y = ~(u32)0;  
    if (!fb_info->modelist.prev || !fb_info->modelist.next)  
        INIT_LIST_HEAD(&fb_info->modelist);  
    fb_var_to_videomode(&mode, &fb_info->var);  
    fb_add_videomode(&mode, &fb_info->modelist);  
    //将特定硬件对应的fb_info注册到registered_fb数组中  
    registered_fb[i] = fb_info;  
    event.info = fb_info;  
    if (!lock_fb_info(fb_info))  
        return -ENODEV;  
    //使用Linux事件通知机制发送一个FrameBuffer注册事件FB_EVENT_FB_REGISTERED  
    fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);  
    unlock_fb_info(fb_info);  
    return 0;  
}  

  注册过程就是将指定的设备驱动信息fb_info存放到registered_fb数组中。因此在注册具体的fb_info时,首先要构造一个fb_info数据结构,并初始化该数据结构,该结构用于描述一个特定的FrameBuffer驱动。

fbX设备文件的打开过程

open(“/dev/fb0”)打开设备文件fb0对应的操作过程如下:

static int fb_open(struct inode *inode, struct file *file)  
__acquires(&info->lock)  
__releases(&info->lock)  
{  
    //从文件节点中取得次设备号  
    int fbidx = iminor(inode);  
    struct fb_info *info;  
    int res = 0;  
    //根据次设备号从registered_fb数组中取出对应的fb_info  
    info = get_fb_info(fbidx);  
    if (!info) {  
        request_module("fb%d", fbidx);  
        info = get_fb_info(fbidx);  
        if (!info)  
            return -ENODEV;  
    }  
    if (IS_ERR(info))  
        return PTR_ERR(info);  
    mutex_lock(&info->lock);  
    if (!try_module_get(info->fbops->owner)) {  
        res = -ENODEV;  
        goto out;  
    }  
    //将当前的fb_info保存到/dev/fbx设备文件的private_data成员中  
    file->private_data = info;  
    if (info->fbops->fb_open) {  
        //调用当前fb_info的fb_open函数打开当前FrameBuffer设备  
        res = info->fbops->fb_open(info,1);  
        if (res)  
            module_put(info->fbops->owner);  
    }  
#ifdef CONFIG_FB_DEFERRED_IO  
    if (info->fbdefio)  
        fb_deferred_io_open(info, inode, file);  
#endif  
out:  
    mutex_unlock(&info->lock);  
    if (res)  
        put_fb_info(info);  
    return res;  
}  

  打开过程很简单,首先从文件节点中取出要打开FrameBuffer的fb_info数据信息,并保存到设备文件file的private_data变量中,然后调用当前fb_info中的fb_open函数完成设备打开过程。该函数在构造具体的fb_info并注册FrameBuffer时,就已注册了对应的打开操作函数指针。

《(转载)Framebuffer驱动程序分析》

fbX设备文件的映射过程

static int fb_mmap(struct file *file, struct vm_area_struct * vma)  
{  
    //从文件节点中取出fb_info,并且判断是否和private_data变量中的fb_info相同  
    struct fb_info *info = file_fb_info(file);  
    struct fb_ops *fb;  
    unsigned long off;  
    unsigned long start;  
    u32 len;  
    if (!info)  
        return -ENODEV;  
    if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))  
        return -EINVAL;  
    off = vma->vm_pgoff << PAGE_SHIFT;  
    fb = info->fbops;  
    if (!fb)  
        return -ENODEV;  
    mutex_lock(&info->mm_lock);  
    //如果fb_info中注册了fb_mmap函数,则调用fb_info中的fb_mmap来完成地址空间映射  
    if (fb->fb_mmap) {  
        int res;  
        res = fb->fb_mmap(info, vma);  
        mutex_unlock(&info->mm_lock);  
        return res;  
    }  
    //如果具体的fb_info没有实现fb_mmap  
    start = info->fix.smem_start;  
    len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);  
    if (off >= len) {  
        /* memory mapped io */  
        off -= len;  
        if (info->var.accel_flags) {  
            mutex_unlock(&info->mm_lock);  
            return -EINVAL;  
        }  
        start = info->fix.mmio_start;  
        len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);  
    }  
    mutex_unlock(&info->mm_lock);  
    start &= PAGE_MASK;  
    if ((vma->vm_end - vma->vm_start + off) > len)  
        return -EINVAL;  
    off += start;  
    vma->vm_pgoff = off >> PAGE_SHIFT;  
    /* This is an IO map - tell maydump to skip this VMA */  
    vma->vm_flags |= VM_IO | VM_RESERVED;  
    vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);  
    fb_pgprotect(file, vma, off);  
    if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,  
                 vma->vm_end - vma->vm_start, vma->vm_page_prot))  
        return -EAGAIN;  
    return 0;  
}  

这里和fb打开过程类似,仍然是调用具体的fb_info的映射函数来完成地址空间映射过程,但是也有区别,就是在具体的fb_info没有实现地址空间映射时,就在FrameBuffer这一层完成映射过程。

fbX设备文件的命令控制过程

《(转载)Framebuffer驱动程序分析》

static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg)  
{  
    struct fb_ops *fb;  
    struct fb_var_screeninfo var;  
    struct fb_fix_screeninfo fix;  
    struct fb_con2fbmap con2fb;  
    struct fb_cmap cmap_from;  
    struct fb_cmap_user cmap;  
    struct fb_event event;  
    void __user *argp = (void __user *)arg;  
    long ret = 0;  
    switch (cmd) {  
    case FBIOGET_VSCREENINFO:  
        if (!lock_fb_info(info))  
            return -ENODEV;  
        var = info->var;  
        unlock_fb_info(info);  
  
        ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;  
        break;  
    case FBIOPUT_VSCREENINFO:  
        if (copy_from_user(&var, argp, sizeof(var)))  
            return -EFAULT;  
        if (!lock_fb_info(info))  
            return -ENODEV;  
        console_lock();  
        info->flags |= FBINFO_MISC_USEREVENT;  
        ret = fb_set_var(info, &var);  
        info->flags &= ~FBINFO_MISC_USEREVENT;  
        console_unlock();  
        unlock_fb_info(info);  
        if (!ret && copy_to_user(argp, &var, sizeof(var)))  
            ret = -EFAULT;  
        break;  
    case FBIOGET_FSCREENINFO:  
        if (!lock_fb_info(info))  
            return -ENODEV;  
        fix = info->fix;  
        unlock_fb_info(info);  
  
        ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;  
        break;  
    case FBIOPUTCMAP:  
        if (copy_from_user(&cmap, argp, sizeof(cmap)))  
            return -EFAULT;  
        ret = fb_set_user_cmap(&cmap, info);  
        break;  
    case FBIOGETCMAP:  
        if (copy_from_user(&cmap, argp, sizeof(cmap)))  
            return -EFAULT;  
        if (!lock_fb_info(info))  
            return -ENODEV;  
        cmap_from = info->cmap;  
        unlock_fb_info(info);  
        ret = fb_cmap_to_user(&cmap_from, &cmap);  
        break;  
    case FBIOPAN_DISPLAY:  
        if (copy_from_user(&var, argp, sizeof(var)))  
            return -EFAULT;  
        if (!lock_fb_info(info))  
            return -ENODEV;  
        console_lock();  
        ret = fb_pan_display(info, &var);  
        console_unlock();  
        unlock_fb_info(info);  
        if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))  
            return -EFAULT;  
        break;  
    case FBIO_CURSOR:  
        ret = -EINVAL;  
        break;  
    case FBIOGET_CON2FBMAP:  
        if (copy_from_user(&con2fb, argp, sizeof(con2fb)))  
            return -EFAULT;  
        if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)  
            return -EINVAL;  
        con2fb.framebuffer = -1;  
        event.data = &con2fb;  
        if (!lock_fb_info(info))  
            return -ENODEV;  
        event.info = info;  
        fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);  
        unlock_fb_info(info);  
        ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;  
        break;  
    case FBIOPUT_CON2FBMAP:  
        if (copy_from_user(&con2fb, argp, sizeof(con2fb)))  
            return -EFAULT;  
        if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)  
            return -EINVAL;  
        if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)  
            return -EINVAL;  
        if (!registered_fb[con2fb.framebuffer])  
            request_module("fb%d", con2fb.framebuffer);  
        if (!registered_fb[con2fb.framebuffer]) {  
            ret = -EINVAL;  
            break;  
        }  
        event.data = &con2fb;  
        if (!lock_fb_info(info))  
            return -ENODEV;  
        event.info = info;  
        ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);  
        unlock_fb_info(info);  
        break;  
    case FBIOBLANK:  
        if (!lock_fb_info(info))  
            return -ENODEV;  
        console_lock();  
        info->flags |= FBINFO_MISC_USEREVENT;  
        ret = fb_blank(info, arg);  
        info->flags &= ~FBINFO_MISC_USEREVENT;  
        console_unlock();  
        unlock_fb_info(info);  
        break;  
    default:  
        if (!lock_fb_info(info))  
            return -ENODEV;  
        fb = info->fbops;  
        if (fb->fb_ioctl)  
            ret = fb->fb_ioctl(info, cmd, arg);  
        else  
            ret = -ENOTTY;  
        unlock_fb_info(info);  
    }  
    return ret;  
}  

FrameBuffer驱动的框架就介绍到这来,总结一下:

  1. 构建一个fb_info数据结构,用来描述帧缓冲设备;
  2. 调用FrameBuffer驱动模块提供的接口函数register_framebuffer来注册帧缓冲设备;
  3. 对FrameBuffer设备文件的操作过程是,首先执行FrameBuffer驱动函数,然后根据注册的帧缓冲设备的次设备号得到注册的fb_info,最后调用具体的帧缓冲设备的操作函数;

转载自:https://blog.csdn.net/yangwen123/article/details/12096483

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d 博主赞过: