feat: devices via caps (BootInfo, init assigns devices, drivers map MMIO/DMA themselves, IRQ-driven input); drop boot device wiring and info pages; headless display fallback

This commit is contained in:
2026-10-27 12:28:39 +01:00
parent 8bc5402a29
commit 694c675a40
39 changed files with 731 additions and 387 deletions

View File

@@ -1,20 +1,70 @@
use server_framework::Server;
use port_input_device::InputDevice;
use port_input_device::{InputDevice, InputEvent};
use types::bounded::CapSlot;
use crate::protocol::{InputRequest, InputResponse};
/// Events captured on interrupts and not yet asked for.
const BUFFERED: usize = 32;
pub struct InputServer<D: InputDevice> {
device: D,
/// The IRQ to re-arm after each interrupt, if the device has one.
irq: Option<CapSlot>,
events: [Option<InputEvent>; BUFFERED],
head: usize,
len: usize,
}
impl<D: InputDevice> InputServer<D> {
/// A server that reads the device only when a client asks.
pub fn new(device: D) -> Self {
Self { device }
Self { device, irq: None, events: [None; BUFFERED], head: 0, len: 0 }
}
/// A server woken by `irq` (routed and bound by the caller): it drains
/// the device into a buffer on every interrupt, so events that arrive
/// between requests are kept.
pub fn with_irq(device: D, irq: CapSlot) -> Self {
Self { irq: Some(irq), ..Self::new(device) }
}
fn push(&mut self, event: InputEvent) {
if self.len == BUFFERED {
// Full: the oldest event goes.
self.head = (self.head + 1) % BUFFERED;
self.len -= 1;
}
let tail = (self.head + self.len) % BUFFERED;
if let Some(slot) = self.events.get_mut(tail) {
*slot = Some(event);
self.len += 1;
}
}
fn pop(&mut self) -> Option<InputEvent> {
if self.len == 0 {
return None;
}
let event = self.events.get_mut(self.head)?.take();
self.head = (self.head + 1) % BUFFERED;
self.len -= 1;
event
}
/// The next event: buffered first, then whatever the device has now.
fn next_event(&mut self) -> Option<InputEvent> {
self.pop().or_else(|| self.device.poll())
}
pub fn device(&self) -> &D {
&self.device
}
#[cfg(test)]
pub fn replace_device_for_test(&mut self, device: D) {
self.device = device;
}
}
impl<D: InputDevice> Server for InputServer<D> {
@@ -23,14 +73,22 @@ impl<D: InputDevice> Server for InputServer<D> {
fn handle(&mut self, request: InputRequest) -> InputResponse {
match request {
InputRequest::PollEvent => match self.device.poll() {
Some(event) => InputResponse::Event(event),
None => InputResponse::NoEvent,
},
InputRequest::WaitEvent => match self.device.poll() {
// WaitEvent cannot block: a server thread has one reply slot,
// so it answers like PollEvent.
InputRequest::PollEvent | InputRequest::WaitEvent => match self.next_event() {
Some(event) => InputResponse::Event(event),
None => InputResponse::NoEvent,
},
}
}
fn signal(&mut self, _bits: usize) {
while let Some(event) = self.device.poll() {
self.push(event);
}
self.device.acknowledge();
if let Some(irq) = self.irq {
let _ = libkos::syscall::ack_interrupt(irq);
}
}
}