Browse Source

usb3: add some SuperSpeed BOS device capability descriptors

main
Katherine Temkin 4 years ago
parent
commit
dddc5cfe99
3 changed files with 131 additions and 12 deletions
  1. +68
    -6
      usb_protocol/emitters/descriptors/standard.py
  2. +19
    -2
      usb_protocol/types/descriptor.py
  3. +44
    -4
      usb_protocol/types/descriptors/standard.py

+ 68
- 6
usb_protocol/emitters/descriptors/standard.py View File

@@ -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)




+ 19
- 2
usb_protocol/types/descriptor.py View File

@@ -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)


+ 44
- 4
usb_protocol/types/descriptors/standard.py View File

@@ -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),


Loading…
Cancel
Save