<!-- Source: https://medius.k4tech.net/native/commands/transfer -->
# Transfer

_One control request on the real device_

[`TRANSFER`](/native/commands/transfer.md#transfer) runs one USB control transfer on the real device from the control PC; [`TRANSFER_RESP`](/native/commands/transfer.md#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](/native/commands/transfer.md#proxy).

> **Warning**
>
> `TRANSFER` is advanced control and runs only under the [imperfect-clone opt-in](/native/commands/option.md#imperfect). Otherwise a request with a full setup packet gets `0xFC` and never reaches the device.

## TRANSFER

_One request, one reply_

`TRANSFER` carries a target endpoint, an eight-byte setup packet, and any OUT data stage. [Opcode](/native/frame.md#opcodes) `0x1A`.

```text
TRANSFER 0x1A · payload 9..512 bytes
```

_Reply_

#### PAYLOAD

| 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.

#### DATA STAGE

| 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](/native/frame.md#layout) leaves after `ep` and the setup packet.

> **Warning**
>
> 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.

#### REFUSALS

| When | Sends |
| --- | --- |
| payload under 9 bytes | nothing; frame discarded |
| [opt-in](/native/commands/option.md#imperfect) off | `0xFC` |
| `wLength` above `504` | `0xFC` |
| OUT request with fewer than `wLength` data bytes | `0xFC` |
| host chip [control queue](/native/commands/transfer.md#proxy) full, from any user | `0xFC` |
| nonzero `ep` naming no declared control endpoint | `0xFE`, or `0xFF` with no device attached |

#### EXAMPLE

`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`](/library/advanced/transfer.md#transfer), [`transfer_timeout`](/library/advanced/transfer.md#transfer), and the [`AsyncDevice`](/library/advanced/transfer.md#async) forms.

## TRANSFER_RESP

_Result of one TRANSFER_

One reply per [`TRANSFER`](/native/commands/transfer.md#transfer) with a full setup packet, its [`SEQ`](/native/frame.md#seq) echoing the command's. [Opcode](/native/frame.md#opcodes) `0x1B`.

```text
TRANSFER_RESP 0x1B · payload 2..506 bytes
```

_Reply_

#### PAYLOAD

| 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`](/native/frame.md#layout) |

#### STATUS

| 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](/native/commands/transfer.md#transfer) |
| `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`](/native/commands/catch.md#traffic-event) event, the transfer a [clip](/native/commands/clip.md#items) runs.

#### EXAMPLE

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 reply_

The 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
```

#### TIMING

| 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. |

> **Warning**
>
> Every other command waits behind a running `TRANSFER`, including [`MOVE`](/native/commands/move.md#move) and [`INJECT`](/native/commands/inject.md#inject); keep transfers out of time-critical streams.

> **Note**
>
> 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 turns_

The 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](/native/commands/clip.md#items) 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`.

#### TAPS

A `TRANSFER` runs outside every tap, rule and trigger: [`CATCH CONTROL`](/native/commands/catch.md#traffic-event), [`REWRITE`](/native/commands/rewrite.md) on `CONTROL`, and [clip packet triggers](/native/commands/clip.md#packet-triggers) cover the game PC's traffic only.

> **Warning**
>
> A slow request holds the device's EP0 for up to 500 ms, and a game PC request queued behind it waits that long.
