Nick: patrickg E-mail: none Board: unknown Contents: Companion patch for some versions of https://chromium-review.googlesource.com/c/chromiumos/third_party/hdctools/+/3822598 Might be instructive for USB3 hub handling, too. diff --git usb/backend/libusb0.py usb/backend/libusb0.py index cb34c3e..16c81d9 100644 --- usb/backend/libusb0.py +++ usb/backend/libusb0.py @@ -191,6 +191,8 @@ class _DeviceDescriptor: self.port_numbers = None self.speed = None + self.ContainerID = None + _lib = None def _load_library(find_library=None): diff --git usb/backend/libusb1.py usb/backend/libusb1.py index 73bda39..a7823b5 100644 --- usb/backend/libusb1.py +++ usb/backend/libusb1.py @@ -31,6 +31,7 @@ from ctypes import * import usb.util import sys +import uuid import logging from usb._debug import methodtrace import usb._interop as _interop @@ -243,6 +244,46 @@ class _libusb_iso_packet_descriptor(Structure): ('actual_length', c_uint), ('status', c_int)] # enum libusb_transfer_status +def _libusb_bos_dev_capability_descriptor_generator(num = 0): + class _libusb_bos_dev_capability_descriptor(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bDevCapabilityType', c_uint8), + ('dev_capability_data', c_uint8 * num)] + return _libusb_bos_dev_capability_descriptor + +def _libusb_bos_descriptor_generator(num = 0): + class _libusb_bos_descriptor(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('wTotalLength', c_uint16), + ('bNumDeviceCaps', c_uint8), + ('dev_capability', c_void_p * num)] + return _libusb_bos_descriptor + +class _libusb_usb_2_0_extension_descriptor(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bDevCapabilityType', c_uint8), + ('bmAttributes', c_uint32)] + +class _libusb_ss_usb_device_capability_descriptor(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bDevCapabilityType', c_uint8), + ('bmAttributes', c_uint8), + ('wSpeedSupported', c_uint16), + ('bFunctionalitySupported', c_uint8), + ('bU1DevExitLat', c_uint8), + ('bU2DevExitLat', c_uint16)] + +class _libusb_container_id_descriptor(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bDevCapabilityType', c_uint8), + ('bReserved', c_uint8), + ('ContainerID', c_uint8 * 16)] + _libusb_device_handle = c_void_p class _libusb_transfer(Structure): @@ -486,6 +527,15 @@ def _setup_prototypes(lib): lib.libusb_strerror.argtypes = [c_uint] lib.libusb_strerror.restype = c_char_p + if hasattr(lib, 'libusb_get_bos_descriptor'): + # int libusb_get_bos_descriptor(libusb_device_handle *handle, struct libusb_bos_descriptor **bos) + lib.libusb_get_bos_descriptor.argtypes = [_libusb_device_handle, + POINTER(POINTER(c_void_p))] + + if hasattr(lib, 'libusb_free_bos_descriptor'): + # void libusb_free_bos_descriptor(libusb_bos_descriptor *bos) + lib.libusb_free_bos_descriptor.argtypes = [c_void_p] + # int libusb_clear_halt(libusb_device_handle *dev, unsigned char endpoint) lib.libusb_clear_halt.argtypes = [_libusb_device_handle, c_ubyte] @@ -769,6 +819,37 @@ class _LibUSB(usb.backend.IBackend): except AttributeError: dev_desc.port_numbers = None + dev_desc.ContainerID = None + if dev_desc.bcdUSB > 0x200: + # Only available in newer versions of libusb + try: + dev_handle = self.open_device(dev) + bos_desc = POINTER(c_void_p)() + _check(self.lib.libusb_get_bos_descriptor(dev_handle.handle, byref(bos_desc))) + bos_desc = cast(bos_desc, POINTER(_libusb_bos_descriptor_generator())) + bos_desc = cast(bos_desc, POINTER(_libusb_bos_descriptor_generator(bos_desc[0].bNumDeviceCaps))) + bos_desc = bos_desc + self.close_device(dev_handle) + + for i in range(0, bos_desc[0].bNumDeviceCaps): + cap = bos_desc[0].dev_capability[i] + cap = cast(cap, POINTER(_libusb_bos_dev_capability_descriptor_generator())) + cap = cast(cap, POINTER(_libusb_bos_dev_capability_descriptor_generator(cap[0].bLength - 3))) + if cap[0].bDevCapabilityType == 2: + cap = cast(cap, POINTER(_libusb_usb_2_0_extension_descriptor)) + cap = cap[0] + elif cap[0].bDevCapabilityType == 3: + cap = cast(cap, POINTER(_libusb_ss_usb_device_capability_descriptor)) + cap = cap[0] + elif cap[0].bDevCapabilityType == 4: + cap = cast(cap, POINTER(_libusb_container_id_descriptor)) + cap = cap[0] + dev_desc.ContainerID = uuid.UUID(bytes_le = bytes(cap.ContainerID)) + + self.lib.libusb_free_bos_descriptor(bos_desc) + except Exception as e: + pass + return dev_desc @methodtrace(_logger) diff --git usb/backend/openusb.py usb/backend/openusb.py index 033e83d..80aa51d 100644 --- usb/backend/openusb.py +++ usb/backend/openusb.py @@ -572,6 +572,7 @@ class _OpenUSB(usb.backend.IBackend): desc.port_number = None desc.port_numbers = None desc.speed = None + desc.ContainerID = None return desc @methodtrace(_logger) diff --git usb/core.py usb/core.py index b5d239c..d0ee6bf 100644 --- usb/core.py +++ usb/core.py @@ -816,6 +816,7 @@ class Device(_objfinalizer.AutoFinalizedObject): 'port_number', 'port_numbers', 'speed', + 'ContainerID', ) )