use server_framework::{Decode, Encode, MALFORMED, Server}; 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 { device: D, /// The IRQ to re-arm after each interrupt, if the device has one. irq: Option, events: [Option; BUFFERED], head: usize, len: usize, /// Signalled when events arrive (the display server's notification). subscriber: Option, } impl InputServer { /// A server that reads the device only when a client asks. pub fn new(device: D) -> Self { Self { device, irq: None, events: [None; BUFFERED], head: 0, len: 0, subscriber: None } } /// 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 { 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 { self.pop().or_else(|| self.device.poll()) } pub fn device(&self) -> &D { &self.device } pub fn subscriber(&self) -> Option { self.subscriber } #[cfg(test)] pub fn replace_device_for_test(&mut self, device: D) { self.device = device; } } impl Server for InputServer { type Request = InputRequest; type Response = InputResponse; fn handle(&mut self, request: InputRequest) -> InputResponse { match request { // 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 handle_call(&mut self, _badge: usize, words: [usize; 4], cap: Option) -> ([usize; 4], Option) { if words[0] == types::input::SUBSCRIBE { self.subscriber = cap; return ([0; 4], None); } match InputRequest::decode(words) { Some(request) => (self.handle(request).encode(), None), None => ([MALFORMED, 0, 0, 0], None), } } fn signal(&mut self, _bits: usize) { let mut arrived = false; while let Some(event) = self.device.poll() { self.push(event); arrived = true; } if let (true, Some(subscriber)) = (arrived, self.subscriber) { let _ = libkos::syscall::signal(subscriber); } self.device.acknowledge(); if let Some(irq) = self.irq { let _ = libkos::syscall::ack_interrupt(irq); } } }