quimby/quimby-setup

203 lines
6.2 KiB
Python
Executable File

#!/usr/bin/env python3
import binascii
import os
import sys
keyboard = {
'protocol': 1, # keyboard
'subclass': 1, # boot interface
'report_length': 8,
'report_desc': bytes([
0x05, 0x01, # Usage Page (Generic Desktop Ctrls)
0x09, 0x06, # Usage (Keyboard)
0xA1, 0x01, # Collection (Application)
# Control key bitmask
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)
# Reserved byte
0x95, 0x01, # Report Count (1)
0x75, 0x08, # Report Size (8)
0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
# LED status
0x95, 0x05, # Report Count (5)
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)
# Padding
0x95, 0x01, # Report Count (1)
0x75, 0x03, # Report Size (3)
0x91, 0x03, # Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
# 6 general buttons
0x95, 0x06, # Report Count (6)
0x75, 0x08, # Report Size (8)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x65, # Logical Maximum (101)
0x05, 0x07, # Usage Page (Kbrd/Keypad)
0x19, 0x00, # Usage Minimum (0x00)
0x29, 0x9a, # Usage Maximum (0x9a)
0x81, 0x00, # Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, # End Collection
]),
}
mouse = {
'protocol': 2, # mouse
'subclass': 1, # boot interface
'report_length': 4,
'report_desc': 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)
0x09, 0x38, # Usage (Wheel)
0x15, 0x81, # Logical Minimum (-127)
0x25, 0x7F, # Logical Maximum (127)
0x75, 0x08, # Report Size (8)
0x95, 0x03, # Report Count (3)
0x81, 0x06, # Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0, # End Collection
0xC0, # End Collection
])
}
media = {
'protocol': 1, # Keyboard
'subclass': 0, # None
'report_length': 1,
'report_desc': bytes([
0x05, 0x0C, # Usage Page (Consumer)
0x09, 0x01, # Usage (Consumer Control)
0xA1, 0x01, # Collection (Application)
0x05, 0x0C, # Usage Page (Consumer)
0x15, 0x00, # Logical Minimum (0)
0x25, 0x01, # Logical Maximum (1)
0x75, 0x01, # Report Size (1)
0x95, 0x08, # Report Count (8)
0x09, 0xB5, # Usage (Scan Next Track)
0x09, 0xB6, # Usage (Scan Previous Track)
0x09, 0xB7, # Usage (Stop)
0x09, 0xB8, # Usage (Eject)
0x09, 0xCD, # Usage (Play/Pause)
0x09, 0xE2, # Usage (Mute)
0x09, 0xE9, # Usage (Volume Increment)
0x09, 0xEA, # Usage (Volume Decrement)
0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, # End Collection
])
}
try:
UDC = os.listdir('/sys/class/udc')
if len(UDC) != 1:
print("Expected a single entry in '/sys/class/udc'")
sys.exit(1)
UDC = UDC[0]
except FileNotFoundError:
print ("Unable to query UDC")
UDC='foo'
#sys.exit (1)
files = {
'idVendor': '0x1d6b', # Linux Foundation
'idProduct': '0x0104', # Multifunction Composite Gadget
'bcdDevice': '0x0100', # v1.0.0
'bcdUSB': '0x0200',
'strings': {
'0x409': {
'serialnumber': "fedcba9876543210",
'manufacturer': "Quimby",
'product': "Virtual Keyboard",
}
},
'configs': {
'c.1': {
'strings': {
'0x0409': {
'configuration': 'Config 1: ECM network'
}
},
'MaxPower': 250
}
},
'functions': {
'hid.usb0': keyboard,
'hid.usb1': mouse,
'hid.usb2': media,
}
}
name = 'quimby'
root = os.path.join('/sys/kernel/config/usb_gadget/', name)
try:
os.mkdir(root)
except FileExistsError:
pass
def serialise(root, tree):
for key,val in tree.items():
child = os.path.join(root, key)
if isinstance(val, dict):
try:
os.mkdir(child)
except FileExistsError:
pass
serialise(child, val)
else:
with open(child, 'wb') as dst:
print(child,val)
if not isinstance(val, bytes):
val = bytes(str(val).encode())
dst.write(val)
serialise(root, files)
# Link the functions in
for key in files['functions'].keys():
src = os.path.join(root, 'functions', key)
dst = os.path.join(root, 'configs', 'c.1', key)
os.symlink(src, dst)
# UDC needs to be written last
with open(f"{root}/UDC", 'w') as dst:
dst.write(UDC)