整个框架分为三个部分:hal部分逻辑调用,kernel层的通用驱动 sensorlist.c 和 具体IC的驱动 xxxx_mipi_raw.c。kernel 起来后不会直接去访问硬件sensor,而是会注册相关的驱动,之后Android系统起来后会启动相关的服务如 :camera_service,在camera服务中会直接去访问hal,kernel驱动,进而操作camera。
-Kernel部分主要有两块:一块是imagesensor驱动,负责具体型号的sensor的id检测,上电,以及在preview,capture,初始化,3A等等功能设定时的寄存器配置。另一块是ispdriver,通过DMA将sensor数据流上传。
-HAL层这边主要分3块:一块是imageio,主要是数据buffer上传的pipe。一块是drv,包含imgsensor和isp的hal层控制。最后是featureio,包含各种3A等性能配置。
流程图:
主要发生在两个时间点:开机过程中camera的动作以及打开应用时camera的动作。
-开机时:camera完成了sensor框架的初始化,id检测,以及上下电操作。
-打开应用时:camera会有上电,完成寄存器的初始配置,向上层传送基本参数及配置信息,以及preview和capture模式循环。
(下面的文件如不知道路径,请在代码中查找)
1,系统配置文件---ProjectConfig.mk
2,Sensor ID 和一些枚举类型的定义---kd_imgsensor.h,kd_imgsensor_define.h
定义sensor id和sensor name
此处填写正确的sensor ID
#define OV5648MIPI_SENSOR_ID 0x5648
此处填写的字符串包含 sensor的 part no 、格式(YUV or RAW)
#define SENSOR_DRVNAME_OV5648_MIPI_RAW "ov5648_mipi_raw"
3,kd_sensorlist.h,sensorlist.cpp
声明初始化函数
UINT32 OV5648MIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc);
kdSensorList[] :
#if defined(OV5648_MIPI_RAW) //与xxxxxSensor.c中的函数名对应,即驱动文件夹名大写
{OV5648MIPI_SENSOR_ID, SENSOR_DRVNAME_OV5648_MIPI_RAW, OV5648MIPI_RAW_SensorInit},
#endif
SensorList[] :
#if defined(OV5648_MIPI_RAW)
YUV_INFO(OV5648MIPI_SENSOR_ID,SENSOR_DRVNAME_OV5648_MIPI_RAW, NULL),
#endif
sensor 在kdSensorList[] 中的顺序必须和SensorList[]中的顺序保持一致 ,通常按照resolution从大到小的顺序依次排列下来。
4,hal层--camera_info_ov5648mipiraw.h
#define SENSOR_ID OV5648MIPI_SENSOR_ID
#define SENSOR_DRVNAME SENSOR_DRVNAME_OV5648_MIPI_RAW //为kd_imgsensor.h中定义的宏
5,AF定义---lenslist.cpp
MSDK_LENS_INIT_FUNCTION_STRUCT LensList_main[MAX_NUM_OF_SUPPORT_LENS] =
{
#if defined(AD5820AF)
{OV5648MIPI_SENSOR_ID, AD5820AF_LENS_ID, "AD5820AF", pAD5820AF_getDefaultData},
#endif
}
{ YOUR SENSOR ID(在kd_imgsensor.h里面定义的一致),LENS ID(不用改变),“lens名称”(不需要改),Lens Para(不需要改)}
(有点长,是按照代码的调用逻辑排版的,所以会有点乱,边看边阅读代码会比较好理解)
1,kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6580\kd_sensorlist.c
在驱动装载函数 CAMERA_HW_i2C_init 中注册了 platform driver
static struct platform_driver g_stCAMERA_HW_Driver = {
.probe = CAMERA_HW_probe, //入口
.remove = CAMERA_HW_remove, //删除
.suspend = CAMERA_HW_suspend, //挂起
.resume = CAMERA_HW_resume, //休眠
.driver = {
.name = "image_sensor", //驱动名称
.owner = THIS_MODULE,
#ifdef CONFIG_OF //与设备树的形式进行匹配
.of_match_table = CAMERA_HW_of_ids,
#endif
}
};
if (platform_driver_register(&g_stCAMERA_HW_Driver)) { // 注册platform总线的driver
PK_ERR("failed to register CAMERA_HW driver\n");
return -ENODEV;
}
与设备树里的 platform device 匹配成功后调用 CAMERA_HW_probe 方法注册 i2c driver
struct i2c_driver CAMERA_HW_i2c_driver = {
.probe = CAMERA_HW_i2c_probe,
.remove = CAMERA_HW_i2c_remove,
.driver = {
.name = CAMERA_HW_DRVNAME1,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = CAMERA_HW_i2c_of_ids,
#endif
},
.id_table = CAMERA_HW_i2c_id,
};
static int CAMERA_HW_probe(struct platform_device *pdev)
{
#if !defined(CONFIG_MTK_LEGACY)
mtkcam_gpio_init(pdev);
mtkcam_pin_mux_init(pdev);
#endif
return i2c_add_driver(&CAMERA_HW_i2c_driver); //注册 i2c driver
}
I2c匹配成功之后调用 CAMERA_HW_i2c_probe 方法
static int CAMERA_HW_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int i4RetValue = 0;
PK_DBG("[CAMERA_HW] Attach I2C\n");
/* get sensor i2c client */
spin_lock(&kdsensor_drv_lock);
g_pstI2Cclient = client; //这里是获得我们的clientdevice,并且以platform方式进行注册
/* set I2C clock rate */
g_pstI2Cclient->timing = 100; /* 100k */
g_pstI2Cclient->ext_flag &= ~I2C_POLLING_FLAG; /* No I2C polling busy waiting */
spin_unlock(&kdsensor_drv_lock);
/* Register char driver */
i4RetValue = RegisterCAMERA_HWCharDrv(); // 注册字符驱动
if (i4RetValue) {
PK_ERR("[CAMERA_HW] register char device failed!\n");
return i4RetValue;
}
/* spin_lock_init(&g_CamHWLock); */
#if !defined(CONFIG_MTK_LEGACY)
Get_Cam_Regulator();
#endif
PK_DBG("[CAMERA_HW] Attached!!\n");
return 0;
}
在 CAMERA_HW_i2c_probe 函数里面主要就是调用了 RegisterCAMERA_HWCharDrv 函数来注册一个字符驱动
static inline int RegisterCAMERA_HWCharDrv(void)
{
#if CAMERA_HW_DYNAMIC_ALLOCATE_DEVNO
if (alloc_chrdev_region(&g_CAMERA_HWdevno, 0, 1, CAMERA_HW_DRVNAME1)) {
PK_DBG("[CAMERA SENSOR] Allocate device no failed\n");
return -EAGAIN;
}
#else
if (register_chrdev_region(g_CAMERA_HWdevno, 1, CAMERA_HW_DRVNAME1)) {
PK_DBG("[CAMERA SENSOR] Register device no failed\n");
return -EAGAIN;
}
#endif
/* Allocate driver */
g_pCAMERA_HW_CharDrv = cdev_alloc(); // 申请一个cdev结构体
if (NULL == g_pCAMERA_HW_CharDrv) {
unregister_chrdev_region(g_CAMERA_HWdevno, 1);
PK_DBG("[CAMERA SENSOR] Allocate mem for kobject failed\n");
return -ENOMEM;
}
/* Attatch file operation. */ //关联到file_operation进入字符设备
cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops); //初始化字符设备
g_pCAMERA_HW_CharDrv->owner = THIS_MODULE;
/* Add to system */
if (cdev_add(g_pCAMERA_HW_CharDrv, g_CAMERA_HWdevno, 1)) { //注册到内核
PK_DBG("[mt6516_IDP] Attatch file operation failed\n");
unregister_chrdev_region(g_CAMERA_HWdevno, 1);
return -EAGAIN;
}
sensor_class = class_create(THIS_MODULE, "sensordrv"); //创建一个sensordrv类
if (IS_ERR(sensor_class)) {
int ret = PTR_ERR(sensor_class);
PK_DBG("Unable to create class, err = %d\n", ret);
return ret;
}
sensor_device =
device_create(sensor_class, NULL, g_CAMERA_HWdevno, NULL, CAMERA_HW_DRVNAME1);
return 0;
}
g_stCAMERA_HW_fops 如下:
static const struct file_operations g_stCAMERA_HW_fops = {
.owner = THIS_MODULE,
.open = CAMERA_HW_Open, //对g_CamDrvOpenCnt变量进行了一个原子读的过程
.release = CAMERA_HW_Release,
.unlocked_ioctl = CAMERA_HW_Ioctl, //上层跟驱动进行通讯
#ifdef CONFIG_COMPAT
.compat_ioctl = CAMERA_HW_Ioctl_Compat,
#endif
};
代码开始先判断是否定义了 CAMERA_HW_DYNAMIC_ALLOCATE_DEVNO 变量来判断动态还是静态分配一个字符设备,然后通过 cdev_alloc 申请了一个cdev结构体后,通过cdev_init将 g_stCAMERA_HW_fops 关联到字符设备,这是这个函数往下走下去的关键。然后就是将我们分配的字符设备,attach上 file_operation 添加到sys,最后在sys/class目录下创建一个sensordrv类。open函数没有做一些实际的行为,只是做了一个原子操作,用来计数打开cameradde的数量。
重点的操作行为在ioctl函数中,CAMERA_HW_Ioctl这个函数很重要,沟通上下层,提供接口,通过 switch case,将ioctl传下来的参数选择调用分支
static long CAMERA_HW_Ioctl(struct file *a_pstFile,
unsigned int a_u4Command, unsigned long a_u4Param)
{
int i4RetValue = 0;
void *pBuff = NULL;
u32 *pIdx = NULL;
mutex_lock(&kdCam_Mutex);
if (_IOC_NONE == _IOC_DIR(a_u4Command)) {
} else {
pBuff = kmalloc(_IOC_SIZE(a_u4Command), GFP_KERNEL); //申请分配一个buffer
if (NULL == pBuff) {
PK_DBG("[CAMERA SENSOR] ioctl allocate mem failed\n");
i4RetValue = -ENOMEM;
goto CAMERA_HW_Ioctl_EXIT;
}
/*
判断是否可写
将用户传递过来的命令参数复制到内核空间,接下来我们会根据这个数据进行选择
*/
if (_IOC_WRITE & _IOC_DIR(a_u4Command)) {
if (copy_from_user(pBuff, (void *)a_u4Param, _IOC_SIZE(a_u4Command))) {
kfree(pBuff);
PK_DBG("[CAMERA SENSOR] ioctl copy from user failed\n");
i4RetValue = -EFAULT;
goto CAMERA_HW_Ioctl_EXIT;
}
}
}
pIdx = (u32 *) pBuff; //使用pIdx指针,储存从用户空间拷贝过来的数据
switch (a_u4Command) {
#if 0
case KDIMGSENSORIOC_X_POWER_ON:
i4RetValue =
kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM) *pIdx, true,
CAMERA_HW_DRVNAME);
break;
case KDIMGSENSORIOC_X_POWER_OFF:
i4RetValue =
kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM) *pIdx, false,
CAMERA_HW_DRVNAME);
break;
#endif
//会调用kernel层的kdSetDriver接口,获取sensor初始化列表,获取各个camera驱动中的Init函数入口
case KDIMGSENSORIOC_X_SET_DRIVER:
i4RetValue = kdSetDriver((unsigned int *)pBuff);
break;
//打来camera硬件
case KDIMGSENSORIOC_T_OPEN:
i4RetValue = adopt_CAMERA_HW_Open();
break;
//获取对应的camera硬件节点信息
case KDIMGSENSORIOC_X_GETINFO:
i4RetValue = adopt_CAMERA_HW_GetInfo(pBuff);
break;
//获取摄像头分辨率
case KDIMGSENSORIOC_X_GETRESOLUTION2:
i4RetValue = adopt_CAMERA_HW_GetResolution(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_T_CLOSE:
i4RetValue = adopt_CAMERA_HW_Close();
break;
//会调用kernel层的adopt_CAMERA_HW_CheckIsAlive进行上电,获取sensor id,
case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:
i4RetValue = adopt_CAMERA_HW_CheckIsAlive();
break;
case KDIMGSENSORIOC_X_GET_SOCKET_POS:
i4RetValue = kdGetSocketPostion((unsigned int *)pBuff);
break;
case KDIMGSENSORIOC_X_SET_I2CBUS:
/* i4RetValue = kdSetI2CBusNum(*pIdx); */
break;
case KDIMGSENSORIOC_X_RELEASE_I2C_TRIGGER_LOCK:
/* i4RetValue = kdReleaseI2CTriggerLock(); */
break;
case KDIMGSENSORIOC_X_SET_SHUTTER_GAIN_WAIT_DONE:
/* i4RetValue = kdSensorSetExpGainWaitDone((int *)pBuff); */
break;
case KDIMGSENSORIOC_X_SET_CURRENT_SENSOR:
i4RetValue = kdSetCurrentSensorIdx(*pIdx);
break;
case KDIMGSENSORIOC_X_SET_MCLK_PLL:
i4RetValue = kdSetSensorMclk(pBuff);
break;
case KDIMGSENSORIOC_X_SET_GPIO:
i4RetValue = kdSetSensorGpio(pBuff);
break;
case KDIMGSENSORIOC_X_GET_ISP_CLK:
/* PK_DBG("get_isp_clk=%d\n",get_isp_clk()); */
/* *(unsigned int*)pBuff = get_isp_clk(); */
break;
default:
PK_DBG("No such command\n");
i4RetValue = -EPERM;
break;
}
//判断是否可读
if (_IOC_READ & _IOC_DIR(a_u4Command)) {
//将获得的数据传递给user空间
if (copy_to_user((void __user *)a_u4Param, pBuff, _IOC_SIZE(a_u4Command))) {
kfree(pBuff);
PK_DBG("[CAMERA SENSOR] ioctl copy to user failed\n");
i4RetValue = -EFAULT;
goto CAMERA_HW_Ioctl_EXIT;
}
}
kfree(pBuff);
CAMERA_HW_Ioctl_EXIT:
mutex_unlock(&kdCam_Mutex);
return i4RetValue;
}
KDIMGSENSORIOC_X_SET_DRIVER 和 KDIMGSENSORIOC_T_CHECK_IS_ALIVE 这两个在开机初始化监测id会被hal层调用
代码路径:\\vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6580\hal\senso\imgsensor_drv.cpp
MINT32//在开机过程中被调用,用于检测id,匹配main/sub image
ImgSensorDrv::impSearchSensor(pfExIdChk pExIdChkCbf)
{
........................................................
//! If imp sensor search process already done before,
//! only need to return the sensorDevs, not need to
//! search again.
if (SENSOR_DOES_NOT_EXIST != m_mainSensorId) {
....................................................
}
GetSensorInitFuncList(&m_pstSensorInitFunc);//获取sensorlist
LOG_MSG("SENSOR search start \n");
if (-1 != m_fdSensor) {
::close(m_fdSensor);
m_fdSensor = -1;
}
........................................................
// search main/main_2/sub 3 sockets
#ifdef MTK_MAIN2_IMGSENSOR
for (SensorEnum = DUAL_CAMERA_MAIN_SENSOR; SensorEnum <= DUAL_CAMERA_MAIN_2_SENSOR; SensorEnum <<= 1) {
LOG_MSG("impSearchSensor search to main_2\n");
#else
#ifdef MTK_SUB_IMGSENSOR
for (SensorEnum = DUAL_CAMERA_MAIN_SENSOR; SensorEnum <= DUAL_CAMERA_SUB_SENSOR; SensorEnum <<= 1) {
LOG_MSG("impSearchSensor search to sub\n");
#else
for (SensorEnum = DUAL_CAMERA_MAIN_SENSOR; SensorEnum < DUAL_CAMERA_SUB_SENSOR; SensorEnum <<= 1) {
LOG_MSG("impSearchSensor search to main\n");
#endif
#endif
//hal层开始探测sensor,因为有两颗sensor,外层循环两次
//内层循环根据上面的sensor列表来,最大支持兼容16颗sensor,hal层特效,
//如果没有整合特定imagesensor的hal层代码,这边会直接退出。
for (i = 0; i < MAX_NUM_OF_SUPPORT_SENSOR; i++) {
//end of driver list
if (m_pstSensorInitFunc[i].getCameraDefault == NULL) {//设定hal层camera所有特效参数
//通过之前的sensorlist来连接特定imagesensor的具体实现
LOG_MSG("m_pstSensorInitFunc[i].getCameraDefault is NULL: %d \n", i);
break;
}
//set sensor driver
id[KDIMGSENSOR_INVOKE_DRIVER_0] = (SensorEnum << KDIMGSENSOR_DUAL_SHIFT) | i;
LOG_MSG("set sensor driver id =%x\n", id[KDIMGSENSOR_INVOKE_DRIVER_0]);
//ioctl向驱动层下command,下传的id就是目前正在检测的imagesensor的id,然后回到kd_sensorlist.c
err = ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER,&id[KDIMGSENSOR_INVOKE_DRIVER_0] );
if (err < 0) {
LOG_ERR("ERROR:KDCAMERAHWIOC_X_SET_DRIVER\n");
}
//err = open();//对于正在遍历的这颗sensor,已经挂接上具体的底层驱动接口了
//那么下达check id的真正指令
err = ioctl(m_fdSensor, KDIMGSENSORIOC_T_CHECK_IS_ALIVE);
........................................................
}
GetSensooInitFuncList 这个函数主要为了获得下表:
\vendor\mediatek\proprietary\custom\tb8321p2_bsp\hal\imgsensor_src\sensorlist.cpp
包含了 id,name 和一些方法的调用
MSDK_SENSOR_INIT_FUNCTION_STRUCT SensorList[] =
{* 500w */
#if defined(AR0543_MIPI_RAW)
RAW_INFO(AR0543MIPI_SENSOR_ID,SENSOR_DRVNAME_AR0543_MIPI_RAW,NULL),
#endif
#if defined(SP5506_MIPI_RAW)
RAW_INFO(SP5506MIPI_SENSOR_ID, SENSOR_DRVNAME_SP5506_MIPI_RAW, NULL),
#endif
/* 800w */
#if defined(OV8858_MIPI_RAW)
RAW_INFO(OV8858MIPI_SENSOR_ID,SENSOR_DRVNAME_OV8858_MIPI_RAW,NULL),
#endif
#if defined(GC8024_MIPI_RAW)
RAW_INFO(GC8024MIPI_SENSOR_ID, SENSOR_DRVNAME_GC8024_MIPI_RAW, NULL),
#endif
/* 1300w */
#if defined(OV13850_MIPI_RAW)
RAW_INFO(OV13850_SENSOR_ID, SENSOR_DRVNAME_OV13850_MIPI_RAW, NULL),
#endif
};
typedef struct
{
MUINT32 SensorId;
MUINT8 drvname[32];
NSFeature::SensorInfoBase* pSensorInfo;
NSFeature::SensorInfoBase* (*pfGetSensorInfoInstance)();
MUINT32 (*getCameraDefault)(CAMERA_DATA_TYPE_ENUM CameraDataType, MVOID *pDataBuf, MUINT32 size);
MUINT32 (*getCameraCalData)(MUINT32* pGetCalData);
MUINT32 (*getCameraFlickerPara)(MINT32 sensorMode, MVOID *pDataBuf);
} MSDK_SENSOR_INIT_FUNCTION_STRUCT, *PMSDK_SENSOR_INIT_FUNCTION_STRUCT;
getCameraDefault 调用很重要,hal层camera的所有特效参数,包括3A,shading都在这边设定,通过之前的sensorlist来连接特定imagesensor的具体实现。
ioctl向下层传入 KDIMGSENSORIOC_X_SET_DRIVER,下层调用kdSetDriver,回到 kd_sensorlist.c
/*******************************************************************************
* kdSetDriver
********************************************************************************/
int kdSetDriver(unsigned int *pDrvIndex)
{
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT *pSensorList = NULL;
u32 drvIdx[KDIMGSENSOR_MAX_INVOKE_DRIVERS] = { 0, 0 };
u32 i;
/* set driver for MAIN or SUB sensor */
PK_INF("pDrvIndex:0x%08x/0x%08x\n", pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_0],
pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_1]);
/* Camera information */
gDrvIndex = pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_0];
if (0 != kdGetSensorInitFuncList(&pSensorList)) { //获得sensor初始化列表
PK_ERR("ERROR:kdGetSensorInitFuncList()\n");
return -EIO;
}
for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) {
/* */
spin_lock(&kdsensor_drv_lock);
g_bEnableDriver[i] = FALSE;
g_invokeSocketIdx[i] = //区分目前正在匹配的是main还是sub
(CAMERA_DUAL_CAMERA_SENSOR_ENUM) ((pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_MSB) >>
KDIMGSENSOR_DUAL_SHIFT);
spin_unlock(&kdsensor_drv_lock);
drvIdx[i] = (pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_LSB); //列表的序列号
/* */
if (DUAL_CAMERA_NONE_SENSOR == g_invokeSocketIdx[i]) {
continue;
}
#if 0
if (DUAL_CAMERA_MAIN_SENSOR == g_invokeSocketIdx[i]
|| DUAL_CAMERA_SUB_SENSOR == g_invokeSocketIdx[i]
|| DUAL_CAMERA_MAIN_2_SENSOR == g_invokeSocketIdx[i]) {
spin_lock(&kdsensor_drv_lock);
gI2CBusNum = SENSOR_I2C_BUS_NUM[g_invokeSocketIdx[i]];
spin_unlock(&kdsensor_drv_lock);
PK_XLOG_INFO("kd_MultiSensorOpen: switch I2C BUS%d\n", gI2CBusNum);
}
#else
if (DUAL_CAMERA_SUB_SENSOR == g_invokeSocketIdx[i]) {
spin_lock(&kdsensor_drv_lock);
gI2CBusNum = SUPPORT_I2C_BUS_NUM2;
spin_unlock(&kdsensor_drv_lock);
/* PK_XLOG_INFO("kdSetDriver: switch I2C BUS2\n"); */
} else {
spin_lock(&kdsensor_drv_lock);
gI2CBusNum = SUPPORT_I2C_BUS_NUM1;
spin_unlock(&kdsensor_drv_lock);
/* PK_XLOG_INFO("kdSetDriver: switch I2C BUS1\n"); */
}
#endif
PK_INF("g_invokeSocketIdx[%d]=%d,drvIdx[%d]=%d\n", i, g_invokeSocketIdx[i], i,
drvIdx[i]);
/* PK_INF("[kdSetDriver]drvIdx[%d] = %d\n", i, drvIdx[i]); */
/* */
if (MAX_NUM_OF_SUPPORT_SENSOR > drvIdx[i]) {
if (NULL == pSensorList[drvIdx[i]].SensorInit) {//判断模块驱动的init函数是否为NULL
PK_ERR("ERROR:kdSetDriver()\n");
return -EIO;
}
pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]); //获取各个cam驱动中Init函数入口
if (NULL == g_pInvokeSensorFunc[i]) {
PK_ERR("ERROR:NULL g_pSensorFunc[%d]\n", i);
return -EIO;
}
/* */
spin_lock(&kdsensor_drv_lock);
g_bEnableDriver[i] = TRUE;
spin_unlock(&kdsensor_drv_lock);
/* get sensor name */
memcpy((char *)g_invokeSensorNameStr[i],
(char *)pSensorList[drvIdx[i]].drvname,
sizeof(pSensorList[drvIdx[i]].drvname));
/* return sensor ID */
/* pDrvIndex[0] = (unsigned int)pSensorList[drvIdx].SensorId; */
PK_INF("[%d][%d][%d][%s][%d]\n", i, g_bEnableDriver[i],
g_invokeSocketIdx[i], g_invokeSensorNameStr[i],
sizeof(pSensorList[drvIdx[i]].drvname));
}
}
return 0;
}
typedef struct {
MUINT32 SensorId;
MUINT8 drvname[32];
MUINT32(*SensorInit)(PSENSOR_FUNCTION_STRUCT *pfFunc);
} ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT, *PACDK_KD_SENSOR_INIT_FUNCTION_STRUCT;
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] =
{
#if defined(OV5648_MIPI_RAW)
{OV5648MIPI_SENSOR_ID,SENSOR_DRVNAME_OV5648_MIPI_RAW,OV5648MIPI_RAW_SensorInit},
#endif
..............
}
kdSetDriver 这个函数比较重要,上层调用底层的命令应该第一步就是调用这个命令的,函数开头定义了一个ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT *pSensorList = NULL 这样的结构体,ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT 变量是为 kd_sensorlist.h 文件里面保存sensor的ID,NAME以及init的结构体,if (0 !=kdGetSensorInitFuncList(&pSensorList)) 通过调用 kdGetSensorInitFuncList 函数,将 pSensorList 的首地址指向 kd_sensorlist.h 里面 ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT 变量的首地址。
/*******************************************************************************
* general camera image sensor kernel driver
*******************************************************************************/
UINT32 SensorInitFuncList(ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT **ppSensorList)
{
if (NULL == ppSensorList) {
PK_ERR("[kdGetSensorInitFuncList]ERROR: NULL ppSensorList\n");
return 1;
}
*ppSensorList = &kdSensorList[0]; //获取sensorlist数组首地址
//kdSensorList 在 kd_sensorlist.h文件里面,就是保存cameraId,cameraName,模块入口函数结构体
return 0;
} /* kdGetSensorInitFuncList() */
调用了 kdGetSensorInitFuncList 后,代码先将 g_bEnableDriver 置为 FALSE,而这个变量在open函数里面出现过的。然后通过if (NULL ==pSensorList[drvIdx[i]].SensorInit) 判断模块驱动的init函数是否为NULL
if (NULL == pSensorList[drvIdx[i]].SensorInit) { //判断模块驱动的init函数是否为NULL
PK_ERR("ERROR:kdSetDriver()\n");
return -EIO;
}
pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]); //获取各个cam驱动中Init函数入口
if (NULL == g_pInvokeSensorFunc[i]) {
PK_ERR("ERROR:NULL g_pSensorFunc[%d]\n", i);
return -EIO;
}
pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]);
传递 &g_pInvokeSensorFunc[i] 为参数,其中还是传递的地址,这就将 g_pInvokeSensorFunc 的首地址指向了模块驱动函数中的 UINT32 OV5648MIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc) 这个函数
static SENSOR_FUNCTION_STRUCT sensor_func = {
open,
get_info,
get_resolution,
feature_control,
control,
close
};
UINT32 OV5648MIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc)
{
/* To Do : Check Sensor status here */
if (pfFunc!=NULL)
*pfFunc=&sensor_func;
return ERROR_NONE;
} /* OV5648MIPISensorInit */
这样就实现了驱动代码的分离,hal层只需调用Sensorlist.c这样一个虚拟设备的驱动,就可以和具体的Sensor Driver通信。
typedef struct {
MUINT32(*SensorOpen)(void);
MUINT32(*SensorGetInfo)(MSDK_SCENARIO_ID_ENUM ScenarioId, MSDK_SENSOR_INFO_STRUCT *pSensorInfo,
MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData);
MUINT32(*SensorGetResolution)(MSDK_SENSOR_RESOLUTION_INFO_STRUCT *pSensorResolution);
MUINT32(*SensorFeatureControl)(MSDK_SENSOR_FEATURE_ENUM FeatureId, MUINT8 *pFeaturePara, MUINT32 *pFeatureParaLen);
MUINT32(*SensorControl)(MSDK_SCENARIO_ID_ENUM ScenarioId, MSDK_SENSOR_EXPOSURE_WINDOW_STRUCT *pImageWindow, MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData);
MUINT32(*SensorClose)(void);
#if 1 /* isp suspend resume patch */
MSDK_SCENARIO_ID_ENUM ScenarioId;
MSDK_SENSOR_EXPOSURE_WINDOW_STRUCT imageWindow;
MSDK_SENSOR_CONFIG_STRUCT sensorConfigData;
SENSOR_STATE_ENUM sensorState;
#endif
MUINT8 arch;
void *psensor_inst; /* IMGSENSOR_SENSOR_INST */
} SENSOR_FUNCTION_STRUCT, *PSENSOR_FUNCTION_STRUCT;
这就就可以通过 g_pInvokeSensorFunc 直接调用模块驱动中的接口函数。
ioctl 里面的其他几条cmd命令基本都是在获取到了 g_pInvokeSensorFunc 后然后调用模块驱动中的各个接口函数
回到hal层
=> \\vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6580\hal\senso\imgsensor_drv.cpp
还是 impSearchSensor 这个函数
//err = open();//对于正在遍历的这颗sensor,已经挂接上具体的底层驱动接口了
//那么下达check id的真正指令
err = ioctl(m_fdSensor, KDIMGSENSORIOC_T_CHECK_IS_ALIVE);
if (err < 0) {
LOG_MSG("[impSearchSensor] Err-ctrlCode (%s) \n", strerror(errno));
}
底层调用 adopt_CAMERA_HW_CheckIsAlive
//会调用kernel层的adopt_CAMERA_HW_CheckIsAlive进行上电,获取sensor id,
case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:
i4RetValue = adopt_CAMERA_HW_CheckIsAlive();
break;
第一步是上电 power on,第二步是读sensor id
if (g_pSensorFunc) {
for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) {
if (DUAL_CAMERA_NONE_SENSOR != g_invokeSocketIdx[i]) {
err =
g_pSensorFunc->SensorFeatureControl(g_invokeSocketIdx[i],//读取SensorID
SENSOR_FEATURE_CHECK_SENSOR_ID,
(MUINT8 *) &sensorID,
&retLen);
if (sensorID == 0) { /* not implement this feature ID */
PK_DBG
(" Not implement!!, use old open function to check\n");
err = ERROR_SENSOR_CONNECT_FAIL;
} else if (sensorID == 0xFFFFFFFF) { /* fail to open the sensor */
PK_DBG(" No Sensor Found");
err = ERROR_SENSOR_CONNECT_FAIL;
..........................
}
调用之前挂接的具体sensor的 Feature control,并带参
case SENSOR_FEATURE_SET_VIDEO_MODE:
set_video_mode(*feature_data);
break;
case SENSOR_FEATURE_CHECK_SENSOR_ID: //优化传入的cmd为SENSOR_FEATURE_CHECK_SENSOR_ID,
//则会调用feature_control中的get_imgsensor_id
get_imgsensor_id(feature_return_para_32);
break;
case SENSOR_FEATURE_SET_AUTO_FLICKER_MODE:
set_auto_flicker_mode((BOOL)*feature_data_16,*(feature_data_16+1));
break;
读id一般在 开机 和 打开sensor 时执行,读之前软件 reset sensor,保证所读取的id的正确性,读到id后和预先设定的id作比较,如果一致,那么就找到了要找的sensor,因为有前后摄像头,所以这个动作要执行两次以上
static kal_uint32 get_imgsensor_id(UINT32 *sensor_id)
{
kal_uint8 i = 0;
kal_uint8 retry = 2;
//sensor have two i2c address 0x6c 0x6d & 0x21 0x20, we should detect the module used i2c address
while (imgsensor_info.i2c_addr_table[i] != 0xff) {
spin_lock(&imgsensor_drv_lock);
imgsensor.i2c_write_id = imgsensor_info.i2c_addr_table[i];
spin_unlock(&imgsensor_drv_lock);
do {
*sensor_id = return_sensor_id(); //return_sensor_id读取IC的ID
if (*sensor_id == imgsensor_info.sensor_id) {
LOG_INF("i2c write id: 0x%x, sensor id: 0x%x\n", imgsensor.i2c_write_id,*sensor_id);
return ERROR_NONE;
}
LOG_INF("Read sensor id fail, write id:0x%x id: 0x%x\n", imgsensor.i2c_write_id,*sensor_id);
retry--;
} while(retry > 0);
i++;
retry = 2;
}
if (*sensor_id != imgsensor_info.sensor_id) {
// if Sensor ID is not correct, Must set *sensor_id to 0xFFFFFFFF
*sensor_id = 0xFFFFFFFF;
return ERROR_SENSOR_CONNECT_FAIL;
}
return ERROR_NONE;
}
这边读id是通过i2c通信
/*******************************************************************************
* iReadRegI2C
这一步完成I2c的读取,也就是说如果I2c配置正确,并且上电正确,
到这一步就可以正确的读取ID,整个camera也就基本调通了
********************************************************************************/
int iReadRegI2C(u8 *a_pSendData, u16 a_sizeSendData, u8 *a_pRecvData, u16 a_sizeRecvData,
u16 i2cId)
{
int i4RetValue = 0;
if (gI2CBusNum == SUPPORT_I2C_BUS_NUM1) {
spin_lock(&kdsensor_drv_lock);
g_pstI2Cclient->addr = (i2cId >> 1);
g_pstI2Cclient->ext_flag = (g_pstI2Cclient->ext_flag) & (~I2C_DMA_FLAG);
/* Remove i2c ack error log during search sensor */
/* PK_ERR("g_pstI2Cclient->ext_flag: %d", g_IsSearchSensor); */
if (g_IsSearchSensor == 1) {
g_pstI2Cclient->ext_flag = (g_pstI2Cclient->ext_flag) | I2C_A_FILTER_MSG;
} else {
g_pstI2Cclient->ext_flag = (g_pstI2Cclient->ext_flag) & (~I2C_A_FILTER_MSG);
}
spin_unlock(&kdsensor_drv_lock);
/* */
i4RetValue = i2c_master_send(g_pstI2Cclient, a_pSendData, a_sizeSendData);
if (i4RetValue != a_sizeSendData) {
PK_ERR("[CAMERA SENSOR] I2C send failed!!, Addr = 0x%x\n", a_pSendData[0]);
return -1;
}
i4RetValue = i2c_master_recv(g_pstI2Cclient, (char *)a_pRecvData, a_sizeRecvData);
if (i4RetValue != a_sizeRecvData) {
.....................
return 0;
}
读完id并没有结束,因为还处于开机初始化阶段,并不是打开camera应用,check完id,还要给sensor下电,匹配上id后,又回到hal层,id不对的 return err<0
回到hal层
=>\\vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6580\hal\senso\imgsensor_drv.cpp
还是impSearchSensor这个函数
sensorType = this->getCurrentSensorType((SENSOR_DEV_ENUM)SensorEnum);
//
socketPos = this->getSocketPosition((CAMERA_DUAL_CAMERA_SENSOR_ENUM)SensorEnum);
//check extra ID , from EEPROM maybe
//may need to keep power here
if (NULL != pExIdChkCbf) {
err2 = pExIdChkCbf();
if (err2 < 0) {
LOG_ERR("Error:pExIdChkCbf() \n");
}
}
匹配上的sensor则继续下传cmd,获取一些sensordde的信息和配置,流程和之前的id检测类似。
hal层运行 Search sensor 这个线程
hal层遍历 sensorlist 并挂接hal层性能如:3A等一些参数获取接口
hal层下达 setDriver 的cmd,并下传正在遍历的sensor在 sensorlist 列表中的id
Driver层根据这个id,挂接Driver层 sensorlist 中对应的Sensor和具体Sensor底层操作接口
Driver层为对应sensor上电,通过i2c读取预存在寄存器中的 sensor id
比较读取结果,不匹配,return error,继续遍历。
匹配,HAL层下达其他指令收集sensor信息
下电
参考博文 : https://blog.csdn.net/xiaopangzi313/article/details/52205561