os_essentials 0.0.3

A collection of tools for building simple educational operating systems in Rust in an x86 system. NOTE: MEANT TO BE BAREMETAL, YOU MUST HAVE compiler-buildtins-mem, core, compiler_builtins, alloc and a suited target, a vm or physical computer and a bootable usb required to test.
Documentation
//! # PS/2 Keyboard Driver Module
//!
//! This module provides the necessary functionality to initialize and interact with a PS/2 keyboard
//! in a low-level environment. It includes functions to initialize the keyboard, read scan codes from
//! the keyboard, and send commands to the PS/2 controller.

use x86_64::instructions::port::Port;

// Define the ports for the PS/2 controller communication
const PS2_DATA_PORT: u16 = 0x60;
const PS2_COMMAND_PORT: u16 = 0x64;

// PS/2 commands to enable or disable the keyboard
const PS2_CMD_DISABLE_KEYBOARD: u8 = 0xAD;
const PS2_CMD_ENABLE_KEYBOARD: u8 = 0xAE;

/// Writes a byte value to a specified port.
///
/// # Arguments
///
/// * `port` - The port address to which the byte will be written.
/// * `value` - The byte value to be written to the specified port.
///
/// # Safety
///
/// This function uses unsafe code to interact directly with hardware ports. The caller should
/// ensure that the correct port is being accessed and the value being written is valid.
fn outb(port: u16, value: u8) {
    let mut port = Port::new(port);
    unsafe {
        port.write(value);
    }
}

/// Reads a byte value from a specified port.
///
/// # Arguments
///
/// * `port` - The port address from which the byte will be read.
///
/// # Returns
///
/// Returns the byte value read from the specified port.
///
/// # Safety
///
/// This function uses unsafe code to interact directly with hardware ports. The caller should
/// ensure that the correct port is being accessed.
fn inb(port: u16) -> u8 {
    let mut port = Port::new(port);
    unsafe {
        port.read()
    }
}

/// Initializes the PS/2 keyboard by disabling it, waiting for the controller to be ready,
/// then enabling it again to start receiving input.
///
/// This function ensures that the keyboard is ready to send scan codes by communicating
/// with the PS/2 controller over the PS/2 command port.
///
/// # Example
///
/// ```rust
/// ps2_keyboard::init_ps2();
/// ```
///
/// # Safety
///
/// This function involves direct hardware interaction, so it should only be called
/// after proper initialization of the system hardware and the I/O ports.
pub fn init_ps2() {
    // Disable the keyboard
    outb(PS2_COMMAND_PORT, PS2_CMD_DISABLE_KEYBOARD);

    // Wait for the controller to be ready
    while inb(PS2_COMMAND_PORT) & 0x02 != 0 {}

    // Enable the keyboard
    outb(PS2_COMMAND_PORT, PS2_CMD_ENABLE_KEYBOARD);

    // Wait for the controller to be ready
    while inb(PS2_COMMAND_PORT) & 0x02 != 0 {}
}

/// Reads a scan code from the PS/2 keyboard.
///
/// This function reads a single byte from the PS/2 data port. The byte represents a scan code
/// sent by the keyboard to the PS/2 controller. It is typically used to detect key presses.
///
/// # Returns
///
/// Returns the scan code (a `u8` value) corresponding to a key press or release.
/// 
/// If a key is pressed, its scan code will be returned. If a key is released, the scan code 
/// of the released key will be returned.
///
/// # Example
///
/// ```rust
/// let scan_code = ps2_keyboard::read_scan_code();
/// println!("Read scan code: {}", scan_code);
/// ```
///
/// # Safety
///
/// This function interacts with hardware directly and should be used in a properly initialized system.
pub fn read_scan_code() -> u8 {
    inb(PS2_DATA_PORT)
}