Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: gadget: clarify usage of USB_GADGET_DELAYED_STATUS

USB_GADGET_DELAYED_STATUS was introduced in commit 1b9ba000177e ("usb:
gadget: composite: Allow function drivers to pause control transfers").
It was initially intended for the composite framework to allow delaying
completing the status stage of a SET_CONFIGURATION request until all
functions are ready.

Unfortunately, that commit had an unintended side-effect of returning
USB_GADGET_DELAYED_STATUS from the ->setup() call of the composite
framework gadget driver.

As a result of this and the incomplete documentation, some UDC drivers
started relying on USB_GADGET_DELAYED_STATUS to decide when to avoid
autocompleting the status stage for 0-length control transfers. dwc3 was
the first in commit 5bdb1dcc6330 ("usb: dwc3: ep0: handle delayed_status
again"). And a number of other UDC drivers followed later, probably
relying on the dwc3 behavior as a reference.

Unfortunately, this violated the interface between the UDC and the
gadget driver for 0-length control transfers: the UDC driver must only
proceed with the status stage for a 0-length control transfer once the
gadget driver queued a response to EP0.

As a result, a few gadget drivers are partially broken when used with
a UDC that only delays the status stage for 0-length transfers when
USB_GADGET_DELAYED_STATUS is returned from the setup() callback.

This includes Raw Gadget and GadgetFS. For FunctionFS, a workaround was
added in commit 946ef68ad4e4 ("usb: gadget: ffs: Let setup() return
USB_GADGET_DELAYED_STATUS") and commit 4d644abf2569 ("usb: gadget: f_fs:
Only return delayed status when len is 0").

The proper solution to this issue would be to contain
USB_GADGET_DELAYED_STATUS within the composite framework and make all
UDC drivers to not complete the status stage for 0-length requests on
their own.

Unfortunately, there is quite a few UDC drivers that need to get fixed
and the required changes for some of them are not trivial.

For now, update the comments to clarify that USB_GADGET_DELAYED_STATUS
must not be used by the UDC drivers.

The following two commits also add workarounds to Raw Gadget and GadgetFS
to make them compatible with the broken UDC drivers until they are fixed.

Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Andrey Konovalov <andreyknvl@gmail.com>
Link: https://lore.kernel.org/r/7f0ee06c68c7241c844cd50f8565fdd5ead79b1b.1693237258.git.andreyknvl@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Andrey Konovalov and committed by
Greg Kroah-Hartman
3551ff7c 36c38087

+17
+8
include/linux/usb/composite.h
··· 35 35 * are ready. The control transfer will then be kept from completing till 36 36 * all the function drivers that requested for USB_GADGET_DELAYED_STAUS 37 37 * invoke usb_composite_setup_continue(). 38 + * 39 + * NOTE: USB_GADGET_DELAYED_STATUS must not be used in UDC drivers: they 40 + * must delay completing the status stage for 0-length control transfers 41 + * regardless of the whether USB_GADGET_DELAYED_STATUS is returned from 42 + * the gadget driver's setup() callback. 43 + * Currently, a number of UDC drivers rely on USB_GADGET_DELAYED_STATUS, 44 + * which is a bug. These drivers must be fixed and USB_GADGET_DELAYED_STATUS 45 + * must be contained within the composite framework. 38 46 */ 39 47 #define USB_GADGET_DELAYED_STATUS 0x7fff /* Impossibly large value */ 40 48
+9
include/linux/usb/gadget.h
··· 711 711 * get_interface. Setting a configuration (or interface) is where 712 712 * endpoints should be activated or (config 0) shut down. 713 713 * 714 + * The gadget driver's setup() callback does not have to queue a response to 715 + * ep0 within the setup() call, the driver can do it after setup() returns. 716 + * The UDC driver must wait until such a response is queued before proceeding 717 + * with the data/status stages of the control transfer. 718 + * 719 + * NOTE: Currently, a number of UDC drivers rely on USB_GADGET_DELAYED_STATUS 720 + * being returned from the setup() callback, which is a bug. See the comment 721 + * next to USB_GADGET_DELAYED_STATUS for details. 722 + * 714 723 * (Note that only the default control endpoint is supported. Neither 715 724 * hosts nor devices generally support control traffic except to ep0.) 716 725 *