descriptors(9)
π 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) β literallyFUNCTIONFS_DESCRIPTORS_MAGIC_V2β¨off 4Β·length(LE32) β length of the whole data chunkoff 8Β·flags(LE32) β combination offunctionfs_flagseventfd(LE32) β eventfd file descriptorfs_count(LE32) β number of full-speed descriptorshs_count(LE32) β number of high-speed descriptorsss_count(LE32) β number of super-speed descriptorsos_count(LE32) β number of MS OS descriptorsfs_descrs(Descriptor[]) β list of full-speed descriptorshs_descrs(Descriptor[]) β list of high-speed descriptorsss_descrs(Descriptor[]) β list of super-speed descriptorsos_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_MAGICoff 4Β·length(LE32) β length of the whole data chunkoff 8Β·fs_count(LE32) β number of full-speed descriptorsoff 12Β·hs_count(LE32) β number of high-speed descriptorsoff 16Β·fs_descrs(Descriptor[]) β list of full-speed descriptorshs_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 descriptoroff 1Β·bDescriptorType(U8) β descriptor typeoff 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 numberoff 1Β·dwLength(U32) β length of the descriptoroff 5Β·bcdVersion(U16) β currently supported:1off 7Β·wIndex(U16) β currently supported:4off 9Β·bCount(U8) β number of ext. compat.off 10Β·Reserved(U8) β0off 11Β·ExtCompat[]β list of ext. compat. d.
π Format the second
off 0Β·interface(U8) β related interface numberoff 1Β·dwLength(U32) β length of the descriptoroff 5Β·bcdVersion(U16) β currently supported:1off 7Β·wIndex(U16) β currently supported:5off 9Β·wCount(U16) β number of ext. compat.off 11Β·ExtProp[]β list of ext. prop. d.
the difference is lowkey everything:wIndexis4vs5,bCount(U8) vswCount(U16), andExtCompat[]vsExtProp[]. 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 groupoff 1Β·Reserved(U8) β1off 2Β·CompatibleID(U8[8]) β compatible ID stringoff 10Β·SubCompatibleID(U8[8]) β subcompatible ID stringoff 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 descriptoroff 4Β·dwPropertyDataType(U32) β1..7off 8Β·wPropertyNameLength(U16) βbPropertyNamelength (NL)off 10Β·bPropertyName(U8[NL]) β name of this propertyoff 10+NLΒ·dwPropertyDataLength(U32) βbPropertyDatalength (DL)off 14+NLΒ·bProperty(U8[DL]) β payload of this property
see theNLin there? that's thebPropertyNamelength, so10+NLand14+NLslide 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.hstructusb_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
- nixpkgs unstable: linux-manual 7.3.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms