camera开机初始化流程
一.开机camera启动流程framework到hal
Main_mediaserver.cpp (frameworks\av\media\mediaserver)
CameraService::instantiate();
//mediaserver的main函数中调用了CameraService的instantiate函数来创建实例,该函数的实现在其父类BinderService中实现
//CameraService.cpp (frameworks\av\services\camera\libcameraservice)
CameraService::onFirstRef
// Update battery life tracking if service is restarting
BatteryNotifier& notifier(BatteryNotifier::getInstance());
notifier.noteResetCamera();
notifier.noteResetFlashlight();
//通过hw_get_module函数加载了一个hw_module_t模块,这个模块是与hal层对接的接口,ID为CAMERA_HARDWARE_MODULE_ID,并将它保存在mModule成员变量中。
int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t **)&rawModule);
mModule = new CameraModule(rawModule);
err = mModule->init();
//通过mModule->get_number_of_cameras函数进入到hal层,获取到了camera的个数。这个函数很重要,对于frameworks层来说只是拿到了camera的个数,
//但对于hal层和drivers层来说Camera的上电和初始化流程都是从这里开始的
mNumberOfCameras = mModule->getNumberOfCameras();
//CameraModule.cpp (frameworks\av\services\camera\libcameraservice\common)
return mModule->get_number_of_cameras(); //调用到HAL层
Module.h (vendor\mediatek\proprietary\hardware\mtkcam\legacy\module_hal\module)
NSCam::getCamDeviceManager()->getNumberOfDevices();
//CamDeviceManagerImp.cpp (vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6735\devicemgr)
&gCamDeviceManager;getNumberOfDevices
//CamDeviceManagerBase.cpp (vendor\mediatek\proprietary\hardware\mtkcam\legacy\module_hal\devicemgr)
mi4DeviceNum = enumDeviceLocked();
//CamDeviceManagerImp.cpp (vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6735\devicemgr)
IHalSensorList*const pHalSensorList = IHalSensorList::get();
size_t const sensorNum = pHalSensorList->searchSensors(); //搜索看从HAL层开始分析
具体分析可以参考
http://blog.csdn.net/eternity9255/article/details/52085864
二.开机打开sensor总结
- HAL层运行Search sensor这个线程
- HAL层遍历sensorlist列表并挂载HAL层性能3A等一些参数获取的接口
- HAL层下达setDriver的cmd,并下传正在遍历的sensorlist列表中的ID
- Driver层根据这个ID,挂载Driver层sensorlist中对应的Sensorlist中对应的Sensor和具体Sensor底层操作接口
- HAL层对正确遍历的sensor下达check ID的指令
- Driver层为对应sensor上电,通过I2C读取预存在寄存器中的sensor id
- 比较读取结果,不匹配,return error,继续遍历
- 匹配,HAL层下达其他指令收集sensor信息
- sensor下电
kdSetDriver()函数有一个参数,这个参数是由impSearchSensor()传下来的,如果主(后)camera,那么这个值是10000、10001、10002等,如果是次(前)camera,那么这个值是20000、20001、20002等
如果是后camera,那么g_invokeSocketIdx[0]的值应为1,如果是前camera,那么应是2。而drvIdx[0]的值是sensor驱动列表的索引号,例如0、1、2等。
这就是找到一个sensor的流程,先主(后)camera,后次(前)camera。
找后camera,会遍历一遍sensor列表,找前camera,再遍历一遍sensor列表,注意模块的上电,id值的读取。
找后camera,会遍历一遍sensor列表,找前camera,再遍历一遍sensor列表,注意模块的上电,id值的读取。
1.从HAL层开始分析
CamDeviceManagerImp.cpp (vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6735\devicemgr)的enumDeviceLocked()函数
pHalSensorList->searchSensors() 将调用SensorDrv::searchSensor(NULL)函数,该函数再调用ImgSensor_drv.cpp文件中中的ImgSensorDrv::impSearchSensor函数
enumDeviceLocked()
sensorNum = pHalSensorList->searchSensors();
//Imgsensor_drv.cpp (vendor\mediatek\proprietary\hardware\mtkcam\legacy\platform\mt6735\hal\sensor)
ImgSensorDrv::impSearchSensor
//If imp sensor search process already done before,only need to return the sensorDevs, not need to search again.
//如果已经运行了搜索进程,就不会再进程搜索,直接返回。
GetSensorInitFuncList(&m_pstSensorInitFunc); //没有搜索的情况下,调用这个函数,单独分析1
sprintf(cBuf,"/dev/%s",CAMERA_HW_DEVNAME); //这个宏在device/mediatek/common/kernel-headers/kd_imgsensor.h中
#define CAMERA_HW_DEVNAME "kd_camera_hw"
m_fdSensor = ::open(cBuf, O_RDWR); //打开/dev/kd_camera_hw节点,在Kd_sensorlist.c (kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6735)生成 的file_operations的open
for (i = 0; i < MAX_NUM_OF_SUPPORT_SENSOR; i++) //MAX_NUM_OF_SUPPORT_SENSOR是32个
//在device/mediatek/common/kernel-headers/kd_imgsensor_define.h中
#define KDIMGSENSOR_INVOKE_DRIVER_0 (0)
#define KDIMGSENSOR_DUAL_SHIFT 16
DUAL_CAMERA_MAIN_SENSOR = 1
////因为前面SensorEnum = (MUINT32)DUAL_CAMERA_MAIN_SENSOR;,所以SensorEnum = 1;
id[KDIMGSENSOR_INVOKE_DRIVER_0] = (SensorEnum << KDIMGSENSOR_DUAL_SHIFT) | i; 化简==>id[0] = 0x10000 | i;
err = ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER,&id[KDIMGSENSOR_INVOKE_DRIVER_0] ); //获取底层的摄像头相应的操作函数
err = ioctl(m_fdSensor, KDIMGSENSORIOC_T_CHECK_IS_ALIVE); //检测摄像头是否存在,主要是读ID
sensorType = this->getCurrentSensorType((SENSOR_DEV_ENUM)SensorEnum);
getInfo(scenarioId, m_psensorInfo, m_psensorConfigData)
ioctl(m_fdSensor, KDIMGSENSORIOC_X_GETINFO , &getInfo); //得到sensor的信息
socketPos = this->getSocketPosition((CAMERA_DUAL_CAMERA_SENSOR_ENUM)SensorEnum);
err = ioctl(m_fdSensor, KDIMGSENSORIOC_X_GET_SOCKET_POS , &socketPos); //得到分辨率
//保存一些信息
m_mainSensorDrv.index[m_mainSensorDrv.number] = i;
m_mainSensorDrv.position = socketPos;
。。。。。。。。。。。。。。。
//close system call may be off sensor power. check first!!!
::close(m_fdSensor);
err = ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_CURRENT_SENSOR, &sensorIdx);
err = ioctl(m_fdSensor, KDIMGSENSORIOC_T_CLOSE); //关闭摄像头
单独分析1
GetSensorInitFuncList(&m_pstSensorInitFunc); //没有搜索的情况下,调用这个函数,单独分析
//Sensorlist.cpp (vendor\mediatek\proprietary\custom\mt6735\hal\d1\imgsensor_src)
GetSensorInitFuncList //调用这个函数,获取hal层sensor列表
MSDK_SENSOR_INIT_FUNCTION_STRUCT SensorList[] = {
#if defined(GC5005_MIPI_RAW)
RAW_INFO(GC5005_SENSOR_ID, SENSOR_DRVNAME_GC5005_MIPI_RAW,NULL), //单独分析2
#endif
}
//单独分析2
RAW_INFO和YUV_INFO
#define YUV_INFO(_id, name, getCalData)\ //
{ \
_id, name, \
NSFeature::YUVSensorInfo<_id>::createInstance(name, #name), \
(NSFeature::SensorInfoBase*(*)()) \
NSFeature::YUVSensorInfo<_id>::getInstance, \
NSFeature::YUVSensorInfo<_id>::getDefaultData, \
getCalData, \
NSFeature::YUVSensorInfo<_id>::getNullFlickerPara \
#define RAW_INFO(_id, name, getCalData)\
{ \
_id, name, \
NSFeature::RAWSensorInfo<_id>::createInstance(name, #name), \
(NSFeature::SensorInfoBase*(*)()) \
NSFeature::RAWSensorInfo<_id>::getInstance, \
NSFeature::RAWSensorInfo<_id>::getDefaultData, \
getCalData, \
NSFeature::RAWSensorInfo<_id>::getFlickerPara \
}
根据不同的sensor类型使用RAW_INFO或YUV_INFO,再根据ID和name生成结构体,所以ID和NAME需要唯一。
二.驱动分析
Kd_sensorlist.c (kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6735)
1.初始化
static struct platform_device camerahw_platform_device = {
.name = "image_sensor",
.id = 0,
.dev = {
.coherent_dma_mask = DMA_BIT_MASK(32),
}
};
static struct platform_device camerahw2_platform_device = {
.name = "image_sensor_bus2",
.id = 0,
.dev = {
}
};
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
}
};
tatic struct platform_driver g_stCAMERA_HW_Driver2 = {
.probe = CAMERA_HW_probe2,
.remove = CAMERA_HW_remove2,
.suspend = CAMERA_HW_suspend2,
.resume = CAMERA_HW_resume2,
.driver = {
.name = "image_sensor_bus2",
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = CAMERA_HW2_of_ids,
#endif
CAMERA_HW_i2C_init
platform_device_register(&camerahw_platform_device); //注册device
platform_device_register(&camerahw2_platform_device);
platform_driver_register(&g_stCAMERA_HW_Driver) //注册driver,进入CAMERA_HW_probe
platform_driver_register(&g_stCAMERA_HW_Driver2) ////注册driver,进入CAMERA_HW_probe2
proc_create("driver/camsensor", 0, NULL, &fcamera_proc_fops); // proc/driver/camsensor调试文件节点,写寄存器
proc_create("driver/camsensor2", 0, NULL, &fcamera_proc_fops2);
proc_create("driver/camsensor3", 0, NULL, &fcamera_proc_fops3);
proc_create(PROC_CAMERA_INFO, 0, NULL, &fcamera_proc_fops1); //#define PROC_CAMERA_INFO "driver/camera_info",读取摄像头信息
2.平台probe函数
truct 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,
};
CAMERA_HW_probe
mtkcam_gpio_init(pdev); //获取DTS的端口
camctrl = devm_pinctrl_get(&pdev->dev);
cam0_pnd_h = pinctrl_lookup_state(camctrl, "cam0_pnd1");
i2c_add_driver(&CAMERA_HW_i2c_driver); //注册I2C设备,进入I2C的CAMERA_HW_i2c_probe函数
struct i2c_driver CAMERA_HW_i2c_driver2 = {
.probe = CAMERA_HW_i2c_probe2,
.remove = CAMERA_HW_i2c_remove2,
.driver = {
.name = CAMERA_HW_DRVNAME2,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = CAMERA_HW2_i2c_driver_of_ids,
#endif
},
.id_table = CAMERA_HW_i2c_id2,
};
CAMERA_HW_probe2
i2c_add_driver(&CAMERA_HW_i2c_driver2); //注册
3.I2C的probe函数
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,
#ifdef CONFIG_COMPAT
.compat_ioctl = CAMERA_HW_Ioctl_Compat,
#endif
CAMERA_HW_i2c_probe
/* set I2C clock rate */
g_pstI2Cclient2->timing = 100;/* 100k */
/* Register char driver */
RegisterCAMERA_HWCharDrv();、
alloc_chrdev_region(&g_CAMERA_HWdevno, 0, 1, CAMERA_HW_DRVNAME1) // #define CAMERA_HW_DRVNAME1 "kd_camera_hw"
g_pCAMERA_HW_CharDrv = cdev_alloc(); ///* Allocate driver */
cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops); //设置操作函数
cdev_add(g_pCAMERA_HW_CharDrv, g_CAMERA_HWdevno, 1) //添加到系统
sensor_class = class_create(THIS_MODULE, "sensordrv"); //sysfs类型
device_create(sensor_class, NULL, g_CAMERA_HWdevno, NULL, CAMERA_HW_DRVNAME1); //sysfs节点
static const struct file_operations g_stCAMERA_HW_fops0 = {
.owner = THIS_MODULE,
.open = CAMERA_HW_Open2,
.release = CAMERA_HW_Release2,
.unlocked_ioctl = CAMERA_HW_Ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = CAMERA_HW_Ioctl_Compat,
#endif
};
CAMERA_HW_i2c_probe2
g_pstI2Cclient2->timing = 100;/* 100k */
RegisterCAMERA_HWCharDrv2();
alloc_chrdev_region(&g_CAMERA_HWdevno2, 0, 1, CAMERA_HW_DRVNAME2) //#define CAMERA_HW_DRVNAME2 "kd_camera_hw_bus2"
g_pCAMERA_HW_CharDrv2 = cdev_alloc();
cdev_init(g_pCAMERA_HW_CharDrv2, &g_stCAMERA_HW_fops0); //操作函数
cdev_add(g_pCAMERA_HW_CharDrv2, g_CAMERA_HWdevno2, 1)
sensor2_class = class_create(THIS_MODULE, "sensordrv2");
device_create(sensor2_class, NULL, g_CAMERA_HWdevno2, NULL, CAMERA_HW_DRVNAME2);
四.驱动层给HAL层提供的IOCTL函数
Kd_sensorlist.c (kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6735)
CAMERA_HW_Ioctl
_IOC_NONE == _IOC_DIR(a_u4Command) // 获取读写属性域值 (bit30 ~ bit31)
pBuff = kmalloc(_IOC_SIZE(a_u4Command), GFP_KERNEL); //分配4个字节
if (_IOC_WRITE & _IOC_DIR(a_u4Command)) //如果是写
copy_from_user(pBuff , (void *) a_u4Param, _IOC_SIZE(a_u4Command)) //拷贝用户空间的数据
switch (a_u4Command) //执行IOCTL
case KDIMGSENSORIOC_X_SET_DRIVER: //设置对应摄像头的操作函数
i4RetValue = kdSetDriver((unsigned int *)pBuff); //单独分析1,这个pBuff是从上层传下来的
case KDIMGSENSORIOC_T_CHECK_IS_ALIVE: //检查摄像头是否存在,上电和读取id
i4RetValue = adopt_CAMERA_HW_CheckIsAlive(); //单独分析2
case KDIMGSENSORIOC_X_GETINFO: //获取摄像头信息
i4RetValue = adopt_CAMERA_HW_GetInfo(pBuff);
g_pSensorFunc->SensorGetInfo(pScenarioId, pInfo, pConfig);
SensorGetInfo //调用具体摄像头驱动的SensorGetInfo
copy_to_user((void __user *)(pSensorGetInfo->pInfo[i]), (void *)pInfo[i] , sizeof(MSDK_SENSOR_INFO_STRUCT)) /* SenorInfo */
copy_to_user((void __user *)(pSensorGetInfo->pConfig[i]) , (void *)pConfig[i] , sizeof(MSDK_SENSOR_CONFIG_STRUCT)) /* SensorConfig */
case KDIMGSENSORIOC_X_SET_CURRENT_SENSOR: //设置现在的摄像头id
i4RetValue = kdSetCurrentSensorIdx(*pIdx);
g_CurrentSensorIdx = idx;
case KDIMGSENSORIOC_T_CLOSE: //关闭摄像头
i4RetValue = adopt_CAMERA_HW_Close();
g_pSensorFunc->SensorClose(); //调用具体的摄像头的函数
static SENSOR_FUNCTION_STRUCT sensor_func = {
open,
get_info,
get_resolution,
feature_control,
control,
close
};
//单独分析1
kdSetDriver
kdGetSensorInitFuncList(&pSensorList) //得到sensor列表
*ppSensorList = &kdSensorList[0]; //Kd_sensorlist.h (kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6735)中的
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] = {
#if defined(IMX220_MIPI_RAW)
{IMX220_SENSOR_ID, SENSOR_DRVNAME_IMX220_MIPI_RAW, IMX220_MIPI_RAW_SensorInit},
#endif
}
for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++) //化简得到==> for(i=0;i<2;i++)
g_bEnableDriver[i] = FALSE;
//化简下面的==》g_invokeSocketIdx[i] = (CAMERA_DUAL_CAMERA_SENSOR_ENUM)((pDrvIndex[i] & 0xFFFF0000) >> 16); 得到高16位是1还是2,1就是主摄像头
g_invokeSocketIdx[i] = (CAMERA_DUAL_CAMERA_SENSOR_ENUM)((pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_MSB) >> KDIMGSENSOR_DUAL_SHIFT);
//化简下面==》 drvIdx[i] = (pDrvIndex[i] & 0x0000FFFF); 得到低16位,就也是摄像头在表中的位置,所以kdSensorList和SensorList要一一对应
drvIdx[i] = (pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_LSB);
if (DUAL_CAMERA_SUB_SENSOR == g_invokeSocketIdx[i]) //如果是前置摄像头
gI2CBusNum = SUPPORT_I2C_BUS_NUM2;
else //否则
gI2CBusNum = SUPPORT_I2C_BUS_NUM1;
pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]); //执行 SensorInit函数,这里就是kdSensorList里面填的函数,得到sensor的接口函数,赋值
GC2355_MIPI_RAW_SensorInit //比如GC2355
*pfFunc=&sensor_func;
g_bEnableDriver[i] = TRUE;
memcpy((char *)g_invokeSensorNameStr[i], (char *)pSensorList[drvIdx[i]].drvname, sizeof(pSensorList[drvIdx[i]].drvname)); //得到sensor的名字
//单独分析2
adopt_CAMERA_HW_CheckIsAlive
//上电,/* power on sensor */
g_invokeSocketIdx:是前摄还是后摄; g_invokeSensorNameStr:摄像头名称; true:上电; CAMERA_HW_DRVNAME1:名称
kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM *)g_invokeSocketIdx, g_invokeSensorNameStr, true, CAMERA_HW_DRVNAME1);
if (g_bEnableDriver[i])
ret = kdCISModulePowerOn(socketIdx[i], sensorNameStr[i], On, mode_name);
if (On) {
if (pinSetIdx == 0) //主摄像头
ISP_MCLK1_EN(1); //第一路ISP时钟打开
else if (pinSetIdx == 1) //副摄像头
ISP_MCLK1_EN(1); //第一路ISP时钟打开
if (currSensorName && (0 == strcmp(SENSOR_DRVNAME_OV5648_MIPI_RAW, currSensorName))) //匹配具体摄像头
if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN]) //摄像头的上电脚
//pinSetIdx:主摄像头还是摄像头; CAMPDN:那个引脚; pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_OFF]:拉高还是拉低
mtkcam_gpio_set(pinSetIdx, CAMPDN, pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_OFF]); //拉低使能引脚
if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMRST])
mtkcam_gpio_set(pinSetIdx, CAMRST, pinSet[pinSetIdx][IDX_PS_CMRST + IDX_PS_OFF]); //拉低复位脚
_hwPowerOn(VCAMIO, VOL_1800) //IO供电1.8V
_hwPowerOn(VCAMA, VOL_2800) //模拟供电脚2.8v
_hwPowerOn(VCAMD, VOL_1500) //数字供电聊2.5V
_hwPowerOn(VCAMAF, VOL_2800) //AF供电2.8v
if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMPDN])
mtkcam_gpio_set(pinSetIdx, CAMPDN, pinSet[pinSetIdx][IDX_PS_CMPDN + IDX_PS_ON]); //拉高使能脚
if (GPIO_CAMERA_INVALID != pinSet[pinSetIdx][IDX_PS_CMRST])
mtkcam_gpio_set(pinSetIdx, CAMRST, pinSet[pinSetIdx][IDX_PS_CMRST + IDX_PS_ON]); //拉高复位脚
else //如果没有特殊要求,使用默认供电函数
。。。。。。。。。。。。。
else { /* power OFF */ 下电
if (pinSetIdx == 0)
ISP_MCLK1_EN(0); //关闭ISP时钟
else if (pinSetIdx == 1)
ISP_MCLK1_EN(0);
。。。。。。。。。。根据上电下电。。。。。。。。
if (g_pSensorFunc)
for (i = KDIMGSENSOR_INVOKE_DRIVER_0; i < KDIMGSENSOR_MAX_INVOKE_DRIVERS; i++)
g_pSensorFunc->SensorFeatureControl(g_invokeSocketIdx[i], SENSOR_FEATURE_CHECK_SENSOR_ID, (MUINT8 *)&sensorID, &retLen);
feature_control //调用具体摄像头的feature_control函数
case SENSOR_FEATURE_CHECK_SENSOR_ID: //这里获取sensor ID
get_imgsensor_id(feature_return_para_32); //通过I2C读取摄像头的ID
//如果读取到了ID就把摄像头的名字和前后摄状态记录
snprintf(mtk_ccm_name, sizeof(mtk_ccm_name), "%s CAM[%d]:%s;", mtk_ccm_name, g_invokeSocketIdx[i], g_invokeSensorNameStr[i]);
/* reset sensor state after power off */
err1 = g_pSensorFunc->SensorClose(); //关闭sensor
kdModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM *)g_invokeSocketIdx, g_invokeSensorNameStr, false, CAMERA_HW_DRVNAME1); //下电
五.camera的i2c注册
1. 首先注册一个假的I2C设备,然后通讯的时候用真的I2C地址,因为有两个摄像头,所以注册两个设备。
i2c_add_driver(&CAMERA_HW_i2c_driver); //注册I2C设备,进入I2C的CAMERA_HW_i2c_probe函数,在probe里面没有读取i2c设备,所以可以注册成功。
g_pstI2Cclient = client; //把client保存在g_pstI2Cclient
gc2355mipi_Sensor.c (kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6735m\gc2355_mipi_raw)
1.上层函数检查sensor是否存在的时候,也是就是四章中的单独分析2
get_imgsensor_id(feature_return_para_32); //通过I2C读取摄像头的ID
imgsensor.i2c_write_id = imgsensor_info.i2c_addr_table[i]; //这是当前摄像头的I2C地址
*sensor_id = return_sensor_id();
return ((read_cmos_sensor(0xf0) << 8) | read_cmos_sensor(0xf1));
iReadRegI2C(pu_send_cmd, 1, (u8*)&get_byte, 1, imgsensor.i2c_write_id); //读取i2c
//调用Kd_sensorlist.c (kernel-3.18\drivers\misc\mediatek\imgsensor\src\mt6735)中的iReadRegI2C
g_pstI2Cclient->addr = (i2cId >> 1); //给I2Cclient赋值真正的I2C地址
i4RetValue = i2c_master_send(g_pstI2Cclient, a_pSendData, a_sizeSendData); //写设备,如果能写成功,说明设备存在
i4RetValue = i2c_master_recv(g_pstI2Cclient, (char *)a_pRecvData, a_sizeRecvData); //读,如果成功,说明存在