Last active
June 21, 2024 16:48
-
-
Save mzyy94/60ae253a45e2759451789a117c59acf9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
cd /sys/kernel/config/usb_gadget/ | |
mkdir -p procon | |
cd procon | |
echo 0x057e > idVendor | |
echo 0x2009 > idProduct | |
echo 0x0200 > bcdDevice | |
echo 0x0200 > bcdUSB | |
echo 0x00 > bDeviceClass | |
echo 0x00 > bDeviceSubClass | |
echo 0x00 > bDeviceProtocol | |
mkdir -p strings/0x409 | |
echo "000000000001" > strings/0x409/serialnumber | |
echo "Nintendo Co., Ltd." > strings/0x409/manufacturer | |
echo "Pro Controller" > strings/0x409/product | |
mkdir -p configs/c.1/strings/0x409 | |
echo "Nintendo Switch Pro Controller" > configs/c.1/strings/0x409/configuration | |
echo 500 > configs/c.1/MaxPower | |
echo 0xa0 > configs/c.1/bmAttributes | |
mkdir -p functions/hid.usb0 | |
echo 0 > functions/hid.usb0/protocol | |
echo 0 > functions/hid.usb0/subclass | |
echo 64 > functions/hid.usb0/report_length | |
echo 050115000904A1018530050105091901290A150025017501950A5500650081020509190B290E150025017501950481027501950281030B01000100A1000B300001000B310001000B320001000B35000100150027FFFF0000751095048102C00B39000100150025073500463B0165147504950181020509190F2912150025017501950481027508953481030600FF852109017508953F8103858109027508953F8103850109037508953F9183851009047508953F9183858009057508953F9183858209067508953F9183C0 | xxd -r -ps > functions/hid.usb0/report_desc | |
ln -s functions/hid.usb0 configs/c.1/ | |
ls /sys/class/udc > UDC |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import os | |
import threading | |
import time | |
# Re-connect USB Gadget device | |
os.system('echo > /sys/kernel/config/usb_gadget/procon/UDC') | |
os.system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC') | |
time.sleep(0.5) | |
gadget = os.open('/dev/hidg0', os.O_RDWR | os.O_NONBLOCK) | |
procon = os.open('/dev/hidraw0', os.O_RDWR | os.O_NONBLOCK) | |
def procon_input(): | |
while True: | |
try: | |
input_data = os.read(gadget, 128) | |
print('>>>', input_data.hex()) | |
os.write(procon, input_data) | |
except BlockingIOError: | |
pass | |
except: | |
os._exit(1) | |
def procon_output(): | |
while True: | |
try: | |
output_data = os.read(procon, 128) | |
print('<<<', output_data.hex()) | |
os.write(gadget, output_data) | |
except BlockingIOError: | |
pass | |
except: | |
os._exit(1) | |
threading.Thread(target=procon_input).start() | |
threading.Thread(target=procon_output).start() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pi@raspberrypi:~ $ sudo python3 bypass_procon.py | grep -v '<<< 30' | |
>>> 0000 | |
>>> 0000 | |
>>> 8005 | |
>>> 0000 | |
>>> 8001 | |
<<< 810100031f861dd60304000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 8002 | |
<<< 81020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 01000000000000000000033000000000000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 21b191008000f3e77ae1e77e00800300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 8004 | |
>>> 01080000000000000000480000000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 01090000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 21b691008000f2f77ae2f77e00804800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 010a0000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 21e391008000f2e77ae2f77e008202034803020403d61d861f030100000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 010b0000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 21e791008000f2f77ae2c77e00800800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 010c0000000000000000100060000010000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 21eb91008000f2e77ae3d77e0090100060000010ffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000 | |
>>> 010d000000000000000010506000000d000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 21ef91008000f4f77ae4e77e009010506000000d323232ffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000 | |
>>> 010e00000000000000000104185395d6030400043c4e696e74656e646f2053776974636800000000006800ac90113f5900 | |
<<< 21f391008000f3f77ae1e77e00810103000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 010f0001404000014040033000000000000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 21f791008000eed77ae2d77e0c800300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 01000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 21fc91008000f1e77ae2e77e0a830400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 01010000000000000000108060000018000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 210091008000f2e77ae1e77e099010806000001850fd0000c60f0f30619630f3d41454411554c7799c3336630000000000000000000000000000000000000000 | |
>>> 01020000000000000000109860000012000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 210491008000f2e77ae2e77e0b901098600000120f30619630f3d41454411554c7799c3336630000000000000000000000000000000000000000000000000000 | |
>>> 01030001404000014040101080000018000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 210991008000f4077be3c77e0990101080000018ffffffffffffffffffffffffffffffffffffffffffffb2a10000000000000000000000000000000000000000 | |
>>> 01040000000000000000103d60000019000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 210d91008000f2f77ae3e77e0b90103d60000019ba156211b87f29065bffe77e0e36569e8560ff323232ffffff00000000000000000000000000000000000000 | |
>>> 01050000000000000000102880000018000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 211191008000f3f77ae3d77e0990102880000018beff3e00f001004000400040fefffeff0800e73be73be73b0000000000000000000000000000000000000000 | |
>>> 01060000000000000000400100000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 10070001404000014040 | |
<<< 211891008000f4e77ae3c77e0c804000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 10080001404000014040 | |
>>> 10090001404000014040 | |
>>> 100a0001404000014040 | |
>>> 100b0001404000014040 | |
>>> 100c0001404000014040 | |
>>> 010d0000000000000000480100000000000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 218291008000e40bbbe3d77e0c804800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 010ec218037200014040212100000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 100f0001404000000000 | |
<<< 218691008000422cc2e0b77e00a0210100ff0003000501000000000000000000000000000000000000000000000000005c000000000000000000000000000000 | |
>>> 01000000000000000000300100000000000000000000000000000000000000000000000000000000000000000000000000 | |
<<< 218c9100800048fcc1e0d77e0a803000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
>>> 10010000000002786040 | |
>>> 10020001404000014040 | |
>>> 10030001404000014040 | |
>>> 10040001404000014040 | |
>>> 10050001404000014040 | |
>>> 10060001404000014040 | |
>>> 10070001404000014040 | |
>>> 10080001404000014040 | |
>>> 10090001404000014040 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
0x05, 0x01, // Usage Page (Generic Desktop Ctrls) | |
0x15, 0x00, // Logical Minimum (0) | |
0x09, 0x04, // Usage (Joystick) | |
0xA1, 0x01, // Collection (Application) | |
0x85, 0x30, // Report ID (48) | |
0x05, 0x01, // Usage Page (Generic Desktop Ctrls) | |
0x05, 0x09, // Usage Page (Button) | |
0x19, 0x01, // Usage Minimum (0x01) | |
0x29, 0x0A, // Usage Maximum (0x0A) | |
0x15, 0x00, // Logical Minimum (0) | |
0x25, 0x01, // Logical Maximum (1) | |
0x75, 0x01, // Report Size (1) | |
0x95, 0x0A, // Report Count (10) | |
0x55, 0x00, // Unit Exponent (0) | |
0x65, 0x00, // Unit (None) | |
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0x05, 0x09, // Usage Page (Button) | |
0x19, 0x0B, // Usage Minimum (0x0B) | |
0x29, 0x0E, // Usage Maximum (0x0E) | |
0x15, 0x00, // Logical Minimum (0) | |
0x25, 0x01, // Logical Maximum (1) | |
0x75, 0x01, // Report Size (1) | |
0x95, 0x04, // Report Count (4) | |
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0x75, 0x01, // Report Size (1) | |
0x95, 0x02, // Report Count (2) | |
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0x0B, 0x01, 0x00, 0x01, 0x00, // Usage (0x010001) | |
0xA1, 0x00, // Collection (Physical) | |
0x0B, 0x30, 0x00, 0x01, 0x00, // Usage (0x010030) | |
0x0B, 0x31, 0x00, 0x01, 0x00, // Usage (0x010031) | |
0x0B, 0x32, 0x00, 0x01, 0x00, // Usage (0x010032) | |
0x0B, 0x35, 0x00, 0x01, 0x00, // Usage (0x010035) | |
0x15, 0x00, // Logical Minimum (0) | |
0x27, 0xFF, 0xFF, 0x00, 0x00, // Logical Maximum (65534) | |
0x75, 0x10, // Report Size (16) | |
0x95, 0x04, // Report Count (4) | |
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0xC0, // End Collection | |
0x0B, 0x39, 0x00, 0x01, 0x00, // Usage (0x010039) | |
0x15, 0x00, // Logical Minimum (0) | |
0x25, 0x07, // Logical Maximum (7) | |
0x35, 0x00, // Physical Minimum (0) | |
0x46, 0x3B, 0x01, // Physical Maximum (315) | |
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) | |
0x75, 0x04, // Report Size (4) | |
0x95, 0x01, // Report Count (1) | |
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0x05, 0x09, // Usage Page (Button) | |
0x19, 0x0F, // Usage Minimum (0x0F) | |
0x29, 0x12, // Usage Maximum (0x12) | |
0x15, 0x00, // Logical Minimum (0) | |
0x25, 0x01, // Logical Maximum (1) | |
0x75, 0x01, // Report Size (1) | |
0x95, 0x04, // Report Count (4) | |
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0x75, 0x08, // Report Size (8) | |
0x95, 0x34, // Report Count (52) | |
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) | |
0x85, 0x21, // Report ID (33) | |
0x09, 0x01, // Usage (0x01) | |
0x75, 0x08, // Report Size (8) | |
0x95, 0x3F, // Report Count (63) | |
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0x85, 0x81, // Report ID (-127) | |
0x09, 0x02, // Usage (0x02) | |
0x75, 0x08, // Report Size (8) | |
0x95, 0x3F, // Report Count (63) | |
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) | |
0x85, 0x01, // Report ID (1) | |
0x09, 0x03, // Usage (0x03) | |
0x75, 0x08, // Report Size (8) | |
0x95, 0x3F, // Report Count (63) | |
0x91, 0x83, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile) | |
0x85, 0x10, // Report ID (16) | |
0x09, 0x04, // Usage (0x04) | |
0x75, 0x08, // Report Size (8) | |
0x95, 0x3F, // Report Count (63) | |
0x91, 0x83, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile) | |
0x85, 0x80, // Report ID (-128) | |
0x09, 0x05, // Usage (0x05) | |
0x75, 0x08, // Report Size (8) | |
0x95, 0x3F, // Report Count (63) | |
0x91, 0x83, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile) | |
0x85, 0x82, // Report ID (-126) | |
0x09, 0x06, // Usage (0x06) | |
0x75, 0x08, // Report Size (8) | |
0x95, 0x3F, // Report Count (63) | |
0x91, 0x83, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile) | |
0xC0, // End Collection | |
// 203 bytes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import os | |
import threading | |
import time | |
KEY1=21 | |
KEY2=20 | |
KEY3=16 | |
LEFT=5 | |
RIGHT=26 | |
UP=6 | |
DOWN=19 | |
PRESS=13 | |
KEYS = [KEY1,KEY2,KEY3,UP,DOWN,LEFT,RIGHT,PRESS] | |
export = os.open('/sys/class/gpio/export', os.O_WRONLY | os.O_NONBLOCK) | |
for gpio in KEYS: | |
if not os.path.exists('/sys/class/gpio/gpio%d' % gpio): | |
os.write(export, bytes(str(gpio), 'ascii')) | |
direction = os.open('/sys/class/gpio/gpio%d/direction' % gpio, os.O_WRONLY | os.O_NONBLOCK) | |
os.write(direction, bytes('high', 'ascii')) | |
os.close(direction) | |
os.close(export) | |
# Reset USB Gadget | |
os.system('echo > /sys/kernel/config/usb_gadget/procon/UDC') | |
os.system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC') | |
time.sleep(0.5) | |
gadget = os.open('/dev/hidg0', os.O_RDWR | os.O_NONBLOCK) | |
counter = 0 | |
mac_addr = '00005e00535e' | |
initial_input = '81008000f8d77a22c87b0c' | |
def countup(): | |
global counter | |
while True: | |
counter = (counter + 3) % 256 | |
time.sleep(0.03) | |
def response(code, cmd, data): | |
buf = bytearray([code, cmd]) | |
buf.extend(data) | |
buf.extend(bytearray(64-len(buf))) | |
try: | |
os.write(gadget, buf) | |
except BlockingIOError: | |
pass | |
except: | |
os._exit(1) | |
def uart_response(code, subcmd, data): | |
buf = bytearray.fromhex(initial_input) | |
buf.extend([code, subcmd]) | |
buf.extend(data) | |
response(0x21, counter, buf) | |
def spi_response(addr, data): | |
buf = bytearray(addr) | |
buf.extend([0x00, 0x00]) | |
buf.append(len(data)) | |
buf.extend(data) | |
uart_response(0x90, 0x10, buf) | |
def input_response(): | |
while True: | |
buf = bytearray.fromhex(initial_input) | |
inputs = {} | |
for gpio in KEYS: | |
with open('/sys/class/gpio/gpio%d/value' % gpio, 'r') as f: | |
inputs[gpio] = f.read().startswith('0') | |
buf[1] = inputs[KEY1] << 3 | inputs[KEY2] << 2 | |
buf[2] |= inputs[KEY3] << 4 | inputs[PRESS] << 1 | |
buf[3] = inputs[LEFT] << 3 | inputs[RIGHT] << 2 | inputs[UP] << 1 | inputs[DOWN] | |
response(0x30, counter, buf) | |
time.sleep(0.03) | |
def simulate_procon(): | |
while True: | |
try: | |
data = os.read(gadget, 128) | |
if data[0] == 0x80: | |
if data[1] == 0x01: | |
response(0x81, data[1], bytes.fromhex('0003' + mac_addr)) | |
elif data[1] == 0x02: | |
response(0x81, data[1], []) | |
elif data[1] == 0x04: | |
threading.Thread(target=input_response).start() | |
else: | |
print('>>>', data.hex()) | |
elif data[0] == 0x01 and len(data) > 16: | |
if data[10] == 0x01: # Bluetooth manual pairing | |
uart_response(0x81, data[10], [0x03]) | |
elif data[10] == 0x02: # Request device info | |
uart_response(0x82, data[10], bytes.fromhex('03480302' + mac_addr[::-1] + '0301')) | |
elif data[10] == 0x03 or data[10] == 0x08 or data[10] == 0x30 or data[10] == 0x38 or data[10] == 0x40 or data[10] == 0x48: | |
uart_response(0x80, data[10], []) | |
elif data[10] == 0x04: # Trigger buttons elapsed time | |
uart_response(0x83, data[10], []) | |
elif data[10] == 0x21: # Set NFC/IR MCU configuration | |
uart_response(0xa0, data[10], bytes.fromhex('0100ff0003000501')) | |
elif data[10] == 0x10: | |
if data[11:13] == b'\x00\x60': # Serial number | |
spi_response(data[11:13], bytes.fromhex('ffffffffffffffffffffffffffffffff')) | |
elif data[11:13] == b'\x50\x60': # Controller Color | |
spi_response(data[11:13], bytes.fromhex('bc1142 75a928 ffffff ffffff ff')) # Raspberry Color | |
elif data[11:13] == b'\x80\x60': # Factory Sensor and Stick device parameters | |
spi_response(data[11:13], bytes.fromhex('50fd0000c60f0f30619630f3d41454411554c7799c333663')) | |
elif data[11:13] == b'\x98\x60': # Factory Stick device parameters 2 | |
spi_response(data[11:13], bytes.fromhex('0f30619630f3d41454411554c7799c333663')) | |
elif data[11:13] == b'\x3d\x60': # Factory configuration & calibration 2 | |
spi_response(data[11:13], bytes.fromhex('ba156211b87f29065bffe77e0e36569e8560ff323232ffffff')) | |
elif data[11:13] == b'\x10\x80': # User Analog sticks calibration | |
spi_response(data[11:13], bytes.fromhex('ffffffffffffffffffffffffffffffffffffffffffffb2a1')) | |
elif data[11:13] == b'\x28\x80': # User 6-Axis Motion Sensor calibration | |
spi_response(data[11:13], bytes.fromhex('beff3e00f001004000400040fefffeff0800e73be73be73b')) | |
else: | |
print("Unknown SPI address:", data[11:13].hex()) | |
else: | |
print('>>> [UART]', data.hex()) | |
elif data[0] == 0x10 and len(data) == 10: | |
pass | |
else: | |
print('>>>', data.hex()) | |
except BlockingIOError: | |
pass | |
except: | |
os._exit(1) | |
threading.Thread(target=simulate_procon).start() | |
threading.Thread(target=countup).start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment