diff --git a/src/dev/virtio/input.rs b/src/dev/virtio/input.rs index fe06bc0..afdea47 100644 --- a/src/dev/virtio/input.rs +++ b/src/dev/virtio/input.rs @@ -1,4 +1,11 @@ -use crate::dev::virtio::{Descriptor, VirtQueue, VIRTIO_DESC_F_WRITE, VIRTIO_MMIO_GUEST_FEATURES, VIRTIO_MMIO_GUEST_PAGE_SIZE, VIRTIO_MMIO_QUEUE_NUM, VIRTIO_MMIO_QUEUE_NUM_MAX, VIRTIO_MMIO_QUEUE_PFN, VIRTIO_MMIO_QUEUE_SEL, VIRTIO_MMIO_STATUS, VIRTIO_MMIO_STATUS_ACKNOWLEDGE, VIRTIO_MMIO_STATUS_DRIVER, VIRTIO_MMIO_STATUS_DRIVER_OK, VIRTIO_MMIO_STATUS_FAILED, VIRTIO_MMIO_STATUS_FEATURES_OK, VIRTIO_QUEUE_SIZE}; +use core::sync::atomic::{AtomicBool, Ordering}; +use crate::dev::virtio::{ + Descriptor, VIRTIO_DESC_F_WRITE, VIRTIO_MMIO_GUEST_FEATURES, VIRTIO_MMIO_GUEST_PAGE_SIZE, + VIRTIO_MMIO_QUEUE_NUM, VIRTIO_MMIO_QUEUE_NUM_MAX, VIRTIO_MMIO_QUEUE_PFN, VIRTIO_MMIO_QUEUE_SEL, + VIRTIO_MMIO_STATUS, VIRTIO_MMIO_STATUS_ACKNOWLEDGE, VIRTIO_MMIO_STATUS_DRIVER, + VIRTIO_MMIO_STATUS_DRIVER_OK, VIRTIO_MMIO_STATUS_FAILED, VIRTIO_MMIO_STATUS_FEATURES_OK, + VIRTIO_QUEUE_SIZE, VirtQueue, +}; use crate::trafficcontrol::TrafficControl; unsafe extern "C" { @@ -74,7 +81,7 @@ impl VirtIoInputDevice { // setup event queue let queue_max_by_device = - unsafe { ((addr + VIRTIO_MMIO_QUEUE_NUM_MAX) as *const u32).read_volatile() }; + unsafe { ((addr + VIRTIO_MMIO_QUEUE_NUM_MAX) as *const u32).read_volatile() }; if queue_max_by_device < VIRTIO_QUEUE_SIZE as _ { unsafe { ((addr + VIRTIO_MMIO_STATUS) as *mut u32).write_volatile(VIRTIO_MMIO_STATUS_FAILED); @@ -95,12 +102,11 @@ impl VirtIoInputDevice { } } unsafe { - ((addr + VIRTIO_MMIO_GUEST_PAGE_SIZE) as *mut u32).write_volatile( - 4096 - ); + ((addr + VIRTIO_MMIO_GUEST_PAGE_SIZE) as *mut u32).write_volatile(4096); } unsafe { - ((addr + VIRTIO_MMIO_QUEUE_PFN) as *mut u32).write_volatile(event_queue_ptr as u32 / 4096); + ((addr + VIRTIO_MMIO_QUEUE_PFN) as *mut u32) + .write_volatile(event_queue_ptr as u32 / 4096); } // setup status queue @@ -115,12 +121,11 @@ impl VirtIoInputDevice { } } unsafe { - ((addr + VIRTIO_MMIO_GUEST_PAGE_SIZE) as *mut u32).write_volatile( - 4096 - ); + ((addr + VIRTIO_MMIO_GUEST_PAGE_SIZE) as *mut u32).write_volatile(4096); } unsafe { - ((addr + VIRTIO_MMIO_QUEUE_PFN) as *mut u32).write_volatile(status_queue_ptr as u32 / 4096); + ((addr + VIRTIO_MMIO_QUEUE_PFN) as *mut u32) + .write_volatile(status_queue_ptr as u32 / 4096); } // all done! @@ -130,7 +135,10 @@ impl VirtIoInputDevice { } let event_buffer_ptr = unsafe { - tc.memory_manager.as_mut().unwrap_unchecked().alloc_n_blocks((size_of::() * VIRTIO_INPUT_EVENTBUFFER_SIZE).div_ceil(512)) + tc.memory_manager + .as_mut() + .unwrap_unchecked() + .alloc_n_blocks((size_of::() * VIRTIO_INPUT_EVENTBUFFER_SIZE).div_ceil(512)) }; let mut input = VirtIoInputDevice { @@ -147,7 +155,6 @@ impl VirtIoInputDevice { input.fill_event(i); } - Ok(input) } @@ -178,25 +185,44 @@ impl VirtIoInputDevice { match event.event_type { x if x == VIRTIO_INPUT_EVENT_TYPE_KEYBOARD => { - // todo: handle key events - { - let uart = crate::arch::serial_port(); - if let Some(uart) = uart { - uart.putstr("keybd "); - uart.put_bytes(&crate::strprint::u32_hex(event.code as u32)); - uart.putstr("\n"); + let keycode = event.code; + let down = event.value == 1; + + // first, handle shift todo: handle more control characters + if keycode == LinuxKeycode::LeftShift as u16 || keycode == LinuxKeycode::RightShift as u16 { + UPPERCASE.store(down, Ordering::Relaxed); + } + + // next, handle ascii characters + if !down { // write on UP + let ascii = KEYMAP_ASCII.iter().find_map(|(a, b)| { + if keycode == *a as u16 { + Some(*b) + } else { + None + } + }); + if let Some(mut ascii) = ascii { + if UPPERCASE.load(Ordering::Relaxed) { + if ascii.is_ascii_alphabetic() { + ascii = ascii.to_ascii_uppercase(); + } else { + // todo: handle other characters + } + } + tc.write_inbuf(ascii); } } } - _ => { - } + _ => {} } } // status queue let queue = unsafe { &(*(self.status_queue as *mut VirtQueue)) }; while self.status_queue_ack_used_idx != queue.used.idx { - let elem = &queue.used.ring[self.status_queue_ack_used_idx as usize % VIRTIO_QUEUE_SIZE]; + let elem = + &queue.used.ring[self.status_queue_ack_used_idx as usize % VIRTIO_QUEUE_SIZE]; let desc = &queue.desc[elem.id as usize]; let event = unsafe { &*(desc.addr as *const Event) }; self.status_queue_ack_used_idx = self.status_queue_ack_used_idx.wrapping_add(1); @@ -204,9 +230,11 @@ impl VirtIoInputDevice { } } +static UPPERCASE: AtomicBool = AtomicBool::new(false); // linux keycodes -#[repr(u32)] +#[repr(u16)] +#[derive(Copy, Clone)] pub enum LinuxKeycode { ESC = 1, Key1 = 2, @@ -291,4 +319,62 @@ pub enum LinuxKeycode { KP3 = 81, KP0 = 82, KPDot = 83, -} \ No newline at end of file +} + +// keys that do not map directly are handled outside of this +const KEYMAP_ASCII: &[(LinuxKeycode, u8)] = &[ + (LinuxKeycode::ESC, 0x1B), + (LinuxKeycode::Key1, b'1'), + (LinuxKeycode::Key2, b'2'), + (LinuxKeycode::Key3, b'3'), + (LinuxKeycode::Key4, b'4'), + (LinuxKeycode::Key5, b'5'), + (LinuxKeycode::Key6, b'6'), + (LinuxKeycode::Key7, b'7'), + (LinuxKeycode::Key8, b'8'), + (LinuxKeycode::Key9, b'9'), + (LinuxKeycode::Key0, b'0'), + (LinuxKeycode::Minus, b'-'), + (LinuxKeycode::Equal, b'='), + (LinuxKeycode::Backspace, 0x7F), + (LinuxKeycode::Tab, 0x9), + (LinuxKeycode::Q, b'q'), + (LinuxKeycode::W, b'w'), + (LinuxKeycode::E, b'e'), + (LinuxKeycode::R, b'r'), + (LinuxKeycode::T, b't'), + (LinuxKeycode::Y, b'y'), + (LinuxKeycode::U, b'u'), + (LinuxKeycode::I, b'i'), + (LinuxKeycode::O, b'o'), + (LinuxKeycode::P, b'p'), + (LinuxKeycode::LeftBracket, b'['), + (LinuxKeycode::RightBracket, b']'), + (LinuxKeycode::Enter, b'\r'), + (LinuxKeycode::A, b'a'), + (LinuxKeycode::S, b's'), + (LinuxKeycode::D, b'd'), + (LinuxKeycode::F, b'f'), + (LinuxKeycode::G, b'g'), + (LinuxKeycode::H, b'h'), + (LinuxKeycode::J, b'j'), + (LinuxKeycode::K, b'k'), + (LinuxKeycode::L, b'l'), + (LinuxKeycode::Semicolon, b';'), + (LinuxKeycode::Apostrophe, b'\''), + (LinuxKeycode::Grave, b'`'), + (LinuxKeycode::LeftShift, b'/'), + (LinuxKeycode::Backslash, b'\\'), + (LinuxKeycode::Z, b'z'), + (LinuxKeycode::X, b'x'), + (LinuxKeycode::C, b'c'), + (LinuxKeycode::V, b'v'), + (LinuxKeycode::B, b'b'), + (LinuxKeycode::N, b'n'), + (LinuxKeycode::M, b'm'), + (LinuxKeycode::Comma, b','), + (LinuxKeycode::Dot, b'.'), + (LinuxKeycode::Slash, b'/'), + (LinuxKeycode::KPAsterisk, b'*'), + (LinuxKeycode::Space, b' '), +];