Skip to content

Instantly share code, notes, and snippets.

@QBFreak
Created November 29, 2018 18:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save QBFreak/b7bc6a7421c2df8da63a43324c25e372 to your computer and use it in GitHub Desktop.
Save QBFreak/b7bc6a7421c2df8da63a43324c25e372 to your computer and use it in GitHub Desktop.
Problematic USB keyboard emulation for Raspi Zero
#!/usr/bin/env python3
#
# Switch the KVM input by means of a virtual keyboard
# 71/47 Scroll Lock
# 30/1E 1
# 31/1F 2
# 32/20 3
# 33/21 4
# 40/28 RETURN/ENTER
import sys
if len(sys.argv) < 1:
print("Error: You must specify a KVM port to switch to.")
exit()
try:
port = int(sys.argv[1])
except:
print("Error: The KVM port must be a valid integer")
exit()
if port < 1 or port > 4:
print("Error: The KVM port must be a valid integer, 1-4")
exit()
NULL_CHAR = chr(0)
ONE = chr(30)
TWO = chr(31)
THREE = chr(32)
FOUR = chr(33)
RETURN = chr(40)
SCROLL_LOCK = chr(71)
key = ""
if port == 1:
key = ONE
elif port == 2:
key = TWO
elif port == 3:
key = THREE
elif port == 4:
key = FOUR
else:
raise ValueError("'port' is out of bounds")
def write_report(report):
with open('/dev/hidg0', 'rb+') as fd:
fd.write(report.encode())
# Scroll Lock and release, twice
write_report(NULL_CHAR*2+SCROLL_LOCK+NULL_CHAR*5)
write_report(NULL_CHAR*8)
write_report(NULL_CHAR*2+SCROLL_LOCK+NULL_CHAR*5)
write_report(NULL_CHAR*8)
# Number and release
write_report(NULL_CHAR*2+key+NULL_CHAR*5)
write_report(NULL_CHAR*8)
# RETURN and release
write_report(NULL_CHAR*2+RETURN+NULL_CHAR*5)
write_report(NULL_CHAR*8)
#!/bin/bash
# Create gadget
mkdir -p /sys/kernel/config/usb_gadget/mykeyboard
cd /sys/kernel/config/usb_gadget/mykeyboard
# Add basic information
echo 0x0100 > bcdDevice # Version 1.0.0
echo 0x0200 > bcdUSB # USB 2.0
echo 0x00 > bDeviceClass
echo 0x00 > bDeviceProtocol
echo 0x00 > bDeviceSubClass
echo 0x08 > bMaxPacketSize0
echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x1d6b > idVendor # Linux Foundation
# Create English locale
mkdir strings/0x409
echo "Cube Computer Services" > strings/0x409/manufacturer
echo "Virtual keyboard" > strings/0x409/product
echo "0000000001" > strings/0x409/serialnumber
# Create HID function
mkdir functions/hid.usb0
echo 1 > functions/hid.usb0/protocol
echo 8 > functions/hid.usb0/report_length # 8-byte reports
echo 1 > functions/hid.usb0/subclass
# Write report descriptor
# From the article I followed
echo "05010906a101050719e029e71500250175019508810275089501810175019503050819012903910275019505910175089506150026ff00050719002aff008100c0" | xxd -r -ps > functions/hid.usb0/report_desc
# Random one I found on the internet, with my own custom name in it, I was desperate
#echo "05010906a1010507850119e029e71500250175019508810295017508810195057501050885011901290591029501750391039506750815002565Cube Computer Services 0507190029658100c0" | xxd -r -ps > functions/hid.usb0/report_desc
# Create configuration
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo 0x80 > configs/c.1/bmAttributes
echo 200 > configs/c.1/MaxPower # 200 mA
echo "Default configuration" > configs/c.1/strings/0x409/configuration
# Link HID function to configuration
ln -s functions/hid.usb0 configs/c.1
# Enable gadget
ls /sys/class/udc > UDC
sleep 2

Symptoms

RasPi Zero W Keyboard emulation works fine except:

At boot, older PCs hang during POST if the keyboard is attached via KVM.

All other scenarios (booting without Pi connected, booting with Pi connected directly to PC not KVM, using kvm.py to switch KVM ports) work fine.

Attempts to read reports from keyboard during boot yield no data. PC doesn't seem to be waiting for keyboard.

@QBFreak
Copy link
Author

QBFreak commented Nov 29, 2018

Update: It looks like there is definitely something wrong with the USB device in general. I just spotted this in the Kernel Ring Buffer (dmesg). This occurred while the Pi was connected directly to the PC.

[    1.281021] usb 5-1: New USB device found, idVendor=1d6b, idProduct=0104
[    1.281027] usb 5-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[    1.281031] usb 5-1: Product: Virtual keyboard
[    1.281034] usb 5-1: Manufacturer: Cube Computer Services
[    1.281037] usb 5-1: SerialNumber: 0000000001
[    1.285939] hidraw: raw HID events driver (C) Jiri Kosina
[    1.288593] usbcore: registered new interface driver usbhid
[    1.288598] usbhid: USB HID core driver
[    1.289590] hid-generic 0003:1D6B:0104.0001: item fetching failed at offset 915304763
[    1.289654] hid-generic: probe of 0003:1D6B:0104.0001 failed with error -22

@QBFreak
Copy link
Author

QBFreak commented Nov 29, 2018

I found this post. Using that report descriptor cleared up all the PC issues. I still can't get the system to POST when the Pi is connected via the KVM.

@theboyknowsclass
Copy link

I don't suppose you've seen issues sending the scroll lock key? mine just seems to freeze up after sending it?

@QBFreak
Copy link
Author

QBFreak commented Dec 16, 2021

I didn't have any issues with scroll lock when I was still using it. That was the key my KVM used to switch. I haven't used it for some time, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment