diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index b1c755069451..0ef3bb695619 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -125,6 +125,18 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt0 = { .iInterface = 0, }; +static struct usb_interface_descriptor uvc_bulk_streaming_intf_alt0 = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = UVC_INTF_VIDEO_STREAMING, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING, + .bInterfaceProtocol = 0x00, + .iInterface = 0, +}; + static struct usb_interface_descriptor uvc_streaming_intf_alt1 = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, @@ -148,6 +160,16 @@ static struct usb_endpoint_descriptor uvc_fs_streaming_ep = { */ }; +static struct usb_endpoint_descriptor uvc_fs_bulk_streaming_ep = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + /* The wMaxPacketSize and bInterval values will be initialized from + * module parameters. + */ +}; + static struct usb_endpoint_descriptor uvc_hs_streaming_ep = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -159,6 +181,16 @@ static struct usb_endpoint_descriptor uvc_hs_streaming_ep = { */ }; +static struct usb_endpoint_descriptor uvc_hs_bulk_streaming_ep = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + /* The wMaxPacketSize and bInterval values will be initialized from + * module parameters. + */ +}; + static struct usb_endpoint_descriptor uvc_ss_streaming_ep = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -171,6 +203,17 @@ static struct usb_endpoint_descriptor uvc_ss_streaming_ep = { */ }; +static struct usb_endpoint_descriptor uvc_ss_bulk_streaming_ep = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + /* The wMaxPacketSize and bInterval values will be initialized from + * module parameters. + */ +}; + static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = { .bLength = sizeof(uvc_ss_streaming_comp), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, @@ -179,18 +222,36 @@ static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = { */ }; +static struct usb_ss_ep_comp_descriptor uvc_ss_bulk_streaming_comp = { + .bLength = sizeof(uvc_ss_bulk_streaming_comp), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + /* The bMaxBurst, bmAttributes and wBytesPerInterval values will be + * initialized from module parameters. + */ +}; + static const struct usb_descriptor_header * const uvc_fs_streaming[] = { (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, (struct usb_descriptor_header *) &uvc_fs_streaming_ep, NULL, }; +static const struct usb_descriptor_header * const uvc_fs_bulk_streaming[] = { + (struct usb_descriptor_header *)&uvc_fs_bulk_streaming_ep, + NULL, +}; + static const struct usb_descriptor_header * const uvc_hs_streaming[] = { (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, (struct usb_descriptor_header *) &uvc_hs_streaming_ep, NULL, }; +static const struct usb_descriptor_header * const uvc_hs_bulk_streaming[] = { + (struct usb_descriptor_header *)&uvc_hs_bulk_streaming_ep, + NULL, +}; + static const struct usb_descriptor_header * const uvc_ss_streaming[] = { (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, (struct usb_descriptor_header *) &uvc_ss_streaming_ep, @@ -198,6 +259,11 @@ static const struct usb_descriptor_header * const uvc_ss_streaming[] = { NULL, }; +static const struct usb_descriptor_header * const uvc_ss_bulk_streaming[] = { + (struct usb_descriptor_header *)&uvc_ss_bulk_streaming_ep, + (struct usb_descriptor_header *)&uvc_ss_bulk_streaming_comp, + NULL, +}; void uvc_set_trace_param(unsigned int trace) { uvc_gadget_trace_param = trace; @@ -272,15 +338,27 @@ static int uvc_function_get_alt(struct usb_function *f, unsigned interface) { struct uvc_device *uvc = to_uvc(f); + struct f_uvc_opts *opts; INFO(f->config->cdev, "uvc_function_get_alt(%u)\n", interface); + opts = fi_to_f_uvc_opts(f->fi); + if (interface == uvc->control_intf) return 0; else if (interface != uvc->streaming_intf) return -EINVAL; - else + else if (!opts->streaming_bulk) return uvc->video.ep->enabled ? 1 : 0; + else + /* + * 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. + */ + return 0; } static int @@ -290,10 +368,13 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) struct usb_composite_dev *cdev = f->config->cdev; struct v4l2_event v4l2_event; struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; + struct f_uvc_opts *opts; int ret; INFO(cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); + opts = fi_to_f_uvc_opts(f->fi); + if (interface == uvc->control_intf) { if (alt) return -EINVAL; @@ -322,49 +403,89 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) if (interface != uvc->streaming_intf) return -EINVAL; - /* TODO - if (usb_endpoint_xfer_bulk(&uvc->desc.vs_ep)) - return alt ? -EINVAL : 0; - */ + if (!opts->streaming_bulk) { + switch (alt) { + case 0: + if (uvc->state != UVC_STATE_STREAMING) + return 0; - switch (alt) { - case 0: - if (uvc->state != UVC_STATE_STREAMING) + if (uvc->video.ep) + usb_ep_disable(uvc->video.ep); + + memset(&v4l2_event, 0, sizeof(v4l2_event)); + v4l2_event.type = UVC_EVENT_STREAMOFF; + v4l2_event_queue(&uvc->vdev, &v4l2_event); + + uvc->state = UVC_STATE_CONNECTED; return 0; - if (uvc->video.ep) + case 1: + if (uvc->state != UVC_STATE_CONNECTED) + return 0; + + if (!uvc->video.ep) + return -EINVAL; + + INFO(cdev, "reset UVC\n"); usb_ep_disable(uvc->video.ep); - memset(&v4l2_event, 0, sizeof(v4l2_event)); - v4l2_event.type = UVC_EVENT_STREAMOFF; - v4l2_event_queue(&uvc->vdev, &v4l2_event); + ret = config_ep_by_speed(f->config->cdev->gadget, + &uvc->func, uvc->video.ep); + if (ret) + return ret; + usb_ep_enable(uvc->video.ep); - uvc->state = UVC_STATE_CONNECTED; - return 0; + memset(&v4l2_event, 0, sizeof(v4l2_event)); + v4l2_event.type = UVC_EVENT_STREAMON; + v4l2_event_queue(&uvc->vdev, &v4l2_event); + return USB_GADGET_DELAYED_STATUS; - case 1: - if (uvc->state != UVC_STATE_CONNECTED) + default: + return -EINVAL; + } + } else { + switch (uvc->state) { + case UVC_STATE_CONNECTED: + if (uvc->video.ep && + !uvc->video.ep->enabled) { + /* + * Enable the video streaming endpoint, + * but don't change the 'uvc->state'. + */ + ret = config_ep_by_speed(cdev->gadget, + &uvc->func, + uvc->video.ep); + if (ret) + return ret; + ret = usb_ep_enable(uvc->video.ep); + if (ret) + return ret; + } else { + memset(&v4l2_event, 0, sizeof(v4l2_event)); + v4l2_event.type = UVC_EVENT_STREAMON; + v4l2_event_queue(&uvc->vdev, &v4l2_event); + + uvc->state = UVC_STATE_STREAMING; + } return 0; - if (!uvc->video.ep) + case UVC_STATE_STREAMING: + if (uvc->video.ep && + uvc->video.ep->enabled) { + ret = usb_ep_disable(uvc->video.ep); + if (ret) + return ret; + } + + memset(&v4l2_event, 0, sizeof(v4l2_event)); + v4l2_event.type = UVC_EVENT_STREAMOFF; + v4l2_event_queue(&uvc->vdev, &v4l2_event); + uvc->state = UVC_STATE_CONNECTED; + return 0; + + default: return -EINVAL; - - INFO(cdev, "reset UVC\n"); - usb_ep_disable(uvc->video.ep); - - ret = config_ep_by_speed(f->config->cdev->gadget, - &(uvc->func), uvc->video.ep); - if (ret) - return ret; - usb_ep_enable(uvc->video.ep); - - memset(&v4l2_event, 0, sizeof(v4l2_event)); - v4l2_event.type = UVC_EVENT_STREAMON; - v4l2_event_queue(&uvc->vdev, &v4l2_event); - return USB_GADGET_DELAYED_STATUS; - - default: - return -EINVAL; + } } } @@ -462,32 +583,45 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) const struct uvc_descriptor_header * const *uvc_streaming_cls; const struct usb_descriptor_header * const *uvc_streaming_std; const struct usb_descriptor_header * const *src; + struct usb_interface_descriptor *streaming_intf_alt0; struct usb_descriptor_header **dst; struct usb_descriptor_header **hdr; + struct f_uvc_opts *opts; unsigned int control_size; unsigned int streaming_size; unsigned int n_desc; unsigned int bytes; void *mem; + opts = fi_to_f_uvc_opts(uvc->func.fi); + switch (speed) { case USB_SPEED_SUPER: uvc_control_desc = uvc->desc.ss_control; uvc_streaming_cls = uvc->desc.ss_streaming; - uvc_streaming_std = uvc_ss_streaming; + if (!opts->streaming_bulk) + uvc_streaming_std = uvc_ss_streaming; + else + uvc_streaming_std = uvc_ss_bulk_streaming; break; case USB_SPEED_HIGH: uvc_control_desc = uvc->desc.fs_control; uvc_streaming_cls = uvc->desc.hs_streaming; - uvc_streaming_std = uvc_hs_streaming; + if (!opts->streaming_bulk) + uvc_streaming_std = uvc_hs_streaming; + else + uvc_streaming_std = uvc_hs_bulk_streaming; break; case USB_SPEED_FULL: default: uvc_control_desc = uvc->desc.fs_control; uvc_streaming_cls = uvc->desc.fs_streaming; - uvc_streaming_std = uvc_fs_streaming; + if (!opts->streaming_bulk) + uvc_streaming_std = uvc_fs_streaming; + else + uvc_streaming_std = uvc_fs_bulk_streaming; break; } @@ -507,12 +641,17 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) * uvc_{fs|hs}_streaming */ + if (!opts->streaming_bulk) + streaming_intf_alt0 = &uvc_streaming_intf_alt0; + else + streaming_intf_alt0 = &uvc_bulk_streaming_intf_alt0; + /* Count descriptors and compute their size. */ control_size = 0; streaming_size = 0; bytes = uvc_iad.bLength + uvc_control_intf.bLength + uvc_control_ep.bLength + uvc_control_cs_ep.bLength - + uvc_streaming_intf_alt0.bLength; + + streaming_intf_alt0->bLength; if (speed == USB_SPEED_SUPER) { bytes += uvc_ss_control_comp.bLength; @@ -562,7 +701,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp); UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep); - UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0); + UVC_COPY_DESCRIPTOR(mem, dst, streaming_intf_alt0); uvc_streaming_header = mem; UVC_COPY_DESCRIPTORS(mem, dst, @@ -587,15 +726,24 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) struct usb_ep *ep; struct f_uvc_opts *opts; int ret = -EINVAL; + u8 address; INFO(cdev, "uvc_function_bind\n"); opts = fi_to_f_uvc_opts(f->fi); /* Sanity check the streaming endpoint module parameters. */ - opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U); - opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 3072U); - opts->streaming_maxburst = min(opts->streaming_maxburst, 15U); + if (!opts->streaming_bulk) { + opts->streaming_interval = clamp(opts->streaming_interval, + 1U, 16U); + opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, + 1U, 3072U); + opts->streaming_maxburst = min(opts->streaming_maxburst, 15U); + } else { + opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, + 1U, 1024U); + opts->streaming_maxburst = min(opts->streaming_maxburst, 15U); + } /* For SS, wMaxPacketSize has to be 1024 if bMaxBurst is not 0 */ if (opts->streaming_maxburst && @@ -622,21 +770,37 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) max_packet_size = opts->streaming_maxpacket / 3; } - uvc_fs_streaming_ep.wMaxPacketSize = - cpu_to_le16(min(opts->streaming_maxpacket, 1023U)); - uvc_fs_streaming_ep.bInterval = opts->streaming_interval; + if (!opts->streaming_bulk) { + uvc_fs_streaming_ep.wMaxPacketSize = + cpu_to_le16(min(opts->streaming_maxpacket, 1023U)); + uvc_fs_streaming_ep.bInterval = opts->streaming_interval; - uvc_hs_streaming_ep.wMaxPacketSize = - cpu_to_le16(max_packet_size | ((max_packet_mult - 1) << 11)); - uvc_hs_streaming_ep.bInterval = opts->streaming_interval; + uvc_hs_streaming_ep.wMaxPacketSize = + cpu_to_le16(max_packet_size | + ((max_packet_mult - 1) << 11)); + uvc_hs_streaming_ep.bInterval = opts->streaming_interval; - uvc_ss_streaming_ep.wMaxPacketSize = cpu_to_le16(max_packet_size); - uvc_ss_streaming_ep.bInterval = opts->streaming_interval; - uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1; - uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst; - uvc_ss_streaming_comp.wBytesPerInterval = - cpu_to_le16(max_packet_size * max_packet_mult * - (opts->streaming_maxburst + 1)); + uvc_ss_streaming_ep.wMaxPacketSize = + cpu_to_le16(max_packet_size); + uvc_ss_streaming_ep.bInterval = opts->streaming_interval; + uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1; + uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst; + uvc_ss_streaming_comp.wBytesPerInterval = + cpu_to_le16(max_packet_size * max_packet_mult * + (opts->streaming_maxburst + 1)); + } else { + uvc_fs_bulk_streaming_ep.wMaxPacketSize = + cpu_to_le16(min(opts->streaming_maxpacket, 64U)); + + uvc_hs_bulk_streaming_ep.wMaxPacketSize = + cpu_to_le16(min(opts->streaming_maxpacket, 512U)); + + uvc_ss_bulk_streaming_ep.wMaxPacketSize = + cpu_to_le16(max_packet_size); + uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst; + uvc_ss_streaming_comp.wBytesPerInterval = + cpu_to_le16(max_packet_size * opts->streaming_maxburst); + } /* Allocate endpoints. */ ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); @@ -646,23 +810,57 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) } uvc->control_ep = ep; - if (gadget_is_superspeed(c->cdev->gadget)) - ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep, - &uvc_ss_streaming_comp); - else if (gadget_is_dualspeed(cdev->gadget)) - ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep); - else - ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); + if (gadget_is_superspeed(c->cdev->gadget)) { + if (!opts->streaming_bulk) + ep = usb_ep_autoconfig_ss(cdev->gadget, + &uvc_ss_streaming_ep, + &uvc_ss_streaming_comp); + else + ep = usb_ep_autoconfig_ss(cdev->gadget, + &uvc_ss_bulk_streaming_ep, + &uvc_ss_bulk_streaming_comp); + } else if (gadget_is_dualspeed(cdev->gadget)) { + if (!opts->streaming_bulk) { + ep = usb_ep_autoconfig(cdev->gadget, + &uvc_hs_streaming_ep); + } else { + ep = usb_ep_autoconfig(cdev->gadget, + &uvc_hs_bulk_streaming_ep); + /* + * In ep_matches(), it will set wMaxPacketSize to 64 + * bytes if ep is Bulk and ep_comp is NULL for hs/fs + * bulk maxpacket. So we need to set hs bulk maxpacket + * 512 bytes again here. + */ + uvc_hs_bulk_streaming_ep.wMaxPacketSize = + cpu_to_le16(min(opts->streaming_maxpacket, + 512U)); + } + } else { + if (!opts->streaming_bulk) + ep = usb_ep_autoconfig(cdev->gadget, + &uvc_fs_streaming_ep); + else + ep = usb_ep_autoconfig(cdev->gadget, + &uvc_fs_bulk_streaming_ep); + } if (!ep) { INFO(cdev, "Unable to allocate streaming EP\n"); goto error; } uvc->video.ep = ep; + address = uvc->video.ep->address; - uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address; - uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address; - uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address; + if (!opts->streaming_bulk) { + uvc_fs_streaming_ep.bEndpointAddress = address; + uvc_hs_streaming_ep.bEndpointAddress = address; + uvc_ss_streaming_ep.bEndpointAddress = address; + } else { + uvc_fs_bulk_streaming_ep.bEndpointAddress = address; + uvc_hs_bulk_streaming_ep.bEndpointAddress = address; + uvc_ss_bulk_streaming_ep.bEndpointAddress = address; + } us = usb_gstrings_attach(cdev, uvc_function_strings, ARRAY_SIZE(uvc_en_us_strings)); @@ -673,8 +871,12 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) uvc_iad.iFunction = us[UVC_STRING_CONTROL_IDX].id; uvc_control_intf.iInterface = us[UVC_STRING_CONTROL_IDX].id; ret = us[UVC_STRING_STREAMING_IDX].id; - uvc_streaming_intf_alt0.iInterface = ret; - uvc_streaming_intf_alt1.iInterface = ret; + if (!opts->streaming_bulk) { + uvc_streaming_intf_alt0.iInterface = ret; + uvc_streaming_intf_alt1.iInterface = ret; + } else { + uvc_bulk_streaming_intf_alt0.iInterface = ret; + } /* Allocate interface IDs. */ if ((ret = usb_interface_id(c, f)) < 0) @@ -685,8 +887,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) if ((ret = usb_interface_id(c, f)) < 0) goto error; - uvc_streaming_intf_alt0.bInterfaceNumber = ret; - uvc_streaming_intf_alt1.bInterfaceNumber = ret; + + if (!opts->streaming_bulk) { + uvc_streaming_intf_alt0.bInterfaceNumber = ret; + uvc_streaming_intf_alt1.bInterfaceNumber = ret; + } else { + uvc_bulk_streaming_intf_alt0.bInterfaceNumber = ret; + } + uvc->streaming_intf = ret; /* Copy descriptors */ @@ -735,6 +943,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) if (ret < 0) goto error; + if (opts->streaming_bulk) + uvc->video.max_payload_size = uvc->video.imagesize; /* Register a V4L2 device. */ ret = uvc_register_video(uvc); if (ret < 0) { diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h index 025c2ae4e177..35e03eb75abd 100644 --- a/drivers/usb/gadget/function/u_uvc.h +++ b/drivers/usb/gadget/function/u_uvc.h @@ -24,6 +24,7 @@ DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(1, 1); struct f_uvc_opts { struct usb_function_instance func_inst; + bool streaming_bulk; unsigned int uvc_gadget_trace_param; unsigned int streaming_interval; unsigned int streaming_maxpacket; diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 26c6ba150193..997650739655 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -2253,6 +2253,8 @@ UVC_ATTR(f_uvc_opts_, cname, cname) #define identity_conv(x) (x) +UVCG_OPTS_ATTR(streaming_bulk, streaming_bulk, identity_conv, + kstrtou8, u8, identity_conv, 1); UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv, kstrtou8, u8, identity_conv, 16); UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu, @@ -2265,6 +2267,7 @@ UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv, #undef UVCG_OPTS_ATTR static struct configfs_attribute *uvc_attrs[] = { + &f_uvc_opts_attr_streaming_bulk, &f_uvc_opts_attr_streaming_interval, &f_uvc_opts_attr_streaming_maxpacket, &f_uvc_opts_attr_streaming_maxburst, diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 81f1d614fbe6..8bc9b506898e 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -207,11 +207,21 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type) return ret; /* - * Complete the alternate setting selection setup phase now that - * userspace is ready to provide video frames. + * 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. */ - uvc_function_setup_continue(uvc); - uvc->state = UVC_STATE_STREAMING; + if (!usb_endpoint_xfer_bulk(video->ep->desc)) { + /* + * Complete the alternate setting selection + * setup phase now that userspace is ready + * to provide video frames. + */ + uvc_function_setup_continue(uvc); + uvc->state = UVC_STATE_STREAMING; + } return 0; } diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index 0f01c04d7cbd..f1acfcaaa92e 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -241,9 +241,14 @@ uvc_video_alloc_requests(struct uvc_video *video) BUG_ON(video->req_size); - req_size = video->ep->maxpacket - * max_t(unsigned int, video->ep->maxburst, 1) - * (video->ep->mult); + if (!usb_endpoint_xfer_bulk(video->ep->desc)) { + req_size = video->ep->maxpacket + * max_t(unsigned int, video->ep->maxburst, 1) + * (video->ep->mult); + } else { + req_size = video->ep->maxpacket + * max_t(unsigned int, video->ep->maxburst, 1); + } for (i = 0; i < UVC_NUM_REQUESTS; ++i) { video->req_buffer[i] = kmalloc(req_size, GFP_KERNEL);