framebuffer驱动框架代码解析

注:我的博客都是我在学习时候为了增强我对一些内容的印象而写的,不喜勿喷
一、framebuffer驱动相关基础
1.驱动框架部分涉及的文件
(1)driver/video/fbmem.c
(2)driver/video/fbsys.c
(3)driver/video/fb_notify.c

2.相关的两个重要结构体。
(1)fb_fix_screeninfo结构体,framebuffer不可变参数的结构体

struct fb_fix_screeninfo {
    char id[16];            /* identification string eg "TT Builtin" */
    //显存的物理地址
    unsigned long smem_start;
    __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 */
};

(2)fb_var_screeninfo结构体,framebuffer可变参数的结构体

struct fb_var_screeninfo {
    //屏幕的可视分辨率
    __u32 xres;         /* visible resolution       */
    __u32 yres;
    //屏幕的虚拟分辨率
    __u32 xres_virtual;     /* virtual resolution       */
    __u32 yres_virtual;
    //x,y相对于虚拟分辨率的偏移量
    __u32 xoffset;          /* offset from virtual to visible */
    __u32 yoffset;          /* resolution           */
    //像素深度,bpp
    __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 */
};

(3)写应用我们可以读取fb的可变信息和不可变信息。读取方法:
使用ioctl函数。传入命令FBIOGET_VSCREENINFO或者FBIOGET_FSCREENINFO宏定义。记得包括/linux/fb.h头文件。命令所带的参数就是传入相应的结构体变量地址。
例:ioctl(fd, FBIOGET_FSCREENINFO, &fbinfo_f);
fbinfo_f这个变量是我们自己定义的( struct fb_fix_screeninfo fbinfo_f = {0}; )

二、驱动框架分析
(1)fbmem_init函数分析(driver/video/fbmem.c)

static int __init fbmem_init(void)
{
    //在proc目录下创建一个fb文件。
    proc_create("fb", 0, NULL, &fb_proc_fops);

    //注册一个字符设备,主设备号是FB_MAJOR(29),并且绑定了fb_fops文件操作方法。
    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;
}
//绑定的fb_ops操作方法结构体
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,                //打开fb文件的操作方法
    .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
};

(2)看一个fb_open具体的操作方法
1)首先得明白,内核是用一个数组来管理已经注册的framebuffer的。也就是registered_fb[fbidx]; fbidx最大值就是32.
2)struct fb_info *registered_fb[FB_MAX]; registered_fb是一个指针数组。最大能注册32个framebuffer设备。
3)int num_registered_fb; 也就是用来记录已经注册了多少个framebuffer设备

static int fb_open(struct inode *inode, struct file *file) 
__acquires(&info->lock) __releases(&info->lock)
{
    //inode就是我们打开的那个fb文件的文件节点,使用iminor宏得到次设备号
    int fbidx = iminor(inode);
    struct fb_info *info;
    int res = 0;

    if (fbidx >= FB_MAX)
        return -ENODEV;
    //得到得到次设备号,在去已经数组里面找到那个framebuffer设备
    info = registered_fb[fbidx];
    if (!info)
        request_module("fb%d", fbidx);
    info = registered_fb[fbidx];
    if (!info)
        return -ENODEV;
    mutex_lock(&info->lock);
    if (!try_module_get(info->fbops->owner)) {
        res = -ENODEV;
        goto out;
    }
    file->private_data = info;
    //判断如果打开的framebuffer文件的fbops->fb_open不为空的话就执行info->fbops->fb_open(info,1);这个就是驱动工程师自己写的open函数(在注册时候放进去的那个结构体里面的fbops)
    if (info->fbops->fb_open) {
        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);
    return res;
}

(3)register_framebuffer函数分析

int register_framebuffer(struct fb_info *fb_info)
{
    int i;
    struct fb_event event;
    struct fb_videomode mode;

    /****************判断fb_info的参数是否正确**************/
    if (num_registered_fb == FB_MAX)
        return -ENXIO;

    if (fb_check_foreignness(fb_info))
        return -ENOSYS;

    remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
                     fb_is_primary_device(fb_info));
    /****************判断fb_info的参数是否正确**************/

    //判断正确说明这个可以注册这个framebuffer设备,则 num_registered_fb++
    num_registered_fb++;

    //遍历registered_fb指针数组,如果registered_fb[i]为空,则记录下i的值
    for (i = 0 ; i < FB_MAX; i++)
        if (!registered_fb[i])
            break;
    //标记framebuffer里面的node
    fb_info->node = i;

    //初始化互斥锁
    mutex_init(&fb_info->lock);
    mutex_init(&fb_info->mm_lock);

    //在/sys/class/graphics目录下创建要注册的device
    fb_info->dev = device_create(fb_class, fb_info->device,
                     MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
    if (IS_ERR(fb_info->dev)) {
        /* Not fatal */
        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_init_device(fb_info);    //这个初始化函数比较重要。下面会分析

    //下面这一坨pixmap不知道这个参数是干嘛的。
    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_info里面的可变参数,并且填充mode
    fb_var_to_videomode(&mode, &fb_info->var);

    //把屏幕显示的模式注册到b_info->modelist链表中
    fb_add_videomode(&mode, &fb_info->modelist);

    //最佳之绝唱,一句话注册framebuffer设备
    registered_fb[i] = fb_info;

    //event不知道是干嘛的。
    event.info = fb_info;
    if (!lock_fb_info(fb_info))
        return -ENODEV;
    //内核设计的异步通知,告诉内核有framebuffer要注册了。
    fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
    unlock_fb_info(fb_info);
    return 0;
}

注:register_framebuffer函数就是驱动工程师在写lcd驱动注册时候要调用的函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值