Completes the CBW -> Data-In -> CSW chain for READ(10) started last commit. xhci_bot_read_data_in() and xhci_bot_receive_csw(), each a single Normal TRB on the bulk IN Transfer Ring via a new xhci_bulk_in_enqueue_and_ring() helper (mirrors the OUT-side helper from CBW send). All three stages now chain automatically via the existing deferred next_action pattern: CBW completion defers into Data-In, Data-In completion defers into CSW receive, CSW completion is where signature/tag/status validation happens. Data-In reads into a new fixed 512-byte bot_data_buf -- single-block scope for this increment, matches QEMU's usb-storage reported block size; xhci_bot_send_read10() now refuses rather than overflow/truncate if a request exceeds it. CSW validation (BOT spec section 5.2) checks dCSWSignature and dCSWTag (a new bot_last_tag field, latched from the CBW) before trusting bCSWStatus at all, so a garbled/misaligned CSW read can't be misread as a clean pass. usb_bot_csw_t follows the same struct-with-explicit-length-not-sizeof discipline as usb_bot_cbw_t. Verified live via a temporary probe (written, run once, log captured, reverted per this project's own probe convention), all three architectures, byte-identical: the full CBW -> Data-In -> CSW exchange completes cleanly, well-formed CSW with correct signature and echoed tag, no wedge, clean disconnect immediately after. The SCSI command itself reports CSW status FAILED against the current test fixture -- expected at this stage (no TEST UNIT READY / UNIT ATTENTION handling implemented yet, consistent with a fresh-attach unit-attention condition, not a transport-layer defect) and not root-caused further here; the BOT mechanism itself is confirmed correct end to end. Probe-free re-verification afterward on all three architectures. FABRIC-2.md Section X Milestone 2g's CSW checklist item marked done; "get one real READ(10) working end to end" stays explicitly open, distinguishing "the mechanism works" from "the SCSI command succeeds." Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R4VMX6VSKCten8nGgaMkq4
476 lines
24 KiB
C
476 lines
24 KiB
C
/*
|
|
* xhci_driver.h — xHCI USB host controller driver public API for StarKernel
|
|
*
|
|
* Register-layout definitions live in xhci.h; this header is the driver's
|
|
* own state and public entry points, matching virtio_blk.h's split.
|
|
*/
|
|
|
|
#ifndef STARKERNEL_XHCI_DRIVER_H
|
|
#define STARKERNEL_XHCI_DRIVER_H
|
|
|
|
#include <stdint.h>
|
|
#include "starkernel/pci.h"
|
|
#include "starkernel/xhci.h"
|
|
|
|
/* Driver state for one xHCI controller instance. Only one controller is
|
|
* supported (matches virtio_blk's single-device precedent). */
|
|
typedef struct {
|
|
PciDevice pci;
|
|
uint64_t bar0_phys; /* physical MMIO base, BAR0 */
|
|
xhci_cap_regs_t *cap; /* BAR0 + 0 */
|
|
xhci_op_regs_t *op; /* BAR0 + cap->cap_length */
|
|
xhci_runtime_regs_t *runtime; /* BAR0 + cap->rts_off */
|
|
xhci_doorbell_t *doorbell; /* BAR0 + cap->db_off */
|
|
uint32_t max_slots;
|
|
uint32_t max_ports;
|
|
uint32_t max_intrs;
|
|
uint32_t max_scratchpad_bufs;
|
|
|
|
/* Set up by xhci_bringup(); NULL/0 until then. */
|
|
void *dcbaa; /* Device Context Base Address Array */
|
|
void *scratchpad_arr; /* array of scratchpad buffer pointers, if any */
|
|
xhci_trb_t *cmd_ring; /* Command Ring, XHCI_RING_TRB_COUNT TRBs;
|
|
* index XHCI_RING_TRB_COUNT-1 is a
|
|
* permanent Link TRB back to index 0 */
|
|
uint32_t cmd_ring_cycle; /* current Command Ring Cycle State (RCS) */
|
|
uint32_t cmd_ring_enq; /* next free Command Ring index (0..COUNT-2) */
|
|
xhci_trb_t *evt_ring; /* Event Ring, XHCI_RING_TRB_COUNT TRBs */
|
|
void *evt_ring_seg_table; /* Event Ring Segment Table (1 entry) */
|
|
uint32_t evt_ring_cycle; /* current Event Ring Cycle State */
|
|
uint32_t evt_ring_deq; /* current Event Ring dequeue index */
|
|
xhci_intr_regs_t *intr0; /* Interrupter 0 register set, cached
|
|
* by xhci_bringup() for
|
|
* xhci_poll_events() */
|
|
|
|
/* Milestone 2e: connect -> Enable Slot correlation. port_slot_id is
|
|
* indexed by port_id - 1 (1-based port IDs, matching PORTSC/Port
|
|
* Status Change Event numbering); 0 means no slot allocated for that
|
|
* port yet. Fixed-size, not heap-allocated -- XHCI_MAX_TRACKED_PORTS
|
|
* comfortably covers any real or emulated root hub's port count
|
|
* without adding a new kmalloc_aligned() call to xhci_bringup(); ports
|
|
* beyond this bound (checked against both this array and max_ports)
|
|
* are simply not tracked, matching this driver's existing preference
|
|
* for fixed allocations over dynamic growth (xhci.h's own ring-sizing
|
|
* rationale). Only one Enable Slot is ever in flight at a time (this
|
|
* driver issues commands synchronously with respect to connect events,
|
|
* not a queue) -- pending_connect_port_id is 0 when idle, or the
|
|
* port_id whose Command Completion Event is still outstanding. */
|
|
uint32_t port_slot_id[XHCI_MAX_TRACKED_PORTS];
|
|
uint32_t pending_connect_port_id;
|
|
uint32_t pending_connect_speed; /* PORTSC.Port Speed at connect time */
|
|
|
|
/* Milestone 2e: Address Device. This driver only ever addresses one
|
|
* device at a time (single-drive-at-a-time scope), so these are
|
|
* single, reused allocations rather than per-slot -- lazily allocated
|
|
* on the first connect that reaches xhci_cmd_address_device(), then
|
|
* reinitialised (not reallocated) on every subsequent connect. connect
|
|
* state tracks which command a still-outstanding completion event
|
|
* belongs to, since Enable Slot and Address Device are issued
|
|
* sequentially, not concurrently, for a given connect. */
|
|
enum {
|
|
XHCI_CONN_IDLE = 0,
|
|
XHCI_CONN_AWAIT_ENABLE_SLOT,
|
|
XHCI_CONN_AWAIT_ADDRESS_DEVICE,
|
|
XHCI_CONN_AWAIT_DISABLE_SLOT,
|
|
XHCI_CONN_AWAIT_CONFIGURE_ENDPOINT
|
|
} 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 */
|
|
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. transfer_purpose says which
|
|
* request that is, since xhci_poll_events() needs to know which
|
|
* buffer to interpret and what (if anything) to chain next on
|
|
* success -- e.g. a successful short Configuration descriptor read
|
|
* chains into a full-length read once wTotalLength is known.
|
|
* device_descriptor is the full 18-byte standard USB device
|
|
* descriptor; config_descriptor holds the Configuration descriptor
|
|
* and everything after it in the same read (Interface + Endpoint
|
|
* descriptors, concatenated, per USB spec) -- fixed 128 bytes,
|
|
* comfortably covers a single-interface Mass Storage device's full
|
|
* descriptor set without a dynamic allocation. All reused (not
|
|
* per-slot), matching this driver's single-device scope. */
|
|
enum {
|
|
XHCI_XFER_NONE = 0,
|
|
XHCI_XFER_DEVICE_DESC,
|
|
XHCI_XFER_CONFIG_DESC_SHORT,
|
|
XHCI_XFER_CONFIG_DESC_FULL,
|
|
XHCI_XFER_SET_CONFIG,
|
|
XHCI_XFER_CBW_SENT,
|
|
XHCI_XFER_BOT_DATA_IN,
|
|
XHCI_XFER_CSW_RECEIVED
|
|
} transfer_purpose;
|
|
uint32_t pending_transfer_slot_id;
|
|
uint8_t device_descriptor[18];
|
|
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;
|
|
|
|
/* Milestone 2g: bulk endpoint Transfer Rings, one per direction --
|
|
* same fixed-ring-plus-Link-TRB pattern as ep0_ring, lazily allocated
|
|
* once and reused across every connect (single-device scope, matching
|
|
* every other ring in this driver). Not usable for actual transfers
|
|
* until xhci_cmd_configure_endpoint() succeeds -- allocating them
|
|
* early (rather than only after success) keeps the allocation site in
|
|
* one place and lets the Input Context's EP Contexts point at real,
|
|
* already-initialised rings before the command is even submitted. */
|
|
xhci_trb_t *bulk_in_ring;
|
|
uint32_t bulk_in_ring_cycle;
|
|
uint32_t bulk_in_ring_enq;
|
|
xhci_trb_t *bulk_out_ring;
|
|
uint32_t bulk_out_ring_cycle;
|
|
uint32_t bulk_out_ring_enq;
|
|
|
|
/* Milestone 2g: Bulk-Only Transport. bot_cbw/bot_csw are reused across
|
|
* every command (single-outstanding-transfer scope, matching every
|
|
* other buffer in this driver) -- built/overwritten fresh each call,
|
|
* not preserved between calls. bot_next_tag is a free-running counter
|
|
* for dCBWTag; bot_last_tag latches the tag of the CBW currently in
|
|
* flight, so the CSW stage can verify dCSWTag matches (BOT spec
|
|
* requirement) without needing to re-derive it. bot_data_buf is a
|
|
* fixed 512-byte Data-In destination -- covers exactly one 512-byte
|
|
* block, this increment's whole scope (a real multi-block/variable-
|
|
* block-size transfer is 2h's problem once the block subsystem
|
|
* actually calls this path with real sizes). bot_expected_data_len is
|
|
* the byte count the Data-In stage was told to read, staged at CBW
|
|
* build time and consumed once the Data-In TRB is actually enqueued. */
|
|
usb_bot_cbw_t bot_cbw;
|
|
usb_bot_csw_t bot_csw;
|
|
uint32_t bot_next_tag;
|
|
uint32_t bot_last_tag;
|
|
uint8_t bot_data_buf[512];
|
|
uint32_t bot_expected_data_len;
|
|
|
|
/* 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
|
|
* currently being handled -- confirmed live (amd64 QEMU) to hang the
|
|
* guest outright when tried (a doorbell rung mid-acknowledgment of
|
|
* the previous event, evidenced by checkpoint logging showing
|
|
* execution stop exactly at the doorbell MMIO write). Chained
|
|
* requests (device descriptor -> short config read -> full config
|
|
* read) instead set these fields during event processing; the actual
|
|
* doorbell ring happens once, after the main loop and the ERDP
|
|
* write, from a small dispatch at the end of xhci_poll_events(). */
|
|
enum {
|
|
XHCI_NEXT_ACTION_NONE = 0,
|
|
XHCI_NEXT_ACTION_GET_DEVICE_DESC,
|
|
XHCI_NEXT_ACTION_GET_CONFIG_DESC,
|
|
XHCI_NEXT_ACTION_CONFIGURE_ENDPOINT,
|
|
XHCI_NEXT_ACTION_SET_CONFIG,
|
|
XHCI_NEXT_ACTION_BOT_DATA_IN,
|
|
XHCI_NEXT_ACTION_BOT_CSW_RECEIVE
|
|
} next_action;
|
|
uint32_t next_action_slot_id;
|
|
uint16_t next_action_length;
|
|
uint8_t next_action_config_value; /* SET_CONFIGURATION's wValue, staged by
|
|
* the CONFIG_DESC_FULL handler once
|
|
* bConfigurationValue is known */
|
|
} xhci_dev_t;
|
|
|
|
/*
|
|
* xhci_find_and_map — locate the xHCI controller on PCI bus 0, enable it
|
|
* (I/O+MEM+bus-master), map its BAR0 MMIO region, and
|
|
* fill in the four register-region pointers in *dev.
|
|
*
|
|
* dev must point to a zero-initialised xhci_dev_t.
|
|
*
|
|
* Returns 0 on success.
|
|
* Returns -1 if no xHCI device was found on the PCI bus.
|
|
* Returns -2 if the BAR0 mapping failed.
|
|
*/
|
|
int xhci_find_and_map(xhci_dev_t *dev);
|
|
|
|
/*
|
|
* xhci_bringup — reset the controller, allocate and program the DCBAA,
|
|
* Command Ring, and Event Ring (Interrupter 0), then start
|
|
* the controller (RUN/STOP=1) and confirm it left the
|
|
* halted state.
|
|
*
|
|
* Must be called after a successful xhci_find_and_map(). Does not enable
|
|
* interrupts (USBCMD.INTE / IMAN.IE) -- this driver is polled, not
|
|
* interrupt-driven (see xhci_poll_events()'s own doc comment for why).
|
|
*
|
|
* Returns 0 on success.
|
|
* Returns -1 on reset timeout.
|
|
* Returns -2 on allocation failure.
|
|
* Returns -3 if the controller failed to leave the halted state after RUN.
|
|
* On success, latches dev into the module-static pointer xhci_poll_events()
|
|
* reads -- only one controller is supported, matching virtio_blk's
|
|
* single-device precedent.
|
|
*/
|
|
int xhci_bringup(xhci_dev_t *dev);
|
|
|
|
/*
|
|
* xhci_poll_events — read Interrupter 0's Event Ring, dispatching each TRB
|
|
* by type: Port Status Change reads PORTSC to log
|
|
* connect/disconnect and acknowledges CSC; Command
|
|
* Completion and Transfer Event are logged only (slot
|
|
* allocation and BOT transfers are later increments).
|
|
* Advances the Event Ring dequeue pointer and clears
|
|
* ERDP.EHB when done.
|
|
*
|
|
* Polled, not interrupt-driven: an initial attempt at IRQ delivery
|
|
* (Milestone 2d's first draft) found the amd64 PCI INTx routing formula
|
|
* gives a demonstrably wrong GSI (checked live via QMP query-pci: xHCI at
|
|
* PCI slot 4 reports IRQ 10, the formula predicted 16), and the
|
|
* aarch64/riscv64 slot/pin-derived source IDs were unverified at the new
|
|
* slot this controller occupies. Rather than guess further at chipset
|
|
* PIRQ routing, this matches Section U item 6's own design intent
|
|
* (Captain Bob: "interrupt-driven, coarse cadence, cheap early-exit...
|
|
* quick check blocks... done") via sk_repl_idle()'s existing coarse-cadence
|
|
* hook instead of a per-arch IRQ path -- USB insertion is a human-timescale
|
|
* event, not a hot path, so polling costs nothing meaningful here.
|
|
*
|
|
* No arguments and no return value -- only one xHCI controller is
|
|
* supported, so the caller needs no device handle. A no-op if
|
|
* xhci_bringup() has not completed successfully (dev pointer not yet
|
|
* latched).
|
|
*/
|
|
void xhci_poll_events(void);
|
|
|
|
/*
|
|
* xhci_cmd_enable_slot — submit an Enable Slot command TRB to the Command
|
|
* Ring and ring doorbell 0. Does not wait for or
|
|
* read the resulting Command Completion Event -- it
|
|
* arrives asynchronously via xhci_poll_events(),
|
|
* which correlates the returned Slot ID back to
|
|
* dev->pending_connect_port_id and records it in
|
|
* dev->port_slot_id[].
|
|
*
|
|
* Called from xhci_poll_events()'s own Port Status Change handling on a
|
|
* real connect event -- not called directly by other code.
|
|
*
|
|
* Returns 0 if the command was posted, -1 if dev/dev->cmd_ring is not set
|
|
* up (xhci_bringup() has not completed).
|
|
*/
|
|
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,
|
|
* allocate the EP0 Transfer Ring, and submit an
|
|
* Address Device command TRB.
|
|
*
|
|
* speed is the PORTSC.Port Speed value read live at the connect this call
|
|
* is servicing (xHCI 1.2 spec table 7-13 speed IDs) -- used to pick EP0's
|
|
* default Max Packet Size before any device descriptor has been read.
|
|
*
|
|
* Refuses (-2) if HCCPARAMS1.CSZ indicates 64-byte contexts -- only
|
|
* 32-byte contexts are implemented (see xhci.h's own doc comment on
|
|
* xhci_slot_ctx32_t).
|
|
*
|
|
* Called from xhci_poll_events()'s Command Completion handling once Enable
|
|
* Slot succeeds -- not called directly by other code.
|
|
*
|
|
* Returns 0 if the command was posted, -1 on allocation failure, -2 if
|
|
* 64-byte contexts are required.
|
|
*/
|
|
int xhci_cmd_address_device(xhci_dev_t *dev, uint32_t slot_id,
|
|
uint32_t port_id, uint32_t speed);
|
|
|
|
/*
|
|
* xhci_cmd_configure_endpoint — build the Input Context (Slot + the two
|
|
* bulk EP Contexts, add-only), allocate the
|
|
* bulk Transfer Rings, and submit a
|
|
* Configure Endpoint command TRB for
|
|
* slot_id.
|
|
*
|
|
* Per xHCI 1.2 spec section 4.3.5, this must be issued after enumeration
|
|
* has identified the endpoints a device's chosen configuration/interface
|
|
* actually uses, and before the USB SET_CONFIGURATION request is sent to
|
|
* the device -- the reverse of that order (which this driver used before
|
|
* this increment) works against QEMU's lenient emulation but is not
|
|
* spec-correct. Requires dev->bulk_in_ep_addr/bulk_out_ep_addr to already
|
|
* be populated (2f's config descriptor walk) -- refuses if either is
|
|
* still 0 (not found).
|
|
*
|
|
* The Slot Context's Route String/Speed/Root Hub Port/Interrupter Target
|
|
* fields are copied from the already-addressed device's own Device
|
|
* Context (populated by a prior successful Address Device) rather than
|
|
* reconstructed from scratch -- those values aren't retained anywhere
|
|
* else by the time enumeration reaches this point (pending_connect_port_id
|
|
* is cleared as soon as Address Device completes). Only Context Entries is
|
|
* changed, to the highest DCI now in use.
|
|
*
|
|
* Called from xhci_poll_events()'s deferred next_action dispatch once the
|
|
* full Configuration descriptor has confirmed a Mass Storage/BOT interface
|
|
* and identified both bulk endpoints -- not called directly by other code.
|
|
*
|
|
* Returns 0 if the command was posted, -1 on allocation failure or missing
|
|
* prerequisite state, -2 if 64-byte contexts are required.
|
|
*/
|
|
int xhci_cmd_configure_endpoint(xhci_dev_t *dev, uint32_t slot_id);
|
|
|
|
/*
|
|
* xhci_bot_send_read10 — build a Command Block Wrapper for a SCSI
|
|
* READ(10) and submit it on the bulk OUT Transfer
|
|
* Ring; the Data-In stage and CSW receive follow
|
|
* automatically once this CBW's own completion
|
|
* arrives (see xhci_bot_read_data_in()/
|
|
* xhci_bot_receive_csw() below), same deferred-
|
|
* chaining pattern as device descriptor -> config
|
|
* descriptor -> Configure Endpoint -> SET_CONFIG.
|
|
*
|
|
* lba is the starting Logical Block Address, num_blocks the SCSI transfer
|
|
* length (blocks, not bytes -- READ(10)'s own field), block_size the
|
|
* device's actual bytes-per-block, used only to compute
|
|
* dCBWDataTransferLength (the data stage's total byte length CBW
|
|
* declares up front, not carried in the CDB itself). num_blocks*block_size
|
|
* must fit in dev->bot_data_buf (512 bytes, this increment's whole scope
|
|
* -- see xhci_dev_t's own doc comment) -- refuses otherwise.
|
|
*
|
|
* Does not wait for or read any of the three stages' Transfer Events --
|
|
* they arrive asynchronously via xhci_poll_events(), correlated via
|
|
* dev->transfer_purpose, same pattern as every other transfer in this
|
|
* driver. The final result (CSW signature/tag/status validated) is only
|
|
* ever logged, not returned to any caller -- there is no synchronous
|
|
* "did the read succeed" API yet; that's 2h's problem once something
|
|
* actually needs the data back.
|
|
*
|
|
* Requires bulk_out_ep_addr/bulk_out_ring and bulk_in_ep_addr/
|
|
* bulk_in_ring to already be populated (2f/2g's config descriptor walk
|
|
* and Configure Endpoint command) -- refuses if any prerequisite is
|
|
* missing.
|
|
*
|
|
* Returns 0 if the CBW was posted, -1 if a prerequisite is missing or
|
|
* the requested transfer size exceeds dev->bot_data_buf.
|
|
*/
|
|
int xhci_bot_send_read10(xhci_dev_t *dev, uint32_t slot_id, uint32_t lba,
|
|
uint16_t num_blocks, uint32_t block_size);
|
|
|
|
/*
|
|
* xhci_bot_read_data_in — submit a Normal TRB on the bulk IN Transfer
|
|
* Ring to read dev->bot_expected_data_len bytes
|
|
* into dev->bot_data_buf.
|
|
*
|
|
* Called from xhci_poll_events()'s deferred next_action dispatch once a
|
|
* CBW's own Command completion (XHCI_XFER_CBW_SENT) succeeds -- not
|
|
* called directly by other code.
|
|
*
|
|
* Returns 0 if the TRB was posted, -1 if bulk_in_ring isn't set up.
|
|
*/
|
|
int xhci_bot_read_data_in(xhci_dev_t *dev, uint32_t slot_id);
|
|
|
|
/*
|
|
* xhci_bot_receive_csw — submit a Normal TRB on the bulk IN Transfer Ring
|
|
* to read the 13-byte Command Status Wrapper into
|
|
* dev->bot_csw.
|
|
*
|
|
* Called from xhci_poll_events()'s deferred next_action dispatch once the
|
|
* Data-In stage's own Transfer Event (XHCI_XFER_BOT_DATA_IN) succeeds --
|
|
* not called directly by other code. The CSW's own completion
|
|
* (XHCI_XFER_CSW_RECEIVED) is where signature/tag/status validation
|
|
* against dev->bot_last_tag actually happens, in xhci_poll_events()
|
|
* itself, not here.
|
|
*
|
|
* Returns 0 if the TRB was posted, -1 if bulk_in_ring isn't set up.
|
|
*/
|
|
int xhci_bot_receive_csw(xhci_dev_t *dev, uint32_t slot_id);
|
|
|
|
/*
|
|
* 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.
|
|
* Sets dev->transfer_purpose so
|
|
* xhci_poll_events() knows how to
|
|
* interpret the completion.
|
|
*
|
|
* Called once Address Device succeeds -- not called directly by other
|
|
* code.
|
|
*
|
|
* 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);
|
|
|
|
/*
|
|
* xhci_ep0_get_config_descriptor — issue a GET_DESCRIPTOR (Configuration)
|
|
* control transfer for `length` bytes,
|
|
* reading into dev->config_descriptor
|
|
* (capped to its fixed size). Used
|
|
* twice per device: once for a short
|
|
* 9-byte read (just the Configuration
|
|
* descriptor header, to learn
|
|
* wTotalLength) and once for the full
|
|
* read once that length is known --
|
|
* xhci_poll_events() chains the second
|
|
* call automatically on the first
|
|
* read's success.
|
|
*
|
|
* Called once the device descriptor read succeeds -- not called directly
|
|
* by other code.
|
|
*
|
|
* Returns 0 if the transfer was posted, -1 if dev/dev->ep0_ring is not
|
|
* set up.
|
|
*/
|
|
int xhci_ep0_get_config_descriptor(xhci_dev_t *dev, uint32_t slot_id, uint16_t length);
|
|
|
|
/*
|
|
* xhci_ep0_set_configuration — issue a SET_CONFIGURATION control transfer
|
|
* (Setup + Status stage only, no Data stage)
|
|
* with wValue = config_value. Moves the
|
|
* device from Addressed into Configured
|
|
* state -- required before any endpoint
|
|
* other than EP0 (i.e. the bulk IN/OUT
|
|
* endpoints 2g needs) can be used.
|
|
*
|
|
* Called once the Configuration descriptor read confirms a Mass Storage/
|
|
* SCSI/BOT device, with config_value = that descriptor's own
|
|
* bConfigurationValue field -- not called directly by other code.
|
|
*
|
|
* Returns 0 if the transfer was posted, -1 if dev/dev->ep0_ring is not
|
|
* set up.
|
|
*/
|
|
int xhci_ep0_set_configuration(xhci_dev_t *dev, uint32_t slot_id, uint8_t config_value);
|
|
|
|
#endif /* STARKERNEL_XHCI_DRIVER_H */
|