MTK——lcm驱动整理
2016-02-18 11:36
218 查看
转载自http://www.th7.cn/system/lin/201408/67216.shtml
许多学习嵌入式的进入MTK开发平台,很多东西都会感到很陌生。在MTK平台上你可以简简单单几分钟就点亮一块屏。加上MTK快速开发的节奏,也很少有时间自己整理学习。如果不思进取,不加班加点学习。很容易就慢慢……。这也难怪有些人说MTK造就了一批懒人,毁掉了一批工程师。但其实都是基于linux开发,核心的东西都是一样一样的。我刚入行业,在迷茫之际,自己整理跟踪源码。想慢慢找回自己熟悉的感觉,掌握MTK的整体框架。也希望能给有需要的人带来些帮助。好吧!前话说到这,开始正题。
本文可能有的地方会出现错误,或不够深入,欢迎批评指正。毕竟都是个人理解,希望能和大家多多交流。大家一起慢慢吃透MTK。随便提一句,如果不熟悉“linux平台设备驱动”模型的,可以找相关资料看看。
注:-->表示函数之间的调用
一、平台驱动:Mtkfb.c
就从Mtkfb.c文件开始说起吧。路径在:alps/mediatek/platform/common/kernel/drivers/video/Mtkfb.c
在该文件中,我们能非常熟悉的看到内核的原态。下面我删截了一部分大家最熟悉的源码。
看了上面代码,大家肯定知道mtkfb_probe函数是核心。但暂时我还不想说这一块,因为底层框架还没分析完,熟悉平台设备驱动的都知道:仅仅有driver是跑不到probe函数的。在入口函数上面的注视,有写同时注册driver和device。不知道是MTK掩人耳目还是同事的错误标注,反正我没在里面找到注册device相关的代码。这一块希望看过本文的人能提供解释。
二、平台设备:Mt_devs.c
事实上我在另外的地方跟到了device的注册函数。在Mt_devs.c中,路径在:mediatek/platform/common/kernel/drivers/video(在bootable/bootloader/lk目录下也有一份一样的,目前不能给出明确解释。)
1、在该文件中:__init int mt_board_init(void)函数-->platform_device_register(&mt6575_device_fb),在mt6575_device_fb结构体中我们能看到disp_device.name = "mtkfb"。对比Mtkfb.c中的结构体mtkfb_driver.name = MTKFB_DRIVER。我们能发现两者同名。这又到了我们熟悉的地方。出现同名设备,不管先后,内核会调用Mtkfb.c中的probe函数。这时我们可以开始分析probe函数了。
2、在这之前,有个问题我得说明,我们先来看看__init int mt_board_init(void)函数的调用过程:Main.c里的kmain函数-->platform_early_init-->board_init-->mt_board_init。源头追溯到了C函数的入口Main.c。我之所以去跟,是因为Mt_devs.c中并不是以我们熟悉的模块的形式注册的设备,也就是根本没有module_init()入口标记,而且mt_board_init一个函数中做了几乎所有平台设备的注册工作。这是和平时学习有别的地方,所以特意说明。也免得大家和我开始一样,一直疑惑设备驱动文件为啥没入口函数。
时候不早了,该下班了。下次接着“第三点”,说说mtkfb_probe函数里边的工作
待续…………
以下文字转载自:http://blog.csdn.net/xuan_h/article/details/38610985?utm_source=tuicool&utm_medium=referral
一、驱动核心 Fbmem.c (alps\kernel\drivers\video\Fbmem.c) 分析
下面先摘取一部分源码,源码包括:入口函数、fb_fops、fb_fops中的open函数。用户调用open函数打开lcd时,会调用到这里的fb_open函数,我们待会就从这个函数开始分析下流程。
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表示调用。
许多学习嵌入式的进入MTK开发平台,很多东西都会感到很陌生。在MTK平台上你可以简简单单几分钟就点亮一块屏。加上MTK快速开发的节奏,也很少有时间自己整理学习。如果不思进取,不加班加点学习。很容易就慢慢……。这也难怪有些人说MTK造就了一批懒人,毁掉了一批工程师。但其实都是基于linux开发,核心的东西都是一样一样的。我刚入行业,在迷茫之际,自己整理跟踪源码。想慢慢找回自己熟悉的感觉,掌握MTK的整体框架。也希望能给有需要的人带来些帮助。好吧!前话说到这,开始正题。
本文可能有的地方会出现错误,或不够深入,欢迎批评指正。毕竟都是个人理解,希望能和大家多多交流。大家一起慢慢吃透MTK。随便提一句,如果不熟悉“linux平台设备驱动”模型的,可以找相关资料看看。
注:-->表示函数之间的调用
一、平台驱动:Mtkfb.c
就从Mtkfb.c文件开始说起吧。路径在:alps/mediatek/platform/common/kernel/drivers/video/Mtkfb.c
在该文件中,我们能非常熟悉的看到内核的原态。下面我删截了一部分大家最熟悉的源码。
static struct platform_driver mtkfb_driver ={ .driver = { .name = MTKFB_DRIVER,#ifdef CONFIG_PM .pm = &mtkfb_pm_ops,#endif .bus = &platform_bus_type, .probe = mtkfb_probe, .remove = mtkfb_remove, .suspend = mtkfb_suspend, .resume = mtkfb_resume, .shutdown = mtkfb_shutdown, },};
/* Register both the driver and the device */int __init mtkfb_init(void){ int r = 0; MSG_FUNC_ENTER();#ifdef DEFAULT_MMP_ENABLE MMProfileEnable(1); init_mtkfb_mmp_events(); init_ddp_mmp_events(); MMProfileStart(1);#endif /* Register the driver with LDM */ if (platform_driver_register(&mtkfb_driver)) { PRNERR("failed to register mtkfb driver/n"); r = -ENODEV; goto exit; }#ifdef CONFIG_HAS_EARLYSUSPEND register_early_suspend(&mtkfb_early_suspend_handler);#endif DBG_Init();//#ifdef MTK_DISP_CONFIG_SUPPORT ConfigPara_Init();//In order to Trigger Display Customization Tool..//#endifexit: MSG_FUNC_LEAVE(); return r;}
module_init(mtkfb_init);module_exit(mtkfb_cleanup);
看了上面代码,大家肯定知道mtkfb_probe函数是核心。但暂时我还不想说这一块,因为底层框架还没分析完,熟悉平台设备驱动的都知道:仅仅有driver是跑不到probe函数的。在入口函数上面的注视,有写同时注册driver和device。不知道是MTK掩人耳目还是同事的错误标注,反正我没在里面找到注册device相关的代码。这一块希望看过本文的人能提供解释。
二、平台设备:Mt_devs.c
事实上我在另外的地方跟到了device的注册函数。在Mt_devs.c中,路径在:mediatek/platform/common/kernel/drivers/video(在bootable/bootloader/lk目录下也有一份一样的,目前不能给出明确解释。)
1、在该文件中:__init int mt_board_init(void)函数-->platform_device_register(&mt6575_device_fb),在mt6575_device_fb结构体中我们能看到disp_device.name = "mtkfb"。对比Mtkfb.c中的结构体mtkfb_driver.name = MTKFB_DRIVER。我们能发现两者同名。这又到了我们熟悉的地方。出现同名设备,不管先后,内核会调用Mtkfb.c中的probe函数。这时我们可以开始分析probe函数了。
2、在这之前,有个问题我得说明,我们先来看看__init int mt_board_init(void)函数的调用过程:Main.c里的kmain函数-->platform_early_init-->board_init-->mt_board_init。源头追溯到了C函数的入口Main.c。我之所以去跟,是因为Mt_devs.c中并不是以我们熟悉的模块的形式注册的设备,也就是根本没有module_init()入口标记,而且mt_board_init一个函数中做了几乎所有平台设备的注册工作。这是和平时学习有别的地方,所以特意说明。也免得大家和我开始一样,一直疑惑设备驱动文件为啥没入口函数。
时候不早了,该下班了。下次接着“第三点”,说说mtkfb_probe函数里边的工作
待续…………
以下文字转载自:http://blog.csdn.net/xuan_h/article/details/38610985?utm_source=tuicool&utm_medium=referral
一、驱动核心 Fbmem.c (alps\kernel\drivers\video\Fbmem.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 devs\n", FB_MAJOR); 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; } #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(®istration_lock); fb_info = registered_fb[idx]; //给fb_info赋值 if (fb_info) atomic_inc(&fb_info->count); mutex_unlock(®istration_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结构体
相关文章推荐
- 网站建站实践
- web.xml 中的listener、 filter、servlet 加载顺序
- AOV图-AOE图
- JDBC—MeteData、PreparedStatement、CallableStatement
- 数据结构 魔王语言C++
- iOS加密
- Android设置TextView显示指定个数字符,超过部分显示...(省略号)的方法
- C++ Primer Plus 札记(一) 数组,字符串和string
- 深入Java虚拟机(1)——Java体系结构
- 深入Java虚拟机(1)——Java体系结构
- 深入Java虚拟机(1)——Java体系结构
- java处理html空格变成问号问题
- Mac OS X Yosemite安装Hadoop 2.6记录
- 深入Java虚拟机(1)——Java体系结构
- C#集合转换为json
- cron表达式详解
- 修改android 开机动画
- jdk环境变量
- 使用极光推送实现分组发送和服务端集成
- 证书的签发者无效的问题