]> Repositories - Adafruit_Blinka-hackapet.git/blobdiff - src/usb_hid.py
add working descriptors
[Adafruit_Blinka-hackapet.git] / src / usb_hid.py
index 3f526cc08b556afc15ff0c77f0583c336fd1012f..5fcd2a1f3bf2dc8bc70ad6a8dc50ea078022cbbf 100644 (file)
@@ -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/<gadget name>
-    
+
     e.g.::
-    
+
         $ mkdir $CONFIGFS_HOME/usb_gadget/g1
-    
+
         ...
         ...
         ...
-    
+
         $ cd $CONFIGFS_HOME/usb_gadget/g1
-    
+
     Each gadget needs to have its vendor id <VID> and product id <PID> specified::
-    
+
         $ echo <VID> > idVendor
         $ echo <PID> > 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 <serial number> > strings/0x409/serialnumber
         $ echo <manufacturer> > strings/0x409/manufacturer
         $ echo <product> > 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/<name>.<number>
-    
+
     where <name> can be any string which is legal in a filesystem and the
     <number> 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 <configuration> > 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/<name>.<instance name>
-        
+
         where <name> 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/<name>.<instance name> configs/<name>.<number>
-            
+
             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 name> > UDC
-    
+
     where <udc name> is one of those found in /sys/class/udc/*
     e.g.::