(OK) kernel create framebuffer device - /dev/graphics/fb0
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中
- static int __init s3cfb_probe(struct platform_device
*pdev)
- {
- //第一步为framebuffer分配空间
- struct fb_info *fbinfo = framebuffer_alloc(sizeof(s3cfb_info_t), &pdev->dev);
- //第二步初始化fbinfo
- ....
- ....
- //第三步注册framebuffer
- ret = register_framebuffer(&s3cfb_info[index].fb);
- }
在drivers/video/fbsysfs.c中,
主要作用就是: 申请内存,并略微初始化fb_info结构体,主要的初始化是在s3c_probe函数中
- struct fb_info *framebuffer_alloc(size_t size, struct device
*dev)
- {
- int fb_info_size
= sizeof(struct fb_info);
- struct fb_info *info;
- fb_info_size += PADDING;
//为了对齐
- //申请内存,并清零
- info = (struct fb_info *) kzalloc(fb_info_size + size, GFP_KERNEL);
- info->par
= p + fb_info_size;
- //device指针保存dev
- info->device = dev;
- return info;
- }
在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,说明注册完成
- int register_framebuffer(struct fb_info
*fb_info)
- {
- int i;
- struct fb_event event;
- struct fb_videomode mode;
- 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));
- num_registered_fb++;
- for (i
= 0 ; i
< FB_MAX; i++)
//1.1在数组registered_fb中搜索没有使用的一项来注册
- if (!registered_fb[i])
- break;
- fb_info->node
= i;
//1.2这个i值很重要,以后open(/dev/fb0),后面的0,1,2就是这个i
- mutex_init(&fb_info->lock);
- mutex_init(&fb_info->mm_lock);
- //2.在"/dev/grapihc"下创建fb[i]设备文件,fb_class="/dev/graphic"
- fb_info->dev
= device_create(fb_class, fb_info->device, MKDEV(FB_MAJOR,
i),
NULL, "fb%d", i);
- fb_init_device(fb_info);
//在/sys/device目录下创建/sys文件
- 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);
- registered_fb[i]
= fb_info; //3.将初始化了的fb_info加到全局变量中
- event.info
= fb_info;
- if (!lock_fb_info(fb_info))
- return -ENODEV;
- fb_notifier_call_chain(FB_EVENT_FB_REGISTERED,
&event);
- unlock_fb_info(fb_info);
- return 0;
- }
二.上层调用 open /dev/graphics/fb0时
通过register_framebuffer产生了设备文件/dev/graphics/fb0,但是open /dev/graphics/fb0时的文件操作是如何产生的呢?
看一下drivers/video/fbmem.c的注册过程就知道了.
module_init(fbmem_init);
--> fbmem_init
- static int __init
fbmem_init(void)
- {
- proc_create("fb", 0,
NULL,
&fb_proc_fops);
//创建/proc/fb
- register_chrdev(FB_MAJOR,"fb",&fb_fops); //注册字符设备文件
- //创建class=/dev/graphics",以后用device_create创建的设备文件都会在/dev/graphics目录下
- fb_class = class_create(THIS_MODULE,
"graphics");
- return 0;
- }
- static const struct file_operations fb_fops
= {
- .owner = THIS_MODULE,
- .mmap = fb_mmap,
- .open = fb_open,
- .... //省略
- };
上层调用open /dev/graphics/fb0时,会先调用fb_open函数
- static int fb_open(struct inode
*inode, struct file
*file)
- __acquires(&info->lock)
- __releases(&info->lock)
- {
- //从inode中获取次设备号,来判断是哪个fb,并将次设备号转为索引值
- int fbidx
= iminor(inode);
- struct fb_info *info;
- int res = 0;
- if (fbidx
>= FB_MAX)
- return -ENODEV;
- info = registered_fb[fbidx];
//通过索引值找在全局数组中找到fb
- if (!info)
- request_module("fb%d", fbidx);
- info = registered_fb[fbidx];
//通过索引值找在全局数组中找到fb
- if (!info) //为什么要调两次?
- return -ENODEV;
- mutex_lock(&info->lock);
- if (!try_module_get(info->fbops->owner))
{ //模块引用计数加1
- res =
-ENODEV;
- goto out;
- }
- file->private_data
= info;
- if (info->fbops->fb_open)
{ //如果fb0有open函数则调用fb0的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;
- }