Artemis Milestone 2g (partial): bulk endpoint discovery + 2e disconnect teardown
Picked up from a crashed session: xhci_driver.h/xhci.h already had the bulk_in/out_ep_addr/max_packet fields and Endpoint-descriptor offset macros scaffolded, but the actual walk that populates them was never written. Added it: after 2f confirms a Mass Storage/SCSI/BOT interface, a nested walk continues through the Endpoint descriptors that follow it (bDescriptorType==5, stopping at the next Interface descriptor or end of stream), keeping only Bulk-type endpoints and splitting IN/OUT by bEndpointAddress bit 7. Also reset the four new fields in xhci_bringup(), which the scaffolding had missed. Also completed 2e's disconnect teardown, which was fully implemented this session (not scaffolded): a Disable Slot command is now submitted on a real disconnect, with the port's tracked slot ID captured and cleared from port_slot_id[] immediately (before the command completes) so a fresh connect on the same port isn't confused for one already in progress, and DCBAA[slot_id] cleared only on a successful completion. Verified live via QMP hotplug (deliberate device_add/device_del against freshly launched, individually-tracked instances -- not whatever happened to be attached at boot), all three architectures, byte-identical: bulk IN endpoint=0x81, bulk OUT endpoint=0x02, then a clean disconnect -> disable slot succeeded, no wedge. Caught and fixed a documentation near-miss in the same pass: an initial draft cited the probe-free three-arch acceptance boots as this feature's verification evidence, but a stale leftover log directory from a pre-crash orphaned QEMU process had been picked up by an `ls -dt | head -1` glob during monitoring and mistaken for this session's own result -- the real acceptance logs never had a device attached at all. Re-verified against real PIDs and real log paths before writing FABRIC-2.md's final writeup. FABRIC-2.md Section X Milestone 2 updated: 2e's disconnect-teardown checklist item marked done, 2g's endpoint-identification item marked partially done (identification only -- Configure Endpoint / EP Context wiring is still open). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R4VMX6VSKCten8nGgaMkq4
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b4bbd043d0
commit
96d55fcd87
@@ -192,6 +192,7 @@ typedef struct {
|
||||
/* TRB types used by this driver (subset — xHCI defines many more) */
|
||||
#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_DISABLE_SLOT_CMD 10
|
||||
#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
|
||||
@@ -260,6 +261,19 @@ typedef struct {
|
||||
#define USB_SUBCLASS_SCSI 0x06u /* SCSI transparent command set */
|
||||
#define USB_PROTOCOL_BOT 0x50u /* Bulk-Only Transport */
|
||||
|
||||
/* Standard USB Endpoint descriptor field offsets (7 bytes, USB 2.0 spec
|
||||
* table 9-13) -- found the same way as the Interface descriptor: walked
|
||||
* by bDescriptorType within the concatenated stream, not a fixed offset,
|
||||
* since the number of endpoints on the interface isn't known up front. */
|
||||
#define USB_DESC_TYPE_ENDPOINT 5u
|
||||
#define USB_EP_OFF_ADDRESS 2u /* bEndpointAddress: bit 7 = direction, bits 3:0 = number */
|
||||
#define USB_EP_OFF_ATTRIBUTES 3u /* bmAttributes: bits 1:0 = transfer type */
|
||||
#define USB_EP_OFF_MAX_PACKET_SIZE 4u /* wMaxPacketSize, 2 bytes */
|
||||
#define USB_EP_ADDR_DIR_MASK 0x80u
|
||||
#define USB_EP_ADDR_NUM_MASK 0x0Fu
|
||||
#define USB_EP_ATTR_TYPE_MASK 0x03u
|
||||
#define USB_EP_TYPE_BULK 0x02u
|
||||
|
||||
/* 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
|
||||
|
||||
@@ -70,9 +70,21 @@ typedef struct {
|
||||
enum {
|
||||
XHCI_CONN_IDLE = 0,
|
||||
XHCI_CONN_AWAIT_ENABLE_SLOT,
|
||||
XHCI_CONN_AWAIT_ADDRESS_DEVICE
|
||||
XHCI_CONN_AWAIT_ADDRESS_DEVICE,
|
||||
XHCI_CONN_AWAIT_DISABLE_SLOT
|
||||
} connect_state;
|
||||
uint32_t pending_connect_slot_id;
|
||||
/* Milestone 2e/2g: disconnect teardown. Same single-outstanding-
|
||||
* command assumption as Enable Slot/Address Device above -- a
|
||||
* disconnect that arrives while another Command Ring command is
|
||||
* already outstanding is dropped rather than queued (matches the
|
||||
* existing "enable slot already pending -- dropped" precedent).
|
||||
* pending_disable_slot_id is captured at disconnect time, since the
|
||||
* port's own tracked slot ID (port_slot_id[]) is cleared immediately
|
||||
* on disconnect so a fresh connect on the same port isn't confused
|
||||
* for one already in progress -- by the time the Disable Slot
|
||||
* command's completion arrives, the port array no longer has it. */
|
||||
uint32_t pending_disable_slot_id;
|
||||
void *input_ctx; /* Input Control Ctx + Slot Ctx + EP0 Ctx (96 bytes, 32-byte contexts) */
|
||||
void *device_ctx; /* Slot Ctx + EP0 Ctx (64 bytes) -- DCBAA[slot_id] points here */
|
||||
xhci_trb_t *ep0_ring; /* EP0 Transfer Ring, XHCI_RING_TRB_COUNT TRBs */
|
||||
@@ -107,6 +119,19 @@ typedef struct {
|
||||
uint8_t config_descriptor[128];
|
||||
uint16_t config_total_length;
|
||||
|
||||
/* Milestone 2g: bulk endpoints, discovered by walking the Endpoint
|
||||
* descriptors that follow the confirmed Mass Storage/BOT Interface
|
||||
* descriptor in config_descriptor. bEndpointAddress in full (not just
|
||||
* the endpoint number) -- bit 7 is needed later to pick the right
|
||||
* Doorbell target / EP Context DCI, and callers that want direction
|
||||
* alone can just mask it. 0 means "not found yet" for both --
|
||||
* endpoint address 0 is always EP0 (control), never a valid bulk
|
||||
* endpoint address, so it's a safe not-found sentinel. */
|
||||
uint8_t bulk_in_ep_addr;
|
||||
uint16_t bulk_in_max_packet;
|
||||
uint8_t bulk_out_ep_addr;
|
||||
uint16_t bulk_out_max_packet;
|
||||
|
||||
/* Deferred chaining: a doorbell ring (new control transfer) must
|
||||
* never happen synchronously from inside xhci_poll_events()'s event-
|
||||
* processing loop, before ERDP has been updated for the event
|
||||
@@ -209,6 +234,22 @@ void xhci_poll_events(void);
|
||||
*/
|
||||
int xhci_cmd_enable_slot(xhci_dev_t *dev);
|
||||
|
||||
/*
|
||||
* xhci_cmd_disable_slot — submit a Disable Slot command TRB for slot_id
|
||||
* and ring doorbell 0. Does not wait for or read
|
||||
* the resulting Command Completion Event -- it
|
||||
* arrives asynchronously via xhci_poll_events(),
|
||||
* which clears DCBAA[slot_id] on success.
|
||||
*
|
||||
* Called from xhci_poll_events()'s own Port Status Change handling on a
|
||||
* real disconnect event, for a slot that was actually addressed -- not
|
||||
* called directly by other code.
|
||||
*
|
||||
* Returns 0 if the command was posted, -1 if dev/dev->cmd_ring is not set
|
||||
* up.
|
||||
*/
|
||||
int xhci_cmd_disable_slot(xhci_dev_t *dev, uint32_t slot_id);
|
||||
|
||||
/*
|
||||
* xhci_cmd_address_device — build the Input Context (Slot + EP0, add-only),
|
||||
* program DCBAA[slot_id] with the Device Context,
|
||||
|
||||
Reference in New Issue
Block a user