我是靠谱客的博主 朴素信封,最近开发中收集的这篇文章主要介绍MTK平台LCD驱动框架详解(二),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前篇博客链接:http://blog.csdn.net/xuan_h/article/details/38519975

上篇博文说到了mtkfb_probe函数,本文在说mtkfb_probe函数之前。我还是打算在从应用程序的调用开始分析下具体的调用过程。这是我们理解驱动框架的核心,而并不是简单的接受。


一、驱动核心Fbmem.c(alpskerneldriversvideoFbmem.c)分析

      下面先摘取一部分源码,源码包括:入口函数、fb_fops、fb_fops中的open函数。用户调用open函数打开lcd时,会调用到这里的fb_open函数,我们待会就从这个函数开始分析下流程。

static int fb_open(struct inode *inode, struct file *file)
__acquires(&info->lock)
__releases(&info->lock)
{
	int fbidx = iminor(inode);  //获得次设备号
	struct fb_info *info;
	int res = 0;

	info = get_fb_info(fbidx);  //根据次设备号获得fb_info结构体
	if (!info) {
		request_module("fb%d", fbidx);
		info = get_fb_info(fbidx);
		if (!info)
			return -ENODEV;
	}
	if (IS_ERR(info))
		return PTR_ERR(info);

	mutex_lock(&info->lock);
	if (!try_module_get(info->fbops->owner)) {
		res = -ENODEV;
		goto out;
	}
	file->private_data = info;
	if (info->fbops->fb_open) {
		res = info->fbops->fb_open(file,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);
	if (res)
		put_fb_info(info);
	return res;
}

static const struct file_operations fb_fops = {
	.owner =	THIS_MODULE,
	.read =		fb_read,
	.write =	fb_write,
	.unlocked_ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = fb_compat_ioctl,
#endif
	.mmap =		fb_mmap,
	.open =		fb_open,
	.release =	fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
	.get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
	.fsync =	fb_deferred_io_fsync,
#endif
	.llseek =	default_llseek,
};

static int __init fbmem_init(void)
{
	proc_create("fb", 0, NULL, &fb_proc_fops);

	if (register_chrdev(FB_MAJOR,"fb",&fb_fops))       //注册字符设备
		printk("unable to get major %d for fb devsn", FB_MAJOR);

	fb_class = class_create(THIS_MODULE, "graphics");   //创建类
	if (IS_ERR(fb_class)) {
		printk(KERN_WARNING "Unable to create fb class; errno = %ldn", PTR_ERR(fb_class));
		fb_class = NULL;
	}
	return 0;
}
#ifdef MODULE
module_init(fbmem_init);
      open函数里get_fb_info函数的实现如下:

static struct fb_info *get_fb_info(unsigned int idx)
{
	struct fb_info *fb_info;

	if (idx >= FB_MAX)
		return ERR_PTR(-ENODEV);

	mutex_lock(&registration_lock);
	fb_info = registered_fb[idx];   //给fb_info赋值
	if (fb_info)
		atomic_inc(&fb_info->count);
	mutex_unlock(&registration_lock);

	return fb_info;
}
      重点就在该函数里的这句代码了:fb_info = registered_fb[idx];根据次设备号idx,从register_fb[]数组中给fb_info赋值。那 register_fb[]这个数组又是什么时候被赋值的呢?在文件中搜索,可以找到,调用过程如下:

register_framebuffer(struct fb_info *fb_info)

--> ret = do_register_framebuffer(fb_info);

--> registered_fb[i] = fb_info;

        那register_framebuffer又是被谁调用呢?到这里可以开始说说我们的probe了。probe函数会调用register_framebuffer来向内核注册一个fb_info结构体。而这个fb_info结构体便是lcd驱动的核心了。它就是应用程序调用open,open函数根据次设备号寻找的fb_info结构体。下面可以总结下probe函数的核心工作了,也是我们写整个驱动的核心工作:

      1、分配fb_info结构体;

      2、设置fb_info结构体;

      3、register_framebuffer()向内核注册fb_info结构体;

      这样应用程序在调用open函数时,它会找到我们提交的fb_info结构体。并应用里边的设置来完成相应的操作。当然除了open函数,read、write等函数都会调用到我们的fb_info,感兴趣的可以自己去跟跟源码。好了,现在再说probe感觉还是踏实些了。


二、mtkfb_probe

     下面还是以函数调用加注释的形式来说明,字太多了,绕的有点晕。下面最好自己跟跟源码,同级函数顶端对其,靠后一个tab表示调用。

mtkfb_probe
    ------------Disp_drv.c-------------------
    fbi = framebuffer_alloc(sizeof(struct mtkfb_device), dev); //1、分配fbi结构体:fbi是fb_info结构体
    /********从这往下的调用就和MTK提供的驱动文件息息相关了*********/
    DISP_Init
        disp_drv_init_context
            DISP_DetectDevice
                disp_drv_get_lcm_driver //获得lcm_driver结构体的函数
                    if(lcm_count ==1) //Drv只有一个。在mt65xx_lcm_list.c的lcm_driver_list中定义,mak中定义几个屏,lcm_count就是几
                        lcm = lcm_driver_list[0]; //只有一个,将第一个付给lcm,这个便是驱动程序里的LCM_DRIVER结构体
                        lcm->set_util_funcs(&lcm_utils); //设置功能函数
                        lcm->get_params(&s_lcm_params); //获得lcm参数
                        lcm_params = &s_lcm_params; //保存这些参数
                        lcm_drv = lcm; //保存lcm
                    else
                        for(i = 0;i < lcm_count;i++) //遍历lcm_driver_list结构体
                            lcm_params = &s_lcm_params;
                            lcm = lcm_driver_list[i]; //存储LCM_DRIVER结构体
                            lcm->set_util_funcs(&lcm_utils);
                            disp_drv_init_ctrl_if(); //接口设置(DBI、DPI、DSI…)
               return lcm_drv;
		     
    /* Register to system */
    r = mtkfb_fbinfo_init(fbi);  //2、设置fbi结构体
        info->fbops = &mtkfb_ops; //2.1、设置fops
        memset(&var, 0, sizeof(var)); //2.2、清零可变参数
        ……  //2.3、设置可变参数
        r = mtkfb_check_var(&var, info); //2.4、检查可变参数
        mtkfb_set_par
            set_fb_fix(fbdev); //2.5、设置固定参数
        ………… /*2.6、通常还需要做一些硬件操作,初始化lcd寄存器,时序等其实正常工作。关于这部分工作我还没跟到,日后找到了补上*/
        
    …………  //3、待续…………
    r = register_framebuffer(fbi); //4、注册fbi结构体 

 

        
上面的只是个大体,还不够完善。正如注释2.6所说,我们最关注的一块(硬件的操作)。因为暂时自己还弄得不是太清楚,所以以省略号的形式空在那了。日后待这部分完善以后,大体的框架便已经清晰。 

      这里还想要说的一点,我们注册的fb_info结构体和mtk驱动的关系在哪?注释3。也就是在注册fb_info结构体之前,mtk提供的核心结构体LCM_DRIVER和fb_info结构体之间是怎样关联的。因为时间关系,这部分下次再做说明。




最后

以上就是朴素信封为你收集整理的MTK平台LCD驱动框架详解(二)的全部内容,希望文章能够帮你解决MTK平台LCD驱动框架详解(二)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部