|
|
@ -1,88 +1,91 @@
|
|
|
|
use core::fmt::{Write, Result, Arguments};
|
|
|
|
use core::fmt::{Write, Result, Arguments};
|
|
|
|
use core::ptr::{read_volatile, write_volatile};
|
|
|
|
use core::ptr::{read_volatile, write_volatile};
|
|
|
|
|
|
|
|
|
|
|
|
struct SerialPort {};
|
|
|
|
struct SerialPort {
|
|
|
|
|
|
|
|
base: usize
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl SerialPort {
|
|
|
|
impl SerialPort {
|
|
|
|
fn new() -> SerialPort {
|
|
|
|
fn new() -> SerialPort {
|
|
|
|
SerialPort { }
|
|
|
|
SerialPort { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Write for SerialPort {
|
|
|
|
pub fn init(&mut self, base: usize) {
|
|
|
|
fn write_str(&mut self, s: &str) -> Result {
|
|
|
|
self.base = base;
|
|
|
|
for c in s.bytes() {
|
|
|
|
// Turn off the FIFO
|
|
|
|
if c == 127 {
|
|
|
|
write(self.base + COM_FCR, 0 as u8);
|
|
|
|
putchar(8);
|
|
|
|
// Set speed; requires DLAB latch
|
|
|
|
putchar(b' ');
|
|
|
|
write(self.base + COM_LCR, COM_LCR_DLAB);
|
|
|
|
putchar(8);
|
|
|
|
write(self.base + COM_DLL, (115200 / 9600) as u8);
|
|
|
|
} else {
|
|
|
|
write(self.base + COM_DLM, 0 as u8);
|
|
|
|
putchar(c);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn write<T>(addr: usize, content: T) {
|
|
|
|
// 8 data bits, 1 stop bit, parity off; turn off DLAB latch
|
|
|
|
let cell = (addr) as *mut T;
|
|
|
|
write(self.base + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB);
|
|
|
|
write_volatile(cell, content);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn read<T>(addr: usize) -> T {
|
|
|
|
// No modem controls
|
|
|
|
let cell = (addr) as *const T;
|
|
|
|
write(self.base + COM_MCR, 0 as u8);
|
|
|
|
read_volatile(cell);
|
|
|
|
// Enable rcv interrupts
|
|
|
|
}
|
|
|
|
write(self.base + COM_IER, COM_IER_RDI);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// non-blocking version of putchar()
|
|
|
|
/// non-blocking version of putchar()
|
|
|
|
fn putchar(c: u8) {
|
|
|
|
fn putchar(&mut self, c: u8) {
|
|
|
|
write(COM1 + COM_TX, c);
|
|
|
|
write(self.base + COM_TX, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// blocking version of getchar()
|
|
|
|
/// blocking version of getchar()
|
|
|
|
pub fn getchar() -> char {
|
|
|
|
pub fn getchar(&mut self) -> char {
|
|
|
|
loop {
|
|
|
|
loop {
|
|
|
|
if (read::<u8>(COM1 + COM_LSR) & COM_LSR_DATA) == 0 {
|
|
|
|
if (read::<u8>(self.base + COM_LSR) & COM_LSR_DATA) == 0 {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let c = read::<u8>(COM1 + COM_RX);
|
|
|
|
let c = read::<u8>(self.base + COM_RX);
|
|
|
|
match c {
|
|
|
|
match c {
|
|
|
|
255 => '\0', // null
|
|
|
|
255 => '\0', // null
|
|
|
|
c => c as char,
|
|
|
|
c => c as char,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// non-blocking version of getchar()
|
|
|
|
/// non-blocking version of getchar()
|
|
|
|
pub fn getchar_option() -> Option<char> {
|
|
|
|
pub fn getchar_option(&mut self) -> Option<char> {
|
|
|
|
match read::<u8>(COM1 + COM_LSR) & COM_LSR_DATA {
|
|
|
|
match read::<u8>(self.base + COM_LSR) & COM_LSR_DATA {
|
|
|
|
0 => None,
|
|
|
|
0 => None,
|
|
|
|
else => Some(read::<u8>(COM1 + COM_RX) as u8 as char),
|
|
|
|
_ => Some(read::<u8>(self.base + COM_RX) as u8 as char),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn putfmt(&mut self, fmt: Arguments) {
|
|
|
|
|
|
|
|
self.write_fmt(fmt).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn putfmt(fmt: Arguments) {
|
|
|
|
|
|
|
|
SerialPort.write_fmt(fmt).unwrap();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn init() {
|
|
|
|
impl Write for SerialPort {
|
|
|
|
// Turn off the FIFO
|
|
|
|
fn write_str(&mut self, s: &str) -> Result {
|
|
|
|
write(COM1 + COM_FCR, 0 as u8);
|
|
|
|
for c in s.bytes() {
|
|
|
|
// Set speed; requires DLAB latch
|
|
|
|
if c == 127 {
|
|
|
|
write(COM1 + COM_LCR, COM_LCR_DLAB);
|
|
|
|
self.putchar(8);
|
|
|
|
write(COM1 + COM_DLL, (115200 / 9600) as u8);
|
|
|
|
self.putchar(b' ');
|
|
|
|
write(COM1 + COM_DLM, 0 as u8);
|
|
|
|
self.putchar(8);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
self.putchar(c);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 8 data bits, 1 stop bit, parity off; turn off DLAB latch
|
|
|
|
fn write<T>(addr: usize, content: T) {
|
|
|
|
write(COM1 + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB);
|
|
|
|
let cell = (addr) as *mut T;
|
|
|
|
|
|
|
|
write_volatile(cell, content);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// No modem controls
|
|
|
|
fn read<T>(addr: usize) -> T {
|
|
|
|
write(COM1 + COM_MCR, 0 as u8);
|
|
|
|
let cell = (addr) as *const T;
|
|
|
|
// Enable rcv interrupts
|
|
|
|
read_volatile(cell);
|
|
|
|
write(COM1 + COM_IER, COM_IER_RDI);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const COM1 :usize = 0xbf000900; // 16550 Base Address
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const COM_RX :usize = 0; // In: Receive buffer (DLAB=0)
|
|
|
|
const COM_RX :usize = 0; // In: Receive buffer (DLAB=0)
|
|
|
|
const COM_TX :usize = 0; // Out: Transmit buffer (DLAB=0)
|
|
|
|
const COM_TX :usize = 0; // Out: Transmit buffer (DLAB=0)
|
|
|
@ -109,6 +112,6 @@ lazy_static! {
|
|
|
|
pub static ref SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
|
|
|
|
pub static ref SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn init() {
|
|
|
|
pub fn init(base: usize) {
|
|
|
|
SERIAL_PORT.lock().init();
|
|
|
|
SERIAL_PORT.lock().init(base);
|
|
|
|
}
|
|
|
|
}
|