diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index aa6ab666741a..7fb30b09e980 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -652,22 +652,32 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) unsigned int max_packet_size; struct usb_ep *ep; struct f_uvc_opts *opts; + bool bulk; int ret = -EINVAL; uvcg_info(f, "%s()\n", __func__); opts = fi_to_f_uvc_opts(f->fi); + bulk = opts->streaming_bulk; /* 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); - /* For SS, wMaxPacketSize has to be 1024 if bMaxBurst is not 0 */ - if (opts->streaming_maxburst && - (opts->streaming_maxpacket % 1024) != 0) { - opts->streaming_maxpacket = roundup(opts->streaming_maxpacket, 1024); - uvcg_info(f, "overriding streaming_maxpacket to %d\n", - opts->streaming_maxpacket); + if (bulk) { + opts->streaming_maxpacket = + clamp(opts->streaming_maxpacket, 1U, 1024U); + } else { + opts->streaming_maxpacket = + clamp(opts->streaming_maxpacket, 1U, 3072U); + /* For SS, wMaxPacketSize has to be 1024 if bMaxBurst is not 0 */ + if (opts->streaming_maxburst && + (opts->streaming_maxpacket % 1024) != 0) { + opts->streaming_maxpacket = + roundup(opts->streaming_maxpacket, 1024); + uvcg_info(f, + "overriding streaming_maxpacket to %d\n", + opts->streaming_maxpacket); + } } /* @@ -677,37 +687,70 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) * NOTE: We assume that the user knows what they are doing and won't * give parameters that their UDC doesn't support. */ - if (opts->streaming_maxpacket <= 1024) { + if (bulk) { max_packet_mult = 1; max_packet_size = opts->streaming_maxpacket; - } else if (opts->streaming_maxpacket <= 2048) { - max_packet_mult = 2; - max_packet_size = opts->streaming_maxpacket / 2; - } else { - max_packet_mult = 3; - 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; + uvc_fs_streaming_ep.bmAttributes = USB_ENDPOINT_XFER_BULK; + uvc_hs_streaming_ep.bmAttributes = USB_ENDPOINT_XFER_BULK; + uvc_ss_streaming_ep.bmAttributes = USB_ENDPOINT_XFER_BULK; - uvc_hs_streaming_ep.wMaxPacketSize = - cpu_to_le16(max_packet_size | ((max_packet_mult - 1) << 11)); + uvc_fs_streaming_ep.wMaxPacketSize = + cpu_to_le16(min(opts->streaming_maxpacket, 64U)); + uvc_fs_streaming_ep.bInterval = 0; - /* A high-bandwidth endpoint must specify a bInterval value of 1 */ - if (max_packet_mult > 1) - uvc_hs_streaming_ep.bInterval = 1; - else - 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_hs_streaming_ep.wMaxPacketSize = + cpu_to_le16(min(opts->streaming_maxpacket, 512U)); + uvc_hs_streaming_ep.bInterval = 0; + + uvc_ss_streaming_ep.wMaxPacketSize = + cpu_to_le16(min(opts->streaming_maxpacket, 1024U)); + uvc_ss_streaming_ep.bInterval = 0; + uvc_ss_streaming_comp.bmAttributes = 0; + uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst; + uvc_ss_streaming_comp.wBytesPerInterval = cpu_to_le16(0); + } else { + if (opts->streaming_maxpacket <= 1024) { + max_packet_mult = 1; + max_packet_size = opts->streaming_maxpacket; + } else if (opts->streaming_maxpacket <= 2048) { + max_packet_mult = 2; + max_packet_size = opts->streaming_maxpacket / 2; + } else { + max_packet_mult = 3; + max_packet_size = opts->streaming_maxpacket / 3; + } + + uvc_fs_streaming_ep.bmAttributes = + USB_ENDPOINT_SYNC_ASYNC | USB_ENDPOINT_XFER_ISOC; + uvc_hs_streaming_ep.bmAttributes = + USB_ENDPOINT_SYNC_ASYNC | USB_ENDPOINT_XFER_ISOC; + uvc_ss_streaming_ep.bmAttributes = + USB_ENDPOINT_SYNC_ASYNC | USB_ENDPOINT_XFER_ISOC; + + 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)); + + /* A high-bandwidth endpoint must specify a bInterval value of 1 */ + if (max_packet_mult > 1) + uvc_hs_streaming_ep.bInterval = 1; + else + 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)); + } /* Allocate endpoints. */ if (opts->enable_interrupt_ep) { diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h index 3ac392cbb779..b57e2d10ddcd 100644 --- a/drivers/usb/gadget/function/u_uvc.h +++ b/drivers/usb/gadget/function/u_uvc.h @@ -24,6 +24,7 @@ struct f_uvc_opts { unsigned int streaming_interval; unsigned int streaming_maxpacket; unsigned int streaming_maxburst; + unsigned int streaming_bulk; unsigned int control_interface; unsigned int streaming_interface; diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index a4a2d3dcb0d6..80817ff1b6fe 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -3751,6 +3751,7 @@ UVC_ATTR(f_uvc_opts_, cname, cname) UVCG_OPTS_ATTR(streaming_interval, streaming_interval, 16); UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, 3072); UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, 15); +UVCG_OPTS_ATTR(streaming_bulk, streaming_bulk, 1); #undef UVCG_OPTS_ATTR @@ -3800,6 +3801,7 @@ static struct configfs_attribute *uvc_attrs[] = { &f_uvc_opts_attr_streaming_interval, &f_uvc_opts_attr_streaming_maxpacket, &f_uvc_opts_attr_streaming_maxburst, + &f_uvc_opts_attr_streaming_bulk, &f_uvc_opts_string_attr_function_name, NULL, };