/* * 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 #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; } 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); #endif /* STARKERNEL_XHCI_DRIVER_H */