**

camera驱动&系统流程整理

**

根据上面要求进行深度整理(主要针对msm8909 高通平台)

目录
一 camera 驱动需要弄明白 2
1 需要获取到的资料 2
2 点亮过程、dtsi 中需要添加什么 2
3 读取摄像头 ID 2
4 驱动分层 2
5 V4L2 架构,video* 节点进行读取 2
二 camera系统需要弄明白 2
1 mm_camera层详细分析—- 画流程图 2
2 dev/video*的读取 2
3 HAL层流程——预览、拍照、录像 画图分析 2
4 导致预览、拍照、录像 花屏、黑屏的原因有哪些,举例说明 2
5 framework 层的工作、AIDL相关、进程间的通信 2
6 算法的移植过程,与APP层的交互 画图分析 2
7 清晰度算法 —— 画图分析 2

一 camera 驱动需要弄明白

1 需要获取到的资料
Sensor datasheet、原理图、模组规格书 三份资料
datasheet和原理图可以知道sensor电源(AVDD、IOVDD、DVDD)、控制讯号(reset、POWERDOWN)、通信方式(I2C通信、CLK、DATA线)、数据通信(MIPI、CLK、lane数)、其他信号(sensor_ID_PIN、MCLK、GND)
原理图和模组规格书可以知道——调焦马达(AF_VDD、AF_EN、I2C、GND)和闪光灯(I2C、GPIO)支持

2 点亮过程、dtsi 中需要添加什么

从下面代码可以知道,分为两大部分——soc 和 i2c部分,其中 soc中是关于闪光灯支持,i2c中添加 马达、eeprom 和sensor 三部分
包含供电配置、GPIO添加、I2C地址这些填进来

&soc {

flash_SY7803:flashlight {compatible = "qcom,leds-gpio-flash";status = "okay";pinctrl-names = "flash_default";pinctrl-0 = ;qcom,flash-en = ;qcom,flash-now = ;qcom,op-seq = "flash_en", "flash_now";qcom,torch-seq-val = ;qcom,flash-seq-val = ;linux,name = "flashlight";linux,default-trigger = "flashlight-trigger";};led_flash0: qcom,camera-led-flash {cell-index = ;compatible = "qcom,camera-led-flash";qcom,flash-type = ;qcom,flash-source = ;qcom,torch-source = ;};

};

&i2c_3 {

actuator0: qcom,actuator@0 {cell-index = ;reg = ;compatible = "qcom,actuator";qcom,cci-master = ;cam_vaf-supply = ;qcom,cam-vreg-name = "cam_vaf";qcom,cam-vreg-type = ;qcom,cam-vreg-min-voltage = ;qcom,cam-vreg-max-voltage = ;qcom,cam-vreg-op-mode = ;pinctrl-names = "cam_sn_default", "cam_sn_suspend";pinctrl-0 = ;pinctrl-1 = ;//qcom,gpio-led = ;qcom,gpio-moto-cw = ;qcom,gpio-moto-en = ;qcom,gpio-moto-clk = ;};eeprom0: qcom,eeprom@6d{cell-index = ;reg = ;qcom,eeprom-name = "wdsen_ov5670";compatible = "qcom,eeprom";qcom,slave-addr = ;clocks = ,;clock-names = "cam_src_clk", "cam_clk";};qcom,camera@0 {cell-index = ;compatible = "qcom,camera";reg = ;//qcom,special-support-sensors="ov5670_wdsen";qcom,eeprom-src = ;qcom,csiphy-sd-index = ;qcom,csid-sd-index = ;qcom,mount-angle = ;qcom,actuator-src = ;qcom,led-flash-src = ;cam_vana-supply = ;cam_vio-supply = ;cam_vdig-supply = ;cam_vaf-supply = ;qcom,cam-vreg-name = "cam_vio", "cam_vana","cam_vdig","cam_vaf";qcom,cam-vreg-type = ;qcom,cam-vreg-min-voltage = ;qcom,cam-vreg-max-voltage = ;qcom,cam-vreg-op-mode = ;pinctrl-names = "cam_default", "cam_suspend";pinctrl-0 = ;pinctrl-1 = ;gpios = ,,;qcom,gpio-reset = ;qcom,gpio-standby = ;qcom,gpio-req-tbl-num = ;qcom,gpio-req-tbl-flags = ;qcom,gpio-req-tbl-label = "CAMIF_MCLK","CAM_RESET1","CAM_STANDBY";qcom,sensor-position = ;qcom,sensor-mode = ;qcom,cci-master = ;status = "ok";clocks = ,;clock-names = "cam_src_clk", "cam_clk";};qcom,camera@1 {cell-index = ;compatible = "qcom,camera";reg = ;//qcom,special-support-sensors="ov2680_wdsen";qcom,csiphy-sd-index = ;qcom,csid-sd-index = ;qcom,mount-angle = ;cam_vana-supply = ;cam_vio-supply = ;qcom,cam-vreg-name = "cam_vio", "cam_vana";qcom,cam-vreg-type = ;qcom,cam-vreg-min-voltage = ;qcom,cam-vreg-max-voltage = ;qcom,cam-vreg-op-mode = ;pinctrl-names = "cam_default", "cam_suspend";pinctrl-0 = ;pinctrl-1 = ;gpios = ,,;qcom,gpio-reset = ;qcom,gpio-standby = ;qcom,gpio-req-tbl-num = ;qcom,gpio-req-tbl-flags = ;qcom,gpio-req-tbl-label = "CAMIF_MCLK","CAM_RESET","CAM_STANDBY";qcom,cci-master = ;status = "ok";clocks = ,;clock-names = "cam_src_clk", "cam_clk";};

};

3 读取摄像头 ID
Qcom,slave-id = 包含i2c地址、设备ID地址和预计的ID读取值
4 驱动分层
1)Msm_sensor_power_setting结构体,设置上电时序及电压
2)Eeprom 信息
3)有AF需要添加actuator 节点信息

第二就是vendor 下面的代码,也分为两部分,
一个是 sensor_libs目录下的sensor具体设定,主要是实现V4L2结构,进行V4L2的设备注册、I2C设备注册
https://blog.csdn.net/u014517638/article/details/73349385

另一个就是 ISP 效果文件

Vendor 就是高通自己实现的 daemon 进程,用于和kernel 以及hal 层进行通讯的框架代码,另一部分就是效果代码,在此目录下有 media-controller,server-tuning,server-imaging,我们需要关注的是 mediacontroller 目录,整个树形结构如下:

5 V4L2 架构,video* 节点进行读取
分为两部分,一个是 系统 V4L2代码,一个是具体sensor 驱动实现v4l2子设备相关结构体的代码,然后 在mm_camera 就会通过 dev/video*来 open 读取到 sensor 相关操作的
有关驱动中的 buffer 是怎么传到应用程序的请看
https://blog.csdn.net/yanbixing123/article/details/52294305

二 camera系统需要弄明白

1 mm_camera层详细分析—- 画流程图

https://www.jianshu.com/p/1baad2a5281d
Mm_camera主要用到5个文件

Mm_camera_interface.c 这是暴露给HAL 层调用的接口
Mm_camera.c 这是中枢部分
Mm_camera_channel.c 这是mm层 channel (通道)
Mm_camera_stream.c 这是mm层stream (流)
Mm_camera_thread.c 这是任务调度的关键部分

这里面使用的C语言写的,可以相互引用,实际上也是相互引用的(通过结构体),通过调用对应文件里方法要传参对应 结构体 的方法可以完成类似面向对象的组织方式

对应成员的具体代表意义可以看 mm_camera.h 头文件说明

下面具体说一下相关 ****.c 文件
A: mm_camera_interface.c
这里通过mm_camera_ops_t 这个结构体来暴露给 HAL 层调用,主要是注册函数指针与函数的映射关系,
static mm_camera_ops_t mm_camera_ops = {
.query_capability = mm_camera_intf_query_capability,
.register_event_notify = mm_camera_intf_register_event_notify,
.close_camera = mm_camera_intf_close,
.set_parms = mm_camera_intf_set_parms,
.get_parms = mm_camera_intf_get_parms,
.do_auto_focus = mm_camera_intf_do_auto_focus,
.cancel_auto_focus = mm_camera_intf_cancel_auto_focus,
.prepare_snapshot = mm_camera_intf_prepare_snapshot,
.start_zsl_snapshot = mm_camera_intf_start_zsl_snapshot,
.stop_zsl_snapshot = mm_camera_intf_stop_zsl_snapshot,
.map_buf = mm_camera_intf_map_buf,
.unmap_buf = mm_camera_intf_unmap_buf,
.add_channel = mm_camera_intf_add_channel,
.delete_channel = mm_camera_intf_del_channel,
.get_bundle_info = mm_camera_intf_get_bundle_info,
.add_stream = mm_camera_intf_add_stream,
.link_stream = mm_camera_intf_link_stream,
.delete_stream = mm_camera_intf_del_stream,
.config_stream = mm_camera_intf_config_stream,
.qbuf = mm_camera_intf_qbuf,
.get_queued_buf_count = mm_camera_intf_get_queued_buf_count,
.map_stream_buf = mm_camera_intf_map_stream_buf,
.unmap_stream_buf = mm_camera_intf_unmap_stream_buf,
.set_stream_parms = mm_camera_intf_set_stream_parms,
.get_stream_parms = mm_camera_intf_get_stream_parms,
.start_channel = mm_camera_intf_start_channel,
.stop_channel = mm_camera_intf_stop_channel,
.request_super_buf = mm_camera_intf_request_super_buf,
.cancel_super_buf_request = mm_camera_intf_cancel_super_buf_request,
.flush_super_buf_queue = mm_camera_intf_flush_super_buf_queue,
.configure_notify_mode = mm_camera_intf_configure_notify_mode,
.process_advanced_capture = mm_camera_intf_process_advanced_capture
};
左边是暴露给HAL 层调用的,右边是在自己里面定义的函数, 注意调用每个函数都要传入camera的句柄 camera_handle(cameraopen 的时候生成的 int 数字),通过mm_camera_util_get_camera_by_handler 获取对应的 mm_camera 结构体(一个手机有多个camera 设备),其中 interface里的每个方法也是调用mm_camera里对应的方法

这里面 Open camera
mm_camera_vtbl_t * camera_open(uint8_t camera_idx)
按相机索引打开相机 index

HAL3 打开接口
int32_t camera_open(uint8_t camera_idx, mm_camera_vtbl_t **camera_vtbl)

B: mm_camera.c
这个文件主要是产生和管理 channel, 然后配置管理 stream ,然后也定义了一些事件回调来处理事件,直接扫描到 dev/video**
Mm_camera和mm_channel 的沟通方式是调用 mm_channel 的状态机方法
在open camera 时候会开启 mm_thread.c 里面定义的两个线程:
Cmd_thread 和 poll_thread

Poll_thread 是一个很关键的线程,最后获取数据也是靠这个线程,但是开启这个线程不用来处理数据的,而是用来处理 kernel 返回的 event, 比如相机挂了这类问题
kernel的event 会通过poll_thread 回调 mm_camera_event_notify 传达到 mm_camera层,然后mm_camera会给 cmd_thread 发送相应命令,然后回调 mm_camera_dispatch_app_event,最后会回调到 HAL 层 QCamera3HardInterface的 camEvtHandle方法

int32_t mm_camera_open(mm_camera_obj_t *my_obj)
{

const char *temp_dev_name = mm_camera_util_get_dev_name(my_obj->my_hdl);

strlcpy(t_devname, temp_dev_name, sizeof(t_devname));
snprintf(dev_name, sizeof(dev_name), “/dev/%s”,t_devname );
sscanf(dev_name, “/dev/video%d”, &cam_idx);
CDBG_ERROR(“%s: dev name = %s, cam_idx = %d”, func, dev_name, cam_idx);

CDBG(“%s : Launch evt Thread in Cam Open”,func);
snprintf(my_obj->evt_thread.threadName, THREAD_NAME_SIZE, “CAM_Dispatch”);
mm_camera_cmd_thread_launch(&my_obj->evt_thread,
mm_camera_dispatch_app_event,
(void *)my_obj);

/* launch event poll thread * we will add evt fd into event poll thread upon user first register for evt */CDBG("%s : Launch evt Poll Thread in Cam Open", __func__);snprintf(my_obj->evt_thread.threadName, THREAD_NAME_SIZE, "CAM_Poll");mm_camera_poll_thread_launch(&my_obj->evt_poll_thread,                             MM_CAMERA_POLL_TYPE_EVT);mm_camera_evt_sub(my_obj, TRUE);

C:mm_camera_channel

D: mm_camera_stream

E: mm_camera_thread

最后用流程图进行进行完整的 mm_camera 总结:

2 dev/video*的读取

Mm_camera.c 中在 open camera 中调用
int32_t mm_camera_open(mm_camera_obj_t *my_obj)
{

strlcpy(t_devname, temp_dev_name, sizeof(t_devname));
snprintf(dev_name, sizeof(dev_name), “/dev/%s”,t_devname );
sscanf(dev_name, “/dev/video%d”, &cam_idx);
CDBG_ERROR(“%s: dev name = %s, cam_idx = %d”, func, dev_name, cam_idx);

3 HAL层流程——预览、拍照、录像 画图分析

A: 预览参考
https://www.jianshu.com/p/02772c83dc35

B: 拍照参考
https://www.jianshu.com/p/a70bf4620087

4 导致预览、拍照、录像 花屏、黑屏的原因有哪些,举例说明
A: 打开闪退,调用到马达时候闪退重启,
B:
5 framework 层的工作、AIDL相关、进程间的通信

Camera 从 framework到HAL
Camera2 数据流从framework到Hal源码分析
https://www.jianshu.com/p/ecb1be82e6a8

6 算法的移植过程,与APP层的交互 画图分析

7 清晰度算法 —— 画图分析