mirror of
https://github.com/ZeroOSProject/ZeroOS.git
synced 2026-09-13 00:24:41 +08:00
329 lines
7.3 KiB
Rust
329 lines
7.3 KiB
Rust
use crate::drivers::platform::pic;
|
|
use crate::io::{disable_interrupts, enable_interrupts, inb};
|
|
|
|
const DATA_PORT: u16 = 0x60;
|
|
const STATUS_PORT: u16 = 0x64;
|
|
const OUTPUT_FULL: u8 = 1 << 0;
|
|
const BUFFER_SIZE: usize = 256;
|
|
|
|
static mut KEYBOARD: Ps2Keyboard = Ps2Keyboard::new();
|
|
|
|
pub struct Ps2Keyboard {
|
|
buffer: [u8; BUFFER_SIZE],
|
|
read_index: usize,
|
|
write_index: usize,
|
|
shift: bool,
|
|
extended: bool,
|
|
}
|
|
|
|
impl Ps2Keyboard {
|
|
const fn new() -> Self {
|
|
Self {
|
|
buffer: [0; BUFFER_SIZE],
|
|
read_index: 0,
|
|
write_index: 0,
|
|
shift: false,
|
|
extended: false,
|
|
}
|
|
}
|
|
|
|
fn push(&mut self, byte: u8) {
|
|
let next = (self.write_index + 1) % BUFFER_SIZE;
|
|
if next != self.read_index {
|
|
self.buffer[self.write_index] = byte;
|
|
self.write_index = next;
|
|
}
|
|
}
|
|
|
|
fn pop(&mut self) -> Option<u8> {
|
|
if self.read_index == self.write_index {
|
|
return None;
|
|
}
|
|
|
|
let byte = self.buffer[self.read_index];
|
|
self.read_index = (self.read_index + 1) % BUFFER_SIZE;
|
|
Some(byte)
|
|
}
|
|
|
|
fn handle_scancode(&mut self, scancode: u8) {
|
|
if scancode == 0xe0 {
|
|
self.extended = true;
|
|
return;
|
|
}
|
|
|
|
if self.extended {
|
|
self.extended = false;
|
|
if scancode & 0x80 != 0 {
|
|
return;
|
|
}
|
|
match scancode {
|
|
0x48 => self.push_escape_sequence(b"\x1b[A"),
|
|
0x50 => self.push_escape_sequence(b"\x1b[B"),
|
|
0x4b => self.push_escape_sequence(b"\x1b[D"),
|
|
0x4d => self.push_escape_sequence(b"\x1b[C"),
|
|
0x47 => self.push_escape_sequence(b"\x1b[H"),
|
|
0x4f => self.push_escape_sequence(b"\x1b[F"),
|
|
0x53 => self.push_escape_sequence(b"\x1b[3~"),
|
|
_ => {}
|
|
}
|
|
return;
|
|
}
|
|
|
|
let released = scancode & 0x80 != 0;
|
|
let code = scancode & 0x7f;
|
|
|
|
match code {
|
|
0x2a | 0x36 => {
|
|
self.shift = !released;
|
|
return;
|
|
}
|
|
_ if released => return,
|
|
_ => {}
|
|
}
|
|
|
|
if let Some(ascii) = scancode_set1_to_ascii(code, self.shift) {
|
|
self.push(ascii);
|
|
}
|
|
}
|
|
|
|
fn push_escape_sequence(&mut self, bytes: &[u8]) {
|
|
for byte in bytes {
|
|
self.push(*byte);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub unsafe fn init() {
|
|
unsafe {
|
|
drain_output_buffer();
|
|
pic::unmask_irq(pic::KEYBOARD_IRQ);
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub extern "C" fn zeroos_ps2_keyboard_interrupt() {
|
|
unsafe {
|
|
if inb(STATUS_PORT) & OUTPUT_FULL != 0 {
|
|
let scancode = inb(DATA_PORT);
|
|
(*(&raw mut KEYBOARD)).handle_scancode(scancode);
|
|
}
|
|
|
|
pic::end_of_interrupt(pic::KEYBOARD_IRQ);
|
|
}
|
|
}
|
|
|
|
pub fn read_char() -> Option<u8> {
|
|
disable_interrupts();
|
|
let ch = unsafe { (*(&raw mut KEYBOARD)).pop() };
|
|
enable_interrupts();
|
|
ch
|
|
}
|
|
|
|
pub fn has_char() -> bool {
|
|
disable_interrupts();
|
|
let ready = unsafe {
|
|
let keyboard = &*(&raw const KEYBOARD);
|
|
keyboard.read_index != keyboard.write_index
|
|
};
|
|
enable_interrupts();
|
|
ready
|
|
}
|
|
|
|
unsafe fn drain_output_buffer() {
|
|
unsafe {
|
|
while inb(STATUS_PORT) & OUTPUT_FULL != 0 {
|
|
let _ = inb(DATA_PORT);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn scancode_set1_to_ascii(code: u8, shift: bool) -> Option<u8> {
|
|
let byte = match code {
|
|
0x01 => 0x1b,
|
|
0x02 => {
|
|
if shift {
|
|
b'!'
|
|
} else {
|
|
b'1'
|
|
}
|
|
}
|
|
0x03 => {
|
|
if shift {
|
|
b'@'
|
|
} else {
|
|
b'2'
|
|
}
|
|
}
|
|
0x04 => {
|
|
if shift {
|
|
b'#'
|
|
} else {
|
|
b'3'
|
|
}
|
|
}
|
|
0x05 => {
|
|
if shift {
|
|
b'$'
|
|
} else {
|
|
b'4'
|
|
}
|
|
}
|
|
0x06 => {
|
|
if shift {
|
|
b'%'
|
|
} else {
|
|
b'5'
|
|
}
|
|
}
|
|
0x07 => {
|
|
if shift {
|
|
b'^'
|
|
} else {
|
|
b'6'
|
|
}
|
|
}
|
|
0x08 => {
|
|
if shift {
|
|
b'&'
|
|
} else {
|
|
b'7'
|
|
}
|
|
}
|
|
0x09 => {
|
|
if shift {
|
|
b'*'
|
|
} else {
|
|
b'8'
|
|
}
|
|
}
|
|
0x0a => {
|
|
if shift {
|
|
b'('
|
|
} else {
|
|
b'9'
|
|
}
|
|
}
|
|
0x0b => {
|
|
if shift {
|
|
b')'
|
|
} else {
|
|
b'0'
|
|
}
|
|
}
|
|
0x0c => {
|
|
if shift {
|
|
b'_'
|
|
} else {
|
|
b'-'
|
|
}
|
|
}
|
|
0x0d => {
|
|
if shift {
|
|
b'+'
|
|
} else {
|
|
b'='
|
|
}
|
|
}
|
|
0x0e => 0x08,
|
|
0x0f => b'\t',
|
|
0x10 => letter(b'q', shift),
|
|
0x11 => letter(b'w', shift),
|
|
0x12 => letter(b'e', shift),
|
|
0x13 => letter(b'r', shift),
|
|
0x14 => letter(b't', shift),
|
|
0x15 => letter(b'y', shift),
|
|
0x16 => letter(b'u', shift),
|
|
0x17 => letter(b'i', shift),
|
|
0x18 => letter(b'o', shift),
|
|
0x19 => letter(b'p', shift),
|
|
0x1a => {
|
|
if shift {
|
|
b'{'
|
|
} else {
|
|
b'['
|
|
}
|
|
}
|
|
0x1b => {
|
|
if shift {
|
|
b'}'
|
|
} else {
|
|
b']'
|
|
}
|
|
}
|
|
0x1c => b'\r',
|
|
0x1e => letter(b'a', shift),
|
|
0x1f => letter(b's', shift),
|
|
0x20 => letter(b'd', shift),
|
|
0x21 => letter(b'f', shift),
|
|
0x22 => letter(b'g', shift),
|
|
0x23 => letter(b'h', shift),
|
|
0x24 => letter(b'j', shift),
|
|
0x25 => letter(b'k', shift),
|
|
0x26 => letter(b'l', shift),
|
|
0x27 => {
|
|
if shift {
|
|
b':'
|
|
} else {
|
|
b';'
|
|
}
|
|
}
|
|
0x28 => {
|
|
if shift {
|
|
b'"'
|
|
} else {
|
|
b'\''
|
|
}
|
|
}
|
|
0x29 => {
|
|
if shift {
|
|
b'~'
|
|
} else {
|
|
b'`'
|
|
}
|
|
}
|
|
0x2b => {
|
|
if shift {
|
|
b'|'
|
|
} else {
|
|
b'\\'
|
|
}
|
|
}
|
|
0x2c => letter(b'z', shift),
|
|
0x2d => letter(b'x', shift),
|
|
0x2e => letter(b'c', shift),
|
|
0x2f => letter(b'v', shift),
|
|
0x30 => letter(b'b', shift),
|
|
0x31 => letter(b'n', shift),
|
|
0x32 => letter(b'm', shift),
|
|
0x33 => {
|
|
if shift {
|
|
b'<'
|
|
} else {
|
|
b','
|
|
}
|
|
}
|
|
0x34 => {
|
|
if shift {
|
|
b'>'
|
|
} else {
|
|
b'.'
|
|
}
|
|
}
|
|
0x35 => {
|
|
if shift {
|
|
b'?'
|
|
} else {
|
|
b'/'
|
|
}
|
|
}
|
|
0x39 => b' ',
|
|
_ => return None,
|
|
};
|
|
|
|
Some(byte)
|
|
}
|
|
|
|
const fn letter(lower: u8, shift: bool) -> u8 {
|
|
if shift { lower - 32 } else { lower }
|
|
}
|