Devices can now arrive and leave after boot. A "usbhotplug" kernel thread handles root-port changes, which it is told about by Port Status Change events and also checks for every quarter second. It also handles changes behind hubs, which each hub reports on its status-change endpoint. An unplugged device has its endpoints closed and any transfer in flight failed. Then its drivers' disconnect hooks run, the slot is disabled and its memory is freed. Everything behind a hub that goes goes with it. This needed the interrupt handler to file command and endpoint-0 completions for their waiters, so that enumeration can run while keyboards interrupt. On real hardware: the controller is taken from the firmware through USB Legacy Support before reset, with SMIs off. On Intel 7/8/9 series parts the ports are switched over from EHCI, which is where firmware leaves them. Every interface of a device is offered to the class drivers, not just the first, so a receiver's mouse on interface 1 gets a driver. Configure Endpoint now copies the slot context from the controller. Before, it rebuilt it and lost the route string and TT fields of devices behind hubs. HID: pointers are read in report protocol from their report descriptor. That covers buttons, X/Y and wheel, relative or absolute, and report IDs. Boot protocol is kept as the fallback for mice and for keyboards. Non-pointer HID interfaces are declined rather than treated as tablets. USB keyboards get software key repeat. Mass storage handles up to four sticks, each unregistered from the block layer when it is pulled out, along with its cached blocks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HH7xukt4aaiGj1nQEAoQf1
174 lines
7.3 KiB
C
174 lines
7.3 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_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_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
|