# 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 binascii import hexlify as hx, unhexlify as uhx from pathlib import Path CMD_ID_EXIT = 0 CMD_ID_FILE_RANGE = 1 CMD_ID_FILE_RANGE_PADDED = 2 CMD_TYPE_RESPONSE = 1 BUFFER_SEGMENT_DATA_SIZE = 0x100000 PADDING_SIZE = 0x1000 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) if (padding): buf = b'\x00' * PADDING_SIZE + buf 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') # Find the switch dev = usb.core.find(idVendor=0x057E, idProduct=0x3000) if dev is None: raise ValueError('Switch is not found!') 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 send_nsp_list(nsp_dir, out_ep) poll_commands(nsp_dir, in_ep, out_ep)