一.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);
-
}
2. framebuffer_alloc过程
在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;
-
}
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,说明注册完成
-
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;
-
}
这样就注册好了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
-
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;
-
}
-
注册的文件操作结构体是fb_fops
-
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;
-
}
阅读(2223) | 评论(0) | 转发(0) |