diff --git a/src/vga.rs b/src/vga.rs index b07e105..c717f81 100644 --- a/src/vga.rs +++ b/src/vga.rs @@ -170,6 +170,17 @@ impl Vga { self.crtc_controller_registers.read(emulation_mode, index) } + /// Writes `value` to the crtc controller, as determined by `index`. + pub fn write_crtc_controller( + &mut self, + emulation_mode: EmulationMode, + index: CrtcControllerIndex, + value: u8, + ) { + self.crtc_controller_registers + .write(emulation_mode, index, value); + } + /// Returns the current `EmulationMode` as determined by the miscellaneous output register. pub fn get_emulation_mode(&mut self) -> EmulationMode { EmulationMode::from(self.general_registers.read_msr() & 0x1) diff --git a/src/writers/text_40x25.rs b/src/writers/text_40x25.rs index 0cb3421..88781e4 100644 --- a/src/writers/text_40x25.rs +++ b/src/writers/text_40x25.rs @@ -2,6 +2,7 @@ use super::ScreenCharacter; use crate::{ colors::{Color16Bit, TextModeColor, DEFAULT_PALETTE}, fonts::TEXT_8X16_FONT, + registers::CrtcControllerIndex, vga::{Vga, VideoMode, VGA}, }; use spinning_top::SpinlockGuard; @@ -76,6 +77,30 @@ impl Text40x25 { vga.load_font(&TEXT_8X16_FONT); } + /// Sets the current text cursor to the position specified by + /// `x` and `y`. + /// + /// Panics if `x >= 40` or `y >= 25`. + pub fn set_cursor_position(&self, x: usize, y: usize) { + assert!(x < WIDTH, "x >= {}", WIDTH); + assert!(y < HEIGHT, "y >= {}", HEIGHT); + let offset = WIDTH * y + x; + let (mut vga, _frame_buffer) = self.get_frame_buffer(); + let emulation_mode = vga.get_emulation_mode(); + let cursor_start = offset & 0xFF; + let cursor_end = (offset >> 8) & 0xFF; + vga.write_crtc_controller( + emulation_mode, + CrtcControllerIndex::TextCursorLocationLow, + cursor_start as u8, + ); + vga.write_crtc_controller( + emulation_mode, + CrtcControllerIndex::TextCursorLocationHigh, + cursor_end as u8, + ); + } + /// Returns the start of the `FrameBuffer` as `*mut ScreenCharacter` /// as well as a lock to the vga driver. This ensures the vga /// driver stays locked while the frame buffer is in use. diff --git a/src/writers/text_40x50.rs b/src/writers/text_40x50.rs index e08390e..6f62895 100644 --- a/src/writers/text_40x50.rs +++ b/src/writers/text_40x50.rs @@ -2,6 +2,7 @@ use super::ScreenCharacter; use crate::{ colors::{Color16Bit, TextModeColor, DEFAULT_PALETTE}, fonts::TEXT_8X8_FONT, + registers::CrtcControllerIndex, vga::{Vga, VideoMode, VGA}, }; use spinning_top::SpinlockGuard; @@ -76,6 +77,30 @@ impl Text40x50 { vga.load_font(&TEXT_8X8_FONT); } + /// Sets the current text cursor to the position specified by + /// `x` and `y`. + /// + /// Panics if `x >= 40` or `y >= 50`. + pub fn set_cursor_position(&self, x: usize, y: usize) { + assert!(x < WIDTH, "x >= {}", WIDTH); + assert!(y < HEIGHT, "y >= {}", HEIGHT); + let offset = WIDTH * y + x; + let (mut vga, _frame_buffer) = self.get_frame_buffer(); + let emulation_mode = vga.get_emulation_mode(); + let cursor_start = offset & 0xFF; + let cursor_end = (offset >> 8) & 0xFF; + vga.write_crtc_controller( + emulation_mode, + CrtcControllerIndex::TextCursorLocationLow, + cursor_start as u8, + ); + vga.write_crtc_controller( + emulation_mode, + CrtcControllerIndex::TextCursorLocationHigh, + cursor_end as u8, + ); + } + /// Returns the start of the `FrameBuffer` as `*mut ScreenCharacter` /// as well as a lock to the vga driver. This ensures the vga /// driver stays locked while the frame buffer is in use. diff --git a/src/writers/text_80x25.rs b/src/writers/text_80x25.rs index 843e729..63a533d 100644 --- a/src/writers/text_80x25.rs +++ b/src/writers/text_80x25.rs @@ -2,6 +2,7 @@ use super::ScreenCharacter; use crate::{ colors::{Color16Bit, TextModeColor, DEFAULT_PALETTE}, fonts::TEXT_8X16_FONT, + registers::CrtcControllerIndex, vga::{Vga, VideoMode, VGA}, }; use spinning_top::SpinlockGuard; @@ -76,6 +77,30 @@ impl Text80x25 { vga.load_font(&TEXT_8X16_FONT); } + /// Sets the current text cursor to the position specified by + /// `x` and `y`. + /// + /// Panics if `x >= 80` or `y >= 25`. + pub fn set_cursor_position(&self, x: usize, y: usize) { + assert!(x < WIDTH, "x >= {}", WIDTH); + assert!(y < HEIGHT, "y >= {}", HEIGHT); + let offset = WIDTH * y + x; + let (mut vga, _frame_buffer) = self.get_frame_buffer(); + let emulation_mode = vga.get_emulation_mode(); + let cursor_start = offset & 0xFF; + let cursor_end = (offset >> 8) & 0xFF; + vga.write_crtc_controller( + emulation_mode, + CrtcControllerIndex::TextCursorLocationLow, + cursor_start as u8, + ); + vga.write_crtc_controller( + emulation_mode, + CrtcControllerIndex::TextCursorLocationHigh, + cursor_end as u8, + ); + } + /// Returns the start of the `FrameBuffer` as `*mut ScreenCharacter` /// as well as a lock to the vga driver. This ensures the vga /// driver stays locked while the frame buffer is in use.