1use spin::Once;
6use x86_64::instructions::port::ReadWriteAccess;
7
8use crate::{
9 console::uart_ns16650a::{Ns16550aAccess, Ns16550aRegister, Ns16550aUart},
10 io::{IoPort, reserve_io_port_range},
11 sync::{LocalIrqDisabled, SpinLock},
12};
13
14pub static SERIAL_PORT: Once<SpinLock<Ns16550aUart<SerialAccess>, LocalIrqDisabled>> =
16 Once::initialized(SpinLock::new(Ns16550aUart::new(
17 unsafe { SerialAccess::new(0x3F8) },
23 )));
24reserve_io_port_range!(0x3F8..0x400);
25
26#[derive(Debug)]
28pub struct SerialAccess {
29 data: IoPort<u8, ReadWriteAccess>,
30 int_en: IoPort<u8, ReadWriteAccess>,
31 fifo_ctrl: IoPort<u8, ReadWriteAccess>,
32 line_ctrl: IoPort<u8, ReadWriteAccess>,
33 modem_ctrl: IoPort<u8, ReadWriteAccess>,
34 line_stat: IoPort<u8, ReadWriteAccess>,
35 modem_stat: IoPort<u8, ReadWriteAccess>,
36}
37
38impl SerialAccess {
39 const unsafe fn new(port: u16) -> Self {
44 unsafe {
46 Self {
47 data: IoPort::new(port),
48 int_en: IoPort::new(port + 1),
49 fifo_ctrl: IoPort::new(port + 2),
50 line_ctrl: IoPort::new(port + 3),
51 modem_ctrl: IoPort::new(port + 4),
52 line_stat: IoPort::new(port + 5),
53 modem_stat: IoPort::new(port + 6),
54 }
55 }
56 }
57}
58
59impl Ns16550aAccess for SerialAccess {
60 fn read(&self, reg: Ns16550aRegister) -> u8 {
61 match reg {
62 Ns16550aRegister::DataOrDivisorLo => self.data.read(),
63 Ns16550aRegister::IntEnOrDivisorHi => self.int_en.read(),
64 Ns16550aRegister::FifoCtrl => self.fifo_ctrl.read(),
65 Ns16550aRegister::LineCtrl => self.line_ctrl.read(),
66 Ns16550aRegister::ModemCtrl => self.modem_ctrl.read(),
67 Ns16550aRegister::LineStat => self.line_stat.read(),
68 Ns16550aRegister::ModemStat => self.modem_stat.read(),
69 }
70 }
71
72 fn write(&mut self, reg: Ns16550aRegister, val: u8) {
73 match reg {
74 Ns16550aRegister::DataOrDivisorLo => self.data.write(val),
75 Ns16550aRegister::IntEnOrDivisorHi => self.int_en.write(val),
76 Ns16550aRegister::FifoCtrl => self.fifo_ctrl.write(val),
77 Ns16550aRegister::LineCtrl => self.line_ctrl.write(val),
78 Ns16550aRegister::ModemCtrl => self.modem_ctrl.write(val),
79 Ns16550aRegister::LineStat => self.line_stat.write(val),
80 Ns16550aRegister::ModemStat => self.modem_stat.write(val),
81 }
82 }
83}
84
85pub(crate) fn init() {
87 SERIAL_PORT.get().unwrap().lock().init();
88}