Skip to content

Instantly share code, notes, and snippets.

@Novakov
Created July 23, 2023 07:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Novakov/3daed356fb9668e75855578450898a6b to your computer and use it in GitHub Desktop.
Save Novakov/3daed356fb9668e75855578450898a6b to your computer and use it in GitHub Desktop.
LibUSB + multiple WinUSB functions in composite device
def compatibility_id():
return msft.CompatibilityIdTriple(
descriptorIndex=4,
sectionsCount=3,
interfaceNumber0=0,
compatibleId0='WINUSB',
subCompatibleId0='',
interfaceNumber1=1,
compatibleId1='WINUSB',
subCompatibleId1='',
interfaceNumber2=4,
compatibleId2='WINUSB',
subCompatibleId2=''
)
def extended_descriptor1():
return msft.ExtendedDescriptor(
sections=[
msft.ExtendedDescriptor.Section(
data_type=1,
property_name='DeviceInterfaceGUID\0',
value='{644991b2-1f10-45f7-a445-9a50ee4ce73d}\0'
)
]
)
def extended_descriptor2():
return msft.ExtendedDescriptor(
sections=[
msft.ExtendedDescriptor.Section(
data_type=1,
property_name='DeviceInterfaceGUID\0',
value='{13b2b252-adbf-45f8-9512-07342e35f305}\0'
)
]
)
def extended_descriptor3():
return msft.ExtendedDescriptor(
sections=[
msft.ExtendedDescriptor.Section(
data_type=1,
property_name='DeviceInterfaceGUID\0',
value='{519c4f5a-9543-4a53-8da2-5f6b428421a6}\0'
)
]
)
def make_descriptor(collection: DeviceDescriptorCollection) -> None:
with collection.DeviceDescriptor() as d:
d.idVendor = int.from_bytes(b'MN', byteorder='big')
d.idProduct = int.from_bytes(b'DU', byteorder='big')
d.bcdDevice = 0x00_15
d.bNumConfigurations = 1
d.bDeviceClass = CLASS_MISC
d.bDeviceSubclass = SUBCLASS_MISC_IAD
d.bDeviceProtocol = PROTOCOL_MISC_IAD
d.iManufacturer = 'Novakov'
d.iProduct = 'Double WinUSB'
d.iSerialNumber = '123456'
with collection.ConfigurationDescriptor() as c:
c: ConfigurationDescriptorEmitter
# WinUSB device1
with c.InterfaceDescriptor() as iface:
iface: InterfaceDescriptorEmitter
iface.bInterfaceNumber = 0
iface.bInterfaceClass = CLASS_VENDOR
with add_descriptor(c, InterfaceAssociationDescriptorEmitter) as iac:
iac.bFirstInterface = 1
iac.bInterfaceCount = 3
iac.bFunctionClass = CLASS_VENDOR
iac.bFunctionSubClass = ord('A')
iac.bFunctionProtocol = 0
iac.iFunction = collection.get_index_for_string('IAD Device')
# WinUSB IAD Device
with c.InterfaceDescriptor() as iface:
iface: InterfaceDescriptorEmitter
iface.bInterfaceNumber = 1
iface.bInterfaceClass = CLASS_VENDOR
iface.bInterfaceSubclass = ord('1')
with c.InterfaceDescriptor() as iface:
iface: InterfaceDescriptorEmitter
iface.bInterfaceNumber = 2
iface.bInterfaceClass = CLASS_VENDOR
iface.bInterfaceSubclass = ord('2')
with c.InterfaceDescriptor() as iface:
iface: InterfaceDescriptorEmitter
iface.bInterfaceNumber = 3
iface.bInterfaceClass = CLASS_VENDOR
iface.bInterfaceSubclass = ord('3')
with c.InterfaceDescriptor() as iface:
iface: InterfaceDescriptorEmitter
iface.bInterfaceNumber = 4
iface.bInterfaceClass = CLASS_VENDOR
iface.iInterface = 'Third device'
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request)
{
// nothing to with DATA & ACK stage
if(stage != CONTROL_STAGE_SETUP)
return true;
if((request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR) &&
(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE) && (request->bRequest == 0xAA))
{
tud_control_status(rhport, request);
return true;
}
if((request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR) && (request->bRequest == 0x33) &&
(request->wIndex == 4))
{
return tud_control_xfer(
rhport,
request,
(void*)usb::descriptors::msft::CompatibilityId,
usb::descriptors::msft::CompatibilityIdLength);
}
if((request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR) && (request->bRequest == 0x33) &&
(request->wIndex == 5))
{
switch((request->wValue & 0xFF))
{
case 0:
return tud_control_xfer(
rhport,
request,
(void*)usb::descriptors::msft::ExtendedDescriptor1,
usb::descriptors::msft::ExtendedDescriptorLength1);
case 1:
return tud_control_xfer(
rhport,
request,
(void*)usb::descriptors::msft::ExtendedDescriptor2,
usb::descriptors::msft::ExtendedDescriptorLength2);
case 4:
return tud_control_xfer(
rhport,
request,
(void*)usb::descriptors::msft::ExtendedDescriptor3,
usb::descriptors::msft::ExtendedDescriptorLength3);
default:;
}
}
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment