Add serial init and serial interrupts
This commit is contained in:
parent
722d738254
commit
543ef3d96f
9 changed files with 155 additions and 53 deletions
|
@ -43,6 +43,7 @@ pub struct VBEModeInfo {
|
|||
}
|
||||
|
||||
pub static DISPLAY: Mutex<Option<Display>> = Mutex::new(None);
|
||||
static FONT: &'static [u8] = include_bytes!("../../../../res/unifont.font");
|
||||
|
||||
pub unsafe fn init(active_table: &mut ActivePageTable) {
|
||||
active_table.identity_map(Frame::containing_address(PhysicalAddress::new(0x5200)), entry::PRESENT | entry::NO_EXECUTE);
|
||||
|
@ -108,6 +109,7 @@ impl Display {
|
|||
}
|
||||
}
|
||||
|
||||
/// Draw a rectangle
|
||||
pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) {
|
||||
let start_y = cmp::min(self.height - 1, y);
|
||||
let end_y = cmp::min(self.height, y + h);
|
||||
|
@ -123,4 +125,25 @@ impl Display {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a character
|
||||
pub fn char(&mut self, x: usize, y: usize, character: char, color: u32) {
|
||||
if x + 8 <= self.width && y + 16 <= self.height {
|
||||
let mut offset = y * self.width + x;
|
||||
|
||||
let font_i = 16 * (character as usize);
|
||||
if font_i + 16 <= FONT.len() {
|
||||
for row in 0..16 {
|
||||
let row_data = FONT[font_i + row];
|
||||
for col in 0..8 {
|
||||
if (row_data >> (7 - col)) & 1 == 1 {
|
||||
self.data[offset + col] = color;
|
||||
}
|
||||
}
|
||||
|
||||
offset += self.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@ use paging::ActivePageTable;
|
|||
|
||||
pub mod display;
|
||||
pub mod ps2;
|
||||
pub mod serial;
|
||||
|
||||
pub unsafe fn init(active_table: &mut ActivePageTable){
|
||||
display::init(active_table);
|
||||
serial::init();
|
||||
ps2::init();
|
||||
display::init(active_table);
|
||||
}
|
||||
|
||||
pub unsafe fn init_ap(active_table: &mut ActivePageTable) {
|
||||
|
|
|
@ -15,6 +15,10 @@ bitflags! {
|
|||
const INPUT_FULL = 1 << 1,
|
||||
const SYSTEM = 1 << 2,
|
||||
const COMMAND = 1 << 3,
|
||||
// Chipset specific
|
||||
const KEYBOARD_LOCK = 1 << 4,
|
||||
// Chipset specific
|
||||
const SECOND_OUTPUT_FULL = 1 << 5,
|
||||
const TIME_OUT = 1 << 6,
|
||||
const PARITY = 1 << 7
|
||||
}
|
||||
|
@ -26,10 +30,12 @@ bitflags! {
|
|||
const SECOND_INTERRUPT = 1 << 1,
|
||||
const POST_PASSED = 1 << 2,
|
||||
// 1 << 3 should be zero
|
||||
const CONFIG_RESERVED_3 = 1 << 3,
|
||||
const FIRST_DISABLED = 1 << 4,
|
||||
const SECOND_DISABLED = 1 << 5,
|
||||
const FIRST_TRANSLATE = 1 << 6,
|
||||
// 1 << 7 should be zero
|
||||
const CONFIG_RESERVED_7 = 1 << 7,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
118
arch/x86_64/src/device/serial.rs
Normal file
118
arch/x86_64/src/device/serial.rs
Normal file
|
@ -0,0 +1,118 @@
|
|||
use core::fmt::{self, Write};
|
||||
use spin::Mutex;
|
||||
|
||||
use io::{Io, Pio, ReadOnly};
|
||||
|
||||
pub static COM1: Mutex<SerialPort> = Mutex::new(SerialPort::new(0x3F8));
|
||||
pub static COM2: Mutex<SerialPort> = Mutex::new(SerialPort::new(0x2F8));
|
||||
|
||||
pub unsafe fn init() {
|
||||
COM1.lock().init();
|
||||
COM2.lock().init();
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Interrupt enable flags
|
||||
flags IntEnFlags: u8 {
|
||||
const RECEIVED = 1,
|
||||
const SENT = 1 << 1,
|
||||
const ERRORED = 1 << 2,
|
||||
const STATUS_CHANGE = 1 << 3,
|
||||
// 4 to 7 are unused
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Line status flags
|
||||
flags LineStsFlags: u8 {
|
||||
const INPUT_FULL = 1,
|
||||
// 1 to 4 unknown
|
||||
const OUTPUT_EMPTY = 1 << 5,
|
||||
// 6 and 7 unknown
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SerialPort {
|
||||
/// Data register, read to receive, write to send
|
||||
data: Pio<u8>,
|
||||
/// Interrupt enable
|
||||
int_en: Pio<u8>,
|
||||
/// FIFO control
|
||||
fifo_ctrl: Pio<u8>,
|
||||
/// Line control
|
||||
line_ctrl: Pio<u8>,
|
||||
/// Modem control
|
||||
modem_ctrl: Pio<u8>,
|
||||
/// Line status
|
||||
line_sts: ReadOnly<Pio<u8>>,
|
||||
/// Modem status
|
||||
modem_sts: ReadOnly<Pio<u8>>,
|
||||
}
|
||||
|
||||
impl SerialPort {
|
||||
const fn new(base: u16) -> SerialPort {
|
||||
SerialPort {
|
||||
data: Pio::new(base),
|
||||
int_en: Pio::new(base + 1),
|
||||
fifo_ctrl: Pio::new(base + 2),
|
||||
line_ctrl: Pio::new(base + 3),
|
||||
modem_ctrl: Pio::new(base + 4),
|
||||
line_sts: ReadOnly::new(Pio::new(base + 5)),
|
||||
modem_sts: ReadOnly::new(Pio::new(base + 6))
|
||||
}
|
||||
}
|
||||
|
||||
fn int_en(&self) -> IntEnFlags {
|
||||
IntEnFlags::from_bits_truncate(self.int_en.read())
|
||||
}
|
||||
|
||||
fn line_sts(&self) -> LineStsFlags {
|
||||
LineStsFlags::from_bits_truncate(self.line_sts.read())
|
||||
}
|
||||
|
||||
fn write(&mut self, data: u8) {
|
||||
while ! self.line_sts().contains(OUTPUT_EMPTY) {}
|
||||
self.data.write(data)
|
||||
}
|
||||
|
||||
fn init(&mut self) {
|
||||
self.int_en.write(0x00);
|
||||
self.line_ctrl.write(0x80);
|
||||
self.data.write(0x03);
|
||||
self.int_en.write(0x00);
|
||||
self.line_ctrl.write(0x03);
|
||||
self.fifo_ctrl.write(0xC7);
|
||||
self.modem_ctrl.write(0x0B);
|
||||
self.int_en.write(0x01);
|
||||
}
|
||||
|
||||
pub fn on_receive(&mut self) {
|
||||
let data = self.data.read();
|
||||
write!(self, "SERIAL {:X}\n", data);
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for SerialPort {
|
||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||
for byte in s.bytes() {
|
||||
self.write(byte);
|
||||
|
||||
if byte == 8 {
|
||||
self.write(b' ');
|
||||
self.write(8);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SerialConsole;
|
||||
|
||||
impl Write for SerialConsole {
|
||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||
COM1.lock().write_str(s);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue