目录
一.主要文件
二.camera框架中的结构
三.camera驱动初始化流程
一.主要文件
1.文件路径
kernel-4.19/drivers/misc/mediatek/imgsensor/src/common/v1/
2.文件内容介绍
二.camera框架中的结构
整个框架的关键结构体是IMGSENSOR,可以看到它包含了IMGSENSOR_HW(上电相关)结构体和IMGSENSOR_SENSOR sensor[ ]结构体数组等一些成员,当前项目使用到的cmos sensor(图像传感器,后面都称呼为sensor)的各种信息就会随着这个驱动框架的启动在这个数组中完成初始化以及调用,如果项目中有一个前摄像头一个后摄像头,这个结构体数组中就会有两个元素将它们分别保存起来。具体结构如下:
struct IMGSENSOR {struct IMGSENSOR_STATUS status;struct IMGSENSOR_HW hw;//上电用到struct IMGSENSOR_CLK clk;struct IMGSENSOR_SENSOR sensor[IMGSENSOR_SENSOR_IDX_MAX_NUM];//操作sensor用到/* 省略部分成员 */
};
三.camera驱动初始化流程
入口函数注册一个platform驱动:
static int __init imgsensor_init(void) {if (platform_driver_register(&gimgsensor_platform_driver)) {PK_DBG("failed to register CAMERA_HW driver\n");return -ENODEV;}/* ...省略部分代码... */return 0;
}
platform驱动结构体如下:
#ifdef CONFIG_OF
static const struct of_device_id gimgsensor_of_device_id[] = {{.compatible = "mediatek,imgsensor",}, //与设备树进行匹配{}
};
#endifstatic struct platform_driver gimgsensor_platform_driver = {.probe = imgsensor_probe, //匹配成功调用probe函数.remove = imgsensor_remove,.suspend = imgsensor_suspend,.resume = imgsensor_resume,.driver = {.name = "image_sensor",.owner = THIS_MODULE,
#ifdef CONFIG_OF.of_match_table = gimgsensor_of_device_id,
#endif}
};
与设备树匹配成功之后会调用probe()函数:
static int imgsensor_probe(struct platform_device *pdev) {/* 注册字符设备 */if (imgsensor_driver_register()) {PK_DBG("[CAMERA_HW] register char device failed!\n");return -1;}/* ...省略部分代码... *//* 上电初始化 */imgsensor_hw_init(&pgimgsensor->hw);/* 注册i2c driver */imgsensor_i2c_create();/* proc文件系统初始化 */imgsensor_proc_init();/* ...省略部分代码... */return 0;
}
probe()函数主要做了创建字符设备、上电信息初始化、添加i2c设备等工作。其中的注册字符设备时添加了文件操作集:
static const struct file_operations gimgsensor_file_operations = {.owner = THIS_MODULE,.open = imgsensor_open,.release = imgsensor_release,.unlocked_ioctl = imgsensor_ioctl,
#ifdef CONFIG_COMPAT.compat_ioctl = imgsensor_compat_ioctl
#endif
};
这里可以看到camera设备驱动使用ioctl来控制,imgsensor_ioctl()函数实现如下:
static long imgsensor_ioctl(struct file *a_pstFile,unsigned int a_u4Command,unsigned long a_u4Param) {int i4RetValue = 0;void *pBuff = NULL;if (_IOC_DIR(a_u4Command) != _IOC_NONE) {pBuff = kmalloc(_IOC_SIZE(a_u4Command), GFP_KERNEL);/* ...省略部分代码... */if (_IOC_WRITE & _IOC_DIR(a_u4Command)) {if (copy_from_user(pBuff, (void *) a_u4Param, _IOC_SIZE(a_u4Command)))/* ...省略部分代码... */} elsememset(pBuff, 0, _IOC_SIZE(a_u4Command));} /* ...省略部分代码... */switch (a_u4Command) {case KDIMGSENSORIOC_X_GET_CONFIG_INFO:i4RetValue = adopt_CAMERA_HW_GetInfo(pBuff);break;case KDIMGSENSORIOC_X_GETINFO2:i4RetValue = adopt_CAMERA_HW_GetInfo2(pBuff);break;case KDIMGSENSORIOC_X_FEATURECONCTROL:i4RetValue = adopt_CAMERA_HW_FeatureControl(pBuff);break;case KDIMGSENSORIOC_X_CONTROL:i4RetValue = adopt_CAMERA_HW_Control(pBuff);break;case KDIMGSENSORIOC_X_SET_MCLK_PLL:i4RetValue = imgsensor_clk_set(&pgimgsensor->clk,(struct ACDK_SENSOR_MCLK_STRUCT *) pBuff);break;/* ...省略部分代码... */}/* ...省略部分代码... */return i4RetValue;
}
这里除了获取一些信息之外,有一个adopt_CAMERA_HW_FeatureControl()函数实现通过ioctl来控制硬件:
static inline int adopt_CAMERA_HW_FeatureControl(void *pBuf) {struct ACDK_SENSOR_FEATURECONTROL_STRUCT *pFeatureCtrl;struct IMGSENSOR_SENSOR *psensor;unsigned int FeatureParaLen = 0;void *pFeaturePara = NULL;struct ACDK_KD_SENSOR_SYNC_STRUCT *pSensorSyncInfo = NULL;signed int ret = 0;pFeatureCtrl = (struct ACDK_SENSOR_FEATURECONTROL_STRUCT *) pBuf;/* InvokeCamera与sensor枚举对应,例如0代表前摄,1代表后摄 */psensor = imgsensor_sensor_get_inst(pFeatureCtrl->InvokeCamera);if (copy_from_user((void *) &FeatureParaLen,(void *) pFeatureCtrl->pFeatureParaLen,sizeof(unsigned int))) {PK_DBG(" ioctl copy from user failed\n");return -EFAULT;}/* ...省略部分代码... */pFeaturePara = kmalloc(FeatureParaLen, GFP_KERNEL);memset(pFeaturePara, 0x0, FeatureParaLen);/* copy from user */switch (pFeatureCtrl->FeatureId) {case SENSOR_FEATURE_OPEN:ret = imgsensor_sensor_open(psensor);break;case SENSOR_FEATURE_CLOSE:ret = imgsensor_sensor_close(psensor);/* reset the delay frame flag */break;case SENSOR_FEATURE_SET_DRIVER: {MINT32 drv_idx;psensor->inst.sensor_idx = pFeatureCtrl->InvokeCamera;drv_idx = imgsensor_set_driver(psensor);memcpy(pFeaturePara, &drv_idx, FeatureParaLen);break;}case SENSOR_FEATURE_CHECK_IS_ALIVE:imgsensor_check_is_alive(psensor);break;/* ...省略部分代码... */imgsensor_sensor_feature_control(psensor,SENSOR_FEATURE_SET_ESHUTTER,(unsigned char *) &pSensorSyncInfo->u2SensorNewExpTime,(unsigned int *) &FeatureParaLen);imgsensor_sensor_feature_control(psensor,SENSOR_FEATURE_SET_GAIN,(unsigned char *) &pSensorSyncInfo->u2SensorNewGain,(unsigned int *) &FeatureParaLen);break;return ret;}
}
imgsensor_sensor_get_inst()这个函数传入的是ioctl的参数,这个参数直接作为数组索引,拿到了文章开头的struct IMGSENSOR_SENSOR sensor[ ]数组中的一个元素地址,准备开始初始化这个ioctl参数所代表的sensor:
struct IMGSENSOR_SENSOR *imgsensor_sensor_get_inst(enum IMGSENSOR_SENSOR_IDX idx) {if (idx < IMGSENSOR_SENSOR_IDX_MIN_NUM ||idx >= IMGSENSOR_SENSOR_IDX_MAX_NUM)return NULL;elsereturn &pgimgsensor->sensor[idx];
}
之后会调用imgsensor_set_driver()函数用来设定某一个具体的sensor:
int imgsensor_set_driver(struct IMGSENSOR_SENSOR *psensor) {u32 drv_idx = 0;int ret = -EIO;struct IMGSENSOR_SENSOR_INST *psensor_inst = &psensor->inst;/* kdSensorList[]数组包含具体sensor的驱动信息 */struct IMGSENSOR_INIT_FUNC_LIST *pSensorList = kdSensorList;
#define TOSTRING(value) #value
#define STRINGIZE(stringizedName) TOSTRING(stringizedName)
/** 在配置文件xxx_defconfig中申明可使用的sensor名字,* 例如当前项目的配置:* CONFIG_CUSTOM_KERNEL_IMGSENSOR="ovxxxx_qtech_main_mipi_raw gcxxxx_kingc_front_mipi_raw* s5k4xxxx_kingc_main_mipi_raw ovxxxx_ofilm_front_mipi_raw"* 这就表示当前项目支持ovxxxx、gcxxxx、三星xxx等这四个摄像头*/char *psensor_list_config = NULL, *psensor_list = NULL;char *sensor_configs = STRINGIZE(CONFIG_CUSTOM_KERNEL_IMGSENSOR);static int orderedSearchList[MAX_NUM_OF_SUPPORT_SENSOR] = {-1};static bool get_search_list = true;int i = 0;int j = 0;char *driver_name = NULL;imgsensor_mutex_init(psensor_inst);/* 绑定i2c */imgsensor_i2c_init(&psensor_inst->i2c_cfg,imgsensor_custom_config[(unsigned int) psensor_inst->sensor_idx].i2c_dev);imgsensor_i2c_filter_msg(&psensor_inst->i2c_cfg, true);/* 配置文件和kdSensorList[]数组中的信息匹配 */if (get_search_list) {psensor_list = psensor_list_config =kmalloc(strlen(sensor_configs) - 1, GFP_KERNEL);if (psensor_list_config) {for (j = 0; j < MAX_NUM_OF_SUPPORT_SENSOR; j++)orderedSearchList[j] = -1;memcpy(psensor_list_config,sensor_configs + 1,strlen(sensor_configs) - 2);*(psensor_list_config + strlen(sensor_configs) - 2) = '\0';PK_DBG("sensor_list %s\n", psensor_list_config);driver_name = strsep(&psensor_list_config, " \0");while (driver_name != NULL) {for (j = 0;j < MAX_NUM_OF_SUPPORT_SENSOR;j++) {if (pSensorList[j].init == NULL)break;else if (!strcmp(driver_name,pSensorList[j].name)) {orderedSearchList[i++] = j;break;}}driver_name =strsep(&psensor_list_config, " \0");}get_search_list = false;}kfree(psensor_list);}for (i = 0; i < MAX_NUM_OF_SUPPORT_SENSOR; i++) {/*PK_DBG("orderedSearchList[%d]=%d\n",*i, orderedSearchList[i]);*/if (orderedSearchList[i] == -1)continue;drv_idx = orderedSearchList[i];if (pSensorList[drv_idx].init) {/* 匹配完成之后调用具体的某个sensor的初始化函数 */pSensorList[drv_idx].init(&psensor->pfunc);if (psensor->pfunc) {/* get sensor name */psensor_inst->psensor_name =(char *) pSensorList[drv_idx].name;
#ifdef IMGSENSOR_LEGACY_COMPATpsensor_inst->status.arch =psensor->pfunc->arch;
#endif/* 上下电 */if (!imgsensor_check_is_alive(psensor)) {PK_DBG("[%s]:[%d][%d][%s]\n",__func__,psensor->inst.sensor_idx,drv_idx,psensor_inst->psensor_name);ret = drv_idx;break;}} else {PK_DBG("ERROR:NULL g_pInvokeSensorFunc[%d][%d]\n",psensor->inst.sensor_idx,drv_idx);}} else {PK_DBG("ERROR:NULL sensor list[%d]\n", drv_idx);}}imgsensor_i2c_filter_msg(&psensor_inst->i2c_cfg, false);return ret;
}
具体分析这段代码,发现它主要做了这样一些工作:
- 根据ioctl参数初始化i2c设备
- 检查当前项目支持哪些sensor
- 初始化ioctl参数代表的这个sensor,绑定sensor的操作函数
- 执行一次上下电操作来试验一下这个sensor。
其中,检查当前支持的sensor过程如下:
①申明一个数组orderedSearchList[MAX_NUM_OF_SUPPORT_SENSOR],从命名来看是“有序地搜索”,长度是最大支持的sensor,用来保存当前项目支持的sensor信息。
②把配置文件中保存的sensor名字取出来保存到psensor_list_config。
③用strsep()函数来分解psensor_list_config,结果用driver_name保存。
④把driver_name和pSensorList[]中保存的sensor的name相比对,如果名字对应,就把该sensor在pSensorList[]中的索引值保存到orderedSearchList[]数组。
匹配过程如下图所示:
为sensor绑定操作函数,通过调用sensor_func就可以实现对sensor的操作:
static struct SENSOR_FUNCTION_STRUCT sensor_func = {open,//初始化和注册get_info,get_resolution,feature_control,//对sensor工作模式等进行设置control,close
};/* init */
UINT32 OV8856_QTECH_MAIN_MIPI_RAW_SensorInit(struct SENSOR_FUNCTION_STRUCT **pfFunc) {if (pfFunc != NULL)*pfFunc = &sensor_func;return ERROR_NONE;
}
使用imgsensor_check_is_alive()函数来试验sensor,也就是执行上下电操作:
static inline int imgsensor_check_is_alive(struct IMGSENSOR_SENSOR *psensor) {struct IMGSENSOR_SENSOR_INST *psensor_inst = &psensor->inst;UINT32 err = 0;MUINT32 sensorID = 0;MUINT32 retLen = sizeof(MUINT32);IMGSENSOR_PROFILE_INIT(&psensor_inst->profile_time);/* 上电 */err = imgsensor_hw_power(&pgimgsensor->hw,psensor,psensor_inst->psensor_name,IMGSENSOR_HW_POWER_STATUS_ON);/* 检查sensor id */if (err == IMGSENSOR_RETURN_SUCCESS)imgsensor_sensor_feature_control(psensor,SENSOR_FEATURE_CHECK_SENSOR_ID,(MUINT8 * ) & sensorID,&retLen);if (sensorID == 0 || sensorID == 0xFFFFFFFF) {PK_DBG("Fail to get sensor ID %x\n", sensorID);err = ERROR_SENSOR_CONNECT_FAIL;} else {PK_DBG(" Sensor found ID = 0x%x\n", sensorID);err = ERROR_NONE;}if (err != ERROR_NONE)PK_DBG("ERROR: No imgsensor alive\n");/* 下电 */imgsensor_hw_power(&pgimgsensor->hw,psensor,psensor_inst->psensor_name,IMGSENSOR_HW_POWER_STATUS_OFF);IMGSENSOR_PROFILE(&psensor_inst->profile_time, "CheckIsAlive");return err ? -EIO : err;
}
具体上电过程后续分析。(未完待续)
本人还在入门阶段,欢迎大家指出错误。
参考巨佬博客:karaskass的博客_CSDN博客-camera driver+hal+framework,《Android深度探索 卷1 HAL与驱动开发》笔记,audio driver+hal+framework领域博主