目录
一 注册fb_info
接着上一小节的register_framebuffer函数开始,
调用do_register_framebuffer函数,,列出主要内容
static int do_register_framebuffer(struct fb_info *fb_info)
{
int i, ret;
struct fb_event event;
struct fb_videomode mode;
if (num_registered_fb == FB_MAX)
return -ENXIO;
num_registered_fb++;
for (i = 0 ; i < FB_MAX; i++)
if (!registered_fb[i])
break;
fb_info->node = i;
fb_info->dev = device_create(fb_class, fb_info->device,MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
fb_init_device(fb_info);
fb_var_to_videomode(&mode, &fb_info->var);
fb_add_videomode(&mode, &fb_info->modelist);
registered_fb[i] = fb_info;
return 0;
}
注意看这个函数已经调用到了哪里,drivers\video\fbdev\core\fbmem.c,没错,就是LCD驱动的核心层
一开始判断变量num_registered_fb的值,表示已经注册fb的数量,由内核统一管理,它有一个最大值的限制(32),然后变量一个fb的数组registered_fb,所有注册的fb_info都会放到这个数组中去
一个循环从数组中找出一个空位置,放入飞思卡尔注册的这个LCD的fb_info registered_fb[i] = fb_info;
接下来很重要的一步就是创建设备,device_create(fb_class, fb_info->device,MKDEV(FB_MAJOR, i), NULL, "fb%d", i);在fb_class这个类下面去创建设备
总结一下注册fb_info的过程
- 从registered_fb数组中找出一个空项,把注册的fb_info结构体放进去
- 在fb_class类下面创建设备
二 核心层代码
这个类是哪里来的呢?这就涉及核心层的代码了,所以一下它,可以在核心层的入口函数中找到
对应的路径就是/sys/class/graphics,如果注册成功的话,就会在该目录下看到刚才创建的设备fbxxx
在前面还有更重要的一步,就是创建字符设备,fb对外来说就是一个字符设备,主设备号29
对于字符设备来说,重点就是它的操作函数集了,
打开open函数
获取打开设备的次设备号,iminor(inode);主设备号都是一样的,根据次设备号去registered_fb数组中取出对应下标的fb_info结构体
有了fb_info结构体那不就简单了,直接调用fb_info->fops->open函数就可以了,也确实是这样做的,就调到了mxsfb.c中设置的那个fops结构体中了,
看一下read函数,也是这样做的
获取次设备号,从数据中取出fb_info结构体,如果它实现了read函数就去执行它的read函数,如果没有实现也是可以的,为什么这么说呢?
往下看就知道,在核心层的read函数里它直接拿到fb_info的显存基地址,然后去操作就可以,对于其他的函数都是一样的.
总结
随着分析,已经从设备层来到了核心层,看到了核心层的代码,注册一个fb的字符设备,根据应用层打开的文件的次设备号,从registered_fb数组中取出对于项,
然后调用fb_info fops中的函数,但是,可以发现,设备注册的fb_info结构体中的fops其实不重要,在核心层一样可以操作的到设备的显存地址.