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
+33
View File
@@ -193,6 +193,9 @@ typedef struct {
#define XHCI_TRB_TYPE_LINK 6 /* ring-wraparound marker, Command/Transfer Rings only */
#define XHCI_TRB_TYPE_ENABLE_SLOT_CMD 9
#define XHCI_TRB_TYPE_ADDRESS_DEVICE_CMD 11
#define XHCI_TRB_TYPE_SETUP_STAGE 2 /* Transfer Ring, control transfers only */
#define XHCI_TRB_TYPE_DATA_STAGE 3
#define XHCI_TRB_TYPE_STATUS_STAGE 4
#define XHCI_TRB_TYPE_TRANSFER_EVENT 32
#define XHCI_TRB_TYPE_COMMAND_COMPLETION_EVT 33
#define XHCI_TRB_TYPE_PORT_STATUS_CHANGE_EVT 34
@@ -200,6 +203,36 @@ typedef struct {
/* Control bits used only by Link TRBs */
#define XHCI_TRB_CONTROL_TC (1u << 1) /* Toggle Cycle */
/* Control bits for control-transfer TRBs (xHCI 1.2 spec section 4.11.2.2 /
* table 6-23..6-25). IDT (Immediate Data) tells the controller the Setup
* Stage TRB's parameter field IS the 8-byte setup packet, not a pointer
* to one -- required for every Setup Stage TRB. TRT/DIR select data
* direction: TRT=3 (IN Data Stage) for the standard "read a descriptor"
* case this driver needs first; DIR must match TRT's direction on the
* Data Stage TRB, and the Status Stage TRB's DIR is the OPPOSITE
* direction of the Data Stage (status is always the reverse handshake). */
#define XHCI_TRB_CONTROL_IDT (1u << 6)
#define XHCI_TRB_CONTROL_IOC (1u << 5) /* Interrupt On Completion */
#define XHCI_TRB_CONTROL_DIR_IN (1u << 16) /* Data/Status Stage: 1=IN, 0=OUT */
#define XHCI_SETUP_TRT_NO_DATA 0u
#define XHCI_SETUP_TRT_OUT_DATA 2u
#define XHCI_SETUP_TRT_IN_DATA 3u
#define XHCI_TRB_CONTROL_TRT_SHIFT 16 /* Setup Stage TRB only; Data/Status Stage overlays DIR at the same bit */
/* Standard USB Setup packet (8 bytes) -- the exact bytes placed in a
* Setup Stage TRB's parameter field via IDT. */
typedef struct {
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} usb_setup_packet_t;
#define USB_REQ_GET_DESCRIPTOR 6u
#define USB_DESC_TYPE_DEVICE 1u
#define USB_DIR_DEVICE_TO_HOST 0x80u
/* Command Completion Event TRB layout (xHCI 1.2 spec table 6-32):
* parameter[63:4] = Command TRB Pointer, status[31:24] = Completion Code,
* status[23:0] = unused here, control[31:24] = Slot ID (Enable Slot's
+31
View File
@@ -78,6 +78,16 @@ typedef struct {
xhci_trb_t *ep0_ring; /* EP0 Transfer Ring, XHCI_RING_TRB_COUNT TRBs */
uint32_t ep0_ring_cycle;
uint32_t ep0_ring_enq;
/* Milestone 2f: EP0 control transfers. Like connect_state, this
* driver only ever has one control transfer outstanding at a time --
* pending_transfer_slot_id is 0 when idle, else the slot ID whose
* Transfer Event (posted only by the Status Stage TRB, which alone
* has IOC set) is still outstanding. device_descriptor is the
* (reused, not per-slot) buffer control transfers read into; 18
* bytes is the full standard USB device descriptor size. */
uint32_t pending_transfer_slot_id;
uint8_t device_descriptor[18];
} xhci_dev_t;
/*
@@ -181,4 +191,25 @@ int xhci_cmd_enable_slot(xhci_dev_t *dev);
int xhci_cmd_address_device(xhci_dev_t *dev, uint32_t slot_id,
uint32_t port_id, uint32_t speed);
/*
* xhci_ep0_get_device_descriptor — issue a standard GET_DESCRIPTOR
* (Device) control transfer (Setup +
* Data-IN + Status-OUT stages) on
* slot_id's EP0, reading the 18-byte
* result into dev->device_descriptor.
* Does not wait for completion -- the
* result arrives asynchronously via
* xhci_poll_events()'s Transfer Event
* handling, which currently only logs
* success/failure (parsing the fields
* is the next increment).
*
* Called once Address Device succeeds -- not called directly by other
* code yet (Milestone 2f is still in progress).
*
* Returns 0 if the transfer was posted, -1 if dev/dev->ep0_ring is not
* set up.
*/
int xhci_ep0_get_device_descriptor(xhci_dev_t *dev, uint32_t slot_id);
#endif /* STARKERNEL_XHCI_DRIVER_H */