Skip to content

Commit

Permalink
Support booting without keyboard
Browse files Browse the repository at this point in the history
  • Loading branch information
fruhland committed Mar 12, 2024
1 parent 1621ad7 commit ee68407
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 27 deletions.
50 changes: 26 additions & 24 deletions os/kernel/src/device/ps2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use nolock::queues::mpmc::bounded::scq::{Receiver, Sender};
use nolock::queues::{mpmc, DequeueError};
use ps2::flags::{ControllerConfigFlags, KeyboardLedFlags};
use ps2::{Controller, KeyboardType};
use ps2::error::{ControllerError, KeyboardError};
use spin::Mutex;
use crate::{apic, interrupt_dispatcher, ps2_devices};

Expand Down Expand Up @@ -74,75 +75,76 @@ impl PS2 {
}
}

pub fn init_controller(&self) {
pub fn init_controller(&self) -> Result<(), ControllerError> {
info!("Initializing controller");
let mut controller = self.controller.lock();

// Disable ports
controller.disable_keyboard().expect("Failed to disable first port");
controller.disable_mouse().expect("Failed to disable second port");
controller.disable_keyboard()?;
controller.disable_mouse()?;

// Flush output buffer
let _ = controller.read_data();

// Disable interrupts and translation
let mut config = controller.read_config().expect("Failed to read config");
let mut config = controller.read_config()?;
config.set(ControllerConfigFlags::ENABLE_KEYBOARD_INTERRUPT | ControllerConfigFlags::ENABLE_MOUSE_INTERRUPT | ControllerConfigFlags::ENABLE_TRANSLATE, false);
controller.write_config(config).expect("Failed to write config");
controller.write_config(config)?;

// Perform self test on controller
controller.test_controller().expect("Self test failed");
controller.test_controller()?;
info!("Self test result is OK");

// Check if the controller has reset itself during the self test and if so, write the configuration byte again
if controller.read_config().expect("Failed to read config") != config {
controller.write_config(config).expect("Failed to write config");
if controller.read_config()? != config {
controller.write_config(config)?;
}

// Check if keyboard is present
if controller.test_keyboard().is_ok() {
let test_result = controller.test_keyboard();
if test_result.is_ok() {
// Enable keyboard
info!("First port detected");
controller.enable_keyboard().expect("Failed to enable first port");
controller.enable_keyboard()?;
config.set(ControllerConfigFlags::DISABLE_KEYBOARD, false);
config.set(ControllerConfigFlags::ENABLE_KEYBOARD_INTERRUPT, true);
controller.write_config(config).expect("Failed to write config");
controller.write_config(config)?;
info!("First port enabled");
} else {
panic!("No keyboard detected!");
}

return test_result;
}

pub fn init_keyboard(&mut self) {
pub fn init_keyboard(&mut self) -> Result<(), KeyboardError> {
info!("Initializing keyboard");
let mut controller = self.controller.lock();

// Perform self test on keyboard
controller.keyboard().reset_and_self_test().expect("Keyboard self test failed");
controller.keyboard().reset_and_self_test()?;
info!("Keyboard has been reset and self test result is OK");

// Enable keyboard translation if needed
controller.keyboard().disable_scanning().expect("Failed to disable scanning");
let kb_type = controller.keyboard().get_keyboard_type().expect("Failed to query keyboard type");
controller.keyboard().disable_scanning()?;
let kb_type = controller.keyboard().get_keyboard_type()?;
info!("Detected keyboard type [{:?}]", kb_type);

match kb_type {
KeyboardType::ATWithTranslation | KeyboardType::MF2WithTranslation | KeyboardType::ThinkPadWithTranslation => {
info!("Enabling keyboard translation");
let mut config = controller.read_config().expect("Failed to read config");
let mut config = controller.read_config()?;
config.set(ControllerConfigFlags::ENABLE_TRANSLATE, true);
controller.write_config(config).expect("Failed to write config");
controller.write_config(config)?;
}
_ => info!("Keyboard does not need translation"),
}

// Setup keyboard
info!("Enabling keyboard");
controller.keyboard().set_defaults().expect("Failed to set default keyboard configuration");
controller.keyboard().set_scancode_set(1).expect("Failed to set scancode set");
controller.keyboard().set_typematic_rate_and_delay(0).expect("Failed to set typematic rate");
controller.keyboard().set_leds(KeyboardLedFlags::empty()).expect("Failed to set LEDs");
controller.keyboard().enable_scanning().expect("Failed to enable scanning");
controller.keyboard().set_defaults()?;
controller.keyboard().set_scancode_set(1)?;
controller.keyboard().set_typematic_rate_and_delay(0)?;
controller.keyboard().set_leds(KeyboardLedFlags::empty())?;
controller.keyboard().enable_scanning()
}

pub fn keyboard(&self) -> &Keyboard {
Expand Down
13 changes: 10 additions & 3 deletions os/kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::process::thread::Thread;
use alloc::boxed::Box;
use core::fmt::Arguments;
use core::panic::PanicInfo;
use ::log::{Level, Log, Record};
use ::log::{error, Level, Log, Record};
use acpi::AcpiTables;
use multiboot2::ModuleTag;
use spin::{Mutex, Once, RwLock};
Expand Down Expand Up @@ -168,8 +168,15 @@ pub fn init_terminal(buffer: *mut u8, pitch: u32, width: u32, height: u32, bpp:
pub fn init_keyboard() {
PS2.call_once(|| {
let mut ps2 = PS2::new();
ps2.init_controller();
ps2.init_keyboard();
match ps2.init_controller() {
Ok(_) => {
match ps2.init_keyboard() {
Ok(_) => {}
Err(error) => error!("Keyboard initialization failed: {:?}", error)
}
}
Err(error) => error!("PS/2 controller initialization failed: {:?}", error)
}

return ps2;
});
Expand Down

0 comments on commit ee68407

Please sign in to comment.