【高通SDM660平台 Android 10.0】Qcom Camera Daemon 代码分析
- 一、mm-qcamera-daemon 进程
- 1.1 server.c
- 1.1.1 Sensor模块初始化 module_sensor_init()
- 1.1.2 Iface模块初始化 module_iface_init()
- 1.1.3 ISP模块初始化 module_isp_init()
- 1.1.4 Stats模块初始化 stats_module_init()
- 1.1.5 Pproc模块初始化 pproc_module_init()
- 1.1.6 Imglib模块初始化 module_imglib_init()
《【高通SDM660平台】(1) — Camera 驱动 Bringup Guide》
《【高通SDM660平台】(2) — Camera Kernel 驱动层代码逻辑分析》
《【高通SDM660平台】(3) — Camera V4L2 驱动层分析 》
《【高通SDM660平台】(4) — Camera Init 初始化流程 》
《【高通SDM660平台】(5) — Camera Open 流程》
《【高通SDM660平台】(6) — Camera getParameters 及 setParameters 流程》
《【高通SDM660平台】(7) — Camera onPreview 代码流程》
《【高通SDM660平台】(8) — Camera MetaData介绍》
《【高通SDM660平台 Android 10.0】(9) — Qcom Camera Daemon 代码分析》
《【高通SDM660平台 Android 10.0】(10) — Camera Sensor lib 与 Kernel Camera Probe 代码分析》
《【高通SDM660平台 Android 10.0】(11) — Eeprom lib 与 Kernel eeprom代码分析》
《【高通SDM660平台 Android 10.0】(12) — Camera Chromatix 代码分析》
《【高通SDM660平台】Camera Capture 流程》
《【高通SDM660平台】Camera mm-qcamera-app 代码分析》
《【高通SDM660平台 Android 10.0】 — 高通马达、eeprom、flash 等外设代码分析》
前面我都是在Android 8.0 的代码上分析的,前两天,我刚下载好一套高通SDM660 Android 10.0 的源码,
所以后续,我们分析代码都是在 10.0 上分析。
好,废话不多说,我们来看下 Camera Sensor Daemon吧。
高通camera把sensor端底层设置、ISP效果参数、chomatix等进行了单独的剥离,放在daemon进程中进行。
一、mm-qcamera-daemon 进程
其代码位于/vendor/qcom/proprietary/mm-camera/mm-camera2/server-imaging/Android.mk
LOCAL_SRC_FILES:= server.c \
server_process.c
LOCAL_SHARED_LIBRARIES:= libcutils libdl libmmcamera2_mct \
libmmcamera2_stats_modules \
libmmcamera2_iface_modules \
libmmcamera2_isp_modules \
libmmcamera2_sensor_modules \
libmmcamera2_pproc_modules \
libmmcamera2_imglib_modules \
libmmcamera_dbg
LOCAL_MODULE:= mm-qcamera-daemon
可以看出,mm-qcamera-daemon
是包含sensor、iface、isp、stats、pproc、imglib 这几个模块的。
@ /device/qcom/sdm660_64/init.target.rc
#start camera server as daemon
service qcamerasvr /system/bin/mm-qcamera-daemon
class late_start
user camera
group camera system inet input graphics
1.1 server.c
我们先来看下 server.c
代码
主要工作如下:
-
开启 Camera Debug 功能
-
打开/dev/media0 获取msm_config 对应的V4L2的 entity名字
-
打开节点, /dev/video0
-
将当前打开节点,添加到 监听列表 中
-
开始初始化sensor 模块,此时会下发 probe camera sensor 命令
-
开始初始化其余的模块 包括 iface、isp、stats、pproc、imglib。
分别调用module_iface_init
、module_isp_init
、stats_module_init
、pproc_module_init
、module_imglib_init
初始化完毕后,添加到mct_list列表中 -
依次下发如下 V4L2 命令,测试是否成功
-
创建定时器,供后续监测超时使用
-
寻找初始化完毕的 V4L2 节点的
MSM_CAMERA_SUBDEV_SENSOR_INIT
类型设备, 对应的 msm_sensor_init -
打开节点
-
下发 sensor_init
VIDIOC_MSM_SENSOR_INIT_CFG
命令,cfgtype= CFG_SINIT_PROBE_DONE
-
通过 select 监听已经打开的v4l2 节点的事件
@ /vendor/qcom/proprietary/mm-camera/mm-camera2/server-imaging/server.c
int main(int argc __unused, char *argv[] __unused)
{
old_mode = umask(S_IRWXO);
// 1. 开启 Camera Debug 功能
cam_debug_open();
CLOGD(CAM_MCT_MODULE, "CAMERA_DAEMON: start of camera Daemon.");
/* 1. find server node name and open the node */
// 2. 打开/dev/media0 获取msm_config 对应的V4L2的 entity名字
get_server_node_name(serv_hal_node_name);
CLOGD(CAM_MCT_MODULE, "after get_server_node_name");
hal_fd = malloc(sizeof(read_fd_info_t));
// 3. 打开节点, /dev/video0
snprintf(dev_name, sizeof(dev_name), "/dev/%s", serv_hal_node_name);
hal_fd->fd[0] = open(dev_name, O_RDWR | O_NONBLOCK);
// 4. 将当前打开节点,添加到 监听列表 中
hal_fd->type = RD_FD_HAL;
listen_fd_list = mct_list_append(listen_fd_list, hal_fd, NULL, NULL);
property_get("vendor.camera.cameradaemon.SaveMemAtBoot", savemem, "0");
enabled_savemem = atoi(savemem);
CLOGD(CAM_MCT_MODULE, "CAMERA_DAEMON: start all modules init");
// 5. 开始初始化sensor 模块,此时会下发 probe camera sensor 命令
/* 2. after open node, initialize modules */
server_process_module_sensor_init();
========================>
+ @/vendor/qcom/proprietary/mm-camera/mm-camera2/server-imaging/server_process.c
+ CLOGD(CAM_MCT_MODULE, "CAMERA_DAEMON: Begin sensor init mods");
+
+ temp = modules_list[0].init_mod(modules_list[0].name);
+ if (temp) {
+ modules_list[0].module = temp;
+ modules = mct_list_append(modules, temp, NULL, NULL));
+ }
+ --------------->
+ @ /mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor.c
+ mct_module_t *module_sensor_init(const char *name)
+ <---------------
+ CLOGD(CAM_MCT_MODULE, "CAMERA_DAEMON: sensor init mods done");
<========================
CLOGD(CAM_MCT_MODULE, "CAMERA_DAEMON:End of all modules init");
// 6. 开始初始化其余的模块 包括 iface、isp、stats、pproc、imglib。
if (enabled_savemem != 1) {
server_process_module_init();
============================>
// mm-camera/mm-camera2/server-imaging/server_process.c
// 分别调用 module_iface_init、module_isp_init、stats_module_init、pproc_module_init、module_imglib_init
// 初始化完毕后,添加到mct_list列表中。
for (i = 1; i < (int)(sizeof(modules_list)/sizeof(mct_module_init_name_t)); i++) {
CLOGD(CAM_MCT_MODULE, "CAMERA_DAEMON: module name : %s: E", modules_list[i].name);
temp = modules_list[i].init_mod(modules_list[i].name);
CLOGD(CAM_MCT_MODULE, "CAMERA_DAEMON: module name : %s: X", modules_list[i].name);
if (temp) {
modules_list[i].module = temp;
(modules = mct_list_append(modules, temp, NULL, NULL));
}
modules_all = mct_list_append(modules_all, temp, NULL, NULL);
}
} /* for */
<============================
}
// 7. 依次下发如下 V4L2 命令,测试是否成功
/* Subcribe V4L2 event */
// /* event id */
#define MSM_CAMERA_EVENT_MIN 0
#define MSM_CAMERA_NEW_SESSION (MSM_CAMERA_EVENT_MIN + 1)
#define MSM_CAMERA_DEL_SESSION (MSM_CAMERA_EVENT_MIN + 2)
#define MSM_CAMERA_SET_PARM (MSM_CAMERA_EVENT_MIN + 3)
#define MSM_CAMERA_GET_PARM (MSM_CAMERA_EVENT_MIN + 4)
#define MSM_CAMERA_MAPPING_CFG (MSM_CAMERA_EVENT_MIN + 5)
#define MSM_CAMERA_MAPPING_SES (MSM_CAMERA_EVENT_MIN + 6)
#define MSM_CAMERA_MSM_NOTIFY (MSM_CAMERA_EVENT_MIN + 7)
#define MSM_CAMERA_EVENT_MAX (MSM_CAMERA_EVENT_MIN + 8)
memset(&subscribe, 0, sizeof(struct v4l2_event_subscription));
subscribe.type = MSM_CAMERA_V4L2_EVENT_TYPE;
for (i = MSM_CAMERA_EVENT_MIN + 1; i < MSM_CAMERA_EVENT_MAX; i++) {
subscribe.id = i;
ioctl(hal_fd->fd[0], VIDIOC_SUBSCRIBE_EVENT, &subscribe);
}
signal_received = 0;
select_fds.select_fd = hal_fd->fd[0];
/* create a timer */
// 8. 创建定时器,供后续监测超时使用
mct_t_ret = mct_util_create_timer();
// 9. 寻找初始化完毕的 V4L2 节点的 MSM_CAMERA_SUBDEV_SENSOR_INIT 类型设备, 对应的 msm_sensor_init
ret_subdev = mct_util_find_v4l2_subdev(probe_done_node_name);
// 10. 打开节点
snprintf(probe_done_dev_name, sizeof(probe_done_dev_name), "/dev/%s", probe_done_node_name);
probe_done_fd = open(probe_done_dev_name, O_RDWR | O_NONBLOCK);
// 11. 下发 sensor_init VIDIOC_MSM_SENSOR_INIT_CFG 命令, cfgtype= CFG_SINIT_PROBE_DONE
cfg.cfgtype = CFG_SINIT_PROBE_DONE;
if (ioctl(probe_done_fd, VIDIOC_MSM_SENSOR_INIT_CFG, &cfg) < 0) {
CLOGE(CAM_MCT_MODULE, "ioctl SENSOR_INIT_CFG failed");
ret = FALSE;
}
close(probe_done_fd);
CLOGD(CAM_MCT_MODULE, "CAMERA_DAEMON:waiting for camera to open");
do {
// 12. 通过 select 监听已经打开的v4l2 节点的事件
FD_ZERO(&(select_fds.fds));
mct_list_traverse(listen_fd_list, server_reset_select_fd, &select_fds);
/* no timeout */
ret = select(select_fds.select_fd + 1, &(select_fds.fds), NULL, NULL, NULL);
// 13.
if (ret > 0) {
find_list = mct_list_find_custom(listen_fd_list, &(select_fds.fds), server_check_listen_fd);
fd_info = (read_fd_info_t *)find_list->data;
switch (fd_info->type) {
case RD_FD_HAL: { // 13. 将消息发送到MCT
if (ioctl(fd_info->fd[0], VIDIOC_DQEVENT, &event) < 0) {
continue;
}
/* server process HAL event:
*
* 1. if it returns success, it means the event message has been
* posted to MCT, don't need to send CMD ACK back to kernel
* immediately, because MCT will notify us after process;
*
* 2. if it returns failure, it means the event message was not
* posted to MCT successfully, hence we need to send CMD ACK back
* to kernel immediately so that HAL thread which sends this
* event can be blocked.
*/
proc_ret = server_process_hal_event(&event);
}break;
case RD_DS_FD_HAL:
/* server process message sent by HAL through Domain Socket */
proc_ret = server_process_hal_ds_packet(fd_info->fd[0], fd_info->session);
break;
case RD_PIPE_FD_MCT:
/* server process message sent by media controller through pipe: */
proc_ret = server_process_mct_msg(fd_info->fd[0],d_info->session);
break;
} /* switch (fd_info->type) */
switch (proc_ret.result) {
case RESULT_NEW_SESSION: {
struct msm_v4l2_event_data *ret_data = (struct msm_v4l2_event_data *)proc_ret.ret_to_hal.ret_event.u.data;
if( ret_data->status == MSM_CAMERA_CMD_SUCCESS) {
num_sessions++;
hal_ds_fd = malloc(sizeof(read_fd_info_t));
hal_ds_fd->session = proc_ret.new_session_info.session_idx;
hal_ds_fd->fd[0] = proc_ret.new_session_info.hal_ds_fd;
hal_ds_fd->type = RD_DS_FD_HAL;
mct_fds = malloc(sizeof(read_fd_info_t));
mct_fds->session = proc_ret.new_session_info.session_idx;
mct_fds->fd[0] = proc_ret.new_session_info.mct_msg_rd_fd;
mct_fds->fd[1] = proc_ret.new_session_info.mct_msg_wt_fd;
mct_fds->type = RD_PIPE_FD_MCT;
}
listen_fd_list = mct_list_append(listen_fd_list,hal_ds_fd,NULL,NULL);
listen_fd_list = mct_list_append(listen_fd_list, mct_fds, NULL,NULL);
if (!listen_fd_list) {
free(hal_ds_fd);
free(mct_fds);
goto server_proc_new_session_error;
}
} else {
CLOGE(CAM_MCT_MODULE, "New session [%d] creation failed with error", ret_data->session_id);
}
if (TRUE == server_register_for_kill_signal(&default_sa)) {
is_signal_registered = TRUE;
}
if (num_sessions == 1) {
if (TRUE == server_register_timer_cb(&timer_id)) {
is_timer_cb_registered = TRUE;
}
}
goto check_proc_ret;
} /* RESULT_NEW_SESSION */
break;
case RESULT_DEL_SESSION: { ......} goto check_proc_ret; break;
case RESULT_FAILURE: goto server_proc_error; break;
case RESULT_SUCCESS: goto check_proc_ret; break;
} /* switch (proc_ret.result) */
return 0;
}
1.1.1 Sensor模块初始化 module_sensor_init()
- 初始化一个 mct_module 类型结构体,填充sensor ssession 操作方法
- EEPROM BIN 初始化
- 获取eeprom bin 数据
- 初始化Camera Sensor,此时会开始下发 probe 命令
- 寻找现有的外设
- 外设
func_tbl
结构体函数初始化,获取各个外设的 open,procexx,close 方法 - 创建外设 port 端口
- 加载eeprom lib 库,初始化 eeprom
@ /vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor.c
/** module_sensor_init: sensor module init
* Return: mct_module_t pointer corresponding to sensor
* This function creates mct_module_t for sensor module,
* creates port, fills capabilities and add it to the sensor module **/
mct_module_t *module_sensor_init(const char *name)
{
mct_module_t *s_module = NULL;
module_sensor_ctrl_t *module_ctrl = NULL;
SHIGH("Sensor driver Version: %s", SENSOR_DRIVER_VERSION); // "2.15.0"
SHIGH("Sensor SDK capabilities: %s", SENSOR_SDK_CAPABILITIES);
SHIGH("Actuator driver Version: %s", ACTUATOR_DRIVER_VERSION); // "1.0.0"
SHIGH("Actuator SDK capabilities: %s", ACTUATOR_SDK_CAPABILITIES);// "VCM, PIEZO, HVCM, BIVCM"
SHIGH("EEPROM driver Version: %s", EEPROM_DRIVER_VERSION); // "2.3.0"
SHIGH("EEPROM SDK capabilities: %s", EEPROM_SDK_CAPABILITIES);
SHIGH("Flash driver Version: %s", FLASH_DRIVER_VERSION); // "1.0.0"
SHIGH("Flash SDK capabilities: %s", FLASH_SDK_CAPABILITIES);
SHIGH("OIS driver Version: %s", OIS_DRIVER_VERSION); // "1.2.1"
SHIGH("OIS SDK capabilities: %s", OIS_SDK_CAPABILITIES);
SHIGH("PDAF driver Version: %s", PDAF_DRIVER_VERSION); // "2.3.3"
SHIGH("PDAF SDK capabilities: %s", PDAF_SDK_CAPABILITIES);
/* Create MCT module for sensor */
// 1. 初始化一个 mct_module 类型结构体,填充sensor ssession 操作方法
s_module = mct_module_create(name);
/* Fill function table in MCT module */
s_module->set_mod = module_sensor_set_mod;
s_module->query_mod = module_sensor_query_mod;
s_module->start_session = module_sensor_start_session;
s_module->stop_session = module_sensor_stop_session;
s_module->set_session_data = module_sensor_set_session_data;
s_module->get_session_data = module_sensor_get_session_data;
/* Create sensor module control structure that consists of bundle information */
module_ctrl = malloc(sizeof(module_sensor_ctrl_t));
memset(module_ctrl, 0, sizeof(module_sensor_ctrl_t));
s_module->module_private = (void *)module_ctrl;
/* sensor module doesn't have sink port */
s_module->numsinkports = 0;
// 2. EEPROM BIN 初始化
rc = eebin_interface_init(&module_ctrl->eebin_hdl);
// 3. 获取eeprom bin 数据
bin_ctl.cmd = EEPROM_BIN_GET_BIN_DATA;
rc = eebin_interface_control(module_ctrl->eebin_hdl, &bin_ctl);
=============>
eebin_get_bin_data(ctrl);
<=============
// 4. 初始化Camera Sensor
/* module_sensor_probe_sensors */
ret = sensor_init_probe(module_ctrl);
=============>
RETURN_ON_FALSE(sensor_init_xml_probe(module_ctrl, sd_fd));
<=============
// 5. 寻找现有的外设
/* find all the actuator, etc with sensor */
ret = module_sensor_find_other_subdev(module_ctrl);
// 6. 外设func_tbl结构体函数初始化,获取各个外设的 open,procexx,close 方法
/* Init sensor modules */
ret = mct_list_traverse(module_ctrl->sensor_bundle, module_sensors_subinit, NULL);
// 7. 创建外设 port 端口
/* Create ports based on CID info */
ret = mct_list_traverse(module_ctrl->sensor_bundle, port_sensor_create, s_module);
// 8. 加载eeprom lib 库,初始化 eeprom
/* intiialize the eeprom */
ret = mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_init_eeprom, module_ctrl->eebin_hdl);
// 9. 初始化 chromatix
/* Create chromatix manager */
ret = mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_init_chromatix, module_ctrl->eebin_hdl);
/* Initialize dual cam stream mutex */
pthread_mutex_init(&module_ctrl->dual_cam_mutex, NULL);
SLOW("SUCCESS");
return s_module;
SERR("FAILED");
ERROR1:
mct_module_destroy(s_module);
return NULL;
}
1.1.1.1 Camera初始化 sensor_init_xml_probe()
- 拼凑
camera_config.xml
路径的字符串,/data/vendor/camera/camera_config.xml
- 打开
camera_config.xml
文件,找到CameraConfigurationRoot
节点 - 每个
CameraModuleConfig
对应着一个 Camera, 统计config 数量,供后续遍历使用 - 对每个Camera开始probe,下发sensor name,开始 probe ,例
sensor name=imx258
, 成功后保存在 slot_probed[] 数组中
@ mm-camera/mm-camera2/media-controller/modules/sensors/module/sensor_init.c
static boolean sensor_init_xml_probe(module_sensor_ctrl_t *module_ctrl, int32_t sd_fd)
{
/* Create the xml path from data partition */
// 1. 拼凑camera_config.xml 路径的字符串,/data/vendor/camera/camera_config.xml
snprintf(config_xml_name, BUFF_SIZE_255, "%s%s", CONFIG_XML_PATH, CONFIG_XML);
SHIGH("reading from file %s", config_xml_name);
// 2. 找到 CameraConfigurationRoot 节点
/* Get the Root pointer and Document pointer of XMl file */
ret = sensor_xml_util_load_file(config_xml_name, &docPtr, &rootPtr, "CameraConfigurationRoot");
// 3. 每个 CameraModuleConfig 对应着一个 Camera, 统计config 数量,供后续遍历使用
/* Get number of camera module configurations */
num_cam_config = sensor_xml_util_get_num_nodes(rootPtr, "CameraModuleConfig");
SLOW("num_cam_config = %d", num_cam_config);
xmlConfig.docPtr = docPtr;
xmlConfig.configPtr = &camera_cfg;
// 4. 对每个Camera下发probe 命令
for (i = 0; i < num_cam_config; i++) {
nodePtr = sensor_xml_util_get_node(rootPtr, "CameraModuleConfig", i);
xmlConfig.nodePtr = nodePtr;
ret = sensor_xml_util_get_camera_probe_config(&xmlConfig, "CameraModuleConfig");
// 4.1 如果该Camera 已经probe 过了,则直接 continue
if (slot_probed[camera_cfg.camera_id]) {
SHIGH("slot %d already probed", camera_cfg.camera_id);
continue;
}
// 4.2 下发sensor name开始 probe ,例sensor name=imx258, 成功后保存在 slot_probed[] 数组中
rc = sensor_probe(module_ctrl, sd_fd, camera_cfg.sensor_name, NULL, &xmlConfig, FALSE, FALSE);
slot_probed[camera_cfg.camera_id] = TRUE;
}
return ret;
}
1.1.1.1.1 触发Camera Probe初始化 sensor_probe()
- 根据xml 中解析的 sensor name, 查找并打开对应的 sensor lib 库,映射lib库方法,如果支持PDAF ,则加载 PDAF 的函数
- 获取 Camera Sensor 上下电配置
- 获取上电,下电配置
- 获取 Sensor 出图的数据类型 ,BAYER(RGB) Or YCBCR(YUV)
- 下发
CFG_SINIT_PROBE
,开始触发 Sensor Probe,传参 slave_info,包含上下电配置 - 解析该Camera 对应的 Lens info、CSI Info、chromatix info 信息
- 将该camera Sensor 和其他的相关的外设绑定在一起
@ mm-camera/mm-camera2/media-controller/modules/sensors/module/sensor_init.c
static boolean sensor_probe(module_sensor_ctrl_t *module_ctrl, int32_t fd,
const char *sensor_name, char *path, struct xmlCameraConfigInfo *xmlConfig,
boolean is_stereo_config, boolean bypass_video_node_creation)
{
sensor_lib_params_t *sensor_lib_params;
struct sensor_init_cfg_data cfg;
struct msm_camera_sensor_slave_info *slave_info = NULL;
struct msm_sensor_power_setting *power_up_setting = NULL;
struct msm_sensor_power_setting *power_down_setting = NULL;
struct camera_power_setting_array *power_setting_array;
sensor_lib_params = CAM_CALLOC(1, sizeof(sensor_lib_params_t));
// 1. 根据xml 中解析的 sensor name, 查找并打开对应的 sensor lib 库,例如 libmmcamera_imx258.so
/* Load sensor library */
rc = sensor_load_library(sensor_name, sensor_lib_params, path);
================>
@ mm-camera/mm-camera2/media-controller/modules/sensors/sensor/module/sensor.c
snprintf(lib_name, BUFF_SIZE_255, "libmmcamera_%s.so", name);
sensor_lib_params->sensor_lib_handle = dlopen(lib_name, RTLD_NOW);
*(void **)&sensor_open_lib = dlsym(sensor_lib_params->sensor_lib_handle,open_lib_str);
sensor_lib_params->sensor_lib_ptr = (sensor_lib_t *)sensor_open_lib();
// 如果支持PDAF ,则加载 PDAF 的函数
API_ptr->pdlib_get_defocus = dlsym(sensor_lib_params->sensor_lib_handle, API_name->pdaf_get_defocus_API);
API_ptr->pdlib_init = dlsym(sensor_lib_params->sensor_lib_handle, API_name->pdaf_init_API);
API_ptr->pdlib_deinit = dlsym(sensor_lib_params->sensor_lib_handle, API_name->pdaf_deinit_API);
API_ptr->sensor_custom_calc_defocus = dlsym(sensor_lib_params->sensor_lib_handle, sensor_lib_params->sensor_lib_ptr->sensorlib_pdaf_api.calcdefocus);
<================
// 2. 获取 Camera Sensor 上下电配置
power_setting_array = &sensor_lib_params->sensor_lib_ptr->sensor_slave_info. power_setting_array;
slave_info = (struct msm_camera_sensor_slave_info *)malloc(sizeof(*slave_info));
RETURN_ON_NULL(slave_info);
memset(slave_info, 0, sizeof(*slave_info));
power_up_setting = (struct msm_sensor_power_setting *)malloc( sizeof(*power_up_setting) * power_setting_array->size);
power_down_setting = (struct msm_sensor_power_setting *)malloc( sizeof(*power_down_setting) * power_setting_array->size_down);
// 3. 获取上电,下电配置
translate_sensor_slave_info(slave_info,
&sensor_lib_params->sensor_lib_ptr->sensor_slave_info,
xmlConfig->configPtr, power_up_setting, power_down_setting);
// 4. 获取 Sensor 出图的数据类型 ,BAYER(RGB) Or YCBCR(YUV)
/* Update the output format in slave info */
if (SENSOR_BAYER == sensor_lib_params->sensor_lib_ptr->sensor_output.output_format)
slave_info->output_format = MSM_SENSOR_BAYER;
else
slave_info->output_format = MSM_SENSOR_YCBCR;
// 5. 下发 CFG_SINIT_PROBE ,开始触发 Sensor Probe,传参 slave_info,包含上下电配置
// 有关 VIDIOC_MSM_SENSOR_INIT_CFG 见《【高通SDM660平台 Android 10.0】Camera Sensor lib 与 Kernel Camera Probe 代码分析》
/* Pass slave information to kernel and probe */
memset(&cfg, 0, sizeof(cfg));
cfg.cfgtype = CFG_SINIT_PROBE;
cfg.cfg.setting = slave_info;
ioctl(fd, VIDIOC_MSM_SENSOR_INIT_CFG, &cfg);
SLOW("[%s] probe succeeded: session_id(%d) entity_name(%s)", sensor_name, cfg.probed_info.session_id, cfg.entity_name);
// 6. 解析该Camera 对应的 Lens info、CSI Info、chromatix info 信息
ret = sensor_xml_util_get_camera_full_config(xmlConfig);
===========>
/* Read the Lens info */
RETURN_ON_FALSE(sensor_xml_util_get_lens_info(docPtr, nodePtr, configPtr));
/* Read the CSI info */
RETURN_ON_FALSE(sensor_xml_util_get_csi_info(docPtr, nodePtr, configPtr));
/* Read the chromatix info */
if (xmlStrlen((const xmlChar *)(configPtr->chromatix_name))) {
RETURN_ON_FALSE(sensor_xml_util_parse_chromatix_config(configPtr));
} else {
SHIGH(" No chromatix xml mentioned for %s", configPtr->sensor_name);
}
<===========
/* CSID core is taken from xml config file */
cfg.probed_info.subdev_id[SUB_MODULE_CSID] = xmlConfig->configPtr->camera_csi_params.csid_core;
// 7. 将该camera Sensor 和其他的相关的外设绑定在一起,保存在 sensor_bundle 结构体中
sensor_create_sbundle(module_ctrl,
&cfg.probed_info,
cfg.entity_name,
xmlConfig->configPtr,
sensor_lib_params,
is_stereo_config,
bypass_video_node_creation);
return ret;
}
1.1.1.2 寻找现有的外设 module_sensor_find_other_subdev()
- 打开 /dev/media0 节点,下发 MEDIA_IOC_DEVICE_INFO 获取的设备信息,匹配找到“msm_config”
- 循环遍历,将所有的外设的类型,id,name 均保存在 module_ctrl->sensor_bundle 中
@ mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor.c
static boolean module_sensor_find_other_subdev(module_sensor_ctrl_t *module_ctrl)
{
while (1) {
// 1. 打开 /dev/media0 节点,下发 MEDIA_IOC_DEVICE_INFO 获取的设备信息,匹配找到“msm_config”
snprintf(dev_name, sizeof(dev_name), "/dev/media%d", num_media_devices);
dev_fd = open(dev_name, O_RDWR | O_NONBLOCK);
SLOW("Opened Device %s",dev_name);
num_media_devices++;
rc = LOG_IOCTL(dev_fd, MEDIA_IOC_DEVICE_INFO, &mdev_info, "dev_info");
if (strncmp(mdev_info.model, "msm_config", sizeof(mdev_info.model)) != 0) {
close(dev_fd);
continue;
}
// 2. 循环遍历,将所有的外设的类型,id,name 均保存在 module_ctrl->sensor_bundle 中
while (1) {
struct media_entity_desc entity;
memset(&entity, 0, sizeof(entity));
entity.id = num_entities | MEDIA_ENT_ID_FLAG_NEXT;
SLOW("entity id %d", entity.id);
rc = LOG_IOCTL(dev_fd, MEDIA_IOC_ENUM_ENTITIES, &entity, "enum_entities");
num_entities = entity.id;
SLOW("entity name %s type %x group id %d", entity.name, entity.type, entity.group_id);
subdev_type = entity.type;
if (subdev_type == MSM_CAMERA_SUBDEV_ACTUATOR ||
subdev_type == MSM_CAMERA_SUBDEV_EEPROM ||
subdev_type == MSM_CAMERA_SUBDEV_FLASH ||
subdev_type == MSM_CAMERA_SUBDEV_STROBE_FLASH ||
subdev_type == MSM_CAMERA_SUBDEV_CSIPHY ||
subdev_type == MSM_CAMERA_SUBDEV_CSID ||
subdev_type == MSM_CAMERA_SUBDEV_OIS ||
subdev_type == MSM_CAMERA_SUBDEV_EXT ||
subdev_type == MSM_CAMERA_SUBDEV_IR_LED ||
subdev_type == MSM_CAMERA_SUBDEV_IR_CUT ||
subdev_type == MSM_CAMERA_SUBDEV_LASER_LED) {
snprintf(subdev_name, sizeof(subdev_name), "/dev/%s", entity.name);
SLOW("sensor subdev %s", subdev_name);
sd_fd = open(subdev_name, O_RDWR);
/* Read subdev index */
rc = LOG_IOCTL(sd_fd, VIDIOC_MSM_SENSOR_GET_SUBDEV_ID, &subdev_id, "subdev_id");
SLOW("subdev_name %s subdev id %d", subdev_name, subdev_id);
/* TODO: read id and fill in sensor_bundle.entity.actuator_name */
switch (subdev_type) {
case MSM_CAMERA_SUBDEV_ACTUATOR:
match_id_params.sub_module = SUB_MODULE_ACTUATOR;
match_id_params.subdev_id = subdev_id;
match_id_params.subdev_name = entity.name;
SLOW("SUB_MODULE_ACTUATOR subdev_name %s subdev_id %d",subdev_name, match_id_params.subdev_id);
mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_set_sub_module_id, &match_id_params);
break;
case MSM_CAMERA_SUBDEV_EEPROM:
match_id_params.sub_module = SUB_MODULE_EEPROM;
match_id_params.subdev_id = subdev_id;
match_id_params.subdev_name = entity.name;
SLOW("SUB_MODULE_EEPROM subdev_name %s subdev_id %d", subdev_name, match_id_params.subdev_id);
mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_set_sub_module_id, &match_id_params);
break;
case MSM_CAMERA_SUBDEV_FLASH:
match_id_params.sub_module = SUB_MODULE_LED_FLASH;
match_id_params.subdev_id = subdev_id;
match_id_params.subdev_name = entity.name;
SLOW("SUB_MODULE_LED_FLASH subdev_name %s subdev_id %d", subdev_name, match_id_params.subdev_id);
mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_set_sub_module_id, &match_id_params);
break;
case MSM_CAMERA_SUBDEV_STROBE_FLASH:
match_id_params.sub_module = SUB_MODULE_STROBE_FLASH;
match_id_params.subdev_id = subdev_id;
match_id_params.subdev_name = entity.name;
SLOW("SUB_MODULE_STROBE_FLASH subdev_name %s subdev_id %d",subdev_name, match_id_params.subdev_id);
mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_set_sub_module_id, &match_id_params);
break;
case MSM_CAMERA_SUBDEV_CSIPHY:
match_id_params.sub_module = SUB_MODULE_CSIPHY;
match_id_params.subdev_id = subdev_id;
match_id_params.subdev_name = entity.name;
SLOW("SUB_MODULE_CSIPHY subdev_name %s subdev_id %d", subdev_name, match_id_params.subdev_id);
mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_set_sub_module_id, &match_id_params);
break;
case MSM_CAMERA_SUBDEV_CSID:
match_id_params.sub_module = SUB_MODULE_CSID;
match_id_params.subdev_id = subdev_id;
match_id_params.subdev_name = entity.name;
SLOW("SUB_MODULE_CSID subdev_name %s subdev_id %d", subdev_name, match_id_params.subdev_id);
mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_set_sub_module_id, &match_id_params);
break;
case MSM_CAMERA_SUBDEV_OIS:
match_id_params.sub_module = SUB_MODULE_OIS;
match_id_params.subdev_id = subdev_id;
match_id_params.subdev_name = entity.name;
SLOW("SUB_MODULE_OIS subdev_name %s subdev_id %d", subdev_name, match_id_params.subdev_id);
mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_set_sub_module_id, &match_id_params);
break;
case MSM_CAMERA_SUBDEV_IR_LED:
match_id_params.sub_module = SUB_MODULE_IR_LED;
match_id_params.subdev_id = subdev_id;
match_id_params.subdev_name = entity.name;
SLOW("SUB_MODULE_IR_LED subdev_name %s subdev_id %d", subdev_name, match_id_params.subdev_id);
mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_set_sub_module_id, &match_id_params);
break;
case MSM_CAMERA_SUBDEV_IR_CUT:
match_id_params.sub_module = SUB_MODULE_IR_CUT;
match_id_params.subdev_id = subdev_id;
match_id_params.subdev_name = entity.name;
SLOW("SUB_MODULE_IR_CUT subdev_name %s subdev_id %d", subdev_name, match_id_params.subdev_id);
mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_set_sub_module_id, &match_id_params);
break;
case MSM_CAMERA_SUBDEV_LASER_LED:
match_id_params.sub_module = SUB_MODULE_LASER_LED;
match_id_params.subdev_id = subdev_id;
match_id_params.subdev_name = entity.name;
SLOW("SUB_MODULE_LASER_LED subdev_name %s subdev_id %d", subdev_name, match_id_params.subdev_id);
mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_set_sub_module_id, &match_id_params);
break;
case MSM_CAMERA_SUBDEV_EXT:
match_id_params.sub_module = SUB_MODULE_EXT;
match_id_params.subdev_id = subdev_id;
match_id_params.subdev_name = entity.name;
SLOW("SUB_MODULE_EXT subdev_name %s subdev_id %d", subdev_name, match_id_params.subdev_id);
mct_list_traverse(module_ctrl->sensor_bundle, module_sensor_set_sub_module_id, &match_id_params);
break;
default:
SLOW("ERROR Default subdev_type %d subdev_name %s subdev_id %d", subdev_type, entity.name, subdev_id);
break;
}
close(sd_fd);
}
}
close(dev_fd);
}
return TRUE;
};
1.1.1.3 外设func_tbl结构体函数初始化 module_sensors_subinit()
@ mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor.c
static boolean module_sensors_subinit(void *data, void *user_data __attribute__((unused)))
{
for (i = 0; i < SUB_MODULE_MAX; i++) {
s_bundle->module_sensor_params[i] = malloc(sizeof(module_sensor_params_t));
intf_info = &s_bundle->subdev_info[i].intf_info[SUBDEV_INTF_PRIMARY];
memset(s_bundle->module_sensor_params[i], 0, sizeof(module_sensor_params_t));
rc = sub_module_init[i](&s_bundle->module_sensor_params[i]->func_tbl);
}
module_sensor_update_settings_size(s_bundle->sensor_common_info.sensor_lib_params->sensor_lib_ptr);
}
各个模块init 函数,定义如下:
@ mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor.c
/** Initialization table **/
static int32_t (*sub_module_init[SUB_MODULE_MAX])(sensor_func_tbl_t *) = {
[SUB_MODULE_SENSOR] = sensor_sub_module_init,
[SUB_MODULE_CHROMATIX] = chromatix_sub_module_init,
[SUB_MODULE_ACTUATOR] = actuator_sub_module_init,
[SUB_MODULE_EEPROM] = eeprom_sub_module_init,
[SUB_MODULE_LED_FLASH] = led_flash_sub_module_init,
[SUB_MODULE_CSIPHY] = csiphy_sub_module_init,
[SUB_MODULE_CSIPHY_3D] = csiphy_sub_module_init,
[SUB_MODULE_CSID] = csid_sub_module_init,
[SUB_MODULE_CSID_3D] = csid_sub_module_init,
[SUB_MODULE_OIS] = ois_sub_module_init,
[SUB_MODULE_EXT] = external_sub_module_init,
[SUB_MODULE_IR_LED] = ir_led_sub_module_init,
[SUB_MODULE_IR_CUT] = ir_cut_sub_module_init,
[SUB_MODULE_LASER_LED] = laser_led_sub_module_init
};
我们进代码看下:
可以看出,主要工作就是,保存subdev 模块的 open、process、close 方法。
当需要使用该模块时,通过 process 方法,发相应的事件过去即可。
下面我们挑几个常用的来看下:
@ mm-camera/mm-camera2/media-controller/modules/sensors/sensor/module/sensor.c
int32_t sensor_sub_module_init(sensor_func_tbl_t *func_tbl)
{
func_tbl->open = sensor_open;
func_tbl->process = sensor_process;
func_tbl->close = sensor_close;
return SENSOR_SUCCESS;
}
@ mm-camera/mm-camera2/media-controller/modules/sensors/chromatix/module/chromatix_sub_module.c
int32_t chromatix_sub_module_init(sensor_func_tbl_t *func_tbl)
{
func_tbl->open = chromatix_open;
func_tbl->process = chromatix_process;
func_tbl->close = chromatix_close;
return SENSOR_SUCCESS;
}
@ mm-camera/mm-camera2/media-controller/modules/sensors/actuator/module/actuator.c
int32_t actuator_sub_module_init(sensor_func_tbl_t *func_tbl)
{
func_tbl->open = actuator_open;
func_tbl->process = actuator_process;
func_tbl->close = actuator_close;
return 0;
}
@ mm-camera/mm-camera2/media-controller/modules/sensors/eeprom/module/eeprom.c
int32_t eeprom_sub_module_init(sensor_func_tbl_t *func_tbl)
{
func_tbl->open = eeprom_open;
func_tbl->process = eeprom_process;
func_tbl->close = eeprom_close;
return SENSOR_SUCCESS;
}
@ mm-camera/mm-camera2/media-controller/modules/sensors/flash/module/flash.c
int32_t led_flash_sub_module_init(sensor_func_tbl_t *func_tbl)
{
func_tbl->open = flash_open;
func_tbl->process = flash_process;
func_tbl->close = flash_close;
return SENSOR_SUCCESS;
}
好,写到这里就不再深入了,后面,我们再写一篇文章来专门写外设procexx 工作代码分析:
《【高通SDM660平台 Android 10.0】 — 高通马达、eeprom、flash 等外设代码分析》。
敬请期待吧。^_^
1.1.1.4 创建外设 port 端口 port_sensor_create()
主要工作如下:
- 打开
/dev/csi
, 切点下发CSID_INIT
命令,初始化 CSID ,上电,使能 csi clk, 使能中断等 - 发送
CSID_GET_VERSION
命令 获得 CSID 版本号 - 发送
SENSOR_GET_SENSOR_PORT_INFO
命令获得sensor 端口信息,也就是sensor lib库 头文件中的sensor_stream_info_array
信息 - 以 /sensor/libs/imx258/imx258_lib.h 为例,此处 sensor_stream_info_array->siz = 2
- 创建 mct port 口, name=csi0 / csi1
- 将创建 好的 sensor PORT 口添加在 s_module 中
@ mm-camera/mm-camera2/media-controller/modules/sensors/module/port_sensor.c
boolean port_sensor_create(void *data, void *user_data)
{
module_sensor_params = s_bundle->module_sensor_params[SUB_MODULE_SENSOR];
csid_module_params = s_bundle->module_sensor_params[SUB_MODULE_CSID];
// 1. 打开 /dev/csi, 切点下发 CSID_INIT 命令,初始化 CSID ,上电,使能 csi clk, 注册中断等
rc = csid_module_params->func_tbl.open(&csid_module_params->sub_module_private,
&s_bundle->subdev_info[SUB_MODULE_CSID]);
====================>
+ @ mm-camera/mm-camera2/media-controller/modules/sensors/csid/csid.c
+ snprintf(subdev_string, sizeof(subdev_string), "/dev/%s",
+ info->intf_info[SUBDEV_INTF_PRIMARY].sensor_sd_name);
+ ctrl->fd = open(subdev_string, O_RDWR);
+ cfg.cfgtype = CSID_INIT;
+ rc = ioctl(ctrl->fd, VIDIOC_MSM_CSID_IO_CFG, &cfg);
+ ---------->
+ rc = msm_csid_init(csid_dev, &cdata->cfg.csid_version);
+ ---->
+ cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSID,CAM_AHB_SVS_VOTE);
+ /* power up */
+ msm_camera_config_vreg(&csid_dev->pdev->dev, csid_dev->csid_vreg,
+ csid_dev->regulator_count, NULL, 0, &csid_dev->csid_reg_ptr[0], 1);
+
+ msm_camera_config_vreg(&csid_dev->pdev->dev,
+ csid_vreg_info, ARRAY_SIZE(csid_vreg_info),NULL, 0, &csid_dev->csi_vdd, 1);
+
+ msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_dev->csid_vreg,
+ csid_dev->regulator_count, NULL, 0, &csid_dev->csid_reg_ptr[0], 1);
+
+ msm_camera_enable_vreg(&csid_dev->pdev->dev,
+ csid_vreg_info, ARRAY_SIZE(csid_vreg_info), NULL, 0, &csid_dev->csi_vdd, 1);
+
+ msm_camera_clk_enable(&csid_dev->pdev->dev,csid_dev->csid_clk_info, csid_dev->csid_clk,
+ csid_dev->num_clk, true);
+ msm_camera_enable_irq(csid_dev->irq, true);
+ msm_csid_reset(csid_dev);
+ csid_dev->csid_state = CSID_POWER_UP;
+ <----------
<====================
// 2. 发送 CSID_GET_VERSION 命令 获得 CSID 版本号
rc = csid_module_params->func_tbl.process(csid_module_params->sub_module_private,
CSID_GET_VERSION, &csid_version);
--------->
+ csid_get_version(csid_ctrl, data);
+ ---->
+ csid_version = (uint32_t *)data;
+ *csid_version = ctrl->csid_version;
<---------
csid_module_params->func_tbl.close(csid_module_params->sub_module_private);
// 3. 发送 SENSOR_GET_SENSOR_PORT_INFO 命令获得sensor 端口信息,也就是sensor lib库 头文件中的 sensor_stream_info_array 信息
module_ctrl = (module_sensor_ctrl_t *)s_module->module_private;
sensor_lib_params = s_bundle->sensor_lib_params;
rc = module_sensor_params->func_tbl.process(s_bundle->sensor_lib_params,
SENSOR_GET_SENSOR_PORT_INFO, &sensor_stream_info_array);
------------------->
+ @ mm-camera/mm-camera2/media-controller/modules/sensors/sensor/module/sensor.c
+ case SENSOR_GET_SENSOR_PORT_INFO:
+ rc = sensor_get_sensor_port_info(sctrl, data);
+ ---------->
+ sensor_stream_info_array_t **sensor_port_info_array = (sensor_stream_info_array_t **)data;
+ *sensor_port_info_array = &(lib->sensor_lib_ptr->sensor_stream_info_array);
+ <----------
<-------------------
// 4. 以 /sensor/libs/imx258/imx258_lib.h 为例,此处 sensor_stream_info_array->siz = 2
SLOW("sensor_stream_info_array->size %d", sensor_stream_info_array->size);
for (j = 0; j < sensor_stream_info_array->size; j++) {
// 5. 创建 mct port 口, name=csi0 / csi1
snprintf(port_name, sizeof(port_name), "%s%d", s_bundle->sensor_info->sensor_name, j);
s_port = mct_port_create(port_name);
==================>
+ @ mm-camera/mm-camera2/media-controller/mct/port/mct_port.c
+ port = malloc(sizeof(mct_port_t));
+ mct_object_set_name(MCT_OBJECT_CAST(port), name); ===> object->name = mct_strdup(name);
+ mct_port_init_default(port);
<==================
sensor_src_port_cap = malloc(sizeof(sensor_src_port_cap_t));
memset(sensor_src_port_cap, 0, sizeof(sensor_src_port_cap_t));
sensor_src_port_cap->session_id = s_bundle->sensor_info->session_id;
sensor_src_port_cap->num_cid_ch = sensor_stream_info_array->sensor_stream_info[j].vc_cfg_size;
sensor_src_port_cap->is_stereo_config = s_bundle->is_stereo_configuration;
for (i = 0; i < sensor_src_port_cap->num_cid_ch; i++) {
+ sensor_src_port_cap->sensor_cid_ch[i].cid = sensor_stream_info_array->sensor_stream_info[j].vc_cfg[i].cid;
+ sensor_src_port_cap->sensor_cid_ch[i].csid = (uint32_t)s_bundle->sensor_info->subdev_id[SUB_MODULE_CSID];
+
+ sensor_src_port_cap->sensor_cid_ch[i].csid_version = csid_version;
+ sensor_src_port_cap->sensor_cid_ch[i].dt = sensor_stream_info_array->sensor_stream_info[j].vc_cfg[i].dt;
+
+ sensor_src_port_cap->sensor_cid_ch[i].is_bayer_sensor =
+ s_bundle->sensor_common_info.sensor_lib_params->sensor_lib_ptr->
+ sensor_output.output_format == SENSOR_YCBCR ? 0 : 1;
+
+ pix_fmt_fourcc = sensor_util_get_fourcc_format(
+ sensor_stream_info_array->sensor_stream_info[j].pix_data_fmt[i],
+ s_bundle->sensor_lib_params->sensor_lib_ptr->sensor_output.filter_arrangement,
+ sensor_stream_info_array->sensor_stream_info[j].vc_cfg[i].decode_format);
+
+ sensor_src_port_cap->sensor_cid_ch[i].fmt = sensor_util_get_hal_format(pix_fmt_fourcc);
}
s_port->direction = MCT_PORT_SRC;
s_port->check_caps_reserve = port_sensor_caps_reserve;
s_port->check_caps_unreserve = port_sensor_caps_unreserve;
s_port->ext_link = port_sensor_ext_link_func;
s_port->un_link = port_sensor_unlink_func;
s_port->event_func = port_sensor_port_process_event;
s_port->intra_event_func = port_sensor_port_process_event;
SLOW("s_port=%p event_func=%p", s_port, s_port->event_func);
s_port->caps.u.data = (void *)sensor_src_port_cap;
s_port->port_private = (module_sensor_port_data_t *) malloc(sizeof(module_sensor_port_data_t));
memset(s_port->port_private, 0, sizeof(module_sensor_port_data_t));
// 6. 将 PORT 口添加在 s_module 中。
ret = mct_module_add_port(s_module, s_port);
}
}
1.1.1.4.1 Stream Info 示例
以 IMX258 为例, stream info 如下
@ mm-camera/mm-camera2/media-controller/modules/sensors/sensor/libs/imx258/imx258_lib.h
.sensor_stream_info_array =
{
.sensor_stream_info =
{
{
.vc_cfg_size = 2,
.vc_cfg =
{
{
.cid = 0,
.dt = CSI_RAW10,
.decode_format = CSI_DECODE_10BIT,
},
{
.cid = 1,
.dt = IMX258_CSI_PD_ISTATS,
.decode_format = CSI_DECODE_8BIT,
},
},
.pix_data_fmt =
{
SENSOR_BAYER,
SENSOR_META,
},
},
{
.vc_cfg_size = 1,
.vc_cfg =
{
{
.cid = 2,
.dt = CSI_EMBED_DATA,
.decode_format = CSI_DECODE_8BIT,
},
},
.pix_data_fmt =
{
SENSOR_META,
},
},
},
.size = 2,
},
1.1.1.5 Eeprom初始化 module_sensor_init_eeprom()
- 初始化 eeprom 的open、process、close 方法
- 找开 msm_eeprom 节点 ( /dev/v4l-subdevX )
- copy sensor name (解析自 config.xml 中,如 rohm_brcg064gwz_3)
- 加载 eeprom lib 库,映射 eeprom_open_lib 方法
- 解析EEPROM 上电时序,下发 CFG_EEPROM_INIT 上电且初始化 eeprom
- 下发 CFG_EEPROM_READ_CAL_DATA 获取eeprom 数据
- 处理 EEPROM OTP 数据
- 获取格式化过后的 eeprom 数据
- 如果是双摄的话,格式化双摄数据
@ mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor.c
static boolean module_sensor_init_eeprom(void *data, void *eebin_hdl)
{
s_bundle = (module_sensor_bundle_info_t *)data;
// 1. 初始化eeprom 的open、process、close 方法
eeprom_sub_module_init(&func_tbl);
---------------->
+ func_tbl->open = eeprom_open;
+ func_tbl->process = eeprom_process;
+ func_tbl->close = eeprom_close;
<---------------
s_bundle->eeprom_data = (sensor_eeprom_data_t *) malloc(sizeof(sensor_eeprom_data_t));
// 2. 找开 msm_eeprom 节点 ( /dev/v4l-subdevX )
/* (1) Open the eeprom sub module */
rc = func_tbl.open((void **)&s_bundle->eeprom_data, &s_bundle->subdev_info[SUB_MODULE_EEPROM]);
------------------->
ctrl = (sensor_eeprom_data_t *)(*eeprom_ctrl);
snprintf(subdev_string, sizeof(subdev_string), "/dev/%s",
info->intf_info[SUBDEV_INTF_PRIMARY].sensor_sd_name);
<-------------------
// 3. copy sensor name(解析自 config.xml中,如 rohm_brcg064gwz_3 )
memset(&s_bundle->eeprom_data->eeprom_params, 0, sizeof(eeprom_params_t));
memcpy(s_bundle->eeprom_data->eeprom_params.eeprom_name,
s_bundle->sensor_common_info.camera_config.eeprom_name,
sizeof(s_bundle->eeprom_data->eeprom_params.eeprom_name));
/* (2) Load eeprom library */
bin_ctl.cmd = EEPROM_BIN_GET_NAME_DATA;
bin_ctl.ctl.q_num.type = EEPROM_BIN_LIB_EEPROM;
bin_ctl.ctl.name_data.name = s_bundle->sensor_info->sensor_name;
bin_ctl.ctl.name_data.path = NULL;
rc = eebin_interface_control(eebin_hdl, &bin_ctl);
==================>
@ mm-camera/mm-camera2/media-controller/modules/sensors/eebin/module/eebin_interface.c
rc = eebin_name_data(eebin_hdl, &bin_ctl->ctl.name_data);
type_l = BIN_DEV_EEPROM;
for (i = 0; i < master_h->num_modules; i++) {
for(j = 0; j < bin_device->moddev[i].module_h.max_devices; j++) {
if(bin_device->moddev[i].device_h[j].type == type_l) {
if(!strncmp(bin_device->moddev[i].device_h[j].name, name_data->name,
sizeof(bin_device->moddev[i].device_h[j].name)))
{
name_data->lib_name = bin_device->moddev[i].device_h[j].lib_name;
name_data->path = bin_device->moddev[i].device_h[j].path;
SLOW("name:%s lib_name:%s, path:%s",
bin_device->moddev[i].device_h[j].name,
bin_device->moddev[i].device_h[j].lib_name,
bin_device->moddev[i].device_h[j].path);
}
}
}
}
<==================
SHIGH("EEPROM path: %s name: %s", bin_ctl.ctl.name_data.path, s_bundle->eeprom_data->eeprom_params.eeprom_name);
// 4. 加载eeprom lib库,映射 eeprom_open_lib 方法
rc = eeprom_load_library(s_bundle->eeprom_data, bin_ctl.ctl.name_data.path);
==================>
@ mm-camera/mm-camera2/media-controller/modules/sensors/eeprom/module/eeprom.c
snprintf(lib_name, sizeof(lib_name), "libmmcamera_%s_eeprom.so", name);
SHIGH("lib_name %s",lib_name);
e_ctrl->eeprom_lib.eeprom_lib_handle = dlopen(lib_name, RTLD_NOW);
snprintf(open_lib_str, sizeof(open_lib_str), "%s_eeprom_open_lib", name);
*(void **)&eeprom_open_lib = dlsym(e_ctrl->eeprom_lib.eeprom_lib_handle, open_lib_str);
e_ctrl->eeprom_lib.func_tbl = (eeprom_lib_func_t *)eeprom_open_lib();
<==================
// 5. 解析EEPROM 上电时序,下发 CFG_EEPROM_INIT 上电且初始化 eeprom
/* (3) Powerup and parse the eeprom */
rc = func_tbl.process(s_bundle->eeprom_data, EEPROM_INIT, NULL);
==================>
+ // mm-camera/mm-camera2/media-controller/modules/sensors/eeprom/module/eeprom.c
+ static int32_t eeprom_init(void *ptr)
+ {
+ power_setting_array = (struct msm_sensor_power_setting_array *)malloc(
+ sizeof(struct msm_sensor_power_setting_array));
+ translate_camera_power_setting(power_setting_array,
+ &(ectrl->eeprom_lib.func_tbl->eeprom_info.power_setting_array));
+ translate_eeprom_memory_map(&eeprom_map_array,
+ &(ectrl->eeprom_lib.func_tbl->eeprom_info.mem_map_array));
+ eeprom_info.power_setting_array = power_setting_array;
+ eeprom_info.mem_map_array = &eeprom_map_array;
+
+ cfg.cfgtype = CFG_EEPROM_INIT;
+ cfg.cfg.eeprom_info = eeprom_info;
+ rc = ioctl(ectrl->fd, VIDIOC_MSM_EEPROM_CFG, &cfg);
+ }
<==================
// 6. 下发 CFG_EEPROM_READ_CAL_DATA 获取eeprom 数据
/* (4) Read the eeprom data from kernel */
rc = func_tbl.process(s_bundle->eeprom_data, EEPROM_READ_DATA, NULL);
=================>
+ cfg.cfgtype = CFG_EEPROM_GET_CAL_DATA;
+ rc = ioctl(ep->fd, VIDIOC_MSM_EEPROM_CFG, &cfg);
+
+ cfg.cfgtype = CFG_EEPROM_READ_CAL_DATA;
+ cfg.cfg.read_data.num_bytes = ep->eeprom_params.num_bytes;
+ cfg.cfg.read_data.dbuffer = ep->eeprom_params.buffer;
+ rc = ioctl(ep->fd, VIDIOC_MSM_EEPROM_CFG, &cfg);
<==================
// 7. 处理 EEPROM OTP 数据
/* (5) Format the cal data */
rc = func_tbl.process(s_bundle->eeprom_data, EEPROM_SET_FORMAT_DATA, NULL);
=================>
@ mm-camera/mm-camera2/media-controller/modules/sensors/eeprom/module/eeprom.c
int32_t eeprom_format_calibration_data(void *e_ctrl)
{
eeprom_check_property(&ectrl->eeprom_data);
ectrl->eeprom_lib.func_tbl->format_calibration_data(e_ctrl);
ectrl->eeprom_lib.func_tbl->get_calibration_items(e_ctrl);
eeprom_dbg_data_dump(e_ctrl, NULL, EEPROM_DUMP_OTP);
}
<=================
// 8. 获取格式化过后的 eeprom 数据
rc = func_tbl.process(s_bundle->eeprom_data, EEPROM_GET_FORMATTED_DATA, &s_bundle->formatted_data);
===========>
+ format_data_t **ptr = (format_data_t **)data;
+ *ptr = &ep->eeprom_data;
<===========
// 9. 如果是双摄的话,格式化双摄数据
rc = func_tbl.process(s_bundle->eeprom_data, EEPROM_SET_CALIBRATE_DUALCAM_PARAM, &s_bundle->dualcam_tune_data);
s_bundle->is_valid_dualcalib = TRUE;
/* (6) close the eeprom sub module */
rc = func_tbl.close(s_bundle->eeprom_data);
SLOW("Exit");
return TRUE;
}
1.1.1.5.1 处理OTP数据 eeprom_format_calibration_data()
- 根据属性,判断 af,awb,lsc, pdaf, dual 是否有都要做 OTP
- 开始格式化 eeprom 数据,不同的eeprom的数据存储格式也不一样,实现方法在lib.c 中
- 判断哪些项要做 otp
- 将otp 数据以 txt 形式 dump 出来
@ mm-camera/mm-camera2/media-controller/modules/sensors/eeprom/module/eeprom.c
int32_t eeprom_format_calibration_data(void *e_ctrl)
{
SDBG("Enter");
eeprom_check_property(&ectrl->eeprom_data);
// 1. 根据属性,判断 af,awb,lsc, pdaf, dual 是否有都要做 OTP
=================>
+ e_items->is_afc = 1;
+ e_items->is_wbc = 1;
+ e_items->is_lsc = 1;
+ e_items->is_dpc = 1;
+ e_items->is_ois = 1;
+ e_items->is_dual = 1;
+
+ if (property_get("persist.vendor.camera.cal.af", value, "1"))
+ e_items->is_afc = (atoi(value) == 1)? TRUE:FALSE;
+ if (property_get("persist.vendor.camera.cal.awb", value, "1"))
+ e_items->is_wbc = (atoi(value) == 1)? TRUE:FALSE;
+ if (property_get("persist.vendor.camera.cal.lsc", value, "1"))
+ e_items->is_lsc = (atoi(value) == 1)? TRUE:FALSE;
+ if (property_get("persist.vendor.camera.cal.dp", value, "1"))
+ e_items->is_dpc = (atoi(value) == 1)? TRUE:FALSE;
+ if (property_get("persist.vendor.camera.cal.dual", value, "1"))
+ e_items->is_dual = (atoi(value) == 1)? TRUE:FALSE;
+
+ SLOW("is_afc: %d,is_wbc: %d,is_lsc: %d, is_dpc: %d, is_dual: %d, is_ois: %d",
+ e_items->is_afc,e_items->is_wbc,e_items->is_lsc,
+ e_items->is_dpc,e_items->is_dual,e_items->is_ois);
<=================
// 2. 开始格式化 eeprom 数据,不同的eeprom的数据存储格式也不一样,实现方法在lib.c 中
ectrl->eeprom_lib.func_tbl->format_calibration_data(e_ctrl);
// 3. 判断哪些项要做 otp
ectrl->eeprom_lib.func_tbl->get_calibration_items(e_ctrl);
=================>
+ void brcg064gwz_3_get_calibration_items(void *e_ctrl)
+ {
+ sensor_eeprom_data_t *ectrl = (sensor_eeprom_data_t *)e_ctrl;
+ eeprom_calib_items_t *e_items = &(ectrl->eeprom_data.items);
+
+ e_items->is_wbc = datapresent ? TRUE : FALSE;
+ e_items->is_afc = datapresent ? TRUE : FALSE;
+ e_items->is_lsc = datapresent ? TRUE : FALSE;
+ e_items->is_dpc = FALSE;
+ e_items->is_insensor = FALSE;
+ e_items->is_ois = FALSE;
+ }
<=================
// 4. 将otp 数据以 txt 形式 dump 出来
/* Dump the OTP data */
eeprom_dbg_data_dump(e_ctrl, NULL, EEPROM_DUMP_OTP);
================>
+ dump_wbc_data(e_ctrl, EEPROM_DUMP_WB);
+ dump_lsc_data(e_ctrl, EEPROM_DUMP_LSC);
+ dump_af_data(e_ctrl, EEPROM_DUMP_AF);
+ dump_pdaf_data(e_ctrl, EEPROM_DUMP_PDAF);
+ dump_dpc_data(e_ctrl, EEPROM_DUMP_DPC);
+ dump_dualc_data(e_ctrl, EEPROM_DUMP_DUALC);
<================
SDBG("Exit: ret = %d", ret);
return ret;
}
1.1.1.5.1 格式化OTP数据 format_calibration_data()
以 imx258 为例,它使用的eeprom 是 rohm_brcg064gwz_3。
从代码中,可以看出,分别对 pdaf、awb、AF、LSC 数据各自进行处理,
具体本文先不深入,见后续文章《【高通SDM660平台 Android 10.0】(11) — Eeprom lib 与 Kernel 代码分析》
@mm-camera/mm-camera2/media-controller/modules/sensors/eeprom/libs/rohm_brcg064gwz_3/rohm_brcg064gwz_3_eeprom.c
static void brcg064gwz_3_format_calibration_data(void *e_ctrl) {
SHIGH("OTP: total bytes: %d",ctrl->eeprom_params.num_bytes);
datapresent = 1;
brcg064gwz_3_format_pdafdata(ctrl);
brcg064gwz_3_format_wbdata(ctrl);
brcg064gwz_3_format_afdata(ctrl);
brcg064gwz_3_format_lscdata(ctrl);
}
1.1.1.6 chromatix初始化 module_sensor_init_chromatix()
- 获取eeprom 的open、process、close 方法
- 打开eeprom设备
- 创建 chromatix 对象,传参为 eeprom_data 设备描述符
- 关闭eeprom设备
# mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor.c
static boolean module_sensor_init_chromatix(void *data, void *eebin_hdl)
{
s_bundle = (module_sensor_bundle_info_t *)data;
sensor_lib_ptr = s_bundle->sensor_lib_params->sensor_lib_ptr;
// 1. 获取eeprom 的open、process、close 方法
eeprom_sub_module_init(&func_tbl);
// 2. 打开eeprom设备
func_tbl.open((void **)&s_bundle->eeprom_data, &s_bundle->subdev_info[SUB_MODULE_EEPROM]);
// 3. 创建 chromatix ,传参为 eeprom_data 设备描述符
rc = cm_create(&s_bundle->chromatix_manager, s_bundle->sensor_info->sensor_name,
&s_bundle->sensor_common_info.camera_config.chromatix_info, s_bundle->eeprom_data, eebin_hdl);
// 4. 关闭eeprom设备
func_tbl.close(s_bundle->eeprom_data);
}
}
接下来,我们进入 cm_create
看下:
- 创建 hash 表对象,size为37
- 创建 LRU 节点,大小为40
- 获取 eeprom 的open、processo、close 等方法
- 加载所有的 chromatix lib 库
# mm-camera/mm-camera2/media-controller/modules/sensors/chromatix/module/chromatix_manager.c
boolean cm_create(chromatix_manager_type* cm, const char *sensor_name,
module_chromatix_info_t *chromatix_array, sensor_eeprom_data_t *eeprom_ctrl, void *eebin_hdl)
{
SLOW("Enter for %s", sensor_name);
// 1. 创建 hash 表对象,size为37
hash_create(&cm->hash, 0);
// 2. 创建 LRU 节点,大小为40
lru_create(&cm->lru, MAX_CHROMATIX_COUNT)
cm->mutex_created = TRUE;
// 3. 获取 eeprom 的open、processo、close 等方法
cm->eeprom_ctrl = eeprom_ctrl;
if (eeprom_ctrl) {
cm->eeprom_func = (sensor_func_tbl_t *)malloc(sizeof(sensor_func_tbl_t));
eeprom_sub_module_init(cm->eeprom_func);
}
cm->eebin_hdl = eebin_hdl;
bin_ctl.cmd = EEPROM_BIN_GET_LIB_NAME_DATA;
bin_ctl.ctl.q_num.type = EEPROM_BIN_LIB_CHROMATIX;
// 4. 加载所有的 chromatix lib 库
/* add all chromatix libraries */
for (i = 0; i < chromatix_array->size; i++) {
chromatix_name = &chromatix_array->chromatix_name[i];
rc = addLib(cm, chromatix_name->isp_common, EEPROM_CALIBRATE_LSC);
=============>
addLib_getSymbol(cm, chromatix_name->isp_common, EEPROM_CALIBRATE_LSC);
<=============
rc = addLib(cm, chromatix_name->isp_preview, EEPROM_CALIBRATE_WB_GREEN);
=============>
addLib_getSymbol(cm, chromatix_name->isp_preview, EEPROM_CALIBRATE_WB_GREEN);
<=============
rc = addLib(cm, chromatix_name->isp_snapshot, EEPROM_CALIBRATE_WB_GREEN);
=============>
addLib_getSymbol(cm, chromatix_name->isp_snapshot, EEPROM_CALIBRATE_WB_GREEN);
<=============
rc = addLib(cm, chromatix_name->isp_video, EEPROM_CALIBRATE_WB_GREEN);
=============>
addLib_getSymbol(cm, chromatix_name->isp_video, EEPROM_CALIBRATE_WB_GREEN);
<=============
rc = addLib(cm, chromatix_name->cpp_preview, 0);
=============>
addLib_getSymbol(cm, chromatix_name->cpp_preview, 0);
<=============
rc = addLib(cm, chromatix_name->cpp_snapshot, 0);
=============>
addLib_getSymbol(cm, chromatix_name->cpp_snapshot, 0);
<=============
rc = addLib(cm, chromatix_name->cpp_video, 0);
=============>
addLib_getSymbol(cm, chromatix_name->cpp_video, 0);
<=============
rc = addLib(cm, chromatix_name->cpp_liveshot, 0);
=============>
addLib_getSymbol(cm, chromatix_name->cpp_liveshot, 0);
<=============
rc = addLib(cm, chromatix_name->postproc, 0);
=============>
addLib_getSymbol(cm, chromatix_name->postproc, 0);
<=============
rc = addLib(cm, chromatix_name->a3_video, EEPROM_CALIBRATE_WB);
=============>
addLib_getSymbol(cm, chromatix_name->a3_video, EEPROM_CALIBRATE_WB);
<=============
rc = addLib(cm, chromatix_name->a3_preview, EEPROM_CALIBRATE_WB);
=============>
addLib_getSymbol(cm, chromatix_name->a3_preview, EEPROM_CALIBRATE_WB);
<=============
rc = addLib(cm, chromatix_name->iot, 0);
C=============>
addLib_getSymbol(cm, chromatix_name->iot, 0);
<=============
if (lru_count(&cm->lru) == MAX_CHROMATIX_COUNT) {
SERR("HASH cache is full");
break;
}
}
lru_traverse(&cm->lru);
return TRUE;
}
1.1.1.6.1 CharmatixName 定义xml
前面我们mm-camera/mm-camera2/media-controller/modules/sensors/configs/sdm660_camera.xml
文件中,
我们得知 ChromatixName = imx258_lc898217xc_chromatix
<CameraConfigurationRoot>
<CameraModuleConfig>
<CameraId>2</CameraId>
<SensorName>imx258</SensorName>
<ActuatorName>lc898217xc</ActuatorName>
<EepromName>rohm_brcg064gwz_3</EepromName>
<FlashName>pmic</FlashName>
<ChromatixName>imx258_lc898217xc_chromatix</ChromatixName>
<ModesSupported>1</ModesSupported>
<Position>FRONT</Position>
<MountAngle>270</MountAngle>
<SensorSlaveAddress>0x34</SensorSlaveAddress>
</CameraModuleConfig>
我们进入 imx258_lc898217xc_chromatix.xml
中,可以看到当前 chromatix 的所有lib库的name。
@ mm-camera/mm-camera2/media-controller/modules/sensors/configs/imx258_lc898217xc_chromatix.xml
<ChromatixConfigurationRoot>
<CommonChromatixInfo>
<ChromatixName>
<ISPCommon>imx258_lc898217xc_common</ISPCommon>
<PostProc>imx258_lc898217xc_postproc</PostProc>
<CPPPreview>imx258_lc898217xc_cpp_preview</CPPPreview>
<CPPSnapshot>imx258_lc898217xc_cpp_snapshot</CPPSnapshot>
<CPPLiveshot>imx258_lc898217xc_cpp_liveshot</CPPLiveshot>
</ChromatixName>
</CommonChromatixInfo>
<ResolutionChromatixInfo>
<ChromatixName sensor_resolution_index="0">
<ISPPreview>imx258_lc898217xc_snapshot</ISPPreview>
<ISPSnapshot>imx258_lc898217xc_snapshot</ISPSnapshot>
<ISPVideo>imx258_lc898217xc_default_video</ISPVideo>
<CPPVideo>imx258_lc898217xc_cpp_video</CPPVideo>
<A3Preview>imx258_lc898217xc_zsl_preview_3a</A3Preview>
<A3Video>imx258_lc898217xc_zsl_video_3a</A3Video>
</ChromatixName>
<ChromatixName sensor_resolution_index="1">
<ISPPreview>imx258_lc898217xc_preview</ISPPreview>
<ISPSnapshot>imx258_lc898217xc_preview</ISPSnapshot>
<ISPVideo>imx258_lc898217xc_preview</ISPVideo>
<CPPVideo>imx258_lc898217xc_cpp_video</CPPVideo>
<A3Preview>imx258_lc898217xc_4k_preview_3a</A3Preview>
<A3Video>imx258_lc898217xc_4k_video_3a</A3Video>
</ChromatixName>
<ChromatixName sensor_resolution_index="2">
<ISPPreview>imx258_lc898217xc_preview</ISPPreview>
<ISPSnapshot>imx258_lc898217xc_preview</ISPSnapshot>
<ISPVideo>imx258_lc898217xc_preview</ISPVideo>
<CPPVideo>imx258_lc898217xc_cpp_video</CPPVideo>
<A3Preview>imx258_lc898217xc_default_preview_3a</A3Preview>
<A3Video>imx258_lc898217xc_default_video_3a</A3Video>
</ChromatixName>
</ResolutionChromatixInfo>
</ChromatixConfigurationRoot>
1.1.1.6.2 打开并获取lib库方法 addLib_getSymbol()
以 <ISPCommon>imx258_lc898217xc_common</ISPCommon>
为例,
会加载 libchromatix_imx258_lc898217xc_common.so
库文件,
获取其 load_chromatix()
方法。
如果 so 库文件,加载失败,刚会尝试加载 chromatix_imx258_lc898217xc_common.bin
文件
将 imx258_lc898217xc_common
添加到 lru 及hash 中。
有关 chromatix 相关的,打算专门写一篇文章,可以见文章《【高通SDM660平台 Android 10.0】(12) — Camera Chromatix 代码分析》
@ mm-camera/mm-camera2/media-controller/modules/sensors/chromatix/module/chromatix_manager.c
static void* addLib_getSymbol(chromatix_manager_type* cm, const char *key, int32_t cal_type)
{
SLOW("chromatix: %s", key);
/* open library */
bin_ctl.ctl.name_data.lib_name = (char *)key; // imx258_lc898217xc_common
bin_ctl.ctl.name_data.path = NULL;
if (cm->eebin_hdl)
if (eebin_interface_control(cm->eebin_hdl, &bin_ctl) < 0)
SERR("No Camera Multimodule data.");
rc = load_chromatix(key, bin_ctl.ctl.name_data.path, &data_hdl, &data_sym);
====================>
+ // abs_path=NULL, name=imx258_lc898217xc_common
+ snprintf(lib_name, PATH_SIZE_255, "%s/libchromatix_%s.so", abs_path, name);
+ snprintf(bin_name, PATH_SIZE_255, "%schromatix_%s.bin", CONFIG_XML_PATH, name);
+ SLOW ("lib_name %s", (char *)lib_name);
+ // 打开 libchromatix_imx258_lc898217xc_common.so , 获取其 load_chromatix() 方法。
+ *handle = dlopen((const char *)lib_name, RTLD_NOW);
+ *(void **)&open_lib = dlsym(*handle, "load_chromatix");
+ *symbol = open_lib();
+ SLOW("handle = 0x%p symbol = 0x%p", *handle, *symbol);
+
+ // 如果 so 库文件,加载失败,刚会尝试加载 chromatix_imx258_lc898217xc_common.bin 文件
+ LIB_LOAD_ERROR:
+ SLOW ("bin_name %s", (char *)bin_name);
+ fp = fopen(bin_name, "rb");
+ fseek(fp, 0L, SEEK_END); /* Seek to the end of the stream */
+ file_size = ftell(fp); /* Get the number of bytes in file */
+ fseek(fp, 0L, SEEK_SET); /* Seek to the begin of the stream */
+ pBuffer = malloc(file_size);
+ bytes_read = fread(pBuffer, 1, file_size, fp);
+ *symbol = pBuffer;
+ fclose(fp);
+ return SENSOR_SUCCESS;
<====================
/* calibration */
if (cm->eeprom_ctrl && cm->eeprom_func && cal_type > 0)
((sensor_func_tbl_t*)(cm->eeprom_func))->process( cm->eeprom_ctrl, cal_type, data_sym);
// 将 imx258_lc898217xc_common 添加到 lru 及hash 中。
lru_add(&cm->lru, key, &cIndex);
hash_add(&cm->hash, key, data_hdl, data_sym, cIndex);
return data_sym;
}
好,至此为止,我们 module_sensor_init 工作就完事了
主要是初始化 sensor,subdev,eeprom,chromatix,这几部分。