Browse Source

descriptors: extend to include some SuperSpeed content

main
Katherine Temkin 4 years ago
parent
commit
9fc29f0369
4 changed files with 158 additions and 30 deletions
  1. +1
    -1
      usb_protocol/emitters/__init__.py
  2. +99
    -7
      usb_protocol/emitters/descriptors/standard.py
  3. +18
    -14
      usb_protocol/types/__init__.py
  4. +40
    -8
      usb_protocol/types/descriptors/standard.py

+ 1
- 1
usb_protocol/emitters/__init__.py View File

@@ -4,4 +4,4 @@
""" USB-related emitters. """

from .construct import emitter_for_format, ConstructEmitter
from .descriptors.standard import DeviceDescriptorCollection
from .descriptors.standard import DeviceDescriptorCollection, SuperSpeedDeviceDescriptorCollection

+ 99
- 7
usb_protocol/emitters/descriptors/standard.py View File

@@ -13,16 +13,20 @@ from ..descriptor import ComplexDescriptorEmitter
from ...types import LanguageIDs
from ...types.descriptors.standard import \
DeviceDescriptor, StringDescriptor, EndpointDescriptor, DeviceQualifierDescriptor, \
ConfigurationDescriptor, InterfaceDescriptor, StandardDescriptorNumbers, StringLanguageDescriptor
ConfigurationDescriptor, InterfaceDescriptor, StandardDescriptorNumbers, StringLanguageDescriptor, \
BinaryObjectStoreDescriptor, SuperSpeedEndpointCompanionDescriptor


# Create our basic emitters...
DeviceDescriptorEmitter = emitter_for_format(DeviceDescriptor)
StringDescriptorEmitter = emitter_for_format(StringDescriptor)
StringLanguageDescriptorEmitter = emitter_for_format(StringLanguageDescriptor)
EndpointDescriptorEmitter = emitter_for_format(EndpointDescriptor)
DeviceQualifierDescriptor = emitter_for_format(DeviceQualifierDescriptor)

# ... our basic superspeed emitters ...
BinaryObjectStoreDescriptorEmitter = emitter_for_format(BinaryObjectStoreDescriptor)
SuperSpeedEndpointCompanionDescriptorEmitter = emitter_for_format(SuperSpeedEndpointCompanionDescriptor)

# ... convenience functions ...
def get_string_descriptor(string):
""" Generates a string descriptor for the relevant string. """
@@ -33,13 +37,37 @@ def get_string_descriptor(string):

# ... and complex emitters.

class EndpointDescriptorEmitter(ComplexDescriptorEmitter):
""" Emitter that creates an InterfaceDescriptor. """

DESCRIPTOR_FORMAT = EndpointDescriptor

@contextmanager
def SuperSpeedCompanion(self):
""" Context manager that allows addition of a SuperSpeed Companion to this endpoint descriptor.

It can be used with a `with` statement; and yields an SuperSpeedEndpointCompanionDescriptorEmitter
that can be populated:

with endpoint.SuperSpeedEndpointCompanion() as d:
d.bMaxBurst = 1

This adds the relevant descriptor, automatically.
"""

descriptor = SuperSpeedEndpointCompanionDescriptorEmitter()
yield descriptor

self.add_subordinate_descriptor(descriptor)


class InterfaceDescriptorEmitter(ComplexDescriptorEmitter):
""" Emitter that creates an InterfaceDescriptor. """

DESCRIPTOR_FORMAT = InterfaceDescriptor

@contextmanager
def EndpointDescriptor(self):
def EndpointDescriptor(self, *, add_default_superspeed=False):
""" Context manager that allows addition of a subordinate endpoint descriptor.

It can be used with a `with` statement; and yields an EndpointDesriptorEmitter
@@ -57,6 +85,11 @@ class InterfaceDescriptorEmitter(ComplexDescriptorEmitter):
descriptor = EndpointDescriptorEmitter()
yield descriptor

# If we're adding a default SuperSpeed extension, do so.
if add_default_superspeed:
with descriptor.SuperSpeedCompanion():
pass

self.add_subordinate_descriptor(descriptor)


@@ -260,15 +293,15 @@ class DeviceDescriptorCollection:


def _ensure_has_language_descriptor(self):
""" Ensures that we have a language descriptor; adding one if necessary."""
""" ensures that we have a language descriptor; adding one if necessary."""

# If we're not automatically adding a language descriptor, we shouldn't do anything,
# if we're not automatically adding a language descriptor, we shouldn't do anything,
# and we'll just ignore this.
if not self._automatic_language_descriptor:
return

# If we don't have a language descriptor, add our default one.
if not (StandardDescriptorNumbers.STRING, 0) in self._descriptors:
# if we don't have a language descriptor, add our default one.
if (StandardDescriptorNumbers.STRING, 0) not in self._descriptors:
self.add_language_descriptor()


@@ -294,6 +327,63 @@ class DeviceDescriptorCollection:
return ((number, index, desc) for ((number, index), desc) in self._descriptors.items())


class SuperSpeedDeviceDescriptorCollection(DeviceDescriptorCollection):
""" Object that builds a full collection of descriptors related to a given USB3 device. """

def __init__(self, automatic_descriptors=True):
"""
Parameters:
automatic_descriptors -- If set or not provided, certian required descriptors will be
be added if none exists.
"""
self._automatic_descriptors = automatic_descriptors
super().__init__(automatic_language_descriptor=automatic_descriptors)


@contextmanager
def BOSDescriptor(self):
""" Context manager that allows addition of a Binary Object Store descriptor.

It can be used with a `with` statement; and yields an BinaryObjectStoreDescriptorEmitter
that can be populated:

with collection.BOSDescriptor() as d:
[snip]

This adds the relevant descriptor, automatically. Note that populating derived
fields such as bNumDeviceCaps aren't necessary; they'll be populated automatically.
"""
descriptor = BinaryObjectStoreDescriptorEmitter()
yield descriptor

self.add_descriptor(descriptor)


def add_default_bos_descriptor(self):
""" Adds a default, empty BOS descriptor. """

descriptor = BinaryObjectStoreDescriptorEmitter()
self.add_descriptor(descriptor)


def _ensure_has_bos_descriptor(self):
""" Ensures that we have a BOS descriptor; adding one if necessary."""

# If we're not automatically adding a language descriptor, we shouldn't do anything,
# and we'll just ignore this.
if not self._automatic_descriptors:
return

# If we don't have a language descriptor, add our default one.
if (StandardDescriptorNumbers.BOS, 0) not in self._descriptors:
self.add_default_bos_descriptor()


def __iter__(self):
""" Allow iterating over each of our descriptors; yields (index, value, descriptor). """
self._ensure_has_bos_descriptor()
return super().__iter__()


class EmitterTests(unittest.TestCase):

@@ -414,3 +504,5 @@ class EmitterTests(unittest.TestCase):

if __name__ == "__main__":
unittest.main()



+ 18
- 14
usb_protocol/types/__init__.py View File

@@ -593,20 +593,6 @@ class USBUsageType(IntEnum):
IMPLICIT_FEEDBACK = 2


class USBStandardRequests(IntEnum):
GET_STATUS = 0
CLEAR_FEATURE = 1
SET_FEATURE = 3
SET_ADDRESS = 5
GET_DESCRIPTOR = 6
SET_DESCRIPTOR = 7
GET_CONFIGURATION = 8
SET_CONFIGURATION = 9
GET_INTERFACE = 10
SET_INTERFACE = 11
SYNCH_FRAME = 12


class USBTransferType(IntEnum):
CONTROL = 0
ISOCHRONOUS = 1
@@ -639,3 +625,21 @@ class USBStandardRequests(IntEnum):
GET_INTERFACE = 10
SET_INTERFACE = 11
SYNCH_FRAME = 12

# USB3 only.
SET_ENCRYPTION = 13
GET_ENCRYPTION = 14
SET_HANDSHAKE = 15
GET_HANDSHAKE = 16
SET_CONNECTION = 17
SET_SECURITY_DATA = 18
GET_SECURITY_DATA = 19
SET_WUSB_DATA = 20
LOOPBACK_DATA_WRITE = 21
LOOPBACK_DATA_READ = 22
SET_INTERFACE_DS = 23
SET_SEL = 48
SET_ISOCH_DELAY = 49




+ 40
- 8
usb_protocol/types/descriptors/standard.py View File

@@ -18,14 +18,25 @@ from ..descriptor import \
class StandardDescriptorNumbers(IntEnum):
""" Numbers of our standard descriptors. """

DEVICE = 1
CONFIGURATION = 2
STRING = 3
INTERFACE = 4
ENDPOINT = 5
DEVICE_QUALIFIER = 6
OTHER_SPEED_DESCRIPTOR = 7
INTERFACE_POWER = 8
DEVICE = 1
CONFIGURATION = 2
STRING = 3
INTERFACE = 4
ENDPOINT = 5
DEVICE_QUALIFIER = 6
OTHER_SPEED_DESCRIPTOR = 7
OTHER_SPEED = 7
INTERFACE_POWER = 8
OTG = 9
DEBUG = 10
INTERFACE_ASSOCIATION = 11

# SuperSpeed only
BOS = 15
DEVICE_CAPABILITY = 16
SUPERSPEED_USB_ENDPOINT_COMPANION = 48
SUPERSPEEDPLUS_ISOCHRONOUS_ENDPOINT_COMPANION = 49



DeviceDescriptor = DescriptorFormat(
@@ -46,6 +57,7 @@ DeviceDescriptor = DescriptorFormat(
)



ConfigurationDescriptor = DescriptorFormat(
"bLength" / construct.Const(9, construct.Int8ul),
"bDescriptorType" / DescriptorNumber(StandardDescriptorNumbers.CONFIGURATION),
@@ -122,6 +134,26 @@ 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),
)

SuperSpeedEndpointCompanionDescriptor = DescriptorFormat(
"bLength" / construct.Const(0x6, construct.Int8ul),
"bDescriptorType" / DescriptorNumber(StandardDescriptorNumbers.SUPERSPEED_USB_ENDPOINT_COMPANION),
"bMaxBurst" / DescriptorField("Maximum Burst Length", default=0),
"bmAttributes" / DescriptorField("Extended Attributes", default=0),
"wBytesPerInterval" / DescriptorField("Bytes Per Service Interval", default=0),
)



class DescriptorParserCases(unittest.TestCase):

STRING_DESCRIPTOR = bytes([


Loading…
Cancel
Save