@@ -11,10 +11,7 @@ from .. import emitter_for_format | |||
from ..descriptor import ComplexDescriptorEmitter | |||
from ...types import LanguageIDs | |||
from ...types.descriptors.standard import \ | |||
DeviceDescriptor, StringDescriptor, EndpointDescriptor, DeviceQualifierDescriptor, \ | |||
ConfigurationDescriptor, InterfaceDescriptor, StandardDescriptorNumbers, StringLanguageDescriptor, \ | |||
BinaryObjectStoreDescriptor, SuperSpeedEndpointCompanionDescriptor | |||
from ...types.descriptors.standard import * | |||
# Create our basic emitters... | |||
@@ -24,8 +21,9 @@ StringLanguageDescriptorEmitter = emitter_for_format(StringLanguageDescriptor) | |||
DeviceQualifierDescriptor = emitter_for_format(DeviceQualifierDescriptor) | |||
# ... our basic superspeed emitters ... | |||
BinaryObjectStoreDescriptorEmitter = emitter_for_format(BinaryObjectStoreDescriptor) | |||
SuperSpeedEndpointCompanionDescriptorEmitter = emitter_for_format(SuperSpeedEndpointCompanionDescriptor) | |||
USB2ExtensionDescriptorEmitter = emitter_for_format(USB2ExtensionDescriptor) | |||
SuperSpeedUSBDeviceCapabilityDescriptorEmitter = emitter_for_format(SuperSpeedUSBDeviceCapabilityDescriptor) | |||
SuperSpeedEndpointCompanionDescriptorEmitter = emitter_for_format(SuperSpeedEndpointCompanionDescriptor) | |||
# ... convenience functions ... | |||
def get_string_descriptor(string): | |||
@@ -327,6 +325,63 @@ class DeviceDescriptorCollection: | |||
return ((number, index, desc) for ((number, index), desc) in self._descriptors.items()) | |||
class BinaryObjectStoreDescriptorEmitter(ComplexDescriptorEmitter): | |||
""" Emitter that creates a BinaryObjectStore descriptor. """ | |||
DESCRIPTOR_FORMAT = BinaryObjectStoreDescriptor | |||
@contextmanager | |||
def USB2Extension(self): | |||
""" Context manager that allows addition of a USB 2.0 Extension to this Binary Object Store. | |||
It can be used with a `with` statement; and yields an USB2ExtensionDescriptorEmitter | |||
that can be populated: | |||
with bos.USB2Extension() as e: | |||
e.bmAttributes = 1 | |||
This adds the relevant descriptor, automatically. | |||
""" | |||
descriptor = USB2ExtensionDescriptorEmitter() | |||
yield descriptor | |||
self.add_subordinate_descriptor(descriptor) | |||
@contextmanager | |||
def SuperSpeedUSBDeviceCapability(self): | |||
""" Context manager that allows addition of a SS Device Capability to this Binary Object Store. | |||
It can be used with a `with` statement; and yields an SuperSpeedUSBDeviceCapabilityDescriptorEmitter | |||
that can be populated: | |||
with bos.SuperSpeedUSBDeviceCapability() as e: | |||
e.wSpeedSupported = 0b1110 | |||
e.bFunctionalitySupport = 1 | |||
This adds the relevant descriptor, automatically. | |||
""" | |||
descriptor = SuperSpeedUSBDeviceCapabilityDescriptorEmitter() | |||
yield descriptor | |||
self.add_subordinate_descriptor(descriptor) | |||
def _pre_emit(self): | |||
# Figure out the total length of our descriptor, including subordinates. | |||
subordinate_length = sum(len(sub) for sub in self._subordinates) | |||
self.wTotalLength = subordinate_length + self.DESCRIPTOR_FORMAT.sizeof() | |||
# Count our subordinate descriptors, and update our internal count. | |||
self.bNumDeviceCaps = len(self._subordinates) | |||
class SuperSpeedDeviceDescriptorCollection(DeviceDescriptorCollection): | |||
""" Object that builds a full collection of descriptors related to a given USB3 device. """ | |||
@@ -362,7 +417,14 @@ class SuperSpeedDeviceDescriptorCollection(DeviceDescriptorCollection): | |||
def add_default_bos_descriptor(self): | |||
""" Adds a default, empty BOS descriptor. """ | |||
# Create an empty BOS descriptor... | |||
descriptor = BinaryObjectStoreDescriptorEmitter() | |||
# ... populate our default required descriptors... | |||
descriptor.add_subordinate_descriptor(USB2ExtensionDescriptorEmitter()) | |||
descriptor.add_subordinate_descriptor(SuperSpeedUSBDeviceCapabilityDescriptorEmitter()) | |||
# ... and add it to our overall BOS descriptor. | |||
self.add_descriptor(descriptor) | |||
@@ -180,6 +180,16 @@ class DescriptorField(construct.Subconstruct): | |||
'w' : construct.Int16ul, | |||
} | |||
LENGTH_TYPES = { | |||
1: construct.Int8ul, | |||
2: construct.Int16ul, | |||
3: construct.Int24ul, | |||
4: construct.Int32ul, | |||
8: construct.Int64ul | |||
} | |||
@staticmethod | |||
def _get_prefix(name): | |||
""" Returns the lower-case prefix on a USB descriptor name. """ | |||
@@ -210,13 +220,20 @@ class DescriptorField(construct.Subconstruct): | |||
raise ValueError("field names must be formatted per the USB standard!") | |||
def __init__(self, description="", default=None): | |||
def __init__(self, description="", default=None, *, length=None): | |||
self.description = description | |||
self.default = default | |||
self.length = length | |||
def __rtruediv__(self, field_name): | |||
field_type = self._get_type_for_name(field_name) | |||
# If we have a length, use it to figure out the type. | |||
# Otherwise, extract the type from the prefix. (Using a length | |||
# is useful for e.g. USB3 bitfields; which can span several bytes.) | |||
if self.length is not None: | |||
field_type = self.LENGTH_TYPES[self.length] | |||
else: | |||
field_type = self._get_type_for_name(field_name) | |||
if self.default is not None: | |||
field_type = construct.Default(field_type, self.default) | |||
@@ -43,6 +43,27 @@ class StandardDescriptorNumbers(IntEnum): | |||
SUPERSPEEDPLUS_ISOCHRONOUS_ENDPOINT_COMPANION = 49 | |||
class DeviceCapabilityTypes(IntEnum): | |||
""" Numbers for the SuperSpeed standard Device Capabilities. """ | |||
WIRELESS_USB = 1 | |||
USB_2_EXTENSION = 2 | |||
SUPERSPEED_USB = 3 | |||
CONTAINER_ID = 4 | |||
PLATFORM = 5 | |||
POWER_DELIVERY_CAPABILITY = 6 | |||
BATTERY_INFO_CAPABILITY = 7 | |||
PD_CONSUMER_PORT_CAPABILITY = 8 | |||
PD_PROVIDER_PORT_CAPABILITY = 9 | |||
SUPERSPEED_PLUS = 10 | |||
PRECISION_TIME_MEASUREMENT = 11 | |||
WIRELESS_USB_EXTENSION = 12 | |||
BILLBOARD = 13 | |||
AUTHENTICATION = 14 | |||
BILLBOARD_EXTENSION = 15 | |||
CONFIGURATION_SUMMARY = 16 | |||
DeviceDescriptor = DescriptorFormat( | |||
"bLength" / construct.Const(0x12, construct.Int8ul), | |||
@@ -143,12 +164,31 @@ DeviceQualifierDescriptor = DescriptorFormat( | |||
# SuperSpeed descriptors | |||
# | |||
BinaryObjectStoreDescriptor = DescriptorFormat( | |||
"bLength" / construct.Const(0x5, construct.Int8ul), | |||
"bDescriptorType" / DescriptorNumber(StandardDescriptorNumbers.BOS), | |||
"wTotalLength" / DescriptorField("Total Length", default=5), | |||
"bNumDeviceCaps" / DescriptorField("Device Capability Descriptors", default=0), | |||
"bLength" / construct.Const(0x5, construct.Int8ul), | |||
"bDescriptorType" / DescriptorNumber(StandardDescriptorNumbers.BOS), | |||
"wTotalLength" / DescriptorField("Total Length", default=5), | |||
"bNumDeviceCaps" / DescriptorField("Device Capability Descriptors", default=0), | |||
) | |||
USB2ExtensionDescriptor = DescriptorFormat( | |||
"bLength" / construct.Const(0x7, construct.Int8ul), | |||
"bDescriptorType" / DescriptorNumber(StandardDescriptorNumbers.DEVICE_CAPABILITY), | |||
"bDevCapabilityType" / construct.Const(DeviceCapabilityTypes.USB_2_EXTENSION, construct.Int8ul), | |||
"bmAttributes" / DescriptorField("Attributes", default=0b10, length=4) | |||
) | |||
SuperSpeedUSBDeviceCapabilityDescriptor = DescriptorFormat( | |||
"bLength" / construct.Const(0xA, construct.Int8ul), | |||
"bDescriptorType" / DescriptorNumber(StandardDescriptorNumbers.DEVICE_CAPABILITY), | |||
"bDevCapabilityType" / construct.Const(DeviceCapabilityTypes.SUPERSPEED_USB, construct.Int8ul), | |||
"bmAttributes" / DescriptorField("Attributes", default=0), | |||
"wSpeedsSupported" / DescriptorField("USB3 Speeds Supported", default=0b1000), | |||
"bFunctionalitySupport" / DescriptorField("Lowest Speed with Full Support", default=3), | |||
"bU1DevExitLat" / DescriptorField("U1 Exit Latency", default=0), | |||
"wU2DevExitLat" / DescriptorField("U2 Exit Latency", default=0) | |||
) | |||
SuperSpeedEndpointCompanionDescriptor = DescriptorFormat( | |||
"bLength" / construct.Const(0x6, construct.Int8ul), | |||
"bDescriptorType" / DescriptorNumber(StandardDescriptorNumbers.SUPERSPEED_USB_ENDPOINT_COMPANION), | |||