Transfer
One control request on the real deviceTRANSFER runs one USB control transfer on the real device from the control PC; TRANSFER_RESP returns the result: a descriptor, a string, a vendor value, or the handshake that ended it.
control PC DEVICE chip HOST chip real device
| | | |
|-- TRANSFER, SEQ n ->| | |
| |-- link request ----->| |
| | |-- SETUP, OUT data ->|
| | |<-- IN data, status -|
| |<-- link answer ------| |
|<- TRANSFER_RESP, n -| | |The request crosses the inter-chip link on its own messages and joins the game PC's control requests in the host chip's control queue.
TRANSFER is advanced control and runs only under the imperfect-clone opt-in. Otherwise a request with a full setup packet gets 0xFC and never reaches the device.
TRANSFER
One request, one replyTRANSFER carries a target endpoint, an eight-byte setup packet, and any OUT data stage. Opcode 0x1A.
TRANSFER 0x1A · payload 9..512 bytes
Reply
| Offset | Field | Type | Notes |
|---|---|---|---|
| 0 | ep | u8 | 0 = EP0, else a control endpoint the real device declares, matched on bits 0-3 |
| 1 | bmRequestType | u8 | bit 7 is direction: 1 IN, 0 OUT |
| 2 | bRequest | u8 | request code |
| 3 | wValue | u16 | little-endian |
| 5 | wIndex | u16 | little-endian |
| 7 | wLength | u16 | data stage length, little-endian, at most 504 |
| 9.. | data | u8[] | OUT only: the first wLength bytes are the data stage |
Offsets 1 to 8 are the setup packet exactly as the device receives it, never rewritten or retried.
| Value | Effect |
|---|---|
| bit 7 = 1, IN | bytes after offset 8 ignored; the reply carries what the device sent, up to wLength |
| bit 7 = 0, OUT | the first wLength bytes sent, the rest ignored; fewer is refused |
An OUT stage tops out at 503 bytes, what a 512-byte payload leaves after ep and the setup packet.
A SET_CONFIGURATION or SET_INTERFACE sent here changes only the real device; the clone and the endpoints the host chip polls stay as the game PC set them.
| When | Sends |
|---|---|
| payload under 9 bytes | nothing; frame discarded |
| opt-in off | 0xFC |
wLength above 504 | 0xFC |
OUT request with fewer than wLength data bytes | 0xFC |
| host chip control queue full, from any user | 0xFC |
nonzero ep naming no declared control endpoint | 0xFE, or 0xFF with no device attached |
GET_DESCRIPTOR(device) on EP0, 18 bytes: setup 80 06 00 01 00 00 12 00.
+--------+--------+--------+--------+--------+ | A5 | 1A | 07 | 09 00 | 00 | +--------+--------+--------+--------+--------+ | SOF | TYPE | SEQ | LEN | ep | +--------+--------+--------+--------+--------+ +---------------+----------+--------+--------+--------+--------+ | 80 | 06 | 00 01 | 00 00 | 12 00 | lo hi | +---------------+----------+--------+--------+--------+--------+ | bmRequestType | bRequest | wValue | wIndex | wLength| CRC16 | +---------------+----------+--------+--------+--------+--------+
An OUT request: SET_REPORT(Output) on interface 0 with one data byte, 02, a boot keyboard's Caps Lock LED.
+--------+--------+--------+--------+--------+ | A5 | 1A | 08 | 0A 00 | 00 | +--------+--------+--------+--------+--------+ | SOF | TYPE | SEQ | LEN | ep | +--------+--------+--------+--------+--------+ +---------------+----------+--------+--------+--------+--------+--------+ | 21 | 09 | 00 02 | 00 00 | 01 00 | 02 | lo hi | +---------------+----------+--------+--------+--------+--------+--------+ | bmRequestType | bRequest | wValue | wIndex | wLength| data | CRC16 | +---------------+----------+--------+--------+--------+--------+--------+
Library bindings: transfer, transfer_timeout, and the AsyncDevice forms.
TRANSFER_RESP
Result of one TRANSFEROne reply per TRANSFER with a full setup packet, its SEQ echoing the command's. Opcode 0x1B.
TRANSFER_RESP 0x1B · payload 2..506 bytes
Reply
| Offset | Field | Type | Notes |
|---|---|---|---|
| 0 | ep | u8 | echoes the command's ep byte |
| 1 | status | u8 | how the transfer ended, as below |
| 2.. | data | u8[] | IN data stage, only on an IN request with status = 0; length from the frame LEN |
| Value | State | Means |
|---|---|---|
0x00 | completed | the device finished the status stage; an IN request's data follows |
0xFC | refused | stopped before the device, per the refusals |
0xFD | STALL | the device STALLed the request |
0xFE | no answer | device didn't finish within 500 ms, the transfer failed on the bus, the endpoint is undeclared, or no reply crossed the link within 800 ms |
0xFF | no device | nothing attached on the host chip, or the host chip is re-enumerating it |
The same codes flag a CLIP_XFER event, the transfer a clip runs.
The device descriptor for SEQ 07 (18 data bytes, so LEN = 20):
+--------+--------+--------+--------+--------+--------+ | A5 | 1B | 07 | 14 00 | 00 | 00 | +--------+--------+--------+--------+--------+--------+ | SOF | TYPE | SEQ | LEN | ep | status | +--------+--------+--------+--------+--------+--------+ +--------------------------------------------+--------+ | 12 01 00 02 00 00 00 40 ... (18 bytes) | lo hi | +--------------------------------------------+--------+ | IN data: the device descriptor | CRC16 | +--------------------------------------------+--------+
A device that STALLs SEQ 08's request (no data):
+--------+--------+--------+--------+--------+--------+--------+ | A5 | 1B | 08 | 02 00 | 00 | FD | lo hi | +--------+--------+--------+--------+--------+--------+--------+ | SOF | TYPE | SEQ | LEN | ep | status | CRC16 | +--------+--------+--------+--------+--------+--------+--------+
One at a time
A TRANSFER holds the control port until its replyThe box runs a TRANSFER to completion before reading the next control frame, so replies arrive in command order.
TRANSFER A --> [ runs, up to 800 ms ] --> TRANSFER_RESP A TRANSFER B --> waits on the box -------------------------> [ runs ] --> TRANSFER_RESP B MOVE, ... --> waits on the box -------------------------> applied in arrival order
| Quantity | Value |
|---|---|
| Device reply, host chip | 500 ms, then 0xFE. |
| Link reply, device chip | 800 ms, then 0xFE. |
| Frames held while one runs | 63 frames, the running one included, or just under 16 KiB of payload; a frame past either is dropped. |
| Injection silence timer | Restarts when the frame is read and again when a reply arrives; an 800 ms timeout leaves it counting from the frame. |
Every other command waits behind a running TRANSFER, including MOVE and INJECT; keep transfers out of time-critical streams.
An 0xFE from the 800 ms window leaves the request queued on the host chip; it can still reach the device after the reply, and its late result is dropped.
One control queue
Requests to the real device take turnsThe host chip feeds the real device one control request at a time from one six-deep queue, shared by TRANSFER, the game PC's requests, clip transfers, and the box's own.
game PC ------EP0------> clone -----------------+
|
clip transfer items ---> DEVICE chip -----------+
|
control PC --TRANSFER--> DEVICE chip -----------+--> HOST chip queue --> real device
| six deep one at a time
halt clears, baseline reads (HOST chip) --------+A queue filled by any of them refuses a TRANSFER with 0xFC.
A TRANSFER runs outside every tap, rule and trigger: CATCH CONTROL, REWRITE on CONTROL, and clip packet triggers cover the game PC's traffic only.
A slow request holds the device's EP0 for up to 500 ms, and a game PC request queued behind it waits that long.