平台: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时是有区别的。
标签:UVC,Gadget,state,bulk,STATE,video,Android,uvc,v4l2 From: https://www.cnblogs.com/blogs-of-lxl/p/18393324