From the first boot on real hardware: a Razer mouse's control transfer failed with a babble, and an ITE controller's late endpoint-0 completion was reported as an "unexpected event" during a command. A failed control transfer left endpoint 0 halted (or, on a timeout, still running with TRBs queued), so every request after it to that device failed too. It is now reset or stopped and its dequeue pointer moved past what was left on the ring. A STALL -- a device declining a request it does not implement -- is logged only on a verbose boot. HID interfaces without the boot subclass were turned away unless they had a pointer. The report descriptor's keyboard page is now read too -- modifier bits, a key array, an NKRO bitmap -- and each report rewritten into the boot layout for the existing path. Checked with QEMU's usb-kbd forced into report protocol: "echo Hi", Shift included, typed and ran. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
178 lines
7.5 KiB
C
178 lines
7.5 KiB
C
#pragma once
|
|
|
|
// eXtensible Host Controller Interface -- the register and data-structure
|
|
// definitions from the xHCI 1.2 specification.
|
|
//
|
|
// Why xHCI and not UHCI/OHCI/EHCI: xHCI is the only host controller interface
|
|
// that speaks every USB speed, so one driver covers USB 1.1 through 3.x. The
|
|
// older controllers would each need their own, and a machine with all of them
|
|
// needs the companion-controller handover dance on top. There is no hardware
|
|
// worth supporting that has no xHCI.
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Capability registers -- at the start of BAR0, read-only
|
|
// ---------------------------------------------------------------------------
|
|
#define XHCI_CAPLENGTH 0x00 // byte: where the operational regs begin
|
|
#define XHCI_HCIVERSION 0x02 // word
|
|
#define XHCI_HCSPARAMS1 0x04
|
|
#define XHCI_HCSPARAMS2 0x08
|
|
#define XHCI_HCSPARAMS3 0x0C
|
|
#define XHCI_HCCPARAMS1 0x10
|
|
#define XHCI_DBOFF 0x14 // doorbell array offset from BAR0
|
|
#define XHCI_RTSOFF 0x18 // runtime register offset from BAR0
|
|
|
|
#define HCS1_MAXSLOTS(x) ((x) & 0xFF)
|
|
#define HCS1_MAXINTRS(x) (((x) >> 8) & 0x7FF)
|
|
#define HCS1_MAXPORTS(x) (((x) >> 24) & 0xFF)
|
|
|
|
// Scratchpad buffer count is split across two fields, high part first.
|
|
#define HCS2_SPB_HI(x) (((x) >> 21) & 0x1F)
|
|
#define HCS2_SPB_LO(x) (((x) >> 27) & 0x1F)
|
|
|
|
#define HCC1_AC64 (1 << 0) // 64-bit addressing
|
|
#define HCC1_CSZ (1 << 2) // contexts are 64 bytes, not 32
|
|
#define HCC1_XECP(x) (((x) >> 16) & 0xFFFF) // extended caps, in dwords
|
|
|
|
// Extended capabilities: a chain of dwords, each with an ID in bits 7:0 and
|
|
// the distance to the next, in dwords, in bits 15:8.
|
|
#define XECP_ID(v) ((v) & 0xFF)
|
|
#define XECP_NEXT(v) (((v) >> 8) & 0xFF)
|
|
#define XECP_LEGACY 1 // USB Legacy Support
|
|
#define LEGSUP_BIOS_OWNED (1u << 16)
|
|
#define LEGSUP_OS_OWNED (1u << 24)
|
|
// USBLEGCTLSTS, the dword after it: the SMI enables to clear and the
|
|
// write-one-to-clear SMI events, as xHCI 1.2 section 7.1.2 lays them out.
|
|
#define LEGCTL_KEEP ((0x7u << 1) | (0xFFu << 5) | (0x7u << 17))
|
|
#define LEGCTL_EVENTS (0x7u << 29)
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Operational registers -- at BAR0 + CAPLENGTH
|
|
// ---------------------------------------------------------------------------
|
|
#define XHCI_USBCMD 0x00
|
|
#define XHCI_USBSTS 0x04
|
|
#define XHCI_PAGESIZE 0x08
|
|
#define XHCI_DNCTRL 0x14
|
|
#define XHCI_CRCR 0x18 // 64-bit
|
|
#define XHCI_DCBAAP 0x30 // 64-bit
|
|
#define XHCI_CONFIG 0x38
|
|
#define XHCI_PORTSC(p) (0x400 + 0x10 * ((p) - 1)) // ports are 1-based
|
|
|
|
#define CMD_RS (1 << 0) // run/stop
|
|
#define CMD_HCRST (1 << 1) // host controller reset
|
|
#define CMD_INTE (1 << 2) // interrupter enable
|
|
#define CMD_HSEE (1 << 3)
|
|
|
|
#define STS_HCH (1 << 0) // halted
|
|
#define STS_HSE (1 << 2) // host system error
|
|
#define STS_EINT (1 << 3) // event interrupt (write 1 to clear)
|
|
#define STS_PCD (1 << 4) // port change detect (write 1 to clear)
|
|
#define STS_CNR (1 << 11) // controller not ready
|
|
|
|
#define CRCR_RCS (1 << 0) // ring cycle state
|
|
|
|
// PORTSC. The change bits are write-1-to-clear, and so is PED -- writing back
|
|
// a value read from this register clears whatever happened to be set. Every
|
|
// write has to mask them off first.
|
|
#define PORT_CCS (1 << 0) // current connect status
|
|
#define PORT_PED (1 << 1) // port enabled (RW1C!)
|
|
#define PORT_OCA (1 << 3)
|
|
#define PORT_PR (1 << 4) // port reset
|
|
#define PORT_PLS(x) (((x) >> 5) & 0xF)
|
|
#define PORT_PP (1 << 9) // port power
|
|
#define PORT_SPEED(x) (((x) >> 10) & 0xF)
|
|
#define PORT_CSC (1 << 17)
|
|
#define PORT_PEC (1 << 18)
|
|
#define PORT_PRC (1 << 21)
|
|
#define PORT_CHANGES 0x00FE0000u // every change bit, 17..23
|
|
#define PORT_RW1C 0x00FE0002u // change bits 17..23, plus PED
|
|
|
|
// PORTSC speed encoding. These are the same numbers as USB_SPEED_* in usb.h,
|
|
// which is not a coincidence -- the core uses this encoding directly so that
|
|
// nothing has to be translated on its way to a slot context.
|
|
#define XSPEED_FULL USB_SPEED_FULL
|
|
#define XSPEED_LOW USB_SPEED_LOW
|
|
#define XSPEED_HIGH USB_SPEED_HIGH
|
|
#define XSPEED_SUPER USB_SPEED_SUPER
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Runtime registers -- at BAR0 + RTSOFF. Interrupter n is at 0x20 + 32*n.
|
|
// ---------------------------------------------------------------------------
|
|
#define XHCI_MFINDEX 0x00
|
|
#define XHCI_IR0 0x20
|
|
#define IR_IMAN 0x00
|
|
#define IR_IMOD 0x04
|
|
#define IR_ERSTSZ 0x08
|
|
#define IR_ERSTBA 0x10 // 64-bit
|
|
#define IR_ERDP 0x18 // 64-bit
|
|
|
|
#define IMAN_IP (1 << 0) // interrupt pending (RW1C)
|
|
#define IMAN_IE (1 << 1) // interrupt enable
|
|
#define ERDP_EHB (1 << 3) // event handler busy (RW1C)
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Transfer Request Blocks
|
|
// ---------------------------------------------------------------------------
|
|
struct trb {
|
|
uint64 param;
|
|
uint32 status;
|
|
uint32 control;
|
|
} __attribute__((packed));
|
|
|
|
#define TRB_TYPE(t) (((t) & 0x3F) << 10)
|
|
#define TRB_GET_TYPE(c) (((c) >> 10) & 0x3F)
|
|
#define TRB_C (1 << 0) // cycle bit
|
|
#define TRB_TC (1 << 1) // toggle cycle (link TRBs)
|
|
#define TRB_ISP (1 << 2)
|
|
#define TRB_CH (1 << 4) // chain
|
|
#define TRB_IOC (1 << 5) // interrupt on completion
|
|
#define TRB_IDT (1 << 6) // immediate data
|
|
#define TRB_SLOT(s) ((uint32)(s) << 24)
|
|
#define TRB_GET_SLOT(c) (((c) >> 24) & 0xFF)
|
|
#define TRB_GET_EPID(c) (((c) >> 16) & 0x1F) // transfer events
|
|
|
|
// Transfer TRBs
|
|
#define TRB_NORMAL 1
|
|
#define TRB_SETUP 2
|
|
#define TRB_DATA 3
|
|
#define TRB_STATUS 4
|
|
#define TRB_LINK 6
|
|
// Command TRBs
|
|
#define TRB_ENABLE_SLOT 9
|
|
#define TRB_DISABLE_SLOT 10
|
|
#define TRB_ADDRESS_DEV 11
|
|
#define TRB_CONFIG_EP 12
|
|
#define TRB_EVAL_CTX 13
|
|
#define TRB_RESET_EP 14
|
|
#define TRB_STOP_EP 15
|
|
#define TRB_SET_TR_DEQ 16
|
|
#define TRB_NOOP_CMD 23
|
|
// Event TRBs
|
|
#define TRB_XFER_EVENT 32
|
|
#define TRB_CMD_COMPLETE 33
|
|
#define TRB_PORT_STATUS 34
|
|
|
|
#define TRB_CC(status) (((status) >> 24) & 0xFF)
|
|
#define CC_SUCCESS 1
|
|
#define CC_BABBLE 3
|
|
#define CC_STALL 6
|
|
#define CC_SHORT_PACKET 13
|
|
|
|
// Setup Stage transfer type, and Data Stage direction.
|
|
#define TRT_NONE 0
|
|
#define TRT_OUT 2
|
|
#define TRT_IN 3
|
|
#define DIR_IN (1 << 16)
|
|
|
|
// Endpoint types in an endpoint context. Direction is part of the type, and
|
|
// the numbering is not arbitrary: OUT types are 1-3, control is 4, and the IN
|
|
// types are the OUT ones plus four.
|
|
#define EPTYPE_ISOCH_OUT 1
|
|
#define EPTYPE_BULK_OUT 2
|
|
#define EPTYPE_INT_OUT 3
|
|
#define EPTYPE_CONTROL 4
|
|
#define EPTYPE_ISOCH_IN 5
|
|
#define EPTYPE_BULK_IN 6
|
|
#define EPTYPE_INT_IN 7
|
|
|
|
// Doorbell targets: 0 is the command ring; for a device slot, DCI 1 is EP0.
|
|
#define DCI_EP0 1
|