续。。。
3、video_device
struct video_device{
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
#endif
const struct v4l2_file_operations*fops;
struct device dev; /* v4l device */
struct cdev *cdev; /* characterdevice */
struct device *parent; /* deviceparent */
struct v4l2_device *v4l2_dev; /*v4l2_device parent */
struct v4l2_ctrl_handler*ctrl_handler;
struct v4l2_prio_state *prio;
char name[32];
int vfl_type;
int minor;
u16 num;
unsigned long flags;
int index;
spinlock_t fh_lock; /* Lock forall v4l2_fhs */
struct list_head fh_list; /* List ofstruct v4l2_fh */
int debug; /* Activates debuglevel*/
v4l2_std_id tvnorms; /* Supported tvnorms */
v4l2_std_id current_norm; /* Currenttvnorm */
void (*release)(struct video_device*vdev);
const struct v4l2_ioctl_ops*ioctl_ops;
struct mutex *lock;
};
在/dev中实际的设备节点使用video_deice结构创建。该结构既可以被动态创建,也可以被嵌入到更大的结构当中:
动态创建:
struct video_device *vdev =video_device_alloc();
vdec->release =video_device_release;
嵌入到更大的结构当中:
Struct video_device *vdev =&my_vdev->vdev;
vdev->relase = my_vdev_release;
要完成这个结构的初始化,还需要设置以下的域:
.v4l2_dev 设置v4l2_device父设备
.name 设置唯一的描述名
.fops 设置v4l2_file_operations结构
.ioctl_ops 使用v4l2_ioctl_ops来简化ioctl的维护
.lock 如果想在驱动中进行全局锁定的话设置为NULL,否则初始化为一个 mutex_lock,这样就可以在unlocked_ioctl的操作之前和之后对操作内容进行保护
.prio 跟踪属性。用来实现VIDIOC_G/S_PRIORITY,如果设置为NULL,将使用v4l2_device中的v4l2_prio_state。
.parent NULL . 如果硬件中有多个PCI设备共享v4l2_device核心,那么就要设置父设备。
.flags 可选,设置V4L2_FL_USE_FH_PRIO,如果想让framework来处理VIDIOC_G/S_PRIORITYioctls的话。
如果要使用v4l2_ioctl_ops,那么就需要将.unlocked_ioctl设置为video_ioctl2,这样的话,就可以打通上层应用在使用ioctl操作/dev/videoX的时候和v4l2设备之间的信 息交换通道。
在某些应用场景下,还需要mask掉在v4l2_ioctl_ops中指定的功能,那么需要调用
void v4l2_disable_ioctl(structvideo_device *vdev, unsigned int cmd)来屏蔽对该cmd的调用。
v4l2_file_operations结构是一个file_operations的子集,主要的区别是inode参数不再使用了,因为从来没有用到过。
Ioctls和locking域:
V4L2核心提供了可选的锁定服务,主要体现在video_device结构当中的lock域,指向一个mutex,如果你初始化了这个域,那么它将被用在unlocked_ioctl中用来序列化所有的ioctl操作。
如果使用videobuf2框架来管理视频缓冲,那么还得在初始化一个video_device->queue->lock,并且这个锁会替代video_device->lock来序列化所有队列ioctl的操作。
队列ioctl的操作使用不同的锁有个优点,就是某些设备的操作需要很长的时间,而在此期间的其他非队列ioctl操作也可以进行。举个例子,有个场景就是既要设置camera的闪光灯亮,也要从videobuf当中读取数据的时候,我们就需要分开来锁定两个ioctl,以便两者能够基本上保持同步。
在videobuf2当中,需要实现wait_prepare和wait_finish回调函数来lock/unlock,如果想要使用queue->lock,最好是使用vb2_ops_wait_prepare/finish
video_device 的注册:
接下来,通过video_device_alloc()分配好一个video_device之后,就要把它注册到系统当中,这将会为你创建一个字符设备。
err = video_register_device(vdev,VFL_TYPE_GRABBER, -1);
if (err) {
video_device_release(vdev);
return err;
}
如果v4l2_device有一个非空的mdev,那么video_device实体也会自动注册媒体设备。
具体注册成什么类型的V4l2设备,要看type指定为什么:
VFL_TYPE_GRABBER video的输入输出设备,体现为/dev/videoX
VFL_TYPE_VBI vertical blank data体现为/dev/vbiX
VFL_TYPE_RADIO radio tuners设备/dev/radioX
第三个参数是指定设备号,如果传入-1的话,就是让v4l2框架自动选择一个可用的node号,如果指定了非-1的参数,并且这个参数代表的设备已经被注册了,那么系统也会自动选择下一个可用的设备号,但是会给出警告。
一旦一个video_device被创建,那么框架也会同时为你创建一些设备属性节点,在/sys/class/video4linux/videoX/下你会看到诸如name,index等的属性节点。
如果注册失败了,那么就要调用video_device_release()来释放所有申请的资源。
video_device的清理工作:
当要移除视频设备节点的时候,就要调用video_unregister_device(vdev)将之前注册到系统中的信息销毁掉。
一些videodevice的帮助函数
file/video_device的private_data,我们可以通过以下这些函数来设置和获取驱动的private_data:
void * video_get_drvdata(structvideo_device *vdev)
void video_set_drvdata(structvideo_device *vdev, void * data)
struct video_device*video_devdata(struct file *file)会返回一个属于file的video_device结构体指针。
Void * video_drvdata(struct file*file)首先使用video_devdata获取video_device,然后通过video_get_drvdata获取private_data.
设备节点名:
video_device_node_name(structvideo_device *vdev)返回一个字符串。
到这儿,就基本上了解了v4l2的控制框架。接下来的博文中,会介绍videobuf及videobuf2的相关知识。