/**
向核心层注册一个framebuffer设备
*/
int register_framebuffer(struct fb_info * fb_info)
{
/**
设备的次设备号
*/
int i;
/**
struct fb_event
{
struct fb_info *info;
void *data;
};
*/
struct fb_event event;
/*
struct fb_videomode {
const char *name;
u32 refresh;
u32 xres; X方向上的分辨率
u32 yres; Y方向上的分辨率
u32 pixclock; 像素时钟
一些时序参数
u32 left_margin;
u32 right_margin;
u32 upper_margin;
u32 lower_margin;
....
};
下面会在这个函数中 fb_var_to_videomode() 进行初始化
*/
struct fb_videomode mode;
/**
FB_MAX : 32
每注册一个framebuffer设备,num_registered_fb就递增一次
下面会有num_registered_fb++
只能注册32个设备
/dev/fb0 /dev/fb1 /dev/fb2 ..... /dev/fb31
struct fb_info *registered_fb[32];
*/
if (num_registered_fb = FB_MAX)
{
return -ENXIO;
}
for ( i = 0; i < FB_MAX; i++)
{
if (!registreed_fb[i])
{
continue;
}
if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) {
if (fb_do_apertures_overlap(registered_fb[i], fb_info)) {
printk(KERN_ERR "fb: conflicting fb hw usage "
"%s vs %s - removing generic driver\n",
fb_info->fix.id,
registered_fb[i]->fix.id);
unregister_framebuffer(registered_fb[i]);
break;
}
}
}
//注册一个framebuffer设备就递增一次
num_registered_fb++;
/**
从registered_fb[]中找到第一个空缺项
下面会把设置好的fb_info放到里面去
这个空缺项目的索引值 i 就是设备的次设备号
*/
for (i = 0 ; i < FB_MAX; i++)
{
if (!registered_fb[i])
{
break;
}
}
/**
【这一步很重要】。
把设备的次设备号赋给了node,即把存放这个fb_info的数组索引值赋值给了node
像open()函数:
static int fb_open(struct inode *inode, struct file *file)
{
int fbidx = iminor(inode);//获取次设备号
struct fb_info *info;
...
info = registered_fb[fbidx];//根据次设备号从registered_fb[]获取对应的fb_info
}
*/
fb_info->node = i;
/*
初始化互斥锁
*/
mutex_init(&fb_info->lock);
mutex_init(&fb_info->mm_lock);
/**
在类下创建设备。
创建类是再fbmem_init()函数中创建的。
static int __init fbmem_init(void)
{
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_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{
/**
会调用device_create_file()来创建设备文件
*/
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_videomode 进行初始化赋值
mode->name = NULL;
mode->xres = var->xres;
mode->yres = var->yres;
mode->pixclock = var->pixclock;
mode->hsync_len = var->hsync_len;
mode->vsync_len = var->vsync_len;
其中有一项很重要
if (!var->pixclock)
{
return;
}
pixclock = PICOS2KHZ(var->pixclock) * 1000;
....
*/
fb_var_to_videomode(&mode, &fb_info->var);
/**
把设备驱动层设置好的fb_info放入到registered_fb[]数组中
*/
registered_fb[i] = fb_info;
/**
将fb_videomode添加到modelist链表上
*/
fb_add_videomode(&mode, &fb_info->modelist);
/**
把设备驱动层设置好的fb_info放入到registered_fb[]数组中
这边没有使用互斥机制来保护临界区。
而且在调用register_framebuffer的函数在调用register_framebuffer
的时候,也没有进行加锁
但是在3.0以上的内核中 改进了这一点
一下是 3.0内核中的代码
int register_framebuffer(struct fb_info *fb_info)
{
int ret;
mutex_lock(®istration_lock);
ret = do_register_framebuffer(fb_info)
{
...
registered_fb[i] = fb_info;
...
}
mutex_unlock(®istration_lock);
return ret;
}
*/
registered_fb[i] = fb_info;
/**
将fb_info赋值给evdev中的info
*/
event.info = fb_info;
/**
这个函数
1 : 是判断fb_info有没有提供fbops,
2 : 封装了mutex_lock,用来对临界区进行互斥保护
它用一个互斥锁.
可能会问:
临界区这么短小,为什么不用自旋锁。
而且临界区中没有能引起阻塞的代码呀
为什么不一开始 在函数的开头 就判断有没有提供呢,
int lock_fb_info(struct fb_info *info)
{
mutex_lock(&info->lock);
if (!info->fbops) {
mutex_unlock(&info->lock);
return 0;
}
return 1;
}
这是因为:
它最终要锁定的临界区是这个:
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
lock_fb_info 要锁的是 这个临界区。所以 不适合使用自旋锁。
*/
if (!lock_fb_info(fb_info))
{
return -ENODEV;
}
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
/**
mutex_unlock(&info->lock);
*/
unlock_fb_info(fb_info);
return 0;
}
记录kernel lcd驱动 register_framebuffer中的一个bug
最新推荐文章于 2022-09-25 22:59:57 发布