sheldon_blogs

Android设备之间UVC Gadget bulk模式无法正常打开问题

平台:RK3588
Android版本:12
内核版本:Linux 5.10.66

问题: 通过usb gadget枚举uvc设备后,使用bulk传输,连接windows PC可用正常打开预览,连接到另外Android Host设备无法正常打开。如果使用isochronous方式传输则都正常。

分析:连接到PC(windows)上可以正常出图,但是连接到另外一个RK3588设备,可以正常识别到设备,也可以用v4l2-ctl读到正常配置信息,但是打开对应video节点取流时阻塞住了,从另一端RK3588(device)查看uvc gadget应用端 ioctl执行VIDIOC_STREAMON报错: UVC: Unable to start streaming No such device (19). 另外接了一个bulk传输的usb摄像头到rk3588上是正常的,说明问题出在uvc gadget device驱动。

既然报错在VIDIOC_STREAMON,则从驱动代码中对应方法入手排查:

kernel-5.10/drivers/usb/gadget/function/uvc_v4l2.c

static int
uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
{
        struct video_device *vdev = video_devdata(file);
        struct uvc_device *uvc = video_get_drvdata(vdev);
        struct uvc_video *video = &uvc->video;
        int ret;

        //通过打印知道在此处判断不是UVC_STATE_CONNECTED状态就直接返回错误
        if (uvc->state != UVC_STATE_CONNECTED)
            return -ENODEV;

        /* Enable UVC video. */
        ret = uvcg_video_enable(video, 1);
        if (ret < 0)
                return ret;

        /*
         * Alt settings in an interface are supported only
         * for ISOC endpoints as there are different alt-
         * settings for zero-bandwidth and full-bandwidth
         * cases, but the same is not true for BULK endpoints,
         * as they have a single alt-setting.
         *
         * For ISOC endpoints, Complete the alternate setting
         * selection setup phase now that userspace is ready
         * to provide video frames.
         */
        if (!usb_endpoint_xfer_bulk(video->ep->desc)) {
                uvc_function_setup_continue(uvc);
        }

        uvc->state = UVC_STATE_STREAMING;

        return 0;
}

在以上代码段加打印调试知道是此时stream on走到这里时 uvc->state 值已经是 UVC_STATE_STREAMING,直接返回 -EINVAL,而对比isoc传输stream on时是UVC_STATE_CONNECTED状态,然后通过连接不同host的log对比发现bulk模式连接 Android设备上的时候就会走了1次 uvc_function_set_alt,然后stream on时又会执行一次,  此时就已经把 uvc->state 改成了 UVC_STATE_STREAMING:

对应源码中就是在此处更改了uvc->state的值:

kernel-5.10/drivers/usb/gadget/function/f_uvc.c

以至于后面走到uvc_v4l2_streamon时就判断uvc->state != UVC_STATE_CONNECTED 直接  return -ENODEV。

解决方法:修改uvc_v4l2_streamon中针对bulk模式时的判断逻辑,在 uvc->state == UVC_STATE_DISCONNECTED 才 return -ENODEV。

--- a/kernel-5.10/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/kernel-5.10/drivers/usb/gadget/function/uvc_v4l2.c
@@ -200,8 +200,15 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        if (type != video->queue.queue.type)
                return -EINVAL;

-       if (uvc->state != UVC_STATE_CONNECTED)
-               return -ENODEV;
+       //sheldon add begin: for bulk mode
+       if (!usb_endpoint_xfer_bulk(video->ep->desc)) {
+               if (uvc->state != UVC_STATE_CONNECTED)
+                       return -ENODEV;
+       } else {
+               if (uvc->state == UVC_STATE_DISCONNECTED)
+                       return -ENODEV;
+       }
+       //sheldon add end

具体连接Android平台为什么走的流程不一样还不清楚,可能和 https://www.usbzh.com/article/detail-166.html 描述的类似,连接Linux主机时就进行了参数配置,而Windows在打开摄像头的时候才进行相关参数的获取,所以UVC设备在连接Windows和Linux时是有区别的。

posted on 2024-09-03 10:28  sheldon_blogs  阅读(90)  评论(0编辑  收藏  举报

导航