标签:
在平时工作中,camera模块是经常进行调试修改的模块,所以熟悉camera的工作流程以及工作原理将会大大的提供工作效率,但对于整个android系统camera是个十分复杂的模块,下面对camera的驱动加载进行分析。
b) :Standby/PowerDown信号,用于进入待机模式,降低功耗。
c) :Mclk,即MasterClock 信号,是由 BB 端提供。a) :Pclk,即 PixelClock 信号,由 MCLK 分频得到,作为外部时钟控制图像传输帧率;
b) :HSYNC,行同步信号,其上升沿表示新一列行图像数据的开始;
c) :VSYNC,帧同步信号,其下降沿表示新的一帧图片的开始;
d) :D0-D9 一共 10 根数据线(8/10 根等)。
上图的架构相信大家都有了一定的了解,android 将系统大致分为应用层、库文件和硬件抽象层、Linux 内核三层。在底层的内核空间,Camera 的 driver 将其驱动起来以后,将硬件驱动的接口交给硬件抽象层,android 上层的 Camera 应用程序在 android 实时系统中的虚拟机中,加载 android 留给 Camera 公用的一些库文件,调用硬件抽象层的接口来控制 Camera硬件来实现功能。当然,如果是 Raw 模式的 Camera,还需要在硬件抽象层调用一些参数来控制 Camera 的效果。
Kernel 部分主要有两块:一块是image sensor 驱动,负责具体型号的sensor 的id 检测,上电,以及在preview,capture,初始化,3A 等等功能设定时的寄存器配置。另一块是isp driver,通过DMA 将sensor数据流上传。
HAL层这边主要分3 块,一块是imageio,主要是数据buffer上传的pipe。一块是drv,包含imgsensor 和isp 的hal 层控制。最后是feature io,包含各种3A 等性能配置。#if 1 ///defined(CONFIG_VIDEO_CAPTURE_DRIVERS) retval = platform_device_register(&sensor_dev); if (retval != 0){ return retval; } #endif static struct platform_device sensor_dev = { .name = "image_sensor", .id = -1, };image_sensor的platform类型驱动的device的name为 "image_sensor",而在linux中,所有的总线的driver与device都是通过name来与进行匹配的,platform总线也不例外,所以可以通过grep命令来查找camera注册的总线中driver的注册路径为:mediatek/custom/common/kernel/imgsensor/src/kd_sensorlist.c,代码为:
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, } };下面就来看看image_sensorplatform的driver整个注册流程是怎样实现的。先来看看kd_sensorlist.c驱动文件的init人口函数:
/*======================================================================= * CAMERA_HW_i2C_init() *=======================================================================*/ static int __init CAMERA_HW_i2C_init(void) { struct proc_dir_entry *prEntry; //i2c_register_board_info(CAMERA_I2C_BUSNUM, &kd_camera_dev, 1); i2c_register_board_info(SUPPORT_I2C_BUS_NUM1, &i2c_devs1, 1); // 填充i2c的板极文件 //i2c_register_board_info(SUPPORT_I2C_BUS_NUM2, &i2c_devs2, 1); if(platform_driver_register(&g_stCAMERA_HW_Driver)){ // 注册platform总线的driver PK_ERR("failed to register CAMERA_HW driver\n"); return -ENODEV; } //if(platform_driver_register(&g_stCAMERA_HW_Driver2)){ // PK_ERR("failed to register CAMERA_HW driver\n"); // return -ENODEV; //} //Register proc file for main sensor register debug prEntry = create_proc_entry("driver/camsensor", 0, NULL); //在proc下创建driver/camsensor这个节点,用于前置摄像头进行adb效果调试 if (prEntry) { prEntry->read_proc = CAMERA_HW_DumpReg_To_Proc; prEntry->write_proc = CAMERA_HW_Reg_Debug; } else { PK_ERR("add /proc/driver/camsensor entry fail \n"); } //Register proc file for sub sensor register debug prEntry = create_proc_entry("driver/camsensor2", 0, NULL); //在proc下创建driver/camsensor2这个节点,用于后置摄像头进行adb效果调试 if (prEntry) { prEntry->read_proc = CAMERA_HW_DumpReg_To_Proc; prEntry->write_proc = CAMERA_HW_Reg_Debug2; } else { PK_ERR("add /proc/driver/camsensor2 entry fail \n"); } atomic_set(&g_CamHWOpend, 0); //atomic_set(&g_CamHWOpend2, 0); atomic_set(&g_CamDrvOpenCnt, 0); //atomic_set(&g_CamDrvOpenCnt2, 0); atomic_set(&g_CamHWOpening, 0); return 0; }CAMERA_HW_i2C_init函数主要做的是对I2C总线的版级文件进行了填充,然后注册platform总线的driver,通过g_stCAMERA_HW_Driver结构体里面的name来与device进行匹配。同时,在函数里面还在proc目录下创建了driver/camsensor和driver/camsensor2两个节点,这样做主要是方便sensor的IC原厂FAE利用adb进行效果调试的。
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, } };g_stCAMERA_HW_Driver结构体中主要有probe、remove、suspend等接口的实现,probe接口为设备注册的匹配函数,所以在在注册了driver就会调用 .probe = CAMERA_HW_probe进入CAMERA_HW_probe函数:
static int CAMERA_HW_probe(struct platform_device *pdev) { return i2c_add_driver(&CAMERA_HW_i2c_driver); } struct i2c_driver CAMERA_HW_i2c_driver = { .probe = CAMERA_HW_i2c_probe, .remove = CAMERA_HW_i2c_remove, .driver.name = CAMERA_HW_DRVNAME1, .id_table = CAMERA_HW_i2c_id, };CAMERA_HW_probe做的就是注册一个i2c的driver,camera会挂载在I2C总线上,利用I2C进入寄存器的读写,所以,sensor驱动最终还是会注册I2C设备,I2C总线的注册其实跟platform总线的注册大致相同,注册完I2C driver后系统就会调用CAMERA_HW_i2c_driver 结构体里面的 .probe = 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 = 300;//200k 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); PK_DBG("[CAMERA_HW] Attached!! \n"); return 0; }在CAMERA_HW_i2c_probe函数里面主要就是调用了RegisterCAMERA_HWCharDrv函数来注册一个字符驱动。
inline static int RegisterCAMERA_HWCharDrv(void) { struct device* sensor_device = NULL; #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. cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops); //关联到file_operation进入字符设备 g_pCAMERA_HW_CharDrv->owner = THIS_MODULE; //Add to system if(cdev_add(g_pCAMERA_HW_CharDrv, g_CAMERA_HWdevno, 1)) //将我们分配的字符设备,attach上file_operation添加到system { 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; }linux驱动分为三大部分驱动,分别为字符驱动,块驱动以及网络驱动,而camera的模块驱动为字符驱动,所以RegisterCAMERA_HWCharDrv函数主要是对camera_image进行字符驱动注册,代码开始先判断是否定义了CAMERA_HW_DYNAMIC_ALLOCATE_DEVNO变量来判断动态还是静态分配一个字符设备,然后通过cdev_alloc申请了一个cdev结构体后,通过cdev_init将g_stCAMERA_HW_fops关联到字符设备,这是这个函数往下走下去的关键。然后就是将我们分配的字符设备,attach上file_operation添加到sys,最后在sys/class目录下创建一个sensordrv类,如下图所示:
static const struct file_operations g_stCAMERA_HW_fops = { .owner = THIS_MODULE, .open = CAMERA_HW_Open, .release = CAMERA_HW_Release, .unlocked_ioctl = CAMERA_HW_Ioctl };file_operations 是为上层调用底层提供的接口,往往打开接口就是先打开open,那么先来看看struct file_operations g_stCAMERA_HW_fops结构体中的open函数;
static int CAMERA_HW_Open(struct inode * a_pstInode, struct file * a_pstFile) { //reset once in multi-open if ( atomic_read(&g_CamDrvOpenCnt) == 0) { //default OFF state //MUST have //kdCISModulePowerOn(DUAL_CAMERA_MAIN_SENSOR,"",true,CAMERA_HW_DRVNAME1); //kdCISModulePowerOn(DUAL_CAMERA_SUB_SENSOR,"",true,CAMERA_HW_DRVNAME1); //kdCISModulePowerOn(DUAL_CAMERA_MAIN_2_SENSOR,"",true,CAMERA_HW_DRVNAME1); //kdCISModulePowerOn(DUAL_CAMERA_MAIN_SENSOR,"",false,CAMERA_HW_DRVNAME1); //kdCISModulePowerOn(DUAL_CAMERA_SUB_SENSOR,"",false,CAMERA_HW_DRVNAME1); //kdCISModulePowerOn(DUAL_CAMERA_MAIN_2_SENSOR,"",false,CAMERA_HW_DRVNAME1); } // atomic_inc(&g_CamDrvOpenCnt); return 0; }整个函数就是对g_CamDrvOpenCnt变量进行了一个原子读的过程,没有进行别的操作。而上层跟驱动进行通讯主要是通过ioctl发送命令,然后进行数据传输,然后在看看.unlocked_ioctl= CAMERA_HW_Ioctl中的CAMERA_HW_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; 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 case KDIMGSENSORIOC_X_SET_DRIVER: i4RetValue = kdSetDriver((unsigned int*)pBuff); break; case KDIMGSENSORIOC_T_OPEN: i4RetValue = adopt_CAMERA_HW_Open(); break; case KDIMGSENSORIOC_X_GETINFO: i4RetValue = adopt_CAMERA_HW_GetInfo(pBuff); break; case KDIMGSENSORIOC_X_GETRESOLUTION: i4RetValue = adopt_CAMERA_HW_GetResolution(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; 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; default : PK_DBG("No such command \n"); i4RetValue = -EPERM; break; } if(_IOC_READ & _IOC_DIR(a_u4Command)) { 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; }ioctl主要就是上层通过cmd命令来与底层进行通信,下面就看看这个比较重要的cmd命令:
case KDIMGSENSORIOC_T_OPEN: i4RetValue = adopt_CAMERA_HW_Open(); break; inline static int adopt_CAMERA_HW_Open(void) { UINT32 err = 0; KD_IMGSENSOR_PROFILE_INIT(); if (atomic_read(&g_CamHWOpend) == 0 ) { if (g_pSensorFunc) { //判断我们imagesensor 操作函数指针是否为NULL,如果为NULL,报错,因为我们就是靠这个操作函数集合去操作imagesensor 的 err = g_pSensorFunc->SensorOpen(); // 会调用到kd_MultiSensorFunc里面的kd_MultiSensorOpen函数 if(ERROR_NONE != err) { PK_DBG(" ERROR:SensorOpen(), turn off power \n"); kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM*) g_invokeSocketIdx, g_invokeSensorNameStr, false, CAMERA_HW_DRVNAME1); } } else { PK_DBG(" ERROR:NULL g_pSensorFunc\n"); } KD_IMGSENSOR_PROFILE("SensorOpen"); } else { //PK_ERR("adopt_CAMERA_HW_Open Fail, g_CamHWOpend = %d,g_CamHWOpend2 = %d\n ",atomic_read(&g_CamHWOpend),atomic_read(&g_CamHWOpend2) ); PK_ERR("adopt_CAMERA_HW_Open Fail, g_CamHWOpend = %d\n ",atomic_read(&g_CamHWOpend) ); } if (err == 0 ) { atomic_set(&g_CamHWOpend, 1); //atomic_set(&g_CamHWOpend2, 1); } return err?-EIO:err; } /* adopt_CAMERA_HW_Open() */g_pSensorFunc结构体的定义为staticMULTI_SENSOR_FUNCTION_STRUCT *g_pSensorFunc = &kd_MultiSensorFunc,它跟kd_MultiSensorFunc指向相同的地址,if (g_pSensorFunc) 由这里可以看出,上层调用ioctl命令时不可能先走KDIMGSENSORIOC_T_OPEN这个命令,因为此时g_pSensorFunc 为NULL,还没有赋值,由后面的代码可以看到,ioctl先走的cmd命令是KDIMGSENSORIOC_X_SET_DRIVER。当g_pSensorFunc不为NULL时,就是执行这个err =g_pSensorFunc->SensorOpen(); ,这里的SensorOpen函数指向的是kd_MultiSensorOpen函数。
MUINT32 kd_MultiSensorOpen ( void ) { MUINT32 ret = ERROR_NONE; MINT32 i = 0; KD_MULTI_FUNCTION_ENTRY(); // 得到当前时间 for ( i = (KDIMGSENSOR_MAX_INVOKE_DRIVERS-1) ; i >= KDIMGSENSOR_INVOKE_DRIVER_0 ; i-- ) { if ( g_bEnableDriver[i] && g_pInvokeSensorFunc[i] ) { // turn on power ret = kdCISModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM)g_invokeSocketIdx[i],(char*)g_invokeSensorNameStr[i],true,CAMERA_HW_DRVNAME1); if ( ERROR_NONE != ret ) { // 上电 PK_ERR("[%s]",__FUNCTION__); return ret; } //wait for power stable mDELAY(10); KD_IMGSENSOR_PROFILE("kdModulePowerOn"); ret = g_pInvokeSensorFunc[i]->SensorOpen(); //调用到模块驱动中的open函数,g_pInvokeSensorFunc保存的值为模块驱动中的SENSOR_FUNCTION_STRUCT SensorFuncGC2035这个结构体 if ( ERROR_NONE != ret ) { kdCISModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM)g_invokeSocketIdx[i],(char*)g_invokeSensorNameStr[i],false,CAMERA_HW_DRVNAME1); // 掉电 PK_ERR("SensorOpen"); return ret; } } } KD_MULTI_FUNCTION_EXIT(); return ERROR_NONE; }g_bEnableDriver定义为一个bool型的变量,定义如下static BOOL g_bEnableDriver[KDIMGSENSOR_MAX_INVOKE_DRIVERS] ={FALSE,FALSE},而g_pInvokeSensorFunc的定义为static SENSOR_FUNCTION_STRUCT*g_pInvokeSensorFunc[KDIMGSENSOR_MAX_INVOKE_DRIVERS] = {NULL,NULL};而g_pInvokeSensorFunc的地址跟模块驱动中的SENSOR_FUNCTION_STRUCT SensorFuncGC2035这个地址指向是相同的,他是作为一个参数传递来被调用的,这两个变量的实现都会在后面KDIMGSENSORIOC_X_SET_DRIVER命令调用时介绍的。当这两个变量都为true时,就对sensor进行上电,然后就通过ret =g_pInvokeSensorFunc[i]->SensorOpen()进入到了模块sensor驱动中的open函数。至于上电跟掉电函数kdCISModulePowerOn,在mediatek/custom/ztenj72_we_72_m536_kk/kernel/camera/camera/kd_camera_hw.c文件中,其实上电跟掉电时序就是配置一些GPIO口,然后在把camera的三路电压按dateshell配置一下上掉电的时间。
case KDIMGSENSORIOC_X_SET_DRIVER: i4RetValue = kdSetDriver((unsigned int*)pBuff); break;
int kdSetDriver(unsigned int* pDrvIndex) { ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT *pSensorList = NULL; // 这是一个保存cameraId跟cameraName的结构体 u32 drvIdx[KDIMGSENSOR_MAX_INVOKE_DRIVERS] = {0,0}; u32 i; PK_XLOG_INFO("pDrvIndex:0x%08x/0x%08x \n",pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_0],pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_1]); //set driver for MAIN or SUB sensor 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] = (CAMERA_DUAL_CAMERA_SENSOR_ENUM)((pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_MSB)>>KDIMGSENSOR_DUAL_SHIFT); // 保存camera的sensorId spin_unlock(&kdsensor_drv_lock); drvIdx[i] = (pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_LSB); // if ( DUAL_CAMERA_NONE_SENSOR == g_invokeSocketIdx[i] ) { continue; } //ToDo: remove print information PK_XLOG_INFO("[kdSetDriver] i,g_invokeSocketIdx[%d] = %d :\n",i,i,drvIdx[i]); PK_XLOG_INFO("[kdSetDriver] i,drvIdx[%d] = %d :\n",i,i,drvIdx[i]); // if ( MAX_NUM_OF_SUPPORT_SENSOR > drvIdx[i] ) { if (NULL == pSensorList[drvIdx[i]].SensorInit) { PK_ERR("ERROR:kdSetDriver()\n"); return -EIO; } pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]);// 调用模块驱动中的init函数,将模块驱动里面的SENSOR_FUNCTION_STRUCT SensorFuncOV2685值传递给g_pInvokeSensorFunc结构体 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; g_CurrentInvokeCam = g_invokeSocketIdx[i]; 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_XLOG_INFO("[kdSetDriver] :[%d][%d][%d][%s][%d]\n",i,g_bEnableDriver[i],g_invokeSocketIdx[i],g_invokeSensorNameStr[i],sizeof(pSensorList[drvIdx[i]].drvname)); } } return 0; }kdSetDriver这个函数比较重要,上层调用底层的命令应该第一步就是调用这个命令的,函数开头定义了一个ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT *pSensorList = NULL;这样的结构体,ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT 变量是为src/kd_sensorlist.h文件里面保存sensor的ID,NAME以及init的结构体,if (0 !=kdGetSensorInitFuncList(&pSensorList))通过调用kdGetSensorInitFuncList函数,将pSensorList的首地址指向src/kd_sensorlist.h里面ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT变量的首地址。
UINT32 kdGetSensorInitFuncList(ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT **ppSensorList) { if (NULL == ppSensorList) { PK_DBG("[kdGetSensorInitFuncList]ERROR: NULL ppSensorList\n"); return 1; } *ppSensorList = &kdSensorList[0]; // kdSensorList在kd_sensorlist.h文件里面,就是保存cameraId,cameraNmae,模块驱动人口函数的结构体 return 0; }调用了kdGetSensorInitFuncList后,代码先将g_bEnableDriver置为FALSE,而这个变量就是在上面的open函数里面出现过的。然后通过if (NULL ==pSensorList[drvIdx[i]].SensorInit)判断模块驱动的init函数是否为NULL,pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]);传递&g_pInvokeSensorFunc[i]为参数,其中还是传递的地址,这就将g_pInvokeSensorFunc的首地址指向了模块驱动函数中的UINT32 GC2035_YUV_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc)这个函数,这就是上面kd_MultiSensorOpen 中为什么g_pInvokeSensorFunc可以直接调用模块驱动中的open函数,其实就是在这里实现的。当调用完成后,然后就将camera的ID,NAME等信息保存并将g_bEnableDriver[i]变量置为TRUE。
case KDIMGSENSORIOC_T_OPEN: i4RetValue = adopt_CAMERA_HW_Open(); break; inline static int adopt_CAMERA_HW_Open(void) { UINT32 err = 0; KD_IMGSENSOR_PROFILE_INIT(); //power on sensor //if ((atomic_read(&g_CamHWOpend) == 0) && (atomic_read(&g_CamHWOpend2) == 0)) { if (atomic_read(&g_CamHWOpend) == 0 ) { //move into SensorOpen() for 2on1 driver // turn on power //kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM*) g_invokeSocketIdx, g_invokeSensorNameStr,true, CAMERA_HW_DRVNAME); //wait for power stable //mDELAY(10); //KD_IMGSENSOR_PROFILE("kdModulePowerOn"); // if (g_pSensorFunc) { err = g_pSensorFunc->SensorOpen(); if(ERROR_NONE != err) { PK_DBG(" ERROR:SensorOpen(), turn off power \n"); kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM*) g_invokeSocketIdx, g_invokeSensorNameStr, false, CAMERA_HW_DRVNAME1); } } else { PK_DBG(" ERROR:NULL g_pSensorFunc\n"); } KD_IMGSENSOR_PROFILE("SensorOpen"); } else { //PK_ERR("adopt_CAMERA_HW_Open Fail, g_CamHWOpend = %d,g_CamHWOpend2 = %d\n ",atomic_read(&g_CamHWOpend),atomic_read(&g_CamHWOpend2) ); PK_ERR("adopt_CAMERA_HW_Open Fail, g_CamHWOpend = %d\n ",atomic_read(&g_CamHWOpend) ); } if (err == 0 ) { atomic_set(&g_CamHWOpend, 1); //atomic_set(&g_CamHWOpend2, 1); } return err?-EIO:err; } /* adopt_CAMERA_HW_Open() */KDIMGSENSORIOC_T_OPEN命令就是通过调用adopt_CAMERA_HW_Open函数,而adopt_CAMERA_HW_Open函数中会通过err =g_pSensorFunc->SensorOpen();调用到模块驱动中的open函数。而在这里就不一一介绍了,下面来看看你看驱动中的各个接口函数有什么含义,以gc2035驱动为模板分析。
UINT32 GC2035_YUV_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc) { /* To Do : Check Sensor status here */ if (pfFunc!=NULL) *pfFunc=&SensorFuncGC2035; return ERROR_NONE; } /* Sensor SENSOR_FUNCTION_STRUCT SensorFuncGC2035= { GC2035Open, GC2035GetInfo, GC2035GetResolution, GC2035FeatureControl, GC2035Control, GC2035Close }; GC2035Open: UINT32 GC2035Open(void) { volatile signed char i; kal_uint16 sensor_id=0; zoom_factor = 0; Sleep(10); SENSORDB("GC2035Open\r\n"); // Read sensor ID to adjust I2C is OK? for(i=0;i<3;i++) { sensor_id = (GC2035_read_cmos_sensor(0xf0) << 8) | GC2035_read_cmos_sensor(0xf1); if(sensor_id != GC2035_SENSOR_ID) // GC2035_SENSOR_ID = 0x2035 { return ERROR_SENSOR_CONNECT_FAIL; } } SENSORDB("GC2035 Sensor Read ID OK \r\n"); GC2035_Sensor_Init(); GC2035_Write_More(); Preview_Shutter =GC2035_read_shutter(); return ERROR_NONE; }通过函数实现就可以看出来,这里是在通过i2c控制imagesensor 的register,读取deivceid ,看是否链接上对应的imagesensor;
GC2035GetInfo: UINT32 GC2035GetInfo(MSDK_SCENARIO_ID_ENUM ScenarioId, MSDK_SENSOR_INFO_STRUCT *pSensorInfo, MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData) { pSensorInfo->SensorPreviewResolutionX=GC2035_IMAGE_SENSOR_PV_WIDTH; pSensorInfo->SensorPreviewResolutionY=GC2035_IMAGE_SENSOR_PV_HEIGHT; pSensorInfo->SensorFullResolutionX=GC2035_IMAGE_SENSOR_FULL_WIDTH; pSensorInfo->SensorFullResolutionY=GC2035_IMAGE_SENSOR_FULL_HEIGHT; pSensorInfo->SensorCameraPreviewFrameRate=30; pSensorInfo->SensorVideoFrameRate=30; pSensorInfo->SensorStillCaptureFrameRate=10; pSensorInfo->SensorWebCamCaptureFrameRate=15; pSensorInfo->SensorResetActiveHigh=FALSE; pSensorInfo->SensorResetDelayCount=1; pSensorInfo->SensorOutputDataFormat=SENSOR_OUTPUT_FORMAT_YUYV; pSensorInfo->SensorClockPolarity=SENSOR_CLOCK_POLARITY_LOW; /*??? */ pSensorInfo->SensorClockFallingPolarity=SENSOR_CLOCK_POLARITY_LOW; pSensorInfo->SensorHsyncPolarity = SENSOR_CLOCK_POLARITY_LOW; pSensorInfo->SensorVsyncPolarity = SENSOR_CLOCK_POLARITY_LOW; pSensorInfo->SensorInterruptDelayLines = 1; pSensorInfo->CaptureDelayFrame = 4; pSensorInfo->PreviewDelayFrame = 1; // 2 betty pSensorInfo->VideoDelayFrame = 0; pSensorInfo->SensorMasterClockSwitch = 0; pSensorInfo->SensorDrivingCurrent = ISP_DRIVING_6MA; pSensorInfo->SensroInterfaceType=SENSOR_INTERFACE_TYPE_PARALLEL; SENSORDB("GC2035GetInfo\r\n"); switch (ScenarioId) { case MSDK_SCENARIO_ID_CAMERA_PREVIEW: case MSDK_SCENARIO_ID_VIDEO_PREVIEW: pSensorInfo->SensorClockFreq=22; pSensorInfo->SensorClockDividCount=3; pSensorInfo->SensorClockRisingCount= 0; pSensorInfo->SensorClockFallingCount= 2; pSensorInfo->SensorPixelClockCount= 3; pSensorInfo->SensorDataLatchCount= 2; pSensorInfo->SensorGrabStartX = 2; pSensorInfo->SensorGrabStartY = 2; break; case MSDK_SCENARIO_ID_CAMERA_CAPTURE_JPEG: pSensorInfo->SensorClockFreq=22; pSensorInfo->SensorClockDividCount=3; pSensorInfo->SensorClockRisingCount= 0; pSensorInfo->SensorClockFallingCount= 2; pSensorInfo->SensorPixelClockCount= 3; pSensorInfo->SensorDataLatchCount= 2; pSensorInfo->SensorGrabStartX = 2; pSensorInfo->SensorGrabStartY = 2; break; default: pSensorInfo->SensorClockFreq=22; pSensorInfo->SensorClockDividCount=3; pSensorInfo->SensorClockRisingCount=0; pSensorInfo->SensorClockFallingCount=2; pSensorInfo->SensorPixelClockCount=3; pSensorInfo->SensorDataLatchCount=2; pSensorInfo->SensorGrabStartX = 2; pSensorInfo->SensorGrabStartY = 2; break; } memcpy(pSensorConfigData, &GC2035SensorConfigData, sizeof(MSDK_SENSOR_CONFIG_STRUCT)); return ERROR_NONE; }上面的函数一共传递进来了3个变量,第一个变量:是控制camera的工作模式,(拍照、摄像等等)第2个参数:主要设置imagesensor 的频率的(时钟频率、预览频率、以及同步频率);第3个参数同样也是camera的设置,其实要看到底是在干嘛,只要看看这个参数是如何定义的就可以了。
GC2035GetResolution: UINT32 GC2035GetResolution(MSDK_SENSOR_RESOLUTION_INFO_STRUCT *pSensorResolution) { SENSORDB("GC2035GetResolution\r\n"); pSensorResolution->SensorFullWidth=GC2035_IMAGE_SENSOR_FULL_WIDTH - 2 * IMAGE_SENSOR_START_GRAB_X; pSensorResolution->SensorFullHeight=GC2035_IMAGE_SENSOR_FULL_HEIGHT - 2 * IMAGE_SENSOR_START_GRAB_Y; pSensorResolution->SensorPreviewWidth=GC2035_IMAGE_SENSOR_PV_WIDTH - 2 * IMAGE_SENSOR_START_GRAB_X; pSensorResolution->SensorPreviewHeight=GC2035_IMAGE_SENSOR_PV_HEIGHT - 2 * IMAGE_SENSOR_START_GRAB_Y; pSensorResolution->SensorVideoWidth=GC2035_IMAGE_SENSOR_PV_WIDTH - 2 * IMAGE_SENSOR_START_GRAB_X; pSensorResolution->SensorVideoHeight=GC2035_IMAGE_SENSOR_PV_HEIGHT - 2 * IMAGE_SENSOR_START_GRAB_Y; return ERROR_NONE; }设置camera在预览模式下的高度、宽度等;
GC2035FeatureControl: UINT32 GC2035FeatureControl(MSDK_SENSOR_FEATURE_ENUM FeatureId, UINT8 *pFeaturePara,UINT32 *pFeatureParaLen) { UINT16 *pFeatureReturnPara16=(UINT16 *) pFeaturePara; UINT16 *pFeatureData16=(UINT16 *) pFeaturePara; UINT32 *pFeatureReturnPara32=(UINT32 *) pFeaturePara; UINT32 *pFeatureData32=(UINT32 *) pFeaturePara; MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData=(MSDK_SENSOR_CONFIG_STRUCT *) pFeaturePara; MSDK_SENSOR_REG_INFO_STRUCT *pSensorRegData=(MSDK_SENSOR_REG_INFO_STRUCT *) pFeaturePara; switch (FeatureId) { case SENSOR_FEATURE_GET_RESOLUTION: *pFeatureReturnPara16++=GC2035_IMAGE_SENSOR_FULL_WIDTH; *pFeatureReturnPara16=GC2035_IMAGE_SENSOR_FULL_HEIGHT; *pFeatureParaLen=4; break; case SENSOR_FEATURE_GET_PERIOD: *pFeatureReturnPara16++=GC2035_IMAGE_SENSOR_PV_WIDTH; *pFeatureReturnPara16=GC2035_IMAGE_SENSOR_PV_HEIGHT; *pFeatureParaLen=4; break; case SENSOR_FEATURE_GET_PIXEL_CLOCK_FREQ: //*pFeatureReturnPara32 = GC2035_sensor_pclk/10; *pFeatureParaLen=4; break; case SENSOR_FEATURE_SET_ESHUTTER: break; case SENSOR_FEATURE_SET_NIGHTMODE: GC2035_night_mode((BOOL) *pFeatureData16); break; case SENSOR_FEATURE_SET_GAIN: case SENSOR_FEATURE_SET_FLASHLIGHT: break; case SENSOR_FEATURE_SET_ISP_MASTER_CLOCK_FREQ: GC2035_isp_master_clock=*pFeatureData32; break; case SENSOR_FEATURE_SET_REGISTER: GC2035_write_cmos_sensor(pSensorRegData->RegAddr, pSensorRegData->RegData); break; case SENSOR_FEATURE_GET_REGISTER: pSensorRegData->RegData = GC2035_read_cmos_sensor(pSensorRegData->RegAddr); break; case SENSOR_FEATURE_GET_CONFIG_PARA: memcpy(pSensorConfigData, &GC2035SensorConfigData, sizeof(MSDK_SENSOR_CONFIG_STRUCT)); *pFeatureParaLen=sizeof(MSDK_SENSOR_CONFIG_STRUCT); break; case SENSOR_FEATURE_SET_CCT_REGISTER: case SENSOR_FEATURE_GET_CCT_REGISTER: case SENSOR_FEATURE_SET_ENG_REGISTER: case SENSOR_FEATURE_GET_ENG_REGISTER: case SENSOR_FEATURE_GET_REGISTER_DEFAULT: case SENSOR_FEATURE_CAMERA_PARA_TO_SENSOR: case SENSOR_FEATURE_SENSOR_TO_CAMERA_PARA: case SENSOR_FEATURE_GET_GROUP_INFO: case SENSOR_FEATURE_GET_ITEM_INFO: case SENSOR_FEATURE_SET_ITEM_INFO: case SENSOR_FEATURE_GET_ENG_INFO: break; case SENSOR_FEATURE_GET_GROUP_COUNT: *pFeatureReturnPara32++=0; *pFeatureParaLen=4; break; case SENSOR_FEATURE_GET_LENS_DRIVER_ID: // get the lens driver ID from EEPROM or just return LENS_DRIVER_ID_DO_NOT_CARE // if EEPROM does not exist in camera module. *pFeatureReturnPara32=LENS_DRIVER_ID_DO_NOT_CARE; *pFeatureParaLen=4; break; case SENSOR_FEATURE_CHECK_SENSOR_ID: GC2035_GetSensorID(pFeatureData32); break; case SENSOR_FEATURE_SET_YUV_CMD: //printk("GC2035 YUV sensor Setting:%d, %d \n", *pFeatureData32, *(pFeatureData32+1)); GC2035YUVSensorSetting((FEATURE_ID)*pFeatureData32, *(pFeatureData32+1)); break; case SENSOR_FEATURE_SET_VIDEO_MODE: GC2035YUVSetVideoMode(*pFeatureData16); break; default: break; } return ERROR_NONE; }这个是上层会提供featureid,底层通过这个id进行不同case的执行为para和paralen赋值:
GC2035Control: UINT32 GC2035Control(MSDK_SCENARIO_ID_ENUM ScenarioId, MSDK_SENSOR_EXPOSURE_WINDOW_STRUCT *pImageWindow, MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData) { switch (ScenarioId) { case MSDK_SCENARIO_ID_CAMERA_PREVIEW: case MSDK_SCENARIO_ID_VIDEO_PREVIEW: GC2035_sensor_cap_zsd = KAL_FALSE; GC2035Preview(pImageWindow, pSensorConfigData); break; case MSDK_SCENARIO_ID_CAMERA_CAPTURE_JPEG: GC2035_sensor_cap_zsd = KAL_FALSE; GC2035Capture(pImageWindow, pSensorConfigData); break; case MSDK_SCENARIO_ID_CAMERA_ZSD: GC2035_sensor_cap_zsd = KAL_TRUE; GC2035Capture(pImageWindow, pSensorConfigData); break; default: break; } return TRUE; }这个函数和上面一样,也是提供控制的一个Interface。
GC2035Close:
UINT32 GC2035Close(void) { // CISModulePowerOn(FALSE); SENSORDB("GC2035Close\r\n"); return ERROR_NONE; }这里close没有实现任何事情。
标签:
原文地址:http://blog.csdn.net/bsxiaomage/article/details/51290312