← Developer's Journal

PSP USB Research: From Firmware Decryption to a Custom Device Driver

What started as an attempt to enable USB host mode became a deep reverse engineering expedition — decrypting Sony's USB firmware, mapping undocumented hardware registers, and ultimately building a working custom USB device driver in Rust that turns the PSP into a thin client for external compute.

The Original Goal

The plan was straightforward: enable USB host mode on the PSP so it could supply 5V VBUS power and communicate with microcontrollers like the Luckfox Pico. Sony's first-party accessories (Go!Cam, GPS, TV tuner) proved the hardware could do it. We just needed to find the right register writes.

What followed was three weeks of increasingly deep reverse engineering across two PSP models (PSP-1001 and PSP-3001), dozens of firmware experiments, and the decryption of Sony's USB firmware blob — ultimately leading to a fundamental discovery about how PSP accessories actually work.

The Discovery: PSP Accessories Are the Host

After exhaustively testing every accessible register, Syscon command, and GPIO pin, we discovered that the PSP never acts as a USB host. Sony's accessories contain their own USB host controller chips. The PSP is always the device. The accessories power themselves from dedicated side contact pins on the PSP's USB port, not from VBUS.

How PSP Accessories Actually Work

What we assumed:
  PSP (host) ──VBUS 5V──> Accessory (device)
  PSP enumerates and controls the peripheral

What actually happens:
  PSP (device) <──data──> Accessory (host)
  Accessory has its own host chip + power
  PSP presents itself as a custom USB device
  Accessory controls the conversation
The PSP's Mini-B port is always a device port — accessories are the masters

The Reverse Engineering Journey

Phase 0–1: VBUS Experiments

Built kernel-mode Rust EBOOTs to probe the PSP's USB hardware. Tested GPIO pins, Syscon SPI commands (0x00–0x50), SYSCTL registers, and USB PHY configuration. No VBUS appeared on either PSP model despite setting every accessible bit.

Phase 2: Firmware Decryption

Extracted and decrypted the USB firmware blob embedded within usb_cam.prx:

Phase 3: Register Map Discovery

The firmware analysis revealed three previously undocumented register blocks:

Address BlockPurposeKey Finding
0xBE4C0000 USB PHY serial controller Clock, mode, features — configures the physical layer
0xBD101000 OHCI host controller Gated by BC100050 bit 13 — fully functional OHCI 1.0 rev 3
0xBDE00000 Raw SPI/DMA controller Dead code in firmware — never called

We also mapped the complete Syscon command set for Baryon 0x00040600 (256 GET commands, 14 SET commands identified from kernel disassembly) and found the _sceSysconCommonWrite function with its GET/SET pairing (e.g., GET=0x46, SET=0x47 for USB power).

The Pivot: Custom USB Device Driver

With USB host mode ruled out, we pivoted to the correct architecture: the PSP as a USB device with custom bulk endpoints. If we want the PSP to talk to a Luckfox Pico, the Pico should be the USB host and the PSP should present a custom device interface.

PSP Thin Client Architecture

┌─────────────────┐   USB 2.0   ┌──────────────────┐
│  Luckfox Pico   │◄───────────►│       PSP        │
│  (USB Host)     │   480Mbps   │  (USB Device)    │
│                 │   bulk xfer │                  │
│  ARM Cortex-A7  │             │  Custom driver:  │
│  Linux + libusb │             │  sceUsbbdRegister│
│  AI / compute   │             │  EP1 IN  (0x81)  │
│  networking     │             │  EP2 OUT (0x02)  │
│  $9, 51x21mm    │             │                  │
└─────────────────┘             └──────────────────┘
The PSP registers a vendor-specific USB device with bulk endpoints

sceUsbbd: The Undocumented Kernel API

The PSP's sceUsbBus_driver exports functions for registering custom USB device drivers — the same API that Sony's mass storage and camera drivers use internally. These functions are kernel-only and not documented in any public SDK:

FunctionNID (6.61)Purpose
sceUsbbdRegister 0xB1644BE7 Register a custom USB device driver
sceUsbbdReqSend 0x913EC15D Queue async bulk IN transfer (device→host)
sceUsbbdReqRecv 0x7B87815D Queue async bulk OUT transfer (host→device)

The NIDs were resolved from the PSP-3001's kernel memory dump — the standard PSPSDK NIDs are wrong for 6.61 firmware. The functions require direct address calls rather than NID-resolved stubs on ARK-4 CFW.

It Works

The custom USB device driver successfully registers with the PSP's USB bus driver and presents itself to any connected USB host:

$ lsusb
Bus 003 Device 073: ID 054c:1337 Sony Corp.

$ lsusb -v -d 054c:1337
  idVendor         0x054c Sony Corp.
  idProduct        0x1337
    Interface Descriptor:
      bInterfaceClass     255 Vendor Specific Class
      bNumEndpoints         2
      Endpoint Descriptor:
        bEndpointAddress  0x81  EP 1 IN  (Bulk, 512 bytes)
      Endpoint Descriptor:
        bEndpointAddress  0x02  EP 2 OUT (Bulk, 512 bytes)

Two high-speed bulk endpoints at 512 bytes per packet — enough for ~30 MB/s sustained throughput. A full 480×272 RGBA framebuffer (522 KB) can be transferred in under 20ms, enabling 30+ FPS thin client rendering.

Phase 2: VBUS Power Output Research (Ongoing)

While the thin client architecture works over USB device mode, the original goal of powering a Luckfox Pico from the PSP's USB port remains compelling. We returned to the VBUS problem with new tools.

On-Device PRX Decryption

Built a kernel-mode EBOOT (oasis-prx-decrypt-psp) that uses the PSP's own Kirk hardware crypto engine (memlmd NID 0xEF73E85B) to decrypt firmware modules. Successfully decrypted all 15 USB/system PRX files from flash0:/kd/ — something desktop tools couldn't do with 6.61 keys.

NID Analysis: The MUSB Discovery

A standalone binary analyzer (scripts/psp_nid_analyze.py) scanned the decrypted usb.prx and revealed a critical finding: the USB driver has 143 references to the MUSB (Mentor USB OTG) controller at 0xBD80xxxx and zero to the OHCI controller we'd been testing. We'd been probing the wrong USB controller.

PRX FileKey Finding
usb.prx 143 MUSB accesses, GPIO pin 23 VBUS enable at offset 0x8C74, 14 sceSysreg imports
lowio.prx 50 GPIO accesses, 90 sceSysreg — the actual GPIO hardware driver
syscon.prx Also controls GPIO pin 23 directly, accesses BC100083

Interactive VBUS Test Tool

The 19-step interactive EBOOT (oasis-usb-vbus-psp) tested every accessible approach to enabling VBUS on the PSP-3001 (TA-090v2):

The Verdict: Silicon-Level Lock

Ghidra decompilation of lowio.prx (run via an amd64 Docker container on our ARM64 host) revealed the GPIO output enable register at 0xBE240024 — written by sceGpioSetPortMode2 with 1 << pin. On-device testing confirmed this register rejects all writes on TA-090v2, along with AltFunc (0xBE240040) and BC1000C4.

An exhaustive search followed: all 14 sceSysreg NIDs, every Syscon command 0x00–0xFF, the sysreg GPIO port enable (BC10007C), USB bus gates, scePower functions, OTG ID pin grounding with two different adapters, and live register monitoring during cable plug/unplug. Nothing unlocks the GPIO output enable.

The lock is set by the Tachyon SoC's mask ROM during the earliest boot phase, before any firmware code executes. It cannot be overridden from kernel mode. Sony's Go!Cam accessory likely triggers VBUS through a hardware detection circuit in the Syscon or Pommel chip that monitors USB connector pin voltages — not through any software command or the standard OTG ID pin.

What's Next