v4l2-event:自定义事件调试

V4L2的event事件机制是内核空间与用户空间的通信的一种机制,一种实用的机制,可以用于一些驱动状态出现变化,通知应用层对变化做出动作的场景,例如RK3588平台的HDMIIN,分辨率变化、拔插变化都是通过事件的形式上报给应用的。本文主要介绍一下如何在驱动添加私有的V4L2事件。

目录

(1)V4L2事件结构体

(2)camera sensor驱动添加私有事件

①定义私有V4L2事件的类型

②v4l2_subdev_core_ops订阅事件接口实现

③上报事件

(3)应用层实现

①订阅事件

②DQueue事件

(4)模拟调试


(1)V4L2事件结构体

struct v4l2_event {
	__u32				type;
	union {
		struct v4l2_event_vsync		vsync;
		struct v4l2_event_ctrl		ctrl;
		struct v4l2_event_frame_sync	frame_sync;
		struct v4l2_event_src_change	src_change;
		struct v4l2_event_motion_det	motion_det;
		__u8				data[64];
	} u;
	__u32				pending;
	__u32				sequence;
#ifdef __KERNEL__
	struct __kernel_timespec	timestamp;
#else
	struct timespec			timestamp;
#endif
	__u32				id;
	__u32				reserved[8];
};

type:事件类型的结构体,V4L2原生定义的一些事件类型包括如下,V4L2_EVENT_PRIVATE_START可用于扩展自定义的事件类型。

#define V4L2_EVENT_ALL				0
#define V4L2_EVENT_VSYNC			1
#define V4L2_EVENT_EOS				2
#define V4L2_EVENT_CTRL				3
#define V4L2_EVENT_FRAME_SYNC			4
#define V4L2_EVENT_SOURCE_CHANGE		5
#define V4L2_EVENT_MOTION_DET			6
#define V4L2_EVENT_PRIVATE_START		0x08000000

data:用户自定义的消息实体/内容。在添加私有事件的时候,可以定义data的数据,来向应用层传递相关信息。

sequence:消息的序列号(不是index)。和struct v4l2_fh的成员sequence相同。

timestamp:消息发送的时间戳。

pending:记录消息队列中尚未处理的消息数量。

id:命令ID。

目前实际应用发现,使用私有事件的时候必须指定type和data,可以传递到用户层,其他的参数由V4L2自行填充。

(2)camera sensor驱动添加私有事件

下面介绍一下在camera sensor的驱动如何添加一个私有的事件。

①定义私有V4L2事件的类型

基于V4L2_EVENT_PRIVATE_START进行拓展事件定义。

/* Private v4l2 event */
#define V4L2_EVENT_I2C_LOST \
	(V4L2_EVENT_PRIVATE_START + 1)

②v4l2_subdev_core_ops订阅事件接口实现

实现事件订阅的回调接口。

+static int imx415_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+				    struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_I2C_LOST:
+		return v4l2_event_subscribe(fh, sub, 0, NULL);
+	default:
+		return -EINVAL;
+	}
+}
+
 static const struct v4l2_subdev_core_ops imx415_core_ops = {
 	.s_power = imx415_s_power,
+	.subscribe_event = imx415_subscribe_event,
 	.ioctl = imx415_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl32 = imx415_compat_ioctl32,

③上报事件

在需要上报事件的位置将事件queue到事件队列中,由应用层去dqueue事件。

将事件queue到队列的时候,需要指定事件的类型和驱动需要向用户空间传递的data数据。

static void imx415_event_report(struct v4l2_subdev *sd, int err)
{
	struct v4l2_event event = {
		.type = V4L2_EVENT_I2C_LOST,
		.u.data[0] = err,
	};

	if (sd->devnode)
		v4l2_event_queue(sd->devnode, &event);
}

(3)应用层实现

应用层需要对驱动生成的设备节点订阅相关时间,然后将事件队列的事件dq出来进行处理。具体实现如下:

①订阅事件

打开对应的设备节点,订阅相关事件。

        fd = open(dev, O_RDWR, 0);
        if (fd < 0) {
                printf("open dev:%s fail\n", dev);
                return -1;
        }

        ret = subscribe_event(fd, V4L2_EVENT_I2C_LOST);

......

int subscribe_event(int fd, int event)
{
        int ret = 0;
        struct v4l2_event_subscription sub;
        if (fd < 0) {
                printf("fd is err\n");
                return -1;
        }
        sub.type = event;
        sub.id = 0;
        ret = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
        if (ret < 0) {
                printf("VIDIOC_SUBSCRIBE_EVENT fail\n");
                return -1;
        }
        return 0;
}

②DQueue事件

类似V4L2 buffer的控制,用户层需要将事件DQ出来进行出来,根据事件类型和传递的data数据,进行后级的应用处理。

        while (1) {
                printf("VIDIOC_DQEVENT ready %d\n", ret);
                ret = ioctl(fd, VIDIOC_DQEVENT, &event);
                if (ret) {
                        printf("VIDIOC_DQEVENT err %d\n", ret);
                        goto end;
                }
                printf("VIDIOC_DQEVENT event %x, data: %d\n", event.type, event.u.data[0]);
  
        }

(4)模拟调试

可以使用V4L2-ctl的工具调试,如下命令可以查询对应私有事件的变化,如果驱动有报事件

 v4l2-ctl -d /dev/v4l-subdev2 --poll-for-event=0x08000001

268.648750: event 0, pending 0: unknown private event (08000001)
280.348455: event 1, pending 0: unknown private event (08000001)

也可以根据上述的应用实现例子来监测事件。

v4l-event /dev/v4l-subdev2

VIDIOC_DQEVENT ready 0
VIDIOC_DQEVENT event 8000001, data: 0
VIDIOC_DQEVENT ready 0
VIDIOC_DQEVENT event 8000001, data: 251
VIDIOC_DQEVENT ready 0

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人生苦短,菜的抠脚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值