Artemis Milestone 2f: EP0 control transfer, device descriptor request

Adds Setup/Data/Status stage TRB types and control bits (IDT, TRT, DIR)
to xhci.h, and xhci_ep0_enqueue_trb()/xhci_ep0_get_device_descriptor() to
xhci.c -- the first real control transfer this driver has issued.
Follows the same enqueue-then-doorbell-once pattern as the Command Ring,
operating on the EP0 Transfer Ring built during 2e's Address Device work.
Setup Stage uses Immediate Data (parameter IS the 8-byte setup packet);
Data Stage reads into a reused 18-byte device_descriptor buffer; Status
Stage alone carries IOC, so exactly one Transfer Event signals transfer
completion, correlated via a new pending_transfer_slot_id (same
single-outstanding-operation pattern as connect/Enable Slot/Address
Device).

Automatically triggered once Address Device succeeds. Verified live via
QMP hotplug, all three architectures, worked first try with identical
results everywhere: idVendor=0x46f4, idProduct=0x0001, bDeviceClass=0x00
-- the class=0 confirms Mass Storage class detection needs the
Configuration/Interface descriptor (2f's next item), not the device
descriptor.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm
This commit is contained in:
Robert Allan James
2026-08-22 12:59:49 -04:00
co-authored by Claude Sonnet 5
parent 2e7e957680
commit 2c34e45d05
13 changed files with 36397 additions and 6 deletions
+22 -2
View File
@@ -3323,8 +3323,11 @@ increment's test device was SuperSpeed and self-enabled), disconnect teardown (D
command, DCBAA entry clear), and the callback surface into Section U's higher-level code.
**2f. USB device enumeration (post-connect, before it's usable as storage)**
- [ ] Request and parse the device descriptor (confirm vendor/product IDs are even needed,
or if class-only detection suffices for this project's purposes)
- [x] Request and parse the device descriptor **done 2026-08-22**, see writeup below.
Answered its own open question: `bDeviceClass=0x00` on the real test device (QEMU's
`usb-storage`), meaning class is defined at the interface level, not device level, for
standard Mass Storage devices — confirms the "is this a USB drive" check has to read the
Configuration/Interface descriptor (next item below), not the device descriptor
- [ ] Request and parse the configuration descriptor
- [ ] Confirm the device reports the Mass Storage class / Bulk-Only Transport subclass/
protocol (this is the actual "is this a USB drive" check — separate from, and prior
@@ -3332,6 +3335,23 @@ command, DCBAA entry clear), and the callback surface into Section U's higher-le
layer up, after the drive is already known to be USB mass storage)
- [ ] Set the device configuration (SET_CONFIGURATION control transfer)
**Device descriptor request, done 2026-08-22.** Extends the EP0 Transfer Ring built in 2e's
Address Device work with real control-transfer submission: a new `xhci_ep0_enqueue_trb()`
(same fixed-ring-plus-Link-TRB pattern as the Command Ring) posts Setup/Data/Status stage TRBs
as a group, doorbell rung once after all three — matching how xHCI actually processes a
control transfer, not one doorbell ring per TRB. Setup Stage uses `IDT` (Immediate Data — the
TRB's `parameter` field IS the 8-byte USB setup packet, not a pointer to one) and `TRT=3` (IN
Data Stage); Data Stage points at a reused `device_descriptor[18]` buffer with `DIR=IN`;
Status Stage has `DIR=OUT` (the reverse handshake direction) and is the only one of the three
with `IOC` set, so exactly one Transfer Event signals "the whole control transfer is done" —
correlated via a new `dev->pending_transfer_slot_id`, same single-outstanding-operation pattern
already used for connect/Enable Slot/Address Device.
Verified live via QMP hotplug, all three architectures, worked first try, byte-identical
results everywhere: `idVendor=0x46f4` (QEMU's own USB vendor ID), `idProduct=0x0001`,
`bDeviceClass=0x00`. `logs/20260822-125515/amd64/`, `logs/20260822-125624/aarch64/`,
`logs/20260822-125800/riscv64/`.
**2g. Bulk-Only Transport (BOT) — the actual read/write path**
- [ ] Identify and configure the device's bulk IN and bulk OUT endpoints
- [ ] Implement CBW (Command Block Wrapper) construction and send, for a SCSI READ(10)