Fix UART controller for malta, now input works!

Signed-off-by: Harry Chen <i@harrychen.xyz>
master
Harry Chen 6 years ago
parent ecdbc9fd7a
commit 706f7e4e9a

@ -2,7 +2,7 @@ use once::*;
use alloc::string::String;
use mips::registers::cp0;
#[path = "../../../../drivers/serial/16550_reg.rs"]
#[path = "../../../../drivers/serial/ti_16c550c.rs"]
pub mod serial;
#[path = "../../../../drivers/gpu/fb.rs"]
pub mod fb;

@ -132,13 +132,15 @@ fn syscall(tf: &mut TrapFrame) {
let arguments = [tf.a0, tf.a1, tf.a2, tf.a3, tf.t0, tf.t1];
trace!("MIPS syscall {} invoked with {:?}", tf.v0, arguments);
let ret = crate::syscall::syscall(tf.v0, arguments, tf);
let ret = tf.v0 as isize;
let ret = crate::syscall::syscall(tf.v0, arguments, tf) as isize;
// comply with mips n32 abi, always return a positive value
// https://git.musl-libc.org/cgit/musl/tree/arch/mipsn32/syscall_arch.h
if (ret < 0) {
tf.v0 = (-ret) as usize;
tf.a3 = 1;
} else {
tf.v0 = ret as usize;
tf.a3 = 0;
}
}

@ -0,0 +1,110 @@
//! TI 16c550c serial adapter driver for malta board
#![allow(dead_code)]
use core::fmt::{Write, Result, Arguments};
use core::ptr::{read_volatile, write_volatile};
use spin::Mutex;
pub struct SerialPort {
base: usize
}
impl SerialPort {
fn new() -> SerialPort {
SerialPort {
base: 0
}
}
pub fn init(&mut self, base: usize) {
self.base = base;
// Turn off the FIFO
// write(self.base + COM_FCR, 0 as u8);
// Set speed; requires DLAB latch
// write(self.base + COM_LCR, COM_LCR_DLAB);
// write(self.base + COM_DLL, (115200 / 9600) as u8);
// write(self.base + COM_DLM, 0 as u8);
// 8 data bits, 1 stop bit, parity off; turn off DLAB latch
// write(self.base + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB);
// No modem controls
// write(self.base + COM_MCR, 0 as u8);
// Enable rcv interrupts
write(self.base + COM_INT_EN, 0x1);
}
/// non-blocking version of putchar()
pub fn putchar(&mut self, c: u8) {
write(self.base + COM_TX, c);
}
/// blocking version of getchar()
pub fn getchar(&mut self) -> char {
loop {
if (read::<u8>(self.base + COM_LSR) & 0x01) == 0 {
break;
}
}
let c = read::<u8>(self.base + COM_RX);
match c {
255 => '\0', // null
c => c as char,
}
}
/// non-blocking version of getchar()
pub fn getchar_option(&mut self) -> Option<char> {
match read::<u8>(self.base + COM_LSR) & 0x01 {
0 => None,
_ => Some(read::<u8>(self.base + COM_RX) as u8 as char),
}
}
pub fn putfmt(&mut self, fmt: Arguments) {
self.write_fmt(fmt).unwrap();
}
}
impl Write for SerialPort {
fn write_str(&mut self, s: &str) -> Result {
for c in s.bytes() {
if c == 127 {
self.putchar(8);
self.putchar(b' ');
self.putchar(8);
} else {
self.putchar(c);
}
}
Ok(())
}
}
fn write<T>(addr: usize, content: T) {
let cell = (addr) as *mut T;
unsafe { write_volatile(cell, content); }
}
fn read<T>(addr: usize) -> T {
let cell = (addr) as *const T;
unsafe { read_volatile(cell) }
}
const COM_RX :usize = 0x00; // In: Receive buffer (DLAB=0)
const COM_TX :usize = 0x00; // Out: Transmit buffer (DLAB=0)
const COM_INT_EN :usize = 0x08; // In: Interrupt enable
const COM_INT_ID :usize = 0x10; // Out: Interrupt identification
const COM_LSR :usize = 0x28; // In: Line status register
lazy_static! {
pub static ref SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
}
pub fn init(base: usize) {
SERIAL_PORT.lock().init(base);
}
Loading…
Cancel
Save