分五步走:
//HAl层命令通道
static long CAMERA_HW_Ioctl(
struct file *a_pstFile,
unsigned int a_u4Command,
unsigned long a_u4Param
)
{
switch (a_u4Command) {
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_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;
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;
}
return i4RetValue;
}
******************************************
第五步: 汇集于IOCTL
static long CAMERA_HW_Ioctl_Compat(struct file *filp, unsigned int cmd, unsigned long arg)
{
...
/* Data in the following commands is not required to be converted to kernel 64-bit & user 32-bit */
case KDIMGSENSORIOC_T_OPEN:
case KDIMGSENSORIOC_T_CLOSE:
case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:
case KDIMGSENSORIOC_X_SET_DRIVER:
case KDIMGSENSORIOC_X_GET_SOCKET_POS:
case KDIMGSENSORIOC_X_SET_I2CBUS:
case KDIMGSENSORIOC_X_RELEASE_I2C_TRIGGER_LOCK:
case KDIMGSENSORIOC_X_SET_SHUTTER_GAIN_WAIT_DONE:
case KDIMGSENSORIOC_X_SET_MCLK_PLL:
case KDIMGSENSORIOC_X_SET_CURRENT_SENSOR:
case KDIMGSENSORIOC_X_SET_GPIO:
case KDIMGSENSORIOC_X_GET_ISP_CLK:
return filp->f_op->unlocked_ioctl(filp, cmd, arg);
default:
return -ENOIOCTLCMD;
}
}
***********************************************************************************************
第四步 : 分别实现自己的字符设备注册函数以及fops结构体,可以注意到 两个fops指向同一个 ioctl
//主摄像头字符设备 fops
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
};
//副摄像头字符设备 fops
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
};
//主摄像头字符设备 注册函数
static inline int RegisterCAMERA_HWCharDrv(void)
{
...常规字符设备创建过程...
/* Attatch 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;
}
//创建目录 /sys/class/sensordrv/
sensor_class = class_create(THIS_MODULE, "sensordrv");
if (IS_ERR(sensor_class)) {
int ret = PTR_ERR(sensor_class);
PK_DBG("Unable to create class, err = %d\n", ret);
return ret;
}
//创建目录/sys/class/sensordrv/kd_camera_hw
sensor_device = device_create(sensor_class, NULL, g_CAMERA_HWdevno, NULL, CAMERA_HW_DRVNAME1);
return 0;
}
//副摄像头字符设备 注册函数
static inline int RegisterCAMERA_HWCharDrv2(void)
{
...常规字符设备创建过程...
/* Attatch file operation. */
cdev_init(g_pCAMERA_HW_CharDrv2, &g_stCAMERA_HW_fops0);
g_pCAMERA_HW_CharDrv2->owner = THIS_MODULE;
/* Add to system */
if (cdev_add(g_pCAMERA_HW_CharDrv2, g_CAMERA_HWdevno2, 1)) {
PK_DBG("[mt6516_IDP] Attatch file operation failed\n");
unregister_chrdev_region(g_CAMERA_HWdevno2, 1);
return -EAGAIN;
}
//创建目录 /sys/class/sensordrv2/
sensor2_class = class_create(THIS_MODULE, "sensordrv2");
if (IS_ERR(sensor2_class)) {
int ret = PTR_ERR(sensor2_class);
PK_DBG("Unable to create class, err = %d\n", ret);
return ret;
}
//创建目录/sys/class/sensordrv/kd_camera_hw_bus2
sensor_device = device_create(sensor2_class, NULL, g_CAMERA_HWdevno2, NULL, CAMERA_HW_DRVNAME2);
return 0;
}
***********************************************************************************************
第三步: 在i2c prob()中分别注册字符设备驱动
static int CAMERA_HW_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
/* Register char driver 注册字符设备驱动 */
i4RetValue = RegisterCAMERA_HWCharDrv();
}
static int CAMERA_HW_i2c_probe2(struct i2c_client *client, const struct i2c_device_id *id)
{
/* Register char driver 注册字符设备驱动*/
i4RetValue = RegisterCAMERA_HWCharDrv2();
}
*************************************************************************************************
第二步:在平台prob()中分别注册自己的I2C驱动,匹配cust_i2c.dtsi 中的i2c设备 mediatek,camera_main 以及 mediatek,camera_sub ,成功则调用各自的 i2c prob()
//主摄像头I2C设备
static const struct of_device_id CAMERA_HW_i2c_of_ids[] = {
{ .compatible = "mediatek,camera_main", },
{}
};
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,
.of_match_table = CAMERA_HW_i2c_of_ids,
},
.id_table = CAMERA_HW_i2c_id,
};
//副摄像头I2C设备
static const struct of_device_id CAMERA_HW2_i2c_driver_of_ids[] = {
{ .compatible = "mediatek,camera_sub", },
{}
};
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,
.of_match_table = CAMERA_HW2_i2c_driver_of_ids,
},
.id_table = CAMERA_HW_i2c_id2,
};
static int CAMERA_HW_probe(struct platform_device *pdev)
{
return i2c_add_driver(&CAMERA_HW_i2c_driver);
}
static int CAMERA_HW_probe2(struct platform_device *pdev)
{
return i2c_add_driver(&CAMERA_HW_i2c_driver2);
}
***************************************************************************************************
第一步 :CAMERA_HW_i2C_init中初始化,注册平台驱动,并且匹配dts mt6735.dtsi 中的平台设备 mediatek,camera_hw 以及 mediatek,camera_hw2,成功则调用 prob()
//主摄像头平台驱动 以及 匹配设备
static const struct of_device_id CAMERA_HW_of_ids[] = {
{ .compatible = "mediatek,camera_hw", },
{}
};
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
}
};
//副像头平台驱动 以及 匹配设备
static const struct of_device_id CAMERA_HW2_of_ids[] = {
{ .compatible = "mediatek,camera_hw2", },
{}
};
static 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
}
};
static int __init CAMERA_HW_i2C_init(void)
{
//注册i2c设备
i2c_register_board_info(SUPPORT_I2C_BUS_NUM1, &i2c_devs1, 1);
i2c_register_board_info(SUPPORT_I2C_BUS_NUM2, &i2c_devs2, 1);
//注册平台驱动
platform_driver_register(&g_stCAMERA_HW_Driver))
platform_driver_register(&g_stCAMERA_HW_Driver2))
}
module_init(CAMERA_HW_i2C_init);
module_exit(CAMERA_HW_i2C_exit);
cust_i2c.dtsi
{
&i2c0 {
camera_main@10 {
compatible = "mediatek,camera_main";
reg = <0x10>;
};
camera_sub@3c {
compatible = "mediatek,camera_sub";
reg = <0x3c>;
};
};
}
mt6735.dtsi
{
kd_camera_hw1:kd_camera_hw1@15008000 {
compatible = "mediatek,camera_hw";
reg = <0x15008000 0x1000>; /* SENINF_ADDR */
vcama-supply = <&mt_pmic_vcama_ldo_reg>;
vcamd-supply = <&mt_pmic_vcamd_ldo_reg>;
vcamaf-supply = <&mt_pmic_vcam_af_ldo_reg>;
vcamio-supply = <&mt_pmic_vcam_io_ldo_reg>;
/* Camera Common Clock Framework (CCF) */
clocks = <&topckgen TOP_MUX_CAMTG>,
<&topckgen TOP_UNIVPLL_D26>,
<&topckgen TOP_UNIVPLL2_D2>;
clock-names = "TOP_CAMTG_SEL","TOP_UNIVPLL_D26","TOP_UNIVPLL2_D2";
};
kd_camera_hw2:kd_camera_hw2@15008000 {
compatible = "mediatek,camera_hw2";
reg = <0x15008000 0x1000>; /* SENINF_ADDR */
};
}
xxxxx.dts
{
&kd_camera_hw1 {
pinctrl-names = "default", "cam0_rst0", "cam0_rst1", "cam0_pnd0", "cam0_pnd1",
"cam1_rst0", "cam1_rst1", "cam1_pnd0", "cam1_pnd1",
"cam_ldo0_0", "cam_ldo0_1";
pinctrl-0 = <&camera_pins_default>;
pinctrl-1 = <&camera_pins_cam0_rst0>;
pinctrl-2 = <&camera_pins_cam0_rst1>;
pinctrl-3 = <&camera_pins_cam0_pnd0>;
pinctrl-4 = <&camera_pins_cam0_pnd1>;
pinctrl-5 = <&camera_pins_cam1_rst0>;
pinctrl-6 = <&camera_pins_cam1_rst1>;
pinctrl-7 = <&camera_pins_cam1_pnd0>;
pinctrl-8 = <&camera_pins_cam1_pnd1>;
pinctrl-9 = <&camera_pins_cam_ldo0_0>;
pinctrl-10 = <&camera_pins_cam_ldo0_1>;
status = "okay";
};
}
MTK Camera驱动 kernel 中的部分 大致分为两层,核心层和设备层。
核心层又分为两小部分:
核心逻辑 :
kernel/drivers/misc/mediatek/imgsensor/src/mt6735/kd_sensorlist.c //与HAL层通信交互
kernel/drivers/misc/mediatek/imgsensor/src/mt6735/kd_sensorlist.h
kernel/drivers/misc/mediatek/imgsensor/inc/kd_imgsensor_define.h
设备上电 :
kernel/drivers/misc/mediatek/imgsensor/src/mt6735/camera_hw/kd_camera_hw.c //抽象出来的上电操作
设备层:sensor 驱动,寄存器操作
如:kernel/drivers/misc/mediatek/imgsensor/src/mt6735/camera_project/xxx/gc2023_mipi_raw/gc2023mipi_Sensor.c
关键数据结构之间的关系:
kernel-3.18/drivers/misc/mediatek/imgsensor/inc/kd_imgsensor_define.h 中定义了
struct MULTI_SENSOR_FUNCTION_STRUCT2: 用于保存系统中的Sensor的操作方法,如 open 等等
struct SENSOR_FUNCTION_STRUCT : 用于保存系统中的Sensor的操作方法,如 open 等等
struct ACDK_KD_SENSOR_INIT_FUNCTION_STRU : 用于保存系统中Sensor 的 Name、ID、Init()信息
问题:SENSOR_FUNCTION_STRUCT 和 MULTI_SENSOR_FUNCTION_STRUCT2 是一样的,为什么要重复定义呢?
答案:
MULTI_SENSOR_FUNCTION_STRUCT2 主要用于 核心层 kd_sensorlist.c中,kd_sensorlist.c中同样封装了一个新的 MULTI_SENSOR_FUNCTION_STRUCT2,用于保存系统中的Sensor的操作方法,如 open。只是这些操作是核心层的操作,是整个系统的所有Camera 共用的,在这里面可以打开底层各个设备的 SENSOR_FUNCTION_STRUC操作方法集合。SENSOR_FUNCTION_STRUCT 主要用于 设备层,设备层用SENSOR_FUNCTION_STRUCT封装操作自己的方法,供上层调用,这里指的上层就是 核心层。
kd_sensorlist.c : MULTI_SENSOR_FUNCTION_STRUCT2.open
调用
gc2023mipi_Sensor.c : SENSOR_FUNCTION_STRUCT sensor_func.open
kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6735/kd_sensorlist.h 中定义了
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] =
{
...
#if defined(GC2023_MIPI_YUV)
{GC2023MIPI_SENSOR_ID, SENSOR_DRVNAME_GC2023_MIPI_YUV,GC2023MIPISensorInit},
#endif
...
}
ACDK_KD_SENSOR_INIT_FUNCTION_STRUC定义于 kd_imgsensor_define.h。用于保存 Sensor ID Name Init函数 等信息。这里的定义的结构体数组包含了系统所有的Camera的 名称 ID 初始化函数的集合是系统 camera 信息表。如 : {GC2023MIPI_SENSOR_ID, SENSOR_DRVNAME_GC2023_MIPI_YUV,GC2023MIPISensorInit},该数组元素的第一个项表示ID,第二项表示名称,第三项表示初始化函数。
总结:
系统首先是发送 IOCTL: KDIMGSENSORIOC_X_SET_DRIVER。这里面主要的工作是 定义一个 ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT指针 然后调用 kdGetSensorInitFuncList()获取 kd_sensorlist.h中
定义的 kdSensorList[]系统 camera 信息表,接着便利该表,根据SensorID 绑定 核心层的SENSOR_FUNCTION_STRUCT *g_pInvokeSensorFunc 与 设备层的 SENSOR_FUNCTION_STRUCT sensor_func,这样就可以直接操作设备层的SENSOR_FUNCTION_STRUCT中的方法了。
然后发送 IOCTL: KDIMGSENSORIOC_T_OPEN 等一些列 IOCTL(),此时可以直接操作设备层中的方法了
我们主要分析 KDIMGSENSORIOC_T_OPEN和 KDIMGSENSORIOC_X_SET_DRIVER两个ioctl:
–
KDIMGSENSORIOC_X_SET_DRIVER 流程:
1 Hal层发送 ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER, &sensorIdx);
2 Kernel 接受 KDIMGSENSORIOC_X_SET_DRIVER指令,调用 kdSetDriver((unsigned int *)pBuff)
3
3.1 在本地创建 ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT *pSensorList = NULL;
说明:结构体 ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT 定义在 kernel-3.18/drivers/misc/mediatek/imgsensor/inc/kd_imgsensor_define.h中,用于保存Camera的 ID、Name、Init函数 等信息
该结构体于 kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6735/kd_sensorlist.h 创建 ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1]
结构体数组,理解为系统Camera信息表,用于保存整个系统的 Camera 的 ID、Name、Init函数 等信息。
3.2 kdGetSensorInitFuncList(&pSensorList) :
说明:获得 dSensorList[] 数组首地址,将 pSensorList指针 指向 src/kd_sensorlist.h里面 ,获取 kd_sensorlist.h中定义的系统Camera信息表。
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] 变量的首地址。即获取初始化列表地址
3.3 g_bEnableDriver[i] = FALSE;
说明:先将 g_bEnableDriver[i]设置为 false
3.4 g_invokeSocketIdx[i] = (CAMERA_DUAL_CAMERA_SENSOR_ENUM)((pDrvIndex[i] & KDIMGSENSOR_DUAL_MASK_MSB) >> KDIMGSENSOR_DUAL_SHIFT);
说明:保存 camera的sensorId
3.5 if (NULL == pSensorList[drvIdx[i]].SensorInit)
说明:判断模块驱动的init函数是否为NULL
3.6 pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]);
说明:传递 &g_pInvokeSensorFunc[i] 为参数,其中还是传递的地址,这就将g_pInvokeSensorFunc的首地址指向了模块驱动函数中的UINT32 GC2023MIPISensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc)这个函数
调用模块驱动中的init函数,将 g_pInvokeSensorFunc[sensor]指针指向 sensor模组的 SENSOR_FUNCTION_STRUCT。即绑定 sensor模组的 SENSOR_FUNCTION_STRUCT。
3.7 g_bEnableDriver[i] = TRUE;
说明:将 g_bEnableDrive[i] 设置为TRUE,表示与该g_bEnableDriver[i]对应的 sensor 可用。
KDIMGSENSORIOC_T_OPEN 流程:
1 Hal层发送 ioctl(m_fdSensor, KDIMGSENSORIOC_T_OPEN, &sensorIdx);
2 Kernel 接受 KDIMGSENSORIOC_X_SET_DRIVER指令,调用 adopt_CAMERA_HW_Open()
3 adopt_CAMERA_HW_Open()中
3.1 if (g_pSensorFunc)
说明:判断我们 imagesensor 操作函数指针是否为NULL,如果为NULL,报错,因为我们就是靠这个操作函数集合去操作imagesensor 的
3.2 err = g_pSensorFunc->SensorOpen();
说明:会调用到 kd_MultiSensorFunc 里面的 kd_MultiSensorOpen 函数
4 MUINT32 kd_MultiSensorOpen(void)中
4.1 if (g_bEnableDriver[i] && g_pInvokeSensorFunc[i])
说明:
4.1.1 g_bEnableDriver g_pInvokeSensorFunc[i] 这两个变量都为true时,就对sensor进行上电,然后就通过ret =g_pInvokeSensorFunc[i]->SensorOpen()进入到了模块sensor驱动中的open函数。
4.1.2 这里可以看出hal调用ioctl命令时不可能先走 KDIMGSENSORIOC_T_OPEN 这个命令,因为此时 g_pInvokeSensorFunc 为 NULL,还没有绑定到模组的 SENSOR_FUNCTION_STRUCT sensor_func。
所以这里代码无法执行,由后面的代码可以看到,ioctl先走的cmd命令是 KDIMGSENSORIOC_X_SET_DRIVER,在 KDIMGSENSORIOC_X_SET_DRIVER里面对 g_pInvokeSensorFunc进行初始化。
4.1.3 于上电跟掉电函数 kdCISModulePowerOn,在 kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6735/camera_project/xxxx/camera_hw/kd_camera_hw.c文件中,其实上电跟掉电时序就是
配置一些GPIO口,然后在把camera的三路电压按dateshell配置一下上掉电的时间。
4.2 ret = kdCISModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM)g_invokeSocketIdx[i], (char *)g_invokeSensorNameStr[i], true, CAMERA_HW_DRVNAME1);
说明:上电
4.3 ret = g_pInvokeSensorFunc[i]->SensorOpen();
说明:调用到模块驱动中的open函数,g_pInvokeSensorFunc[i]保存的值为模块驱动中的static SENSOR_FUNCTION_STRUCT sensor_func这个结构体的指针(地址)
分析代码如下:罗列了主要的代码和数据结构。
kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6735/kd_sensorlist.c
/*
MULTI_SENSOR_FUNCTION_STRUCT2 和 SENSOR_FUNCTION_STRUCT一样,只不过为了把驱动抽象出来,核心层用MULTI_SENSOR_FUNCTION_STRUCT2。模组驱动层用MULTI_SENSOR_FUNCTION_STRUCT,
上电时会将这两个结构体绑定
*/
MULTI_SENSOR_FUNCTION_STRUCT2 kd_MultiSensorFunc = {
kd_MultiSensorOpen,
kd_MultiSensorGetInfo,
kd_MultiSensorGetResolution,
kd_MultiSensorFeatureControl,
kd_MultiSensorControl,
kd_MultiSensorClose
};
extern MULTI_SENSOR_FUNCTION_STRUCT2 kd_MultiSensorFunc;//imagesensor 操作函数集合
static MULTI_SENSOR_FUNCTION_STRUCT2 *g_pSensorFunc = &kd_MultiSensorFunc;//imagesensor 操作函数指针
/*
1 g_bEnableDriver 定义为一个bool型的变量
2 g_pInvokeSensorFunc 地址跟模块驱动中的 static SENSOR_FUNCTION_STRUCT sensor_func 这个地址指向是相同的,他是作为一个参数传递来被调用的.
3 这两个变量都为true时,就对sensor进行上电,然后就通过ret =g_pInvokeSensorFunc[i]->SensorOpen()进入到了模块sensor驱动中的open函数。
至于上电跟掉电函数 kdCISModulePowerOn,在 kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6735/camera_project/xxxx/camera_hw/kd_camera_hw.c文件中,其实上电跟掉电时序就是
配置一些GPIO口,然后在把camera的三路电压按dateshell配置一下上掉电的时间。
*/
BOOL g_bEnableDriver[KDIMGSENSOR_MAX_INVOKE_DRIVERS] = {FALSE, FALSE};
SENSOR_FUNCTION_STRUCT *g_pInvokeSensorFunc[KDIMGSENSOR_MAX_INVOKE_DRIVERS] = {NULL, NULL};
CAMERA_DUAL_CAMERA_SENSOR_ENUM g_invokeSocketIdx[KDIMGSENSOR_MAX_INVOKE_DRIVERS] = {DUAL_CAMERA_NONE_SENSOR, DUAL_CAMERA_NONE_SENSOR};
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--) {
/*
1 g_bEnableDriver g_pInvokeSensorFunc[i] 这两个变量都为true时,就对sensor进行上电,然后就通过ret =g_pInvokeSensorFunc[i]->SensorOpen()进入到了模块sensor驱动中的open函数。
2 于上电跟掉电函数 kdCISModulePowerOn,在 kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6735/camera_project/xxxx/camera_hw/kd_camera_hw.c文件中,其实上电跟掉电时序就是
配置一些GPIO口,然后在把camera的三路电压按dateshell配置一下上掉电的时间。
3.这里可以看出hal调用ioctl命令时不可能先走 KDIMGSENSORIOC_T_OPEN 这个命令,因为此时 g_pInvokeSensorFunc 为 NULL,还没有绑定到模组的 SENSOR_FUNCTION_STRUCT sensor_func。
所以这里代码无法执行,由后面的代码可以看到,ioctl先走的cmd命令是 KDIMGSENSORIOC_X_SET_DRIVER,在 KDIMGSENSORIOC_X_SET_DRIVER里面对 g_pInvokeSensorFunc进行初始化。
*/
if (g_bEnableDriver[i] && g_pInvokeSensorFunc[i]) {
if (0 != (g_CurrentSensorIdx & g_invokeSocketIdx[i])) {
#ifndef CONFIG_FPGA_EARLY_PORTING
/*上电*/
ret = kdCISModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM)g_invokeSocketIdx[i], (char *)g_invokeSensorNameStr[i], true, CAMERA_HW_DRVNAME1);
#endif
/* wait for power stable 等待电源稳定*/
mDELAY(10);
//调用到模块驱动中的open函数,g_pInvokeSensorFunc[i]保存的值为模块驱动中的static SENSOR_FUNCTION_STRUCT sensor_func这个结构体的指针(地址)
ret = g_pInvokeSensorFunc[i]->SensorOpen();
if (ERROR_NONE != ret) {
#ifndef CONFIG_FPGA_EARLY_PORTING
/*掉电*/
kdCISModulePowerOn((CAMERA_DUAL_CAMERA_SENSOR_ENUM)g_invokeSocketIdx[i], (char *)g_invokeSensorNameStr[i], false, CAMERA_HW_DRVNAME1);
#endif
PK_ERR("SensorOpen");
return ret;
}
}
}
}
KD_MULTI_FUNCTION_EXIT();
return ERROR_NONE;
}
static inline int adopt_CAMERA_HW_Open(void)
{
UINT32 err = 0;
/*
1.判断我们 imagesensor 操作函数指针是否为NULL,如果为NULL,报错,因为我们就是靠这个操作函数集合去操作imagesensor 的
*/
if (g_pSensorFunc) {
err = g_pSensorFunc->SensorOpen();// 会调用到 kd_MultiSensorFunc 里面的 kd_MultiSensorOpen 函数
}
}
UINT32 kdGetSensorInitFuncList(ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT **ppSensorList)
{
/* 获取 kdSensorList[] 数组首地址 kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6735/kd_sensorlist.h
如:
UINT32 GC2023MIPISensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc);
...
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] = {
...
#if defined(GC2023_MIPI_YUV)
{GC2023MIPI_SENSOR_ID, SENSOR_DRVNAME_GC2023_MIPI_YUV,GC2023MIPISensorInit},
...
}
*/
/*
kdSensorList在kd_sensorlist.h文件里面,就是保存 cameraId,cameraNmae,模块驱动人口函数的结构体
*/
*ppSensorList = &kdSensorList[0];
return 0;
}
int kdSetDriver(unsigned int *pDrvIndex)
{
/* ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT *pSensorList 保存 Sensor的 ID Name Init函数信息 */
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT *pSensorList = NULL;
u32 drvIdx[KDIMGSENSOR_MAX_INVOKE_DRIVERS] = {0, 0};
u32 i;
/* Camera information */
gDrvIndex = pDrvIndex[KDIMGSENSOR_INVOKE_DRIVER_0];
/*
首先获得dSensorList[]数组首地址,将 pSensorList指针 指向 src/kd_sensorlist.h里面
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] 变量的首地址。即获取初始化列表地址
*/
if (0 != kdGetSensorInitFuncList(&pSensorList)) {
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_bEnableDriver[i] = FALSE;
// 保存camera的sensorId
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 (MAX_NUM_OF_SUPPORT_SENSOR > drvIdx[i]) {
/*
判断模块驱动的init函数是否为NULL
*/
if (NULL == pSensorList[drvIdx[i]].SensorInit) {
PK_ERR("ERROR:kdSetDriver()\n");
return -EIO;
}
/*
传递 &g_pInvokeSensorFunc[i] 为参数,其中还是传递的地址,这就将g_pInvokeSensorFunc的首地址指向了模块驱动函数中的UINT32 GC2023MIPISensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc)这个函数
调用模块驱动中的init函数,将 g_pInvokeSensorFunc[sensor]指针指向 sensor模组的 SENSOR_FUNCTION_STRUCT。即绑定 sensor模组的 SENSOR_FUNCTION_STRUCT。
*/
pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]);
/*
将 g_bEnableDrive[i] 设置为TRUE,表示与该g_bEnableDriver[i]对应的 sensor 可用。
*/
g_bEnableDriver[i] = TRUE;
/* 获取Sensor Name */
memcpy((char *)g_invokeSensorNameStr[i], (char *)pSensorList[drvIdx[i]].drvname, sizeof(pSensorList[drvIdx[i]].drvname));
}
}
return 0;
}
int kdSetCurrentSensorIdx(unsigned int idx)
{
g_CurrentSensorIdx = idx;
return 0;
}
static long CAMERA_HW_Ioctl(struct file *a_pstFile,unsigned int a_u4Command,unsigned long a_u4Param)
{
switch (a_u4Command) {
//open
case KDIMGSENSORIOC_T_OPEN:
i4RetValue = adopt_CAMERA_HW_Open();
break;
case KDIMGSENSORIOC_X_SET_DRIVER:
i4RetValue = kdSetDriver((unsigned int *)pBuff);
break;
case KDIMGSENSORIOC_X_SET_CURRENT_SENSOR:
i4RetValue = kdSetCurrentSensorIdx(*pIdx);
break;
}
static long CAMERA_HW_Ioctl_Compat(struct file *filp, unsigned int cmd, unsigned long arg)
{
case KDIMGSENSORIOC_T_OPEN://开
case KDIMGSENSORIOC_T_CLOSE:
case KDIMGSENSORIOC_T_CHECK_IS_ALIVE:
case KDIMGSENSORIOC_X_SET_DRIVER:
case KDIMGSENSORIOC_X_GET_SOCKET_POS:
case KDIMGSENSORIOC_X_SET_I2CBUS:
case KDIMGSENSORIOC_X_RELEASE_I2C_TRIGGER_LOCK:
case KDIMGSENSORIOC_X_SET_SHUTTER_GAIN_WAIT_DONE:
case KDIMGSENSORIOC_X_SET_MCLK_PLL:
case KDIMGSENSORIOC_X_SET_CURRENT_SENSOR:
case KDIMGSENSORIOC_X_SET_GPIO:
case KDIMGSENSORIOC_X_GET_ISP_CLK:
return filp->f_op->unlocked_ioctl(filp, cmd, arg);
default:
return -ENOIOCTLCMD;
}
}
//主摄像头字符设备 fops
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
};
//副摄像头字符设备 fops
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
};
kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6735/kd_sensorlist.h
...
UINT32 GC2023MIPISensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc);
...
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] =
{
...
#if defined(GC2023_MIPI_YUV)
{GC2023MIPI_SENSOR_ID, SENSOR_DRVNAME_GC2023_MIPI_YUV,GC2023MIPISensorInit},
#endif
...
}
...
kernel-3.18/drivers/misc/mediatek/imgsensor/inc/kd_imgsensor_define.h
typedef struct {
MUINT32(*SensorOpen)(void);
MUINT32(*SensorGetInfo)(MUINT32 *pScenarioId[2], MSDK_SENSOR_INFO_STRUCT * pSensorInfo[2], MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData[2]);
MUINT32(*SensorGetResolution)(MSDK_SENSOR_RESOLUTION_INFO_STRUCT * pSensorResolution[2]);
MUINT32(*SensorFeatureControl)(CAMERA_DUAL_CAMERA_SENSOR_ENUM InvokeCamera, MSDK_SENSOR_FEATURE_ENUM FeatureId, MUINT8 *pFeaturePara, MUINT32 *pFeatureParaLen);
MUINT32(*SensorControl)(CAMERA_DUAL_CAMERA_SENSOR_ENUM InvokeCamera, MSDK_SCENARIO_ID_ENUM ScenarioId, MSDK_SENSOR_EXPOSURE_WINDOW_STRUCT *pImageWindow, MSDK_SENSOR_CONFIG_STRUCT *pSensorConfigData);
MUINT32(*SensorClose)(void);
} MULTI_SENSOR_FUNCTION_STRUCT2, *PMULTI_SENSOR_FUNCTION_STRUCT2;
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;
#endif
} SENSOR_FUNCTION_STRUCT, *PSENSOR_FUNCTION_STRUCT;
//保存 Sensor ID Name Init函数 等信息
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;
kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6735/camera_hw/kd_camera_hw.c
int kdCISModulePowerOn(CAMERA_DUAL_CAMERA_SENSOR_ENUM SensorIdx, char *currSensorName, bool On, char *mode_name)
{
u32 pinSetIdx = 0;/* default main sensor */
...
...
if (DUAL_CAMERA_MAIN_SENSOR == SensorIdx)
pinSetIdx = 0;//主摄像头(后摄像头)
else if (DUAL_CAMERA_SUB_SENSOR == SensorIdx)
pinSetIdx = 1;//副摄像头(前摄像头)
else if (DUAL_CAMERA_MAIN_2_SENSOR == SensorIdx)
pinSetIdx = 2;
//通过DriverName来区分SensorIC ...
如: currSensorName && (0 == strcmp(SENSOR_DRVNAME_IMX258_MIPI_RAW, currSensorName)
//上电操作 ...
}
kernel-3.18/drivers/misc/mediatek/imgsensor/src/mt6735/camera_project/xxxx/gc2023_mipi_raw/gc2023mipi_Sensor.c
static SENSOR_FUNCTION_STRUCT sensor_func = {
open,
get_info,
get_resolution,
feature_control,
control,
close
};
//将 GC2023驱动指针 赋值给 static SENSOR_FUNCTION_STRUCT sensor_func。同理就是后面在通用驱动中可以直接凭借pfun指针调用sensorlist中的驱动中的各个功能函数
UINT32 GC2023MIPISensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc)
{
/* To Do : Check Sensor status here */
if (pfFunc!=NULL)
*pfFunc=&sensor_func;
return ERROR_NONE;
} /* GC2023MIPI_RAW_SensorInit */