一、Camera软件架构
主要包含三个部分的介绍:
1)Android Camera 架构:Android系统原生架构简要介绍.
2)Mediatek Android Camera架构: 简要介绍Mediatek平台在Android系统基础上Camera 的架构.
3)Camera data path: 介绍在平台端Camera的数据流.
1.下图为Android Camera 架构
Camera根据Android 架构从上至下可分为
1)Applications: 最上层的应用,编译后生成Camera APK;
2)Application Framework: 主要为Applications提供API;
3)JNI: 使Application Framework和Libraries可交互;
4)Libraries: 包括Camera Framework和Camera Service(camera service和camera client);
5)HAL: 硬件抽象层, 用来链接driver和 Camera Service;
6)Kernel: image sensor driver的实作.其中2)~4)的部分基本为Android原生的架构和code,Mediatek会有一些拓展,而HAL和Kernel层为Mediatek主要实作的部分,Camera APK是Mediatek基于Android 原生Camera APK修改的应用.
2.下图为MT6589/82/72/92/88平台基于Android架构上,Camera从application到kernel层详细的架构.
1)蓝色部分主要由Java实现(偏向应用层)、黄色为JNI实现(C++,衔接Java层和Native层), 绿色由C++实现(通常称为Native层),而枣红色为C实现(Kernel 层).
2) HAL libraries为Mediatek在HAL层的实现,主要分Camera HAL和Camera Core两大部分.Camera HAL衔接Camera Service并响应它的需求,实现各个feature的scenario; 而Camera Core提供平台一些通用的数据流控制接口.
3.最后这部分为Camera的数据流简要介绍
说明:
1) TG(Timing Generate):从sensor获取数据,并送给ISP处理.
2) Platform Data Processor: 包括平台在后端对图像数据进行resize、rotate、flip、format convert等处理.它可以同时有两个buffer输出.
总结:
Kernel部分:
- image sensor driver,负责具体型号的sensor的id检测,上电,以及在preview、capture、初始化、3A等等功能设定时的寄存器配置;
- isp driver,通过DMA将sensor数据流上传;
hal部分:
- imageio,主要负责数据buffer上传的pipe
- drv,包含imgsensor和isp的hal层控制;
- feature io,包含各种3A等性能配置;
二、camera调用过程
imgsensor起到承上启下的作用,在系统起来时会创建整个camera驱动运行的环境,其中主要的文件和函数如下框图所示,先设备挂载时会调用注册platform设备platform_driver_register,在匹配成功后会调用probe函数进行初始相关的设备:
一、平台驱动注册
文件路径:
kernel-$(KernelVersion)/drivers/misc/mediatek/imgsensor/src/common/v_$(Version)/imgsensor.c
kernel-$(KernelVersion)/drivers/misc/mediatek/imgsensor/src/common/v_$(Version)/imgsensor_proc.c
kernel-$(KernelVersion)/drivers/base/platform.c
kernel-$(KernelVersion)/include/linux/of_device.h
注:v_$(Version)版本信息根据平台确认,上级目录src/Makefile中有定义。
camera 驱动先是注册 platform 平台驱动,然后注册Camera字符设备,创建class类,再通过 I2c 注册前后摄注册字符设备,封装底层方法 imgsensor_ioctl,上层访问底层驱动时候先是使用 setdriver 获取具体IC的驱动的入口,然后使用 checkisalive 对 sensorlist 中的 IC 进行上电,上电完成就通过 I2C 读取设备 ID ,到此为止,上层应用与底层驱动挂接完成,紧接着就是预览和拍照,具体 IC 驱动的实现了。这里介绍v1_1版本,mt6771平台。
module_init
设备加载 module_init加载模块,注册platform总线驱动
#ifdef CONFIG_OF
static const struct of_device_id gimgsensor_of_device_id[] = {
{.compatible = "mediatek,imgsensor",},
{}
};
#endif
static struct platform_driver gimgsensor_platform_driver = {
.probe = imgsensor_probe,
.remove = imgsensor_remove,
.suspend = imgsensor_suspend,
.resume = imgsensor_resume,
.driver = {
.name = "image_sensor",
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = gimgsensor_of_device_id,
#endif
}
};
/*与设备树节点中 compatible = "mediatek,imgsensor" 属进行匹配,匹配成功后调用 imgsensor_probe函数*/
static int imgsensor_probe(struct platform_device *pplatform_device)
{
struct IMGSENSOR *pimgsensor = &gimgsensor;
struct IMGSENSOR_HW *phw = &pimgsensor->hw;
struct device *pdevice;
/* Register char driver */
if (alloc_chrdev_region(&pimgsensor->dev_no, 0, 1,
IMGSENSOR_DEV_NAME)) {
PK_DBG("[CAMERA SENSOR] Allocate device no failed\n");
return -EAGAIN;
}
/* Allocate driver */
pimgsensor->pcdev = cdev_alloc();
if (pimgsensor->pcdev == NULL) {
unregister_chrdev_region(pimgsensor->dev_no, 1);
PK_DBG("[CAMERA SENSOR] Allocate mem for kobject failed\n");
return -ENOMEM;
}
/* Attatch file operation. */
cdev_init(pimgsensor->pcdev, &gimgsensor_file_operations);
pimgsensor->pcdev->owner = THIS_MODULE;
/* Add to system */
if (cdev_add(pimgsensor->pcdev, pimgsensor->dev_no, 1)) {
PK_DBG("Attatch file operation failed\n");
unregister_chrdev_region(pimgsensor->dev_no, 1);
return -EAGAIN;
}
pimgsensor->pclass = class_create(THIS_MODULE, "sensordrv");
if (IS_ERR(pimgsensor->pclass)) {
int ret = PTR_ERR(pimgsensor->pclass);
PK_DBG("Unable to create class, err = %d\n", ret);
return ret;
}
pdevice = device_create(pimgsensor->pclass, NULL,
pimgsensor->dev_no, NULL, IMGSENSOR_DEV_NAME);
pdevice->of_node =
of_find_compatible_node(NULL, NULL, "mediatek,imgsensor");
if (!pdevice->of_node) {
PK_PR_ERR("Get cust camera node failed!\n");
return -ENODEV;
}
phw->common.pplatform_device = pplatform_device;
/*以上注册字符设备,注册IO Ctrl操作函数*/
imgsensor_hw_init(phw); //获取电压配置,电压初始化
imgsensor_i2c_create(); //创建i2c设备
imgsensor_proc_init();
imgsensor_init_sensor_list();
#ifdef IMGSENSOR_OC_ENABLE
imgsensor_oc_init(); //用于启用或禁用相机图像传感器的Occlusion(遮挡)功能
#endif
return 0;
}
imgsensor_hw_init解析
imgsensor_hw_init函数调用,主要进行电压初始化,获取电压配置信息。
enum IMGSENSOR_RETURN imgsensor_hw_init(struct IMGSENSOR_HW *phw)
{
struct IMGSENSOR_HW_SENSOR_POWER *psensor_pwr;
struct IMGSENSOR_HW_CFG *pcust_pwr_cfg;
struct IMGSENSOR_HW_CUSTOM_POWER_INFO *ppwr_info;
unsigned int i, j, len;
char str_prop_name[LENGTH_FOR_SNPRINTF];
const char *pin_hw_id_name;
struct device_node *of_node
= of_find_compatible_node(NULL, NULL, "mediatek,imgsensor");
/*根据compatible信息获取设备节点*/
mutex_init(&phw->common.pinctrl_mutex);
/* update the imgsensor_custom_cfg by dts 依次调用REGULATOR/GPIO/MCLK的init接口*/
for (i = 0; i < IMGSENSOR_SENSOR_IDX_MAX_NUM; i++) {
PK_DBG("IMGSENSOR_SENSOR_IDX: %d\n", i);
pcust_pwr_cfg = imgsensor_custom_config;//根据imgsensor_custom_config数组,获取所有相机供电方式如:GPIO,PMIC,具体配置于imgsensor_cfg_table.c文件中
while (pcust_pwr_cfg->sensor_idx != i &&
pcust_pwr_cfg->sensor_idx != IMGSENSOR_SENSOR_IDX_NONE)
pcust_pwr_cfg++;
if (pcust_pwr_cfg->sensor_idx == IMGSENSOR_SENSOR_IDX_NONE)
continue; //遍历整个数组
ppwr_info = pcust_pwr_cfg->pwr_info;
while (ppwr_info->pin != IMGSENSOR_HW_PIN_NONE) {
memset(str_prop_name, 0, sizeof(str_prop_name));
snprintf(str_prop_name,
sizeof(str_prop_name),
"cam%d_pin_%s",
i,
imgsensor_hw_pin_names[ppwr_info->pin]);//拼接str_prop_name字符串
if (of_property_read_string( //读取节点中str_prop_name属性
of_node, str_prop_name,
&pin_hw_id_name) == 0) {
for (j = 0; j < IMGSENSOR_HW_ID_MAX_NUM; j++) {
len = strlen(imgsensor_hw_id_names[j]);
if (strncmp(pin_hw_id_name, imgsensor_hw_id_names[j], len)
== 0) {
PK_DBG(
"imgsensor_hw_cfg hw_pin:%s, id name:%s, id:%d\n",
str_prop_name, pin_hw_id_name, j);
ppwr_info->id = j;
break;
}
}
}
ppwr_info++;
}
}
/* update the imgsensor_custom_cfg by dts END 以上代码主要获取dts文件中对相机供电设置,并进行配置*/
for (i = 0; i < IMGSENSOR_HW_ID_MAX_NUM; i++) { //依次调用REGULATOR/GPIO/MCLK的init接口
if (hw_open[i] != NULL)
(hw_open[i]) (&phw->pdev[i]); //函数hw_open获取对应结构体
if (phw->pdev[i]->init != NULL)
(phw->pdev[i]->init)(
phw->pdev[i]->pinstance, &phw->common); //执行 gpio,regulator中init函数
}
for (i = 0; i < IMGSENSOR_SENSOR_IDX_MAX_NUM; i++) {
psensor_pwr = &phw->sensor_pwr[i];
pcust_pwr_cfg = imgsensor_custom_config; //根据imgsensor_custom_config数组,获取所有相机供电方式如:GPIO,PMIC,具体配置于imgsensor_cfg_table.c文件中
while (pcust_pwr_cfg->sensor_idx != i &&
pcust_pwr_cfg->sensor_idx != IMGSENSOR_SENSOR_IDX_NONE)
pcust_pwr_cfg++;
if (pcust_pwr_cfg->sensor_idx == IMGSENSOR_SENSOR_IDX_NONE)
continue;
//获取该摄像头的引脚配置
ppwr_info = pcust_pwr_cfg->pwr_info;
while (ppwr_info->pin != IMGSENSOR_HW_PIN_NONE) {
for (j = 0;
j < IMGSENSOR_HW_ID_MAX_NUM &&
ppwr_info->id != phw->pdev[j]->id;
j++) {
}
//保存对应ID的擦操作方法
psensor_pwr->id[ppwr_info->pin] = j;
ppwr_info++;
}
}
//从设备树中获取指定摄像头名字,如:cam3_enable_sensor = "gc2375hmain3_mipi_raw";
for (i = 0; i < IMGSENSOR_SENSOR_IDX_MAX_NUM; i++) {
memset(str_prop_name, 0, sizeof(str_prop_name));
snprintf(str_prop_name,
sizeof(str_prop_name),
"cam%d_%s",
i,
"enable_sensor");
if (of_property_read_string(
of_node, str_prop_name,
&phw->enable_sensor_by_index[i]) < 0) {
PK_DBG("Property cust-sensor not defined\n");
phw->enable_sensor_by_index[i] = NULL;
}
}
return IMGSENSOR_RETURN_SUCCESS;
}
imgsensor_i2c_create解析
imgsensor_i2c_create用于添加I2C设备
enum IMGSENSOR_RETURN imgsensor_i2c_create(void)
{
int i;
for (i = 0; i < IMGSENSOR_I2C_DEV_MAX_NUM; i++)
i2c_add_driver(&gi2c_driver[i]);
return IMGSENSOR_RETURN_SUCCESS;
}
描述i2c_driver配置信息。
#define IMGSENSOR_I2C_DRV_NAME_0 "kd_camera_hw"
#define IMGSENSOR_I2C_DRV_NAME_1 "kd_camera_hw_bus2"
#define IMGSENSOR_I2C_DRV_NAME_2 "kd_camera_hw_bus3"
#define IMGSENSOR_I2C_DRV_NAME_3 "kd_camera_hw_bus4"
#define IMGSENSOR_I2C_DRV_NAME_4 "kd_camera_hw_bus5"
#define IMGSENSOR_I2C_DRV_NAME_5 "kd_camera_hw_bus6"
#define IMGSENSOR_I2C_DRV_NAME_6 "kd_camera_hw_bus7"
#define IMGSENSOR_I2C_DRV_NAME_7 "kd_camera_hw_bus8"
#define IMGSENSOR_I2C_DRV_NAME_8 "kd_camera_hw_trigger"
#define IMGSENSOR_I2C_OF_DRV_NAME_0 "mediatek,camera_main"
#define IMGSENSOR_I2C_OF_DRV_NAME_1 "mediatek,camera_sub"
#define IMGSENSOR_I2C_OF_DRV_NAME_2 "mediatek,camera_main_two"
#define IMGSENSOR_I2C_OF_DRV_NAME_3 "mediatek,camera_sub_two"
#define IMGSENSOR_I2C_OF_DRV_NAME_4 "mediatek,camera_main_three"
#define IMGSENSOR_I2C_OF_DRV_NAME_5 "mediatek,camera_sub_three"
#define IMGSENSOR_I2C_OF_DRV_NAME_6 "mediatek,camera_main_four"
#define IMGSENSOR_I2C_OF_DRV_NAME_7 "mediatek,camera_sub_four"
enum IMGSENSOR_I2C_DEV {
IMGSENSOR_I2C_DEV_0,
IMGSENSOR_I2C_DEV_1,
IMGSENSOR_I2C_DEV_2,
IMGSENSOR_I2C_DEV_3,
IMGSENSOR_I2C_DEV_4,
IMGSENSOR_I2C_DEV_5,
IMGSENSOR_I2C_DEV_6,
IMGSENSOR_I2C_DEV_7,
IMGSENSOR_I2C_DEV_MAX_NUM,
};
/**************************************/
static const struct of_device_id gof_device_id_0[] = {
{.compatible = IMGSENSOR_I2C_OF_DRV_NAME_0,},
{}
};
static const struct of_device_id gof_device_id_1[] = {
{.compatible = IMGSENSOR_I2C_OF_DRV_NAME_1,},
{}
};
static const struct of_device_id gof_device_id_2[] = {
{.compatible = IMGSENSOR_I2C_OF_DRV_NAME_2,},
{}
};
/**************************************/
static struct i2c_driver gi2c_driver[IMGSENSOR_I2C_DEV_MAX_NUM] = {
{
.probe = imgsensor_i2c_probe_0,
.remove = imgsensor_i2c_remove,
.driver = {
.name = IMGSENSOR_I2C_DRV_NAME_0,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = gof_device_id_0,
#endif
},
.id_table = gi2c_dev_id,
},
{
.probe = imgsensor_i2c_probe_1,
.remove = imgsensor_i2c_remove,
.driver = {
.name = IMGSENSOR_I2C_DRV_NAME_1,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = gof_device_id_1,
#endif
},
.id_table = gi2c_dev_id,
},
{
.probe = imgsensor_i2c_probe_2,
.remove = imgsensor_i2c_remove,
.driver = {
.name = IMGSENSOR_I2C_DRV_NAME_2,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = gof_device_id_2,
#endif
},
.id_table = gi2c_dev_id,
}
设备树中的compatible信息于项目dws文件配置,dws经过编译(DrvGen.py脚本)后生成cust_*.h文件,路径:obj\PRELOADER_OBJ\inc;在Preloader和Lk的代码中,很多文件都会包含cust_i2c.h、cust_gpio_boot.h、cust_gpio_usage.h
在Kernel的代码中,每个工程的dts文件都会包含cust.dtsi,路径:obj\KERNEL_OBJ\arch\arm64\boot\dts\******
最终设备树compatible信息生成于out目录下的dts/mediatek中,例如:.tb8797p2_64_k419_wifi.dtb.dts.tmp
&i2c2 {
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <400000>;
mediatek,use-open-drain;
camera_main_mtk:camera_main@1a {
compatible = "mediatek,camera_main";
reg = <0x1a>;
status = "okay";
};
camera_main_eeprom_mtk:camera_main_eeprom@50 {
compatible = "mediatek,camera_main_eeprom";
reg = <0x50>;
status = "okay";
};
camera_main_af_mtk:camera_main_af@72 {
compatible = "mediatek,camera_main_af";
reg = <0x72>;
status = "okay";
};
};
compatible信息匹配成功后调用对对应的probe程序
static int imgsensor_i2c_probe_0(struct i2c_client *client,
const struct i2c_device_id *id)
{
gi2c.inst[IMGSENSOR_I2C_DEV_0].pi2c_client = client;
return 0;
}
imgsensor_proc_init解析
imgsensor_proc_init用于在proc/driver/下创建一些文件接口,cat proc/driver/camera_info,该文件可以看到摄像头硬件信息
enum IMGSENSOR_RETURN imgsensor_proc_init(void)
{
memset(mtk_ccm_name, 0, camera_info_size);
proc_create("driver/camsensor", 0000, NULL, &fcamera_proc_fops);
proc_create("driver/camsensor2", 0000, NULL, &fcamera_proc_fops2);
proc_create("driver/camsensor3", 0000, NULL, &fcamera_proc_fops3);
proc_create("driver/camsensor4", 0000, NULL, &fcamera_proc_fops4);
proc_create("driver/camsensor5", 0000, NULL, &fcamera_proc_fops5);
proc_create("driver/camsensor6", 0000, NULL, &fcamera_proc_fops6);
proc_create("driver/camsensor7", 0000, NULL, &fcamera_proc_fops7);
proc_create("driver/camsensor8", 0000, NULL, &fcamera_proc_fops8);
proc_create("driver/pdaf_type", 0000, NULL,
&fcamera_proc_fops_set_pdaf_type);
proc_create("driver/imgsensor_status_info", 0000, NULL,
&fcamera_proc_fops_status_info);
/* Camera information */
proc_create(PROC_CAMERA_INFO, 0000, NULL, &fcamera_proc_fops1);
return IMGSENSOR_RETURN_SUCCESS;
}
可获取camera名称、ID信息。每个摄像头的配置信息包括预览、捕获、视频、HSV和子采样的分辨率、延迟帧数、传感器类型、输出格式、驱动电流、mclk频率、mipi通道数以及PDAF支持和HDR支持等信息。
imgsensor_init_sensor_list解析
用于获取gimgsensor_sensor_list列表。获取都dts中cust-sensor属性,如果没有找到该属性,函数将直接将所有传感器添加到pimgsensor->psensor_list中。
static void imgsensor_init_sensor_list(void)
{
unsigned int i = 0;
int ret = 0;
struct IMGSENSOR *pimgsensor = &gimgsensor;
struct IMGSENSOR_SENSOR_LIST *psensor_list = gimgsensor_sensor_list;
const char *penable_sensor;
struct device_node *of_node
= of_find_compatible_node(NULL, NULL, "mediatek,imgsensor");
//获取dts中cust-sensor属性,
ret = of_property_read_string(of_node, "cust-sensor", &penable_sensor);
if (ret < 0) {
PK_DBG("Property cust-sensor not defined\n");
while (psensor_list->id && i < MAX_NUM_OF_SUPPORT_SENSOR) {
pimgsensor->psensor_list[i] = psensor_list;
i++;
psensor_list++;
}
} else {
PK_DBG("Customizedsensors: %s\n", penable_sensor);
while (psensor_list->id && i < MAX_NUM_OF_SUPPORT_SENSOR) {
if (strstr(penable_sensor, psensor_list->name)) {
pimgsensor->psensor_list[i] = psensor_list;
i++;
}
psensor_list++;
}
}
}
二、Android hal操作
CameraService是在开机时启动的,启动后进行searchSensor的操作,会search系统有多少camera,开机时的search操作,只进行camera支持数量的遍历,以及sensor ID的读取操作。
文件路径:vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1_1/HalSensorList.cpp
MUINT
HalSensorList::
searchSensors()
{
Mutex::Autolock _l(mEnumSensorMutex);
MY_LOGD("searchSensors");
return enumerateSensor_Locked();
}
文件路径:vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1_1/HalSensorList.enumList.cpp
MUINT
HalSensorList::
enumerateSensor_Locked()
{
int ret = 0;
NSFeature::SensorInfoBase* pSensorInfo ;
SensorDrv *const pSensorDrv = SensorDrv::get();
SeninfDrv *const pSeninfDrv = SeninfDrv::createInstance(); //获取SensorDrv和SeninfDrv实例
if(!pSeninfDrv) {
MY_LOGE("pSeninfDrv == NULL");
return 0;
}
//初始化SeninfDrv,配置ISP相关内容
if((ret = pSeninfDrv->init()) < 0) {
MY_LOGE("pSeninfDrv->init() fail");
return 0;
}
/*search sensor using 8mA driving current*/
pSeninfDrv->setAllMclkOnOff(ISP_DRIVING_8MA, TRUE); //设置所有时钟为8mA驱动电流
pSensorDrv->init(); //初始化SensorDrv
MUINT max_index_of_camera = IMGSENSOR_SENSOR_IDX_SUB;
#ifdef MTK_CAM_MAX_NUMBER_OF_CAMERA
max_index_of_camera = MTK_CAM_MAX_NUMBER_OF_CAMERA - 1;
#endif
MY_LOGD("impSearchSensor search to %d\n", max_index_of_camera); //遍历所有传感器所有
for (MUINT i = IMGSENSOR_SENSOR_IDX_MIN_NUM; i <= max_index_of_camera; i++) {
#ifdef MCLK_DRIVE_CURRENT_BY_PINCTRL
/*search sensor using 8mA driving current*/
MUINT32 current = ISP_DRIVING_8MA;
pSensorDrv->sendCommand((IMGSENSOR_SENSOR_IDX)i, CMD_SENSOR_SET_DRIVE_CURRENT, (MUINTPTR)¤t);
#endif //如果使用引脚控制设置驱动电流为8mA
//搜索所有传感器
if((ret = pSensorDrv->searchSensor((IMGSENSOR_SENSOR_IDX)i)) == SENSOR_NO_ERROR) {
//query sensorinfo 查询传感器信息
querySensorDrvInfo((IMGSENSOR_SENSOR_IDX)i);
//fill in metadata 填充元素数据
buildSensorMetadata((IMGSENSOR_SENSOR_IDX)i);
//获取传感器信息
pSensorInfo = pSensorDrv->getSensorInfo((IMGSENSOR_SENSOR_IDX)i);
if (pSensorInfo == nullptr) {
MY_LOGE("Error! null pSensorInfo\n");
return 0;
}
if (pSensorInfo->getDrvMacroName() == nullptr) { //检查传感器信息是否为空
MY_LOGE("Error! null pSensorInfo->getDrvMacroName\n");
return 0;
}
else {
addAndInitSensorEnumInfo_Locked(
(IMGSENSOR_SENSOR_IDX)i,
mapToSensorType(pSensorInfo->GetType()),
pSensorInfo->getDrvMacroName()); //传感器信息不为空,添加并初始化传感器枚举信息
}
}
}
//关闭所有时钟
pSeninfDrv->setAllMclkOnOff(0, FALSE);
//反向初始化seninfdrc、sensordrv
ret = pSeninfDrv->uninit();
if(ret < 0) {
MY_LOGE("pSeninfDrv->uninit() fail");
return 0;
}
pSeninfDrv->destroyInstance();
pSensorDrv->uninit();
//返回枚举传感器数量
return mEnumSensorList.size();
}
文件路径:vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1_1/imgsensor_drv.cpp
searchSensor()函数的主要功能是搜索并设置图像传感器驱动。它尝试设置一个指定的驱动程序,如果成功,则记录相应的信息;如果设置失败或者该驱动程序已经存在,则根据情况返回不同的错误代码。
MINT32
ImgSensorDrv::searchSensor()
{
MINT32 ret = 0;
//检查m_list.id值,为0表示已经处理过
if (m_list.id != 0) {
LOG_MSG("[searchSensor] Already processed");
return SENSOR_ALREADY_SEARCH;
}
LOG_MSG("searchSensor idx = %d", m_sensorIdx);
// 调用 featureControl函数获取 m_list
ret = featureControl(SENSOR_FEATURE_SET_DRIVER, (MUINT8 *)&m_list, sizeof(IMGSENSOR_SENSOR_LIST));
if (ret != 0)
LOG_MSG("Error! SENSOR_FEATURE_SET_DRIVER ret = %d", ret);
if(m_list.id == 0) {
LOG_WRN("Search fail");
m_list.id = 0xFFFFFFFF;
return SENSOR_INVALID_DRIVER;
} else {
LOG_MSG("found <%x/%s>", m_list.id, m_list.name);
getInfo();
return SENSOR_NO_ERROR;
}
}
featureControl函数
MINT32
ImgSensorDrv::featureControl(
ACDK_SENSOR_FEATURE_ENUM FeatureId,
MUINT8 *pFeaturePara,
MUINT32 featureParaLen
)
{
ACDK_SENSOR_FEATURECONTROL_STRUCT featureCtrl;
int ret = SENSOR_NO_ERROR;
if (FeatureId == SENSOR_FEATURE_BEGIN) {
LOG_MSG("[featureControl] Skip due to no FeatureId");
return SENSOR_NO_ERROR;
}
if (m_fd == -1) {
LOG_ERR("[sendCommand]m_fd fail, sendCommand must be called after init()!");
return SENSOR_UNKNOWN_ERROR;
}
if (pFeaturePara == NULL)
return SENSOR_INVALID_PARA;
featureCtrl.InvokeCamera = m_sensorIdx; //根据枚举,前摄还是后摄ID
featureCtrl.FeatureId = FeatureId; //打开还是关闭的ID
featureCtrl.pFeaturePara = pFeaturePara; //传递的参数
featureCtrl.pFeatureParaLen = &featureParaLen; //参数的长度
ret = ioctl(m_fd, KDIMGSENSORIOC_X_FEATURECONCTROL, &featureCtrl);//利用IOCTL调用到kernel中的imgsensor_ioctl函数
if (ret != 0) {
LOG_ERR("[featureControl] Err-ctrlCode (%s) ret = %d", strerror(errno), ret);
}
return ret;
}
三、imgsensor_ioctl
imgsensor_ioctl操作整体框架如下:
文件路径:kernel-$(KernelVersion)/drivers/misc/mediatek/imgsensor/src/common/v_$(Version)/imgsensor.c
static long imgsensor_ioctl(
struct file *a_pstFile,
unsigned int a_u4Command, unsigned long a_u4Param)
{
int i4RetValue = 0;
void *pBuff = NULL;
//判断传递的命令参数是否为空
if (_IOC_DIR(a_u4Command) != _IOC_NONE) {
pBuff = kmalloc(_IOC_SIZE(a_u4Command), GFP_KERNEL); //申请命令参数储存空间
if (pBuff == NULL) {
PK_DBG("[CAMERA SENSOR] ioctl allocate mem failed\n");
i4RetValue = -ENOMEM;
goto CAMERA_HW_Ioctl_EXIT;
}
memset(pBuff, 0x0, _IOC_SIZE(a_u4Command)); //将命令储存至空间
if (_IOC_WRITE & _IOC_DIR(a_u4Command)) { //判断命令是否可写
if (copy_from_user(pBuff, (void *)a_u4Param,
_IOC_SIZE(a_u4Command))) { //将命令从用户空间复制到内核
PK_DBG(
"[CAMERA SENSOR] ioctl copy from user failed\n");
i4RetValue = -EFAULT;
goto CAMERA_HW_Ioctl_EXIT;
}
}
} else {
i4RetValue = -EFAULT;
goto CAMERA_HW_Ioctl_EXIT;
}
switch (a_u4Command) {
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;
default:
PK_DBG("No such command %d\n", a_u4Command);
i4RetValue = -EPERM;
goto CAMERA_HW_Ioctl_EXIT;
break;
}
if ((_IOC_READ & _IOC_DIR(a_u4Command)) &&
copy_to_user((void __user *)a_u4Param, pBuff,
_IOC_SIZE(a_u4Command))) { //将数据复制到用户空间
PK_DBG("[CAMERA SENSOR] ioctl copy to user failed\n");
i4RetValue = -EFAULT;
goto CAMERA_HW_Ioctl_EXIT;
}
CAMERA_HW_Ioctl_EXIT:
if (pBuff != NULL) {
kfree(pBuff);
pBuff = NULL;
}
return i4RetValue;
}
adopt_CAMERA_HW_FeatureControl函数根据命令调用imgsensor_sensor_open函数,imgsensor_sensor_open函数调用imgsensor_hw_power函数进行上下电操作,imgsensor_hw_power调用imgsensor_hw_power_sequence函数进行具体的上下电操作,imgsensor_check_is_alive函数进行sensor ID读取。