aboutsummaryrefslogtreecommitdiff
path: root/serial.h
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2026-08-29 17:45:02 +0200
committerJavier <dev.git@javispedro.com>2026-08-29 17:45:02 +0200
commit003a26a76982f512e2f3a1108e46b88aa29ab306 (patch)
tree6c508e3ee1fc995ed9e13ffc5075927ff94ed5fe /serial.h
parentd25f344b9980c2d030f8388df84aaf8ff88d2591 (diff)
downloadvbados-003a26a76982f512e2f3a1108e46b88aa29ab306.tar.gz
vbados-003a26a76982f512e2f3a1108e46b88aa29ab306.zip
split bda from int10vga.h , update kitten version to latest from freedos
Diffstat (limited to 'serial.h')
-rw-r--r--serial.h210
1 files changed, 210 insertions, 0 deletions
diff --git a/serial.h b/serial.h
new file mode 100644
index 0000000..beeaf50
--- /dev/null
+++ b/serial.h
@@ -0,0 +1,210 @@
+#ifndef SERIAL_H
+#define SERIAL_H
+
+#include <stdint.h>
+
+#include "bda.h"
+
+enum SERIAL_UART_REGS {
+ SERIAL_TX = 0,
+ SERIAL_RX = 0,
+ /** (only with DLAB enabled) LSB of divisor/baud rate */
+ SERIAL_DIVISOR_LO = 0,
+ /** (only with DLAB enabled) MSB of divisor/baud rate */
+ SERIAL_DIVISOR_HI = 1,
+ /** Interrupt Enable Register(read/write) */
+ SERIAL_IER = 1,
+ /** Fifo Control Register (write-only) */
+ SERIAL_FCR = 2,
+ /** Interrupt Identification Register (read-only) */
+ SERIAL_IIR = 2,
+ /** Line Control Register (read/write), contains DLAB bit */
+ SERIAL_LCR = 3,
+ /** Modem Control Register (read/write) */
+ SERIAL_MCR = 4,
+ /** Line Status Register (read-only) */
+ SERIAL_LSR = 5,
+ /** Modem Status Register (read-only) */
+ SERIAL_MSR = 6
+};
+
+#if 0
+// Comes straight from https://wiki.osdev.org/Serial_Ports#Initialization
+outp(DLOG_TARGET_PORT + 1, 0x00); // Disable all interrupts
+outp(DLOG_TARGET_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
+outp(DLOG_TARGET_PORT + 0, 0x01); // Set divisor to 1 (lo byte) 115200 baud
+outp(DLOG_TARGET_PORT + 1, 0x00); // (hi byte)
+outp(DLOG_TARGET_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
+outp(DLOG_TARGET_PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
+outp(DLOG_TARGET_PORT + 4, 0x03); // RTS/DSR set, IRQs disabled
+#endif
+
+enum SERIAL_DIVISOR {
+ SERIAL_DIVISOR_115200 = 1,
+ SEIRAL_DIVISOR_9600 = 12,
+ SERIAL_DIVISOR_1200 = 96
+};
+
+enum SERIAL_FCR {
+ SERIAL_FCR_RX_TRIGER_1 = 0 << 6,
+ SERIAL_FCR_RX_TRIGER_4 = 1 << 6,
+ SERIAL_FCR_RX_TRIGER_8 = 2 << 6,
+ SERIAL_FCR_RX_TRIGER_14 = 3 << 6,
+ SERIAL_FCR_DMA_SEL = 1 << 3,
+ SERIAL_FCR_TX_RESET = 1 << 2,
+ SERIAL_FCR_RX_RESET = 1 << 1,
+ SERIAL_FCR_FIFO_ENABLE = 1 << 0,
+};
+
+enum SERIAL_LCR {
+ /** Word Length = 5 bits */
+ SERIAL_LCR_WL_5 = 0,
+ SERIAL_LCR_WL_6 = 1,
+ SERIAL_LCR_WL_7 = 2,
+ SERIAL_LCR_WL_8 = 3,
+ /** STop Bit */
+ SERIAL_LCR_STB = 1 << 2,
+ /** Parity ENable */
+ SERIAL_LCR_PEN = 1 << 3,
+ /** Even Parity Select. */
+ SERIAL_LCR_EPS = 1 << 4,
+ /** Stick Parity */
+ SERIAL_LCR_SP = 1 << 5,
+ SERIAL_LCR_PAR_NONE = 0,
+ SERIAL_LCR_PAR_ODD = SERIAL_LCR_PEN,
+ SERIAL_LCR_PAR_EVEN = SERIAL_LCR_PEN | SERIAL_LCR_EPS,
+ SERIAL_LCR_PAR_MARK = SERIAL_LCR_PEN | SERIAL_LCR_SP,
+ SERIAL_LCR_PAR_SPACE = SERIAL_LCR_PEN | SERIAL_LCR_EPS | SERIAL_LCR_SP,
+ /** Set Break */
+ SERIAL_LCR_SB = 1 << 6,
+ /** Divisor Latch Access Bit */
+ SERIAL_LCR_DLAB = 1 << 7,
+};
+
+enum SERIAL_MCR {
+ SERIAL_MCR_DTR = 1 << 0,
+ SERIAL_MCR_RTS = 1 << 1,
+ SERIAL_MCR_OUT1 = 1 << 2,
+ SERIAL_MCR_OUT2 = 1 << 3,
+ SERIAL_MCR_LOOP = 1 << 4,
+};
+
+enum SERIAL_LSR {
+ /** Data Ready (i.e., data ready to be read) */
+ SERIAL_LSR_DR = 1 << 0,
+ SERIAL_LSR_OE = 1 << 1,
+ SERIAL_LSR_PE = 1 << 2,
+ SERIAL_LSR_FE = 1 << 3,
+ SERIAL_LSR_BI = 1 << 4,
+ /** Transmitter Holding Register Empty (i.e. space to send data is available) */
+ SERIAL_LSR_THRE = 1 << 5,
+ SERIAL_LSR_TEMT = 1 << 6,
+ SERIAL_LSR_RXERR = 1 << 7,
+};
+
+enum SERIAL_MSR {
+ SERIAL_MSR_DCD = 1 << 7,
+ SERIAL_MSR_RI = 1 << 6,
+ SERIAL_MSR_DSR = 1 << 5,
+ SERIAL_MSR_CTS = 1 << 4,
+ SERIAL_MSR_DDCD = 1 << 3,
+ SERIAL_MSR_TERI = 1 << 2,
+ SERIAL_MSR_DDSR = 1 << 1,
+ SERIAL_MSR_DCTS = 1 << 0
+};
+
+struct serial_config
+{
+ uint8_t divisor_lo, divisor_hi;
+ uint8_t ier, lcr, mcr;
+};
+
+static unsigned serial_num_ports()
+{
+ uint8_t equipment = bda_get_byte(0x11);
+ uint8_t numports = (equipment & 0xE) >> 1;
+ return numports;
+}
+
+static uint16_t serial_get_iobase(unsigned port)
+{
+ uint16_t bdaport = bda_get_word((port - 1) * 2);
+ if (bdaport > 10) {
+ return bdaport;
+ } else if (port == 1) {
+ // Even if BIOS says no, hardcode the basic COM1 port at least.
+ return 0x3F8;
+ }
+ return 0;
+}
+
+static void serial_save_config(unsigned iobase, struct serial_config *config)
+{
+ config->ier = inp(iobase + SERIAL_IER);
+ config->lcr = inp(iobase + SERIAL_LCR);
+ config->mcr = inp(iobase + SERIAL_MCR);
+ // Set DLAB so that we can read divisor
+ outp(iobase + SERIAL_LCR, config->lcr | SERIAL_LCR_DLAB);
+ config->divisor_lo = inp(iobase + SERIAL_DIVISOR_LO);
+ config->divisor_hi = inp(iobase + SERIAL_DIVISOR_HI);
+ // Restore DLAB to whatever it was
+ outp(iobase + SERIAL_LCR, config->lcr);
+}
+
+static void serial_restore_config(unsigned iobase, const struct serial_config *config)
+{
+ outp(iobase + SERIAL_LCR, config->lcr | SERIAL_LCR_DLAB);
+ outp(iobase + SERIAL_DIVISOR_LO, config->divisor_lo);
+ outp(iobase + SERIAL_DIVISOR_HI, config->divisor_hi);
+ outp(iobase + SERIAL_LCR, config->lcr);
+ outp(iobase + SERIAL_MCR, config->mcr);
+ outp(iobase + SERIAL_IER, config->ier);
+}
+
+static void serial_configure(unsigned iobase, uint16_t divisor, uint8_t lcr)
+{
+ outp(iobase + SERIAL_IER, 0); // Disable all interrupts
+ outp(iobase + SERIAL_LCR, SERIAL_LCR_DLAB); // Enable DLAB and clear all other flags
+ outp(iobase + SERIAL_DIVISOR_LO, divisor);
+ outp(iobase + SERIAL_DIVISOR_HI, divisor >> 8);
+ outp(iobase + SERIAL_LCR, lcr); // This also disables DLAB
+ // Enable and reset both FIFOs
+ outp(iobase + SERIAL_FCR, SERIAL_FCR_RX_TRIGER_14|SERIAL_FCR_FIFO_ENABLE|SERIAL_FCR_RX_RESET|SERIAL_FCR_TX_RESET);
+}
+
+static inline void serial_set_modem_control(unsigned iobase, uint8_t mcr)
+{
+ outp(iobase + SERIAL_MCR, mcr);
+}
+
+static inline void serial_set_modem_status(unsigned iobase, uint8_t msr)
+{
+ outp(iobase + SERIAL_MSR, msr);
+}
+
+static inline uint8_t serial_get_line_status(unsigned iobase)
+{
+ return inp(iobase + SERIAL_LSR);
+}
+
+static inline bool serial_data_ready(unsigned iobase)
+{
+ return serial_get_line_status(iobase) & SERIAL_LSR_DR;
+}
+
+static inline uint8_t serial_read_data(unsigned iobase)
+{
+ return inp(iobase + SERIAL_RX);
+}
+
+static inline bool serial_tx_ready(unsigned iobase)
+{
+ return serial_get_line_status(iobase) & SERIAL_LSR_THRE;
+}
+
+static inline void serial_send_data(unsigned iobase, uint8_t data)
+{
+ outp(iobase + SERIAL_TX, data);
+}
+
+#endif // SERIAL_H