diff options
| author | Javier <dev.git@javispedro.com> | 2026-08-30 02:21:09 +0200 |
|---|---|---|
| committer | Javier <dev.git@javispedro.com> | 2026-08-30 02:21:09 +0200 |
| commit | 1b0344660de2832b472b0a413c50ff7f111a9293 (patch) | |
| tree | 5ae7303643d6c9187da6366cf30a4f6a4c73d54b /serial.h | |
| parent | 003a26a76982f512e2f3a1108e46b88aa29ab306 (diff) | |
| download | vbados-1b0344660de2832b472b0a413c50ff7f111a9293.tar.gz vbados-1b0344660de2832b472b0a413c50ff7f111a9293.zip | |
first steps towards (optional) serial mouse support
Diffstat (limited to 'serial.h')
| -rw-r--r-- | serial.h | 117 |
1 files changed, 99 insertions, 18 deletions
@@ -2,6 +2,7 @@ #define SERIAL_H #include <stdint.h> +#include <conio.h> #include "bda.h" @@ -12,6 +13,7 @@ enum SERIAL_UART_REGS { SERIAL_DIVISOR_LO = 0, /** (only with DLAB enabled) MSB of divisor/baud rate */ SERIAL_DIVISOR_HI = 1, + SERIAL_DIVISOR = SERIAL_DIVISOR_LO, /** Interrupt Enable Register(read/write) */ SERIAL_IER = 1, /** Fifo Control Register (write-only) */ @@ -45,6 +47,19 @@ enum SERIAL_DIVISOR { SERIAL_DIVISOR_1200 = 96 }; +enum SERIAL_IER { + /** No interrupts */ + SERIAL_IER_NONE = 0, + /** Enable Receiver Buffer Full Interrupt */ + SERIAL_IER_ERBFI = 1 << 0, + /** Enable Transmitter Buffer Empty Interrupt */ + SERIAL_IER_ETBEI = 1 << 1, + /** Enable Line Status Interrupt */ + SERIAL_IER_ELSI = 1 << 2, + /** Enable Delta Status Signals Interrupt */ + SERIAL_IER_EDSSI = 1 << 3, +}; + enum SERIAL_FCR { SERIAL_FCR_RX_TRIGER_1 = 0 << 6, SERIAL_FCR_RX_TRIGER_4 = 1 << 6, @@ -54,6 +69,31 @@ enum SERIAL_FCR { SERIAL_FCR_TX_RESET = 1 << 2, SERIAL_FCR_RX_RESET = 1 << 1, SERIAL_FCR_FIFO_ENABLE = 1 << 0, + SERIAL_FCR_FIFO_RESET = SERIAL_FCR_TX_RESET | SERIAL_FCR_RX_RESET, + SERIAL_FCR_FIFO_DISABLE = 0 +}; + +enum SERIAL_IIR { + /** Mask for retrieving the interrupt that occured. See enum SERIAL_IID. */ + SERIAL_IIR_ID = 0xF, + + SERIAL_IIR_FIFO1 = 1 << 6, + SERIAL_IIR_FIFO2 = 1 << 7, +}; + +enum SERIAL_IID { + /** No interrupt. */ + SERIAL_IID_NONE = 1, + /** Highest priority: line error. OE, PE, etc. Serviced by reading LSR. */ + SERIAL_IID_ERROR = 6, + /** Second highest priority: data received or trigger reached. Serviced by reading data. */ + SERIAL_IID_DATA = 4, + /** Second highest priority: stale data in FIFO. Serviced by reading data. */ + SERIAL_IID_STALE = 0xC, + /** Third priority: transmitter buffer has room. Serviced by reading this reg/writing. */ + SERIAL_IID_THRE = 2, + /** Fourth priority: MSR change. Serviced by reading MSR. */ + SERIAL_IID_MODEM = 0, }; enum SERIAL_LCR { @@ -115,14 +155,14 @@ enum SERIAL_MSR { struct serial_config { - uint8_t divisor_lo, divisor_hi; + uint16_t divisor; uint8_t ier, lcr, mcr; }; static unsigned serial_num_ports() { - uint8_t equipment = bda_get_byte(0x11); - uint8_t numports = (equipment & 0xE) >> 1; + uint16_t equipment = bda_get_equipment(); + uint8_t numports = (equipment & 0xE00) >> 9; return numports; } @@ -131,11 +171,31 @@ 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. + } + + // Even if BIOS says no, hardcode basic COM1/COM2 at least. + switch (port) { + case 1: return 0x3F8; + case 2: + return 0x2F8; + default: + return 0; + } +} + +static uint8_t serial_get_irq(unsigned port) +{ + switch (port) { + case 1: + case 3: + return 4; + case 2: + case 4: + return 3; + default: + return 0; } - return 0; } static void serial_save_config(unsigned iobase, struct serial_config *config) @@ -145,8 +205,7 @@ static void serial_save_config(unsigned iobase, struct serial_config *config) 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); + config->divisor = inpw(iobase + SERIAL_DIVISOR); // Restore DLAB to whatever it was outp(iobase + SERIAL_LCR, config->lcr); } @@ -154,22 +213,34 @@ static void serial_save_config(unsigned iobase, struct serial_config *config) 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); + outpw(iobase + SERIAL_DIVISOR, config->divisor); 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) +/// Configure line characteristics (speed, databytes, etc.) +/// Disables interrupts +static void serial_configure_line(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); + outpw(iobase + SERIAL_DIVISOR, divisor); 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); +} + +/// Configures when exceptions are going to be raised +/// it also clears all pending interrupts +/// and enables/disables the OUT2 gator here, which I'm not sure if is conceptually clean +static void serial_configure_interrupts(unsigned iobase, uint8_t ier) +{ + uint8_t mcr = inp(iobase + SERIAL_MCR); + outp(iobase + SERIAL_IER, ier); + if (ier) { + mcr |= SERIAL_MCR_OUT2; // Actually enables IRQ line for this UART + } else { + mcr &= ~SERIAL_MCR_OUT2; + } + outp(iobase + SERIAL_MCR, mcr); } static inline void serial_set_modem_control(unsigned iobase, uint8_t mcr) @@ -177,9 +248,14 @@ 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) +static inline void serial_set_fifo_control(unsigned iobase, uint8_t fcr) { - outp(iobase + SERIAL_MSR, msr); + outp(iobase + SERIAL_FCR, fcr); +} + +static inline uint8_t serial_read_pending_interrupt(unsigned iobase) +{ + return inp(iobase + SERIAL_IIR) & SERIAL_IIR_ID; } static inline uint8_t serial_get_line_status(unsigned iobase) @@ -187,6 +263,11 @@ static inline uint8_t serial_get_line_status(unsigned iobase) return inp(iobase + SERIAL_LSR); } +static inline uint8_t serial_get_modem_status(unsigned iobase) +{ + return inp(iobase + SERIAL_MSR); +} + static inline bool serial_data_ready(unsigned iobase) { return serial_get_line_status(iobase) & SERIAL_LSR_DR; |
