From 42f5edbd331b27c7096f57da2affd7561287c17f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 3 Sep 2019 14:44:46 -0400 Subject: WIP --- tools/gen_usb_descriptor.py | 79 +++++++++++++++++++++++++++++++---------- tools/hid_report_descriptors.py | 60 +++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 19 deletions(-) (limited to 'tools') diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index 10bbf5066..f782f9afc 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -8,6 +8,15 @@ sys.path.append("../../tools/usb_descriptor") from adafruit_usb_descriptor import audio, audio10, cdc, hid, midi, msc, standard, util import hid_report_descriptors +ALL_DEVICES='CDC,MSC,AUDIO,HID' +ALL_DEVICES_SET=frozenset(ALL_DEVICES.split(',')) +DEFAULT_DEVICES='CDC,MSC,AUDIO,HID' + +ALL_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,SYS_CONTROL,GAMEPAD,DIGITIZER,XAC_COMPATIBLE_GAMEPAD' +ALL_HID_DEVICES_SET=frozenset(ALL_HID_DEVICES.split(',')) +# Digitizer works on Linux but conflicts with mouse, so omit it. +DEFAULT_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,GAMEPAD' + parser = argparse.ArgumentParser(description='Generate USB descriptors.') parser.add_argument('--manufacturer', type=str, help='manufacturer of the device') @@ -19,11 +28,24 @@ parser.add_argument('--pid', type=lambda x: int(x, 16), help='product id') parser.add_argument('--serial_number_length', type=int, default=32, help='length needed for the serial number in digits') +parser.add_argument('--devices', type=lambda l: frozenset(l.split(',')), default=DEFAULT_DEVICES, + help='devices to include in descriptor (AUDIO includes MIDI support)') +parser.add_argument('--hid_devices', type=lambda l: frozenset(l.split(',')), default=DEFAULT_HID_DEVICES, + help='HID devices to include in HID report descriptor') parser.add_argument('--output_c_file', type=argparse.FileType('w'), required=True) parser.add_argument('--output_h_file', type=argparse.FileType('w'), required=True) args = parser.parse_args() +unknown_devices = list(args.devices - ALL_DEVICES_SET) +if unknown_devices: + raise ValueError("Unknown device(s)", unknown_devices) + +unknown_hid_devices = list(args.hid_devices - ALL_HID_DEVICES_SET) +if unknown_hid_devices: + raise ValueError("Unknown HID devices(s)", unknown_hid_devices) + + class StringIndex: """Assign a monotonically increasing index to each unique string. Start with 0.""" string_to_index = {} @@ -138,16 +160,27 @@ msc_interfaces = [ ) ] -# Include only these HID devices. -# DIGITIZER works on Linux but conflicts with MOUSE, so leave it out for now. -hid_devices = ("KEYBOARD", "MOUSE", "CONSUMER", "GAMEPAD") - -combined_hid_report_descriptor = hid.ReportDescriptor( +# Sort by Report ID for consistency. +hid_devices = sorted(args.hid_devices, key=lambda name: hid_report_descriptors.REPORT_IDS[name]) + +# When there's only one hid_device, it can't be in a composite descriptor. +# It has no report id (indicated by 0), so remove the existing one. + +#if len(hid_devices) == 1: +if False: + name = hid_devices[0] + combined_hid_report_descriptor = hid.ReportDescriptor( + description=name, + report_descriptor=hid_report_descriptors.remove_report_id( + hid_report_descriptors.REPORT_DESCRIPTORS[name].report_descriptor)) + hid_report_ids_dict = { name : 0 } +else: + combined_hid_report_descriptor = hid.ReportDescriptor( description="MULTIDEVICE", report_descriptor=b''.join( hid_report_descriptors.REPORT_DESCRIPTORS[name].report_descriptor for name in hid_devices )) + hid_report_ids_dict = { name: hid_report_descriptors.REPORT_IDS[name] for name in hid_devices } -hid_report_ids_dict = { name: hid_report_descriptors.REPORT_IDS[name] for name in hid_devices } hid_report_lengths_dict = { name: hid_report_descriptors.REPORT_LENGTHS[name] for name in hid_devices } hid_max_report_length = max(hid_report_lengths_dict.values()) @@ -271,19 +304,27 @@ cdc_iad = standard.InterfaceAssociationDescriptor( bFunctionProtocol=cdc.CDC_PROTOCOL_NONE) descriptor_list = [] -descriptor_list.append(cdc_iad) -descriptor_list.extend(cdc_interfaces) -descriptor_list.extend(msc_interfaces) -# Only add the control interface because other audio interfaces are managed by it to ensure the -# correct ordering. -descriptor_list.append(audio_control_interface) -# Put the CDC IAD just before the CDC interfaces. -# There appears to be a bug in the Windows composite USB driver that requests the -# HID report descriptor with the wrong interface number if the HID interface is not given -# first. However, it still fetches the descriptor anyway. We could reorder the interfaces but -# the Windows 7 Adafruit_usbser.inf file thinks CDC is at Interface 0, so we'll leave it -# there for backwards compatibility. -descriptor_list.extend(hid_interfaces) + +if 'CDC' in args.devices: + # Put the CDC IAD just before the CDC interfaces. + # There appears to be a bug in the Windows composite USB driver that requests the + # HID report descriptor with the wrong interface number if the HID interface is not given + # first. However, it still fetches the descriptor anyway. We could reorder the interfaces but + # the Windows 7 Adafruit_usbser.inf file thinks CDC is at Interface 0, so we'll leave it + # there for backwards compatibility. + descriptor_list.append(cdc_iad) + descriptor_list.extend(cdc_interfaces) + +if 'MSC' in args.devices: + descriptor_list.extend(msc_interfaces) + +if 'AUDIO' in args.devices: + # Only add the control interface because other audio interfaces are managed by it to ensure the + # correct ordering. + descriptor_list.append(audio_control_interface) + +if 'HID' in args.devices: + descriptor_list.extend(hid_interfaces) configuration = standard.ConfigurationDescriptor( description="Composite configuration", diff --git a/tools/hid_report_descriptors.py b/tools/hid_report_descriptors.py index f3b28ebcf..4902657af 100644 --- a/tools/hid_report_descriptors.py +++ b/tools/hid_report_descriptors.py @@ -31,6 +31,11 @@ HID specific descriptors from adafruit_usb_descriptor import hid +def remove_report_id(report_descriptor_bytes): + #return report_descriptor_bytes + report_id_pos = report_descriptor_bytes.index(0x85) + return report_descriptor_bytes[:report_id_pos] + report_descriptor_bytes[report_id_pos + 2:] + REPORT_IDS = { "KEYBOARD" : 1, "MOUSE" : 2, @@ -38,6 +43,9 @@ REPORT_IDS = { "SYS_CONTROL" : 4, "GAMEPAD" : 5, "DIGITIZER" : 6, + "XAC_COMPATIBLE_GAMEPAD" : 7, + # RAW must not have a report ID, so it can't be used with other devices. + "RAW" : 0, } # Byte count for each kind of report. Length does not include report ID in first byte. @@ -48,6 +56,8 @@ REPORT_LENGTHS = { "SYS_CONTROL" : 1, "GAMEPAD" : 6, "DIGITIZER" : 5, + "XAC_COMPATIBLE_GAMEPAD" : 3, + "RAW" : 64, } KEYBOARD_WITH_ID = hid.ReportDescriptor( @@ -228,6 +238,54 @@ DIGITIZER_WITH_ID = hid.ReportDescriptor( 0xC0, # End Collection ])) +XAC_COMPATIBLE_GAMEPAD_WITH_ID = hid.ReportDescriptor( + description="XAC", + report_descriptor=bytes([ + # This descriptor mimics the simple joystick from PDP that the XBox likes + 0x05, 0x01, # Usage Page (Desktop), + 0x09, 0x05, # Usage (Gamepad), + 0xA1, 0x01, # Collection (Application), + 0x85, REPORT_IDS["XAC_COMPATIBLE_GAMEPAD"], # Report ID (n) + 0x15, 0x00, # Logical Minimum (0), + 0x25, 0x01, # Logical Maximum (1), + 0x35, 0x00, # Physical Minimum (0), + 0x45, 0x01, # Physical Maximum (1), + 0x75, 0x01, # Report Size (1), + 0x95, 0x08, # Report Count (8), + 0x05, 0x09, # Usage Page (Button), + 0x19, 0x01, # Usage Minimum (01h), + 0x29, 0x08, # Usage Maximum (08h), + 0x81, 0x02, # Input (Variable), + 0x05, 0x01, # Usage Page (Desktop), + 0x26, 0xFF, 0x00, # Logical Maximum (255), + 0x46, 0xFF, 0x00, # Physical Maximum (255), + 0x09, 0x30, # Usage (X), + 0x09, 0x31, # Usage (Y), + 0x75, 0x08, # Report Size (8), + 0x95, 0x02, # Report Count (2), + 0x81, 0x02, # Input (Variable), + 0xC0 # End Collection + ])) + +RAW = hid.ReportDescriptor( + description="RAW", + report_descriptor=bytes([ + # Provide vendor-defined + 0x06, 0xAF, 0xFF, # Usage Page (Vendor 0xFFAF "Adafruit"), + 0x09, 0xAF, # Usage (AF), + 0xA1, 0x01, # Collection (Application), + 0x75, 0x08, # Report Size (8), + 0x15, 0x00, # Logical Minimum (0), + 0x26, 0xFF, 0x00 # Logical Maximum (255), + 0x95, 0x08, # Report Count (8), + 0x09, 0x01 # Usage(xxx) + 0x81, 0x02 # Input (Variable) + 0x95, 0x08, # Report Count (8), + 0x09, 0x02, # Usage(xxx) + 0x91, 0x02, # Input (Variable) + 0xC0 # End Collection + ])) + # Byte count for each kind of report. Length does not include report ID in first byte. REPORT_DESCRIPTORS = { "KEYBOARD" : KEYBOARD_WITH_ID, @@ -236,4 +294,6 @@ REPORT_DESCRIPTORS = { "SYS_CONTROL" : SYS_CONTROL_WITH_ID, "GAMEPAD" : GAMEPAD_WITH_ID, "DIGITIZER" : DIGITIZER_WITH_ID, + "XAC_COMPATIBLE_GAMEPAD" : XAC_COMPATIBLE_GAMEPAD_WITH_ID, + "RAW" : RAW_WITH_ID, } -- cgit v1.2.3