aboutsummaryrefslogtreecommitdiff
path: root/drivers/serial.cc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial.cc')
-rw-r--r--drivers/serial.cc88
1 files changed, 88 insertions, 0 deletions
diff --git a/drivers/serial.cc b/drivers/serial.cc
new file mode 100644
index 0000000..84dd4b0
--- /dev/null
+++ b/drivers/serial.cc
@@ -0,0 +1,88 @@
+#include "serial.h"
+
+/* Line Control
+ * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+ * |dla| | parity | s | data |
+ */
+enum LineControlRegister : uint8_t {
+ // data bits
+ d5bit = 0b00000000,
+ d6bit = 0b00000001,
+ d7bit = 0b00000010,
+ d8bit = 0b00000011,
+ // parity bits
+ none = 0b00000000,
+ odd = 0b00001000,
+ even = 0b00011000,
+ mark = 0b00101000,
+ space = 0b00111000,
+ // stop bits
+ s1bit = 0b00000000,
+ s2bit = 0b00000100, // 1.5 for 5bit data; 2 otherwise
+ // divisor latch access bit
+ dlab = 0b10000000,
+};
+
+/* Line Status Register */
+enum LineStatusRegister : uint8_t {
+ DR = 0b00000001, // data ready: see if there is data to read
+ OE = 0b00000010, // overrun error: see if there has been data lost
+ PE = 0b00000100, // parity error: see if there was error in transmission
+ FE = 0b00001000, // framing error: see if a stop bit was missing
+ BI = 0b00010000, // break indicator: see if there is a break in data input
+ THRE = 0b00100000, // transmitter holding register empty: see if transmission buffer is empty
+ TEMT = 0b01000000, // transmitter empty: see if transmitter is not doing anything
+ ERRO = 0b10000000, // impending error: see if there is an error with a word in the input buffer
+};
+
+SerialPort::SerialPort() {
+ /*
+ * The serial controller (UART) has a baud rate of 115200 ticks per second; to limit the speed of the port set the
+ * divisor:
+ * 1. set DLAB on LineControl
+ * 2. set BaudDiv_l
+ * 3. set BaudDiv_h
+ * 4. clear LineControl
+ */
+
+ port.write(0x00, InterruptControl); // disable all interrupts
+
+ port.write(dlab, LineControl);
+ port.write(0x03, BaudDiv_l); // div_l: 0x03 38400 baud
+ port.write(0x00, BaudDiv_h); // div_h: 0x00
+ port.write(d8bit | none | s1bit, LineControl); // 8 bits, no parity, one stop bit
+
+ port.write(0xc7, FifoControl); // enable FIFO, clear, with 14-byte threshold
+ port.write(0x0b, ModemControl); // IRQ enabled, RTS/DSR set
+}
+
+bool SerialPort::ready_read() {
+ return (port.read(LineStatus) & DR);
+}
+
+uint8_t SerialPort::read() {
+ while (!ready_read()) {
+ asm volatile("nop");
+ }
+ return port.read();
+}
+
+bool SerialPort::ready_write() {
+ return (port.read(LineStatus) & THRE);
+}
+
+void SerialPort::write(char c) {
+ while (!ready_write()) {
+ asm volatile("nop");
+ }
+
+ switch (c) {
+ case '\n':
+ port.write('\n');
+ port.write('\r');
+ break;
+ default:
+ port.write(static_cast<uint8_t>(c));
+ }
+}
+