本文共 4075 字,大约阅读时间需要 13 分钟。
用户空间-->v4l2-->master-->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; } } }}
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:激活设备,设备可以使用 */}
转载地址:http://ghuen.baihongyu.com/