initial import

This commit is contained in:
Danny Robson 2019-02-23 12:54:46 +11:00
commit ad8f8b198a
4 changed files with 294 additions and 0 deletions

39
cleanup.py Executable file
View File

@ -0,0 +1,39 @@
#!/usr/bin/env python3
import os
import sys
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('name', type=str)
args = parser.parse_args()
name = args.name
root = os.path.join('/sys/kernel/config/usb_gadget/', name)
# Follows the cleanup routine outlined in:
# https://www.kernel.org/doc/Documentation/usb/gadget_configfs.txt
for config in os.scandir(f"{root}/configs"):
# rm configs/<config name>.<number>/<function>
for function in os.scandir(config.path):
if function.is_symlink():
os.remove(function.path)
# rmdir configs/<config name>.<number>/strings/<lang>
for lang in os.scandir(f"{config.path}/strings/"):
os.rmdir(lang.path)
# rmdir configs/<config name>.<number>
os.rmdir(config.path)
# rmdir functions/<name>.<instance name>
for function in os.scandir(f"{root}/functions/"):
os.rmdir(function.path)
# rmdir strings/<lang>
for strings in os.scandir(f"{root}/strings/"):
os.rmdir(strings.path)
# rmdir <gadget name>
os.rmdir(root)

163
generate.py Executable file
View File

@ -0,0 +1,163 @@
#!/usr/bin/env python3
import binascii
import os
import sys
keyboard = {
'protocol': 1,
'subclass': 1,
'report_length': 8,
'report_desc': bytes([
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, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
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)
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)
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, 0x65, # Usage Maximum (0x65)
0x81, 0x00, # Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, # End Collection
]),
}
mouse = {
'protocol': 2,
'subclass': 1,
'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
])
}
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': "Raspberry Pi",
'product': "pizero keyboard Device",
}
},
'configs': {
'c.1': {
'strings': {
'0x0409': {
'configuration': 'Config 1: ECM network'
}
},
'MaxPower': 250
}
},
'functions': {
'hid.usb0': keyboard,
'hid.usb1': mouse,
}
}
name = 'pitooth'
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)

91
relay.py Executable file
View File

@ -0,0 +1,91 @@
#!/usr/bin/env python3
import evdev
import argparse
import os
import sys
scan_to_hid = {
evdev.ecodes.KEY_A: 0x04,
evdev.ecodes.KEY_B: 0x05,
evdev.ecodes.KEY_C: 0x06,
evdev.ecodes.KEY_D: 0x07,
evdev.ecodes.KEY_E: 0x08,
evdev.ecodes.KEY_F: 0x09,
evdev.ecodes.KEY_G: 0x0a,
evdev.ecodes.KEY_H: 0x0b,
evdev.ecodes.KEY_I: 0x0c,
evdev.ecodes.KEY_J: 0x0d,
evdev.ecodes.KEY_K: 0x0e,
evdev.ecodes.KEY_L: 0x0f,
evdev.ecodes.KEY_M: 0x10,
evdev.ecodes.KEY_N: 0x11,
evdev.ecodes.KEY_O: 0x12,
evdev.ecodes.KEY_P: 0x13,
evdev.ecodes.KEY_Q: 0x14,
evdev.ecodes.KEY_R: 0x16,
evdev.ecodes.KEY_S: 0x15,
evdev.ecodes.KEY_T: 0x17,
evdev.ecodes.KEY_U: 0x18,
evdev.ecodes.KEY_V: 0x19,
evdev.ecodes.KEY_W: 0x1a,
evdev.ecodes.KEY_X: 0x1b,
evdev.ecodes.KEY_Y: 0x1c,
evdev.ecodes.KEY_Z: 0x1d,
}
LEFT_CTRL = 1 << 0
LEFT_SHIFT = 1 << 1
LEFT_ALT = 1 << 2
LEFT_GUI = 1 << 3
RIGHT_CTRL = 1 << 4
RIGHT_SHIFT = 1 << 5
RIGHT_ALT = 1 << 6
RIGHT_GUI = 1 << 7
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Forward input events to a USB descriptor')
parser.add_argument('input', type=str, help='The source evdev device')
parser.add_argument('output', type=str, help='The output HID device')
args = parser.parse_args()
dst = os.open(args.output, os.O_WRONLY)
src = evdev.InputDevice(args.input)
src.grab()
modifiers = 0
keys_down = set()
for event in src.read_loop():
if event.type != evdev.ecodes.EV_KEY:
continue
data = evdev.categorize(event)
print("Got key", data.scancode)
code = scan_to_hid.get(data.scancode, None)
if code is None:
print("Ignoring unknown key")
continue
if data.keystate == data.key_down:
if len(keys_down) >= 6:
print("Ignoring key due to rollover")
continue
print("Adding key")
keys_down.add(code)
if data.keystate == data.key_up:
print("Removing key")
keys_down.remove(code)
# Build the packet
packet = [0] + [0] + [k for k in keys_down]
packet += [0] * (8 - len(packet))
assert(len(packet) == 8)
print("Sending", packet)
os.write(dst, bytes(packet))

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
evdev