【高通SDM660平臺 Android 10.0】(9) --- Qcom Camera Daemon 代碼分析


【高通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 代碼
主要工作如下:

  1. 開啓 Camera Debug 功能

  2. 打開/dev/media0 獲取msm_config 對應的V4L2的 entity名字

  3. 打開節點, /dev/video0

  4. 將當前打開節點,添加到 監聽列表 中

  5. 開始初始化sensor 模塊,此時會下發 probe camera sensor 命令

  6. 開始初始化其餘的模塊 包括 iface、isp、stats、pproc、imglib。
    分別調用 module_iface_initmodule_isp_initstats_module_initpproc_module_initmodule_imglib_init
    初始化完畢後,添加到mct_list列表中

  7. 依次下發如下 V4L2 命令,測試是否成功

  8. 創建定時器,供後續監測超時使用

  9. 尋找初始化完畢的 V4L2 節點的 MSM_CAMERA_SUBDEV_SENSOR_INIT 類型設備, 對應的 msm_sensor_init

  10. 打開節點

  11. 下發 sensor_init VIDIOC_MSM_SENSOR_INIT_CFG 命令, cfgtype= CFG_SINIT_PROBE_DONE

  12. 通過 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()

  1. 初始化一個 mct_module 類型結構體,填充sensor ssession 操作方法
  2. EEPROM BIN 初始化
  3. 獲取eeprom bin 數據
  4. 初始化Camera Sensor,此時會開始下發 probe 命令
  5. 尋找現有的外設
  6. 外設func_tbl結構體函數初始化,獲取各個外設的 open,procexx,close 方法
  7. 創建外設 port 端口
  8. 加載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()

  1. 拼湊camera_config.xml 路徑的字符串,/data/vendor/camera/camera_config.xml
  2. 打開camera_config.xml文件,找到 CameraConfigurationRoot 節點
  3. 每個 CameraModuleConfig 對應着一個 Camera, 統計config 數量,供後續遍歷使用
  4. 對每個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()
  1. 根據xml 中解析的 sensor name, 查找並打開對應的 sensor lib 庫,映射lib庫方法,如果支持PDAF ,則加載 PDAF 的函數
  2. 獲取 Camera Sensor 上下電配置
  3. 獲取上電,下電配置
  4. 獲取 Sensor 出圖的數據類型 ,BAYER(RGB) Or YCBCR(YUV)
  5. 下發 CFG_SINIT_PROBE ,開始觸發 Sensor Probe,傳參 slave_info,包含上下電配置
  6. 解析該Camera 對應的 Lens info、CSI Info、chromatix info 信息
  7. 將該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()

  1. 打開 /dev/media0 節點,下發 MEDIA_IOC_DEVICE_INFO 獲取的設備信息,匹配找到“msm_config”
  2. 循環遍歷,將所有的外設的類型,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()

主要工作如下:

  1. 打開 /dev/csi, 切點下發 CSID_INIT 命令,初始化 CSID ,上電,使能 csi clk, 使能中斷等
  2. 發送 CSID_GET_VERSION 命令 獲得 CSID 版本號
  3. 發送 SENSOR_GET_SENSOR_PORT_INFO 命令獲得sensor 端口信息,也就是sensor lib庫 頭文件中的 sensor_stream_info_array 信息
  4. 以 /sensor/libs/imx258/imx258_lib.h 爲例,此處 sensor_stream_info_array->siz = 2
  5. 創建 mct port 口, name=csi0 / csi1
  6. 將創建 好的 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()

  1. 初始化 eeprom 的open、process、close 方法
  2. 找開 msm_eeprom 節點 ( /dev/v4l-subdevX )
  3. copy sensor name (解析自 config.xml 中,如 rohm_brcg064gwz_3)
  4. 加載 eeprom lib 庫,映射 eeprom_open_lib 方法
  5. 解析EEPROM 上電時序,下發 CFG_EEPROM_INIT 上電且初始化 eeprom
  6. 下發 CFG_EEPROM_READ_CAL_DATA 獲取eeprom 數據
  7. 處理 EEPROM OTP 數據
  8. 獲取格式化過後的 eeprom 數據
  9. 如果是雙攝的話,格式化雙攝數據
@ 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()
  1. 根據屬性,判斷 af,awb,lsc, pdaf, dual 是否有都要做 OTP
  2. 開始格式化 eeprom 數據,不同的eeprom的數據存儲格式也不一樣,實現方法在lib.c 中
  3. 判斷哪些項要做 otp
  4. 將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()

  1. 獲取eeprom 的open、process、close 方法
  2. 打開eeprom設備
  3. 創建 chromatix 對象,傳參爲 eeprom_data 設備描述符
  4. 關閉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 看下:

  1. 創建 hash 表對象,size爲37
  2. 創建 LRU 節點,大小爲40
  3. 獲取 eeprom 的open、processo、close 等方法
  4. 加載所有的 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,這幾部分。


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()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章