Linux下v4l2-camera子系统之soc_camera_device(二)
平台:君正x1000
linux kernel: 3.10
camera sensor:ov7725
上节认识了camera子系统的大概框架结构及主要相关结构,现在看看系统中是怎么注册camera_device。
struct i2c_board_info jz_v4l2_camera_devs[] __initdata = {
{
I2C_BOARD_INFO("ov7725", 0x21),
},
};
static struct soc_camera_link iclink_front = {
.bus_id = 0,
.board_info = &jz_v4l2_camera_devs[FRONT_CAMERA_INDEX],
.i2c_adapter_id = 0,
.power = camera_sensor_power,
.reset = camera_sensor_reset,
};
struct platform_device mensa_front_camera_sensor = {
.name = "soc-camera-pdrv",
.id = -1,
.dev = {
.platform_data = &iclink_front,
},
};
platform_device_register(&mensa_front_camera_sensor);
soc_camera_device也是做为平台设备注册进内核,其下.dev.platform_data 指向soc_camera_link,而soc_camera_link管理sensor。
plarform驱动设备驱动模型就不说了,下面看驱动怎么做的。
camera_device驱动
/* \drivers\media\platform\soc_camera\soc_camera.c */
static struct platform_driver __refdata soc_camera_pdrv = {
.probe = soc_camera_pdrv_probe,
.remove = soc_camera_pdrv_remove,
.driver = {
.name = "soc-camera-pdrv",
.owner = THIS_MODULE,
},
};
module_platform_driver(soc_camera_pdrv);
/* \drivers\media\platform\soc_camera\soc_camera.c */
static int soc_camera_pdrv_probe(struct platform_device *pdev)
{
struct soc_camera_desc *sdesc = pdev->dev.platform_data; (1)
struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc;
struct soc_camera_device *icd;
int ret;
icd = devm_kzalloc(&pdev->dev, sizeof(*icd), GFP_KERNEL); (2)
icd->iface = sdesc->host_desc.bus_id; /* struct soc_camera_link成员bus_id */
icd->sdesc = sdesc;
icd->pdev = &pdev->dev;
platform_set_drvdata(pdev, icd);
icd->user_width = DEFAULT_WIDTH;
icd->user_height = DEFAULT_HEIGHT;
return soc_camera_device_register(icd);
/* 将代表着camera sensor的对象soc_camera_device放到了全局链表devices中 */
}
上述代码(1)的soc_camera_desc就是上节说的和soc_camera_link 字节对齐的结构,pdev->dev.platform_data 就是平台设备中soc_camera_link 。(2)就是申请soc_camera_device内存,下面就是对它的初始化,最后注册。
static int soc_camera_device_register(struct soc_camera_device *icd)
{
struct soc_camera_device *ix;
int num = -1, i;
for (i = 0; i < 256 && num < 0; i++) {
num = i;
/* Check if this index is available on this interface */
list_for_each_entry(ix, &devices, list) {
if (ix->iface == icd->iface && ix->devnum == i) {
num = -1;
break;
}
}
}
if (num < 0)
return -ENOMEM;
icd->devnum = num;
icd->use_count = 0;
icd->host_priv = NULL;
list_add_tail(&icd->list, &devices);
return 0;
}
该函数核心是for循环查找icd->iface的主机是否已添加到全局链表&devices,如果没有,则找出空闲的设备号devnum,并添加到全局链表。