@@ -11,10 +11,7 @@ from .. import emitter_for_format | |||||
from ..descriptor import ComplexDescriptorEmitter | from ..descriptor import ComplexDescriptorEmitter | ||||
from ...types import LanguageIDs | 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... | # Create our basic emitters... | ||||
@@ -24,8 +21,9 @@ StringLanguageDescriptorEmitter = emitter_for_format(StringLanguageDescriptor) | |||||
DeviceQualifierDescriptor = emitter_for_format(DeviceQualifierDescriptor) | DeviceQualifierDescriptor = emitter_for_format(DeviceQualifierDescriptor) | ||||
# ... our basic superspeed emitters ... | # ... 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 ... | # ... convenience functions ... | ||||
def get_string_descriptor(string): | def get_string_descriptor(string): | ||||
@@ -327,6 +325,63 @@ class DeviceDescriptorCollection: | |||||
return ((number, index, desc) for ((number, index), desc) in self._descriptors.items()) | 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): | class SuperSpeedDeviceDescriptorCollection(DeviceDescriptorCollection): | ||||
""" Object that builds a full collection of descriptors related to a given USB3 device. """ | """ 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): | def add_default_bos_descriptor(self): | ||||
""" Adds a default, empty BOS descriptor. """ | """ Adds a default, empty BOS descriptor. """ | ||||
# Create an empty BOS descriptor... | |||||
descriptor = BinaryObjectStoreDescriptorEmitter() | 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) | self.add_descriptor(descriptor) | ||||
@@ -180,6 +180,16 @@ class DescriptorField(construct.Subconstruct): | |||||
'w' : construct.Int16ul, | 'w' : construct.Int16ul, | ||||
} | } | ||||
LENGTH_TYPES = { | |||||
1: construct.Int8ul, | |||||
2: construct.Int16ul, | |||||
3: construct.Int24ul, | |||||
4: construct.Int32ul, | |||||
8: construct.Int64ul | |||||
} | |||||
@staticmethod | @staticmethod | ||||
def _get_prefix(name): | def _get_prefix(name): | ||||
""" Returns the lower-case prefix on a USB descriptor 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!") | 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.description = description | ||||
self.default = default | self.default = default | ||||
self.length = length | |||||
def __rtruediv__(self, field_name): | 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: | if self.default is not None: | ||||
field_type = construct.Default(field_type, self.default) | field_type = construct.Default(field_type, self.default) | ||||
@@ -43,6 +43,27 @@ class StandardDescriptorNumbers(IntEnum): | |||||
SUPERSPEEDPLUS_ISOCHRONOUS_ENDPOINT_COMPANION = 49 | 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( | DeviceDescriptor = DescriptorFormat( | ||||
"bLength" / construct.Const(0x12, construct.Int8ul), | "bLength" / construct.Const(0x12, construct.Int8ul), | ||||
@@ -143,12 +164,31 @@ DeviceQualifierDescriptor = DescriptorFormat( | |||||
# SuperSpeed descriptors | # SuperSpeed descriptors | ||||
# | # | ||||
BinaryObjectStoreDescriptor = DescriptorFormat( | 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( | SuperSpeedEndpointCompanionDescriptor = DescriptorFormat( | ||||
"bLength" / construct.Const(0x6, construct.Int8ul), | "bLength" / construct.Const(0x6, construct.Int8ul), | ||||
"bDescriptorType" / DescriptorNumber(StandardDescriptorNumbers.SUPERSPEED_USB_ENDPOINT_COMPANION), | "bDescriptorType" / DescriptorNumber(StandardDescriptorNumbers.SUPERSPEED_USB_ENDPOINT_COMPANION), | ||||