• (OK) kernel create framebuffer device



    http://blog.chinaunix.net/uid-26009923-id-4040712.html


    一.framebuffer的初始化
    1. 以s3cfb的注册过程说明

    module_init(s3cfb_init);
       --> platform_driver_register(&s3cfb_driver);
             --> s3cfb_probe(struct platform_device *pdev)
     在drivers/video/samsung/s3cfb.c中

    1. static int __init s3cfb_probe(struct platform_device *pdev)
    2. {
    3.     //第一步为framebuffer分配空间
    4.     struct fb_info *fbinfo = framebuffer_alloc(sizeof(s3cfb_info_t), &pdev->dev);
    5.     //第二步初始化fbinfo
    6.     ....
    7.     ....
    8.     //第三步注册framebuffer
    9.     ret = register_framebuffer(&s3cfb_info[index].fb);
    10. }
    2. framebuffer_alloc过程
    在drivers/video/fbsysfs.c中,
    主要作用就是: 申请内存,并略微初始化fb_info结构体,主要的初始化是在s3c_probe函数中
    1. struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
    2. {
    3.     int fb_info_size = sizeof(struct fb_info);
    4.     struct fb_info *info;
    5.     fb_info_size += PADDING;    //为了对齐
    6.     //申请内存,并清零
    7.     info = (struct fb_info *) kzalloc(fb_info_size + size, GFP_KERNEL);
    8.     info->par = p + fb_info_size;
    9.     //device指针保存dev
    10.     info->device = dev;
    11.     return info;
    12. }
    3. register_framebuffer过程
    在drivers/video/fbmem.c中
    主要作用是:
         1. 在全局变量数组registered_fb中查找未使用的一项,把找到的这个项号保存在fb_info中
         2. 在/dev/graphics/fb目录下创建设备结点, /dev/graphics/fb0 ls /dev/graphics/fb1就产生了
         3. 将fb_info添加到全局数组registered_fb中,并发送msg,说明注册完成

    1. int register_framebuffer(struct fb_info *fb_info)
    2. {
    3.     int i;
    4.     struct fb_event event;
    5.     struct fb_videomode mode;

    6.     if (num_registered_fb == FB_MAX)
    7.         return -ENXIO;

    8.     if (fb_check_foreignness(fb_info))
    9.         return -ENOSYS;

    10.     remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, fb_is_primary_device(fb_info));

    11.     num_registered_fb++;
    12.     for (i = 0 ; i < FB_MAX; i++)   //1.1在数组registered_fb中搜索没有使用的一项来注册
    13.         if (!registered_fb[i])
    14.             break;
    15.     fb_info->node = i;              //1.2这个i值很重要,以后open(/dev/fb0),后面的0,1,2就是这个i
    16.     mutex_init(&fb_info->lock);
    17.     mutex_init(&fb_info->mm_lock);
    18.     //2.在"/dev/grapihc"下创建fb[i]设备文件,fb_class="/dev/graphic"
    19.     fb_info->dev = device_create(fb_class, fb_info->device, MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
    20.     fb_init_device(fb_info);   //在/sys/device目录下创建/sys文件
    21.     if (fb_info->pixmap.addr == NULL) {
    22.         fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
    23.         if (fb_info->pixmap.addr) {
    24.             fb_info->pixmap.size = FBPIXMAPSIZE;
    25.             fb_info->pixmap.buf_align = 1;
    26.             fb_info->pixmap.scan_align = 1;
    27.             fb_info->pixmap.access_align = 32;
    28.             fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
    29.         }
    30.     }
    31.     fb_info->pixmap.offset = 0;

    32.     if (!fb_info->pixmap.blit_x)
    33.         fb_info->pixmap.blit_x = ~(u32)0;

    34.     if (!fb_info->pixmap.blit_y)
    35.         fb_info->pixmap.blit_y = ~(u32)0;

    36.     if (!fb_info->modelist.prev || !fb_info->modelist.next)
    37.         INIT_LIST_HEAD(&fb_info->modelist);

    38.     fb_var_to_videomode(&mode, &fb_info->var);
    39.     fb_add_videomode(&mode, &fb_info->modelist);
    40.     registered_fb[i] = fb_info;                  //3.将初始化了的fb_info加到全局变量中

    41.     event.info = fb_info;
    42.     if (!lock_fb_info(fb_info))
    43.         return -ENODEV;
    44.     fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
    45.     unlock_fb_info(fb_info);
    46.     return 0;
    47. }
    这样就注册好了framebuffer,有了/dev/graphics/fb0,但是文件操作在哪儿呢?
    二.上层调用 open /dev/graphics/fb0时
    通过register_framebuffer产生了设备文件/dev/graphics/fb0,但是open /dev/graphics/fb0时的文件操作是如何产生的呢?
    看一下drivers/video/fbmem.c的注册过程就知道了.
    module_init(fbmem_init);
        --> fbmem_init
    1. static int __init fbmem_init(void)
    2. {
    3.     proc_create("fb", 0, NULL, &fb_proc_fops);     //创建/proc/fb
    4.     register_chrdev(FB_MAJOR,"fb",&fb_fops);       //注册字符设备文件
    5.    //创建class=/dev/graphics",以后用device_create创建的设备文件都会在/dev/graphics目录下
    6.     fb_class = class_create(THIS_MODULE, "graphics"); 
    7.     return 0;
    8. }

    注册的文件操作结构体是fb_fops
    1. static const struct file_operations fb_fops = {
    2.     .owner =    THIS_MODULE,
    3.     .mmap =        fb_mmap,
    4.     .open =        fb_open,
    5.     .... //省略  
    6. };

    上层调用open /dev/graphics/fb0时,会先调用fb_open函数
    1. static int fb_open(struct inode *inode, struct file *file)
    2. __acquires(&info->lock)
    3. __releases(&info->lock)
    4. {
    5.     //从inode中获取次设备号,来判断是哪个fb,并将次设备号转为索引值
    6.     int fbidx = iminor(inode);  
    7.     struct fb_info *info;
    8.     int res = 0;

    9.     if (fbidx >= FB_MAX)
    10.         return -ENODEV;
    11.     info = registered_fb[fbidx];  //通过索引值找在全局数组中找到fb
    12.     if (!info)
    13.         request_module("fb%d", fbidx);
    14.     info = registered_fb[fbidx];  //通过索引值找在全局数组中找到fb
    15.     if (!info)                    //为什么要调两次?
    16.         return -ENODEV;
    17.     mutex_lock(&info->lock);
    18.     if (!try_module_get(info->fbops->owner)) {  //模块引用计数加1
    19.         res = -ENODEV;
    20.         goto out;
    21.     }
    22.     file->private_data = info;
    23.     if (info->fbops->fb_open) {              //如果fb0有open函数则调用fb0的open
    24.         res = info->fbops->fb_open(info,1);
    25.         if (res)
    26.             module_put(info->fbops->owner);
    27.     }
    28. #ifdef CONFIG_FB_DEFERRED_IO
    29.     if (info->fbdefio)
    30.         fb_deferred_io_open(info, inode, file);
    31. #endif
    32. out:
    33.     mutex_unlock(&info->lock);
    34.     return res;
    35. }





  • 相关阅读:
    This is very likely to create a memory leak. Stack trace of thread错误分析
    spring boot 2.0 neo4j 使用
    造个简单的轮子倒是不难,但可用性健壮性高到qt这样全世界都在用,就几乎不可能了
    0xC0000005;Access Violation(栈区空间很宝贵, linux上栈区空间默认为8M,vc6下默认栈空间大小为1M)
    Object::connect: Cannot queue arguments of type 'QMap<QString,QString>'(要使用qRegisterMetaType<StringMap>进行注册)
    QFileSystemModel只显示名称,不显示size,type,modified
    非Qt工程使用Qt的信号槽机制
    web性能权威指南(High Performance Browser Networking)
    缓存穿透 缓存并发 缓存失效
    互联网架构-基础中间件
  • 原文地址:https://www.cnblogs.com/ztguang/p/12645187.html
Copyright © 2020-2023  润新知