diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 7ccc28c93dc7..19470105bf8b 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -386,6 +386,14 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) usb_ep_enable(uvc->control_ep); + if (uvc->event_suspend) { + memset(&v4l2_event, 0, sizeof(v4l2_event)); + v4l2_event.type = UVC_EVENT_RESUME; + v4l2_event_queue(&uvc->vdev, &v4l2_event); + uvc->event_suspend = 0; + uvc_trace(UVC_TRACE_SUSPEND, "send UVC_EVENT_RESUME\n"); + } + if (uvc->state == UVC_STATE_DISCONNECTED) { memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_CONNECT; @@ -510,6 +518,30 @@ uvc_function_disable(struct usb_function *f) usb_ep_disable(uvc->control_ep); } +static void uvc_function_suspend(struct usb_function *f) +{ + struct uvc_device *uvc = to_uvc(f); + struct v4l2_event v4l2_event; + + memset(&v4l2_event, 0, sizeof(v4l2_event)); + v4l2_event.type = UVC_EVENT_SUSPEND; + v4l2_event_queue(&uvc->vdev, &v4l2_event); + uvc->event_suspend = 1; + uvc_trace(UVC_TRACE_SUSPEND, "send UVC_EVENT_SUSPEND\n"); +} + +static void uvc_function_resume(struct usb_function *f) +{ + struct uvc_device *uvc = to_uvc(f); + struct v4l2_event v4l2_event; + + memset(&v4l2_event, 0, sizeof(v4l2_event)); + v4l2_event.type = UVC_EVENT_RESUME; + v4l2_event_queue(&uvc->vdev, &v4l2_event); + uvc->event_suspend = 0; + uvc_trace(UVC_TRACE_SUSPEND, "send UVC_EVENT_RESUME\n"); +} + /* -------------------------------------------------------------------------- * Connection / disconnection */ @@ -817,9 +849,13 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) 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); + uvc_ss_bulk_streaming_comp.bMaxBurst = opts->streaming_maxburst; + /* + * As per USB 3.1 spec "Table 9-26. SuperSpeed Endpoint + * Companion Descriptor", the wBytesPerInterval must be + * set to zero for bulk endpoints. + */ + uvc_ss_bulk_streaming_comp.wBytesPerInterval = 0; } /* Allocate endpoints. */ @@ -1199,6 +1235,8 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) uvc->func.disable = uvc_function_disable; uvc->func.setup = uvc_function_setup; uvc->func.free_func = uvc_free; + uvc->func.suspend = uvc_function_suspend; + uvc->func.resume = uvc_function_resume; uvc->func.bind_deactivated = true; return &uvc->func; diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 75344517b523..e6a8b84fdcb2 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -138,6 +138,7 @@ struct uvc_device { /* Events */ unsigned int event_length; unsigned int event_setup_out : 1; + unsigned int event_suspend : 1; }; static inline struct uvc_device *to_uvc(struct usb_function *f) diff --git a/include/uapi/linux/usb/g_uvc.h b/include/uapi/linux/usb/g_uvc.h index 652f169a019e..428926e35973 100644 --- a/include/uapi/linux/usb/g_uvc.h +++ b/include/uapi/linux/usb/g_uvc.h @@ -19,7 +19,9 @@ #define UVC_EVENT_STREAMOFF (V4L2_EVENT_PRIVATE_START + 3) #define UVC_EVENT_SETUP (V4L2_EVENT_PRIVATE_START + 4) #define UVC_EVENT_DATA (V4L2_EVENT_PRIVATE_START + 5) -#define UVC_EVENT_LAST (V4L2_EVENT_PRIVATE_START + 5) +#define UVC_EVENT_SUSPEND (V4L2_EVENT_PRIVATE_START + 6) +#define UVC_EVENT_RESUME (V4L2_EVENT_PRIVATE_START + 7) +#define UVC_EVENT_LAST (V4L2_EVENT_PRIVATE_START + 7) struct uvc_request_data { __s32 length;