Skip to content

Instantly share code, notes, and snippets.

@RKennedy9064
Created May 3, 2020 00:36
Show Gist options
  • Save RKennedy9064/de8000f8f63e14d9aa198240d7d9effb to your computer and use it in GitHub Desktop.
Save RKennedy9064/de8000f8f63e14d9aa198240d7d9effb to your computer and use it in GitHub Desktop.
Code for async mouse task
extern "x86-interrupt" fn mouse_interrupt_handler(_stack_frame: &mut InterruptStackFrame) {
let mut port = PortReadOnly::new(0x60);
let packet = unsafe { port.read() };
crate::task::mouse::add_mouse_packet(packet);
unsafe {
PICS.lock()
.notify_end_of_interrupt(InterruptIndex::Mouse.into());
}
}
pub fn init() {
// New code
task::mouse::init();
}
// New code
executor.spawn(Task::new(mouse::process_packets()));
// New code in task/mod.rs
pub mod mouse;
// New code in task/mouse.rs
use crate::println;
use conquer_once::spin::{Lazy, OnceCell};
use core::{
pin::Pin,
task::{Context, Poll},
};
use crossbeam_queue::ArrayQueue;
use futures_util::{
stream::{Stream, StreamExt},
task::AtomicWaker,
};
use ps2_mouse::{Mouse, MouseState};
use spinning_top::Spinlock;
static WAKER: AtomicWaker = AtomicWaker::new();
pub static MOUSE: Lazy<Spinlock<Mouse>> = Lazy::new(|| Spinlock::new(Mouse::new()));
static MOUSE_PACKET_QUEUE: OnceCell<ArrayQueue<u8>> = OnceCell::uninit();
pub(crate) fn add_mouse_packet(packet: u8) {
if let Ok(queue) = MOUSE_PACKET_QUEUE.try_get() {
if let Err(_) = queue.push(packet) {
println!("WARNING: mouse packet queue full; dropping mouse input");
} else {
WAKER.wake();
}
} else {
println!("WARNING: mouse packet queue uninitialized");
}
}
pub(crate) fn init() {
let mut mouse = MOUSE.lock();
mouse.init().expect("failed to initialize mouse");
mouse.set_on_complete(on_complete);
}
pub struct MousePacketStream {
_private: (),
}
impl MousePacketStream {
pub fn new() -> MousePacketStream {
// Default mouse settings generate packets at 100 packets per second/
// This will overflow quickly if the queue is set too low.
MOUSE_PACKET_QUEUE
.try_init_once(|| ArrayQueue::new(500))
.expect("MousePacketStream::new should only be called once");
MousePacketStream { _private: () }
}
}
impl Stream for MousePacketStream {
type Item = u8;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<u8>> {
let queue = MOUSE_PACKET_QUEUE
.try_get()
.expect("mouse state queue not initialized");
if let Ok(packet) = queue.pop() {
return Poll::Ready(Some(packet));
}
WAKER.register(&cx.waker());
match queue.pop() {
Ok(packet) => {
WAKER.take();
Poll::Ready(Some(packet))
}
Err(crossbeam_queue::PopError) => Poll::Pending,
}
}
}
fn on_complete(mouse_state: MouseState) {
use crate::serial_println;
serial_println!("{:?}", mouse_state);
}
pub async fn process_packets() {
let mut mouse = MOUSE.lock();
let mut packets = MousePacketStream::new();
while let Some(packet) = packets.next().await {
mouse.process_packet(packet);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment