descriptors(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

πŸ’… descriptors

okay bestie, so this page is from the Kernel API Manual, and it's literally the descriptors(9) glow-up guide πŸŽ€ β€” like, the whole blueprint for the FunctionFS descriptors blob that gets handed to the kernel. it's giving "spreadsheet but make it USB" and honestly? iconic. let's get into it ✨


🌸 Descriptors format

this is the current, main-character layout of the blob, bestie:

  • off 0 Β· magic (LE32) β€” literally FUNCTIONFS_DESCRIPTORS_MAGIC_V2 ✨
  • off 4 Β· length (LE32) β€” length of the whole data chunk
  • off 8 Β· flags (LE32) β€” combination of functionfs_flags
  • eventfd (LE32) β€” eventfd file descriptor
  • fs_count (LE32) β€” number of full-speed descriptors
  • hs_count (LE32) β€” number of high-speed descriptors
  • ss_count (LE32) β€” number of super-speed descriptors
  • os_count (LE32) β€” number of MS OS descriptors
  • fs_descrs (Descriptor[]) β€” list of full-speed descriptors
  • hs_descrs (Descriptor[]) β€” list of high-speed descriptors
  • ss_descrs (Descriptor[]) β€” list of super-speed descriptors
  • os_descrs (OSDesc[]) β€” list of MS OS descriptors
ngl the first three are the only ones with a fixed off in the chart β€” the rest are just vibing below, no offset given. that's not me skipping them, that's literally how the page is laid out, i'm just the messenger 🫢

and here's the tea β˜• depending on which flags are set, various fields may legitimately be missing in the structure. no, that's not a bug, it's a vibe check.

but 🚨 any flags that are not recognised cause the whole block to be rejected with -ENOSYS. the entire thing. dumped. no cap. so don't be cute with random flag bits πŸ’€


πŸ¦‹ Legacy descriptors format (deprecated as of 3.14)

okay so this is the old one, and it's deprecated as of 3.14 β€” so like, respect the history, but don't show up to the party wearing it πŸ™ˆ

  • off 0 Β· magic (LE32) β€” FUNCTIONFS_DESCRIPTORS_MAGIC
  • off 4 Β· length (LE32) β€” length of the whole data chunk
  • off 8 Β· fs_count (LE32) β€” number of full-speed descriptors
  • off 12 Β· hs_count (LE32) β€” number of high-speed descriptors
  • off 16 Β· fs_descrs (Descriptor[]) β€” list of full-speed descriptors
  • hs_descrs (Descriptor[]) β€” list of high-speed descriptors

✨ Endianness, the one rule

all numbers must be in little endian order. all of them. every single one. this is not a suggestion, this is the law πŸ’…


πŸŽ€ Descriptor[]

so Descriptor[] is an array of valid USB descriptors, and each one has this format:

  • off 0 Β· bLength (U8) β€” length of the descriptor
  • off 1 Β· bDescriptorType (U8) β€” descriptor type
  • off 2 Β· payload β€” descriptor's payload

πŸ‘‘ OSDesc[]

OSDesc[] is an array of valid MS OS Feature Descriptors, and it has one of two formats β€” yes, two, pick your fighter:

🌈 Format the first

  • off 0 Β· interface (U8) β€” related interface number
  • off 1 Β· dwLength (U32) β€” length of the descriptor
  • off 5 Β· bcdVersion (U16) β€” currently supported: 1
  • off 7 Β· wIndex (U16) β€” currently supported: 4
  • off 9 Β· bCount (U8) β€” number of ext. compat.
  • off 10 Β· Reserved (U8) β€” 0
  • off 11 Β· ExtCompat[] β€” list of ext. compat. d.

🌈 Format the second

  • off 0 Β· interface (U8) β€” related interface number
  • off 1 Β· dwLength (U32) β€” length of the descriptor
  • off 5 Β· bcdVersion (U16) β€” currently supported: 1
  • off 7 Β· wIndex (U16) β€” currently supported: 5
  • off 9 Β· wCount (U16) β€” number of ext. compat.
  • off 11 Β· ExtProp[] β€” list of ext. prop. d.
the difference is lowkey everything: wIndex is 4 vs 5, bCount (U8) vs wCount (U16), and ExtCompat[] vs ExtProp[]. don't mix them up, bestie 😭

🧚 ExtCompat[]

ExtCompat[] is an array of valid Extended Compatibility descriptors, and each one goes like this:

  • off 0 Β· bFirstInterfaceNumber (U8) β€” index of the interface or of the 1st interface in an IAD group
  • off 1 Β· Reserved (U8) β€” 1
  • off 2 Β· CompatibleID (U8[8]) β€” compatible ID string
  • off 10 Β· SubCompatibleID (U8[8]) β€” subcompatible ID string
  • off 18 Β· Reserved (U8[6]) β€” 0

πŸ“ ExtProp[]

ExtProp[] is an array of valid Extended Properties descriptors, and this one's a little spicy with the math so bear with me 🌸

  • off 0 Β· dwSize (U32) β€” length of the descriptor
  • off 4 Β· dwPropertyDataType (U32) β€” 1..7
  • off 8 Β· wPropertyNameLength (U16) β€” bPropertyName length (NL)
  • off 10 Β· bPropertyName (U8[NL]) β€” name of this property
  • off 10+NL Β· dwPropertyDataLength (U32) β€” bPropertyData length (DL)
  • off 14+NL Β· bProperty (U8[DL]) β€” payload of this property
see the NL in there? that's the bPropertyName length, so 10+NL and 14+NL slide around depending on how long your property name is. the way that it's variable-length is honestly so real of it πŸ¦‹

πŸ’œ SEE ALSO

  • Kernel file ./include/uapi/linux/usb/functionfs.h struct usb_dfu_functional_descriptor(9)
  • struct usb_ffs_dmabuf_transfer_req(9)

okay that's the whole page, you ate that πŸ’… go forth and lay out your descriptors correctly, bestie. this was descriptors(9) from ./include/uapi/linux/usb, dated October 2026, and it slayed fr fr βœ¨πŸŽ€πŸ‘‘

πŸ“¦ where this page comes from