MSM897x camera flow

来源:互联网 发布:优衣库 淘宝 代购 编辑:程序博客网 时间:2024/06/05 12:46

First of all, we can learn from sensor_init.c which is the hardware layout and communicate the upper layer and kernel space.

static const char *sensor_libs[] = {

 "imx214",

 //"imx214_R",

};

That is the libraries which will be opened and pointed by the later function defined below,

 

boolean sensor_init_probe(module_sensor_ctrl_t *module_ctrl){}

In this function, we will see such code below,

 /* Open sensor libraries and get init information */

 for (i = 0; i < ARRAY_SIZE(sensor_libs); i++) {

        ALOGE("sensor_lib_num is %d\n",i);

   ret = sensor_probe(sd_fd, sensor_libs[i]);

   if (ret == FALSE) {

     SERR("failed: to load %s", sensor_libs[i]);

   }

 }

It will call sensor_probe() function for every library defined previously, it is very interesting, because I just see “imx214” in the array, however, “imx214_R” will also be opened, I think another part of code would do the similar job, I will find them later and complement.

 

“sensor_probe” function locate in sensor.c file. It will actually open the .so lib, code as below,

/* Load sensor library */

 rc = sensor_load_library(sensor_name, &sensor_lib_params);

 if (rc < 0) {

   SERR("failed: to load %s", sensor_name);

   return FALSE;

 }

In “sensor_load_library”, it will call dlsym() function which is very useful for a given function you knew in the library you want to open and return the pointer for later use.

sprintf(open_lib_str, "%s_open_lib", name);

   *(void **)&sensor_open_lib = dlsym(sensor_lib_params->sensor_lib_handle,

open_lib_str);

In the instance above, we know that “open_lib_str” is in the libmmcamera_imx214.so, so use dlsym() to return the handle, and we can see the actual code in imx214_lib.c.

void* imx214_open_lib(void) {

 return &sensor_lib_ptr;

}

We can see that it will return the imx214’s data structure.

After load library in “sensor_probe” function, we will find these codes below,

 /* Pass slave information to kernel and probe */

 cfg.cfgtype = CFG_SINIT_PROBE;

 cfg.cfg.setting = slave_info;

 if (ioctl(fd, VIDIOC_MSM_SENSOR_INIT_CFG, &cfg) < 0) {

   SERR("failed");

   ret = FALSE;

   goto ERROR;

 }

It will pass the imx214’s information to kernel, then we can find the case in msm_sensor_init.c:

Function “msm_sensor_init_subdev_ioctl”

        switch (cmd) {

        case VIDIOC_MSM_SENSOR_INIT_CFG:

                  rc = msm_sensor_driver_cmd(s_init, arg);

                  break;

“msm_sensor_driver_cmd” will pass the argument and then entry this case,

        switch (cfg->cfgtype) {

        case CFG_SINIT_PROBE:

                  mutex_lock(&s_init->imutex);

                  s_init->module_init_status = 0;

                  rc = msm_sensor_driver_probe(cfg->cfg.setting);

                  mutex_unlock(&s_init->imutex);

                  if (rc < 0)

                           pr_err("failed: msm_sensor_driver_probe rc %d", rc);

                  break;

“msm_sensor_driver_probe” function locate in msm_sensor_driver.c and is very huge and complicated. First, it will copy the imx214 structure from user space, like,

        if (copy_from_user(slave_info, (void *)setting, sizeof(*slave_info))) {

                  pr_err("failed: copy_from_user");

                  rc = -EFAULT;

                  goto FREE_SLAVE_INFO;

        }

Then complement the structure of g_sctrl that is very huge structure.

/* Extract s_ctrl from camera id */

        s_ctrl = g_sctrl[slave_info->camera_id];

 

There are some interesting operation, for instance, if we do not define power down sequence, it will copy power up sequence and transform it to power down sequence just by convert the array, code showed below,

        } else {

                  pr_err("failed: no power_down_setting");

                  if (copy_from_user(power_down_setting,

                           (void *)slave_info->power_setting_array.

                                                       power_setting,

                           sizeof(*power_down_setting) * size_down)) {

                           pr_err("failed: copy_from_user");

                           rc = -EFAULT;

                           goto FREE_POWER_DOWN_SETTING;

                  }

                  /*reverce*/

                  end = size_down - 1;

                  for (c = 0; c < size_down/2; c++) {

                           power_down_setting_t = power_down_setting[c];

                           power_down_setting[c] = power_down_setting[end];

                           power_down_setting[end] = power_down_setting_t;

                           end--;

                  }

        }

There are some lines showed how to pass and change i2c address,

        cci_client->cci_i2c_master = s_ctrl->cci_i2c_master;

        cci_client->sid = slave_info->slave_addr >> 1;

        cci_client->retries = 3;

        cci_client->id_map = 0;

Then call power up function,

        /* Power up and probe sensor */

        rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);

It’s defined in msm_sensor.c:

static struct msm_sensor_fn_t msm_sensor_func_tbl = {

        .sensor_config = msm_sensor_config,

        .sensor_power_up = msm_sensor_power_up,

        .sensor_power_down = msm_sensor_power_down,

        .sensor_match_id = msm_sensor_match_id,

};

“sensor_power_up” function is very important, I will discuss it later.

 

Back to “msm_sensor_driver_probe”, finally, create /dev/videoX node for user space, this is very unique because it means kernel node is created by user space call.

        /*

         * Create /dev/videoX node, comment for now until dummy /dev/videoX

         * node is created and used by HAL

         */

        pr_err("sensor type is  %d",s_ctrl->sensor_device_type );

        if (s_ctrl->sensor_device_type == MSM_CAMERA_PLATFORM_DEVICE)

                  rc = msm_sensor_driver_create_v4l_subdev(s_ctrl);

 

“msm_sensor_power_up” function call “msm_camera_power_up” which is in msm_camera_dt_util.c, there are many cases and realize the power up timing you pass in user space. After that, “msm_sensor_check_id” function will be called and then jump to “msm_sensor_match_id” in msm_sensor.c. It contain some customized codes that can help to read sensor and vcm data from eeprom through i2c bus.

         rc = msm_camera_power_up(power_info, s_ctrl->sensor_device_type,

                  sensor_i2c_client);

        if (rc < 0)

                  return rc;

        rc = msm_sensor_check_id(s_ctrl);

        if (rc < 0)

                  msm_camera_power_down(power_info, s_ctrl->sensor_device_type,

                                              sensor_i2c_client);

        return rc;

}

If check_id return error message, it will call “msm_camera_power_down” and do the opposite operation comparing with “msm_camera_power_up”.

0 0
原创粉丝点击