# Copyright 2019 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

# General redefinitions, taken from the Linux headers.

# ch9.h
define USB_DIR_OUT	0
define USB_DIR_IN	0x80
define USB_TYPE_MASK	(0x03 << 5)
define USB_TYPE_STANDARD	(0x00 << 5)
define USB_TYPE_CLASS	(0x01 << 5)
define USB_TYPE_VENDOR	(0x02 << 5)
define USB_TYPE_RESERVED	(0x03 << 5)
define USB_DT_DEVICE	0x01
define USB_DT_CONFIG	0x02
define USB_DT_STRING	0x03
define USB_DT_INTERFACE	0x04
define USB_DT_ENDPOINT	0x05
define USB_DT_DEVICE_QUALIFIER	0x06
define USB_DT_OTHER_SPEED_CONFIG	0x07
define USB_DT_INTERFACE_POWER	0x08
define USB_DT_OTG	0x09
define USB_DT_DEBUG	0x0a
define USB_DT_INTERFACE_ASSOCIATION	0x0b
define USB_DT_SECURITY	0x0c
define USB_DT_KEY	0x0d
define USB_DT_ENCRYPTION_TYPE	0x0e
define USB_DT_BOS	0x0f
define USB_DT_DEVICE_CAPABILITY	0x10
define USB_DT_WIRELESS_ENDPOINT_COMP	0x11
define USB_DT_WIRE_ADAPTER	0x21
define USB_DT_RPIPE	0x22
define USB_DT_CS_RADIO_CONTROL	0x23
define USB_DT_PIPE_USAGE	0x24
define USB_DT_SS_ENDPOINT_COMP	0x30
define USB_DT_SSP_ISOC_ENDPOINT_COMP	0x31
define USB_DT_CS_DEVICE	(USB_TYPE_CLASS | USB_DT_DEVICE)
define USB_DT_CS_CONFIG	(USB_TYPE_CLASS | USB_DT_CONFIG)
define USB_DT_CS_STRING	(USB_TYPE_CLASS | USB_DT_STRING)
define USB_DT_CS_INTERFACE	(USB_TYPE_CLASS | USB_DT_INTERFACE)
define USB_DT_CS_ENDPOINT	(USB_TYPE_CLASS | USB_DT_ENDPOINT)
define USB_CLASS_PER_INTERFACE	0
define USB_CLASS_AUDIO	1
define USB_CLASS_COMM	2
define USB_CLASS_HID	3
define USB_CLASS_PHYSICAL	5
define USB_CLASS_STILL_IMAGE	6
define USB_CLASS_PRINTER	7
define USB_CLASS_MASS_STORAGE	8
define USB_CLASS_HUB	9
define USB_CLASS_CDC_DATA	0x0a
define USB_CLASS_CSCID	0x0b
define USB_CLASS_CONTENT_SEC	0x0d
define USB_CLASS_VIDEO	0x0e
define USB_CLASS_WIRELESS_CONTROLLER	0xe0
define USB_CLASS_MISC	0xef
define USB_CLASS_APP_SPEC	0xfe
define USB_CLASS_VENDOR_SPEC	0xff
define USB_SUBCLASS_VENDOR_SPEC	0xff
define USB_ENDPOINT_NUMBER_MASK	0x0f
define USB_ENDPOINT_DIR_MASK	0x80
define USB_ENDPOINT_XFERTYPE_MASK	0x03
define USB_ENDPOINT_XFER_CONTROL	0
define USB_ENDPOINT_XFER_ISOC	1
define USB_ENDPOINT_XFER_BULK	2
define USB_ENDPOINT_XFER_INT	3
define USB_ENDPOINT_MAX_ADJUSTABLE	0x80
define USB_ENDPOINT_MAXP_MASK	0x07ff
define USB_EP_MAXP_MULT_SHIFT	11
define USB_EP_MAXP_MULT_MASK	(3 << USB_EP_MAXP_MULT_SHIFT)
define USB_ENDPOINT_INTRTYPE	0x30
define USB_ENDPOINT_INTR_PERIODIC	(0 << 4)
define USB_ENDPOINT_INTR_NOTIFICATION	(1 << 4)
define USB_ENDPOINT_SYNCTYPE	0x0c
define USB_ENDPOINT_SYNC_NONE	(0 << 2)
define USB_ENDPOINT_SYNC_ASYNC	(1 << 2)
define USB_ENDPOINT_SYNC_ADAPTIVE	(2 << 2)
define USB_ENDPOINT_SYNC_SYNC	(3 << 2)
define USB_ENDPOINT_USAGE_MASK	0x30
define USB_ENDPOINT_USAGE_DATA	0x00
define USB_ENDPOINT_USAGE_FEEDBACK	0x10
define USB_ENDPOINT_USAGE_IMPLICIT_FB	0x20

# hid.h
define USB_INTERFACE_CLASS_HID	3
define USB_INTERFACE_SUBCLASS_BOOT	1
define USB_INTERFACE_PROTOCOL_KEYBOARD	1
define USB_INTERFACE_PROTOCOL_MOUSE	2
define HID_REQ_GET_REPORT	0x01
define HID_REQ_GET_IDLE	0x02
define HID_REQ_GET_PROTOCOL	0x03
define HID_REQ_SET_REPORT	0x09
define HID_REQ_SET_IDLE	0x0A
define HID_REQ_SET_PROTOCOL	0x0B
define HID_DT_HID	(USB_TYPE_CLASS | 0x01)
define HID_DT_REPORT	(USB_TYPE_CLASS | 0x02)
define HID_DT_PHYSICAL	(USB_TYPE_CLASS | 0x03)
define HID_MAX_DESCRIPTOR_SIZE	4096

# cdc.h
define USB_CDC_HEADER_TYPE	0x00
define USB_CDC_CALL_MANAGEMENT_TYPE	0x01
define USB_CDC_ACM_TYPE	0x02
define USB_CDC_UNION_TYPE	0x06
define USB_CDC_COUNTRY_TYPE	0x07
define USB_CDC_NETWORK_TERMINAL_TYPE	0x0a
define USB_CDC_ETHERNET_TYPE	0x0f
define USB_CDC_WHCM_TYPE	0x11
define USB_CDC_MDLM_TYPE	0x12
define USB_CDC_MDLM_DETAIL_TYPE	0x13
define USB_CDC_DMM_TYPE	0x14
define USB_CDC_OBEX_TYPE	0x15
define USB_CDC_NCM_TYPE	0x1a
define USB_CDC_MBIM_TYPE	0x1b
define USB_CDC_MBIM_EXTENDED_TYPE	0x1c
define USB_CDC_PROTO_NONE	0

# ------------------------------------------------------------------------------

# This is a special fd for USB fuzzing and should only be used with syz_usb_* pseudo-syscalls.
# We don't inherit it from the fd resource, to discourage syzkaller calling raw ioctls on it.
resource fd_usb[int32]: -1

# These are generic pseudo-syscalls for emulating arbitrary USB devices.
# They are mostly targeted to cover the enumeration process.
syz_usb_connect(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000])
syz_usb_disconnect(fd fd_usb) (timeout[300])

define USB_SPEED_UNKNOWN	1
define USB_SPEED_LOW	2
define USB_SPEED_FULL	3
define USB_SPEED_HIGH	4
define USB_SPEED_WIRELESS	5
define USB_SPEED_SUPER	6
define USB_SPEED_SUPER_PLUS	7
usb_device_speed = USB_SPEED_UNKNOWN, USB_SPEED_LOW, USB_SPEED_FULL, USB_SPEED_HIGH, USB_SPEED_WIRELESS, USB_SPEED_SUPER, USB_SPEED_SUPER_PLUS

# TODO: consider patching idVendor and idProduct for all class specific descriptions in Go code to cover more drivers.
# TODO: custom syz_usb_ep_write() descriptions for all class specific descriptions.
# TODO: consider adding custom vusb_connect_descriptors definitions to all class specific descriptions.

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

define USB_DT_DEVICE_SIZE	18
type usb_device_descriptor_verbose_t[USB, CLASS, SUBCLASS, PROTOCOL, PACKET, VENDOR, PRODUCT, DEVICE, CFS] {
	bLength			const[USB_DT_DEVICE_SIZE, int8]
	bDescriptorType		const[USB_DT_DEVICE, int8]

	bcdUSB			USB
	bDeviceClass		const[CLASS, int8]
	bDeviceSubClass		const[SUBCLASS, int8]
	bDeviceProtocol		const[PROTOCOL, int8]
	bMaxPacketSize0		PACKET
	idVendor		const[VENDOR, int16]
	idProduct		const[PRODUCT, int16]
	bcdDevice		const[DEVICE, int16]
	iManufacturer		const[1, int8]
	iProduct		const[2, int8]
	iSerialNumber		const[3, int8]
	bNumConfigurations	len[configs, int8]

	configs			CFS
} [packed]

type usb_device_descriptor_t[CLASS, SUBCLASS, PROTOCOL, VENDOR, PRODUCT, DEVICE, CFS] usb_device_descriptor_verbose_t[flags[usb_versions, int16], CLASS, SUBCLASS, PROTOCOL, flags[usb_device_max_packet_sizes, int8], VENDOR, PRODUCT, DEVICE, CFS]

usb_versions = 0x110, 0x200, 0x201, 0x250, 0x300, 0x310

# https://elixir.bootlin.com/linux/v5.1.7/source/drivers/usb/core/hub.c#L4661
usb_device_max_packet_sizes = 8, 16, 32, 64, 255

define USB_DT_CONFIG_SIZE	9
type usb_config_descriptor_verbose_t[NUM, IFSNUM, ICONFIG, ATTRS, POWER, IFS] {
	bLength			const[USB_DT_CONFIG_SIZE, int8]
	bDescriptorType		const[USB_DT_CONFIG, int8]

	wTotalLength		len[parent, int16]
	bNumInterfaces		IFSNUM
	bConfigurationValue	NUM
	iConfiguration		ICONFIG
	bmAttributes		ATTRS
	bMaxPower		POWER

	interfaces		IFS
} [packed]

type usb_config_descriptor_t[NUM, IFSNUM, IFS] usb_config_descriptor_verbose_t[NUM, IFSNUM, int8, flags[usb_config_attributes, int8], int8, IFS]
type usb_config_descriptor_ifaces_array_t[NUM, IFS] usb_config_descriptor_t[NUM, len[interfaces, int8], IFS]

define USB_DT_INTERFACE_SIZE	9
type usb_interface_descriptor_verbose_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, IIF, EXTRA, EPS] {
	bLength			const[USB_DT_INTERFACE_SIZE, int8]
	bDescriptorType		const[USB_DT_INTERFACE, int8]

	bInterfaceNumber	IFNUM
	bAlternateSetting	ALTNUM
	bNumEndpoints		EPSNUM
	bInterfaceClass		CLASS
	bInterfaceSubClass	SUBCLASS
	bInterfaceProtocol	PROTOCOL
	iInterface		IIF

	extra			EXTRA
	endpoints		EPS
} [packed]

type usb_interface_descriptor_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_verbose_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, int8, EXTRA, EPS]
type usb_interface_descriptor_eps_array_t[IFNUM, ALTNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_t[IFNUM, ALTNUM, len[endpoints, int8], CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS]
type usb_interface_descriptor_fixed_t[IFNUM, ALTNUM, EPSNUM, CLASS, SUBCLASS, PROTOCOL, EXTRA, EPS] usb_interface_descriptor_verbose_t[const[IFNUM, int8], const[ALTNUM, int8], const[EPSNUM, int8], const[CLASS, int8], const[SUBCLASS, int8], const[PROTOCOL, int8], const[0, int8], EXTRA, EPS]

# TODO: non-audio endpoints have USB_DT_ENDPOINT_SIZE.
define USB_DT_ENDPOINT_AUDIO_SIZE	9
type usb_endpoint_descriptor_verbose_t[ADDR, ATTRS, PACKET, INTERVAL, REFRESH, SYNCH, EXTRA] {
	bLength			const[USB_DT_ENDPOINT_AUDIO_SIZE, int8]
	bDescriptorType		const[USB_DT_ENDPOINT, int8]

	bEndpointAddress	ADDR
	bmAttributes		ATTRS
	wMaxPacketSize		PACKET
	bInterval		INTERVAL

	bRefresh		REFRESH
	bSynchAddress		SYNCH

	extra			EXTRA
} [packed]

type usb_endpoint_descriptor_t[ADDR, ATTRS, EXTRA] usb_endpoint_descriptor_verbose_t[ADDR, ATTRS, flags[usb_endpoint_max_packet_sizes, int16], int8, int8, int8, EXTRA]

# TODO: dummy driver has complex requirements for packet sizes, account for those:
# https://elixir.bootlin.com/linux/v5.3.6/source/drivers/usb/gadget/udc/dummy_hcd.c#L497
usb_endpoint_max_packet_sizes = 8, 16, 32, 64, 512, 1023, 1024

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# Generic USB device, configuration, interface and endpoint descriptors.

# We only support one configuration per device.
# bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct
# and bcdDevice are patched by Go code, see sys/linux/init_vusb.go.
usb_device_descriptor {
	inner	usb_device_descriptor_t[0, 0, 0, 0, 0, 0, array[usb_config_descriptor, 1]]
} [packed]

usb_config_descriptor {
	inner	usb_config_descriptor_ifaces_array_t[int8, array[usb_interface_descriptor, 1:4]]
} [packed]

define USB_CONFIG_ATT_ONE	(1 << 7)
define USB_CONFIG_ATT_SELFPOWER	(1 << 6)
define USB_CONFIG_ATT_WAKEUP	(1 << 5)
define USB_CONFIG_ATT_BATTERY	(1 << 4)
usb_config_attributes = USB_CONFIG_ATT_ONE, USB_CONFIG_ATT_SELFPOWER, USB_CONFIG_ATT_WAKEUP, USB_CONFIG_ATT_BATTERY

# bInterfaceNumber, bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol
# are patched by Go code, see sys/linux/init_vusb.go.
usb_interface_descriptor {
	inner	usb_interface_descriptor_eps_array_t[int8, int8, const[0, int8], const[0, int8], const[0, int8], array[usb_interface_extra_descriptor, 0:2], array[usb_endpoint_descriptor, 0:16]]
} [packed]

usb_endpoint_descriptor {
	inner	usb_endpoint_descriptor_t[flags[usb_endpoint_addresses, int8], flags[usb_endpoint_attributes, int8], array[usb_endpoint_extra_descriptor, 0:2]]
} [packed]

usb_endpoint_addresses = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, USB_DIR_OUT, USB_DIR_IN

usb_endpoint_attributes = USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_ISOC, USB_ENDPOINT_XFER_BULK, USB_ENDPOINT_XFER_INT, USB_ENDPOINT_INTR_PERIODIC, USB_ENDPOINT_INTR_NOTIFICATION, USB_ENDPOINT_SYNC_NONE, USB_ENDPOINT_SYNC_ASYNC, USB_ENDPOINT_SYNC_ADAPTIVE, USB_ENDPOINT_SYNC_SYNC, USB_ENDPOINT_USAGE_DATA, USB_ENDPOINT_USAGE_FEEDBACK, USB_ENDPOINT_USAGE_FEEDBACK

vusb_connect_descriptors {
	qual_len	len[qual, int32]
	qual		ptr[in, usb_qualifier_descriptor]
	bos_len		len[bos, int32]
	bos		ptr[in, usb_bos_descriptor]
	strs_len	len[strs, int32]
	strs		array[vusb_connect_string_descriptor]
} [packed]

vusb_connect_string_descriptor {
	len	len[str, int32]
	str	ptr[in, usb_string_descriptor]
} [packed]

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# USB descriptors requested by the kernel before the SET_CONFIGURATION request.

# TODO: figure out when is the USB_DT_OTG descriptor used.
# TODO: figure out when is the USB_DT_INTERFACE_ASSOCIATION descriptor used.
# TODO: figure out when is the USB_DT_BOS descriptor used.

type usb_string_descriptor_t[DATA] {
	bLength		len[parent, int8]
	bDescriptorType	const[USB_DT_STRING, int8]

	data		DATA
} [packed]

usb_string_descriptor [
	lang_id	usb_string_descriptor_t[flags[usb_lang_ids, int16]]
	string	usb_string_descriptor_t[array[int8, 0:256]]
] [varlen]

usb_lang_ids = 0x436, 0x41c, 0x401, 0x801, 0xc01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001, 0x42b, 0x44d, 0x42c, 0x82c, 0x42d, 0x423, 0x445, 0x402, 0x455, 0x403, 0x404, 0x804, 0xc04, 0x1004, 0x1404, 0x41a, 0x405, 0x406, 0x413, 0x813, 0x409, 0x809, 0xc09, 0x1009, 0x1409, 0x1809, 0x1c09, 0x2009, 0x2409, 0x2809, 0x2c09, 0x3009, 0x3409, 0x425, 0x438, 0x429, 0x40b, 0x40c, 0x80c, 0xc0c, 0x100c, 0x140c, 0x180c, 0x437, 0x407, 0x807, 0xc07, 0x1007, 0x1407, 0x408, 0x447, 0x40d, 0x439, 0x40e, 0x40f, 0x421, 0x410, 0x810, 0x411, 0x44b, 0x860, 0x43f, 0x457, 0x412, 0x812, 0x426, 0x427, 0x827, 0x42f, 0x43e, 0x83e, 0x44c, 0x458, 0x44e, 0x861, 0x414, 0x814, 0x448, 0x415, 0x416, 0x816, 0x446, 0x418, 0x419, 0x44f, 0xc1a, 0x81a, 0x459, 0x41b, 0x424, 0x40a, 0x80a, 0xc0a, 0x100a, 0x140a, 0x180a, 0x1c0a, 0x200a, 0x240a, 0x280a, 0x2c0a, 0x300a, 0x340a, 0x380a, 0x3c0a, 0x400a, 0x440a, 0x480a, 0x4c0a, 0x500a, 0x430, 0x441, 0x41d, 0x81d, 0x449, 0x444, 0x44a, 0x41e, 0x41f, 0x422, 0x420, 0x820, 0x443, 0x843, 0x42a, 0x4ff, 0xf0ff, 0xf4ff, 0xf8ff, 0xfcff

usb_qualifier_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_DEVICE_QUALIFIER, int8]

	bcdUSB			flags[usb_versions, int16]
	bDeviceClass		int8
	bDeviceSubClass		int8
	bDeviceProtocol		int8
	bMaxPacketSize0		flags[usb_device_max_packet_sizes, int8]
	bNumConfigurations	int8
	bRESERVED		const[0, int8]
} [packed]

define USB_DT_BOS_SIZE	5

usb_bos_descriptor {
	bLength		const[USB_DT_BOS_SIZE, int8]
	bDescriptorType	const[USB_DT_BOS, int8]

	wTotalLength	len[parent, int16]
	bNumDeviceCaps	len[caps, int8]

	caps		array[usb_dev_cap, 0:6]
} [packed]

usb_dev_cap [
	generic		usb_generic_cap_descriptor
	wireless	usb_wireless_cap_descriptor
	ext_cap		usb_ext_cap_descriptor
	ss_cap		usb_ss_cap_descriptor
	ss_container_id	usb_ss_container_id_descriptor
	ssp_cap		usb_ssp_cap_descriptor
	ptm_cap		usb_ptm_cap_descriptor
] [varlen]

usb_generic_cap_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_DEVICE_CAPABILITY, int8]
	bDevCapabilityType	flags[usb_capability_types, int8]

	data			array[int8, 0:256]
} [packed]

define USB_CAP_TYPE_WIRELESS_USB	1
define USB_CAP_TYPE_EXT	2
define USB_SS_CAP_TYPE	3
define USB_SSP_CAP_TYPE	0xa
define CONTAINER_ID_TYPE	4
define USB_PTM_CAP_TYPE	0xb
usb_capability_types = USB_CAP_TYPE_WIRELESS_USB, USB_CAP_TYPE_EXT, USB_SS_CAP_TYPE, USB_SSP_CAP_TYPE, CONTAINER_ID_TYPE, USB_PTM_CAP_TYPE

usb_wireless_cap_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_DEVICE_CAPABILITY, int8]
	bDevCapabilityType	const[USB_CAP_TYPE_WIRELESS_USB, int8]

	bmAttributes		flags[usb_wireless_cap_attributes, int8]
	wPHYRates		flags[usb_wireless_cap_phyrates, int16]
	bmTFITXPowerInfo	int8
	bmFFITXPowerInfo	int8
	bmBandGroup		int16
	bReserved		int8
} [packed]

define USB_WIRELESS_P2P_DRD	(1 << 1)
define USB_WIRELESS_BEACON_MASK	(3 << 2)
define USB_WIRELESS_BEACON_SELF	(1 << 2)
define USB_WIRELESS_BEACON_DIRECTED	(2 << 2)
define USB_WIRELESS_BEACON_NONE	(3 << 2)
usb_wireless_cap_attributes = USB_WIRELESS_P2P_DRD, USB_WIRELESS_BEACON_MASK, USB_WIRELESS_BEACON_SELF, USB_WIRELESS_BEACON_DIRECTED, USB_WIRELESS_BEACON_NONE

define USB_WIRELESS_PHY_53	(1 << 0)
define USB_WIRELESS_PHY_80	(1 << 1)
define USB_WIRELESS_PHY_107	(1 << 2)
define USB_WIRELESS_PHY_160	(1 << 3)
define USB_WIRELESS_PHY_200	(1 << 4)
define USB_WIRELESS_PHY_320	(1 << 5)
define USB_WIRELESS_PHY_400	(1 << 6)
define USB_WIRELESS_PHY_480	(1 << 7)
usb_wireless_cap_phyrates = USB_WIRELESS_PHY_53, USB_WIRELESS_PHY_80, USB_WIRELESS_PHY_107, USB_WIRELESS_PHY_160, USB_WIRELESS_PHY_200, USB_WIRELESS_PHY_320, USB_WIRELESS_PHY_400, USB_WIRELESS_PHY_480

usb_ext_cap_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_DEVICE_CAPABILITY, int8]
	bDevCapabilityType	const[USB_CAP_TYPE_EXT, int8]

	bmAttributes1		flags[usb_ext_cap_attributes, int32:8]
	bmAttributes2		int32:4
	bmAttributes3		int32:4
	bmAttributes4		int32:16
} [packed]

define USB_LPM_SUPPORT	(1 << 1)
define USB_BESL_SUPPORT	(1 << 2)
define USB_BESL_BASELINE_VALID	(1 << 3)
define USB_BESL_DEEP_VALID	(1 << 4)
usb_ext_cap_attributes = USB_LPM_SUPPORT, USB_BESL_SUPPORT, USB_BESL_BASELINE_VALID, USB_BESL_DEEP_VALID

usb_ss_cap_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_DEVICE_CAPABILITY, int8]
	bDevCapabilityType	const[USB_SS_CAP_TYPE, int8]

	bmAttributes		flags[usb_ss_cap_attributes, int8]
	wSpeedSupported		flags[usb_ss_cap_speed, int16]
	bFunctionalitySupport	int8
	bU1devExitLat		int8
	bU2DevExitLat		int16
} [packed]

define USB_LTM_SUPPORT	(1 << 1)
usb_ss_cap_attributes = USB_LTM_SUPPORT

define USB_LOW_SPEED_OPERATION	(1)
define USB_FULL_SPEED_OPERATION	(1 << 1)
define USB_HIGH_SPEED_OPERATION	(1 << 2)
define USB_5GBPS_OPERATION	(1 << 3)
usb_ss_cap_speed = USB_LOW_SPEED_OPERATION, USB_FULL_SPEED_OPERATION, USB_HIGH_SPEED_OPERATION, USB_5GBPS_OPERATION

usb_ss_container_id_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_DEVICE_CAPABILITY, int8]
	bDevCapabilityType	const[CONTAINER_ID_TYPE, int8]

	bReserved		int8
	ContainerID		array[int8, 16]
} [packed]

usb_ssp_cap_descriptor {
	bLength				len[parent, int8]
	bDescriptorType			const[USB_DT_DEVICE_CAPABILITY, int8]
	bDevCapabilityType		const[USB_SSP_CAP_TYPE, int8]

	bReserved			int8
	bmAttributesSublinkSpeeds	len[bmSublinkSpeedAttr, int32:5]
	bmAttributesSpeedIDs		int32:27
	wFunctionalitySupport		flags[usb_ssp_cap_funcs, int16]
	wReserved			int16
	bmSublinkSpeedAttr		array[flags[usb_ssp_cap_sublink_speeds, int32], 0:6]
} [packed]

define USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID	(0xf)
define USB_SSP_MIN_RX_LANE_COUNT	(0xf << 8)
define USB_SSP_MIN_TX_LANE_COUNT	(0xf << 12)
usb_ssp_cap_funcs = USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID, USB_SSP_MIN_RX_LANE_COUNT, USB_SSP_MIN_TX_LANE_COUNT

define USB_SSP_SUBLINK_SPEED_SSID	(0xf)
define USB_SSP_SUBLINK_SPEED_LSE	(0x3 << 4)
define USB_SSP_SUBLINK_SPEED_ST	(0x3 << 6)
define USB_SSP_SUBLINK_SPEED_RSVD	(0x3f << 8)
define USB_SSP_SUBLINK_SPEED_LP	(0x3 << 14)
define USB_SSP_SUBLINK_SPEED_LSM	(0xff << 16)
usb_ssp_cap_sublink_speeds = USB_SSP_SUBLINK_SPEED_SSID, USB_SSP_SUBLINK_SPEED_LSE, USB_SSP_SUBLINK_SPEED_ST, USB_SSP_SUBLINK_SPEED_RSVD, USB_SSP_SUBLINK_SPEED_LP, USB_SSP_SUBLINK_SPEED_LSM

usb_ptm_cap_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_DEVICE_CAPABILITY, int8]
	bDevCapabilityType	const[USB_PTM_CAP_TYPE, int8]
} [packed]

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# Extra USB descriptors that come after an interface or an endpoint descriptor.

# TODO: consider removing class specific descriptors here for described classes.
usb_interface_extra_descriptor [
	generic		usb_generic_descriptor
	hid_hid		usb_hid_descriptor_hid
	cdc_ecm		usb_cdc_header_ecm
	cdc_ncm		usb_cdc_header_ncm
	uac_control	uac_control_iface_extra_descriptors
	uac_as		uac_as_iface_extra_descriptors
] [varlen]

usb_endpoint_extra_descriptor [
	generic	usb_generic_descriptor
	uac_iso	uac_iso_endpoint_descriptor
] [varlen]

usb_generic_descriptor {
	bLength		len[parent, int8]
	bDescriptorType	flags[usb_descriptor_types, int8]

	data		array[int8, 0:256]
} [packed]

usb_descriptor_types = USB_DT_DEVICE, USB_DT_CONFIG, USB_DT_STRING, USB_DT_INTERFACE, USB_DT_ENDPOINT, USB_DT_DEVICE_QUALIFIER, USB_DT_OTHER_SPEED_CONFIG, USB_DT_INTERFACE_POWER, USB_DT_OTG, USB_DT_DEBUG, USB_DT_INTERFACE_ASSOCIATION, USB_DT_SECURITY, USB_DT_KEY, USB_DT_ENCRYPTION_TYPE, USB_DT_BOS, USB_DT_DEVICE_CAPABILITY, USB_DT_WIRELESS_ENDPOINT_COMP, USB_DT_WIRE_ADAPTER, USB_DT_RPIPE, USB_DT_CS_RADIO_CONTROL, USB_DT_PIPE_USAGE, USB_DT_SS_ENDPOINT_COMP, USB_DT_SSP_ISOC_ENDPOINT_COMP, HID_DT_HID, HID_DT_REPORT, HID_DT_PHYSICAL

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# USB descriptors requested after the SET_CONFIGURATION request.

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# Replies to USB control requests requested after the SET_CONFIGURATION request.

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# HID device class specific descriptions.
# https://www.usb.org/sites/default/files/documents/hid1_11.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/hid/usbhid/hid-core.c
# https://elixir.bootlin.com/linux/latest/source/drivers/hid/hid-core.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/hid.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_hid.c

# Connected HID devices are known to create the following /dev/ files:
# /dev/hidraw#, /dev/usb/hiddev# and /dev/input/event#.

syz_usb_connect$hid(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_hid], conn_descs ptr[in, vusb_connect_descriptors]) fd (timeout[3000], prog_timeout[3000])

# idVendor and idProduct are patched by Go code, see sys/linux/init_vusb.go.
usb_device_descriptor_hid {
	inner	usb_device_descriptor_t[0, 0, 0, 0, 0, 64, array[usb_config_descriptor_hid, 1]]
} [packed]

usb_config_descriptor_hid {
	inner	usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_hid, 1]]
} [packed]

usb_interface_descriptor_hid {
	inner	usb_interface_descriptor_t[const[0, int8], int8, int8[1:2], const[USB_CLASS_HID, int8], const[USB_INTERFACE_SUBCLASS_BOOT, int8], flags[usb_hid_protocols, int8], usb_hid_descriptor_hid, usb_endpoint_descriptors_hid]
} [packed]

usb_hid_protocols = USB_INTERFACE_PROTOCOL_KEYBOARD, USB_INTERFACE_PROTOCOL_MOUSE

usb_endpoint_descriptors_hid {
	in	usb_endpoint_descriptor_hid_in
	out	array[usb_endpoint_descriptor_hid_out, 0:1]
} [packed]

usb_endpoint_descriptor_hid_in {
	inner	usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_IN_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], void]
} [packed]

usb_endpoint_descriptor_hid_out {
	inner	usb_endpoint_descriptor_t[const[USB_ENDPOINT_HID_OUT_ADDRESS, int8], const[USB_ENDPOINT_HID_ATTRIBUTES, int8], void]
} [packed]

define USB_ENDPOINT_HID_ATTRIBUTES	(USB_ENDPOINT_XFER_INT)
define USB_ENDPOINT_HID_IN_ADDRESS	(1 | USB_DIR_IN)
define USB_ENDPOINT_HID_OUT_ADDRESS	(2)

# USB HID specifications allows for multiple report and physical descriptors
# to be present, but I don't see any support for them in the Linux kernel,
# except for a single report descriptor.
usb_hid_descriptor_hid {
	bLength		len[parent, int8]
	bDescriptorType	const[HID_DT_HID, int8]

	bcdHID		int16
	bCountryCode	int8
	bNumDescriptors	const[1, int8]

	report_desc	usb_hid_class_descriptor_report
} [packed]

usb_hid_class_descriptor_report {
	bDescriptorType		const[HID_DT_REPORT, int8]
	wDescriptorLength	int16[0:HID_MAX_DESCRIPTOR_SIZE]
} [packed]

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# PRINTER device class specific descriptions.
# https://www.usb.org/sites/default/files/usbprint11a021811.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/class/usblp.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/printer.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_printer.c

# Connected PRINTER devices are known to create the following /dev/ files:
# /dev/usb/lp#.
# TODO: write descriptions for those.

# drivers/usb/class/usblp.c
define USBLP_REQ_GET_ID	0x00
define USBLP_REQ_GET_STATUS	0x01
define USBLP_REQ_RESET	0x02
define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST	0x00
define USBLP_FIRST_PROTOCOL	1
define USBLP_LAST_PROTOCOL	3

syz_usb_connect$printer(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_printer], conn_descs ptr[in, vusb_connect_descriptors]) fd (timeout[3000], prog_timeout[3000])

usb_device_descriptor_printer {
	inner	usb_device_descriptor_t[0, 0, 0, 0x525, 0xa4a8, 64, array[usb_config_descriptor_printer, 1]]
} [packed]

usb_config_descriptor_printer {
	inner	usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_printer, 1]]
} [packed]

usb_interface_descriptor_printer {
	inner	usb_interface_descriptor_t[const[0, int8], int8, int8[1:2], const[USB_CLASS_PRINTER, int8], const[1, int8], int8[USBLP_FIRST_PROTOCOL:USBLP_LAST_PROTOCOL], void, usb_endpoint_descriptors_printer]
} [packed]

usb_endpoint_descriptors_printer {
	in	usb_endpoint_descriptor_printer_out
	out	array[usb_endpoint_descriptor_printer_in, 0:1]
} [packed]

usb_endpoint_descriptor_printer_out {
	inner	usb_endpoint_descriptor_t[const[USB_ENDPOINT_PRINTER_OUT_ADDRESS, int8], const[USB_ENDPOINT_PRINTER_ATTRIBUTES, int8], void]
} [packed]

usb_endpoint_descriptor_printer_in {
	inner	usb_endpoint_descriptor_t[const[USB_ENDPOINT_PRINTER_IN_ADDRESS, int8], const[USB_ENDPOINT_PRINTER_ATTRIBUTES, int8], void]
} [packed]

define USB_ENDPOINT_PRINTER_ATTRIBUTES	(USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_PRINTER_OUT_ADDRESS	(1)
define USB_ENDPOINT_PRINTER_IN_ADDRESS	(2 | USB_DIR_IN)

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# CDC ECM (Ethernet) device class specific descriptions.
# https://www.usb.org/document-library/class-definitions-communication-devices-12
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/cdc_ether.c
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/usbnet.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/ether.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_ecm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/u_ether.c

# Connected CDC ECM devices are known to create usbN network interfaces.
# TODO: write descriptions for those.

syz_usb_connect$cdc_ecm(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_cdc_ecm], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000])

usb_device_descriptor_cdc_ecm {
	inner	usb_device_descriptor_t[USB_CLASS_COMM, 0, 0, 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ecm, 1]]
} [packed]

usb_config_descriptor_cdc_ecm {
	inner	usb_config_descriptor_ifaces_array_t[const[1, int8], array[usb_interface_descriptor_cdc_ecm, 1]]
} [packed]

define USB_CDC_SUBCLASS_ACM	0x02
define USB_CDC_SUBCLASS_ETHERNET	0x06
define USB_CDC_SUBCLASS_WHCM	0x08
define USB_CDC_SUBCLASS_DMM	0x09
define USB_CDC_SUBCLASS_MDLM	0x0a
define USB_CDC_SUBCLASS_OBEX	0x0b
define USB_CDC_SUBCLASS_EEM	0x0c
define USB_CDC_SUBCLASS_NCM	0x0d
define USB_CDC_SUBCLASS_MBIM	0x0e

# Per specification CDC ECM devices have two interfaces (control and data),
# but here we're merging them into one for simplicity since Linux supports that.
usb_interface_descriptor_cdc_ecm {
	inner	usb_interface_descriptor_t[const[0, int8], int8, int8[2:3], const[USB_CLASS_COMM, int8], const[USB_CDC_SUBCLASS_ETHERNET, int8], const[USB_CDC_PROTO_NONE, int8], usb_cdc_header_ecm, usb_endpoint_descriptors_cdc_ecm]
} [packed]

usb_endpoint_descriptors_cdc_ecm {
	notify	array[usb_endpoint_descriptor_cdc_ecm_notify, 0:1]
	in	usb_endpoint_descriptor_cdc_ecm_in
	out	usb_endpoint_descriptor_cdc_ecm_out
} [packed]

usb_endpoint_descriptor_cdc_ecm_notify {
	inner	usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_NOTIFY_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_NOTIFY_ATTRIBUTES, int8], void]
} [packed]

usb_endpoint_descriptor_cdc_ecm_in {
	inner	usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_IN_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], void]
} [packed]

usb_endpoint_descriptor_cdc_ecm_out {
	inner	usb_endpoint_descriptor_t[const[USB_ENDPOINT_CDC_ECM_OUT_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], void]
} [packed]

define USB_ENDPOINT_CDC_ECM_NOTIFY_ATTRIBUTES	(USB_ENDPOINT_XFER_INT)
define USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES	(USB_ENDPOINT_XFER_BULK)
define USB_ENDPOINT_CDC_ECM_NOTIFY_ADDRESS	(1 | USB_DIR_IN)
define USB_ENDPOINT_CDC_ECM_IN_ADDRESS	(2 | USB_DIR_IN)
define USB_ENDPOINT_CDC_ECM_OUT_ADDRESS	(3)

# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/usb/core/message.c#L2137
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ether.c#L155
usb_cdc_header_ecm {
	union	usb_cdc_union_desc_t[0, 0]
	header	usb_cdc_header_desc
	ether	usb_cdc_ether_desc

	other	array[usb_cdc_header_ecm_other, 0:6]
} [packed]

usb_cdc_header_ecm_other [
	call_mgmt		usb_cdc_call_mgmt_descriptor
	acm			usb_cdc_acm_descriptor
	country_functional	usb_cdc_country_functional_desc
	network_terminal	usb_cdc_network_terminal_desc
	dmm			usb_cdc_dmm_desc
	mdlm			usb_cdc_mdlm_desc
	mdlm_detail		usb_cdc_mdlm_detail_desc
	obex			usb_cdc_obex_desc
	ncm			usb_cdc_ncm_desc
	mbim			usb_cdc_mbim_desc
	mbim_extended		usb_cdc_mbim_extended_desc
] [varlen]

usb_cdc_header_desc {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[USB_CDC_HEADER_TYPE, int8]

	bcdCDC			int16
} [packed]

usb_cdc_call_mgmt_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[USB_CDC_CALL_MANAGEMENT_TYPE, int8]

	bmCapabilities		flags[usb_cdc_call_mgmt_caps, int8]
	bDataInterface		int8
} [packed]

define USB_CDC_CALL_MGMT_CAP_CALL_MGMT	0x01
define USB_CDC_CALL_MGMT_CAP_DATA_INTF	0x02
usb_cdc_call_mgmt_caps = USB_CDC_CALL_MGMT_CAP_CALL_MGMT, USB_CDC_CALL_MGMT_CAP_DATA_INTF

usb_cdc_acm_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[USB_CDC_ACM_TYPE, int8]

	bmCapabilities		flags[usb_cdc_acm_caps, int8]
} [packed]

define USB_CDC_COMM_FEATURE	0x01
define USB_CDC_CAP_LINE	0x02
define USB_CDC_CAP_BRK	0x04
define USB_CDC_CAP_NOTIFY	0x08
usb_cdc_acm_caps = USB_CDC_COMM_FEATURE, USB_CDC_CAP_LINE, USB_CDC_CAP_BRK, USB_CDC_CAP_NOTIFY

type usb_cdc_union_desc_t[MASTER, SLAVE] {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[USB_CDC_UNION_TYPE, int8]

	bMasterInterface0	const[MASTER, int8]
	bSlaveInterface0	const[SLAVE, int8]
	slave_interfaces	array[int8, 0:6]
} [packed]

usb_cdc_country_functional_desc {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[USB_CDC_COUNTRY_TYPE, int8]

	iCountryCodeRelDate	int8
	wCountyCode0		int16
	country_codes		array[int16, 0:6]
} [packed]

usb_cdc_network_terminal_desc {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[USB_CDC_NETWORK_TERMINAL_TYPE, int8]

	bEntityId		int8
	iName			int8
	bChannelIndex		int8
	bPhysicalInterface	int8
} [packed]

usb_cdc_ether_desc {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[USB_CDC_ETHERNET_TYPE, int8]

	iMACAddress		const[1, int8]
	bmEthernetStatistics	int32
	wMaxSegmentSize		int16
	wNumberMCFilters	int16
	bNumberPowerFilters	int8
} [packed]

usb_cdc_dmm_desc {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[USB_CDC_DMM_TYPE, int8]

	bcdVersion		int16
	wMaxCommand		int16
} [packed]

usb_cdc_mdlm_desc {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[USB_CDC_MDLM_TYPE, int8]

	bcdVersion		int16
	bGUID			usb_cdc_ecm_mbm_guid
} [packed]

# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ether.c#L61
usb_cdc_ecm_mbm_guid {
	id0	const[0x14f5e048ba817a3, int64]
	id1	const[0x2a397ecbffc007a6, int64]
} [packed]

usb_cdc_mdlm_detail_desc {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[USB_CDC_MDLM_DETAIL_TYPE, int8]

	bGuidDescriptorType	int8
	bDetailData		array[int8, 0:256]
} [packed]

usb_cdc_obex_desc {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[USB_CDC_OBEX_TYPE, int8]

	bcdVersion		int16
} [packed]

usb_cdc_ncm_desc {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[USB_CDC_NCM_TYPE, int8]

	bcdNcmVersion		int16
	bmNetworkCapabilities	flags[usb_cdc_ncm_ncaps, int8]
} [packed]

define USB_CDC_NCM_NCAP_ETH_FILTER	(1 << 0)
define USB_CDC_NCM_NCAP_NET_ADDRESS	(1 << 1)
define USB_CDC_NCM_NCAP_ENCAP_COMMAND	(1 << 2)
define USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE	(1 << 3)
define USB_CDC_NCM_NCAP_CRC_MODE	(1 << 4)
define USB_CDC_NCM_NCAP_NTB_INPUT_SIZE	(1 << 5)
usb_cdc_ncm_ncaps = USB_CDC_NCM_NCAP_ETH_FILTER, USB_CDC_NCM_NCAP_NET_ADDRESS, USB_CDC_NCM_NCAP_ENCAP_COMMAND, USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE, USB_CDC_NCM_NCAP_CRC_MODE, USB_CDC_NCM_NCAP_NTB_INPUT_SIZE

usb_cdc_mbim_desc {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[USB_CDC_MBIM_TYPE, int8]

	bcdMBIMVersion		int16
	wMaxControlMessage	int16
	bNumberFilters		int8
	bMaxFilterSize		int8
	wMaxSegmentSize		int16
	bmNetworkCapabilities	int8
} [packed]

usb_cdc_mbim_extended_desc {
	bLength				len[parent, int8]
	bDescriptorType			const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType		const[USB_CDC_MBIM_EXTENDED_TYPE, int8]

	bcdMBIMExtendedVersion		int16
	bMaxOutstandingCommandMessages	int8
	wMTU				int16
} [packed]

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# CDC NCM class specific descriptions.
# CDC NCM is based on CDC ECM, so some of the descriptions are reused.
# https://www.usb.org/document-library/network-control-model-devices-specification-v10-and-errata-and-adopters-agreement
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/cdc_ncm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/net/usb/usbnet.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/ncm.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_ncm.c

syz_usb_connect$cdc_ncm(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_cdc_ncm], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000])

usb_device_descriptor_cdc_ncm {
	inner	usb_device_descriptor_t[USB_CLASS_COMM, 0, 0, 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ncm, 1]]
} [packed]

usb_config_descriptor_cdc_ncm {
	inner	usb_config_descriptor_t[const[1, int8], const[2, int8], usb_interface_descriptors_cdc_ncm]
} [packed]

define CDC_NCM_COMM_ALTSETTING_NCM	0
define CDC_NCM_DATA_ALTSETTING_NCM	1

usb_interface_descriptors_cdc_ncm {
	control		usb_interface_descriptor_fixed_t[0, CDC_NCM_COMM_ALTSETTING_NCM, 1, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, usb_cdc_header_ncm, usb_endpoint_descriptor_cdc_ecm_notify]
	data_nop	usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, void, void]
	data		usb_interface_descriptor_fixed_t[1, CDC_NCM_DATA_ALTSETTING_NCM, 2, USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE, void, usb_endpoint_descriptors_cdc_ncm_data]
} [packed]

usb_endpoint_descriptors_cdc_ncm_data {
	in	usb_endpoint_descriptor_cdc_ecm_in
	out	usb_endpoint_descriptor_cdc_ecm_out
} [packed]

# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/usb/core/message.c#L2137
# https://elixir.bootlin.com/linux/v5.2.7/source/drivers/net/usb/cdc_ncm.c#L798
usb_cdc_header_ncm {
	union	usb_cdc_union_desc_t[0, 1]
	header	usb_cdc_header_desc
	ether	usb_cdc_ether_desc
	ncm	usb_cdc_ncm_desc

	other	array[usb_cdc_header_ncm_other, 0:6]
} [packed]

usb_cdc_header_ncm_other [
	call_mgmt		usb_cdc_call_mgmt_descriptor
	acm			usb_cdc_acm_descriptor
	country_functional	usb_cdc_country_functional_desc
	network_terminal	usb_cdc_network_terminal_desc
	dmm			usb_cdc_dmm_desc
	mdlm			usb_cdc_mdlm_desc
	mdlm_detail		usb_cdc_mdlm_detail_desc
	obex			usb_cdc_obex_desc
	mbim			usb_cdc_mbim_desc
	mbim_extended		usb_cdc_mbim_extended_desc
] [varlen]

# cdc.h
define USB_CDC_SEND_ENCAPSULATED_COMMAND	0x00
define USB_CDC_GET_ENCAPSULATED_RESPONSE	0x01
define USB_CDC_REQ_SET_LINE_CODING	0x20
define USB_CDC_REQ_GET_LINE_CODING	0x21
define USB_CDC_REQ_SET_CONTROL_LINE_STATE	0x22
define USB_CDC_REQ_SEND_BREAK	0x23
define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS	0x40
define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER	0x41
define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER	0x42
define USB_CDC_SET_ETHERNET_PACKET_FILTER	0x43
define USB_CDC_GET_ETHERNET_STATISTIC	0x44
define USB_CDC_GET_NTB_PARAMETERS	0x80
define USB_CDC_GET_NET_ADDRESS	0x81
define USB_CDC_SET_NET_ADDRESS	0x82
define USB_CDC_GET_NTB_FORMAT	0x83
define USB_CDC_SET_NTB_FORMAT	0x84
define USB_CDC_GET_NTB_INPUT_SIZE	0x85
define USB_CDC_SET_NTB_INPUT_SIZE	0x86
define USB_CDC_GET_MAX_DATAGRAM_SIZE	0x87
define USB_CDC_SET_MAX_DATAGRAM_SIZE	0x88
define USB_CDC_GET_CRC_MODE	0x89
define USB_CDC_SET_CRC_MODE	0x8a

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# UAC1 device class specific descriptions.
# https://www.usb.org/sites/default/files/audio10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/legacy/audio.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac1.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac1_legacy.c
# https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/usb/audio.h

# TODO: find out which /dev/ files are created by connected UAC1 devices and add descriptions for those.

syz_usb_connect$uac1(speed flags[usb_device_speed], dev_len len[dev], dev ptr[in, usb_device_descriptor_uac1], conn_descs ptr[in, vusb_connect_descriptors]) fd_usb (timeout[3000], prog_timeout[3000])

usb_device_descriptor_uac1 {
	inner	usb_device_descriptor_t[0, 0, 0, 0x1d6b, 0x101, 64, array[usb_config_descriptor_uac1, 1]]
} [packed]

usb_config_descriptor_uac1 {
	inner	usb_config_descriptor_t[const[1, int8], const[3, int8], usb_interface_descriptors_uac1]
} [packed]

# TODO: control interface might have and optional interrupt endpoint.
define USB_SUBCLASS_AUDIOCONTROL	0x01
define USB_SUBCLASS_AUDIOSTREAMING	0x02

usb_interface_descriptors_uac1 {
	control		usb_interface_descriptor_fixed_t[0, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOCONTROL, 0, uac_control_iface_extra_descriptors, void]
	as_out_alt_0	usb_interface_descriptor_fixed_t[1, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, void, void]
	as_out_alt_1	usb_interface_descriptor_fixed_t[1, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, uac_as_iface_extra_descriptors, uac_as_out_endpoint_descriptor]
	as_in_alt_0	usb_interface_descriptor_fixed_t[2, 0, 0, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, void, void]
	as_in_alt_1	usb_interface_descriptor_fixed_t[2, 1, 1, USB_CLASS_AUDIO, USB_SUBCLASS_AUDIOSTREAMING, 0, uac_as_iface_extra_descriptors, uac_as_in_endpoint_descriptor]
} [packed]

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# UAC uses IDs to make it possible for terminals and units to refer to each other.
# We don't have a way to describe this, so just use a limited number of ids.
type uac_id int8[1:6]

uac_control_iface_extra_descriptors {
	header	uac1_ac_header_descriptor_2
	others	array[uac_control_iface_extra_descriptor, 0:6]
} [packed]

uac_as_iface_extra_descriptors {
	others	array[uac_as_iface_extra_descriptor, 0:6]
} [packed]

uac_control_iface_extra_descriptor [
	input_terminal	uac_input_terminal_descriptor
	output_terminal	uac1_output_terminal_descriptor
	mixer_unit	uac_mixer_unit_descriptor
	selector_unit	uac_selector_unit_descriptor
	feature_unit	uac_feature_unit_descriptor
	processing_unit	uac_processing_unit_descriptor
	extension_unit	uac_extension_unit_descriptor
] [varlen]

uac_as_iface_extra_descriptor [
	as_header			uac1_as_header_descriptor
	format_type_i_continuous	uac_format_type_i_continuous_descriptor
	format_type_i_discrete		uac_format_type_i_discrete_descriptor
	format_type_ii_discrete		uac_format_type_ii_discrete_descriptor
] [varlen]

define F_AUDIO_NUM_INTERFACES	2
define UAC_DT_AC_HEADER_LENGTH	(8 + F_AUDIO_NUM_INTERFACES)

define UAC_HEADER	0x01
define UAC_INPUT_TERMINAL	0x02
define UAC_OUTPUT_TERMINAL	0x03
define UAC_MIXER_UNIT	0x04
define UAC_SELECTOR_UNIT	0x05
define UAC_FEATURE_UNIT	0x06
define UAC1_PROCESSING_UNIT	0x07
define UAC1_EXTENSION_UNIT	0x08

uac1_ac_header_descriptor_2 {
	bLength			const[UAC_DT_AC_HEADER_LENGTH, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[UAC_HEADER, int8]

	bcdADC			int16
	wTotalLength		int8
	bInCollection		const[F_AUDIO_NUM_INTERFACES, int8]

# These must match interfaces numbers.
	baInterfaceNr0		const[1, int8]
	baInterfaceNr1		const[2, int8]
} [packed]

uac_input_terminal_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[UAC_INPUT_TERMINAL, int8]

	bTerminalID		uac_id
	wTerminalType		flags[uac_input_terminal_types, int16]
	bAssocTerminal		uac_id
	bNrChannels		int8
	wChannelConfig		int16
	iChannelNames		int8
	iTerminal		int8
} [packed]

define UAC_TERMINAL_UNDEFINED	0x100
define UAC_TERMINAL_STREAMING	0x101
define UAC_TERMINAL_VENDOR_SPEC	0x1FF

define UAC_INPUT_TERMINAL_UNDEFINED	0x200
define UAC_INPUT_TERMINAL_MICROPHONE	0x201
define UAC_INPUT_TERMINAL_DESKTOP_MICROPHONE	0x202
define UAC_INPUT_TERMINAL_PERSONAL_MICROPHONE	0x203
define UAC_INPUT_TERMINAL_OMNI_DIR_MICROPHONE	0x204
define UAC_INPUT_TERMINAL_MICROPHONE_ARRAY	0x205
define UAC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY	0x206

define UAC_OUTPUT_TERMINAL_UNDEFINED	0x300
define UAC_OUTPUT_TERMINAL_SPEAKER	0x301
define UAC_OUTPUT_TERMINAL_HEADPHONES	0x302
define UAC_OUTPUT_TERMINAL_HEAD_MOUNTED_DISPLAY_AUDIO	0x303
define UAC_OUTPUT_TERMINAL_DESKTOP_SPEAKER	0x304
define UAC_OUTPUT_TERMINAL_ROOM_SPEAKER	0x305
define UAC_OUTPUT_TERMINAL_COMMUNICATION_SPEAKER	0x306
define UAC_OUTPUT_TERMINAL_LOW_FREQ_EFFECTS_SPEAKER	0x307

uac_input_terminal_types = UAC_TERMINAL_UNDEFINED, UAC_TERMINAL_STREAMING, UAC_TERMINAL_VENDOR_SPEC, UAC_INPUT_TERMINAL_UNDEFINED, UAC_INPUT_TERMINAL_MICROPHONE, UAC_INPUT_TERMINAL_DESKTOP_MICROPHONE, UAC_INPUT_TERMINAL_PERSONAL_MICROPHONE, UAC_INPUT_TERMINAL_OMNI_DIR_MICROPHONE, UAC_INPUT_TERMINAL_MICROPHONE_ARRAY, UAC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY

uac1_output_terminal_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[UAC_OUTPUT_TERMINAL, int8]

	bTerminalID		uac_id
	wTerminalType		flags[uac_output_terminal_types, int16]
	bAssocTerminal		uac_id
	bSourceID		uac_id
	iTerminal		int8
} [packed]

uac_output_terminal_types = UAC_TERMINAL_UNDEFINED, UAC_TERMINAL_STREAMING, UAC_TERMINAL_VENDOR_SPEC, UAC_OUTPUT_TERMINAL_UNDEFINED, UAC_OUTPUT_TERMINAL_SPEAKER, UAC_OUTPUT_TERMINAL_HEADPHONES, UAC_OUTPUT_TERMINAL_HEAD_MOUNTED_DISPLAY_AUDIO, UAC_OUTPUT_TERMINAL_DESKTOP_SPEAKER, UAC_OUTPUT_TERMINAL_ROOM_SPEAKER, UAC_OUTPUT_TERMINAL_COMMUNICATION_SPEAKER, UAC_OUTPUT_TERMINAL_LOW_FREQ_EFFECTS_SPEAKER

uac_mixer_unit_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[UAC_MIXER_UNIT, int8]

	bUnitID			uac_id
	bNrInPins		int8
	baSourceID		array[int8, 0:6]
} [packed]

uac_selector_unit_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[UAC_SELECTOR_UNIT, int8]

	bUnitID			uac_id
	bNrInPins		int8
	baSourceID		array[int8, 0:6]
} [packed]

uac_feature_unit_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[UAC_FEATURE_UNIT, int8]

	bUnitID			uac_id
	bSourceID		uac_id
	bControlSize		len[bmaControls, int8]
	bmaControls		array[flags[uac_feature_unit_controls, int16], 1:6]
	iFeature		int8
} [packed]

define UAC_FU_MUTE	0x01
define UAC_FU_VOLUME	0x02
define UAC_FU_BASS	0x03
define UAC_FU_MID	0x04
define UAC_FU_TREBLE	0x05
define UAC_FU_GRAPHIC_EQUALIZER	0x06
define UAC_FU_AUTOMATIC_GAIN	0x07
define UAC_FU_DELAY	0x08
define UAC_FU_BASS_BOOST	0x09
define UAC_FU_LOUDNESS	0x0a
uac_feature_unit_controls = UAC_FU_MUTE, UAC_FU_VOLUME, UAC_FU_BASS, UAC_FU_MID, UAC_FU_TREBLE, UAC_FU_GRAPHIC_EQUALIZER, UAC_FU_AUTOMATIC_GAIN, UAC_FU_DELAY, UAC_FU_BASS_BOOST, UAC_FU_LOUDNESS

uac_processing_unit_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[UAC1_PROCESSING_UNIT, int8]

	bUnitID			uac_id
	wProcessType		flags[uac_processing_unit_types, int16]
	bNrInPins		int8
	baSourceID		array[int8, 0:6]
} [packed]

define UAC_PROCESS_UNDEFINED	0x00
define UAC_PROCESS_UP_DOWNMIX	0x01
define UAC_PROCESS_DOLBY_PROLOGIC	0x02
define UAC_PROCESS_STEREO_EXTENDER	0x03
define UAC_PROCESS_REVERB	0x04
define UAC_PROCESS_CHORUS	0x05
define UAC_PROCESS_DYN_RANGE_COMP	0x06
uac_processing_unit_types = UAC_PROCESS_UNDEFINED, UAC_PROCESS_UP_DOWNMIX, UAC_PROCESS_DOLBY_PROLOGIC, UAC_PROCESS_STEREO_EXTENDER, UAC_PROCESS_REVERB, UAC_PROCESS_CHORUS, UAC_PROCESS_DYN_RANGE_COMP

uac_extension_unit_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[UAC1_EXTENSION_UNIT, int8]

	bUnitID			uac_id
	wProcessType		int16
	bNrInPins		int8
	baSourceID		array[int8, 0:6]
} [packed]

define UAC_AS_GENERAL	0x01
define UAC_FORMAT_TYPE	0x02
define UAC_FORMAT_SPECIFIC	0x03

uac1_as_header_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[UAC_AS_GENERAL, int8]

	bTerminalLink		int8
	bDelay			int8
	wFormatTag		flags[uac_format_types, int16]
} [packed]

define UAC_FORMAT_TYPE_UNDEFINED	0x0
define UAC_FORMAT_TYPE_I	0x1
define UAC_FORMAT_TYPE_II	0x2
define UAC_FORMAT_TYPE_III	0x3
define UAC_EXT_FORMAT_TYPE_I	0x81
define UAC_EXT_FORMAT_TYPE_II	0x82
define UAC_EXT_FORMAT_TYPE_III	0x83

define UAC_FORMAT_TYPE_I_UNDEFINED	0x0
define UAC_FORMAT_TYPE_I_PCM	0x1
define UAC_FORMAT_TYPE_I_PCM8	0x2
define UAC_FORMAT_TYPE_I_IEEE_FLOAT	0x3
define UAC_FORMAT_TYPE_I_ALAW	0x4
define UAC_FORMAT_TYPE_I_MULAW	0x5
define UAC_FORMAT_TYPE_II_MPEG	0x1001
define UAC_FORMAT_TYPE_II_AC3	0x1002
uac_format_types = UAC_FORMAT_TYPE_I_UNDEFINED, UAC_FORMAT_TYPE_I_PCM, UAC_FORMAT_TYPE_I_PCM8, UAC_FORMAT_TYPE_I_IEEE_FLOAT, UAC_FORMAT_TYPE_I_ALAW, UAC_FORMAT_TYPE_I_MULAW, UAC_FORMAT_TYPE_II_MPEG, UAC_FORMAT_TYPE_II_AC3

uac_format_type_i_continuous_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[UAC_FORMAT_TYPE, int8]

	bFormatType		const[UAC_FORMAT_TYPE_I, int8]
	bNrChannels		int8
	bSubframeSize		int8[1:4]
	bBitResolution		int8
	bSamFreqType		int8
	tLowerSamFreq		array[int8, 0:3]
	tUpperSamFreq		array[int8, 0:3]
} [packed]

uac_format_type_i_discrete_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[UAC_FORMAT_TYPE, int8]

	bFormatType		const[UAC_FORMAT_TYPE_I, int8]
	bNrChannels		int8
	bSubframeSize		int8[1:4]
	bBitResolution		int8
	bSamFreqType		int8
	tSamFreq		array[int8, 0:9]
} [packed]

uac_format_type_ii_discrete_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_INTERFACE, int8]
	bDescriptorSubType	const[UAC_FORMAT_TYPE, int8]

	bFormatType		const[UAC_FORMAT_TYPE_II, int8]
	wMaxBitRate		int16
	wSamplesPerFrame	int16
	bSamFreqType		int8
	tSamFreq		array[int8, 0:9]
} [packed]

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

uac_as_out_endpoint_descriptor {
	inner	usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_OUT_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac_iso_endpoint_descriptor]
} [packed]

uac_as_in_endpoint_descriptor {
	inner	usb_endpoint_descriptor_t[const[USB_ENDPOINT_UAC1_AS_IN_ADDRESS, int8], const[USB_ENDPOINT_UAC1_AS_ATTRIBUTES, int8], uac_iso_endpoint_descriptor]
} [packed]

define USB_ENDPOINT_UAC1_AS_OUT_ADDRESS	(1 | USB_DIR_OUT)
define USB_ENDPOINT_UAC1_AS_IN_ADDRESS	(2 | USB_DIR_IN)
define USB_ENDPOINT_UAC1_AS_ATTRIBUTES	(USB_ENDPOINT_SYNC_ADAPTIVE | USB_ENDPOINT_XFER_ISOC)

define UAC_EP_GENERAL	0x01

uac_iso_endpoint_descriptor {
	bLength			len[parent, int8]
	bDescriptorType		const[USB_DT_CS_ENDPOINT, int8]
	bDescriptorSubType	const[UAC_EP_GENERAL, int8]

	bmAttributes		flags[uac_iso_ep_attributes, int8]
	bLockDelayUnits		int8
	wLockDelay		int16
} [packed]

define UAC_EP_CS_ATTR_SAMPLE_RATE	0x01
define UAC_EP_CS_ATTR_PITCH_CONTROL	0x02
define UAC_EP_CS_ATTR_FILL_MAX	0x80
uac_iso_ep_attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, UAC_EP_CS_ATTR_PITCH_CONTROL, UAC_EP_CS_ATTR_FILL_MAX

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# TODO: describe MIDI, UAC2, UAC3
# https://www.usb.org/sites/default/files/midi10.pdf
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_midi.c
# https://elixir.bootlin.com/linux/latest/source/drivers/usb/gadget/function/f_uac2.c
# https://elixir.bootlin.com/linux/latest/source/include/linux/usb/audio-v2.h

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# ath9k driver specific descriptions.

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
