diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 3c26508c804b..8aae498ab496 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -124,6 +124,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, @@ -147,6 +159,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, @@ -158,6 +180,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, @@ -170,6 +202,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, @@ -178,18 +221,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, @@ -197,6 +258,12 @@ 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, +}; + /* -------------------------------------------------------------------------- * Control requests */ @@ -260,15 +327,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; uvcg_info(f, "%s(%u)\n", __func__, 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 @@ -278,10 +357,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; uvcg_info(f, "%s(%u, %u)\n", __func__, interface, alt); + opts = fi_to_f_uvc_opts(f->fi); + if (interface == uvc->control_intf) { if (alt) return -EINVAL; @@ -310,49 +392,94 @@ 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 (!alt) { + INFO(cdev, "bulk streaming intf not support alt 0\n"); + return 0; + } + + 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; - - uvcg_info(f, "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; + } } } @@ -467,32 +594,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; } @@ -512,12 +652,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; @@ -567,7 +712,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, @@ -592,15 +737,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; uvcg_info(f, "%s()\n", __func__); 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 && @@ -627,21 +781,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); @@ -651,23 +821,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) { uvcg_info(f, "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)); @@ -678,8 +882,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) @@ -691,8 +899,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; opts->streaming_interface = ret; @@ -742,6 +956,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) if (ret < 0) goto v4l2_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 c6e432d02578..ca9a7db23599 100644 --- a/drivers/usb/gadget/function/u_uvc.h +++ b/drivers/usb/gadget/function/u_uvc.h @@ -22,6 +22,7 @@ DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(1, 1); struct f_uvc_opts { struct usb_function_instance func_inst; + bool streaming_bulk; unsigned int streaming_interval; unsigned int streaming_maxpacket; unsigned int streaming_maxburst; diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 00fb58e50a15..8462da1c621d 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -2424,6 +2424,7 @@ end: \ \ UVC_ATTR(f_uvc_opts_, cname, cname) +UVCG_OPTS_ATTR(streaming_bulk, streaming_bulk, 1); UVCG_OPTS_ATTR(streaming_interval, streaming_interval, 16); UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, 3072); UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, 15); @@ -2431,6 +2432,7 @@ UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, 15); #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 5d37f787f89d..cbf971824a7f 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -201,11 +201,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 633e23d58d86..76d1bba0c2a3 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -87,6 +87,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video, video->fid ^= UVC_STREAM_FID; video->payload_size = 0; + req->zero = 1; } if (video->payload_size == video->max_payload_size || @@ -135,7 +136,7 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req) ret); /* Isochronous endpoints can't be halted. */ - if (usb_endpoint_xfer_bulk(video->ep->desc)) + if (video->ep->desc && usb_endpoint_xfer_bulk(video->ep->desc)) usb_ep_set_halt(video->ep); } @@ -203,9 +204,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);