Skip to main content

os/drivers/chardev/
ns16550a.rs

1///! Ref: https://www.lammertbies.nl/comm/info/serial-uart
2///! Ref: ns16550a datasheet: https://datasheetspdf.com/pdf-file/605590/NationalSemiconductor/NS16550A/1
3///! Ref: ns16450 datasheet: https://datasheetspdf.com/pdf-file/1311818/NationalSemiconductor/NS16450/1
4use super::CharDevice;
5use crate::sync::{Condvar, UPIntrFreeCell};
6use crate::task::schedule;
7use alloc::collections::VecDeque;
8use bitflags::*;
9use volatile::{ReadOnly, Volatile, WriteOnly};
10
11bitflags! {
12    /// InterruptEnableRegister
13    pub struct IER: u8 {
14        const RX_AVAILABLE = 1 << 0;
15        const TX_EMPTY = 1 << 1;
16    }
17
18    /// LineStatusRegister
19    pub struct LSR: u8 {
20        const DATA_AVAILABLE = 1 << 0;
21        const THR_EMPTY = 1 << 5;
22    }
23
24    /// Model Control Register
25    pub struct MCR: u8 {
26        const DATA_TERMINAL_READY = 1 << 0;
27        const REQUEST_TO_SEND = 1 << 1;
28        const AUX_OUTPUT1 = 1 << 2;
29        const AUX_OUTPUT2 = 1 << 3;
30    }
31}
32
33#[repr(C)]
34#[allow(dead_code)]
35struct ReadWithoutDLAB {
36    /// receiver buffer register
37    pub rbr: ReadOnly<u8>,
38    /// interrupt enable register
39    pub ier: Volatile<IER>,
40    /// interrupt identification register
41    pub iir: ReadOnly<u8>,
42    /// line control register
43    pub lcr: Volatile<u8>,
44    /// model control register
45    pub mcr: Volatile<MCR>,
46    /// line status register
47    pub lsr: ReadOnly<LSR>,
48    /// ignore MSR
49    _padding1: ReadOnly<u8>,
50    /// ignore SCR
51    _padding2: ReadOnly<u8>,
52}
53
54#[repr(C)]
55#[allow(dead_code)]
56struct WriteWithoutDLAB {
57    /// transmitter holding register
58    pub thr: WriteOnly<u8>,
59    /// interrupt enable register
60    pub ier: Volatile<IER>,
61    /// ignore FCR
62    _padding0: ReadOnly<u8>,
63    /// line control register
64    pub lcr: Volatile<u8>,
65    /// modem control register
66    pub mcr: Volatile<MCR>,
67    /// line status register
68    pub lsr: ReadOnly<LSR>,
69    /// ignore other registers
70    _padding1: ReadOnly<u16>,
71}
72
73pub struct NS16550aRaw {
74    base_addr: usize,
75}
76
77impl NS16550aRaw {
78    fn read_end(&mut self) -> &mut ReadWithoutDLAB {
79        unsafe { &mut *(self.base_addr as *mut ReadWithoutDLAB) }
80    }
81
82    fn write_end(&mut self) -> &mut WriteWithoutDLAB {
83        unsafe { &mut *(self.base_addr as *mut WriteWithoutDLAB) }
84    }
85
86    pub fn new(base_addr: usize) -> Self {
87        Self { base_addr }
88    }
89
90    pub fn init(&mut self) {
91        let read_end = self.read_end();
92        let mut mcr = MCR::empty();
93        mcr |= MCR::DATA_TERMINAL_READY;
94        mcr |= MCR::REQUEST_TO_SEND;
95        mcr |= MCR::AUX_OUTPUT2;
96        read_end.mcr.write(mcr);
97        let ier = IER::RX_AVAILABLE;
98        read_end.ier.write(ier);
99    }
100
101    pub fn read(&mut self) -> Option<u8> {
102        let read_end = self.read_end();
103        let lsr = read_end.lsr.read();
104        if lsr.contains(LSR::DATA_AVAILABLE) {
105            Some(read_end.rbr.read())
106        } else {
107            None
108        }
109    }
110
111    pub fn write(&mut self, ch: u8) {
112        let write_end = self.write_end();
113        loop {
114            if write_end.lsr.read().contains(LSR::THR_EMPTY) {
115                write_end.thr.write(ch);
116                break;
117            }
118        }
119    }
120}
121
122struct NS16550aInner {
123    ns16550a: NS16550aRaw,
124    read_buffer: VecDeque<u8>,
125}
126
127pub struct NS16550a<const BASE_ADDR: usize> {
128    inner: UPIntrFreeCell<NS16550aInner>,
129    condvar: Condvar,
130}
131
132impl<const BASE_ADDR: usize> NS16550a<BASE_ADDR> {
133    pub fn new() -> Self {
134        let inner = NS16550aInner {
135            ns16550a: NS16550aRaw::new(BASE_ADDR),
136            read_buffer: VecDeque::new(),
137        };
138        //inner.ns16550a.init();
139        Self {
140            inner: unsafe { UPIntrFreeCell::new(inner) },
141            condvar: Condvar::new(),
142        }
143    }
144
145    pub fn read_buffer_is_empty(&self) -> bool {
146        self.inner
147            .exclusive_session(|inner| inner.read_buffer.is_empty())
148    }
149}
150
151impl<const BASE_ADDR: usize> CharDevice for NS16550a<BASE_ADDR> {
152    fn init(&self) {
153        let mut inner = self.inner.exclusive_access();
154        inner.ns16550a.init();
155        drop(inner);
156    }
157
158    fn read(&self) -> u8 {
159        loop {
160            let mut inner = self.inner.exclusive_access();
161            if let Some(ch) = inner.read_buffer.pop_front() {
162                return ch;
163            } else {
164                let task_cx_ptr = self.condvar.wait_no_sched();
165                drop(inner);
166                schedule(task_cx_ptr);
167            }
168        }
169    }
170    fn write(&self, ch: u8) {
171        let mut inner = self.inner.exclusive_access();
172        inner.ns16550a.write(ch);
173    }
174    fn handle_irq(&self) {
175        let mut count = 0;
176        self.inner.exclusive_session(|inner| {
177            while let Some(ch) = inner.ns16550a.read() {
178                count += 1;
179                inner.read_buffer.push_back(ch);
180            }
181        });
182        if count > 0 {
183            self.condvar.signal();
184        }
185    }
186}