Signed-off-by: Harry Chen <i@harrychen.xyz>master
parent
85245c4e21
commit
8dff9f1b14
@ -0,0 +1,7 @@
|
|||||||
|
lazy_static! {
|
||||||
|
pub static ref FRAME_BUFFER: Mutex<Option<Framebuffer>> = Mutex::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FramebufferInfo {}
|
||||||
|
|
||||||
|
pub enum ColorDepth {}
|
@ -0,0 +1,19 @@
|
|||||||
|
use once::*;
|
||||||
|
|
||||||
|
pub mod serial;
|
||||||
|
pub mod fb;
|
||||||
|
#[path = "../../../../drivers/console/mod.rs"]
|
||||||
|
pub mod console;
|
||||||
|
|
||||||
|
/// Initialize serial port first
|
||||||
|
pub fn init_serial_early() {
|
||||||
|
assert_has_not_been_called!("board::init must be called only once");
|
||||||
|
serial::init();
|
||||||
|
println!("Hello QEMU Malta!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize other board drivers
|
||||||
|
pub fn init_driver() {
|
||||||
|
// TODO: add possibly more drivers
|
||||||
|
// timer::init();
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
use core::fmt::{Write, Result, Arguments};
|
||||||
|
use core::ptr::{read_volatile, write_volatile};
|
||||||
|
|
||||||
|
struct SerialPort {};
|
||||||
|
|
||||||
|
impl SerialPort {
|
||||||
|
fn new() -> SerialPort {
|
||||||
|
SerialPort { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for SerialPort {
|
||||||
|
fn write_str(&mut self, s: &str) -> Result {
|
||||||
|
for c in s.bytes() {
|
||||||
|
if c == 127 {
|
||||||
|
putchar(8);
|
||||||
|
putchar(b' ');
|
||||||
|
putchar(8);
|
||||||
|
} else {
|
||||||
|
putchar(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write<T>(addr: usize, content: T) {
|
||||||
|
let cell = (addr) as *mut T;
|
||||||
|
write_volatile(cell, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read<T>(addr: usize) -> T {
|
||||||
|
let cell = (addr) as *const T;
|
||||||
|
read_volatile(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// non-blocking version of putchar()
|
||||||
|
fn putchar(c: u8) {
|
||||||
|
write(COM1 + COM_TX, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// blocking version of getchar()
|
||||||
|
pub fn getchar() -> char {
|
||||||
|
loop {
|
||||||
|
if (read::<u8>(COM1 + COM_LSR) & COM_LSR_DATA) == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let c = read::<u8>(COM1 + COM_RX);
|
||||||
|
match c {
|
||||||
|
255 => '\0', // null
|
||||||
|
c => c as char,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// non-blocking version of getchar()
|
||||||
|
pub fn getchar_option() -> Option<char> {
|
||||||
|
match read::<u8>(COM1 + COM_LSR) & COM_LSR_DATA {
|
||||||
|
0 => None,
|
||||||
|
else => Some(read::<u8>(COM1 + COM_RX) as u8 as char),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn putfmt(fmt: Arguments) {
|
||||||
|
SerialPort.write_fmt(fmt).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
// Turn off the FIFO
|
||||||
|
write(COM1 + COM_FCR, 0 as u8);
|
||||||
|
// Set speed; requires DLAB latch
|
||||||
|
write(COM1 + COM_LCR, COM_LCR_DLAB);
|
||||||
|
write(COM1 + COM_DLL, (115200 / 9600) as u8);
|
||||||
|
write(COM1 + COM_DLM, 0 as u8);
|
||||||
|
|
||||||
|
// 8 data bits, 1 stop bit, parity off; turn off DLAB latch
|
||||||
|
write(COM1 + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB);
|
||||||
|
|
||||||
|
// No modem controls
|
||||||
|
write(COM1 + COM_MCR, 0 as u8);
|
||||||
|
// Enable rcv interrupts
|
||||||
|
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_TX :usize = 0; // Out: Transmit buffer (DLAB=0)
|
||||||
|
const COM_DLL :usize = 0; // Out: Divisor Latch Low (DLAB=1)
|
||||||
|
const COM_DLM :usize = 1; // Out: Divisor Latch High (DLAB=1)
|
||||||
|
const COM_IER :usize = 1; // Out: Interrupt Enable Register
|
||||||
|
const COM_IER_RDI :u8 = 0x01; // Enable receiver data interrupt
|
||||||
|
const COM_IIR :usize = 2; // In: Interrupt ID Register
|
||||||
|
const COM_FCR :usize = 2; // Out: FIFO Control Register
|
||||||
|
const COM_LCR :usize = 3; // Out: Line Control Register
|
||||||
|
const COM_LCR_DLAB :u8 = 0x80; // Divisor latch access bit
|
||||||
|
const COM_LCR_WLEN8 :u8 = 0x03; // Wordlength: 8 bits
|
||||||
|
const COM_MCR :usize = 4; // Out: Modem Control Register
|
||||||
|
const COM_MCR_RTS :u8 = 0x02; // RTS complement
|
||||||
|
const COM_MCR_DTR :u8 = 0x01; // DTR complement
|
||||||
|
const COM_MCR_OUT2 :u8 = 0x08; // Out2 complement
|
||||||
|
const COM_LSR :usize = 5; // In: Line Status Register
|
||||||
|
const COM_LSR_DATA :u8 = 0x01; // Data available
|
||||||
|
const COM_LSR_TXRDY :u8 = 0x20; // Transmit buffer avail
|
||||||
|
const COM_LSR_TSRE :u8 = 0x40; // Transmitter off
|
||||||
|
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
SERIAL_PORT.lock().init();
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
use once::*;
|
||||||
|
|
||||||
|
pub mod serial;
|
||||||
|
pub mod fb;
|
||||||
|
#[path = "../../../../drivers/console/mod.rs"]
|
||||||
|
pub mod console;
|
||||||
|
|
||||||
|
/// Initialize serial port first
|
||||||
|
pub fn init_serial_early() {
|
||||||
|
assert_has_not_been_called!("board::init must be called only once");
|
||||||
|
serial::init();
|
||||||
|
println!("Hello ThinPad!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize other board drivers
|
||||||
|
pub fn init_driver() {
|
||||||
|
// TODO: add possibly more drivers
|
||||||
|
// timer::init();
|
||||||
|
console::init();
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
//! mipsel drivers
|
||||||
|
|
||||||
|
use super::board;
|
||||||
|
use once::*;
|
||||||
|
|
||||||
|
pub use self::board::serial;
|
||||||
|
pub use self::board::fb;
|
||||||
|
#[path = "../../../drivers/console/mod.rs"]
|
||||||
|
pub mod console;
|
||||||
|
|
||||||
|
/// Initialize common drivers
|
||||||
|
pub fn init() {
|
||||||
|
assert_has_not_been_called!("driver::init must be called only once");
|
||||||
|
board::init_driver();
|
||||||
|
console::init();
|
||||||
|
}
|
@ -1,100 +1,30 @@
|
|||||||
use core::fmt::{Write, Result, Arguments};
|
//! Input/output for mipsel.
|
||||||
use core::ptr::{read_volatile, write_volatile};
|
|
||||||
|
|
||||||
struct SerialPort {};
|
use super::driver::console::CONSOLE;
|
||||||
|
use super::driver::serial::*;
|
||||||
|
use core::fmt::{Arguments, Write};
|
||||||
|
|
||||||
impl Write for SerialPort {
|
|
||||||
fn write_str(&mut self, s: &str) -> Result {
|
|
||||||
for c in s.bytes() {
|
|
||||||
if c == 127 {
|
|
||||||
putchar(8);
|
|
||||||
putchar(b' ');
|
|
||||||
putchar(8);
|
|
||||||
} else {
|
|
||||||
putchar(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write<T>(addr: usize, content: T) {
|
|
||||||
let cell = (addr) as *mut T;
|
|
||||||
write_volatile(cell, content);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read<T>(addr: usize) -> T {
|
|
||||||
let cell = (addr) as *const T;
|
|
||||||
read_volatile(cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// non-blocking version of putchar()
|
|
||||||
fn putchar(c: u8) {
|
|
||||||
write(COM1 + COM_TX, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// blocking version of getchar()
|
|
||||||
pub fn getchar() -> char {
|
pub fn getchar() -> char {
|
||||||
loop {
|
unsafe { SERIAL_PORT.force_unlock() }
|
||||||
if (read::<u8>(COM1 + COM_LSR) & COM_LSR_DATA) == 0 {
|
SERIAL_PORT.lock().getchar()
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let c = read::<u8>(COM1 + COM_RX);
|
|
||||||
match c {
|
|
||||||
255 => '\0', // null
|
|
||||||
c => c as char,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// non-blocking version of getchar()
|
pub fn getchar_option() -> Option<Char> {
|
||||||
pub fn getchar_option() -> Option<char> {
|
unsafe { SERIAL_PORT.force_unlock() }
|
||||||
match read::<u8>(COM1 + COM_LSR) & COM_LSR_DATA {
|
SERIAL_PORT.lock().getchar_option()
|
||||||
0 => None,
|
|
||||||
else => Some(read::<u8>(COM1 + COM_RX) as u8 as char),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn putfmt(fmt: Arguments) {
|
pub fn putfmt(fmt: Arguments) {
|
||||||
SerialPort.write_fmt(fmt).unwrap();
|
unsafe { SERIAL_PORT.force_unlock() }
|
||||||
}
|
SERIAL_PORT.lock().write_fmt(fmt).unwrap();
|
||||||
|
|
||||||
pub fn init() {
|
|
||||||
// Turn off the FIFO
|
|
||||||
write(COM1 + COM_FCR, 0 as u8);
|
|
||||||
// Set speed; requires DLAB latch
|
|
||||||
write(COM1 + COM_LCR, COM_LCR_DLAB);
|
|
||||||
write(COM1 + COM_DLL, (115200 / 9600) as u8);
|
|
||||||
write(COM1 + COM_DLM, 0 as u8);
|
|
||||||
|
|
||||||
// 8 data bits, 1 stop bit, parity off; turn off DLAB latch
|
unsafe { CONSOLE.force_unlock() }
|
||||||
write(COM1 + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB);
|
if let Some(console) = CONSOLE.lock().as_mut() {
|
||||||
|
console.write_fmt(fmt).unwrap();
|
||||||
// No modem controls
|
}
|
||||||
write(COM1 + COM_MCR, 0 as u8);
|
|
||||||
// Enable rcv interrupts
|
|
||||||
write(COM1 + COM_IER, COM_IER_RDI);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "board_malta")]
|
pub fn putchar(c: u8) {
|
||||||
const COM1 :usize = 0xbf000900; // 16550 Base Address
|
unsafe { SERIAL_PORT.force_unlock() }
|
||||||
|
SERIAL_PORT.lock().putchar(c);
|
||||||
const COM_RX :usize = 0; // In: Receive buffer (DLAB=0)
|
}
|
||||||
const COM_TX :usize = 0; // Out: Transmit buffer (DLAB=0)
|
|
||||||
const COM_DLL :usize = 0; // Out: Divisor Latch Low (DLAB=1)
|
|
||||||
const COM_DLM :usize = 1; // Out: Divisor Latch High (DLAB=1)
|
|
||||||
const COM_IER :usize = 1; // Out: Interrupt Enable Register
|
|
||||||
const COM_IER_RDI :u8 = 0x01; // Enable receiver data interrupt
|
|
||||||
const COM_IIR :usize = 2; // In: Interrupt ID Register
|
|
||||||
const COM_FCR :usize = 2; // Out: FIFO Control Register
|
|
||||||
const COM_LCR :usize = 3; // Out: Line Control Register
|
|
||||||
const COM_LCR_DLAB :u8 = 0x80; // Divisor latch access bit
|
|
||||||
const COM_LCR_WLEN8 :u8 = 0x03; // Wordlength: 8 bits
|
|
||||||
const COM_MCR :usize = 4; // Out: Modem Control Register
|
|
||||||
const COM_MCR_RTS :u8 = 0x02; // RTS complement
|
|
||||||
const COM_MCR_DTR :u8 = 0x01; // DTR complement
|
|
||||||
const COM_MCR_OUT2 :u8 = 0x08; // Out2 complement
|
|
||||||
const COM_LSR :usize = 5; // In: Line Status Register
|
|
||||||
const COM_LSR_DATA :u8 = 0x01; // Data available
|
|
||||||
const COM_LSR_TXRDY :u8 = 0x20; // Transmit buffer avail
|
|
||||||
const COM_LSR_TSRE :u8 = 0x40; // Transmitter off
|
|
||||||
|
Loading…
Reference in new issue