diff --git a/usb_protocol/emitters/descriptors/hid.py b/usb_protocol/emitters/descriptors/hid.py new file mode 100644 index 0000000..629c605 --- /dev/null +++ b/usb_protocol/emitters/descriptors/hid.py @@ -0,0 +1,41 @@ +import unittest + +from contextlib import contextmanager + +from .. import emitter_for_format +from ..descriptor import ComplexDescriptorEmitter +from ...types.descriptors.hid import * + +class HIDDescriptorEmitter(ComplexDescriptorEmitter): + + DESCRIPTOR_FORMAT = HIDDescriptor + + @contextmanager + def DescriptorReference(self): + """ Context manager that allows addition of a descriptor reference. + + It can be used with a `with` statement; and yields an HIDDescriptorReferenceEmitter + that can be populated: + + with hiddescriptor.DescriptorReference() as r: + r.bDescriptorType = 0x22 + r.wDescriptorLength = 0x10 + r.wDescriptorLength = 0x10 + + This adds the relevant descriptor reference, automatically. + """ + + descriptor = HIDDescriptorReferenceEmitter() + 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.bLength = subordinate_length + self.DESCRIPTOR_FORMAT.sizeof() + self.bNumDescriptors = len(self._subordinates) + pass + + +HIDDescriptorReferenceEmitter = emitter_for_format(HIDDescriptorReference) diff --git a/usb_protocol/types/descriptors/hid.py b/usb_protocol/types/descriptors/hid.py new file mode 100644 index 0000000..20a98fd --- /dev/null +++ b/usb_protocol/types/descriptors/hid.py @@ -0,0 +1,46 @@ +# +# This file is part of usb-protocol. +# +""" Structures describing Human Interface Device Class descriptors. """ + +import unittest +from enum import IntEnum + +from ..descriptor import \ + DescriptorField, DescriptorNumber, DescriptorFormat + +class HidInterfaceClassCodes(IntEnum): + HID = 0x03 + +class HidInterfaceSubclassCodes(IntEnum): + NO_SUBCLASS = 0 + BOOT = 1 + +class HidInterfaceProtocols(IntEnum): + NONE = 0 + KEYBOARD = 1 + MOUSE = 2 + +class HidClassSpecificDescriptorTypes(IntEnum): + CS_UNDEFINED = 0x20 + CS_HID = 0x21 + CS_REPORT = 0x22 + CS_PHYSICAL = 0x23 + + +HIDDescriptor = DescriptorFormat( + "bLength" / DescriptorField("Descriptor Length"), + "bDescriptorType" / DescriptorNumber(HidClassSpecificDescriptorTypes.CS_HID), + "bcdHID" / DescriptorField("HID Protocol Version", default=1.11), + "bCountryCode" / DescriptorField("Hardware target country", default=0), + "bNumDescriptors" / DescriptorField("Number of HID class descriptors to follow", default=0), +) + +# This is not really a stand-alone descriptor, but rather a reference to a descriptor +# that can be retrieved seperately. It is part of the HIDDescriptor above. The HID +# descriptor can contain multiple descriptor references. To support this, a separate +# descriptor format is used. +HIDDescriptorReference = DescriptorFormat( + "bDescriptorType" / DescriptorField("HID Descriptor Type", default=HidClassSpecificDescriptorTypes.CS_REPORT), + "wDescriptorLength" / DescriptorField("HID Descriptor Length") +)