camera驱动
Posted 四季帆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了camera驱动相关的知识,希望对你有一定的参考价值。
V4L2框架:
用户空间-->v4l2-->master-->slave
1.slave端(摄像头数据处理芯片)
ak8859_init
-->i2c_add_driver(&ak8859_i2c_driver);
-->ak8859_probe
-->v4l2_int_device_register(&ak8859_int_device) #slave和master的注册都使用这个函数
-->v4l2_int_device_try_attach_all()
-->m->u.master->attach(s)
详解如下:
drivers/media/platform/mxc/capture/ak8859.c
static int ak8859_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
ak8859_int_device.priv = &ak8859_data; /*用户open的时候会通过cam->sensor->priv来访问sensor*/
ret = v4l2_int_device_register(&ak8859_int_device); /*注册ak8859_data--->*/
}
drivers/media/v4l2-core/v4l2-int-device.c
int v4l2_int_device_register(struct v4l2_int_device *d)
{
if (d->type == v4l2_int_type_slave) /*按照序号存储,加快访问速度*/
sort(d->u.slave->ioctls, d->u.slave->num_ioctls,sizeof(struct v4l2_int_ioctl_desc),&ioctl_sort_cmp, NULL);
list_add(&d->head, &int_list); /*无论是slave还是master都会添加到int_list中*/
v4l2_int_device_try_attach_all(); //都会做匹配动作--->
}
void v4l2_int_device_try_attach_all(void)
{
struct v4l2_int_device *m, *s;
list_for_each_entry(m, &int_list, head) {/*对int_list中每个master*/
if (m->type != v4l2_int_type_master)
continue;
list_for_each_entry(s, &int_list, head) {/*对int_list中每个slave*/
if (s->type != v4l2_int_type_slave)
continue;
if (s->u.slave->master)/*slave中master已经被赋值说明已经连接起来*/
continue;
s->u.slave->master = m;/*说明slave找到了master*/
if (m->u.master->attach(s)) { /*执行master的匹配函数*/
s->u.slave->master = NULL;
module_put(m->module);
continue;
}
}
}
}
2.master端(SOC内置摄像头控制器)
camera_init()
-->mxc_v4l2_probe
-->init_camera_struct(cam, pdev)
-->cam->self->u.master = &mxc_v4l2_master
-->v4l2_int_device_register(cam->self) #slave和master的注册都使用这个函数
-->v4l2_int_device_try_attach_all()
-->m->u.master->attach(s)
-->video_register_device(cam-
>video_dev, VFL_TYPE_GRABBER, video_nr)
详解如下:
drivers/media/platform/mxc/capture/mxc_v4l2_capture.c
static __init int camera_init(void)
{
err = platform_driver_register(&mxc_v4l2_driver); /*平台注册V4L2驱动*/
}
static int mxc_v4l2_probe(struct platform_device *pdev)
{
init_camera_struct(cam, pdev); /*初始化cam_data结构--->*/
/*在很多函数中,形参只是v4l2_int_device类型的self,相要获得更外层的cam_data结构体的话,就可以从self->priv中获取*/
cam->self->priv = cam; /*注意这里的cam赋值,后面match函数中会用到*/
v4l2_int_device_register(cam->self); /*注册在init_camera_struct函数中填充的self结构体--->*/
video_register_device(cam->video_dev, VFL_TYPE_GRABBER, video_nr) /*注册video设备-->*/
}
static int init_camera_struct(cam_data *cam, struct platform_device *pdev)
{
*(cam->video_dev) = mxc_v4l_template; /* 注意这里的赋值,包含了ops操作,ops为用户空间提供了操作接口 */
/*在视频采集过程中,如果一个buffer填充满的话,会产生一个中断信号,中断处理函数中最终会调用到这个函数来处理中断*/
cam->enc_callback = camera_callback; /*设置callback*/
cam->self->u.master = &mxc_v4l2_master; /*slave或者master注册时会调用master的匹配函数*/
}
static void camera_callback(u32 mask, void *dev)
{ #将填满的buffer从working_q链表删除,挂接到done_q链表,然后唤醒等待队列上指定的进程
/* Added to the done queue */
list_del(cam->working_q.next);
list_add_tail(&done_frame->queue, &cam->done_q);
/* Wake up the queue */
cam->enc_counter++;
wake_up_interruptible(&cam->enc_queue); //唤醒等待队列上的进程cam->enc_queue
}
kernel/include/media/v4l2-dev.h
static inline int __must_check video_register_device(struct video_device *vdev,
int type, int nr)
{
return __video_register_device(vdev, type, nr, 1, vdev->fops->owner);
}
drivers/media/v4l2-core/v4l2-dev.c
int __video_register_device(struct video_device *vdev, int type, int nr,int warn_if_nr_in_use, struct module *owner)
{
/* Part 1: 检查设备类型,我们这里是VFL_TYPE_GRABBER*/
switch (type) {
case VFL_TYPE_GRABBER:
name_base = "video";
break;
······
case VFL_TYPE_RADIO:
name_base = "radio";
break;
}
/* Part 2:查找空闲的minor*/
/* Part 3:初始化字符设备*/
vdev->cdev->ops = &v4l2_fops; /*用户打开设备后的file ops!!!!!*/
ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
/* Part 4:注册设备到sysfs*/
/* Part 5:注册一个media设备实体*/
/* Part 6:激活设备,设备可以使用 */
}
以上是关于camera驱动的主要内容,如果未能解决你的问题,请参考以下文章
android摄像头(camera)之 v4l2的c测试代码