forked from AbleOS/ableos_userland
add in a broken ps2 driver based around the now deprecated kernel lever driver in ableOS
This commit is contained in:
parent
9e30c1a3fe
commit
450a22b05c
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -74,6 +74,11 @@ dependencies = [
|
|||
"toml 0.5.9 (git+https://git.ablecorp.us/theoddgarlic/toml-rs)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpuio"
|
||||
version = "0.3.2"
|
||||
source = "git+https://git.ablecorp.us/ondra05/cpuio.git#093cc103101b4ba4abd02d77c884113a376cdc64"
|
||||
|
||||
[[package]]
|
||||
name = "cryptography"
|
||||
version = "0.1.1"
|
||||
|
@ -239,6 +244,15 @@ dependencies = [
|
|||
name = "ps2_keyboard"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "ps2_mouse"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cpuio",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.21"
|
||||
|
|
|
@ -10,7 +10,7 @@ members = [
|
|||
"drivers/graphics/vgable",
|
||||
|
||||
"drivers/keyboards/ps2_keyboard",
|
||||
|
||||
"drivers/mice/ps2_mouse",
|
||||
"libraries/able_graphics_library",
|
||||
"libraries/clparse",
|
||||
"libraries/cryptography",
|
||||
|
|
2
drivers/mice/ps2_mouse/.cargo/config.toml
Normal file
2
drivers/mice/ps2_mouse/.cargo/config.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[build]
|
||||
target = "wasm32-unknown-unknown"
|
15
drivers/mice/ps2_mouse/Cargo.toml
Normal file
15
drivers/mice/ps2_mouse/Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "ps2_mouse"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.3"
|
||||
|
||||
cpuio = { git = "https://git.ablecorp.us/ondra05/cpuio.git" }
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4.17"
|
||||
default-features = false
|
308
drivers/mice/ps2_mouse/src/main.rs
Normal file
308
drivers/mice/ps2_mouse/src/main.rs
Normal file
|
@ -0,0 +1,308 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
use bitflags::bitflags;
|
||||
use cpuio::Port;
|
||||
use log::debug;
|
||||
|
||||
const ADDRESS_PORT_ADDRESS: u16 = 0x64;
|
||||
const DATA_PORT_ADDRESS: u16 = 0x60;
|
||||
const GET_STATUS_BYTE: u8 = 0x20;
|
||||
const SET_STATUS_BYTE: u8 = 0x60;
|
||||
|
||||
const DISABLE_FIRST: u8 = 0xAD;
|
||||
const DISABLE_SECOND: u8 = 0xA7;
|
||||
const ENABLE_FIRST: u8 = 0xAE;
|
||||
const ENABLE_SECOND: u8 = 0xA8;
|
||||
|
||||
bitflags! {
|
||||
/// Represents the flags currently set for the mouse.
|
||||
#[derive(Default)]
|
||||
pub struct MouseFlags: u8 {
|
||||
/// Whether or not the left mouse button is pressed.
|
||||
const LEFT_BUTTON = 0b0000_0001;
|
||||
|
||||
/// Whether or not the right mouse button is pressed.
|
||||
const RIGHT_BUTTON = 0b0000_0010;
|
||||
|
||||
/// Whether or not the middle mouse button is pressed.
|
||||
const MIDDLE_BUTTON = 0b0000_0100;
|
||||
|
||||
/// Whether or not the packet is valid or not.
|
||||
const ALWAYS_ONE = 0b0000_1000;
|
||||
|
||||
/// Whether or not the x delta is negative.
|
||||
const X_SIGN = 0b0001_0000;
|
||||
|
||||
/// Whether or not the y delta is negative.
|
||||
const Y_SIGN = 0b0010_0000;
|
||||
|
||||
/// Whether or not the x delta overflowed.
|
||||
const X_OVERFLOW = 0b0100_0000;
|
||||
|
||||
/// Whether or not the y delta overflowed.
|
||||
const Y_OVERFLOW = 0b1000_0000;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
enum Command {
|
||||
EnablePacketStreaming = 0xF4,
|
||||
SetDefaults = 0xF6,
|
||||
}
|
||||
|
||||
/// A basic interface to interact with a PS2 mouse.
|
||||
#[derive(Debug)]
|
||||
pub struct Mouse {
|
||||
command_port: Port<u8>,
|
||||
data_port: Port<u8>,
|
||||
current_packet: u8,
|
||||
current_state: MouseState,
|
||||
completed_state: MouseState,
|
||||
on_complete: Option<fn(MouseState)>,
|
||||
}
|
||||
|
||||
impl Default for Mouse {
|
||||
fn default() -> Mouse {
|
||||
Mouse::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// A snapshot of the mouse flags, x delta and y delta.
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub struct MouseState {
|
||||
flags: MouseFlags,
|
||||
x: i16,
|
||||
y: i16,
|
||||
}
|
||||
|
||||
impl MouseState {
|
||||
/// Returns a new `MouseState`.
|
||||
pub const fn new() -> MouseState {
|
||||
MouseState {
|
||||
flags: MouseFlags::empty(),
|
||||
x: 0,
|
||||
y: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the left mouse button is currently down.
|
||||
pub fn _left_button_down(&self) -> bool {
|
||||
self.flags.contains(MouseFlags::LEFT_BUTTON)
|
||||
}
|
||||
|
||||
/// Returns true if the left mouse button is currently up.
|
||||
pub fn _left_button_up(&self) -> bool {
|
||||
!self.flags.contains(MouseFlags::LEFT_BUTTON)
|
||||
}
|
||||
|
||||
/// Returns true if the right mouse button is currently down.
|
||||
pub fn _right_button_down(&self) -> bool {
|
||||
self.flags.contains(MouseFlags::RIGHT_BUTTON)
|
||||
}
|
||||
|
||||
/// Returns true if the right mouse button is currently up.
|
||||
pub fn _right_button_up(&self) -> bool {
|
||||
!self.flags.contains(MouseFlags::RIGHT_BUTTON)
|
||||
}
|
||||
|
||||
/// Returns true if the x axis has moved.
|
||||
pub fn _x_moved(&self) -> bool {
|
||||
self.x != 0
|
||||
}
|
||||
|
||||
/// Returns true if the y axis has moved.
|
||||
pub fn _y_moved(&self) -> bool {
|
||||
self.y != 0
|
||||
}
|
||||
|
||||
/// Returns true if the x or y axis has moved.
|
||||
pub fn _moved(&self) -> bool {
|
||||
self._x_moved() || self._y_moved()
|
||||
}
|
||||
|
||||
/// Returns the x delta of the mouse state.
|
||||
pub fn get_x(&self) -> i16 {
|
||||
self.x
|
||||
}
|
||||
|
||||
/// Returns the y delta of the mouse state.
|
||||
pub fn get_y(&self) -> i16 {
|
||||
self.y
|
||||
}
|
||||
}
|
||||
|
||||
impl Mouse {
|
||||
/// Creates a new `Mouse`.
|
||||
pub const fn new() -> Mouse {
|
||||
Mouse {
|
||||
command_port: unsafe { Port::new(ADDRESS_PORT_ADDRESS) },
|
||||
data_port: unsafe { Port::new(DATA_PORT_ADDRESS) },
|
||||
current_packet: 0,
|
||||
current_state: MouseState::new(),
|
||||
completed_state: MouseState::new(),
|
||||
on_complete: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the last completed state of the mouse.
|
||||
pub fn _get_state(&self) -> MouseState {
|
||||
self.completed_state
|
||||
}
|
||||
|
||||
// super helpful resource, albeit in C
|
||||
// https://github.com/29jm/SnowflakeOS/blob/master/kernel/src/devices/ps2.c#L18
|
||||
/// Attempts to initialize a `Mouse`. If successful, interrupts will be generated
|
||||
/// as `PIC offset + 12`.
|
||||
pub fn init(&mut self) -> Result<(), &'static str> {
|
||||
// Disable both PS/2 device ports
|
||||
// Even if only one is present, disabling the second is harmless
|
||||
self.write_command_port(DISABLE_FIRST)?;
|
||||
self.write_command_port(DISABLE_SECOND)?;
|
||||
|
||||
// Flush output buffer: if the controller had anything to say, ignore it
|
||||
unsafe {
|
||||
self.data_port.read();
|
||||
}
|
||||
|
||||
debug!("mouse driver: writing GET_STATUS to port...");
|
||||
self.write_command_port(GET_STATUS_BYTE)?;
|
||||
debug!("mouse driver: reading status from port...");
|
||||
let status = self.read_data_port()? | 0x02;
|
||||
|
||||
debug!("Got status {}", status);
|
||||
|
||||
// self.write_command_port(0xa8)?;
|
||||
|
||||
self.write_command_port(SET_STATUS_BYTE)?;
|
||||
|
||||
self.write_data_port(status & 0xDF)?;
|
||||
|
||||
self.send_command(Command::SetDefaults)?;
|
||||
self.send_command(Command::EnablePacketStreaming)?;
|
||||
|
||||
self.write_command_port(ENABLE_FIRST)?;
|
||||
self.write_command_port(ENABLE_SECOND)?;
|
||||
|
||||
// Some keyboards actually send a reply, flush it
|
||||
unsafe {
|
||||
self.data_port.read();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempts to process a packet.
|
||||
pub fn process_packet(&mut self, packet: u8) {
|
||||
match self.current_packet {
|
||||
0 => {
|
||||
let flags = MouseFlags::from_bits_truncate(packet);
|
||||
if !flags.contains(MouseFlags::ALWAYS_ONE) {
|
||||
return;
|
||||
}
|
||||
self.current_state.flags = flags;
|
||||
}
|
||||
1 => self.process_x_movement(packet),
|
||||
2 => {
|
||||
self.process_y_movement(packet);
|
||||
self.completed_state = self.current_state;
|
||||
if let Some(on_complete) = self.on_complete {
|
||||
on_complete(self.completed_state);
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
self.current_packet = (self.current_packet + 1) % 3;
|
||||
}
|
||||
|
||||
/// Sets the `on_complete` function to be called when a packet is completed.
|
||||
pub fn set_on_complete(&mut self, handler: fn(MouseState)) {
|
||||
self.on_complete = Some(handler);
|
||||
}
|
||||
|
||||
fn process_x_movement(&mut self, packet: u8) {
|
||||
if !self.current_state.flags.contains(MouseFlags::X_OVERFLOW) {
|
||||
self.current_state.x = if self.current_state.flags.contains(MouseFlags::X_SIGN) {
|
||||
self.sign_extend(packet)
|
||||
} else {
|
||||
packet as i16
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn process_y_movement(&mut self, packet: u8) {
|
||||
if !self.current_state.flags.contains(MouseFlags::Y_OVERFLOW) {
|
||||
self.current_state.y = if self.current_state.flags.contains(MouseFlags::Y_SIGN) {
|
||||
self.sign_extend(packet)
|
||||
} else {
|
||||
packet as i16
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn read_data_port(&mut self) -> Result<u8, &'static str> {
|
||||
// INFO: What the fuck
|
||||
debug!("owo");
|
||||
self.wait_for_read()?;
|
||||
// HERESY: Stop
|
||||
debug!("what's this");
|
||||
Ok(unsafe { self.data_port.read() })
|
||||
}
|
||||
|
||||
fn send_command(&mut self, command: Command) -> Result<(), &'static str> {
|
||||
self.write_command_port(0xD4)?;
|
||||
self.write_data_port(command as u8)?;
|
||||
if self.read_data_port()? != 0xFA {
|
||||
return Err("mouse did not respond to the command");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sign_extend(&self, packet: u8) -> i16 {
|
||||
((packet as u16) | 0xFF00) as i16
|
||||
}
|
||||
|
||||
fn write_command_port(&mut self, value: u8) -> Result<(), &'static str> {
|
||||
debug!("mouse driver: waiting for write");
|
||||
self.wait_for_write()?;
|
||||
unsafe {
|
||||
self.command_port.write(value);
|
||||
}
|
||||
debug!("mouse driver: command written");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_data_port(&mut self, value: u8) -> Result<(), &'static str> {
|
||||
self.wait_for_write()?;
|
||||
unsafe {
|
||||
self.data_port.write(value);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn wait_for_read(&mut self) -> Result<(), &'static str> {
|
||||
let timeout = 100_000;
|
||||
for _x in 0..timeout {
|
||||
let value = unsafe { self.command_port.read() };
|
||||
if (value & 0x1) == 0x1 {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err("wait for mouse read timeout")
|
||||
}
|
||||
|
||||
fn wait_for_write(&mut self) -> Result<(), &'static str> {
|
||||
let timeout = 100_000;
|
||||
for _ in 0..timeout {
|
||||
let value = unsafe { self.command_port.read() };
|
||||
if (value & 0x2) == 0x0 {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err("wait for mouse write timeout")
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn start() {
|
||||
// Simple driver
|
||||
}
|
1
rust-toolchain
Normal file
1
rust-toolchain
Normal file
|
@ -0,0 +1 @@
|
|||
nightly
|
Loading…
Reference in a new issue