2.2 Structure of a V4L driver
device instances
|
+-sub-device instances
|
\-V4L2 device nodes
|
\-filehandle instances
2.4 Video device
video device 用于抽象系统注册的 v4l2 /dev 设备节点,以便用户空间可以进行交互.
v4l2-dev.h
:
struct video_device {
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
struct media_intf_devnode *intf_devnode;
struct media_pipeline pipe;
#endif
const struct v4l2_file_operations *fops;
u32 device_caps;
/* sysfs */
struct device dev;
struct cdev *cdev;
struct v4l2_device *v4l2_dev;
struct device *dev_parent;
struct v4l2_ctrl_handler *ctrl_handler;
struct vb2_queue *queue;
struct v4l2_prio_state *prio;
/* device info */
char name[64];
enum vfl_devnode_type vfl_type;
enum vfl_devnode_direction vfl_dir;
int minor;
u16 num;
unsigned long flags;
int index;
/* V4L2 file handles */
spinlock_t fh_lock;
struct list_head fh_list;
int dev_debug;
v4l2_std_id tvnorms;
/* callbacks */
void (*release)(struct video_device *vdev);
const struct v4l2_ioctl_ops *ioctl_ops;
DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
struct mutex *lock;
};
entity:
fops: v4l2 file operations.
device_caps: 设备支持的能力, 在 videodev2.h 中定义.
dev:
cdev:
v4l2_dev: 上层的 v4l2_device 设备.
dev_parent: 上层的 device 设备, 如果为 NULL 在 video_register_device 中会指向 v4l2_dev->dev
ctrl_handler: 如果为 NULL, 在 video_register_device 中会指向 v4l2_dev->ctrl_handler.
queue: 和该 device node 相关的 vb2_queue 结构体.
prio: 如果为 NULL, 在 video_register_device 中会指向 v4l2_dev->prio .
name: video device name.
vfl_type: enum vfl_devnode_type, v4l2 设备的类型, 在 video_register_device 中传入.
vfl_dir: enum vfl_devnode_direction, 表示 v4l2 设备的方向, RX(capture device)/TX(output device)/M2M(mem2mem, codec).
minor: device node 次设备号.
num: video device node 的编号, /dev/videoX 的 X, 在 video_register_device 最后一个参数传入.
flags: enum v4l2_video_device_flags, 一些辅助 flags.
index: 一个物理设备对应多个 v4l2 设备节点, 分别的 index. 每次调用 video_register_device()都会增加 1.
fh_lock: 用来 lock v4l2_fhs.
fh_list: v4l2_fh 链表.
dev_debug: userspace 通过 sysfs 设置的 debug level. /sys/class/video4linux/video0/dev_debug
tvnorms: 支持的电视标准 PAL/NTSC/SECAM.
release: 释放函数. 在 video_device 没有 subclass 的情况下可以使用 video_device_release().
如果 video_device subclass 或者是 static 分配的, 不需要释放内存使用 video_device_release_empty().
ioctl_ops: v4l2 file ioctl operations.
valid_ioctls: 支持的 ioctrl bitmap.
lock: 用来串行化 v4l2 device 的 unlock_ioctl.
其中一些 fields 需要我们手动去初始化, 包括 fops, device_caps, v4l2_dev, queue, name, vfl_dir, ioctl_ops, lock.
如果需要和 media framework 联合使用, 需要初始化 entity 成员, 并调用 media_entity_pads_init().
如果 v4l2 driver 使用 v4l2_ioctl_ops, 则 v4l2_file_operations 中的.unlock_ioctl 回调需要使用 video_ioctl2.
2.4.2 Video device registration
err = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
if (err) {
video_device_release(vdev); /* or kfree(my_vdev); */
return err;
}
不同的设备类型会生成不同的设备节点:
2.4.3 Video device debugging
往/sys/class/video4linux/<devX>/dev_debug
写入数值:
2.4.4 Video device cleanup
video_unregister_device()
别忘记 clean up media_entity:
media_entity_cleanup (&vdev->entity)
2.4.5 helper functions
static inline void *video_get_drvdata(struct video_device *vdev)
static inline void video_set_drvdata(struct video_device *vdev, void *data)
struct video_device *video_devdata(struct file *file)
2.4.6 functions and data structures
一些重要的 APIs:
int video_register_device(struct video_device *vdev,
enum vfl_devnode_type type, int nr);
void video_unregister_device(struct video_device *vdev);
struct video_device *video_device_alloc(void);
2.5 V4L2 device
v4l2 用来抽象最顶层的 v4l2 设备, 包含一系列子设备.
通过v4l2_device_register (dev, v4l2_dev)
注册, 在注册前需要调用 dev_set_drvdata()
设置 dev->drier_data 为包含 v4l2_device 的 driver-specific 结构体.
通过v4l2_device_unregister()
注销, 如果是 hotpluggable 设备, 在此之前还需要调用v4l2_device_disconnect()
v4l2-device.h
:
struct v4l2_device {
struct device *dev;
struct media_device *mdev;
struct list_head subdevs;
spinlock_t lock;
char name[36];
void (*notify)(struct v4l2_subdev *sd,
unsigned int notification, void *arg);
struct v4l2_ctrl_handler *ctrl_handler;
struct v4l2_prio_state prio;
struct kref ref;
void (*release)(struct v4l2_device *v4l2_dev);
};
dev: 底层 device 设备.
mdev: 指向 media device.
subdevs: 子设备列表.
name: v4l2 设备名称.
notify: 子设备调用的通知回调函数.
ctrl_handler: v4l2 控制句柄.
prio: 设备的优先级状态.
ref: 引用计数.
release: 释放回调函数.
APIs:
v4l2-device.h
void v4l2_device_get(struct v4l2_device *v4l2_dev);
int v4l2_device_put(struct v4l2_device *v4l2_dev);
int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
atomic_t *instance);
void v4l2_device_disconnect(struct v4l2_device *v4l2_dev);
void v4l2_device_unregister(struct v4l2_device *v4l2_dev);
#define v4l2_device_register_subdev(v4l2_dev, sd) \
__v4l2_device_register_subdev(v4l2_dev, sd, THIS_MODULE)
int __v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
struct v4l2_subdev *sd,
struct module *module);
void v4l2_device_unregister_subdev(struct v4l2_subdev *sd);
int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev);
int v4l2_device_register_ro_subdev_nodes(struct v4l2_device *v4l2_dev);
void v4l2_subdev_notify(struct v4l2_subdev *sd, unsigned int notification, void *arg);
bool v4l2_device_supports_requests(struct v4l2_device *v4l2_dev);