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

usb: gadget: f_fs: add capability for dfu functional descriptor

Add the ability for the USB FunctionFS (FFS) gadget driver to be able
to create Device Firmware Upgrade (DFU) functional descriptors. [1]

This patch allows implementation of DFU in userspace using the
FFS gadget. The DFU protocol uses the control pipe (ep0) for all
messaging so only the addition of the DFU functional descriptor
is needed in the kernel driver.

The DFU functional descriptor is written to the ep0 file along with
any other descriptors during FFS setup. DFU requires an interface
descriptor followed by the DFU functional descriptor.

This patch includes documentation of the added descriptor for DFU
and conversion of some existing documentation to kernel-doc format
so that it can be included in the generated docs.

An implementation of DFU 1.1 that implements just the runtime descriptor
using the FunctionFS gadget (with rebooting into u-boot for DFU mode)
has been tested on an i.MX8 Nano.

An implementation of DFU 1.1 that implements both runtime and DFU mode
using the FunctionFS gadget has been tested on Xilinx Zynq UltraScale+.
Note that for the best performance of firmware update file transfers, the
userspace program should respond as quick as possible to the setup packets.

[1] https://www.usb.org/sites/default/files/DFU_1.1.pdf

Signed-off-by: David Sands <david.sands@biamp.com>
Co-developed-by: Chris Wulff <crwulff@gmail.com>
Signed-off-by: Chris Wulff <crwulff@gmail.com>
Link: https://lore.kernel.org/r/20240811000004.1395888-2-crwulff@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

David Sands and committed by
Greg Kroah-Hartman
c26cee81 d1e14e06

+147 -12
+39
Documentation/usb/functionfs-desc.rst
··· 1 + ====================== 2 + FunctionFS Descriptors 3 + ====================== 4 + 5 + Some of the descriptors that can be written to the FFS gadget are 6 + described below. Device and configuration descriptors are handled 7 + by the composite gadget and are not written by the user to the 8 + FFS gadget. 9 + 10 + Descriptors are written to the "ep0" file in the FFS gadget 11 + following the descriptor header. 12 + 13 + .. kernel-doc:: include/uapi/linux/usb/functionfs.h 14 + :doc: descriptors 15 + 16 + Interface Descriptors 17 + --------------------- 18 + 19 + Standard USB interface descriptors may be written. The class/subclass of the 20 + most recent interface descriptor determines what type of class-specific 21 + descriptors are accepted. 22 + 23 + Class-Specific Descriptors 24 + -------------------------- 25 + 26 + Class-specific descriptors are accepted only for the class/subclass of the 27 + most recent interface descriptor. The following are some of the 28 + class-specific descriptors that are supported. 29 + 30 + DFU Functional Descriptor 31 + ~~~~~~~~~~~~~~~~~~~~~~~~~ 32 + 33 + When the interface class is USB_CLASS_APP_SPEC and the interface subclass 34 + is USB_SUBCLASS_DFU, a DFU functional descriptor can be provided. 35 + The DFU functional descriptor is a described in the USB specification for 36 + Device Firmware Upgrade (DFU), version 1.1 as of this writing. 37 + 38 + .. kernel-doc:: include/uapi/linux/usb/functionfs.h 39 + :doc: usb_dfu_functional_descriptor
+2
Documentation/usb/functionfs.rst
··· 25 25 them as needed also handling situation when numbers differ in 26 26 different configurations. 27 27 28 + For more information about FunctionFS descriptors see :doc:`functionfs-desc` 29 + 28 30 When descriptors and strings are written "ep#" files appear 29 31 (one for each declared endpoint) which handle communication on 30 32 a single endpoint. Again, FunctionFS takes care of the real
+1
Documentation/usb/index.rst
··· 11 11 dwc3 12 12 ehci 13 13 functionfs 14 + functionfs-desc 14 15 gadget_configfs 15 16 gadget_hid 16 17 gadget_multi
+10 -2
drivers/usb/gadget/function/f_fs.c
··· 2478 2478 2479 2479 static int __must_check ffs_do_single_desc(char *data, unsigned len, 2480 2480 ffs_entity_callback entity, 2481 - void *priv, int *current_class) 2481 + void *priv, int *current_class, int *current_subclass) 2482 2482 { 2483 2483 struct usb_descriptor_header *_ds = (void *)data; 2484 2484 u8 length; ··· 2535 2535 if (ds->iInterface) 2536 2536 __entity(STRING, ds->iInterface); 2537 2537 *current_class = ds->bInterfaceClass; 2538 + *current_subclass = ds->bInterfaceSubClass; 2538 2539 } 2539 2540 break; 2540 2541 ··· 2558 2557 } else if (*current_class == USB_INTERFACE_CLASS_CCID) { 2559 2558 pr_vdebug("ccid descriptor\n"); 2560 2559 if (length != sizeof(struct ccid_descriptor)) 2560 + goto inv_length; 2561 + break; 2562 + } else if (*current_class == USB_CLASS_APP_SPEC && 2563 + *current_subclass == USB_SUBCLASS_DFU) { 2564 + pr_vdebug("dfu functional descriptor\n"); 2565 + if (length != sizeof(struct usb_dfu_functional_descriptor)) 2561 2566 goto inv_length; 2562 2567 break; 2563 2568 } else { ··· 2628 2621 const unsigned _len = len; 2629 2622 unsigned long num = 0; 2630 2623 int current_class = -1; 2624 + int current_subclass = -1; 2631 2625 2632 2626 for (;;) { 2633 2627 int ret; ··· 2648 2640 return _len - len; 2649 2641 2650 2642 ret = ffs_do_single_desc(data, len, entity, priv, 2651 - &current_class); 2643 + &current_class, &current_subclass); 2652 2644 if (ret < 0) { 2653 2645 pr_debug("%s returns %d\n", __func__, ret); 2654 2646 return ret;
+6 -2
include/uapi/linux/usb/ch9.h
··· 254 254 #define USB_DT_DEVICE_CAPABILITY 0x10 255 255 #define USB_DT_WIRELESS_ENDPOINT_COMP 0x11 256 256 #define USB_DT_WIRE_ADAPTER 0x21 257 + /* From USB Device Firmware Upgrade Specification, Revision 1.1 */ 258 + #define USB_DT_DFU_FUNCTIONAL 0x21 259 + /* these are from the Wireless USB spec */ 257 260 #define USB_DT_RPIPE 0x22 258 261 #define USB_DT_CS_RADIO_CONTROL 0x23 259 262 /* From the T10 UAS specification */ ··· 332 329 #define USB_CLASS_USB_TYPE_C_BRIDGE 0x12 333 330 #define USB_CLASS_MISC 0xef 334 331 #define USB_CLASS_APP_SPEC 0xfe 335 - #define USB_CLASS_VENDOR_SPEC 0xff 332 + #define USB_SUBCLASS_DFU 0x01 336 333 337 - #define USB_SUBCLASS_VENDOR_SPEC 0xff 334 + #define USB_CLASS_VENDOR_SPEC 0xff 335 + #define USB_SUBCLASS_VENDOR_SPEC 0xff 338 336 339 337 /*-------------------------------------------------------------------------*/ 340 338
+89 -8
include/uapi/linux/usb/functionfs.h
··· 3 3 #define _UAPI__LINUX_FUNCTIONFS_H__ 4 4 5 5 6 + #include <linux/const.h> 6 7 #include <linux/types.h> 7 8 #include <linux/ioctl.h> 8 9 ··· 37 36 __le16 wMaxPacketSize; 38 37 __u8 bInterval; 39 38 } __attribute__((packed)); 39 + 40 + /** 41 + * struct usb_dfu_functional_descriptor - DFU Functional descriptor 42 + * @bLength: Size of the descriptor (bytes) 43 + * @bDescriptorType: USB_DT_DFU_FUNCTIONAL 44 + * @bmAttributes: DFU attributes 45 + * @wDetachTimeOut: Maximum time to wait after DFU_DETACH (ms, le16) 46 + * @wTransferSize: Maximum number of bytes per control-write (le16) 47 + * @bcdDFUVersion: DFU Spec version (BCD, le16) 48 + */ 49 + struct usb_dfu_functional_descriptor { 50 + __u8 bLength; 51 + __u8 bDescriptorType; 52 + __u8 bmAttributes; 53 + __le16 wDetachTimeOut; 54 + __le16 wTransferSize; 55 + __le16 bcdDFUVersion; 56 + } __attribute__ ((packed)); 57 + 58 + /* from DFU functional descriptor bmAttributes */ 59 + #define DFU_FUNC_ATT_CAN_DOWNLOAD _BITUL(0) 60 + #define DFU_FUNC_ATT_CAN_UPLOAD _BITUL(1) 61 + #define DFU_FUNC_ATT_MANIFEST_TOLERANT _BITUL(2) 62 + #define DFU_FUNC_ATT_WILL_DETACH _BITUL(3) 63 + 40 64 41 65 struct usb_functionfs_descs_head_v2 { 42 66 __le32 magic; ··· 130 104 131 105 #ifndef __KERNEL__ 132 106 133 - /* 107 + /** 108 + * DOC: descriptors 109 + * 134 110 * Descriptors format: 135 111 * 112 + * +-----+-----------+--------------+--------------------------------------+ 136 113 * | off | name | type | description | 137 - * |-----+-----------+--------------+--------------------------------------| 114 + * +-----+-----------+--------------+--------------------------------------+ 138 115 * | 0 | magic | LE32 | FUNCTIONFS_DESCRIPTORS_MAGIC_V2 | 116 + * +-----+-----------+--------------+--------------------------------------+ 139 117 * | 4 | length | LE32 | length of the whole data chunk | 118 + * +-----+-----------+--------------+--------------------------------------+ 140 119 * | 8 | flags | LE32 | combination of functionfs_flags | 120 + * +-----+-----------+--------------+--------------------------------------+ 141 121 * | | eventfd | LE32 | eventfd file descriptor | 122 + * +-----+-----------+--------------+--------------------------------------+ 142 123 * | | fs_count | LE32 | number of full-speed descriptors | 124 + * +-----+-----------+--------------+--------------------------------------+ 143 125 * | | hs_count | LE32 | number of high-speed descriptors | 126 + * +-----+-----------+--------------+--------------------------------------+ 144 127 * | | ss_count | LE32 | number of super-speed descriptors | 128 + * +-----+-----------+--------------+--------------------------------------+ 145 129 * | | os_count | LE32 | number of MS OS descriptors | 130 + * +-----+-----------+--------------+--------------------------------------+ 146 131 * | | fs_descrs | Descriptor[] | list of full-speed descriptors | 132 + * +-----+-----------+--------------+--------------------------------------+ 147 133 * | | hs_descrs | Descriptor[] | list of high-speed descriptors | 134 + * +-----+-----------+--------------+--------------------------------------+ 148 135 * | | ss_descrs | Descriptor[] | list of super-speed descriptors | 136 + * +-----+-----------+--------------+--------------------------------------+ 149 137 * | | os_descrs | OSDesc[] | list of MS OS descriptors | 138 + * +-----+-----------+--------------+--------------------------------------+ 150 139 * 151 140 * Depending on which flags are set, various fields may be missing in the 152 141 * structure. Any flags that are not recognised cause the whole block to be ··· 169 128 * 170 129 * Legacy descriptors format (deprecated as of 3.14): 171 130 * 131 + * +-----+-----------+--------------+--------------------------------------+ 172 132 * | off | name | type | description | 173 - * |-----+-----------+--------------+--------------------------------------| 133 + * +-----+-----------+--------------+--------------------------------------+ 174 134 * | 0 | magic | LE32 | FUNCTIONFS_DESCRIPTORS_MAGIC | 135 + * +-----+-----------+--------------+--------------------------------------+ 175 136 * | 4 | length | LE32 | length of the whole data chunk | 137 + * +-----+-----------+--------------+--------------------------------------+ 176 138 * | 8 | fs_count | LE32 | number of full-speed descriptors | 139 + * +-----+-----------+--------------+--------------------------------------+ 177 140 * | 12 | hs_count | LE32 | number of high-speed descriptors | 141 + * +-----+-----------+--------------+--------------------------------------+ 178 142 * | 16 | fs_descrs | Descriptor[] | list of full-speed descriptors | 143 + * +-----+-----------+--------------+--------------------------------------+ 179 144 * | | hs_descrs | Descriptor[] | list of high-speed descriptors | 145 + * +-----+-----------+--------------+--------------------------------------+ 180 146 * 181 147 * All numbers must be in little endian order. 182 148 * 183 149 * Descriptor[] is an array of valid USB descriptors which have the following 184 150 * format: 185 151 * 152 + * +-----+-----------------+------+--------------------------+ 186 153 * | off | name | type | description | 187 - * |-----+-----------------+------+--------------------------| 154 + * +-----+-----------------+------+--------------------------+ 188 155 * | 0 | bLength | U8 | length of the descriptor | 156 + * +-----+-----------------+------+--------------------------+ 189 157 * | 1 | bDescriptorType | U8 | descriptor type | 158 + * +-----+-----------------+------+--------------------------+ 190 159 * | 2 | payload | | descriptor's payload | 160 + * +-----+-----------------+------+--------------------------+ 191 161 * 192 162 * OSDesc[] is an array of valid MS OS Feature Descriptors which have one of 193 163 * the following formats: 194 164 * 165 + * +-----+-----------------+------+--------------------------+ 195 166 * | off | name | type | description | 196 - * |-----+-----------------+------+--------------------------| 167 + * +-----+-----------------+------+--------------------------+ 197 168 * | 0 | inteface | U8 | related interface number | 169 + * +-----+-----------------+------+--------------------------+ 198 170 * | 1 | dwLength | U32 | length of the descriptor | 171 + * +-----+-----------------+------+--------------------------+ 199 172 * | 5 | bcdVersion | U16 | currently supported: 1 | 173 + * +-----+-----------------+------+--------------------------+ 200 174 * | 7 | wIndex | U16 | currently supported: 4 | 175 + * +-----+-----------------+------+--------------------------+ 201 176 * | 9 | bCount | U8 | number of ext. compat. | 177 + * +-----+-----------------+------+--------------------------+ 202 178 * | 10 | Reserved | U8 | 0 | 179 + * +-----+-----------------+------+--------------------------+ 203 180 * | 11 | ExtCompat[] | | list of ext. compat. d. | 181 + * +-----+-----------------+------+--------------------------+ 204 182 * 183 + * +-----+-----------------+------+--------------------------+ 205 184 * | off | name | type | description | 206 - * |-----+-----------------+------+--------------------------| 185 + * +-----+-----------------+------+--------------------------+ 207 186 * | 0 | inteface | U8 | related interface number | 187 + * +-----+-----------------+------+--------------------------+ 208 188 * | 1 | dwLength | U32 | length of the descriptor | 189 + * +-----+-----------------+------+--------------------------+ 209 190 * | 5 | bcdVersion | U16 | currently supported: 1 | 191 + * +-----+-----------------+------+--------------------------+ 210 192 * | 7 | wIndex | U16 | currently supported: 5 | 193 + * +-----+-----------------+------+--------------------------+ 211 194 * | 9 | wCount | U16 | number of ext. compat. | 195 + * +-----+-----------------+------+--------------------------+ 212 196 * | 11 | ExtProp[] | | list of ext. prop. d. | 197 + * +-----+-----------------+------+--------------------------+ 213 198 * 214 199 * ExtCompat[] is an array of valid Extended Compatiblity descriptors 215 200 * which have the following format: 216 201 * 202 + * +-----+-----------------------+------+-------------------------------------+ 217 203 * | off | name | type | description | 218 - * |-----+-----------------------+------+-------------------------------------| 204 + * +-----+-----------------------+------+-------------------------------------+ 219 205 * | 0 | bFirstInterfaceNumber | U8 | index of the interface or of the 1st| 206 + * +-----+-----------------------+------+-------------------------------------+ 220 207 * | | | | interface in an IAD group | 208 + * +-----+-----------------------+------+-------------------------------------+ 221 209 * | 1 | Reserved | U8 | 1 | 210 + * +-----+-----------------------+------+-------------------------------------+ 222 211 * | 2 | CompatibleID | U8[8]| compatible ID string | 212 + * +-----+-----------------------+------+-------------------------------------+ 223 213 * | 10 | SubCompatibleID | U8[8]| subcompatible ID string | 214 + * +-----+-----------------------+------+-------------------------------------+ 224 215 * | 18 | Reserved | U8[6]| 0 | 216 + * +-----+-----------------------+------+-------------------------------------+ 225 217 * 226 218 * ExtProp[] is an array of valid Extended Properties descriptors 227 219 * which have the following format: 228 220 * 221 + * +-----+-----------------------+------+-------------------------------------+ 229 222 * | off | name | type | description | 230 - * |-----+-----------------------+------+-------------------------------------| 223 + * +-----+-----------------------+------+-------------------------------------+ 231 224 * | 0 | dwSize | U32 | length of the descriptor | 225 + * +-----+-----------------------+------+-------------------------------------+ 232 226 * | 4 | dwPropertyDataType | U32 | 1..7 | 227 + * +-----+-----------------------+------+-------------------------------------+ 233 228 * | 8 | wPropertyNameLength | U16 | bPropertyName length (NL) | 229 + * +-----+-----------------------+------+-------------------------------------+ 234 230 * | 10 | bPropertyName |U8[NL]| name of this property | 231 + * +-----+-----------------------+------+-------------------------------------+ 235 232 * |10+NL| dwPropertyDataLength | U32 | bPropertyData length (DL) | 233 + * +-----+-----------------------+------+-------------------------------------+ 236 234 * |14+NL| bProperty |U8[DL]| payload of this property | 235 + * +-----+-----------------------+------+-------------------------------------+ 237 236 */ 238 237 239 238 struct usb_functionfs_strings_head {