QCamera学习笔记For MSM camera IC, significant portion of image processing and optimization codes are proprietary, so they cannot sit in kernel space. This plays animportant role when making design decisions.其大致意思是,daemon是介于应用和驱动之间翻译ioctl的中间层(委托处理),其目的是将VFE/ISP具体操作策略的私有化代码封闭,所以才会弄出这么一个感觉怪怪的东东。
在驱动设计中,存在msm-config和msm-camera两种model的media controller,前者用于获取事件通知v4l2驱动信息,后者用于获取sensor操作v4l2驱动信息。
一个完整的调用流程大致是:app==>v4l2(stream)==>daemon==>v4l2(control)==>app说明:1、app到daemon主要是在v4l2(stream)中事件通知方式进行的,对于map/unmap则直接通过domain socket方式进行2、daemon到app是通过v4l2(control)的事件通知机制进行的3、v4l2(stream)是通过msm-camera获取到相关信息的,v4l2(control)是通过msm-config获取到相关信息的一. 概述高通新的camera驱动架构设计发生了一些变化,借用互联网上常用的一种结构。
大致的原理如此:1. 将camera的所有功能划分为不同的模块,让模块自己来决定自己的事情(高内聚,低耦合)2. 模块需要有统一的接口和格式。
3. 模块中有端口,通过端口把模块连接起来,又把模块挂在总线上。
4. 每一个端口的连接就是一个流,把这些流用pipeline来管理。
5. 每次启动一个camera就创建一个会话,由这个会话来管理此camera的一切事物。
6. 对于每一个会话,模块是共享的,它可以是camera的硬件资源也可以是其它资源(如一些软件算法等资源)。
那么如何来定义这个模块的结构呢?1.端口——端口属于模块,如果这个模块只有source端口,那么它就是一个src模块;如果只有sink端口就是sink模块,如果都有就是中间模块。
没有端口的模块是不能连接到流中的,但他可以完成一些其他的功能,比如接收引擎的设置,报告事件到bus等。
连接到流中的端口,也就是说流事件(set/get)主要通过端口来处理。
而来自于引擎的(set/get)通过模块来处理,当然端口也可以把事件交给模块来处理。
模块内部的端口可以通过模块来建立关系,也可以建立内部的连接,端口有关get/set process。
2.模块线程——每个模块可以有一个线程来处理模块的事情。
一个线程对应一个队列,线程就是从队列中取出数据处理,然后应答回去。
3.总线回调——挡一个模块向总线注册时,总线向其提供一个回调函数,当模块有事件发生时,调用这个函数向bus发消息,然后总线把这个消息提交给管道,管道把这个消息顺着流发下去。
4.模块的get、set以及process。
管道、引擎与会话管道有两端,一端用于读,一端用于写。
camera引擎负责对管道的监控,而会话管理camera引擎。
从代码结构上来看这种新的驱动架构高通的camera deamon代码放置在vendor\qcom\proprietary\mm-camera目录下,而此目录下的mm-camera2就是新的camera架构位置,进入里面可以看到media-controller、server-imaging、server-tuning及其它几个目录,我们这里需要关注的就是media-controller目录。
media-controller|- mct——应该就是camera的引擎?里面包含了引擎、pipiline、bus、module、stream及event等定义及封装。
|- modules——这里面就是划分好的一些模块代码,各模块大致功能如下|- sensor —— sensor 的驱动模块?—— src模块|- iface —— ISP interface模块— inter模块|- isp ——主要是ISP的处理,其内部又包含了众多的模块–--inter 模块|- stats ——一些统计算法模块,如3A,ASD,AFD,IS,GRRO等数据统计的处理—— sink模块|- pproc —— post process处理—— inter模块|- imglib ——主要是图片的一些后端处理,如HDR等——sink模块以上各模块内部又包含了众多的模块,具体需要看代码分析。
二. 高通camera daemon进程1.概述高通在Android的camera架构中,依旧沿用了其传统的方式,将其自身的一些处理放在一个daemon进程中。
这部分内容出于应用于driver之间,是为了保护自身及硬件厂商的利益而专门弄出来的一个东东。
其它各家平台也采用类似的方式将这部分的处理放在HAL层处理。
2.进程的入口做为一个单独的进程,那肯定是有其main函数入口的。
在vendor\qcom\proprietary\mm-camera\mm-camera2\server-imaging\server.c文件中可以看到这个main函数。
在这个函数中主要做了以下几件事情。
1.找到服务节点的名字并打开此节点get_server_node_name(serv_hal_node_name)......hal_fd->fd[0] = open(dev_name, O_RDWR | O_NONBLOCK); //这里dev_name为节点名如"/dev/serv_hal_node_name"2.初始化模块。
目前有sensor、iface、isp、stats、pproc及imglib六个模块(见笔记一)server_process_module_init();3.进入主循环来处理来自HAL及MCT的事件及消息,处理完之后的结果反馈给kernel(msm.c)RD_FD_HAL----> server_process_hal_event(&event)。
此函数如果返回真,表示事件消息已经传给了MCT,这时不需要发送CMD ACK给kernel,因为MCT处理结束后会发出通知。
如果返回假,表示没有传到MCT,此时需要立即发送CMD ACK到kernel,以便HAL发送此消息的线程阻塞住。
RD_DS_FD_HAL ——通过domain socket传自HAL的消息----> server_process_hal_ds_packet(fd_info->fdRD_PIPE_FD_MCT ——来自media controller的消息三. media controller线程1.概述MCT线程是camera新架构的引擎部分,负责对管道的监控,由此来完成一个camera设备的控制运转。
它运行在daemon进程空间,由MSM_CAMERA_NEW_SESSION事件来开启,具体开启函数为mct_controller_new()。
2.mct_controller_new()函数此函数创建一个新的MCT引擎,这将对应一个事务的pipeline。
我们知道上层可以创建多个事务,每个对应一个camera,也对应自己的MCT及pipeline等。
因此这个函数的主要完成以下几件事情:1.mct_pipeline_new()---->创建一个Pipeline及其bus,并完成pipeline函数的映射。
2.mct_pipeline_start_session()---->开启camera的所有模块并查询其能力3.pthread_create(..., mct_controller_thread_run, ...)---->创建mct线程并开始执行4.pthread_create(..., mct_bus_handler_thread_run, ...)---->创建bus处理线程3.mct_list_traverse()函数此函数在整个mct线程中大量使用,主要用来遍历所有模块并执行一些处理工作。
结合前面所讲,camera各模块都具有统一的接口,通过流来连接,模块中又包含模块,根据这种特性高通使用链表结构来保存这些模块并设计了此函数用来完成遍历操作。
1.先来看看此链表的节点结构。
链表的节点其实也是一个链表,整个链表就好像是一串串同级的节点搭建而成,整个数据结构组成一颗树结构。
struct _mct_list {void *data; // 节点数据mct_list_t *prev; // 上一个节点地址mct_list_t **next; // 下一个节点节点元素数组首地址uint32_t next_num; // 下一个节点节点元素数,大部分情况下为1}mct_list_t;2.通过递归的深度优先算法来遍历整棵树。
4.MCT线程运行MCT整个引擎部分主要处理server及bus两类事情,对应前面提到的MCT及bus两个线程。
MCT线程主要用来处理来自image server的消息,先pop MCT queue,查看是否有消息,如果有则执行mct_controller_proc_serv_msg_internal()函数来处理。
mct_controller_proc_serv_msg_internal函数用来处理来自image server的消息,并返回类型MCT_PROCESS_RET_SERVER_MSG。
这里处理的消息类型主要有SERV_MSG_DS与SERV_MSG_HAL两种,分别在pipline中给出了相应的处理函数,具体查看源码可知。
5.bus线程运行bus线程跟MCT线程流程一样。
从代码上我们看到两个线程都是从同一个queue上面pop消息,他们是通过各自的线程条件变量来进行区分,完成线程的阻塞及运行工作。
MCT的条件变量mctl_cond可以看到是在server_process.c文件中标记的,而bus的条件变量mctl_bus_handle_cond未在源码中找到标志的位置?。