USB Stack & HID Refactor

- New units: usbtypes, usbcore, usbhub, UHCI, OHCI, usb_keyboard,
  usb_mouse
- usbtypes: shared USB descriptors, constants, HC abstraction,
  aligned alloc, unit tests
- usb_keyboard: USB HID boot keyboard driver with HID-to-ASCII
  translation, polling, unit tests
- usb_mouse: USB HID boot mouse driver with delta/scroll/button
  processing, polling, unit tests

HID Layer Restructure:
- keyboard.pas: stripped to abstract API (hook + reportKeyEvent),
  no PS/2 dependency
- mouse.pas: absorbed mousestate.pas, now owns
  position/buttons/scroll/hooks directly
- mousestate.pas: deleted (merged into mouse.pas)
- New ps2_keyboard.pas: PS/2 scan code translation,
  calls keyboard.reportKeyEvent
- New ps2_mouse.pas: PS/2 packet handling, calls
  mouse.setMousePos/fireMouseEvent

LVGL Integration:
- lvgl.pas: updated to use mouse.pas directly (was mousestate),
  improved keyboard input handling with proper key held/release tracking
- vterminal.pas: removed serial debug logging, dropped serial dependency

Kernel:
- kernel.pas: added USB units, USB polling in main loop, unit test
  calls, ps2_keyboard/ps2_mouse init
This commit is contained in:
2026-03-01 21:23:33 +00:00
parent afdc83eaf6
commit cb7144f282
22 changed files with 6886 additions and 1015 deletions
+1 -1
View File
@@ -4,4 +4,4 @@ echo "======================="
echo " "
echo "Compiling FPC Sources..."
echo " "
fpc -Aelf -gw -g -gl -n -v0ew -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ -Fusrc/* -Fusrc/driver/* -Fusrc/driver/net/* src/kernel.pas
fpc -Aelf -gw -g -gl -n -v0ew -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ -Fusrc/* -Fusrc/driver/* -Fusrc/driver/net/* -Fusrc/driver/bus/* -Fusrc/driver/bus/usb/* -Fusrc/driver/hid/* src/kernel.pas
-96
View File
@@ -1,96 +0,0 @@
// Copyright 2021 Kieron Morris
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
{
Driver->Bus->OHCI - Open Host Controller Interface Driver.
@author(Kieron Morris <[email protected]>)
}
unit OHCI;
interface
uses
tracer,
syslog,
PCI,
drivertypes,
pmemorymanager,
vmemorymanager,
util,
drivermanagement;
type
POHCI_MMR = ^TOHCI_MMR;
TOHCI_MMR = packed record
HcRevision : uint32;
HcControl : uint32;
HcCommandStatus : uint32;
HcIntStatus : uint32;
HcIntEnable : uint32;
HcIntDisable : uint32;
HcHCCA : uint32;
HcPeriodCurrentED : uint32;
HcControlHeadED : uint32;
HcControlCurrentED : uint32;
HcBulkHeadED : uint32;
HcBulkCurrentED : uint32;
HcDoneHead : uint32;
HcFmRemaining : uint32;
HcFmNumber : uint32;
HcPeriodicStart : uint32;
HcLSThreshold : uint32;
HcRhDescriptorA : uint32;
HcRhDescriptorB : uint32;
HcRhStatus : uint32;
end;
function load : boolean;
implementation
function load : boolean;
var
devices : TDeviceArray;
count : uint32;
i : uint32;
block : uint32;
MMR : POHCI_MMR;
begin
tracer.push_trace('OHCI.load');
devices:= PCI.getDeviceInfo($0C, $03, $10, count);
syslog.log('USB-OHCI Driver', 'Found ');
syslog.writeint(count);
syslog.writestringln(' USB Controller(s).');
if count > 0 then begin
for i:=0 to count-1 do begin
syslog.log('USB-OHCI Driver', 'Controller[');
syslog.writeint(i);
syslog.writestring(']: ');
syslog.writehex(devices[i].device_id);
syslog.writestring(' ');
syslog.writehex(devices[i].vendor_id);
syslog.writestring(' ');
syslog.writehexln(devices[i].prog_if);
block:= devices[i].address0 SHR 22;
force_alloc_block(block, 0);
map_page(block, block);
MMR:= POHCI_MMR(devices[i].address0);
end;
end;
load:= true;
end;
end.
-65
View File
@@ -1,65 +0,0 @@
// Copyright 2021 Kieron Morris
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
{
Driver->Bus->UHCI - Universal Host Controller Interface Driver.
@author(Kieron Morris <[email protected]>)
}
unit UHCI;
interface
uses
tracer,
syslog,
PCI,
drivertypes,
pmemorymanager,
vmemorymanager,
util,
drivermanagement;
function load : boolean;
implementation
function load : boolean;
var
devices : TDeviceArray;
count : uint32;
i : uint32;
begin
tracer.push_trace('UHCI.load');
devices:= PCI.getDeviceInfo($0C, $03, $00, count);
syslog.log('USB-UHCI Driver','Found ');
syslog.writeint(count);
syslog.writestringln(' USB Controller(s).');
if count > 0 then begin
for i:=0 to count-1 do begin
syslog.log('USB-UHCI Driver','Controller[');
syslog.writeint(i);
syslog.writestring(']: ');
syslog.writehex(devices[i].device_id);
syslog.writestring(' ');
syslog.writehex(devices[i].vendor_id);
syslog.writestring(' ');
syslog.writehexln(devices[i].prog_if);
end;
end;
load:= true;
end;
end.
@@ -29,7 +29,8 @@ uses
pmemorymanager,
vmemorymanager,
util,
drivermanagement;
drivermanagement,
usbtypes;
function load : boolean;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -30,6 +30,11 @@ uses
vmemorymanager,
util,
drivermanagement,
usbtypes,
usbcore,
usbhub,
usb_keyboard,
usb_mouse,
OHCI, UHCI, EHCI, XHCI;
procedure init;
@@ -40,24 +45,28 @@ function loadXHCI(ptr : void) : boolean;
begin
push_trace('USB.loadXHCI');
loadXHCI:= XHCI.load;
pop_trace;
end;
function loadEHCI(ptr : void) : boolean;
begin
push_trace('USB.loadEHCI');
loadEHCI:= EHCI.load;
pop_trace;
end;
function loadOHCI(ptr : void) : boolean;
begin
push_trace('USB.loadOHCI');
loadOHCI:= OHCI.load;
pop_trace;
end;
function loadUHCI(ptr : void) : boolean;
begin
push_trace('USB.loadUHCI');
loadUHCI:= UHCI.load;
pop_trace;
end;
procedure init;
@@ -70,6 +79,16 @@ var
begin
push_trace('USB.init');
syslog.logln('USB Driver', 'INIT BEGIN.');
{ Initialize USB core (HC list, etc.) }
usbcore.init;
{ Initialize hub driver (registers class driver for $09) }
usbhub.init;
{ Initialize HID class drivers }
usb_keyboard.init;
usb_mouse.init;
UHCI_ID.Bus:= biPCI;
UHCI_ID.id0:= idANY;
@@ -29,7 +29,8 @@ uses
pmemorymanager,
vmemorymanager,
util,
drivermanagement;
drivermanagement,
usbtypes;
function load : boolean;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+108 -309
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+46 -34
View File
@@ -13,7 +13,7 @@ interface
uses
video, videotypes, color, serial, tracer, lmemorymanager,
mousestate, keyboard, TMR_0_ISR, util;
mouse, keyboard, TMR_0_ISR, util;
{ ============================================================
Opaque LVGL pointer types (internal C structs)
@@ -1719,10 +1719,11 @@ var
{ Keyboard ring buffer for LVGL }
kb_buf : array[0..15] of uint32;
kb_head : uint32; { next write slot (ISR side) }
kb_head : uint32; { next write slot (hook side) }
kb_tail : uint32; { next read slot (LVGL poll side) }
last_key : uint32; { last key delivered, for release event }
kb_pending_release : boolean; { true = must send RELEASED before next key }
kb_current_key : uint32; { key currently reported as pressed to LVGL, 0 = none }
kb_key_held : boolean; { true while physical key is down }
kb_held_code : uint32; { the LVGL key code of the held key }
const
KB_BUF_SIZE = 16;
@@ -1805,9 +1806,9 @@ end;
============================================================ }
procedure lvgl_mouse_read_cb(indev: Plv_indev; data: Plv_indev_data); cdecl;
begin
data^.point.x := mousestate.getMouseX;
data^.point.y := mousestate.getMouseY;
if mousestate.getMouseLMB then
data^.point.x := mouse.getMouseX;
data^.point.y := mouse.getMouseY;
if mouse.getMouseLMB then
data^.state := LV_INDEV_STATE_PRESSED
else
data^.state := LV_INDEV_STATE_RELEASED;
@@ -1818,28 +1819,29 @@ end;
Keyboard read callback — LVGL polls this for key state
============================================================ }
procedure lvgl_kb_read_cb(indev: Plv_indev; data: Plv_indev_data); cdecl;
var
next_tail: uint32;
begin
if kb_pending_release then begin
{ Send release for the previous key before consuming the next }
data^.key := last_key;
if (kb_current_key <> 0) and
((not kb_key_held) or (kb_held_code <> kb_current_key) or (kb_tail <> kb_head)) then begin
{ Release current key: physical key released, different key now held, or new keys queued }
data^.key := kb_current_key;
data^.state := LV_INDEV_STATE_RELEASED;
kb_pending_release := false;
{ If more keys are queued, tell LVGL to call us again }
kb_current_key := 0;
data^.continue_reading := (kb_tail <> kb_head);
end else if kb_tail <> kb_head then begin
{ Consume next key from ring buffer — send press }
last_key := kb_buf[kb_tail];
{ Consume next key from ring buffer — press }
kb_current_key := kb_buf[kb_tail];
kb_tail := (kb_tail + 1) mod KB_BUF_SIZE;
data^.key := last_key;
data^.key := kb_current_key;
data^.state := LV_INDEV_STATE_PRESSED;
kb_pending_release := true;
{ Always call again to send the matching release }
data^.continue_reading := true;
data^.continue_reading := false; { one press per timer cycle for proper long-press timing }
end else if (kb_current_key <> 0) and kb_key_held then begin
{ Key still physically held — keep reporting pressed for LVGL long-press repeat }
data^.key := kb_current_key;
data^.state := LV_INDEV_STATE_PRESSED;
data^.continue_reading := false;
end else begin
{ No pending keys — idle release }
data^.key := last_key;
{ Idle — no keys }
data^.key := 0;
data^.state := LV_INDEV_STATE_RELEASED;
data^.continue_reading := false;
end;
@@ -1853,12 +1855,13 @@ var
k: uint32;
next_head: uint32;
begin
{ Ctrl+D toggles debug overlay }
if key_info.CTRL_DOWN and (key_info.key_code = ord('d')) then begin
{ Ctrl+D toggles debug overlay (press only) }
if key_info.is_down_code and key_info.CTRL_DOWN and (key_info.key_code = ord('d')) then begin
uidebug.toggle;
exit;
end;
{ Map Asuro key codes to LVGL key codes }
case key_info.key_code of
$1B: k := LV_KEY_ESC;
$08: k := LV_KEY_BACKSPACE;
@@ -1871,11 +1874,19 @@ begin
else k := uint32(key_info.key_code);
end;
{ Push into ring buffer (drop if full — better than corrupting) }
next_head := (kb_head + 1) mod KB_BUF_SIZE;
if next_head <> kb_tail then begin
kb_buf[kb_head] := k;
kb_head := next_head;
if key_info.is_down_code then begin
{ Key press — push into ring buffer and track held state }
next_head := (kb_head + 1) mod KB_BUF_SIZE;
if next_head <> kb_tail then begin
kb_buf[kb_head] := k;
kb_head := next_head;
end;
kb_key_held := true;
kb_held_code := k;
end else begin
{ Key release — clear held state if it matches }
if kb_key_held and (kb_held_code = k) then
kb_key_held := false;
end;
end;
@@ -1895,10 +1906,11 @@ begin
tracer.push_trace('lvgl.init.enter');
tick_accumulator := 0;
last_key := 0;
kb_head := 0;
kb_tail := 0;
kb_pending_release := false;
kb_current_key := 0;
kb_key_held := false;
kb_held_code := 0;
{ Initialize LVGL core }
lv_init;
@@ -1957,10 +1969,10 @@ begin
lv_tick_inc(elapsed);
{ Process scroll wheel }
scroll_delta := mousestate.getMouseScroll;
scroll_delta := mouse.getMouseScroll;
if scroll_delta <> 0 then begin
mx := mousestate.getMouseX;
my := mousestate.getMouseY;
mx := mouse.getMouseX;
my := mouse.getMouseY;
pt.x := mx;
pt.y := my;
target := lv_indev_search_obj(lv_screen_active, @pt);

Some files were not shown because too many files have changed in this diff Show More