cursor_rs/
lib.rs

1//! ## cursor_rs
2//! Getter & Setter cursor position on VGA(0xB8000) in freestanding Rust.
3//!
4//! ## Example
5//! ```rust
6//! #![no_std]
7//! extern crate vgainfo_rs;
8//! use vgainfo_rs::*;
9//! extern crate cursor_rs;
10//! use cursor_rs::*;
11//!
12//! fn reset_screen() {
13//!     let buffer_ptr = LENGTH as *mut VgaCharType;
14//!     let iter = (0..LENGTH).map(|i| unsafe { buffer_ptr.add(i) });
15//!
16//!     for ptr in iter {
17//!         let value = unsafe { ptr.read_volatile() };
18//!         unsafe { ptr.write_volatile(value & 0xff00) };
19//!     }
20//!     VgaCursor::new().set(0,0);
21//! }
22//! ```
23
24#![no_std]
25
26extern crate inout_port_rs;
27extern crate vgainfo_rs;
28
29#[derive(Copy, Clone)]
30#[repr(C, packed)]
31struct __LowHigh {
32    l: u8,
33    h: u8,
34}
35
36#[derive(Copy, Clone)]
37union __Cursor {
38    value: u16,
39    lh: __LowHigh,
40}
41
42fn set_cursor(y: usize, x: usize) {
43    let cursor = __Cursor {
44        value: (y * vgainfo_rs::WIDTH + x) as u16,
45    };
46    unsafe {
47        inout_port_rs::outb(0xe, 0x3d4);
48        inout_port_rs::outb(cursor.lh.h, 0x3d5);
49        inout_port_rs::outb(0xf, 0x3d4);
50        inout_port_rs::outb(cursor.lh.l, 0x3d5);
51    }
52}
53
54fn get_cursor() -> (usize, usize) {
55    let low: u8;
56    let high: u8;
57
58    unsafe {
59        inout_port_rs::outb(0xe, 0x3d4);
60        high = inout_port_rs::inb(0x3d5);
61        inout_port_rs::outb(0xf, 0x3d4);
62        low = inout_port_rs::inb(0x3d5);
63    }
64
65    let cursor = __Cursor {
66        lh: __LowHigh { l: low, h: high },
67    };
68
69    let value = unsafe { cursor.value } as usize;
70    let y = value / vgainfo_rs::WIDTH;
71    let x = value % vgainfo_rs::WIDTH;
72
73    (y, x)
74}
75
76use core::marker::PhantomData;
77
78/// An empty struct for invoking the method.
79pub struct VgaCursor {
80    _phantom: PhantomData<Self>,
81}
82
83impl VgaCursor {
84    /// Create an empty struct for invoking the method.
85    #[inline]
86    pub const fn new() -> Self {
87        Self {
88            _phantom: PhantomData,
89        }
90    }
91}
92
93/// Trait for getter and setter interface
94pub trait VgaCurSorHal {
95    /// Set cursor at (y,x) coordinates
96    fn set(&mut self, y: usize, x: usize);
97    /// Get cursor (y,x) coordinates
98    fn get(&self) -> (usize, usize);
99}
100
101impl VgaCurSorHal for VgaCursor {
102    /// Set cursor at y,x position.
103    /// This method doesn't check range.
104    #[inline]
105    fn set(&mut self, y: usize, x: usize) {
106        set_cursor(y, x);
107    }
108
109    /// Get current cursor position
110    #[inline]
111    fn get(&self) -> (usize, usize) {
112        get_cursor()
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn __cursor_works() {
122        let lh = __LowHigh { l: 1, h: 1 };
123        let cursor = __Cursor { lh: lh };
124        assert_eq!(unsafe { cursor.value }, (1u16 << 8) | (1u16 << 0));
125    }
126
127    #[test]
128    fn __usize_as_u16_works() {
129        let width = vgainfo_rs::WIDTH;
130        let high = vgainfo_rs::HIGH;
131
132        let width_u16 = width as u16;
133        let high_u16 = high as u16;
134
135        assert_eq!((width, high), (width_u16 as usize, high_u16 as usize));
136    }
137}