feature: move all USB HC drivers from polling to interrupt-driven completion
Replace main-loop polling (poll_all, poll_keyboards, poll_mice) with hardware interrupt handlers for all four USB host controller drivers. Each HC driver (XHCI, EHCI, OHCI, UHCI) now: - Registers an ISR on its PCI interrupt line via isrmanager - Enables hardware interrupts after HC initialization - Acknowledges interrupt status in the ISR before calling poll, preventing interrupt storms on level-triggered PCI lines - Uses a PollBusy re-entrancy guard to prevent ISR/inline poll races usbcore gains a completion hook system (register_completion_hook / fire_completion_hooks) so HID drivers (keyboard, mouse) are notified directly from the ISR after transfer completion. Files changed: - usbcore.pas: completion hook infrastructure - XHCI.pas: ISR, enable_interrupts, submit ordering fix - EHCI.pas: ISR, enable_interrupts, status ack in ISR - OHCI.pas: ISR, enable_interrupts, status ack in ISR - UHCI.pas: ISR, enable_interrupts, status ack in ISR - usb_keyboard.pas: register completion hook - usb_mouse.pas: register completion hook
This commit is contained in:
1 parent
3f83f279d7
commit
0c96d32754
8 files changed
+393
-50
No files matched your search
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
@author(Kieron Morris <[email protected]>)
|
@author(Kieron Morris <[email protected]>)
|
||||||
}
|
}
|
||||||
unit EHCI;
|
unit ehci;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
@@ -26,6 +26,7 @@ uses
|
|||||||
drivermanagement,
|
drivermanagement,
|
||||||
usbtypes,
|
usbtypes,
|
||||||
usbcore,
|
usbcore,
|
||||||
|
isrmanager,
|
||||||
lists,
|
lists,
|
||||||
strings;
|
strings;
|
||||||
|
|
||||||
@@ -273,6 +274,7 @@ type
|
|||||||
Has64Bit : boolean; { 64-bit addressing capable }
|
Has64Bit : boolean; { 64-bit addressing capable }
|
||||||
HCSPARAMS : uint32; { Cached structural parameters }
|
HCSPARAMS : uint32; { Cached structural parameters }
|
||||||
HCCPARAMS : uint32; { Cached capability parameters }
|
HCCPARAMS : uint32; { Cached capability parameters }
|
||||||
|
PollBusy : boolean; { Re-entrancy guard for poll }
|
||||||
PCIBus : uint8;
|
PCIBus : uint8;
|
||||||
PCISlot : uint8;
|
PCISlot : uint8;
|
||||||
PCIFunc : uint8;
|
PCIFunc : uint8;
|
||||||
@@ -1319,6 +1321,56 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ ========================= Interrupt-Driven Completion ========================= }
|
||||||
|
|
||||||
|
const
|
||||||
|
EHCI_MAX_INSTANCES = 4;
|
||||||
|
|
||||||
|
var
|
||||||
|
EHCIInstances : array[0..EHCI_MAX_INSTANCES-1] of PUSBHCDriver;
|
||||||
|
EHCIInstanceCount : uint32;
|
||||||
|
|
||||||
|
{ ISR handler — registered on the PCI interrupt line. }
|
||||||
|
procedure ehci_isr;
|
||||||
|
var
|
||||||
|
i : uint32;
|
||||||
|
hc : PUSBHCDriver;
|
||||||
|
priv : PEHCI_PrivData;
|
||||||
|
usbsts : uint32;
|
||||||
|
begin
|
||||||
|
for i := 0 to EHCIInstanceCount - 1 do begin
|
||||||
|
hc := EHCIInstances[i];
|
||||||
|
if hc = nil then continue;
|
||||||
|
priv := PEHCI_PrivData(hc^.PrivData);
|
||||||
|
if priv = nil then continue;
|
||||||
|
|
||||||
|
{ Check if this controller has pending status bits }
|
||||||
|
usbsts := ehci_readl(priv^.OpBase, EHCI_OP_USBSTS);
|
||||||
|
if (usbsts AND $3F) = 0 then continue;
|
||||||
|
|
||||||
|
{ Acknowledge interrupt status NOW to de-assert level-triggered PCI line.
|
||||||
|
Must happen before ehci_poll, because PollBusy guard may skip the
|
||||||
|
acknowledge inside poll — leaving the line asserted = interrupt storm. }
|
||||||
|
ehci_writel(priv^.OpBase, EHCI_OP_USBSTS, usbsts AND $3F);
|
||||||
|
|
||||||
|
{ Process completions (walks QH lists) }
|
||||||
|
ehci_poll(hc);
|
||||||
|
end;
|
||||||
|
usbcore.fire_completion_hooks;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Enable hardware interrupts: USB INT, USB Error INT, Port Change, Host System Error. }
|
||||||
|
procedure ehci_enable_interrupts(hc : PUSBHCDriver);
|
||||||
|
var
|
||||||
|
priv : PEHCI_PrivData;
|
||||||
|
begin
|
||||||
|
if (hc = nil) or (hc^.PrivData = nil) then exit;
|
||||||
|
priv := PEHCI_PrivData(hc^.PrivData);
|
||||||
|
ehci_writel(priv^.OpBase, EHCI_OP_USBINTR,
|
||||||
|
EHCI_STS_USBINT OR EHCI_STS_USBERRINT OR EHCI_STS_PCD OR EHCI_STS_HSE);
|
||||||
|
syslog.logln('EHCI', 'Hardware interrupts enabled.');
|
||||||
|
end;
|
||||||
|
|
||||||
procedure ehci_poll(hc : PUSBHCDriver);
|
procedure ehci_poll(hc : PUSBHCDriver);
|
||||||
var
|
var
|
||||||
priv : PEHCI_PrivData;
|
priv : PEHCI_PrivData;
|
||||||
@@ -1332,6 +1384,11 @@ var
|
|||||||
begin
|
begin
|
||||||
if (hc = nil) or (hc^.PrivData = nil) then exit;
|
if (hc = nil) or (hc^.PrivData = nil) then exit;
|
||||||
priv := PEHCI_PrivData(hc^.PrivData);
|
priv := PEHCI_PrivData(hc^.PrivData);
|
||||||
|
|
||||||
|
{ Re-entrancy guard }
|
||||||
|
if priv^.PollBusy then exit;
|
||||||
|
priv^.PollBusy := true;
|
||||||
|
|
||||||
opbase := priv^.OpBase;
|
opbase := priv^.OpBase;
|
||||||
|
|
||||||
{ Acknowledge status bits }
|
{ Acknowledge status bits }
|
||||||
@@ -1375,6 +1432,7 @@ begin
|
|||||||
qh := nextQH;
|
qh := nextQH;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
priv^.PollBusy := false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ ========================= Load / Init ========================= }
|
{ ========================= Load / Init ========================= }
|
||||||
@@ -1397,6 +1455,7 @@ var
|
|||||||
begin
|
begin
|
||||||
push_trace('EHCI.load');
|
push_trace('EHCI.load');
|
||||||
load := false;
|
load := false;
|
||||||
|
EHCIInstanceCount := 0;
|
||||||
|
|
||||||
devices := PCI.getDeviceInfo($0C, $03, $20, count);
|
devices := PCI.getDeviceInfo($0C, $03, $20, count);
|
||||||
syslog.log('EHCI', 'Found ');
|
syslog.log('EHCI', 'Found ');
|
||||||
@@ -1519,9 +1578,24 @@ begin
|
|||||||
{ Register with USB core and scan ports }
|
{ Register with USB core and scan ports }
|
||||||
hcEntry := usbcore.register_hc(@hc);
|
hcEntry := usbcore.register_hc(@hc);
|
||||||
|
|
||||||
if hcEntry <> nil then
|
if hcEntry <> nil then begin
|
||||||
usbcore.scan_ports(hcEntry)
|
{ Track instance for ISR dispatch }
|
||||||
else
|
if EHCIInstanceCount < EHCI_MAX_INSTANCES then begin
|
||||||
|
EHCIInstances[EHCIInstanceCount] := hcEntry;
|
||||||
|
inc(EHCIInstanceCount);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Register ISR on PCI interrupt line }
|
||||||
|
syslog.log('EHCI', 'Registering ISR on IRQ ');
|
||||||
|
syslog.writeintln(devices[i].interrupt_line);
|
||||||
|
isrmanager.registerISR(32 + devices[i].interrupt_line, @ehci_isr);
|
||||||
|
|
||||||
|
{ Enable hardware interrupts }
|
||||||
|
ehci_enable_interrupts(hcEntry);
|
||||||
|
|
||||||
|
{ Scan for connected devices }
|
||||||
|
usbcore.scan_ports(hcEntry);
|
||||||
|
end else
|
||||||
syslog.logln('EHCI', 'Failed to register HC with USB core.');
|
syslog.logln('EHCI', 'Failed to register HC with USB core.');
|
||||||
|
|
||||||
syslog.logln('EHCI', 'Controller initialized and registered.');
|
syslog.logln('EHCI', 'Controller initialized and registered.');
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
@author(Kieron Morris <[email protected]>)
|
@author(Kieron Morris <[email protected]>)
|
||||||
}
|
}
|
||||||
unit OHCI;
|
unit ohci;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
@@ -23,6 +23,7 @@ uses
|
|||||||
drivermanagement,
|
drivermanagement,
|
||||||
usbtypes,
|
usbtypes,
|
||||||
usbcore,
|
usbcore,
|
||||||
|
isrmanager,
|
||||||
lists,
|
lists,
|
||||||
strings;
|
strings;
|
||||||
|
|
||||||
@@ -234,6 +235,7 @@ type
|
|||||||
EDBulk : POHCI_ED; { Head of bulk ED list }
|
EDBulk : POHCI_ED; { Head of bulk ED list }
|
||||||
EDInterrupt : POHCI_ED; { Dummy head for interrupt ED list }
|
EDInterrupt : POHCI_ED; { Dummy head for interrupt ED list }
|
||||||
NumPorts : uint8; { Number of downstream ports }
|
NumPorts : uint8; { Number of downstream ports }
|
||||||
|
PollBusy : boolean; { Re-entrancy guard for poll }
|
||||||
PCIBus : uint8; { PCI address }
|
PCIBus : uint8; { PCI address }
|
||||||
PCISlot : uint8;
|
PCISlot : uint8;
|
||||||
PCIFunc : uint8;
|
PCIFunc : uint8;
|
||||||
@@ -1022,6 +1024,56 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ ========================= Interrupt-Driven Completion ========================= }
|
||||||
|
|
||||||
|
const
|
||||||
|
OHCI_MAX_INSTANCES = 4;
|
||||||
|
|
||||||
|
var
|
||||||
|
OHCIInstances : array[0..OHCI_MAX_INSTANCES-1] of PUSBHCDriver;
|
||||||
|
OHCIInstanceCount : uint32;
|
||||||
|
|
||||||
|
{ ISR handler — registered on the PCI interrupt line. }
|
||||||
|
procedure ohci_isr;
|
||||||
|
var
|
||||||
|
i : uint32;
|
||||||
|
hc : PUSBHCDriver;
|
||||||
|
priv : POHCI_PrivData;
|
||||||
|
intSts : uint32;
|
||||||
|
begin
|
||||||
|
for i := 0 to OHCIInstanceCount - 1 do begin
|
||||||
|
hc := OHCIInstances[i];
|
||||||
|
if hc = nil then continue;
|
||||||
|
priv := POHCI_PrivData(hc^.PrivData);
|
||||||
|
if priv = nil then continue;
|
||||||
|
|
||||||
|
{ Check if this controller has pending interrupt status }
|
||||||
|
intSts := ohci_read(priv^.MMIOBase, OHCI_REG_INTSTATUS);
|
||||||
|
if intSts = 0 then continue;
|
||||||
|
|
||||||
|
{ Acknowledge interrupt status NOW to de-assert level-triggered PCI line.
|
||||||
|
Must happen before ohci_poll, because PollBusy guard may skip the
|
||||||
|
acknowledge inside poll — leaving the line asserted = interrupt storm. }
|
||||||
|
ohci_write(priv^.MMIOBase, OHCI_REG_INTSTATUS, intSts);
|
||||||
|
|
||||||
|
{ Process completions (walks ED lists) }
|
||||||
|
ohci_poll(hc);
|
||||||
|
end;
|
||||||
|
usbcore.fire_completion_hooks;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Enable hardware interrupts: WritebackDoneHead, RootHubStatusChange, UnrecoverableError + MIE. }
|
||||||
|
procedure ohci_enable_interrupts(hc : PUSBHCDriver);
|
||||||
|
var
|
||||||
|
priv : POHCI_PrivData;
|
||||||
|
begin
|
||||||
|
if (hc = nil) or (hc^.PrivData = nil) then exit;
|
||||||
|
priv := POHCI_PrivData(hc^.PrivData);
|
||||||
|
ohci_write(priv^.MMIOBase, OHCI_REG_INTENABLE,
|
||||||
|
OHCI_INT_WDH OR OHCI_INT_RHSC OR OHCI_INT_UE OR OHCI_INT_MIE);
|
||||||
|
syslog.logln('OHCI', 'Hardware interrupts enabled.');
|
||||||
|
end;
|
||||||
|
|
||||||
procedure ohci_poll(hc : PUSBHCDriver);
|
procedure ohci_poll(hc : PUSBHCDriver);
|
||||||
var
|
var
|
||||||
priv : POHCI_PrivData;
|
priv : POHCI_PrivData;
|
||||||
@@ -1038,6 +1090,11 @@ var
|
|||||||
begin
|
begin
|
||||||
if (hc = nil) or (hc^.PrivData = nil) then exit;
|
if (hc = nil) or (hc^.PrivData = nil) then exit;
|
||||||
priv := POHCI_PrivData(hc^.PrivData);
|
priv := POHCI_PrivData(hc^.PrivData);
|
||||||
|
|
||||||
|
{ Re-entrancy guard }
|
||||||
|
if priv^.PollBusy then exit;
|
||||||
|
priv^.PollBusy := true;
|
||||||
|
|
||||||
base := priv^.MMIOBase;
|
base := priv^.MMIOBase;
|
||||||
|
|
||||||
{ Read and acknowledge interrupt status }
|
{ Read and acknowledge interrupt status }
|
||||||
@@ -1107,6 +1164,7 @@ begin
|
|||||||
ed := nextED;
|
ed := nextED;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
priv^.PollBusy := false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ ========================= Load / Init ========================= }
|
{ ========================= Load / Init ========================= }
|
||||||
@@ -1124,6 +1182,7 @@ var
|
|||||||
begin
|
begin
|
||||||
push_trace('OHCI.load');
|
push_trace('OHCI.load');
|
||||||
load := false;
|
load := false;
|
||||||
|
OHCIInstanceCount := 0;
|
||||||
|
|
||||||
devices := PCI.getDeviceInfo($0C, $03, $10, count);
|
devices := PCI.getDeviceInfo($0C, $03, $10, count);
|
||||||
syslog.log('OHCI', 'Found ');
|
syslog.log('OHCI', 'Found ');
|
||||||
@@ -1220,9 +1279,24 @@ begin
|
|||||||
hcEntry := usbcore.register_hc(@hc);
|
hcEntry := usbcore.register_hc(@hc);
|
||||||
|
|
||||||
{ Scan ports for connected devices (use the stable pointer, not stack-local @hc) }
|
{ Scan ports for connected devices (use the stable pointer, not stack-local @hc) }
|
||||||
if hcEntry <> nil then
|
if hcEntry <> nil then begin
|
||||||
usbcore.scan_ports(hcEntry)
|
{ Track instance for ISR dispatch }
|
||||||
else
|
if OHCIInstanceCount < OHCI_MAX_INSTANCES then begin
|
||||||
|
OHCIInstances[OHCIInstanceCount] := hcEntry;
|
||||||
|
inc(OHCIInstanceCount);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Register ISR on PCI interrupt line }
|
||||||
|
syslog.log('OHCI', 'Registering ISR on IRQ ');
|
||||||
|
syslog.writeintln(devices[i].interrupt_line);
|
||||||
|
isrmanager.registerISR(32 + devices[i].interrupt_line, @ohci_isr);
|
||||||
|
|
||||||
|
{ Enable hardware interrupts }
|
||||||
|
ohci_enable_interrupts(hcEntry);
|
||||||
|
|
||||||
|
{ Scan for connected devices }
|
||||||
|
usbcore.scan_ports(hcEntry);
|
||||||
|
end else
|
||||||
syslog.logln('OHCI', 'Failed to register HC with USB core.');
|
syslog.logln('OHCI', 'Failed to register HC with USB core.');
|
||||||
|
|
||||||
syslog.logln('OHCI', 'Controller initialized and registered.');
|
syslog.logln('OHCI', 'Controller initialized and registered.');
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
@author(Kieron Morris <[email protected]>)
|
@author(Kieron Morris <[email protected]>)
|
||||||
}
|
}
|
||||||
unit UHCI;
|
unit uhci;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
@@ -22,6 +22,7 @@ uses
|
|||||||
drivermanagement,
|
drivermanagement,
|
||||||
usbtypes,
|
usbtypes,
|
||||||
usbcore,
|
usbcore,
|
||||||
|
isrmanager,
|
||||||
lists,
|
lists,
|
||||||
strings;
|
strings;
|
||||||
|
|
||||||
@@ -154,6 +155,7 @@ type
|
|||||||
QHControl : PUHCI_QH; { Queue Head for control transfers }
|
QHControl : PUHCI_QH; { Queue Head for control transfers }
|
||||||
QHBulk : PUHCI_QH; { Queue Head for bulk transfers }
|
QHBulk : PUHCI_QH; { Queue Head for bulk transfers }
|
||||||
QHInterrupt : PUHCI_QH; { Queue Head for interrupt transfers }
|
QHInterrupt : PUHCI_QH; { Queue Head for interrupt transfers }
|
||||||
|
PollBusy : boolean; { Re-entrancy guard for poll }
|
||||||
PCIBus : uint8; { PCI bus/slot/func for bus mastering }
|
PCIBus : uint8; { PCI bus/slot/func for bus mastering }
|
||||||
PCISlot : uint8;
|
PCISlot : uint8;
|
||||||
PCIFunc : uint8;
|
PCIFunc : uint8;
|
||||||
@@ -750,6 +752,56 @@ begin
|
|||||||
pop_trace;
|
pop_trace;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ ========================= Interrupt-Driven Completion ========================= }
|
||||||
|
|
||||||
|
const
|
||||||
|
UHCI_MAX_INSTANCES = 4;
|
||||||
|
|
||||||
|
var
|
||||||
|
UHCIInstances : array[0..UHCI_MAX_INSTANCES-1] of PUSBHCDriver;
|
||||||
|
UHCIInstanceCount : uint32;
|
||||||
|
|
||||||
|
{ ISR handler — registered on the PCI interrupt line. }
|
||||||
|
procedure uhci_isr;
|
||||||
|
var
|
||||||
|
i : uint32;
|
||||||
|
hc : PUSBHCDriver;
|
||||||
|
priv : PUHCI_PrivData;
|
||||||
|
status : uint16;
|
||||||
|
begin
|
||||||
|
for i := 0 to UHCIInstanceCount - 1 do begin
|
||||||
|
hc := UHCIInstances[i];
|
||||||
|
if hc = nil then continue;
|
||||||
|
priv := PUHCI_PrivData(hc^.PrivData);
|
||||||
|
if priv = nil then continue;
|
||||||
|
|
||||||
|
{ Check if this controller has pending interrupt status }
|
||||||
|
status := uhci_read16(priv^.IOBase, UHCI_REG_USBSTS);
|
||||||
|
if (status AND (UHCI_STS_USBINT OR UHCI_STS_ERROR)) = 0 then continue;
|
||||||
|
|
||||||
|
{ Acknowledge interrupt status NOW to de-assert level-triggered PCI line.
|
||||||
|
Must happen before uhci_poll, because PollBusy guard may skip the
|
||||||
|
acknowledge inside poll — leaving the line asserted = interrupt storm. }
|
||||||
|
uhci_write16(priv^.IOBase, UHCI_REG_USBSTS, status AND (UHCI_STS_USBINT OR UHCI_STS_ERROR));
|
||||||
|
|
||||||
|
{ Process completions (walks QH/TD chains) }
|
||||||
|
uhci_poll(hc);
|
||||||
|
end;
|
||||||
|
usbcore.fire_completion_hooks;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Enable hardware interrupts: Interrupt-on-Complete, Short Packet, Timeout/CRC. }
|
||||||
|
procedure uhci_enable_interrupts(hc : PUSBHCDriver);
|
||||||
|
var
|
||||||
|
priv : PUHCI_PrivData;
|
||||||
|
begin
|
||||||
|
if (hc = nil) or (hc^.PrivData = nil) then exit;
|
||||||
|
priv := PUHCI_PrivData(hc^.PrivData);
|
||||||
|
uhci_write16(priv^.IOBase, UHCI_REG_USBINTR,
|
||||||
|
UHCI_INTR_IOC OR UHCI_INTR_SP OR UHCI_INTR_TIMEOUT);
|
||||||
|
syslog.logln('UHCI', 'Hardware interrupts enabled.');
|
||||||
|
end;
|
||||||
|
|
||||||
{ ========================= Poll / Completion ========================= }
|
{ ========================= Poll / Completion ========================= }
|
||||||
|
|
||||||
procedure uhci_poll(hc : PUSBHCDriver);
|
procedure uhci_poll(hc : PUSBHCDriver);
|
||||||
@@ -768,6 +820,10 @@ begin
|
|||||||
if (hc = nil) or (hc^.PrivData = nil) then exit;
|
if (hc = nil) or (hc^.PrivData = nil) then exit;
|
||||||
priv := PUHCI_PrivData(hc^.PrivData);
|
priv := PUHCI_PrivData(hc^.PrivData);
|
||||||
|
|
||||||
|
{ Re-entrancy guard }
|
||||||
|
if priv^.PollBusy then exit;
|
||||||
|
priv^.PollBusy := true;
|
||||||
|
|
||||||
{ Read and clear status register }
|
{ Read and clear status register }
|
||||||
status := uhci_read16(priv^.IOBase, UHCI_REG_USBSTS);
|
status := uhci_read16(priv^.IOBase, UHCI_REG_USBSTS);
|
||||||
if (status AND (UHCI_STS_USBINT OR UHCI_STS_ERROR)) <> 0 then
|
if (status AND (UHCI_STS_USBINT OR UHCI_STS_ERROR)) <> 0 then
|
||||||
@@ -841,6 +897,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
qh := qh^.SWNext;
|
qh := qh^.SWNext;
|
||||||
end;
|
end;
|
||||||
|
priv^.PollBusy := false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ ========================= Load / Init ========================= }
|
{ ========================= Load / Init ========================= }
|
||||||
@@ -857,6 +914,7 @@ var
|
|||||||
begin
|
begin
|
||||||
push_trace('UHCI.load');
|
push_trace('UHCI.load');
|
||||||
load := false;
|
load := false;
|
||||||
|
UHCIInstanceCount := 0;
|
||||||
|
|
||||||
devices := PCI.getDeviceInfo($0C, $03, $00, count);
|
devices := PCI.getDeviceInfo($0C, $03, $00, count);
|
||||||
syslog.log('UHCI', 'Found ');
|
syslog.log('UHCI', 'Found ');
|
||||||
@@ -945,9 +1003,24 @@ begin
|
|||||||
hcEntry := usbcore.register_hc(@hc);
|
hcEntry := usbcore.register_hc(@hc);
|
||||||
|
|
||||||
{ Scan ports for connected devices (use the stable pointer, not stack-local @hc) }
|
{ Scan ports for connected devices (use the stable pointer, not stack-local @hc) }
|
||||||
if hcEntry <> nil then
|
if hcEntry <> nil then begin
|
||||||
usbcore.scan_ports(hcEntry)
|
{ Track instance for ISR dispatch }
|
||||||
else
|
if UHCIInstanceCount < UHCI_MAX_INSTANCES then begin
|
||||||
|
UHCIInstances[UHCIInstanceCount] := hcEntry;
|
||||||
|
inc(UHCIInstanceCount);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Register ISR on PCI interrupt line }
|
||||||
|
syslog.log('UHCI', 'Registering ISR on IRQ ');
|
||||||
|
syslog.writeintln(devices[i].interrupt_line);
|
||||||
|
isrmanager.registerISR(32 + devices[i].interrupt_line, @uhci_isr);
|
||||||
|
|
||||||
|
{ Enable hardware interrupts }
|
||||||
|
uhci_enable_interrupts(hcEntry);
|
||||||
|
|
||||||
|
{ Scan for connected devices }
|
||||||
|
usbcore.scan_ports(hcEntry);
|
||||||
|
end else
|
||||||
syslog.logln('UHCI', 'Failed to register HC with USB core.');
|
syslog.logln('UHCI', 'Failed to register HC with USB core.');
|
||||||
|
|
||||||
syslog.logln('UHCI', 'Controller initialized and registered.');
|
syslog.logln('UHCI', 'Controller initialized and registered.');
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
@author(Kieron Morris <[email protected]>)
|
@author(Kieron Morris <[email protected]>)
|
||||||
}
|
}
|
||||||
unit USB;
|
unit usb;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
|
|||||||
+111
-37
File diff suppressed because it is too large.
Load diff
@@ -40,6 +40,18 @@ procedure scan_ports(hc : PUSBHCDriver);
|
|||||||
{ Poll all registered host controllers. Called from timer/scheduler. }
|
{ Poll all registered host controllers. Called from timer/scheduler. }
|
||||||
procedure poll_all;
|
procedure poll_all;
|
||||||
|
|
||||||
|
{ ========================= Completion Hooks ========================= }
|
||||||
|
|
||||||
|
type
|
||||||
|
TUSBCompletionHook = procedure;
|
||||||
|
|
||||||
|
{ Register a completion hook — called by HC ISRs after processing completions.
|
||||||
|
HID drivers (keyboard, mouse) use this to get notified without polling. }
|
||||||
|
procedure register_completion_hook(hook : TUSBCompletionHook);
|
||||||
|
|
||||||
|
{ Fire all registered completion hooks. Called from HC ISR context. }
|
||||||
|
procedure fire_completion_hooks;
|
||||||
|
|
||||||
{ ========================= Transfer API ========================= }
|
{ ========================= Transfer API ========================= }
|
||||||
|
|
||||||
{ Submit a control transfer. Blocking-style (polls until complete or timeout). }
|
{ Submit a control transfer. Blocking-style (polls until complete or timeout). }
|
||||||
@@ -115,8 +127,13 @@ implementation
|
|||||||
|
|
||||||
{ ========================= Globals ========================= }
|
{ ========================= Globals ========================= }
|
||||||
|
|
||||||
|
const
|
||||||
|
MAX_COMPLETION_HOOKS = 8;
|
||||||
|
|
||||||
var
|
var
|
||||||
HCList : PLinkedListBase;
|
HCList : PLinkedListBase;
|
||||||
|
CompletionHooks : array[0..MAX_COMPLETION_HOOKS-1] of TUSBCompletionHook;
|
||||||
|
CompletionHookCount : uint32;
|
||||||
|
|
||||||
{ ========================= HC Management ========================= }
|
{ ========================= HC Management ========================= }
|
||||||
|
|
||||||
@@ -216,6 +233,26 @@ begin
|
|||||||
pop_trace;
|
pop_trace;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ ========================= Completion Hooks ========================= }
|
||||||
|
|
||||||
|
procedure register_completion_hook(hook : TUSBCompletionHook);
|
||||||
|
begin
|
||||||
|
if CompletionHookCount < MAX_COMPLETION_HOOKS then begin
|
||||||
|
CompletionHooks[CompletionHookCount] := hook;
|
||||||
|
inc(CompletionHookCount);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure fire_completion_hooks;
|
||||||
|
var
|
||||||
|
i : uint32;
|
||||||
|
begin
|
||||||
|
for i := 0 to CompletionHookCount - 1 do begin
|
||||||
|
if CompletionHooks[i] <> nil then
|
||||||
|
CompletionHooks[i]();
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{ ========================= Transfer API ========================= }
|
{ ========================= Transfer API ========================= }
|
||||||
|
|
||||||
function usb_control_msg(dev : PUSBDevice;
|
function usb_control_msg(dev : PUSBDevice;
|
||||||
@@ -691,10 +728,15 @@ end;
|
|||||||
{ ========================= Init ========================= }
|
{ ========================= Init ========================= }
|
||||||
|
|
||||||
procedure init;
|
procedure init;
|
||||||
|
var
|
||||||
|
i : uint32;
|
||||||
begin
|
begin
|
||||||
push_trace('usbcore.init');
|
push_trace('usbcore.init');
|
||||||
syslog.logln('USB Core', 'INIT BEGIN.');
|
syslog.logln('USB Core', 'INIT BEGIN.');
|
||||||
HCList := LL_New(sizeof(TUSBHCDriver));
|
HCList := LL_New(sizeof(TUSBHCDriver));
|
||||||
|
CompletionHookCount := 0;
|
||||||
|
for i := 0 to MAX_COMPLETION_HOOKS - 1 do
|
||||||
|
CompletionHooks[i] := nil;
|
||||||
syslog.logln('USB Core', 'INIT END.');
|
syslog.logln('USB Core', 'INIT END.');
|
||||||
pop_trace;
|
pop_trace;
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -561,6 +561,9 @@ begin
|
|||||||
|
|
||||||
drivermanagement.register_driver('USB Keyboard Driver', @KBID, @load);
|
drivermanagement.register_driver('USB Keyboard Driver', @KBID, @load);
|
||||||
|
|
||||||
|
{ Register completion hook so HC ISRs trigger keyboard polling }
|
||||||
|
usbcore.register_completion_hook(usbcore.TUSBCompletionHook(@poll_keyboards));
|
||||||
|
|
||||||
syslog.logln('USBKeyboard', 'INIT END.');
|
syslog.logln('USBKeyboard', 'INIT END.');
|
||||||
pop_trace;
|
pop_trace;
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -346,6 +346,9 @@ begin
|
|||||||
|
|
||||||
drivermanagement.register_driver('USB Mouse Driver', @MouseID, @load);
|
drivermanagement.register_driver('USB Mouse Driver', @MouseID, @load);
|
||||||
|
|
||||||
|
{ Register completion hook so HC ISRs trigger mouse polling }
|
||||||
|
usbcore.register_completion_hook(usbcore.TUSBCompletionHook(@poll_mice));
|
||||||
|
|
||||||
syslog.logln('USBMouse', 'INIT END.');
|
syslog.logln('USBMouse', 'INIT END.');
|
||||||
pop_trace;
|
pop_trace;
|
||||||
end;
|
end;
|
||||||
|
|||||||
Reference in new issue
Block a user