# This script depends on PyUSB. You can get it with pip install pyusb. # You will also need libusb installed # My sincere apologies for this process being overly complicated. Apparently Python and Windows # aren't very friendly :( # Windows Instructions: # 1. Download Zadig from https://zadig.akeo.ie/. # 2. With your switch plugged in and on the Tinfoil USB install menu, # choose "List All Devices" under the options menu in Zadig, and select libnx USB comms. # 3. Choose libusbK from the driver list and click the "Replace Driver" button. # 4. Run this script # macOS Instructions: # 1. Install Homebrew https://brew.sh # 2. Install Python 3 # sudo mkdir /usr/local/Frameworks # sudo chown $(whoami) /usr/local/Frameworks # brew install python # 3. Install PyUSB # pip3 install pyusb # 4. Install libusb # brew install libusb # 5. Plug in your Switch and go to Tinfoil > Title Management > USB Install NSP # 6. Run this script # python3 usb_install_pc.py import usb.core import usb.util import struct import sys from pathlib import Path import time CMD_ID_EXIT = 0 CMD_ID_FILE_RANGE = 1 CMD_TYPE_RESPONSE = 1 # list of supported extensions. EXTS = (".nsp", ".xci", ".nsz", ".xcz") def send_response_header(out_ep, cmd_id, data_size): out_ep.write(b'TUC0') # Tinfoil USB Command 0 out_ep.write(struct.pack('= end_off: read_size = end_off - curr_off buf = f.read(read_size) out_ep.write(data=buf, timeout=0) curr_off += read_size def poll_commands(nsp_dir, in_ep, out_ep): while True: cmd_header = bytes(in_ep.read(0x20, timeout=0)) magic = cmd_header[:4] print('Magic: {}'.format(magic), flush=True) if magic != b'TUC0': # Tinfoil USB Command 0 continue cmd_type = struct.unpack('""") if __name__ == '__main__': if len(sys.argv) != 2: print_usage() sys.exit(1) nsp_dir = Path(sys.argv[1]) if not nsp_dir.is_dir(): raise ValueError('1st argument must be a directory') print("waiting for switch...\n") dev = None while (dev is None): dev = usb.core.find(idVendor=0x057E, idProduct=0x3000) time.sleep(0.5) print("found the switch!\n") cfg = None try: cfg = dev.get_active_configuration() print("found active config") except usb.core.USBError: print("no currently active config") cfg = None if cfg is None: dev.reset() dev.set_configuration() cfg = dev.get_active_configuration() is_out_ep = lambda ep: usb.util.endpoint_direction(ep.bEndpointAddress) == usb.util.ENDPOINT_OUT is_in_ep = lambda ep: usb.util.endpoint_direction(ep.bEndpointAddress) == usb.util.ENDPOINT_IN out_ep = usb.util.find_descriptor(cfg[(0,0)], custom_match=is_out_ep) in_ep = usb.util.find_descriptor(cfg[(0,0)], custom_match=is_in_ep) assert out_ep is not None assert in_ep is not None print("iManufacturer: {} iProduct: {} iSerialNumber: {}".format(dev.manufacturer, dev.product, dev.serial_number)) print("bcdUSB: {} bMaxPacketSize0: {}".format(hex(dev.bcdUSB), dev.bMaxPacketSize0)) send_nsp_list(nsp_dir, out_ep) poll_commands(nsp_dir, in_ep, out_ep)