[SPRD CAMERA] 4 HAL Camera open流程一

前言

    最近在搞8581的camera问题,作为一个新手从没有做过camera部分,希望通过这一系列的文章记录自己学习过程。
    大量参考大神的文章:【Camera专题】你应该熟悉的Camera驱动框架一(Hal层->kernel层)_justXiaoSha的博客-CSDN博客


一、hal层open流程

我们首先从 CameraDevice::open 开始

idh.code\vendor\sprd\interfaces\camera\device\3.2\default

Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback,
        ICameraDevice::open_cb _hidl_cb)  {
    Status status = initStatus();
    sp<CameraDeviceSession> session = nullptr;

    /** Open HAL device */
    status_t res;
    camera3_device_t *device;

    res = mModule->open(mCameraId.c_str(),
            reinterpret_cast<hw_device_t**>(&device));

    struct camera_info info;
    res = mModule->getCameraInfo(mCameraIdInt, &info);
    //mModule 的初始化在文章1中有介绍 bool LegacyCameraProviderImpl_2_4::initialize()中初始化

    session = createSession(
                device, info.static_camera_characteristics, callback);
    mSession = session;

}

这里主要是:

1)、mModule->open 就是 open camera 的 hal,要注意这参数 device 是把 camera3_device_t * 强转成 hw_device_t**。

2)、createSession 创建一个sp的对象,这里会调用 initialize 接口。

这一篇主要介绍 open 的流程

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

vendor/sprd/modules/libcamera/hal3_2v6/SprdCamera3Factory.cpp
struct hw_module_methods_t SprdCamera3Factory::mModuleMethods = { 
	.open = SprdCamera3Factory::camera_device_open,
};

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);
	}
	
}

这里open a camera device by its ID,通过ID来打开摄像头(后主摄:0 后副摄:2 前主摄:1 前副摄:3)

接着继续调用gSprdCamera3Factory.cameraDeviceOpen();

int SprdCamera3Factory::cameraDeviceOpen(int camera_id,
		                                     struct hw_device_t **hw_device) {
    SprdCamera3HWI *hw =
		new SprdCamera3HWI(multiCameraModeIdToPhyId(camera_id));
		    //这里new一个对象,在构造函数里面初始化这个common
		    //mCameraDevice.common.tag = HARDWARE_DEVICE_TAG;
            //mCameraDevice.common.version = CAMERA_DEVICE_API_VERSION_3_2;
            //mCameraDevice.common.close = close_camera_device;
            //mCameraDevice.ops = &mCameraOps;
            //mCameraDevice.priv = this;
            //这ops很重要

	rc = hw->openCamera(hw_device);

	return rc;
}

这里new了一个 SprdCamera3HWI 的实例,然后调用 openCamera(hw_device) 方法。

这里有个注意点就是 new SprdCamera3HWI时会初始化 mCameraDevice,通过参数返回 common成员的地址,这个 common 是 struct camera3_device_t 的第一个成员变量,

所以做一下类型转换就相当于传了一个 camera3_device_t 回去。还一个比较重要的是获取到了mCameraOps 操作函数集。

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

int SprdCamera3HWI::openCamera(struct hw_device_t **hw_device) {

	ret = openCamera();

	if (ret == 0) { 
		//mCameraDevice 的初始化是在 SprdCamera3HWI 的构造函数里面
		*hw_device = &mCameraDevice.common;
		mCameraSessionActive++;
	} else 
        *hw_device = NULL;

	return ret; 
}

接着继续调用空构造方法openCamera();

int SprdCamera3HWI::openCamera() {
	···
	//new SprdCamera3Setting的实例
	mSetting = new SprdCamera3Setting(mCameraId);

	//new SprdCamera3OEMIf的实例,这里会加载libcamoem.so库,同时mHalOem->ops = omi->ops = oem_module_ops;
	mOEMIf = new SprdCamera3OEMIf(mCameraId, mSetting);

	mOEMIf->camera_ioctrl(CAMERA_IOCTRL_SET_MULTI_CAMERAMODE, &mMultiCameraMode,
		                      NULL);
	//打开mOEMIf->openCamera()方法
	ret = mOEMIf->openCamera();

	mCameraOpened = true;
	···
	return NO_ERROR;
}

这里new SprdCamera3OEMIf的实例,继续调用mOEMIf->openCamera()方法。

vendor/sprd/modules/libcamera/hal3_2v6/SprdCamera3OEMIf.cpp
int SprdCamera3OEMIf::openCamera() {

	//获取宽和高
	mSetting->getLargestPictureSize(mCameraId, &picW, &picH);
	mSetting->getLargestSensorSize(mCameraId, &snsW, &snsH);
	if (picW * picH > snsW * snsH) {
	    mLargestPictureWidth = picW;
	    mLargestPictureHeight = picH;
	} else {
		mLargestPictureWidth = snsW;
		mLargestPictureHeight = snsH;
	}
	//设置最大尺寸
	mHalOem->ops->camera_set_largest_picture_size(
		 mCameraId, mLargestPictureWidth, mLargestPictureHeight);
		
	//进行初始化,初始化mCameraHandle,mCameraHandle相当于libcamoem.so或者cmr的一个句柄
	ret = mHalOem->ops->camera_init(mCameraId, camera_cb, this, 0,
                                    &mCameraHandle, (void *)Callback_Malloc,
                                    (void *)Callback_Free);
                                    
	//获取抓取能力,包含3dnr能力
	mHalOem->ops->camera_ioctrl(
         mCameraHandle, CAMERA_IOCTRL_GET_GRAB_CAPABILITY, &grab_capability);  
      
    /*从oem层获取传感器和镜头信息*/
	mHalOem->ops->camera_get_sensor_exif_info(mCameraHandle, &exif_info);
	mSetting->getLENSTag(&lensInfo);
	lensInfo.aperture = exif_info.aperture;
	mSetting->setLENSTag(lensInfo);
    
	//从oem层获取传感器otp
	mSetting->getOTPTag(&otpInfo);
    mHalOem->ops->camera_get_sensor_otp_info(mCameraHandle, dual_flag,
                                                 &otp_info);
        
	/**添加3d校准,获取最大传感器尺寸*/
	sprddefInfo = mSetting->getSPRDDEFTagPTR();
	mHalOem->ops->camera_get_sensor_info_for_raw(mCameraHandle, mode_info);

	//零延时模式线程初始化
	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;
	}
	
}

SprdCamera3OEMIf::openCamera主要做了以下事情:
mHalOem->ops = oem_module_ops,vendor/sprd/modules/libcamera/oem2v6/src/SprdOEMCamera.c
设置图像的最大尺寸
调用 camera_init 继续启动摄像头,mCameraHandle初始化
零延时模式线程初始化
根据 persist.sys.camera.raw.mode 设置属性

通过mHalOem->ops->camera_init最终会调用到SprdOEMCamera.c代码的camera_init进行初始化

vendor/sprd/modules/libcamera/oem2v6/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) {

	//调用camera_local_int继续进行初始化
	ret = camera_local_int(camera_id, callback, client_data, is_autotest,
		                   camera_handle, cb_of_malloc, cb_of_free); 

	//其他的一些初始化
	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/oem2v6/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) {
	···
	//内存申请
	struct camera_context *cxt = NULL;
	*oem_handle = (cmr_handle)0;
	cxt = (struct camera_context *)malloc(sizeof(struct camera_context));

	//参数赋值
	cmr_bzero(cxt, sizeof(*cxt));
	cxt->camera_id = camera_id;
	cxt->camera_cb = callback;       //后面上送数据的回调要使用
	cxt->client_data = client_data;  //client_data是SprdCamera3OEMIf的对象
	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;
		
	//调用camera_init_internal进行下一步初始化
	ret = camera_init_internal((cmr_handle)cxt, is_autotest);
		
	*oem_handle = (cmr_handle)cxt;
	···
	return ret;
}

这里重点关注一下 oem_handle 的初始化,就是赋值struct camera_context *cxt,还有回调函数camera_cb。
调用camera_init_internal进行下一步初始化

cmr_int camera_init_internal(cmr_handle oem_handle, cmr_uint is_autotest) {
	···
	//sensor初始化
	ret = camera_sensor_init(oem_handle, is_autotest);

	//grab初始化
	ret = camera_grab_init(oem_handle);

	//res初始化
	ret = camera_res_init(oem_handle);

	//isp初始化
	ret = camera_isp_init(oem_handle);

	//初始化完成
	ret = camera_res_init_done(oem_handle);

	//前置摄像头,lcd屏幕可以作为补光灯
	camera_front_lcd_enhance_module_init(oem_handle);
	···
	return ret;
}

该函数主要做了以下事情:

sensor初始化
grab初始化
res初始化
isp初始化
我们先关注camera_sensor_init这个函数,其他的以后在分析

cmr_int camera_sensor_init(cmr_handle oem_handle, cmr_uint is_autotest) {
	struct sensor_context *sn_cxt = NULL;
	sn_cxt = &cxt->sn_cxt;
	···
	init_param.oem_handle = oem_handle;
	//这里出现第二个context,sensor_context
	ret = cmr_sensor_init(&init_param, &sensor_handle);
	//这里可以看到senor_handle最终传到sn_cxt,通过camera_handle能找到sensor_handle
	sn_cxt->sensor_handle = sensor_handle;

    //这里继续open sensor
	ret = cmr_sensor_open(sensor_handle, camera_id_bits);
		
	cmr_sensor_event_reg(sensor_handle, cxt->camera_id, camera_sensor_evt_cb);
		    //struct cmr_sensor_handle *handle = (struct cmr_sensor_handle *)sensor_handle;
		    //handle->sensor_event_cb = event_cb;

    cxt->sn_cxt.sensor_handle = sensor_handle;

    sns_ex_info_ptr = &sn_cxt->cur_sns_ex_info;

    ret = cmr_sensor_init_static_info(cxt);
	···
}

该函数分别调用了 cmr_sensor_init 初始化和 cmr_sensor_open 打开Camera,下面分别介绍这几个函数。
这里出现一个常见的组合xxx_init和xxx_open,在init中设置一个工作函数,在open中传递信息,启动工作线程执行这个函数

1)cmr_sensor_init
vendor/sprd/modules/libcamera/oem2v6/src/cmr_sensor.c

cmr_int cmr_sensor_init(struct sensor_init_param *init_param_ptr,
		                    cmr_handle *sensor_handle) {
	struct cmr_sensor_handle *handle = NULL;
	···
	/*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);
		
	*sensor_handle = (cmr_handle)handle;
	···
	return ret;
}

该函数 对一些参数进行赋值,然后调用cmr_sns_create_thread方法创建 cmr_sns_thread_proc 线程。
如下:
ret = cmr_thread_create(&handle->thread_cxt.thread_handle,
SENSOR_MSG_QUEUE_SIZE,cmr_sns_thread_proc,
(void *)handle)
通过handle->thread_cxt.thread_handle调用 cmr_sns_thread_proc
struct camera_context -----> struct sensor_context -----> (cmr_handle)struct cmr_sensor_handle 

同时struct cmr_sensor_handle 也指向 struct camera_context

2)cmr_sensor_open

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);
	//这里发送msg消息,去启动在cmr_sensor_init创建的
	ret = cmr_thread_msg_send(handle->thread_cxt.thread_handle, &message);
	···
	return ret;
}

3)cmr_sensor_init_static_info

cmr_int cmr_sensor_init_static_info(cmr_handle oem_handle) {
    ...
    val.type = SENSOR_VAL_TYPE_GET_STATIC_INFO;
    val.pval = sns_ex_info_ptr;
    ret = cmr_sensor_ioctl(cxt->sn_cxt.sensor_handle, cxt->camera_id,
                                   SENSOR_ACCESS_VAL, (cmr_uint)&val);
    ...
}

   cmr_int cmr_sensor_ioctl(cmr_handle sensor_handle, cmr_u32 sensor_id,
                         cmr_uint cmd, cmr_uint arg) {
    ...
    ioctl_param.cmd = cmd;
    ioctl_param.arg = arg;

    /*the set mode function can be async control*/
    message.msg_type = CMR_SENSOR_EVT_IOCTL;
    message.sub_msg_type = sensor_id;
    message.sync_flag = CMR_MSG_SYNC_PROCESSED;
    message.data = (void *)malloc(sizeof(struct cmr_sns_ioctl_param));

    cmr_copy(message.data, &ioctl_param, sizeof(struct cmr_sns_ioctl_param));

    ret = cmr_thread_msg_send(handle->thread_cxt.thread_handle, &message);
    ...
}

在cmr_sensor_open中,发送了msg消息,去启动在cmr_sensor_init创建的线程cmr_sns_thread_proc。
这里的消息类型是message.msg_type = CMR_SENSOR_EVT_OPEN;

cmr_sensor_init_static_info中,发送了msg消息,去启动在cmr_sensor_init创建的线程cmr_sns_thread_proc。
这里的消息类型是message.msg_type = CMR_SENSOR_EVT_IOCTL;

cmr_int cmr_sns_thread_proc(struct cmr_msg *message, void *p_data) {//这个p_data就是creat这个proc时传递的p_data
	···
    switch (evt) {

	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);
		
    case CMR_SENSOR_EVT_IOCTL: {
        struct cmr_sns_ioctl_param *p_ioctl_param =
            (struct cmr_sns_ioctl_param *)message->data;
        camera_id = (cmr_u32)message->sub_msg_type;
        CMR_LOGV("camera_id=%d", camera_id);
        sensor_set_cxt_common(&handle->sensor_cxt[camera_id]);
        cmr_sns_ioctl(&handle->sensor_cxt[camera_id], p_ioctl_param->cmd, p_ioctl_param->arg);
                sns_ops = sensor_cxt->sensor_info_ptr->sns_ops;//这个sns_ops是镜头驱动的 static struct sensor_ic_ops s_se4770_ops_tab
                sns_ops->ext_ops[sns_cmd].ops(sensor_cxt->sns_ic_drv_handle, arg);
                        se4770_drv_access_val
        } break;
	}
    ···
}

我们继续看cmr_sns_open方法。

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);
		    }
		}
	}

}

这里出现一个 sensor_cxt 类型是 struct sensor_drv_context
cmr_sns_open方法又继续调用 sensor_open_common 函数,初始化handle->sensor_cxt[cameraId],这个函数比较复杂,主要工作如下:

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) {
	···
	ret = sensor_context_init(sensor_cxt, slot_id, is_autotest, 1);
    ret = sensor_drv_open(sensor_cxt, slot_id);
	···
	return ret;
}

初始化ctx(sensor_drv_context)这个结构体
加载sensor file文件,里面保存了camera的id
根据sensor file里保存的camera 的id打开摄像头

1)、sensor_context_init

cmr_int sensor_context_init(struct sensor_drv_context *sensor_cxt,
		                        cmr_u32 sensor_id, cmr_uint is_autotest,
		                        cmr_int open_phase) {
		
    //创建一个线程,通过sensor_cxt->ctrl_thread_cxt.thread_handle访问
	ret = sensor_create_ctrl_thread(sensor_cxt);
	    //ret = cmr_thread_create(&sensor_cxt->ctrl_thread_cxt.thread_handle,
        //                        SENSOR_CTRL_MSG_QUEUE_SIZE,
        //                        sensor_ctrl_thread_proc, (void *)sensor_cxt);
    
    input_ptr.sensor_id = sensor_id;
	input_ptr.caller_handle = sensor_cxt;
			
    //获取到驱动sprd_sensor的句柄hw_drv_handle,struct hw_drv_cxt
	fd_sensor = hw_sensor_drv_create(&input_ptr, &hw_drv_handle);
	                //hw_drv_cxt = *hw_drv_handle;
		            //hw_drv_cxt->fd_sensor = SENSOR_FD_INIT;
					//hw_drv_cxt->sensor_id = input_ptr->sensor_id;
					//hw_drv_cxt->caller_handle = input_ptr->caller_handle;
					//ret = _hw_sensor_dev_init(*hw_drv_handle, input_ptr->sensor_id);
					            //hw_drv_cxt->fd_sensor = open(HW_SENSOR_DEV_NAME, O_RDWR, 0);
					            //#define HW_SENSOR_DEV_NAME "/dev/sprd_sensor"
								
	sensor_cxt->fd_sensor = fd_sensor;
    sensor_cxt->hw_drv_handle = hw_drv_handle;
    sensor_cxt->sensor_hw_handler = hw_drv_handle;
    //这里是xml文件等配置信息	
	sensor_cxt->sensor_index = &devPtr->drv_idx[sensor_id];
	sensor_cxt->xml_info = &xml_cfg_tab[sensor_id];
	sensor_cxt->current_module = &sensor_cfg_tab[sensor_id];
	sns_module = (SENSOR_INFO_T *)sensor_cxt->current_module;
	sensor_cxt->sensor_info_ptr = sns_module->sensor_info;
}

这函数中有一个新的context,struct hw_drv_cxt sensor_cxt 这个是包含驱动节点sprd_sensor的句柄。这个函数在文章1中有介绍,在读取sensor id时,不过那时没有注册工作线程程序。还有这些静态变量就是在那个时候初始化的,现在就被用上了不用再来一遍。

static cmr_int sensor_drv_open(struct sensor_drv_context *sensor_cxt,
				                       cmr_u32 sensor_id) {
	//sns_ops = s_gc5035_ops_tab,
	sns_ops = sensor_cxt->sensor_info_ptr->sns_ops;

	sensor_cxt->sensor_isInit = SENSOR_TRUE;

    //验证id,函数栈文章1中分析过就不再分析了
	ret = sensor_drv_ic_identify(sensor_cxt, sensor_id, 0);

	//对焦马达初始化
	sensor_af_init(sensor_cxt);
	ret = sensor_set_mode_msg(sensor_cxt, SENSOR_MODE_COMMON_INIT, is_inited);

	//OTP的读取
	sensor_otp_module_init(sensor_cxt);
	module = sensor_cxt->current_module;
			
	sensor_otp_rw_ctrl(sensor_cxt, OTP_READ_PARSE_DATA, 0, NULL);
	sensor_set_otp_data(sensor_cxt);
	sensor_otp_ops_t *otp_ops = PNULL;
	otp_ops = &module->otp_drv_info.otp_drv_entry->otp_ops;
	otp_ops->sensor_otp_ioctl(sensor_cxt->otp_drv_handle,
				              CMD_SNS_OTP_GET_VENDOR_ID,
				              (void *)&vendor_id);
				
	sensor_set_raw_infor(sensor_cxt, vendor_id);

	sensor_set_export_Info(sensor_cxt);
	sensor_cxt->stream_on = 1;
	sensor_stream_off(sensor_cxt);
    //关流,防止上一次没有关流导致的影响
			   
	char value[PROPERTY_VALUE_MAX];
	property_get("ro.fac.cfg.CAMERA_NUMBER", value, "2");
	if(sensor_id < atoi(value))
		property_set( "sys.camera.running", "1" );

};

这个函数主要时操作和很多sensor、af、otp的相关驱动,这里暂时不分析了。

到这里整个open的流程就结束了。

补充知识:给线程传递数据的同步标志sync_flag的作用
enum {
CMR_MSG_SYNC_NONE = 0, 数据送出继续执行
CMR_MSG_SYNC_RECEIVED, 线程收到数据再继续
CMR_MSG_SYNC_PROCESSED, 线程执行完成在继续
};



总结

这一篇主要是沿着open 这条主线在分析代码,这里有很多context 很容易弄的头晕。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值