前面提到注册一个字符设备时,attach上file_operation添加到system;然而file_operations 是为上层调用底层提供的接口;即HAL层就是通过调用file_operations中提供的接口,继而调用驱动进行对硬件的操作。
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
};
一般而言上层先先打开接口open,因此先看一下open函数的实现。整个函数就是对g_CamDrvOpenCnt变量进行了一个原子读的过程,没有进行别的操作,如下所示:
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;
}
static int CAMERA_HW_Release(struct inode *a_pstInode, struct file *a_pstFile)
{
atomic_dec(&g_CamDrvOpenCnt);
return 0;
}
此接口函数也是对g_CamDrvOpenCnt变量进行了一个原子读的过程,没有进行别的操作。
ioctl主要是接收上层传下来的一些命令,是android上层跟底层通讯的一种重要的方法。此处先说明一下:compat_ioctl被使用在用户空间为32位模式,而内核运行在64位模式时。这时候,需要将64位转成32位。关于unlocked_ioctl和compat_ioctl执行的顺序
对于ioctl操作,优先执行f_op->unlocked_ioctl,如果没有unlocked_ioctl,那么执行f_op->ioctl。为此再看看.unlocked_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) {
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;
}
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;
}
camera模块主要就是通过ioctl接口,通过发送不同的cmd命令来与底层进行通信。
->imgsensor_drv.cpp
MINT32
ImgSensorDrv::init(MINT32 sensorIdx)
{
UCHAR cBuf[64];
MINT32 ret = SENSOR_NO_ERROR;
MUINT16 pFeaturePara16[2];
MUINT32 FeaturePara32;
MUINT32 FeatureParaLen;
//MUINT32 sensorDrvInfo[KDIMGSENSOR_MAX_INVOKE_DRIVERS] = {0,0};
IMAGE_SENSOR_TYPE sensorType_prioriy = IMAGE_SENSOR_TYPE_UNKNOWN;
ACDK_SENSOR_RESOLUTION_INFO_STRUCT *pSensorResInfo[2];
SENSOR_DEV_ENUM sensorDevId;
if ( 0 == sensorIdx ) {
LOG_ERR("invalid sensorIdx[0x%08x] \n",sensorIdx);
return SENSOR_INVALID_PARA;
}
//select driver
if ( ( DUAL_CAMERA_MAIN_SENSOR|DUAL_CAMERA_MAIN_2_SENSOR ) == sensorIdx ) {
//N3D mode
SELECT_PRIORITY_DRIVER(main,N3D_PRIORITY_DRIVER);
}
else {
//2D mode
SELECT_PRIORITY_DRIVER(main,N2D_PRIORITY_DRIVER);
//SELECT_PRIORITY_DRIVER(main2,N2D_PRIORITY_DRIVER);
SELECT_PRIORITY_DRIVER(sub,N2D_PRIORITY_DRIVER);
}
//配置为前摄 或者后摄
IMGSNESOR_FILL_SET_DRIVER_INFO(sensorIdx);
//
LOG_MSG("[init] mUsers = %d\n", mUsers);
Mutex::Autolock lock(mLock);
if (mUsers == 0) {
if (m_fdSensor == -1) {
sprintf(cBuf,"/dev/%s",CAMERA_HW_DEVNAME);
m_fdSensor = ::open(cBuf, O_RDWR);
if (m_fdSensor < 0) {
LOG_ERR("[init]: error opening %s: %s \n", cBuf, strerror(errno));
return SENSOR_INVALID_DRIVER;
}
}
}
//设置sensor驱动
**ret = ioctl(m_fdSensor, KDIMGSENSORIOC_X_SET_DRIVER,sensorDrvInit);**
if (ret < 0) {
LOG_ERR("[init]: ERROR:KDCAMERAHWIOC_X_SET_DRIVER\n");
}
android_atomic_inc(&mUsers);
//init. resolution
pSensorResInfo[0] = &m_SenosrResInfo[0];
pSensorResInfo[1] = &m_SenosrResInfo[1];
ret = getResolution(pSensorResInfo);
if (ret < 0) {
LOG_ERR("[init]: Get Resolution error\n");
return SENSOR_UNKNOWN_ERROR;
}
if(SENSOR_MAIN & sensorIdx ) {
sensorDevId = SENSOR_MAIN;
//calculater g_LineTimeInus for exposure time convert.
FeatureParaLen = sizeof(MUINTPTR);
LOG_MSG("[featureControl]: SENSOR_FEATURE_GET_PIXEL_CLOCK_FREQ\n");
ret = featureControl((CAMERA_DUAL_CAMERA_SENSOR_ENUM)sensorDevId, SENSOR_FEATURE_GET_PIXEL_CLOCK_FREQ, (MUINT8*)&FeaturePara32,(MUINT32*)&FeatureParaLen);
if (ret < 0) {
LOG_ERR("[init]: SENSOR_FEATURE_GET_PIXEL_CLOCK_FREQ error\n");
return SENSOR_UNKNOWN_ERROR;
}
FeatureParaLen = sizeof(pFeaturePara16);
ret = featureControl((CAMERA_DUAL_CAMERA_SENSOR_ENUM)sensorDevId, SENSOR_FEATURE_GET_PERIOD, (MUINT8*)pFeaturePara16,(MUINT32*)&FeatureParaLen);
if (ret < 0) {
LOG_ERR("[init]: SENSOR_FEATURE_GET_PERIOD error\n");
return SENSOR_UNKNOWN_ERROR;
}
if (FeaturePara32 && FeaturePara32>1000) {
//in setting domain, use preview line time only
//sensor drv will convert to capture line time when setting to capture mode.
m_LineTimeInus[0] = (MUINT32)(((MUINT64)pFeaturePara16[0]*1000000 + ((FeaturePara32/1000)-1))/(FeaturePara32/1000)); // 1000 base , 33657 mean 33.657 us
} else {
LOG_ERR("[init]: SENSOR_FEATURE_GET_PIXEL_CLOCK_FREQ error = %d\n",FeaturePara32);
}
LOG_MSG("[init]: m_LineTimeInus[0] = %d\n", m_LineTimeInus[0] );
}
if((SENSOR_MAIN_2 & sensorIdx)|| (SENSOR_SUB & sensorIdx)) {
if(SENSOR_MAIN_2 & sensorIdx) {
sensorDevId = SENSOR_MAIN_2;
}
else {
sensorDevId = SENSOR_SUB;
}
//calculater g_LineTimeInus for exposure time convert.
FeatureParaLen = sizeof(MUINTPTR);
ret = featureControl((CAMERA_DUAL_CAMERA_SENSOR_ENUM)sensorDevId, SENSOR_FEATURE_GET_PIXEL_CLOCK_FREQ, (MUINT8*)&FeaturePara32,(MUINT32*)&FeatureParaLen);
if (ret < 0) {
LOG_ERR("[init]: SENSOR_FEATURE_GET_PIXEL_CLOCK_FREQ error\n");
return SENSOR_UNKNOWN_ERROR;
}
FeatureParaLen = sizeof(pFeaturePara16);
ret = featureControl((CAMERA_DUAL_CAMERA_SENSOR_ENUM)sensorDevId, SENSOR_FEATURE_GET_PERIOD, (MUINT8*)pFeaturePara16,(MUINT32*)&FeatureParaLen);
if (ret < 0) {
LOG_ERR("[init]: SENSOR_FEATURE_GET_PERIOD error\n");
return SENSOR_UNKNOWN_ERROR;
}
if (FeaturePara32 && FeaturePara32>1000) {
//in setting domain, use preview line time only
//sensor drv will convert to capture line time when setting to capture mode.
m_LineTimeInus[1] = (MUINT32)(((MUINT64)pFeaturePara16[0]*1000000 + ((FeaturePara32/1000)-1))/(FeaturePara32/1000)); // 1000 base , 33657 mean 33.657 us
} else {
LOG_ERR("[init]: SENSOR_FEATURE_GET_PIXEL_CLOCK_FREQ error = %d\n",FeaturePara32);
}
LOG_MSG("[init]: m_LineTimeInus[1] = %d\n", m_LineTimeInus[1] );
}
return SENSOR_NO_ERROR;
}
大致调用过程为:
ioctl(m_fdSensor,KDIMGSENSORIOC_X_SET_DRIVER,sensorDrvInit);->KDIMGSENSORIOC_X_SET_DRIVER->CAMERA_HW_Ioctl->copy_from_user->a_u4Command= KDIMGSENSORIOC_X_SET_DRIVER->kdSetDriver((unsigned int *)pBuff);
接下来分析一下kdSetDriver实现:
/*******************************************************************************
* kdSetDriver
********************************************************************************/
int kdSetDriver(unsigned int *pDrvIndex)
{
.........
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;
// 保存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 (DUAL_CAMERA_NONE_SENSOR == g_invokeSocketIdx[i]) {
continue;
}
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"); */
}
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) {
PK_ERR("ERROR:kdSetDriver()\n");
return -EIO;
}
// 调用sensor模块驱动中的init函数,例如HI843B_MIPI_RAW_SensorInit;
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;
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]\n", i, g_bEnableDriver[i], g_invokeSocketIdx[i], g_invokeSensorNameStr[i]);
}
}
return 0;
}
通过kdGetSensorInitFuncList获取sensor初始化列表,并把地址赋给pSensorList:
UINT32 kdGetSensorInitFuncList(ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT **ppSensorList)
{
if (NULL == ppSensorList) {
PK_ERR("[kdGetSensorInitFuncList]ERROR: NULL ppSensorList\n");
return 1;
}
*ppSensorList = &kdSensorList[0];
return 0;
} /* kdGetSensorInitFuncList() */
ACDK_KD_SENSOR_INIT_FUNCTION_STRUCT kdSensorList[MAX_NUM_OF_SUPPORT_SENSOR+1] =
{
..............
#if defined(HI843B_MIPI_RAW)
{HI843B_SENSOR_ID, SENSOR_DRVNAME_HI843B_MIPI_RAW,HI843B_MIPI_RAW_SensorInit},
#endif
/* ADD sensor driver before this line */
{0,{0},NULL}, //end of list
};
获取到sensorlist后,回到kdSetDriver函数中继续往下分析pSensorList[drvIdx[i]].SensorInit(&g_pInvokeSensorFunc[i]);根据ID获取到对应的摄像头厂家,并调用其sensor驱动初始化函数,此处以HI843B_MIPI_RAW_SensorInit为例:
UINT32 HI843B_MIPI_RAW_SensorInit(PSENSOR_FUNCTION_STRUCT *pfFunc)
{
/* To Do : Check Sensor status here */
if (pfFunc!=NULL)
*pfFunc=&sensor_func;
return ERROR_NONE;
} /* HI843B_MIPI_RAW_SensorInit */
该函数主要的作用是将sensor_func地址赋给结构体PSENSOR_FUNCTION_STRUCT 的变量pfFunc。而sensor_func其实是sensor驱动提供的接口,如下所示:
static SENSOR_FUNCTION_STRUCT sensor_func = {
open,//.SensorOpen= open
get_info,//.SensorGetInfo = get_info
get_resolution,//.SensorGetResolution = get_resolution
feature_control,//.SensorFeatureControl = feature_control
control,//.SensorControl = control
close//.SensorClose = close
};
相信大家看到这个结构体一定不陌生了,因为它类似前面提到的file_operations。后面就可以通过此结构体提供的接口操作sensor驱动了。
本文分析HAL层怎么通过接口函数ioctl,一步步地进行sensor驱动设置过程。
如果你觉得好,随手点赞,也是对笔者的肯定,谢谢!