Generate comprehensive documentation for all 173 source units and integrate mkdocs-material into the build toolchain. Documentation covers kernel core, x86 architecture, drivers, applications, and all subsystems with a tabbed navigation structure. - Add mkdocs.yml with material theme, mermaid support, and tabbed nav - Add doc/index.md landing page - Generate doc/src/ markdown for every Pascal unit in src/ - Reorganize planning docs into doc/planning/ - Add compat, lvglh, and toolchain doc sections - Update Dockerfile to install python3 and mkdocs-material (pinned <2) - Replace pasdoc-based compile_docs.sh with mkdocs build --strict - Add compile_docs.sh to the main build pipeline in compile.sh - Add deploy-docs step in .drone.yml with host volume mount to nginx - Add site/.gitkeep for build output directory
942 lines
46 KiB
Markdown
942 lines
46 KiB
Markdown
# USB Implementation Plan
|
||
|
||
> Living document — tracks design decisions, architecture, progress, and open questions for Asuro's USB subsystem.
|
||
|
||
## Table of Contents
|
||
- [1. Overview](#1-overview)
|
||
- [2. Design Decisions](#2-design-decisions)
|
||
- [3. Architecture](#3-architecture)
|
||
- [4. File Layout](#4-file-layout)
|
||
- [5. Shared Types (`usbtypes.pas`)](#5-shared-types-usbtypespas)
|
||
- [6. USB Core (`usbcore.pas`)](#6-usb-core-usbcorepas)
|
||
- [7. Host Controller Drivers](#7-host-controller-drivers)
|
||
- [8. Hub Driver (`usbhub.pas`)](#8-hub-driver-usbhubpas)
|
||
- [9. USB Class Drivers](#9-usb-class-drivers)
|
||
- [10. Integration with drivermanagement](#10-integration-with-drivermanagement)
|
||
- [11. Memory & DMA Strategy](#11-memory--dma-strategy)
|
||
- [12. Transfer Scheduling](#12-transfer-scheduling)
|
||
- [13. Implementation Phases](#13-implementation-phases)
|
||
- [14. Progress Tracker](#14-progress-tracker)
|
||
|
||
---
|
||
|
||
## 1. Overview
|
||
|
||
Implement a full USB subsystem for Asuro, supporting all four host controller types (UHCI → OHCI → EHCI → xHCI), all four transfer types (Control, Interrupt, Bulk, Isochronous), full hub support, and a class-driver model integrated with `drivermanagement`. Initial class drivers: USB Keyboard and USB Mouse.
|
||
|
||
**Target environment:** VirtualBox (PIIX3 = UHCI, ICH9 = OHCI + EHCI, optional xHCI), bare-metal i386, ring 0, Standard Pascal (FPC cross-compiler), no runtime library.
|
||
|
||
---
|
||
|
||
## 2. Design Decisions
|
||
|
||
| Decision | Choice | Rationale |
|
||
|---|---|---|
|
||
| HC implementation order | UHCI → OHCI → EHCI → xHCI | UHCI first (VirtualBox PIIX3 default), then OHCI, then EHCI for USB 2.0, xHCI last |
|
||
| Transfer types | All four (Control, Interrupt, Bulk, Isochronous) | Full spec compliance over time |
|
||
| Hub support | Full from the start | Needed for real hardware; root hub + external hubs |
|
||
| USB device ↔ class driver matching | `drivermanagement` with `biUSB` bus type | Reuse existing driver lifecycle, no parallel systems |
|
||
| Completion model | Interrupt-driven (ISR on PCI IRQ, PollBusy guard) | Inline polling fallback in usb_control_msg; ISR fires completion hooks for HID drivers |
|
||
| DMA memory | Existing `pmemorymanager` / `vmemorymanager` (`force_alloc_block` / `map_page`) | Already proven in OHCI stub; identity-mapped pages for DMA |
|
||
| File layout | `src/driver/bus/usb/` subdirectory | Keep HC logic together; class drivers in `src/driver/hid/` and `src/driver/storage/` |
|
||
| Data structures | `lists.pas` linked lists + manual `kalloc`/`kfree` records | Avoid static arrays, use existing infrastructure; class drivers (keyboard, mouse, storage) all use dynamic lists for unlimited device tracking |
|
||
|
||
---
|
||
|
||
## 3. Architecture
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ drivermanagement │
|
||
│ register_driver(biUSB, class/sub/proto) ←→ register_device() │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ USB Class Drivers │
|
||
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────┐ │
|
||
│ │ USB Keyboard │ │ USB Mouse │ │ USB Mass Storage │ │
|
||
│ │ (src/hid/) │ │ (src/hid/) │ │ (src/storage/) │ │
|
||
│ └──────┬───────┘ └──────┬───────┘ └────────┬───────────┘ │
|
||
│ │ │ │ │
|
||
├──────────┴──────────────────┴────────────────────┴───────────────┤
|
||
│ usbcore.pas │
|
||
│ Device enumeration, configuration, pipe management, │
|
||
│ control transfers, descriptor parsing, address assignment │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ usbhub.pas │
|
||
│ Hub driver, port status/change, reset sequencing, │
|
||
│ topology tracking, split transaction TT info │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ Host Controller Interface (HCI) Abstraction │
|
||
│ usbtypes.pas │
|
||
│ TUSBHCDriver record with function pointers: │
|
||
│ init, reset, start, stop, submit_transfer, poll │
|
||
├─────────┬──────────┬──────────┬──────────┬───────────────────────┤
|
||
│ UHCI │ OHCI │ EHCI │ xHCI │ Host Controller │
|
||
│ .pas │ .pas │ .pas │ .pas │ Drivers │
|
||
├─────────┴──────────┴──────────┴──────────┴───────────────────────┤
|
||
│ PCI Bus │
|
||
│ (PCI.pas) │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
|
||
* = future, not in initial implementation
|
||
```
|
||
|
||
---
|
||
|
||
## 4. File Layout
|
||
|
||
```
|
||
src/driver/bus/usb/
|
||
├── usbtypes.pas # Shared types, constants, HC abstraction record
|
||
├── usbcore.pas # Enumeration, configuration, control transfers, pipe API
|
||
├── usbhub.pas # Hub driver (root + external)
|
||
├── UHCI.pas # UHCI host controller driver (moved from bus/)
|
||
├── OHCI.pas # OHCI host controller driver (moved from bus/)
|
||
├── EHCI.pas # EHCI host controller driver (moved from bus/)
|
||
├── XHCI.pas # xHCI host controller driver (moved from bus/)
|
||
└── USB.pas # Init entry point, PCI registration (moved from bus/)
|
||
|
||
src/driver/hid/
|
||
├── usb_keyboard.pas # USB HID keyboard class driver
|
||
└── usb_mouse.pas # USB HID mouse class driver
|
||
|
||
src/driver/storage/
|
||
└── usb_storage.pas # USB Mass Storage class driver (BOT + SCSI)
|
||
```
|
||
|
||
> **Migration:** Existing `UHCI.pas`, `OHCI.pas`, `EHCI.pas`, `XHCI.pas`, `USB.pas` move from `src/driver/bus/` into `src/driver/bus/usb/`. Build scripts will need path updates.
|
||
|
||
---
|
||
|
||
## 5. Shared Types (`usbtypes.pas`)
|
||
|
||
### 5.1 USB Descriptor Types
|
||
|
||
```pascal
|
||
{ Standard descriptor type constants }
|
||
const
|
||
USB_DESC_DEVICE = $01;
|
||
USB_DESC_CONFIGURATION = $02;
|
||
USB_DESC_STRING = $03;
|
||
USB_DESC_INTERFACE = $04;
|
||
USB_DESC_ENDPOINT = $05;
|
||
USB_DESC_HUB = $29;
|
||
|
||
{ USB Request Types }
|
||
USB_REQ_GET_STATUS = $00;
|
||
USB_REQ_CLEAR_FEATURE = $01;
|
||
USB_REQ_SET_FEATURE = $03;
|
||
USB_REQ_SET_ADDRESS = $05;
|
||
USB_REQ_GET_DESCRIPTOR = $06;
|
||
USB_REQ_SET_CONFIG = $09;
|
||
|
||
{ Endpoint direction }
|
||
USB_DIR_OUT = $00;
|
||
USB_DIR_IN = $80;
|
||
|
||
{ Transfer types }
|
||
USB_TRANSFER_CONTROL = 0;
|
||
USB_TRANSFER_ISOCHRONOUS = 1;
|
||
USB_TRANSFER_BULK = 2;
|
||
USB_TRANSFER_INTERRUPT = 3;
|
||
|
||
{ USB speeds }
|
||
USB_SPEED_LOW = 0; { 1.5 Mbps }
|
||
USB_SPEED_FULL = 1; { 12 Mbps }
|
||
USB_SPEED_HIGH = 2; { 480 Mbps }
|
||
USB_SPEED_SUPER = 3; { 5 Gbps }
|
||
|
||
{ Max devices per controller }
|
||
USB_MAX_DEVICES = 127;
|
||
USB_MAX_ENDPOINTS = 32;
|
||
```
|
||
|
||
### 5.2 Standard Descriptors (packed records)
|
||
|
||
```pascal
|
||
type
|
||
PUSBDeviceDescriptor = ^TUSBDeviceDescriptor;
|
||
TUSBDeviceDescriptor = packed record
|
||
bLength : uint8;
|
||
bDescriptorType : uint8;
|
||
bcdUSB : uint16;
|
||
bDeviceClass : uint8;
|
||
bDeviceSubClass : uint8;
|
||
bDeviceProtocol : uint8;
|
||
bMaxPacketSize0 : uint8;
|
||
idVendor : uint16;
|
||
idProduct : uint16;
|
||
bcdDevice : uint16;
|
||
iManufacturer : uint8;
|
||
iProduct : uint8;
|
||
iSerialNumber : uint8;
|
||
bNumConfigurations : uint8;
|
||
end;
|
||
|
||
PUSBConfigDescriptor = ^TUSBConfigDescriptor;
|
||
TUSBConfigDescriptor = packed record
|
||
bLength : uint8;
|
||
bDescriptorType : uint8;
|
||
wTotalLength : uint16;
|
||
bNumInterfaces : uint8;
|
||
bConfigurationValue : uint8;
|
||
iConfiguration : uint8;
|
||
bmAttributes : uint8;
|
||
bMaxPower : uint8;
|
||
end;
|
||
|
||
PUSBInterfaceDescriptor = ^TUSBInterfaceDescriptor;
|
||
TUSBInterfaceDescriptor = packed record
|
||
bLength : uint8;
|
||
bDescriptorType : uint8;
|
||
bInterfaceNumber : uint8;
|
||
bAlternateSetting : uint8;
|
||
bNumEndpoints : uint8;
|
||
bInterfaceClass : uint8;
|
||
bInterfaceSubClass : uint8;
|
||
bInterfaceProtocol : uint8;
|
||
iInterface : uint8;
|
||
end;
|
||
|
||
PUSBEndpointDescriptor = ^TUSBEndpointDescriptor;
|
||
TUSBEndpointDescriptor = packed record
|
||
bLength : uint8;
|
||
bDescriptorType : uint8;
|
||
bEndpointAddress : uint8;
|
||
bmAttributes : uint8;
|
||
wMaxPacketSize : uint16;
|
||
bInterval : uint8;
|
||
end;
|
||
|
||
PUSBHubDescriptor = ^TUSBHubDescriptor;
|
||
TUSBHubDescriptor = packed record
|
||
bDescLength : uint8;
|
||
bDescriptorType : uint8;
|
||
bNbrPorts : uint8;
|
||
wHubCharacteristics : uint16;
|
||
bPwrOn2PwrGood : uint8;
|
||
bHubContrCurrent : uint8;
|
||
{ Variable-length DeviceRemovable + PortPwrCtrlMask follow }
|
||
end;
|
||
```
|
||
|
||
### 5.3 Setup Packet
|
||
|
||
```pascal
|
||
PUSBSetupPacket = ^TUSBSetupPacket;
|
||
TUSBSetupPacket = packed record
|
||
bmRequestType : uint8;
|
||
bRequest : uint8;
|
||
wValue : uint16;
|
||
wIndex : uint16;
|
||
wLength : uint16;
|
||
end;
|
||
```
|
||
|
||
### 5.4 USB Device / Endpoint / Pipe State
|
||
|
||
```pascal
|
||
{ Transfer completion status }
|
||
TUSBTransferStatus = (
|
||
tsSuccess,
|
||
tsStall,
|
||
tsNAK,
|
||
tsBabble,
|
||
tsDataBufferError,
|
||
tsCRCError,
|
||
tsBitStuffError,
|
||
tsTimeout,
|
||
tsNotStarted,
|
||
tsInProgress
|
||
);
|
||
|
||
{ Transfer direction }
|
||
TUSBDirection = (dirOut, dirIn, dirSetup);
|
||
|
||
{ Pipe type matches transfer type }
|
||
TUSBPipeType = (ptControl, ptIsochronous, ptBulk, ptInterrupt);
|
||
|
||
PUSBEndpoint = ^TUSBEndpoint;
|
||
TUSBEndpoint = record
|
||
Address : uint8; { Endpoint number (0-15) }
|
||
Direction : TUSBDirection;
|
||
PipeType : TUSBPipeType;
|
||
MaxPacket : uint16;
|
||
Interval : uint8; { Polling interval (interrupt/iso) }
|
||
Toggle : uint8; { Data toggle state: 0 or 1 }
|
||
end;
|
||
|
||
PUSBDevice = ^TUSBDevice;
|
||
|
||
{ Forward declaration for HC driver }
|
||
PUSBHCDriver = ^TUSBHCDriver;
|
||
|
||
PUSBTransfer = ^TUSBTransfer;
|
||
TUSBTransfer = record
|
||
Device : PUSBDevice;
|
||
Endpoint : PUSBEndpoint;
|
||
Direction : TUSBDirection;
|
||
PipeType : TUSBPipeType;
|
||
Buffer : Pointer;
|
||
BufferLen : uint32;
|
||
ActualLen : uint32; { Bytes actually transferred }
|
||
Status : TUSBTransferStatus;
|
||
Setup : TUSBSetupPacket; { For control transfers }
|
||
HCPriv : Pointer; { HC-specific data (TD chain, etc.) }
|
||
end;
|
||
|
||
TUSBDevice = record
|
||
Address : uint8; { Assigned USB address (1-127) }
|
||
Speed : uint8; { USB_SPEED_* }
|
||
MaxPacket0 : uint8; { EP0 max packet size }
|
||
HC : PUSBHCDriver;
|
||
HCPort : uint8; { Root hub port or hub port }
|
||
ParentHub : PUSBDevice; { nil for root-hub-attached devices }
|
||
ParentPort : uint8; { Port on parent hub }
|
||
DevDesc : TUSBDeviceDescriptor;
|
||
Endpoints : array[0..USB_MAX_ENDPOINTS-1] of TUSBEndpoint;
|
||
NumEndpoints: uint8;
|
||
Configured : boolean;
|
||
end;
|
||
```
|
||
|
||
### 5.5 Host Controller Abstraction
|
||
|
||
```pascal
|
||
{ HC operations - each HC driver fills in these function pointers }
|
||
TUSBHCInit = function(dev : PPCI_Device) : boolean;
|
||
TUSBHCReset = function(hc : PUSBHCDriver) : boolean;
|
||
TUSBHCStart = function(hc : PUSBHCDriver) : boolean;
|
||
TUSBHCStop = procedure(hc : PUSBHCDriver);
|
||
TUSBHCSubmit = function(hc : PUSBHCDriver; transfer : PUSBTransfer) : boolean;
|
||
TUSBHCPoll = procedure(hc : PUSBHCDriver);
|
||
TUSBHCPortReset = function(hc : PUSBHCDriver; port : uint8) : boolean;
|
||
TUSBHCPortStatus = function(hc : PUSBHCDriver; port : uint8) : uint32;
|
||
|
||
TUSBHCDriver = record
|
||
Name : PChar;
|
||
HCType : uint8; { 0=UHCI, 1=OHCI, 2=EHCI, 3=xHCI }
|
||
NumPorts : uint8;
|
||
PCIDev : TPCI_Device; { Owning PCI device }
|
||
BaseAddr : uint32; { I/O base (UHCI) or MMIO base (OHCI/EHCI/xHCI) }
|
||
PrivData : Pointer; { HC-specific state (frame list, HCCA, etc.) }
|
||
Devices : PLinkedListBase; { List of TUSBDevice attached to this HC }
|
||
NextAddress : uint8; { Next available USB address }
|
||
{ Operations }
|
||
fnReset : TUSBHCReset;
|
||
fnStart : TUSBHCStart;
|
||
fnStop : TUSBHCStop;
|
||
fnSubmit : TUSBHCSubmit;
|
||
fnPoll : TUSBHCPoll;
|
||
fnPortReset : TUSBHCPortReset;
|
||
fnPortStatus : TUSBHCPortStatus;
|
||
end;
|
||
```
|
||
|
||
---
|
||
|
||
## 6. USB Core (`usbcore.pas`)
|
||
|
||
The core module orchestrates enumeration and provides the public transfer API used by class drivers.
|
||
|
||
### 6.1 Responsibilities
|
||
|
||
1. **Maintain a global list of HC drivers** (`HCList : PLinkedListBase`)
|
||
2. **Register/unregister HC drivers** — called by each HC's `load` function
|
||
3. **Device enumeration sequence** (called when hub reports a new device):
|
||
- Port reset (via HC abstraction)
|
||
- Create `TUSBDevice` with address 0, EP0 at 8 bytes
|
||
- GET_DESCRIPTOR(Device, 8 bytes) → read `bMaxPacketSize0`
|
||
- SET_ADDRESS(N) → assign unique address
|
||
- GET_DESCRIPTOR(Device, 18 bytes) → full device descriptor
|
||
- GET_DESCRIPTOR(Configuration) → all configs, interfaces, endpoints
|
||
- Parse interface descriptors → populate `Endpoints[]`
|
||
- SET_CONFIGURATION(1)
|
||
- Call `drivermanagement.register_device()` with `biUSB` bus identifier
|
||
4. **Control transfer helpers**:
|
||
- `usb_control_msg(dev, requestType, request, value, index, buf, len) : TUSBTransferStatus`
|
||
- `usb_get_descriptor(dev, descType, descIdx, buf, len) : TUSBTransferStatus`
|
||
- `usb_set_address(dev, addr) : TUSBTransferStatus`
|
||
- `usb_set_configuration(dev, config) : TUSBTransferStatus`
|
||
5. **Interrupt/Bulk transfer helpers**:
|
||
- `usb_interrupt_transfer(dev, endpoint, buf, len) : TUSBTransferStatus`
|
||
- `usb_bulk_transfer(dev, endpoint, buf, len) : TUSBTransferStatus`
|
||
6. **Polling loop** — called from timer/scheduler tick:
|
||
- Iterate all HC drivers → call `fnPoll`
|
||
- HC poll checks for completed transfers and port status changes
|
||
- Port status changes trigger hub logic → enumeration
|
||
|
||
### 6.2 Device Identifier Encoding for drivermanagement
|
||
|
||
When a USB device is enumerated, we register it via:
|
||
|
||
```pascal
|
||
DevID.Bus := biUSB;
|
||
DevID.id0 := (idVendor SHL 16) OR idProduct; { Vendor:Product }
|
||
DevID.id1 := bDeviceClass;
|
||
DevID.id2 := bInterfaceClass; { From first/matching interface }
|
||
DevID.id3 := bInterfaceSubClass;
|
||
DevID.id4 := bInterfaceProtocol;
|
||
DevID.ex := nil; { Could chain additional interface descriptors }
|
||
```
|
||
|
||
Class drivers register with wildcards where appropriate:
|
||
|
||
```pascal
|
||
{ HID Keyboard driver registers: }
|
||
DevID.Bus := biUSB;
|
||
DevID.id0 := idANY; { Any vendor/product }
|
||
DevID.id1 := idANY; { Any device class }
|
||
DevID.id2 := $03; { HID class }
|
||
DevID.id3 := $01; { Boot interface subclass }
|
||
DevID.id4 := $01; { Keyboard protocol }
|
||
```
|
||
|
||
The `TDriverLoadCallback` receives a pointer to a `PUSBDevice`, giving the class driver full access to endpoints and the HC transfer API.
|
||
|
||
---
|
||
|
||
## 7. Host Controller Drivers
|
||
|
||
### 7.1 UHCI (Universal Host Controller Interface)
|
||
|
||
**Priority: First**
|
||
**Spec:** Intel UHCI Design Guide, Rev 1.1
|
||
**I/O model:** Port I/O (not MMIO)
|
||
**PCI prog_if:** `$00`
|
||
|
||
#### Registers (I/O port offsets from BAR4)
|
||
| Offset | Name | Size | Description |
|
||
|--------|------|------|-------------|
|
||
| $00 | USBCMD | 16-bit | Command register |
|
||
| $02 | USBSTS | 16-bit | Status register |
|
||
| $04 | USBINTR | 16-bit | Interrupt enable |
|
||
| $06 | FRNUM | 16-bit | Frame number |
|
||
| $08 | FRBASEADD | 32-bit | Frame list base address |
|
||
| $0C | SOFMOD | 8-bit | Start of frame modify |
|
||
| $10 | PORTSC1 | 16-bit | Port 1 status/control |
|
||
| $12 | PORTSC2 | 16-bit | Port 2 status/control |
|
||
|
||
#### Key Data Structures (all physically contiguous, 16-byte aligned)
|
||
- **Frame List:** 1024 × 32-bit pointers (4KB page-aligned)
|
||
- **Queue Head (QH):** 8 bytes — `QH_Link_Pointer`, `QH_Element_Pointer`
|
||
- **Transfer Descriptor (TD):** 16 bytes — `TD_Link_Pointer`, `TD_Control_Status`, `TD_Token`, `TD_Buffer_Pointer`
|
||
|
||
#### Implementation Steps
|
||
1. Read BAR4 from PCI config → I/O base address
|
||
2. Stop controller (clear USBCMD.RS)
|
||
3. Global reset (USBCMD.GRESET), wait 10ms, clear
|
||
4. Allocate frame list (4KB, page-aligned, identity-mapped)
|
||
5. Initialize all 1024 frame list entries to terminate (T-bit set)
|
||
6. Write frame list physical address to FRBASEADD
|
||
7. Set FRNUM = 0
|
||
8. Create skeleton QH schedule:
|
||
- Control QH → Bulk QH → Interrupt QHs (at frame list intervals)
|
||
9. Start controller (USBCMD.RS = 1)
|
||
10. For each port: check PORTSC, detect device, trigger enumeration
|
||
11. Poll: check USBSTS for completion, walk TD chains for completed transfers
|
||
|
||
#### UHCI Private Data
|
||
```pascal
|
||
PUHCIData = ^TUHCIData;
|
||
TUHCIData = record
|
||
IOBase : uint16;
|
||
FrameList : Pointer; { 4KB-aligned physical address }
|
||
ControlQH : Pointer; { Control transfer queue head }
|
||
BulkQH : Pointer; { Bulk transfer queue head }
|
||
IntQH : array[0..7] of Pointer; { Interrupt QHs at different intervals }
|
||
end;
|
||
```
|
||
|
||
### 7.2 OHCI (Open Host Controller Interface)
|
||
|
||
**Priority: Second**
|
||
**Spec:** OHCI Rev 1.0a
|
||
**I/O model:** MMIO (BAR0)
|
||
**PCI prog_if:** `$10`
|
||
|
||
#### Key Registers (already partially in existing `TOHCI_MMR`)
|
||
Already have the MMIO register record. Need to extend with:
|
||
- Operational registers (HcControl, HcCommandStatus, etc.)
|
||
- `HcHCCA` → points to 256-byte Host Controller Communications Area
|
||
- Port status registers (`HcRhPortStatus[1..N]`)
|
||
|
||
#### Key Data Structures
|
||
- **HCCA:** 256 bytes, 256-byte aligned — contains interrupt table (32 × ED pointers) and frame counter
|
||
- **Endpoint Descriptor (ED):** 16 bytes — links to TD list
|
||
- **Transfer Descriptor (TD):** 16 bytes (General) or 32 bytes (Isochronous)
|
||
|
||
#### Implementation Steps
|
||
1. Map BAR0 MMIO region (existing code does this)
|
||
2. Reset: write OHCI_RESET to HcCommandStatus, wait for completion
|
||
3. Allocate HCCA (256-byte aligned)
|
||
4. Set HcHCCA register
|
||
5. Build ED skeleton schedule (Control, Bulk, Interrupt, Isochronous lists)
|
||
6. Set HcControl to OPERATIONAL state
|
||
7. Enable relevant interrupts in HcIntEnable
|
||
8. Set HcPeriodicStart
|
||
9. Power on root hub ports via HcRhPortStatus
|
||
10. Detect devices, trigger enumeration
|
||
11. Poll: read HcDoneHead for completed TDs
|
||
|
||
### 7.3 EHCI (Enhanced Host Controller Interface)
|
||
|
||
**Priority: Third**
|
||
**Spec:** EHCI Rev 1.0
|
||
**I/O model:** MMIO (BAR0)
|
||
**PCI prog_if:** `$20`
|
||
|
||
#### Key Concepts
|
||
- **Capability Registers** (read-only, offset 0): CAPLENGTH, HCSPARAMS, HCCPARAMS
|
||
- **Operational Registers** (offset CAPLENGTH): USBCMD, USBSTS, USBINTR, FRINDEX, etc.
|
||
- **Periodic Frame List:** 1024 × 32-bit frame list entries (4KB aligned)
|
||
- **Async Schedule:** Circular linked list of Queue Heads (QHs)
|
||
- **Queue Head (QH):** 48 bytes — contains overlay area for current TD
|
||
- **Queue Transfer Descriptor (qTD):** 32 bytes, 32-byte aligned
|
||
|
||
#### Companion Controller Handling
|
||
EHCI routes full/low-speed devices to companion controllers (UHCI/OHCI) via port routing logic. We must:
|
||
- Read HCSPARAMS for N_PORTS and N_CC (companion controllers)
|
||
- Handle port owner change (CONFIGFLAG, PORTSC[n].PortOwner)
|
||
|
||
#### Implementation Steps
|
||
1. Map BAR0, read capability registers
|
||
2. Stop controller (USBCMD.RS = 0), wait for halt
|
||
3. Reset (USBCMD.HCRESET), wait for clear
|
||
4. Allocate periodic frame list + async QH
|
||
5. Set PERIODICLISTBASE, ASYNCLISTADDR
|
||
6. Set CONFIGFLAG = 1 (claim all ports from companions)
|
||
7. Enable async + periodic schedules
|
||
8. Start controller
|
||
9. Port detection, reset (50ms PORTRESET), enumeration
|
||
10. Poll: check USBSTS for async/periodic completion
|
||
|
||
### 7.4 xHCI (eXtensible Host Controller Interface)
|
||
|
||
**Priority: Fourth (last)**
|
||
**Spec:** xHCI Rev 1.2
|
||
**I/O model:** MMIO (BAR0, 64-bit capable)
|
||
**PCI prog_if:** `$30`
|
||
|
||
#### Key Concepts (significantly different from UHCI/OHCI/EHCI)
|
||
- **No frame list** — uses ring-based command/transfer/event model
|
||
- **Device Context:** per-device state maintained by hardware
|
||
- **Command Ring:** kernel submits commands (enable slot, address device, etc.)
|
||
- **Transfer Ring:** per-endpoint ring of TRBs (Transfer Request Blocks)
|
||
- **Event Ring:** hardware posts completions
|
||
- **Doorbell Registers:** notify controller of new TRBs
|
||
- **Scratchpad Buffers:** required by some controllers
|
||
|
||
#### Implementation Steps
|
||
1. Map BAR0 (may need 64-bit BAR handling)
|
||
2. Read capability registers (CAPLENGTH, HCSPARAMS1/2/3, HCCPARAMS1)
|
||
3. Stop controller, wait for halt
|
||
4. Reset (USBCMD.HCRST)
|
||
5. Program MaxSlots, MaxIntrs
|
||
6. Allocate DCBAA (Device Context Base Address Array)
|
||
7. Allocate Command Ring, Event Ring(s), Scratchpad
|
||
8. Set DCBAAP, CRCR registers
|
||
9. Define Interrupter 0 event ring
|
||
10. Start controller
|
||
11. For each port: check PORTSC, issue Port Reset, Enable Slot, Address Device
|
||
12. Poll: read Event Ring for completion TRBs, advance dequeue pointer
|
||
|
||
---
|
||
|
||
## 8. Hub Driver (`usbhub.pas`)
|
||
|
||
### 8.1 Hub Detection
|
||
|
||
Hubs are detected during enumeration when `bDeviceClass = $09` (Hub) or `bInterfaceClass = $09`. The hub driver is registered as a USB class driver via `drivermanagement`:
|
||
|
||
```pascal
|
||
DevID.Bus := biUSB;
|
||
DevID.id0 := idANY;
|
||
DevID.id1 := $09; { Hub device class }
|
||
DevID.id2 := $09; { Hub interface class }
|
||
DevID.id3 := idANY; { Subclass }
|
||
DevID.id4 := idANY; { Protocol }
|
||
```
|
||
|
||
### 8.2 Hub Responsibilities
|
||
|
||
1. **GET_HUB_DESCRIPTOR** → determine number of downstream ports
|
||
2. **SET_PORT_POWER** for each port (if not ganged-power)
|
||
3. **Poll hub status endpoint** (interrupt IN endpoint) for port status change bitmap
|
||
4. On port change:
|
||
- **GET_PORT_STATUS** → check `PORT_CONNECTION`, `PORT_ENABLE`, `PORT_RESET`
|
||
- If new device: **SET_PORT_FEATURE(PORT_RESET)**, wait, **CLEAR_PORT_FEATURE(C_PORT_RESET)**
|
||
- Call `usbcore` enumeration for the new device (with `ParentHub` set)
|
||
- If device removed: tear down device, notify class driver, free resources
|
||
5. **Topology tracking** — maintain parent/child relationships for split transactions (EHCI TT)
|
||
|
||
### 8.3 Root Hub Emulation
|
||
|
||
Each HC driver emulates root hub ports using its native port status registers. The HC abstraction (`fnPortReset`, `fnPortStatus`) provides this. `usbcore` treats root hub ports uniformly by calling these functions during initial scan.
|
||
|
||
---
|
||
|
||
## 9. USB Class Drivers
|
||
|
||
### 9.1 USB Keyboard (`usb_keyboard.pas`)
|
||
|
||
**USB HID Boot Protocol Keyboard**
|
||
|
||
- Registers with `drivermanagement` for `biUSB`, class=$03, subclass=$01, protocol=$01
|
||
- `load` callback receives `PUSBDevice`
|
||
- SET_PROTOCOL(0) → Boot protocol (simpler 8-byte reports)
|
||
- SET_IDLE(0) → Only report on change
|
||
- Find interrupt IN endpoint from device's endpoint list
|
||
- Poll endpoint periodically (using interrupt transfer API)
|
||
- Parse 8-byte boot report:
|
||
- Byte 0: modifier keys (Ctrl, Shift, Alt, GUI)
|
||
- Byte 1: reserved
|
||
- Bytes 2-7: keycodes (up to 6 simultaneous)
|
||
- Translate keycodes to existing `TKeyInfo` format
|
||
- Feed into existing `keyboard.hook` mechanism
|
||
|
||
### 9.2 USB Mouse (`usb_mouse.pas`)
|
||
|
||
**USB HID Boot Protocol Mouse**
|
||
|
||
- Registers for `biUSB`, class=$03, subclass=$01, protocol=$02
|
||
- SET_PROTOCOL(0) → Boot protocol
|
||
- Find interrupt IN endpoint
|
||
- Poll for 3-byte (or 4-byte with scroll) boot reports:
|
||
- Byte 0: buttons (bit0=left, bit1=right, bit2=middle)
|
||
- Byte 1: X displacement (signed)
|
||
- Byte 2: Y displacement (signed)
|
||
- Byte 3: wheel (optional)
|
||
- Feed into existing `mousestate` / `mouse` driver system
|
||
|
||
---
|
||
|
||
## 10. Integration with drivermanagement
|
||
|
||
### 10.1 PCI → HC Driver Loading (existing pattern, refined)
|
||
|
||
The existing `USB.init` procedure already registers four PCI device identifiers with `drivermanagement`. When PCI scan finds a USB controller, `drivermanagement.register_device` triggers the matching HC driver's `load` callback. This stays the same.
|
||
|
||
### 10.2 HC Driver → USB Core
|
||
|
||
Each HC driver's `load` function:
|
||
1. Initializes hardware
|
||
2. Fills in a `TUSBHCDriver` record (kalloc'd)
|
||
3. Calls `usbcore.register_hc(@hcdriver)` to add to the global HC list
|
||
4. Calls `usbcore.scan_ports(@hcdriver)` to enumerate root hub ports
|
||
|
||
### 10.3 USB Core → Class Driver Loading
|
||
|
||
When `usbcore` completes device enumeration:
|
||
1. For each interface on the device, create a `TDeviceIdentifier` with `biUSB` and class/subclass/protocol
|
||
2. Call `drivermanagement.register_device('USB Device', @DevID, @usbdev)`
|
||
3. `drivermanagement` matches against registered class drivers and calls their `load` callback
|
||
4. Class driver receives `PUSBDevice` via the `ptr` parameter, begins operation
|
||
|
||
### 10.4 Lifecycle Flow
|
||
|
||
```
|
||
Boot
|
||
→ kernel.init
|
||
→ drivermanagement.init
|
||
→ PCI.init (registers PCI driver, force_load)
|
||
→ PCI.load (scans all buses)
|
||
→ For each PCI device: drivermanagement.register_device(biPCI, ...)
|
||
→ Matches USB-UHCI/OHCI/EHCI/XHCI drivers registered by USB.init
|
||
→ UHCI.load / OHCI.load / EHCI.load / XHCI.load
|
||
→ HC hardware init
|
||
→ usbcore.register_hc(hc)
|
||
→ usbcore.scan_ports(hc)
|
||
→ For each port with a device:
|
||
→ port reset
|
||
→ enumeration (GET_DESCRIPTOR, SET_ADDRESS, SET_CONFIG)
|
||
→ drivermanagement.register_device(biUSB, class/sub/proto, @usbdev)
|
||
→ Matches usb_keyboard / usb_mouse / usbhub drivers
|
||
→ Class driver load callback
|
||
→ Begin polling / operation
|
||
```
|
||
|
||
---
|
||
|
||
## 11. Memory & DMA Strategy
|
||
|
||
### 11.1 Requirements
|
||
|
||
USB host controllers require physically-contiguous, properly-aligned memory that must be accessible by the hardware (DMA). In Asuro's identity-mapped kernel space, virtual = physical (for pages set up via `force_alloc_block` + `map_page`).
|
||
|
||
### 11.2 Allocation Patterns
|
||
|
||
| Structure | Size | Alignment | Allocator |
|
||
|---|---|---|---|
|
||
| UHCI Frame List | 4096 bytes | 4KB (page) | `force_alloc_block` + `map_page` (full page) |
|
||
| UHCI TD | 32 bytes | 16-byte | `kalloc(32)` — ensure returned address is 16-byte aligned (may need alignment wrapper) |
|
||
| UHCI QH | 16 bytes | 16-byte | `kalloc(16)` + alignment |
|
||
| OHCI HCCA | 256 bytes | 256-byte | Need aligned alloc helper |
|
||
| OHCI ED | 16 bytes | 16-byte | `kalloc(16)` + alignment |
|
||
| OHCI TD | 16 bytes | 16-byte | `kalloc(16)` + alignment |
|
||
| EHCI Periodic Frame List | 4096 bytes | 4KB | `force_alloc_block` + `map_page` |
|
||
| EHCI QH | 64 bytes | 32-byte | `kalloc(64)` + alignment |
|
||
| EHCI qTD | 32 bytes | 32-byte | `kalloc(32)` + alignment |
|
||
| xHCI rings | 4096+ bytes | 64-byte (TRBs are 16B) | Page allocation |
|
||
| xHCI DCBAA | N × 8 bytes | 64-byte | Page allocation |
|
||
| Transfer buffers | Variable | 4KB for bulk/iso | `kalloc` or page alloc |
|
||
|
||
### 11.3 Alignment Helper
|
||
|
||
```pascal
|
||
{ Allocate size bytes with specified alignment }
|
||
function kalloc_aligned(size : uint32; alignment : uint32) : Pointer;
|
||
var
|
||
raw : Pointer;
|
||
aligned : uint32;
|
||
overhead : uint32;
|
||
begin
|
||
overhead := alignment + sizeof(uint32);
|
||
raw := Pointer(kalloc(size + overhead));
|
||
aligned := (uint32(raw) + overhead + alignment - 1) AND (NOT (alignment - 1));
|
||
{ Store original pointer just before aligned address for kfree }
|
||
PUint32(aligned - 4)^ := uint32(raw);
|
||
kalloc_aligned := Pointer(aligned);
|
||
end;
|
||
|
||
procedure kfree_aligned(p : Pointer);
|
||
var
|
||
raw : Pointer;
|
||
begin
|
||
raw := Pointer(PUint32(uint32(p) - 4)^);
|
||
kfree(void(raw));
|
||
end;
|
||
```
|
||
|
||
This utility should go in `usbtypes.pas` or a dedicated `usbmem.pas`.
|
||
|
||
---
|
||
|
||
## 12. Transfer Scheduling
|
||
|
||
### 12.1 Polled Model
|
||
|
||
All four HC types use a polled completion model initially:
|
||
|
||
1. A **timer callback** (registered with the existing timer/scheduler system) fires periodically
|
||
2. Calls `usbcore.poll_all()` which iterates all registered HCs and calls `hc^.fnPoll(hc)`
|
||
3. Each HC's poll function:
|
||
- Checks hardware status register for completion events
|
||
- Walks completed TD/TRB chains
|
||
- Updates `TUSBTransfer.Status` and `TUSBTransfer.ActualLen`
|
||
- Frees completed TDs/TRBs
|
||
- For hub interrupt endpoints: checks for port status changes, triggers enumeration/removal
|
||
|
||
### 12.2 Transfer Submission Flow
|
||
|
||
```
|
||
Class Driver usbcore HC Driver
|
||
│ │ │
|
||
├─ usb_interrupt_transfer() ──►│ │
|
||
│ ├─ build TUSBTransfer ──────►│
|
||
│ │ hc^.fnSubmit(transfer) │
|
||
│ │ ├─ Build TD/QH/TRB chain
|
||
│ │ ├─ Link into schedule
|
||
│ │ ├─ Ring doorbell (xHCI)
|
||
│ │◄──────────── true ─────────┤
|
||
│◄──── tsInProgress ───────────┤ │
|
||
│ │ │
|
||
│ ... time passes ... │ │
|
||
│ │ │
|
||
│ ├─ poll_all() ──────────────►│
|
||
│ │ ├─ Check status register
|
||
│ │ ├─ Walk done list
|
||
│ │ ├─ Update transfer status
|
||
│ │◄──────────────────────────┤
|
||
│ │ │
|
||
│ (Class driver checks │ │
|
||
│ transfer.Status on next │ │
|
||
│ poll cycle) │ │
|
||
```
|
||
|
||
### 12.3 Interrupt Transfer Resubmission
|
||
|
||
HID devices need periodic interrupt transfers. After a successful completion, the class driver (or a helper in usbcore) automatically resubmits the interrupt transfer to maintain continuous polling. The poll interval is derived from `bInterval` in the endpoint descriptor.
|
||
|
||
---
|
||
|
||
## 13. Unit Testing Strategy
|
||
|
||
All phases must include unit tests where appropriate, following the pattern established in `strings.pas`:
|
||
|
||
- Each unit that has testable logic exposes a `procedure UnitTest;` in its interface
|
||
- The `UnitTest` procedure uses a local `Assert(condition, testName)` nested procedure
|
||
- Tests log via `syslog` with the unit name as tag
|
||
- A `PrintSummary` nested procedure reports passed/failed counts
|
||
- Tests are called from `kernel.pas` after init (alongside `strings.UnitTest`)
|
||
- Tests must properly `kfree` any allocated memory to avoid leaks
|
||
- Since this is bare-metal, tests run at boot — focus on logic that can be validated without hardware (descriptor parsing, data structure manipulation, encoding/decoding, identifier matching)
|
||
|
||
**What to test per phase:**
|
||
| Phase | Testable Items |
|
||
|-------|---------------|
|
||
| 0 (Foundation) | `usbtypes`: `kalloc_aligned`/`kfree_aligned`, setup packet building, descriptor size constants |
|
||
| 1 (Core) | `usbcore`: descriptor parsing, address assignment, identifier encoding, endpoint extraction |
|
||
| 2-3 (UHCI/OHCI) | TD/QH/ED construction helpers, frame list setup validation, register bitmask helpers |
|
||
| 4 (Hub) | Port status bitmap parsing, topology depth calculation |
|
||
| 5 (HID) | Boot report parsing (keyboard modifier decode, mouse delta extraction) |
|
||
| 6-7 (EHCI/xHCI) | QH/qTD/TRB construction, capability register parsing |
|
||
|
||
---
|
||
|
||
## 14. Implementation Phases
|
||
|
||
### Phase 0: Foundation (Prerequisites)
|
||
- [x] Create `src/driver/bus/usb/` directory structure
|
||
- [x] Move existing USB/UHCI/OHCI/EHCI/XHCI .pas files to new location
|
||
- [x] Update build scripts (`compile_sources.sh`) for new paths
|
||
- [x] Implement `usbtypes.pas` — all shared types, constants, HC abstraction record
|
||
- [x] Implement alignment helper (`kalloc_aligned` / `kfree_aligned`)
|
||
- [x] Implement `usbtypes.UnitTest` — test alignment helpers, setup packet building, constants
|
||
- [x] Create `usbcore.pas` skeleton — HC registration, device list, poll stubs
|
||
- [x] Verify build still succeeds with moved files
|
||
|
||
### Phase 1: USB Core Skeleton
|
||
- [x] Implement `usb_control_msg()` — builds setup packet, submits via HC abstraction
|
||
- [x] Implement descriptor parsing helpers (device, config, interface, endpoint)
|
||
- [x] Implement address assignment logic
|
||
- [x] Implement full enumeration sequence (reset → get desc → set addr → get full desc → set config → register device)
|
||
- [x] ~~Register a timer/scheduler callback for `poll_all()`~~ — **DEFERRED**: hooking `poll_all` into TMR_0_ISR caused severe UI lag (runs inside IRQ0 with interrupts disabled). Removed for now. `usb_control_msg` polls inline. A non-ISR polling approach (e.g. main loop or scheduler task) is needed later.
|
||
- [x] Implement `usbcore.UnitTest` — descriptor parsing, identifier encoding, endpoint extraction (47 tests)
|
||
|
||
### Phase 2: UHCI Host Controller
|
||
- [x] UHCI register definitions and private data structure
|
||
- [x] UHCI init: read BAR4, global reset, allocate frame list
|
||
- [x] UHCI skeleton schedule: create QH chain (control, bulk, interrupt)
|
||
- [x] UHCI start: write FRBASEADD, set RS bit
|
||
- [x] UHCI port detection: read PORTSC, detect connected devices
|
||
- [x] UHCI port reset sequence
|
||
- [x] UHCI submit_transfer: build TD chain, link to appropriate QH
|
||
- [x] UHCI poll: check USBSTS, walk TDs for completion, update transfer status
|
||
- [x] UHCI control transfer: implemented in `uhci_submit_control` (live test needs real UHCI hardware)
|
||
- [x] UHCI interrupt transfer: implemented via `uhci_submit_async` (live test needs real UHCI hardware)
|
||
- [x] UHCI bulk transfer: implemented via `uhci_submit_async` (live test needs real UHCI hardware)
|
||
- [ ] UHCI isochronous transfer support (low priority — no current use case)
|
||
- [x] UHCI unit tests: TD/QH construction helpers, bitmask encoding (47 tests)
|
||
- [ ] Test: enumerate a USB device on real UHCI hardware — VirtualBox never emulates UHCI (always uses OHCI for USB 1.1)
|
||
|
||
### Phase 3: OHCI Host Controller
|
||
- [x] Extend existing `TOHCI_MMR` with full register set
|
||
- [x] OHCI init: map MMIO, reset, allocate HCCA (256-byte aligned)
|
||
- [x] OHCI ED/TD management: create, link, free
|
||
- [x] OHCI skeleton schedule: control/bulk/interrupt/isochronous ED lists
|
||
- [x] OHCI start: set operational, enable port power
|
||
- [x] OHCI port detection and reset
|
||
- [x] OHCI submit_transfer: build TD chain, attach to ED, place in appropriate list
|
||
- [x] OHCI poll: read HcDoneHead, process completed TDs
|
||
- [x] OHCI control, interrupt, bulk, isochronous transfers
|
||
- [x] OHCI unit tests: ED/TD construction, register bitmask helpers (78/78 pass)
|
||
- [x] Test: enumerate device on VirtualBox (ICH9 chipset) — VID=80EE PID=0021, address 1
|
||
- [x] Fix: DMA virtual→physical address conversion via `vtop()` for all HC-visible pointers
|
||
|
||
### Phase 4: Hub Support
|
||
- [x] Implement `usbhub.pas` — hub class driver
|
||
- [x] Hub detection during enumeration (class $09) via drivermanagement (biUSB, id1=$09)
|
||
- [x] GET_HUB_DESCRIPTOR, port power on (SET_FEATURE PORT_POWER per port)
|
||
- [x] Hub interrupt IN endpoint polling (status change bitmap)
|
||
- [x] Port status change handling (connect, disconnect, reset, overcurrent, enable, suspend)
|
||
- [x] Recursive enumeration for devices behind hubs (depth-limited to 5)
|
||
- [x] Device removal / cleanup path — `usb_remove_device()` with `fnDisconnect` callback (implemented in Phase 8)
|
||
- [x] Topology tracking (parent hub, port, depth via TUSBDevice.ParentHub/ParentPort)
|
||
- [x] Root hub emulation consistency — enumerate_device skips HC port_reset when parentHub<>nil
|
||
- [x] Hub unit tests: port status bitmap parsing, speed detection, constants (44/44 pass)
|
||
|
||
### Phase 5: USB HID Class Drivers
|
||
- [x] `usb_keyboard.pas` — register with drivermanagement (biUSB, $03/$01/$01)
|
||
- [x] Keyboard: SET_PROTOCOL(boot), SET_IDLE(0)
|
||
- [x] Keyboard: find interrupt IN endpoint, begin polling
|
||
- [x] Keyboard: parse 8-byte boot report, translate to `TKeyInfo` via HID usage tables
|
||
- [x] Keyboard: integrate with existing keyboard hook system (`captin_hook`, modifier globals)
|
||
- [x] `usb_mouse.pas` — register with drivermanagement (biUSB, $03/$01/$02)
|
||
- [x] Mouse: SET_PROTOCOL(boot), find interrupt IN endpoint
|
||
- [x] Mouse: parse 3/4-byte boot report (buttons, X, Y, wheel) with signed delta extraction
|
||
- [x] Mouse: integrate with existing mousestate system (setMousePos, fireMouseEvent, addScroll)
|
||
- [x] HID unit tests: boot report parsing — keyboard 62 tests, mouse 33 tests (modifier keys, usage-to-ASCII, deltas, buttons, scroll)
|
||
- [x] Test: USB keyboard in VirtualBox (xHCI) — boot protocol keyboard on slot 1, EP1 interrupt transfers, input working
|
||
|
||
### Phase 6: EHCI Host Controller
|
||
- [x] EHCI capability + operational register mapping
|
||
- [x] EHCI init: reset, halt, allocate periodic frame list + async QH
|
||
- [x] EHCI QH/qTD management
|
||
- [x] EHCI async schedule (control + bulk)
|
||
- [x] EHCI periodic schedule (interrupt + isochronous)
|
||
- [x] EHCI port routing: CONFIGFLAG, companion controller handoff
|
||
- [x] EHCI split transactions for full/low-speed devices behind hubs (TT)
|
||
- [x] EHCI start, port detection, reset, enumeration
|
||
- [x] EHCI poll: USBSTS, async/periodic doorbell, qTD completion
|
||
- [x] EHCI unit tests: QH/qTD construction, capability parsing (90 tests pass)
|
||
- [x] Test: USB 2.0 device on VirtualBox (ICH9) — Intel 8086:265C detected, companion routing works
|
||
|
||
### Phase 7: xHCI Host Controller
|
||
- [x] xHCI capability register parsing (CAPLENGTH, HCSPARAMS1/2, HCCPARAMS1, DBOFF, RTSOFF)
|
||
- [x] xHCI init: reset, halt, MaxSlots, DCBAA, scratchpad buffers
|
||
- [x] xHCI Command Ring, Event Ring, Transfer Ring allocation (page-aligned, Link TRBs)
|
||
- [x] xHCI Interrupter 0 setup (ERST, ERDP, polling mode — no hardware interrupts)
|
||
- [x] xHCI start controller (RS, HSEE, no INTE)
|
||
- [x] xHCI BIOS/OS handoff (USBLEGSUP extended capability)
|
||
- [x] xHCI port detection: PORTSC scan, speed mapping
|
||
- [x] xHCI Enable Slot → Address Device commands (Input Context, Slot+EP0 contexts)
|
||
- [x] xHCI Configure Endpoint: lazy per-endpoint ring allocation + command for non-EP0 endpoints
|
||
- [x] xHCI transfer submission: control (Setup/Data/Status TRBs, SET_ADDRESS interception), bulk/interrupt (Normal TRBs)
|
||
- [x] xHCI poll: dequeue Event Ring, process Transfer Events + Command Completion + Port Status Change
|
||
- [x] xHCI unit tests: TRB construction, DCI calculation, speed mapping, EP type mapping (119 tests pass)
|
||
- [x] Test: USB device on VirtualBox (xHCI enabled) — Intel 8086:1E31 detected, keyboard enumerated + input working
|
||
|
||
### Phase 8: Hardening & Extras
|
||
- [x] Error recovery: stall handling (CLEAR_FEATURE ENDPOINT_HALT) — `usb_clear_halt()` in usbcore
|
||
- [x] Transfer timeouts — `usb_control_msg` uses `bios_data_area.Counters.c32` (1024 Hz) with 5-second real-time timeout instead of spin-loop
|
||
- [x] Device disconnect cleanup (free TDs, endpoints, device record) — `usb_remove_device()` in usbcore
|
||
- [x] `USB` terminal command for USB device information
|
||
- [x] Interrupt-driven completion (ISR registered for each HC on PCI interrupt line)
|
||
- [x] USB Mass Storage (Bulk-Only Transport) class driver — `usb_storage.pas` with CBW/CSW, SCSI (INQUIRY, TEST_UNIT_READY, READ_CAPACITY, READ_10, WRITE_10), storagemanagement integration
|
||
- [x] Hotplug: ISR-driven detection (OHCI RHSC, EHCI PCD, xHCI Port Status Change TRB) → deferred `usb_check_hotplug` in main loop; `HotplugArmed` guard prevents spurious boot-time events
|
||
- [x] Disconnect callbacks: `TUSBDisconnectCallback` on `TUSBDevice.fnDisconnect`, called by `usb_remove_device` before freeing — keyboard/mouse/storage drivers clean up transfers and deactivate
|
||
- [x] Dynamic device lists: keyboard, mouse, storage drivers use `lists.pas` linked lists (no static array limits); devices freely plug/unplug without slot exhaustion
|
||
- [x] HID fail-count guard: 3 consecutive transfer failures → self-deactivate (handles race between unplug and deferred hotplug processing)
|
||
- [x] `usb_bulk_transfer_wait` — blocking bulk helper with timer-based timeout, used by mass storage BOT
|
||
- [ ] Code audit: verify all kalloc/kfree pairs, no leaks
|
||
|
||
---
|
||
|
||
## 14. Progress Tracker
|
||
|
||
| Phase | Status | Notes |
|
||
|-------|--------|-------|
|
||
| Phase 0: Foundation | **Complete** | Files moved to `src/driver/bus/usb/`, `usbtypes.pas` + `usbcore.pas` created, build scripts updated, 71 unit tests passing (51 usbtypes + 20 usbcore) |
|
||
| Phase 1: USB Core | **Complete** | Descriptor parsing helpers, control/bulk/interrupt transfer API, inline polling |
|
||
| Phase 2: UHCI | **Complete** | Full UHCI driver with QH/TD, registers, schedule, control+bulk+interrupt submit, poll — 47 unit tests pass. Live testing requires real UHCI hardware (VirtualBox always uses OHCI for USB 1.1, never UHCI). Isochronous not yet implemented (low priority). |
|
||
| Phase 3: OHCI | **Complete** | Full OHCI driver: HCCA+ED+TD, MMIO, reset/start/stop, control+async submit, poll with TD chain cleanup, vtop() DMA fix — 78 unit tests pass, VirtualBox ICH9 enumerates VID=80EE PID=0021 at address 1 |
|
||
| Phase 4: Hub Support | **Complete** | `usbhub.pas` hub class driver: hub descriptor, port power, port reset, status change polling, recursive enumeration, depth limit — 44 unit tests pass. Device removal via `usb_remove_device()` + `fnDisconnect` (Phase 8). |
|
||
| Phase 5: HID Drivers | **Complete** | `usb_keyboard.pas` (62 tests) + `usb_mouse.pas` (33 tests): HID boot protocol, usage-to-ASCII tables, signed delta extraction, mousestate/keyboard hook integration. VBox live test pending (no HID keyboard/mouse hardware attached). |
|
||
| Phase 6: EHCI | **Complete** | Full EHCI driver: capability/operational registers, QH+qTD 32-byte aligned, async+periodic schedule, BIOS legacy handoff (EECP), port reset with companion controller routing (low-speed/not-enabled → OHCI), control+bulk+interrupt submit, poll with qTD chain completion — 90 unit tests pass. VBox ICH9 live: Intel 8086:265C detected, CONFIGFLAG routes ports, full-speed devices correctly handed off to companion OHCI. |
|
||
| Phase 7: xHCI | **Complete** | Full xHCI driver: capability parsing, ring-based model (Cmd/Evt/Transfer rings), BIOS handoff, DCBAA, scratchpad, polling mode (no IRQ), Enable Slot + Address Device + Configure Endpoint, control+bulk+interrupt submit, event ring poll — 119 unit tests pass. VBox xHCI live: Intel 8086:1E31, keyboard on slot 1 with lazy EP configuration, input working. |
|
||
| Phase 8: Hardening | **Complete** | `usb_clear_halt()` stall recovery, `usb_remove_device()` with `fnDisconnect` callback, `USB` terminal command, interrupt-driven completion for all 4 HCs, completion hooks for HID drivers, polling removed from kernel main loop. Timer-based transfer timeouts (5s via `bios_data_area.Counters.c32`). USB Mass Storage BOT driver (`usb_storage.pas`) with SCSI over bulk endpoints + storagemanagement registration. Hotplug: ISR sets `PortChangePending` (guarded by `HotplugArmed`), deferred `usb_check_hotplug` in main loop. Disconnect callbacks clean up class driver state. Dynamic linked lists replace static arrays — unlimited plug/unplug cycles. HID fail-count self-deactivation (3 strikes). Remaining: kalloc/kfree audit. |
|
||
|
||
---
|
||
|
||
## Appendix A: USB Class Codes (Reference)
|
||
|
||
| Class | Description | Subclass examples |
|
||
|-------|-------------|-------------------|
|
||
| $00 | Use interface descriptors | — |
|
||
| $03 | HID | $01 Boot, Protocol: $01 Keyboard, $02 Mouse |
|
||
| $08 | Mass Storage | $06 SCSI, $50 Bulk-Only |
|
||
| $09 | Hub | $00 Full-speed, $01 Hi-speed single TT, $02 Hi-speed multi TT |
|
||
|
||
## Appendix B: VirtualBox USB Testing Notes
|
||
|
||
- **PIIX3 chipset** → emulates OHCI + EHCI (VirtualBox never emulates UHCI)
|
||
- **ICH9 chipset** → emulates OHCI + EHCI companion pair
|
||
- **xHCI** → optional, enable in VM settings (USB 3.0 controller)
|
||
- USB device passthrough or VirtualBox's emulated USB tablet/keyboard for testing
|
||
- Serial output via `Get-Content "C:\Temp\asuro.log"` for debug logging
|
||
- VirtualBox USB filters can attach host USB devices to the VM
|
||
|
||
## Appendix C: Known Issues & Future Work
|
||
|
||
- **UHCI live-hardware testing**: VirtualBox never emulates UHCI (always uses OHCI for USB 1.1 regardless of PIIX3/ICH9 chipset). UHCI driver code is complete with 47 unit tests but needs real Intel ICH southbridge hardware (Pentium 4 era) for end-to-end testing.
|