Add serial init and serial interrupts

This commit is contained in:
Jeremy Soller 2016-09-01 11:10:56 -06:00
parent 722d738254
commit 543ef3d96f
9 changed files with 155 additions and 53 deletions

View file

@ -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;
}
}
}
}
}

View file

@ -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) {

View file

@ -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,
}
}

View 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(())
}
}