X-Git-Url: https://git.ayoreis.com/Adafruit_Blinka-hackapet.git/blobdiff_plain/0aa0ce122c93ff3f8f888b5f3e37452521a89c19..828dfae0621f66b7c06560df548595570314b750:/src/usb_hid.py diff --git a/src/usb_hid.py b/src/usb_hid.py index 3f526cc..5fcd2a1 100644 --- a/src/usb_hid.py +++ b/src/usb_hid.py @@ -19,39 +19,121 @@ class Device(): self.handle = '' def send_report(self, report: bytearray, report_id: int = None): - device = Path('%s/functions/hid.usb%s/dev' % (gadget_root, report_id or self.report_ids[0])).read_text().strip().split(':')[1] + device = \ + Path('%s/functions/hid.usb%s/dev' % (gadget_root, report_id or self.report_ids[0])) \ + .read_text() \ + .strip() \ + .split(':')[1] with open('/dev/hidg%s' % device, 'rb+') as fd: fd.write(report) Device.KEYBOARD = Device( descriptor=bytes(( - 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x75, 0x08, 0x95, 0x01, 0x81, 0x01, 0x75, 0x01, 0x95, 0x03, 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91, 0x02, 0x75, 0x01, 0x95, 0x05, 0x91, 0x01, 0x75, 0x08, 0x95, 0x06, 0x15, 0x00, 0x26, 0xff, 0x00, 0x05, 0x07, 0x19, 0x00, 0x2a, 0xff, 0x00, 0x81, 0x00, 0xc0 + + 0x05, 0x01, # usage page (generic desktop ctrls) + 0x09, 0x06, # usage (keyboard) + 0xa1, 0x01, # collection (application) + 0x05, 0x07, # usage page (kbrd/keypad) + 0x19, 0xe0, # usage minimum (0xe0) + 0x29, 0xe7, # usage maximum (0xe7) + 0x15, 0x00, # logical minimum (0) + 0x25, 0x01, # logical maximum (1) + 0x75, 0x01, # report size (1) + 0x95, 0x08, # report count (8) + 0x81, 0x02, # input (data,var,abs,no wrap,linear,preferred state,no null position) + 0x95, 0x01, # report count (1) + 0x75, 0x08, # report size (8) + 0x81, 0x01, # input (const,array,abs,no wrap,linear,preferred state,no null position) + 0x95, 0x03, # report count (3) + 0x75, 0x01, # report size (1) + 0x05, 0x08, # usage page (leds) + 0x19, 0x01, # usage minimum (num lock) + 0x29, 0x05, # usage maximum (kana) + 0x91, 0x02, # output (data,var,abs,no wrap,linear,preferred state,no null position,non-volatile) + 0x95, 0x01, # report count (1) + 0x75, 0x05, # report size (5) + 0x91, 0x01, # output (const,array,abs,no wrap,linear,preferred state,no null position,non-volatile) + 0x95, 0x06, # report count (6) + 0x75, 0x08, # report size (8) + 0x15, 0x00, # logical minimum (0) + 0x26, 0xff, 0x00, # logical maximum (255) + 0x05, 0x07, # usage page (kbrd/keypad) + 0x19, 0x00, # usage minimum (0x00) + 0x2a, 0xff, 0x00, # usage maximum (0xff) + 0x81, 0x00, # input (data,array,abs,no wrap,linear,preferred state,no null position) + 0xc0, # end collection )), usage_page=0x1, usage=0x6, - report_ids=[1], + report_ids=[0x1], in_report_lengths=[8], out_report_lengths=[1] ) Device.MOUSE = Device( - descriptor=b"05010906a101050719e029e71500250175019508810275089501810175019503050819012903910275019505910175089506150026ff00050719002aff008100c0", + descriptor=bytes(( + + 0x05, 0x01, # Usage Page (Generic Desktop Ctrls) + 0x09, 0x02, # Usage (Mouse) + 0xA1, 0x01, # Collection (Application) + 0x09, 0x01, # Usage (Pointer) + 0xA1, 0x00, # Collection (Physical) + 0x05, 0x09, # Usage Page (Button) + 0x19, 0x01, # Usage Minimum (0x01) + 0x29, 0x05, # Usage Maximum (0x05) + 0x15, 0x00, # Logical Minimum (0) + 0x25, 0x01, # Logical Maximum (1) + 0x95, 0x05, # Report Count (5) + 0x75, 0x01, # Report Size (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x01, # Report Count (1) + 0x75, 0x03, # Report Size (3) + 0x81, 0x01, # Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, # Usage Page (Generic Desktop Ctrls) + 0x09, 0x30, # Usage (X) + 0x09, 0x31, # Usage (Y) + 0x15, 0x81, # Logical Minimum (-127) + 0x25, 0x7F, # Logical Maximum (127) + 0x75, 0x08, # Report Size (8) + 0x95, 0x02, # Report Count (2) + 0x81, 0x06, # Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x38, # Usage (Wheel) + 0x15, 0x81, # Logical Minimum (-127) + 0x25, 0x7F, # Logical Maximum (127) + 0x75, 0x08, # Report Size (8) + 0x95, 0x01, # Report Count (1) + 0x81, 0x06, # Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, # End Collection + 0xC0, # End Collection + )), # Omitted for brevity. usage_page=0x1, usage=0x02, report_ids=[2], - in_report_lengths=[8], - out_report_lengths=[1], + in_report_lengths=[4], + out_report_lengths=[0], ) Device.CONSUMER_CONTROL = Device( - descriptor=b"05010906a101050719e029e71500250175019508810275089501810175019503050819012903910275019505910175089506150026ff00050719002aff008100c0", + descriptor=bytes(( + 0x05, 0x0C, # Usage Page (Consumer) + 0x09, 0x01, # Usage (Consumer Control) + 0xA1, 0x01, # Collection (Application) + 0x75, 0x10, # Report Size (16) + 0x95, 0x01, # Report Count (1) + 0x15, 0x01, # Logical Minimum (1) + 0x26, 0x8C, 0x02, # Logical Maximum (652) + 0x19, 0x01, # Usage Minimum (Consumer Control) + 0x2A, 0x8C, 0x02, # Usage Maximum (AC Send) + 0x81, 0x00, # Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, # End Collection + )), # Omitted for brevity. usage_page=0x0C, usage=0x01, report_ids=[3], - in_report_lengths=[1], - out_report_lengths=[8], + in_report_lengths=[2], + out_report_lengths=[0], ) devices = [Device.KEYBOARD, Device.MOUSE, Device.CONSUMER_CONTROL] @@ -81,7 +163,10 @@ def disable() -> None: Path(gadget_root).rmdir() except: pass -atexit.register(disable) + + +# atexit.register(disable) + def enable(devices: Sequence[Device], boot_device: int = 0) -> None: if len(devices) == 0: @@ -90,34 +175,34 @@ def enable(devices: Sequence[Device], boot_device: int = 0) -> None: """ 1. Creating the gadgets ----------------------- - + For each gadget to be created its corresponding directory must be created:: - + $ mkdir $CONFIGFS_HOME/usb_gadget/ - + e.g.:: - + $ mkdir $CONFIGFS_HOME/usb_gadget/g1 - + ... ... ... - + $ cd $CONFIGFS_HOME/usb_gadget/g1 - + Each gadget needs to have its vendor id and product id specified:: - + $ echo > idVendor $ echo > idProduct - + A gadget also needs its serial number, manufacturer and product strings. In order to have a place to store them, a strings subdirectory must be created for each language, e.g.:: - + $ mkdir strings/0x409 - + Then the strings can be specified:: - + $ echo > strings/0x409/serialnumber $ echo > strings/0x409/manufacturer $ echo > strings/0x409/product @@ -126,70 +211,70 @@ def enable(devices: Sequence[Device], boot_device: int = 0) -> None: Path('%s/configs' % gadget_root).mkdir(parents=True, exist_ok=True) Path('%s/bcdDevice' % gadget_root).write_text('%s' % 1) # Version 1.0.0 Path('%s/bcdUSB' % gadget_root).write_text('%s' % 0x0200) # USB 2.0 - Path('%s/bDeviceClass' % gadget_root).write_text('%s' % 0xEF) # multipurpose i guess? - Path('%s/bDeviceProtocol' % gadget_root).write_text('%s' % 0x01) - Path('%s/bDeviceSubClass' % gadget_root).write_text('%s' % 0x02) + Path('%s/bDeviceClass' % gadget_root).write_text('%s' % 0x00) # multipurpose i guess? + Path('%s/bDeviceProtocol' % gadget_root).write_text('%s' % 0x00) + Path('%s/bDeviceSubClass' % gadget_root).write_text('%s' % 0x00) Path('%s/bMaxPacketSize0' % gadget_root).write_text('%s' % 0x08) Path('%s/idProduct' % gadget_root).write_text('%s' % 0x0104) # Multifunction Composite Gadget Path('%s/idVendor' % gadget_root).write_text('%s' % 0x1d6b) # Linux Foundation """ 2. Creating the configurations ------------------------------ - + Each gadget will consist of a number of configurations, their corresponding directories must be created: - + $ mkdir configs/. - + where can be any string which is legal in a filesystem and the is the configuration's number, e.g.:: - + $ mkdir configs/c.1 - + ... ... ... - + Each configuration also needs its strings, so a subdirectory must be created for each language, e.g.:: - + $ mkdir configs/c.1/strings/0x409 - + Then the configuration string can be specified:: - + $ echo > configs/c.1/strings/0x409/configuration - + Some attributes can also be set for a configuration, e.g.:: - + $ echo 120 > configs/c.1/MaxPower """ for i, device in enumerate(devices): - config_root = '%s/configs/device.%s' % (gadget_root, i + 1) + + config_root = '%s/configs/device.%s' % (gadget_root, 1) Path('%s/' % config_root).mkdir(parents=True, exist_ok=True) Path('%s/strings/0x409' % config_root).mkdir(parents=True, exist_ok=True) Path('%s/strings/0x409/configuration' % config_root).write_text('my configuration') Path('%s/MaxPower' % config_root).write_text('150') Path('%s/bmAttributes' % config_root).write_text('%s' % 0x080) - """ 3. Creating the functions ------------------------- - + The gadget will provide some functions, for each function its corresponding directory must be created:: - + $ mkdir functions/. - + where corresponds to one of allowed function names and instance name is an arbitrary string allowed in a filesystem, e.g.:: - + $ mkdir functions/ncm.usb0 # usb_f_ncm.ko gets loaded with request_module() - + ... ... ... - + Each function provides its specific set of attributes, with either read-only or read-write access. Where applicable they need to be written to as appropriate. @@ -204,24 +289,24 @@ def enable(devices: Sequence[Device], boot_device: int = 0) -> None: Path('%s/' % function_root).mkdir(parents=True) except FileExistsError: continue - Path('%s/protocol' % function_root).write_text('%s' % 1) + Path('%s/protocol' % function_root).write_text('%s' % report_id) Path('%s/report_length' % function_root).write_text('%s' % device.in_report_lengths[report_index]) Path('%s/subclass' % function_root).write_text('%s' % 1) Path('%s/report_desc' % function_root).write_bytes(device.descriptor) """ 4. Associating the functions with their configurations ------------------------------------------------------ - + At this moment a number of gadgets is created, each of which has a number of configurations specified and a number of functions available. What remains is specifying which function is available in which configuration (the same function can be used in multiple configurations). This is achieved with creating symbolic links:: - + $ ln -s functions/. configs/. - + e.g.:: - + $ ln -s functions/ncm.usb0 configs/c.1 """ @@ -230,12 +315,12 @@ def enable(devices: Sequence[Device], boot_device: int = 0) -> None: 5. Enabling the gadget ---------------------- Such a gadget must be finally enabled so that the USB host can enumerate it. - + In order to enable the gadget it must be bound to a UDC (USB Device Controller):: - + $ echo > UDC - + where is one of those found in /sys/class/udc/* e.g.::