android 将系统大致分为应用层、库文件和硬 件抽象层、Linux 内核三层。在底层的内核空间,Camera 的driver 将其驱动起来以后,将硬 件驱动的接**给硬件抽象层,android 上层的Camera 应用程序在android 实时系统中的虚 拟机中,加载android 留给Camera 公用的一些库文件,调用硬件抽象层的接口来控制Camera 硬件来实现功能。当然,如果是Raw 模式的Camera ,还需要在硬件抽象层调用一些参数来 控制Camera 的效果。 一般在 Linux 设备驱动模型中,我们只需要关心总线、设备、驱动这三个实体。总线会充当红娘对加载于其上的设备与驱动进行配对,对于 Camera 模块也不例外,下面从总线、设备、驱动的角度来分析 Camera 模块驱动的注册、匹配与加载过程。a)驱动的注册:在( \custom\common\kernel\imgsensor\src\Kd_sensorlist.c) CAMERA_HW_i2C_init 这个函数里通过Platform_driver_register(&g_stCAMERA_HW_Driver)把 Camera 模块驱动注册到 Platform 总线上。而 g_stCAMERA_HW_Driver 是对结构体 Platform_driver 这个结构体的填充。(Kernel\include\linux\Platform_device.h)Platform_driver 这个结构体包含 Probe()、 Remove()等函数来完成驱动的填充。b)设备的注册:对 platform_device 的定义通常在 BSP 的板级文件( kernel\arch\sh\boards\mach-ap325rxa\Setup.c)中实现,在板级文件中,将 platform_device归纳为一个数组,最终通过 platform_add_device()函数统一注册: c)总线的匹配:既 然 是 驱 动 Platform_device 那 对 应 的 设 备 必 然 是 挂 载 Platform 总 线 上 的Platform_device, Platform 总线是 Linux 系统提供的一种机制,不同于 I2C、 I2S 等总线,它是一种虚拟的总线。Linux 系统为 Platform 总线定义了一个 bus_type 的实例 Platform_bus_type:( Kernel\drivers\base\platform.c)Platform 总线通过 platform_match 这个成员函数来确定 platform_device 与 platform_driver 如何进行匹配:Camera驱动工作流程:从上图可以清晰的了解到 Camera 的一个工作流程主要分为这么七步:1. 打开 Camera Power LDO,让 Camera 有能量保证。2. 打开 IIC,设置 PDN 引脚,使 Camera 退出出 Standby 模式,按照要求让 Reset 脚做一个复位动作。3. 读一下 sensor 的版本 ID,这样可以让你确认是否连接上你想要的 sensor。4. 对 Sensor 进行初始化下载最基本的参数让 Sensor 工作起来,可能包括软复位。5. 下载 preview 的参数,为预览动作准备。6. 下载 Capture 的参数,为拍照动作准备。7. 设置 PDN 引脚,使 Sensor 进入 Standby 模式,或者关掉 LDO 等动作,退出 Camera。我们都知道, Linux 内核是通过模块的机制来加载设备驱动的,那么接下来我们就从设备模块加载的角度来看下 Camera 工作流程的驱动代码是如何工作的。在-alps\mediatek\custom\common\kernel\imgsensor\src\kd_sensorlist.c 中可以看到:module_init(CAMERA_HW_i2C_init);module_exit(CAMERA_HW_i2C_exit);在这里 Linux 内核加载和卸载 Camera 模块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,}};Camera 模块初始化开始向总线注册驱动,在 Platform_driver 的成员函数.probe()中, 通过 i2c_add_driver(&CAMERA_HW_i2c_driver)向 I2C 申请,而 CAMERA_HW_i2c_driver 这个结构体里填充的是将 Camera 作为一个字符设备在 I2C 上进行注册: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,};/******************************************************************************* * i2c relative start********************************************************************************//******************************************************************************** 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; //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;}在 RegisterCAMERA_HWCharDrv() 中cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops);对设备进行初始化,并将g_stCAMERA_HW_fops 这个文件操作函数作为上层对 Camera 设备操作的接口留给上层进行调用: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};其中成员函数 open()只是初始化一个原子变量留给系统调用。 ioctl()才是整个 Camera驱动的入口:CAMERA_HW_Ioctl()是上层文件操作系统操作底层硬件的方法,它先对 Camera 需要的Buffer 做一个初始化,然后建立对 Cameraopen、 getinfo 等操作的接口:/******************************************************************************** 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); 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;}通过判断 Sensor 状态的逻辑值来进行具体的操作, 对于这个值的定义在:Mediatek\custom\common\kernel\imgsensor\inc\Kd_imgsensor.h 中//sensorOpen//This command will TBD#define KDIMGSENSORIOC_T_OPEN _IO(IMGSENSORMAGIC,0)//sensorGetInfo//This command will TBD#define KDIMGSENSORIOC_X_GETINFO _IOWR(IMGSENSORMAGIC,5,ACDK_SENSOR_GETINFO_STRUCT)//sensorGetResolution//This command will TBD#define KDIMGSENSORIOC_X_GETRESOLUTION _IOWR(IMGSENSORMAGIC,10,ACDK_SENSOR_RESOLUTION_INFO_STRUCT)//sensorFeatureControl//This command will TBD#define KDIMGSENSORIOC_X_FEATURECONCTROL _IOWR(IMGSENSORMAGIC,15,ACDK_SENSOR_FEATURECONTROL_STRUCT)//sensorControl//This command will TBD#define KDIMGSENSORIOC_X_CONTROL _IOWR(IMGSENSORMAGIC,20,ACDK_SENSOR_CONTROL_STRUCT)//sensorClose//This command will TBD#define KDIMGSENSORIOC_T_CLOSE _IO(IMGSENSORMAGIC,25)//sensorSearch #define KDIMGSENSORIOC_T_CHECK_IS_ALIVE _IO(IMGSENSORMAGIC, 30) //set sensor driver#define KDIMGSENSORIOC_X_SET_DRIVER _IOWR(IMGSENSORMAGIC,35,SENSOR_DRIVER_INDEX_STRUCT)//get socket postion#define KDIMGSENSORIOC_X_GET_SOCKET_POS _IOWR(IMGSENSORMAGIC,40,u32)//set I2C bus #define KDIMGSENSORIOC_X_SET_I2CBUS _IOWR(IMGSENSORMAGIC,45,u32)//set I2C bus #define KDIMGSENSORIOC_X_RELEASE_I2C_TRIGGER_LOCK _IO(IMGSENSORMAGIC,50)//Set Shutter Gain Wait Done#define KDIMGSENSORIOC_X_SET_SHUTTER_GAIN_WAIT_DONE _IOWR(IMGSENSORMAGIC,55,u32)//HDR//set mclk#define KDIMGSENSORIOC_X_SET_MCLK_PLL _IOWR(IMGSENSORMAGIC,60,ACDK_SENSOR_MCLK_STRUCT)在 KdSetDriver()中通过判断 name 和 ID 匹配具体型号的 sensor 的驱动,判断它是主摄还是次摄,并对它进行初始化:/******************************************************************************** kdSetDriver********************************************************************************/int kdSetDriver(unsigned int* pDrvIndex){ ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT *pSensorList = NULL; 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)) { PK_ERR("ERROR:kdGetSensorInitFuncList()\n"); return -EIO; } for ( i = KDIMGSENSOR_INVOKE_DRIVER_0; 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);spin_unlock(&kdsensor_drv_lock); drvIdx[i] = (pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_LSB); // if ( DUAL_CAMERA_NONE_SENSOR == g_invokeSocketIdx[i] ) { continue; }/*if( DUAL_CAMERA_MAIN_2_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");}*///ToDo: remove print informationPK_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]); 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;}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;通过 NAME 和 ID 匹配完成后会将 PSENSOR_FUNCTION_STRUCT *pfFunc 这个结构体匹配到具体型号的驱动代码中:SENSOR_FUNCTION_STRUCT SensorFuncGC0329YUV={GC0329Open,GC0329GetInfo,GC0329GetResolution,GC0329FeatureControl,GC0329Control,GC0329Close};到这里,整个 Camera 驱动从总线注册到完成具体 sensor 的初始化的流程就完成了,CAMERA_HW_Ioctl()中其他的 ioctl 操作函数最后都会在$sensor$_sensor.c 中实现。 10-29 16:16