[Camera Project] Sprd - Deep and Simple Camera Driver Framework 1(HAL Layer - Kernel Layer)

I. Preface

This paper mainly studies the Camera driver and HAL layer code architecture of Exhibition Platform, and is familiar with the control process of Exhibition Camera.
Platform: Sprd-Exhibition Platform
Hal Version: [HAL3]
The knowledge points are as follows:
From HAL Layer to deiver Layer
1.Camera open, init and power on call process
2. Preview call process
3. snapshot call process

Camera Software Architecture

camera Software Architecture

2. Camera Open and Initial Call Processes

2.1 framework Layer Entrance

After the process of App - > framework layer - > JNI layer - > cameraservice, call to:
frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

status_t Camera3Device::initialize(camera_module_t *module)
{
   ...
  /** Open HAL device */
    status_t res; 
    String8 deviceName = String8::format("%d", mId);

    camera3_device_t *device;
    //Here we call the module - > open function to open the camera.
    res = module->common.methods->open(&module->common, deviceName.string(),
            reinterpret_cast<hw_device_t**>(&device));

    if (res != OK) {
        SET_ERR_L("Could not open camera: %s (%d)", strerror(-res), res);
        return res; 
    }    
...
}

Here we call module - > common. methods - > open to start working on the HAL layer. Let's move on.

2.2 HAL level

vendor/sprd/modules/libcamera/hal3_2v1/SprdCamera3Factory.cpp

struct hw_module_methods_t SprdCamera3Factory::mModuleMethods = { 
    .open = SprdCamera3Factory::camera_device_open,
};

Actually, the SPRADCamera3Factory:: camera_device_open method is called.

int SprdCamera3Factory::camera_device_open(const struct hw_module_t *module,
                                           const char *id,
                                           struct hw_device_t **hw_device) {
···
    if (isSingleIdExposeOnMultiCameraMode(atoi(id))) {
        return gSprdCamera3Wrapper->cameraDeviceOpen(module, id, hw_device);
    } else {
        return gSprdCamera3Factory.cameraDeviceOpen(atoi(id), hw_device);
    }
···
}

Here, open a camera device by its ID, and turn on the camera through ID (post-main: 0 post-secondary: 2 pre-main: 1 pre-secondary: 3)

 

ID

 

Then continue calling gSprdCamera3Factory.cameraDeviceOpen();

int SprdCamera3Factory::cameraDeviceOpen(int camera_id,
                                         struct hw_device_t **hw_device) {
···
    SprdCamera3HWI *hw =
        new SprdCamera3HWI(multiCameraModeIdToPhyId(camera_id));

    rc = hw->openCamera(hw_device);
···
    return rc;
}

Here new an instance of SprdCamera3HWI, then call openCamera(hw_device) method.

vendor/sprd/modules/libcamera/hal3_2v1/SprdCamera3HWI.cpp

int SprdCamera3HWI::openCamera(struct hw_device_t **hw_device) {
···
    ret = openCamera();

    if (ret == 0) { 
        *hw_device = &mCameraDevice.common;
        mCameraSessionActive++;
    } else 
        *hw_device = NULL;
···
    return ret; 
}

Then continue to call the empty constructor openCamera();

int SprdCamera3HWI::openCamera() {
···
    //Example of new SprdCamera 3OEMIf
    mOEMIf = new SprdCamera3OEMIf(mCameraId, mSetting);

    mOEMIf->camera_ioctrl(CAMERA_IOCTRL_SET_MULTI_CAMERAMODE, &mMultiCameraMode,
                          NULL);
    //Open the mOEMIf - > openCamera () method
    ret = mOEMIf->openCamera();

    mCameraOpened = true;
···
    if (mOEMIf->isIspToolMode()) {
        mOEMIf->ispToolModeInit();//Initialize ispToolMode
        startispserver(mCameraId);
        ispvideo_RegCameraFunc(1, ispVideoStartPreview);//Register ispVideoStartPreview function
        ispvideo_RegCameraFunc(2, ispVideoStopPreview);//Register ispVideoStopPreview function
        ispvideo_RegCameraFunc(3, ispVideoTakePicture);//Register ispVideoTakePicture function
        ispvideo_RegCameraFunc(4, ispVideoSetParam);//Register ispVideoSetParam function
    }
···
    return NO_ERROR;
}

Here, the instance of new SprdCamera3OEMIf continues to call the mOEMIf - > openCamera () method.

vendor/sprd/modules/libcamera/hal3_2v1/SprdCamera3OEMIf.cpp

int SprdCamera3OEMIf::openCamera() {
···
    //Set width and height
    mSetting->getLargestPictureSize(mCameraId, &picW, &picH);
    mSetting->getLargestSensorSize(mCameraId, &snsW, &snsH);
    if (picW * picH > snsW * snsH) {
        mLargestPictureWidth = picW;
        mLargestPictureHeight = picH;
    } else {
        mLargestPictureWidth = snsW;
        mLargestPictureHeight = snsH;
    }
    //Set Maximum Size
    mHalOem->ops->camera_set_largest_picture_size(
        mCameraId, mLargestPictureWidth, mLargestPictureHeight);
   //Call startCameraIf Necessary to continue booting the camera
    if (!startCameraIfNecessary()) {
        ret = UNKNOWN_ERROR;
        HAL_LOGE("start failed");
        goto exit;
    }
   //Zero Delay Mode Thread Initialization
    ZSLMode_monitor_thread_init((void *)this);

#ifdef CONFIG_CAMERA_GYRO
    gyro_monitor_thread_init((void *)this);
#endif

    property_get("persist.sys.camera.raw.mode", value, "jpeg");
    if (!strcmp(value, "raw") || !strcmp(value, "bin")) {
        is_raw_capture = 1;
    }

    property_get("persist.sys.isptool.mode.enable", value, "false");
    if (!strcmp(value, "true") || is_raw_capture) {
        mIsIspToolMode = 1;
    }
···
}

SprdCamera 3OEMIf:: OpenCamera mainly does the following things:
1. Setting the maximum size of the image
2. Call startCameraIf Necessary to continue booting the camera
3. Zero Delay Mode Thread Initialization
4. Set properties according to persist.sys.camera.raw.mode and persist.sys.isptool.mode.enable

Continuing with the startCameraIfNecessary method, this method does a lot of things, some complex.

bool SprdCamera3OEMIf::startCameraIfNecessary() {
···
  //If camera is not initialized, initialize
    if (!isCameraInit()) {
        HAL_LOGI("wait for camera_init");
        if (CMR_CAMERA_SUCCESS !=
            mHalOem->ops->camera_init(mCameraId, camera_cb, this, 0,
                                      &mCameraHandle, (void *)Callback_Malloc,
                                      (void *)Callback_Free)) {
            setCameraState(SPRD_INIT);
            HAL_LOGE("CameraIfNecessary: fail to camera_init().");
            return false;
        } else {
            setCameraState(SPRD_IDLE);
        }
···
      //Obtaining Relevant Parameters of Zero Delay Snapshot
        mHalOem->ops->camera_get_zsl_capability(mCameraHandle, &is_support_zsl,
                                                &max_width, &max_height);
      //Judging whether zero delay is supported
        if (!is_support_zsl) {
            mParameters.setZSLSupport("false");
        }

        // Capturing capability, including 3dnr capability
        mHalOem->ops->camera_ioctrl(
            mCameraHandle, CAMERA_IOCTRL_GET_GRAB_CAPABILITY, &grab_capability);

        /*Obtaining sensor and lens information from oem layer*/
        mHalOem->ops->camera_get_sensor_exif_info(mCameraHandle, &exif_info);
        mSetting->getLENSTag(&lensInfo);
        lensInfo.aperture = exif_info.aperture;
        mSetting->setLENSTag(lensInfo);

        /*Obtaining sensor otp from oem layer*/

        /*Start reading refoucs mode*/
        if (MODE_SINGLE_CAMERA != mMultiCameraMode &&
            MODE_3D_CAPTURE != mMultiCameraMode &&
            MODE_BLUR != mMultiCameraMode && MODE_BOKEH != mMultiCameraMode) {
            mSprdRefocusEnabled = true;
            CMR_LOGI("mSprdRefocusEnabled %d", mSprdRefocusEnabled);
        }
        /*End reading refoucs mode*/

        /*Start with getting OPT information from the oem layer */
        if ((MODE_BOKEH == mMultiCameraMode || mSprdRefocusEnabled == true) &&
            mCameraId == 0) {
            OTP_Tag otpInfo;
            memset(&otpInfo, 0, sizeof(OTP_Tag));
            mSetting->getOTPTag(&otpInfo);
            ···
            struct sensor_otp_cust_info otp_info;
            memset(&otp_info, 0, sizeof(struct sensor_otp_cust_info));
            mHalOem->ops->camera_get_sensor_otp_info(mCameraHandle, &otp_info);
           ···
        }
        /*End of Obtaining OTP Information from the oem Layer*/
        /**Add 3d calibration to get maximum sensor size*/
        mSetting->getSPRDDEFTag(&sprddefInfo);
        mHalOem->ops->camera_get_sensor_info_for_raw(mCameraHandle, mode_info);
        for (i = SENSOR_MODE_PREVIEW_ONE; i < SENSOR_MODE_MAX; i++) {
            HAL_LOGD("trim w=%d, h=%d", mode_info[i].trim_width,
                     mode_info[i].trim_height);
            if (mode_info[i].trim_width * mode_info[i].trim_height >=
                sprddefInfo.sprd_3dcalibration_cap_size[0] *
                    sprddefInfo.sprd_3dcalibration_cap_size[1]) {
                sprddefInfo.sprd_3dcalibration_cap_size[0] =
                    mode_info[i].trim_width;
                sprddefInfo.sprd_3dcalibration_cap_size[1] =
                    mode_info[i].trim_height;
            }
        }
···
    return true;
}

This function has added code annotations to the corresponding location, and we continue to focus on the call process, which is initialized by calling camera_init of SprdOEMCamera.c code through mHalOem - > Ops - > camera_init.

vendor/sprd/modules/libcamera/oem2v1/src/SprdOEMCamera.c

cmr_int camera_init(cmr_u32 camera_id, camera_cb_of_type callback,
                    void *client_data, cmr_uint is_autotest,
                    cmr_handle *camera_handle, void *cb_of_malloc,
                    void *cb_of_free) {
···
    //Initialize OEM log   
    oem_init_log_level();

    //Initialization continues by calling camera_local_int
    ret = camera_local_int(camera_id, callback, client_data, is_autotest,
                           camera_handle, cb_of_malloc, cb_of_free); 
···
    //Other initializations
    camera_lls_enable(*camera_handle, 0);
    camera_set_lls_shot_mode(*camera_handle, 0);
    camera_vendor_hdr_enable(*camera_handle, 0);
···
    return ret; 
}

vendor/sprd/modules/libcamera/oem2v1/src/cmr_oem.c

cmr_int camera_local_int(cmr_u32 camera_id, camera_cb_of_type callback,
                         void *client_data, cmr_uint is_autotest,
                         cmr_handle *oem_handle, void *cb_of_malloc,
                         void *cb_of_free) {
···
    //Memory request
    struct camera_context *cxt = NULL;
    *oem_handle = (cmr_handle)0;
    cxt = (struct camera_context *)malloc(sizeof(struct camera_context));

    //parameter assignment
    cmr_bzero(cxt, sizeof(*cxt));
    cxt->camera_id = camera_id;
    cxt->camera_cb = callback;
    cxt->client_data = client_data;
    cxt->hal_malloc = cb_of_malloc;
    cxt->hal_free = cb_of_free;
    cxt->hal_gpu_malloc = NULL; 
    cxt->is_multi_mode = is_multi_camera_mode_oem;
    cxt->blur_facebeauty_flag = 0;
    
    //Call camera_init_internal for next initialization
    ret = camera_init_internal((cmr_handle)cxt, is_autotest);
···
    return ret;
}

Call camera_init_internal for next initialization

cmr_int camera_init_internal(cmr_handle oem_handle, cmr_uint is_autotest) {
···
    //sensor initialization
    ret = camera_sensor_init(oem_handle, is_autotest);
    if (ret) {
        CMR_LOGE("failed to init sensor %ld", ret);
        goto exit;
    }
    //grab initialization
    ret = camera_grab_init(oem_handle);
    if (ret) {
        CMR_LOGE("failed to init grab %ld", ret);
        goto sensor_deinit;
    }
    //res initialization
    ret = camera_res_init(oem_handle);
    if (ret) {
        CMR_LOGE("failed to init res %ld", ret);
        goto grab_deinit;
    }
    //isp initialization
    ret = camera_isp_init(oem_handle);
    if (ret) {
        CMR_LOGE("failed to init isp %ld", ret);
        goto res_deinit;
    }
    //Initialization complete
    ret = camera_res_init_done(oem_handle);

···
    return ret;
}

This function mainly does the following things:
1.sensor initialization
2.grab initialization
3.res initialization
4.isp initialization
Let's continue to focus on the camera_sensor_init function

cmr_int camera_sensor_init(cmr_handle oem_handle, cmr_uint is_autotest) {
···
    ret = cmr_sensor_init(&init_param, &sensor_handle);

    ret = cmr_sensor_open(sensor_handle, camera_id_bits);
···
}

This function calls cmr_sensor_init initialization and cmr_sensor_open to open Camera, respectively.

vendor/sprd/modules/libcamera/oem2v1/src/cmr_sensor.c

cmr_int cmr_sensor_init(struct sensor_init_param *init_param_ptr,
                        cmr_handle *sensor_handle) {
···
    /*save init param*/
    handle->oem_handle = init_param_ptr->oem_handle;
    handle->sensor_bits = init_param_ptr->sensor_bits;
    handle->private_data = init_param_ptr->private_data;
    handle->is_autotest = init_param_ptr->is_autotest;

    /*create thread*/
    ret = cmr_sns_create_thread(handle);
···
    return ret;
}

This function assigns some parameters, and then calls the cmr_sns_create_thread method to create the cmr_sns_thread_proc thread. As follows:
ret = cmr_thread_create(&handle->thread_cxt.thread_handle,
SENSOR_MSG_QUEUE_SIZE,cmr_sns_thread_proc,
(void *)handle)

cmr_int cmr_sensor_open(cmr_handle sensor_handle, cmr_u32 sensor_id_bits) {
···
    struct cmr_sensor_handle *handle =
        (struct cmr_sensor_handle *)sensor_handle;

    /*the open&close function should be sync*/
    message.msg_type = CMR_SENSOR_EVT_OPEN;
    message.sync_flag = CMR_MSG_SYNC_PROCESSED;
    message.data = (void *)((unsigned long)sensor_id_bits);
    //Send the msg message here to start the one created in cmr_sensor_init
    ret = cmr_thread_msg_send(handle->thread_cxt.thread_handle, &message);
···
    return ret;
}

In cmr_sensor_open, an msg message is sent to start the thread cmr_sns_thread_proc created in cmr_sensor_init.
The message type here is message.msg_type = CMR_SENSOR_EVT_OPEN;

cmr_int cmr_sns_thread_proc(struct cmr_msg *message, void *p_data) {
···
    switch (evt) {
    case CMR_SENSOR_EVT_INIT:
        /*common control info config*/
        CMR_LOGI("INIT DONE!");
        break;

    case CMR_SENSOR_EVT_OPEN:
        /*camera sensor open for every bits*/
        ops_param = (cmr_u32)((unsigned long)message->data);
        ret = cmr_sns_open(handle, ops_param);
        if (ret) {
            /* notify oem through fd_sensor */
            CMR_LOGE("cmr_sns_open failed!");
        }    
        return CMR_CAMERA_INVALID_PARAM;
    }
 ···
}

Therefore, we will follow the branch case CMR_SENSOR_EVT_OPEN and call the cmr_sns_open method.

cmr_int cmr_sns_open(struct cmr_sensor_handle *handle, cmr_u32 sensor_id_bits) {
···
    /*open all signed camera sensor*/
    for (cameraId = 0; cameraId < CAMERA_ID_MAX; cameraId++) {
        if (0 != (sensor_id_bits & (1 << cameraId))) {
            ret = sensor_open_common(&handle->sensor_cxt[cameraId], cameraId,
                                     handle->is_autotest);
            if (ret) {
                CMR_LOGE("camera %u open failed!", cameraId);
            } else {
                handle->sensor_bits |= (1 << cameraId);
            }
        }
    }
···
}

The cmr_sns_open method continues to call the sensor_open_common function, which is more complex. The main work is as follows:
1. Initialize the structure ctx(context)
2. Initialize exif information (photo information)
3. Load the sensor file file, which saves the id of camera
4. Open the camera according to the id of the camera saved in the sensor file
Let's look at the code:
vendor/sprd/modules/libcamera/sensor/sensor_drv_u.c

cmr_int sensor_open_common(struct sensor_drv_context *sensor_cxt,
                           cmr_u32 sensor_id, cmr_uint is_autotest) {
···
    /* Initialize the structure ctx(context) by calling sensor_context_init*/
    ret_val = sensor_context_init(sensor_cxt, sensor_id, is_autotest);
  
    /* Create sensor_ctrl_thread_proc thread. */
    ret_val = sensor_create_ctrl_thread(sensor_cxt);

    /* Initialize the structure hw_drv_init_para of the kernel driver. */
    struct hw_drv_init_para input_ptr;
    cmr_int fd_sensor = SENSOR_FD_INIT;//SENSOR_FD_INIT =-1
    cmr_handle hw_drv_handle = NULL;
    input_ptr.sensor_id = sensor_id;
    input_ptr.caller_handle = sensor_cxt;
    fd_sensor = hw_sensor_drv_create(&input_ptr, &hw_drv_handle);
    if ( (SENSOR_FD_INIT == fd_sensor) || (NULL == hw_drv_handle) ) {
        SENSOR_LOGE("sns_device_init %d error, return", sensor_id);
        ret_val = SENSOR_FAIL;
        goto init_exit;
    }
    //Initialize sensor_cxt
    sensor_cxt->fd_sensor = fd_sensor;
    sensor_cxt->hw_drv_handle = hw_drv_handle;
    sensor_cxt->sensor_hw_handler = hw_drv_handle;

   /* Load all sensor ic information according to the index stored in the sensor idx file*/
    sensor_load_idx_inf_file(sensor_cxt);
    if (sensor_cxt->sensor_identified) {
        if (SENSOR_SUCCESS == sns_load_drv(sensor_cxt, SENSOR_MAIN)){
            sensor_num++;
        }
···
        SENSOR_LOGI("1 is identify, register OK");
        /*Read id information and open it.*/
        ret_val = sensor_open(sensor_cxt, sensor_id);
        if (ret_val != SENSOR_SUCCESS) {
            SENSOR_LOGI("first open sensor failed,start identify");
        }
    }

    /* Scanning the devices in the cfg table to find the correct sensor driver */
    if ((!sensor_cxt->sensor_identified) || (ret_val != SENSOR_SUCCESS)) {
        sensor_num = 0;
        SENSOR_LOGI("register sensor fail, start identify");
        //The core function of traversal is sensor_identify
        if (sensor_identify(sensor_cxt, SENSOR_MAIN))
            sensor_num++;
···
        //After successful traversal, continue to execute the sensor_open action
        ret_val = sensor_open(sensor_cxt, sensor_id);
    }
    sensor_cxt->sensor_identified = SCI_TRUE;//Set the state of sensor_id to TRUE

    sensor_save_idx_inf_file(sensor_cxt);//Save the identified id information to / data/misc/cameraserver/sensor.file
    //Save node information to / sys/devices/virtual/misc/sprd_sensor/camera_sensor_name
    sensor_rid_save_sensor_info(sensor_cxt);
···
    return ret_val;
}

Analysis: first, do some necessary initialization, then call the sensor_load_idx_inf_file function to load the sensor.file file under the /data/misc/cameraserver/ path.

1. If you read the sensor_id, set the sensor_cxt-> sensor_identified to SCI_TRUE (this value is 1), go to the sns_load_drv(sensor_cxt, SENSOR_MAIN) function to register the driver, and then directly execute the sensor_open action.

2. Otherwise, call sensor_identify(sensor_cxt, SENSOR_MAIN) to traverse the sensor list, scan the devices in the cfg table, and find out the correct sensor driver.

After the above success, the sensor_open function is called:
1. Initialization of AF sensor_af_init()
2.OTP reads otp_module_init()
3. Setting of Photo Information sensor_set_export_Info()

The flow chart is as follows:

sensor_open_common process

 

Sensor_identity Scanning Process

LOCAL cmr_int sensor_identify(struct sensor_drv_context *sensor_cxt,
                              SENSOR_ID_E sensor_id) {
···
    ret = sensor_get_match_info(sensor_cxt, sensor_id);

    ret = sensor_ic_identify(sensor_cxt, sensor_id);

    retValue = sensor_identify_search(sensor_cxt, sensor_id);
    return retValue;
}

Analysis:

1. First, we call sensor_get_match_info to get our own camera driver. The process is as follows:

Sensor_get_match_info-> sensor_get_module_tab-> back_sensor_infor_tab (as shown below)

vendor/sprd/modules/libcamera/sensor/sensor_cfg.c

That's why when we add a new Camea to the driver engineer, we add our driver to the cfg list.

const SENSOR_MATCH_T back_sensor_infor_tab[] = {
// gc area
#ifdef GC5005
    {MODULE_SUNNY, "gc5005", &g_gc5005_mipi_raw_info, {&dw9714_drv_entry, 0}, NULL},
#endif
#ifdef GC8024
    {MODULE_SUNNY, "gc8024", &g_gc8024_mipi_raw_info, {&dw9714_drv_entry, 0}, NULL},
#endif
#ifdef GC030A
    {MODULE_SUNNY, "gc030a", &g_gc030a_mipi_raw_info, {NULL, 0}, NULL},
#endif
#ifdef GC2385
    {MODULE_SUNNY, "gc2385", &g_gc2385_mipi_raw_info, {NULL, 0}, NULL},
#endif
···
}

2. then call sensor_ic_identify to identify ic information.

The identification steps are as follows:
1. Establishment of sensor IC driver structure
2. Configure I2C bus, sensor ID, I2C clock, from addr, reg addr lenth, data length
3. Power sensor IC
4. Identify PID and VID of sensor IC
5. Delete sensor IC Driver Architecture

The flow chart of sensor_ic_identity traversal is as follows.

Through sns_ops-> power (sensor_cxt-> sns_ic_drv_handle, power_on); call to the sensor driven power_on interface,
For example, ov8856_drv_power_on()

Sns_ops-> identify (sensor_cxt-> sns_ic_drv_handle, SENSOR_ZERO_I2C); call to the identify interface driven by sensor,
For example, ov8856_drv_identify()

identify process

 

static cmr_int sensor_ic_identify(struct sensor_drv_context *sensor_cxt,
                                  cmr_u32 sensor_id) {

···
    //1. Establishment of sensor IC driver structure
    struct sensor_ic_ops *sns_ops = PNULL;
    struct sensor_ic_drv_init_para sns_init_para;

    register_info = &sensor_cxt->sensor_register_info;
    sns_ops = sensor_cxt->sensor_info_ptr->sns_ops;

    sensor_cxt->i2c_addr = mod_cfg_info->major_i2c_addr;
    /* Create sensor handle */
    ret = sensor_ic_create(sensor_cxt, sensor_id);

try: /*sensor has backup addr*/
        if (sns_ops && sns_ops->identify) {

            /*2.Initialize i2c configuration*/
            hw_drv_cfg.i2c_bus_config = mod_cfg_info->reg_addr_value_bits;
            hw_sensor_drv_cfg(sensor_cxt->hw_drv_handle, &hw_drv_cfg);
            sensor_i2c_init(sensor_cxt, sensor_id);
            //Setting i2c address
            hw_sensor_i2c_set_addr(sensor_cxt->hw_drv_handle,
                                   sensor_cxt->i2c_addr);
            //Setting i2c clock
            hw_sensor_i2c_set_clk(sensor_cxt->hw_drv_handle);
···
            //3. Power sensor
            sensor_power_on(sensor_cxt, SCI_TRUE); /*power on*/
            //Call the specific driver to identify
            ret = sns_ops->identify(sensor_cxt->sns_ic_drv_handle,
                                    SENSOR_ZERO_I2C);
            if (SENSOR_SUCCESS == ret) {
                /**if the following is SCI_FALSE,that is,now is in identify
                 *process
                 * should delete sensor ic handle
                 **/
                if (register_info->is_register[sensor_id] != SCI_TRUE) {
                    sensor_power_on(sensor_cxt, SCI_FALSE);
                    sensor_i2c_deinit(sensor_cxt, sensor_id);
                    sensor_ic_delete(sensor_cxt);
                }
                sensor_cxt->sensor_list_ptr[sensor_id] =
                    sensor_cxt->sensor_info_ptr;
                register_info->is_register[sensor_id] = SCI_TRUE;
                register_info->img_sensor_num++;
            } else {
                // register_info->is_register[sensor_id] = SCI_FALSE;
                sensor_power_on(sensor_cxt, SCI_FALSE);
                if ((sensor_cxt->i2c_addr != mod_cfg_info->minor_i2c_addr) &&
                    mod_cfg_info->minor_i2c_addr != 0x00) {
                    sensor_cxt->i2c_addr = mod_cfg_info->minor_i2c_addr;
                    SENSOR_LOGI("use backup i2c address,try again!");
                    goto try
                        ;
                }
                SENSOR_LOGI("identify failed!");
                //Delete sensor IC information if identified failed
                sensor_ic_delete(sensor_cxt);
                return SENSOR_FAIL;
            }
        }

    return ret;
}

PS: power on process is also where we drive engineers to modify frequently. Here's a few words. Take ov8856 as an example.

This is mainly three-way voltage, avdd, dvdd, iovdd set up power supply, specific reference to my previous article: Camera HW - Hardware Knowledge You Should Know

1. Power supply part
camera contains three voltage channels: analog voltage (VCAMA), digital voltage (VCAMD), and IO port voltage (VCAMIO).
a) VCAMD DVDD digital power supply, mainly ISP power supply
(b) VCAM_IO VDDIO digital IO power supply mainly to I2C part of the power supply;
c) VCAMA AVDD analog power supply, mainly for the photosensitive area and ADC part of the power supply;
d) VCAM_AF_is the power supply for Camera_autofocus motor

/*==============================================================================
 * Description:
 * sensor power on
 * please modify this function acording your spec
 *============================================================================*/
static cmr_int ov8856_drv_power_on(cmr_handle handle, cmr_u32 power_on) {
    SENSOR_IC_CHECK_HANDLE(handle);
···
    if (SENSOR_TRUE == power_on) {
        //Power on process
        //Pull down the pnd foot first
        hw_sensor_power_down(sns_drv_cxt->hw_handle, power_down);
        //Pull down the reset foot
        hw_sensor_set_reset_level(sns_drv_cxt->hw_handle, reset_level);
        usleep(500);//The delay is 500 microseconds. The delay here is based on the specifications.
        //Set av voltage to supply power to sensory area and adc
        hw_sensor_set_avdd_val(sns_drv_cxt->hw_handle, avdd_val);
        //Set DVDD Voltage, mainly to ISP power supply
        hw_sensor_set_dvdd_val(sns_drv_cxt->hw_handle, dvdd_val);
        //Setting IO voltage, IO power supply mainly supplies part of I2C power supply.
        hw_sensor_set_iovdd_val(sns_drv_cxt->hw_handle, iovdd_val);
        usleep(500);//Delay 500 microseconds
        //Pull up PND feet
        hw_sensor_power_down(sns_drv_cxt->hw_handle, !power_down);
        //Pull up rst feet
        hw_sensor_set_reset_level(sns_drv_cxt->hw_handle, !reset_level);
        usleep(500);//Delay 500 microseconds
        //Setting mclk clock
        hw_sensor_set_mclk(sns_drv_cxt->hw_handle, EX_MCLK);
    } else {//Down current path, contrary to power supply
        hw_sensor_set_mclk(sns_drv_cxt->hw_handle, SENSOR_DISABLE_MCLK);
        usleep(500);
        hw_sensor_set_reset_level(sns_drv_cxt->hw_handle, reset_level);
        hw_sensor_power_down(sns_drv_cxt->hw_handle, power_down);
        usleep(200);
        hw_sensor_set_avdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
        hw_sensor_set_dvdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
        hw_sensor_set_iovdd_val(sns_drv_cxt->hw_handle, SENSOR_AVDD_CLOSED);
    }
    SENSOR_LOGI("(1:on, 0:off): %d", power_on);
    return SENSOR_SUCCESS;
}

PS2: Ideify implementation is also posted, continue to verbose a few sentences, to ov8856 power-on as an example
Add key code comments, easy to understand!

/*==============================================================================
 * Description:
 * identify sensor id
 * please modify this function acording your spec
 *============================================================================*/
static cmr_int ov8856_drv_identify(cmr_handle handle, cmr_uint param) {
···
    //hw_sensor_read_reg reads register information
    pid_value = hw_sensor_read_reg(sns_drv_cxt->hw_handle, ov8856_PID_ADDR);
    //Identify the specific sendor id
    if (ov8856_PID_VALUE == pid_value) {
        ver_value = hw_sensor_read_reg(sns_drv_cxt->hw_handle, ov8856_VER_ADDR);
        SENSOR_LOGI("Identify: PID = %x, VER = %x", pid_value, ver_value);
        if (ov8856_VER_VALUE == ver_value) {
            SENSOR_LOGI("this is ov8856 sensor");
            //Save id information
            ov8856_drv_init_fps_info(handle);
            ret_value = SENSOR_SUCCESS;
        } else {
            SENSOR_LOGI("Identify this is %x%x sensor", pid_value, ver_value);
        }
    } else {
        SENSOR_LOGE("sensor identify fail, pid_value = %x", pid_value);
    }

    return ret_value;
}

3. Finally, if identify fails, re-execute the above two steps and re-iterate

 

The sensor_identify_search function is implemented as follows:

LOCAL cmr_u32 sensor_identify_search(struct sensor_drv_context *sensor_cxt,
                                     SENSOR_ID_E sensor_id) {
···
    //Call sensor_get_match_info to get our own camera driver
    module_tab = sensor_get_module_tab(sensor_cxt->is_autotest, sensor_id);
···
    //Call sensor_ic_identity to identify ic information
    retValue = sensor_ic_identify(sensor_cxt, sensor_id);
···
    return retValue;
}

The first part of this article is finished. Take a breath, drink water, and continue to write the second part!

Preview call process

[Hal level]

vendor/sprd/modules/libcamera/hal3_2v1a/SprdCamera3HWI.cpp

int SprdCamera3HWI::openCamera() {
···
      //Register ispVideoStartPreview function
       ispvideo_RegCameraFunc(1, ispVideoStartPreview);
···
}

In the openCamera function, register ispVideoStartPreview through this ispvideo_RegCameraFunc(1, ispVideoStartPreview); and

static int ispVideoStartPreview(uint32_t param1, uint32_t param2) {
···
rtn = regularChannel->start(dev->mFrameNum);
···
}

Next, call regular Channel - > start (dev - > mFrameNum) to go down

vendor/sprd/modules/libcamera/hal3_2v1/SprdCamera3Channel.cpp

int SprdCamera3RegularChannel::start(uint32_t frame_number) {
    int ret = NO_ERROR;
    size_t i = 0; 

    ret = mOEMIf->start(mChannelType, frame_number);
    return ret; 
}

Here's the type:
typedef enum {
CAMERA_CHANNEL_TYPE_DEFAULT, / default /
CAMERA_CHANNEL_TYPE_REGULAR, / regular channel /
CAMERA_CHANNEL_TYPE_PICTURE, / picture channel/
CAMERA_CHANNEL_TYPE_RAW_CALLBACK, /YUV888 callback/
CAMERA_CHANNEL_TYPE_MAX,
} camera_channel_type_t;
Then call RET = mOEMIf - > start (mChannelType, frame_number);

vendor/sprd/modules/libcamera/hal3_2v1/SprdCamera3OEMIf.cpp

int SprdCamera3OEMIf::start(camera_channel_type_t channel_type,
                            uint32_t frame_number) {
···
    switch (channel_type) {
    case CAMERA_CHANNEL_TYPE_REGULAR: {
···
        ret = startPreviewInternal();//Follow up here
        break;
    }
    //Here's the photo section. We're going to analyze the next section.
    case CAMERA_CHANNEL_TYPE_PICTURE: {
        if (mTakePictureMode == SNAPSHOT_NO_ZSL_MODE ||
                ret = takePicture();
            }
        else if (mTakePictureMode == SNAPSHOT_ZSL_MODE) {

                ret = zslTakePicture();
        } else if (mTakePictureMode == SNAPSHOT_VIDEO_MODE) {
            ret = VideoTakePicture();
        }
        break;
    }
    default:
        break;
    }
···
    return ret;
}

If the type is CAMERA_CHANNEL_TYPE_REGULAR, then call:
RET = startPreview Internal (); // Follow up here
If the type is CAMERA_CHANNEL_TYPE_PICTURE, the camera correlation is called:
ret = takePicture();
ret = zslTakePicture();
ret = VideoTakePicture();

int SprdCamera3OEMIf::startPreviewInternal() {
···
    //When preview ing, set the thumbnail size of the photo to match the size of the camera app
    chooseDefaultThumbnailSize(&jpeg_thumb_size.width, &jpeg_thumb_size.height);
···
    ret = mHalOem->ops->camera_start_preview(mCameraHandle, mCaptureMode);
···
}

MHalOem - > Ops - > camera_start_preview (mCameraHandle, mCaptureMode); the implementation of the method in SpreadOEMCamera. C
vendor/sprd/modules/libcamera/oem2v1/src/SprdOEMCamera.c

cmr_int camera_start_preview(cmr_handle camera_handle,
                             enum takepicture_mode mode) {
···
    ret = camera_local_start_preview(camera_handle, mode, CAMERA_PREVIEW);
···
    return ret; 
}

[OEM level]

This function is simple, so continue calling the camera_local_start_preview function.
vendor/sprd/modules/libcamera/oem2v1/src/cmr_oem.c

cmr_int camera_local_start_preview(cmr_handle oem_handle,
                                   enum takepicture_mode mode, 
                                   cmr_uint is_snapshot) {
    //Setting parameters for preview
    ret = camera_set_preview_param(oem_handle, mode, is_snapshot);
    //Continue cmr_preview_start
    ret = cmr_preview_start(prev_cxt->preview_handle, cxt->camera_id);

···
    return ret;
}

This function sets the parameter information of preview, and then continues to call the cmr_preview_start method.
vendor/sprd/modules/libcamera/oem2v1/src/cmr_preview.c

cmr_int cmr_preview_start(cmr_handle preview_handle, cmr_u32 camera_id) {
···
    message.msg_type = PREV_EVT_ASSIST_START;//Setting type type type PREV_EVT_ASSIST_START of msg
    message.sync_flag = CMR_MSG_SYNC_PROCESSED;//Setting up flag for msg
    //Send msg messages
    ret = cmr_thread_msg_send(handle->thread_cxt.assist_thread_handle, &message);
···
    message.msg_type = PREV_EVT_START;//Setting type type type PREV_EVT_START of msg
    message.sync_flag = CMR_MSG_SYNC_PROCESSED;//Setting up flag for msg
    message.data = (void *)((unsigned long)camera_id);
    //Send msg message
    ret = cmr_thread_msg_send(handle->thread_cxt.thread_handle, &message);

···
    return ret;
}

Here we call cmr_thread_msg_send to send two MSG messages.

The first msg = message

assist_thread_handle=prev_assist_thread_proc
Creation of the handle:
Called in prev_create_thread (struct prev_handle*handle)
ret = cmr_thread_create(&handle>thread_cxt.assist_thread_handle,PREV_MSG_QUEUE_SIZE, prev_assist_thread_proc, (void *)handle);

cmr_int prev_assist_thread_proc(struct cmr_msg *message, void *p_data) {
···
    msg_type = (cmr_u32)message->msg_type;//Obtain msg_tyoe
    //Operate according to msg_type
    switch (msg_type) {
    case PREV_EVT_ASSIST_START:
        handle->frame_active = 1;
        break;
···
    case PREV_EVT_ASSIST_STOP:
        handle->frame_active = 0;
        break;
···
    return ret;
}

When msg_type=PREV_EVT_ASSIST_START:
Just handle - > frame_active = 1;

The second msg = message

thread_cxt.thread_handle=prev_thread_proc

cmr_int prev_thread_proc(struct cmr_msg *message, void *p_data) {
···
    switch (msg_type) {
···
    case PREV_EVT_START:
        camera_id = (cmr_u32)((unsigned long)message->data);

        prev_recovery_reset(handle, camera_id);
        ret = prev_start(handle, camera_id, 0, 0);
        /*Notify preview started*/
        cb_data_info.cb_type = PREVIEW_EXIT_CB_PREPARE;
        cb_data_info.func_type = PREVIEW_FUNC_START_PREVIEW;
        cb_data_info.frame_data = NULL;
        prev_cb_start(handle, &cb_data_info);
        break;
···
}

Analysis:
1.ret = prev_start(handle, camera_id, 0, 0) call process as follows:

ret = handle->ops.channel_start(···);[cmr_preview.c]
  ->cmr_int camera_channel_start(···);[cmr_oem.c]
    ->cmr_int cmr_grab_cap_start(···)[cmr_grab.c]
      ->ret = ioctl(p_grab->fd, SPRD_IMG_IO_SET_CAP_SKIP_NUM, &num);[cmr_grab.c]

[kernel layer]

Call the method of kernel layer through ioctl
After the above series of complex processes, we can see that cmr_grab_cap_start() is called into the kernel directory to open DCAM, and cmr_grab_cap_start calls the method of the kernel layer through ioctl.

cmr_int cmr_grab_cap_start(cmr_handle grab_handle, cmr_u32 skip_num) {
···
    ret = ioctl(p_grab->fd, SPRD_IMG_IO_SET_CAP_SKIP_NUM, &num);
    ATRACE_BEGIN("dcam_stream_on");
    ret = ioctl(p_grab->fd, SPRD_IMG_IO_STREAM_ON, &stream_on);
···
    return ret;
}

kernel/drivers/misc/sprd_camera/dcam/dcam_if_r4p0/dcam_ioctrl.c

{SPRD_IMG_IO_STREAM_ON,     dcamio_stream_on},
static int dcamio_stream_on(struct camera_file *camerafile,
             unsigned long arg, 
             unsigned int cmd) 
{
···
    ret = sprd_img_get_dcam_dev(camerafile, &dev, &info);

    ret = sprd_camera_stream_on(camerafile);
···
    return ret; 
}

2. The prev_cb_start (handle, & cb_data_info) call process is as follows:

prev_cb_start(handle, &cb_data_info)//cmr_preview.c
 ->ret = cmr_thread_msg_send(···);//cmr_preview.c
   //message.msg_type = PREV_EVT_CB_START;cb_thread_handle = prev_cb_thread_proc
  ->ret = handle->oem_cb(···)//cmr_preview.c
      //handle->oem_cb = init_param_ptr->oem_cb=camera_preview_cb;
    ->ret = cmr_thread_msg_send(···);// oem2v1/src/cmr_oem.c
      //message.sub_msg_type = oem_cb_type;
      //prev_cb_thr_handle = camera_preview_cb_thread_proc
      ->callback(···);

vendor/sprd/modules/libcamera/oem2v1/src/cmr_oem.c

cmr_int camera_preview_cb_thread_proc(struct cmr_msg *message, void *data) {
···
  callback = cxt->camera_cb;
  callback(message->sub_msg_type, cxt->client_data, 
                        message->msg_type, message->data);
···
    return ret; 
}

Here callback is CXT - > camera_cb, which is implemented in SPRAD Camera 3OEMIf:: camera_cb (....);

vendor/sprd/modules/libcamera/hal3_2v1/SprdCamera3OEMIf.cpp

void SprdCamera3OEMIf::camera_cb(enum camera_cb_type cb,
                                 const void *client_data,
                                 enum camera_func_type func, void *parm4) {
···
    switch (func) {
    case CAMERA_FUNC_START_PREVIEW:
        obj->HandleStartPreview(cb, parm4);
        break;
···

Here in oem_func = CAMERA_FUNC_START_PREVIEW; therefore continue to call Handle Start Preview (cb, parm4);

void SprdCamera3OEMIf::HandleStartPreview(enum camera_cb_type cb, void *parm4) {
···
            receivePreviewFrame((struct camera_frame_type *)parm4);
···
}

Here is to call receivePreviewFrame to receive frame data

void SprdCamera3OEMIf::receivePreviewFrame(struct camera_frame_type *frame) {
···
    //Receiving frame data
    channel->getStream(CAMERA_STREAM_TYPE_PREVIEW, &pre_stream);
    channel->getStream(CAMERA_STREAM_TYPE_VIDEO, &rec_stream);
    channel->getStream(CAMERA_STREAM_TYPE_CALLBACK, &callback_stream);
    HAL_LOGV("pre_stream %p, rec_stream %p, callback_stream %p", pre_stream,
             rec_stream, callback_stream);
//Beauty
#ifdef CONFIG_FACE_BEAUTY
    int sx, sy, ex, ey, angle, pose;
    struct face_beauty_levels beautyLevels;
    beautyLevels.blemishLevel =
        (unsigned char)sprddefInfo.perfect_skin_level[0];
    beautyLevels.smoothLevel = (unsigned char)sprddefInfo.perfect_skin_level[1];
    beautyLevels.skinColor = (unsigned char)sprddefInfo.perfect_skin_level[2];
    beautyLevels.skinLevel = (unsigned char)sprddefInfo.perfect_skin_level[3];
    beautyLevels.brightLevel = (unsigned char)sprddefInfo.perfect_skin_level[4];
    beautyLevels.lipColor = (unsigned char)sprddefInfo.perfect_skin_level[5];
    beautyLevels.lipLevel = (unsigned char)sprddefInfo.perfect_skin_level[6];
    beautyLevels.slimLevel = (unsigned char)sprddefInfo.perfect_skin_level[7];
    beautyLevels.largeLevel = (unsigned char)sprddefInfo.perfect_skin_level[8];
#endif
···
}

This function is very complex to implement, mainly used for recevie Frame data here, as well as beauty, specific details later analysis.

4. Snaphot Call Process

[Hal level]

Let's start with SprdCamera3OEMIf::start to analyze how to call this function, which has been analyzed before, so let's not go into details!

vendor/sprd/modules/libcamera/hal3_2v1/SprdCamera3OEMIf.cpp

int SprdCamera3OEMIf::start(camera_channel_type_t channel_type,
                            uint32_t frame_number) {
···
    switch (channel_type) {
···
    case CAMERA_CHANNEL_TYPE_PICTURE: {
        if (···)
            setCamPreformaceScene(CAM_CAPTURE_S_LEVEL_NH);
        }

        if (mTakePictureMode == SNAPSHOT_NO_ZSL_MODE ||
            mTakePictureMode == SNAPSHOT_ONLY_MODE)
            ···
                ret = takePicture();
            ···
        else if (mTakePictureMode == SNAPSHOT_ZSL_MODE) {
            mVideoSnapshotFrameNum = frame_number;
            ···
                ret = zslTakePicture();
            ···
        } else if (mTakePictureMode == SNAPSHOT_VIDEO_MODE) {
            mVideoSnapshotFrameNum = frame_number;
            ret = VideoTakePicture();
        }
        break;
    }
···
    }
···
}

Analysis: First channel_type=CAMERA_CHANNEL_TYPE_PICTURE, and then the following actions are performed:
1.setCamPreformaceScene(CAM_CAPTURE_S_LEVEL_NH); Set Camera scenarios, the type of scenarios is as follows

typedef enum CAMERA_PERFORMACE_SCENE {
    CAM_OPEN_S,
    CAM_OPEN_E_LEVEL_H,     // DFS:veryhigh
    CAM_OPEN_E_LEVEL_N,     // DFS:normal
    CAM_OPEN_E_LEVEL_L,     // DFS:low
    CAM_PREVIEW_S_LEVEL_H,  // powerhint:performance
    CAM_PREVIEW_S_LEVEL_N,  // powerhint:normal
    CAM_PREVIEW_S_LEVEL_L,  // powerhint:low
    CAM_CAPTURE_S_LEVEL_HH, // powerhint:performance  DFS:veryhigh
    CAM_CAPTURE_S_LEVEL_HN, // powerhint:performance  DFS:normal
    CAM_CAPTURE_S_LEVEL_NH, // powerhint:normal  DFS:veryhigh
    CAM_CAPTURE_S_LEVEL_NN, // powerhint:normal  DFS:normal
    CAM_CAPTURE_E_LEVEL_NH, // powerhint:normal  DFS:veryhigh
    CAM_CAPTURE_E_LEVEL_NN, // powerhint:normal  DFS:normal
    CAM_CAPTURE_E_LEVEL_NL, // powerhint:normal  DFS:low
    CAM_CAPTURE_E_LEVEL_LN, // powerhint:low DFS:normal
    CAM_CAPTURE_E_LEVEL_LL, // powerhint:low  DFS:low
    CAM_CAPTURE_E_LEVEL_LH, // powerhint:low  DFS:veryhigh
    CAM_FLUSH_S,
    CAM_FLUSH_E,
    CAM_EXIT_S,
    CAM_EXIT_E,
} sys_performance_camera_scene;

2. Call different photography methods according to mTakePictureMode

  • The first is the general photography mode.
    mTakePictureMode =SNAPSHOT_NO_ZSL_MODE or SNAPSHOT_ONLY_MODE
    ret = takePicture();
  • Second: Zero Delay Photography (What's the preview, what's the picture taken, WYSIWYG)
    mTakePictureMode == SNAPSHOT_ZSL_MODE
    ret = zslTakePicture();
  • Third: Video mode
    mTakePictureMode == SNAPSHOT_VIDEO_MODE
    ret = VideoTakePicture();

There are three branches, here we choose the ordinary photography mode branch to continue the analysis.

int SprdCamera3OEMIf::takePicture() {
···
    mHalOem->ops->camera_take_picture(mCameraHandle, mCaptureMode)
···
}

In fact, the takePicture function has many operations, such as: whether the camera has preview, if not, first preview, second, whether the camera is capturing (screenshot), if so, wait until the end of capturing and so on. Last call
MHalOem - > Ops - > camera_take_picture (mCameraHandle, mCaptureMode) calls to the oem layer.

OEM Layer (Exhibition Message Packaging Layer, Hal Layer and Driver Layer Communication Intermediate Bridge)

vendor/sprd/modules/libcamera/oem2v1/src/SprdOEMCamera.c

cmr_int camera_take_picture(cmr_handle camera_handle,
                            enum takepicture_mode cap_mode) {
···
    ret = camera_local_start_snapshot(camera_handle, cap_mode, CAMERA_SNAPSHOT);
    if (ret) {
        CMR_LOGE("failed to start snapshot %ld", ret);
    }    
···
}

Analysis: This letter is very simple. It calls camera_local_start_snapshot directly to take photos.
vendor/sprd/modules/libcamera/oem2v1/src/cmr_oem.c

cmr_int camera_local_set_cap_size(cmr_handle oem_handle,
                                  cmr_u32 is_reprocessing, cmr_u32 camera_id,
                                  cmr_u32 width, cmr_u32 height) {
    //1
    ret = cmr_snapshot_post_proc(cxt->snp_cxt.snapshot_handle, &snp_param);
    //2
    ret = camera_local_start_capture(oem_handle);
    //3
    ret = cmr_snapshot_receive_data(cxt->snp_cxt.snapshot_handle,
                                        SNAPSHOT_EVT_CHANNEL_DONE,
                                       (void *)&frame);
}

Analysis: This function mainly does the following things:
1. Call the cmr_snapshot_post_proc() function to send an msg message
2. Call the camera_local_start_capture() function to continue the photography process
3. Data taken by calling cmr_snapshot_receive_data() function receive

First look

1. Call the cmr_snapshot_post_proc() function to send an msg message

vendor/sprd/modules/libcamera/oem2v1/src/cmr_snapshot.c

cmr_int cmr_snapshot_post_proc(cmr_handle snapshot_handle,
                               struct snapshot_param *param_ptr) {
···
    message.msg_type = SNP_EVT_START_PROC;
    message.sync_flag = CMR_MSG_SYNC_PROCESSED;
    message.alloc_flag = 0;
    message.data = param_ptr;
    ret = cmr_thread_msg_send(cxt->thread_cxt.main_thr_handle, &message);
···
}

Message type: message.msg_type = SNP_EVT_START_PROC;
The thread processing function is snp_main_thread_proc.
Let's look at this handler:

cmr_int snp_main_thread_proc(struct cmr_msg *message, void *p_data) {
···
    switch (message->msg_type) {
···
    case SNP_EVT_START_PROC:
        ret = snp_set_post_proc_param(snp_handle,
                                      (struct snapshot_param *)message->data);
        break;
···
    }
···
}

Analysis: Call snp_set_post_proc_param function directly

cmr_int snp_set_post_proc_param(cmr_handle snp_handle,
                                struct snapshot_param *param_ptr) {
···
    ret = cxt->ops.get_sensor_info(cxt->oem_handle, cxt->req_param.camera_id,
                                   &cxt->sensor_info);

    ret = snp_set_jpeg_dec_param(snp_handle);

    ret = snp_set_isp_proc_param(snp_handle);

    ret = snp_set_channel_out_param(snp_handle);
    ret = snp_set_hdr_param(snp_handle);

    snp_get_is_scaling(snp_handle, is_normal_cap);

    ret = snp_set_rot_param(snp_handle);

    ret = snp_set_jpeg_enc_param(snp_handle);

    ret = snp_set_jpeg_exif_param(snp_handle);
···
}

Analysis: Setting various parameters.

2. Call the camera_local_start_capture() function to continue the photography process

vendor/sprd/modules/libcamera/oem2v1/src/cmr_oem.c

cmr_int camera_local_start_capture(cmr_handle oem_handle) {
    //Do you need a flash when setting up a photo?
    camera_local_snapshot_is_need_flash(oem_handle, cxt->camera_id,
                                        &flash_status);    
    //Continue calling cmr_grab_start_capture to take photos
    ret = cmr_grab_start_capture(cxt->grab_cxt.grab_handle, capture_param);
}

Here we continue to call cmr_grab_start_capture to take photos.
vendor/sprd/modules/libcamera/oem2v1/src/cmr_grab.c

cmr_int cmr_grab_start_capture(cmr_handle grab_handle,
                               struct sprd_img_capture_param capture_param) {
    struct cmr_grab *p_grab;

    p_grab = (struct cmr_grab *)grab_handle;

    ret = ioctl(p_grab->fd, SPRD_IMG_IO_START_CAPTURE, &capture_param);
···
}

From here on, we call our driver layer and call the driver function through the ioctl interface. So which function is called through the cmd of SPRD_IMG_IO_START_CAPTURE?

[kernel layer]

kernel/drivers/misc/sprd_camera/dcam/dcam_if_r4p0/

static struct dcam_io_ctrl_fun s_cam_io_ctrl_fun_tab[] = {
···
{SPRD_IMG_IO_START_CAPTURE,     dcamio_start_capture},
···
}

So, you can see when the dcamio_start_capture function is called. Okay, let's go to the kernel layer and explore it!!!
kernel/drivers/misc/sprd_camera/dcam/dcam_if_r4p0/dcam_ioctrl.c

static int dcamio_start_capture(struct camera_file *camerafile,
             unsigned long arg, 
             unsigned int cmd) 
{
    int ret = 0; 
    unsigned int cap_flag = 0; 
    struct camera_dev *dev = NULL;
    struct camera_info *info = NULL;
    struct camera_group *group = NULL;
    //Access to equipment information
    ret = sprd_img_get_dcam_dev(camerafile, &dev, &info);
    if (ret) {
        pr_err("fail to get dcam dev\n");
        goto exit;
    }    

    group = camerafile->grp;
    //Obtain data from user space and copy it to cap_flag variable
    ret = copy_from_user(&cap_flag, (void __user *) arg,
                 sizeof(unsigned int));
    if (ret) {
        pr_err("fail to get user info\n");
        ret = -EFAULT;
        goto exit;
    }
    
    if (dev->cap_flag == DCAM_CAPTURE_STOP) {
        dev->cap_flag = DCAM_CAPTURE_START;
        if (dev->dcam_cxt.need_isp_tool)
            cap_flag = DCAM_CAPTURE_NONE;
        pr_info("start capture, cap_flag %d\n", cap_flag);
        //Call this function to take photos
        ret = sprd_isp_start_pipeline_full(dev->isp_dev_handle,
                           cap_flag);
        if (ret) {
            pr_err("fail to start offline\n");
            goto exit;
        }
    }
    //Photo completion
    pr_info("start capture done\n");

exit:
    return ret;
}

The annotations are added very clearly. Here's a brief comment.
Call the sprd_isp_start_pipeline_full action to execute the photograph, and the final data will be saved in p_offline_frame! [struct camera_frame*p_offline_frame = NULL, p_offline_frame is a pointer]

**p_offline_frame = &dev->offline_frame[ISP_OFF_BUF_FULL];**
**memcpy(p_offline_frame, &frame, sizeof(struct camera_frame));**
    **complete(&dev->offline_full_thread_com);**

Finally, the thread is waked up by complete to receive data.
PS: [complete is the concept of completion, used to protect shared data, prevent races, and tell another dormant thread that I'm finished, you wake up and go on with your work. You can refer to LDD book or Baidu by yourself.

Finally, let's briefly analyze how to collect data.

3. Data taken by calling cmr_snapshot_receive_data() function receive

vendor/sprd/modules/libcamera/oem2v1/src/cmr_snapshot.c

cmr_int cmr_snapshot_receive_data(cmr_handle snapshot_handle, cmr_int evt,
                                  void *data) {
···
    switch (evt) {//Norol Photo Mode
    case SNAPSHOT_EVT_CHANNEL_DONE:
        malloc_len = sizeof(struct frm_info);
        CMR_LOGD("video %d zsl %d yaddr_vir 0x%x",
                 cxt->req_param.is_video_snapshot,
                 cxt->req_param.is_zsl_snapshot, frame_info_ptr->yaddr_vir);
        buffer_id = snp_get_buffer_id(snapshot_handle, data);
        buffer_id += frame_info_ptr->base;

        snp_evt = SNP_EVT_CHANNEL_DONE;
        if (1 == cxt->req_param.is_video_snapshot ||
            1 == cxt->req_param.is_zsl_snapshot) {
            flag = 1;
            width = cxt->req_param.post_proc_setting.chn_out_frm[0].size.width;
            height =
                cxt->req_param.post_proc_setting.chn_out_frm[0].size.height;
            act_width = cxt->req_param.post_proc_setting.actual_snp_size.width;
            act_height =
                cxt->req_param.post_proc_setting.actual_snp_size.height;
            //memcpy refers to the memory copy function used by c and c + + to copy data from the kernel through address to the oem layer
            memcpy(&chn_data, data, sizeof(struct frm_info));
            chn_data.base = CMR_CAP0_ID_BASE;
            chn_data.frame_id = CMR_CAP0_ID_BASE;
            if (1 == cxt->req_param.is_zsl_snapshot) {
                chn_data.base = CMR_CAP1_ID_BASE;
                chn_data.frame_id = CMR_CAP1_ID_BASE;
            }
        }

        if (1 == cxt->req_param.is_video_snapshot) {//Video mode
        ···
            cmr_copy((void *)dst_vir, (void *)src_vir, width * height / 2);
            cmr_snapshot_memory_flush(
                cxt, &(cxt->req_param.post_proc_setting.chn_out_frm[0]));
        ···
        } else if (1 == cxt->req_param.is_zsl_snapshot) {//Zero Delay Photography Mode
        ···
            cmr_copy((void *)dst_vir, (void *)src_vir, width * height / 2);
            cmr_snapshot_memory_flush(
                cxt, &(cxt->req_param.post_proc_setting.chn_out_frm[0]));
        ···
        }
        break;
 ···
    }
···
}

After taking the photo, we will receive an msg message, type=SNAPSHOT_EVT_CHANNEL_DONE, indicating that the photo is completed!
Call memcpy (& chn_data, data, sizeof (struct frm_info)); get data from the kernel, remember that the data is stored in the kernel
In the struct camera_frame*p_offline_frame pointer, we copy the data by address!
That is memcpy (& chn_data, data, sizeof (struct frm_info);!

This is the end!!!

Tags: Mobile snapshot

Posted on Thu, 10 Oct 2019 15:15:30 -0700 by jesse24