2.5 V4L2 device

v4l2 用来抽象最顶层的 v4l2 设备,包含一系列子设备。

通过v4l2_device_register(dev, v4l2_dev)注册。

还需要设置好 v4l2->mdev 为 media_device 结构体。

在调用 v4l2_device_register 之前如果没有设置 v4l2_device->name,那么会自动分配。

还可以提供一个 notify 回调,给 subdev 向 v4l2_device 发送 event,events 定义在v4l2-subdev.h,官方文档里写只能使用 v4l2-subdev.h 中定义的 event,但看到有的 driver 自定义了一些 event。

通过v4l2_device_unregister()注销,如果是 hotpluggable 设备,在此之前还需要调用v4l2_device_disconnect()

v4l2-device.h:

Data Structure and APIs

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);

// 注册 subdev
#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);
// 注册所有 subdev 的设备节点
int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev);
// 注册 subdev 为 read only 节点
int v4l2_device_register_ro_subdev_nodes(struct v4l2_device *v4l2_dev);
// subdev 通知 v4l2_device
void v4l2_subdev_notify(struct v4l2_subdev *sd, unsigned int notification, void *arg);
bool v4l2_device_supports_requests(struct v4l2_device *v4l2_dev);
// 遍历所有 subdev
#define v4l2_device_for_each_subdev(sd, v4l2_dev);
// 调用所有 subdev 的某个回调函数
#define v4l2_device_call_all(v4l2_dev, grpid, o, f, args...);
// 调用所有 subdev 的某个回调函数,直到返回错误
#define v4l2_device_call_until_err(v4l2_dev, grpid, o, f, args...);

v4l2_device_get/put():

v4l2_device_set_name(): 大部分直接设置 v4l2_device->name,没使用这个函数