diff options
author | Aqua-sama <aqua@iserlohn-fortress.net> | 2021-02-12 17:55:31 +0200 |
---|---|---|
committer | Aqua-sama <aqua@iserlohn-fortress.net> | 2021-02-12 17:55:31 +0200 |
commit | 46a5f1ee4db70a037af5038deaa1d64ad0f7862c (patch) | |
tree | 0250b88f2eb69a7a0987a78d23a06e2125df74a2 /drivers/serial.cc | |
parent | Add comments to explain CGA ports better (diff) | |
download | kernel.cpp-46a5f1ee4db70a037af5038deaa1d64ad0f7862c.tar.xz |
Add serial0 console output
Diffstat (limited to 'drivers/serial.cc')
-rw-r--r-- | drivers/serial.cc | 88 |
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)); + } +} + |