/* Serial Port Driver for CubeCactusOS
* COM1 (0x3F8) - Primary serial port
* Provides reliable input/output via QEMU serial
*/
#include <stdint.h>
#define SERIAL_COM1 0x3F8
/* Serial port registers (offset from COM1) */
#define SERIAL_DATA 0 /* Data register (read/write) */
#define SERIAL_INT_ENABLE 1 /* Interrupt enable */
#define SERIAL_FIFO_CTRL 2 /* FIFO control */
#define SERIAL_LINE_CTRL 3 /* Line control */
#define SERIAL_MODEM_CTRL 4 /* Modem control */
#define SERIAL_LINE_STATUS 5 /* Line status */
extern void outb(uint16_t port, uint8_t value);
extern uint8_t inb(uint16_t port);
/* Initialize serial port */
void serial_init() {
outb(SERIAL_COM1 + SERIAL_INT_ENABLE, 0x00); /* Disable interrupts */
outb(SERIAL_COM1 + SERIAL_LINE_CTRL, 0x80); /* Enable DLAB (set baud rate divisor) */
outb(SERIAL_COM1 + 0, 0x03); /* Set divisor to 3 (lo byte) 38400 baud */
outb(SERIAL_COM1 + 1, 0x00); /* (hi byte) */
outb(SERIAL_COM1 + SERIAL_LINE_CTRL, 0x03); /* 8 bits, no parity, one stop bit */
outb(SERIAL_COM1 + SERIAL_FIFO_CTRL, 0xC7); /* Enable FIFO, clear them, 14-byte threshold */
outb(SERIAL_COM1 + SERIAL_MODEM_CTRL, 0x0B); /* IRQs enabled, RTS/DSR set */
}
/* Check if serial port can transmit */
static int serial_is_transmit_empty() {
return inb(SERIAL_COM1 + SERIAL_LINE_STATUS) & 0x20;
}
/* Send a character to serial port */
void serial_putchar(char c) {
/* Wait for transmit buffer to be empty */
while (!serial_is_transmit_empty());
outb(SERIAL_COM1 + SERIAL_DATA, c);
}
/* Send a string to serial port */
void serial_puts(const char* str) {
while (*str) {
serial_putchar(*str++);
}
}
/* Check if serial port has received data */
static int serial_received() {
return inb(SERIAL_COM1 + SERIAL_LINE_STATUS) & 0x01;
}
/* Read a character from serial port (blocking) */
char serial_getchar() {
/* Wait for data to be received */
while (!serial_received());
return inb(SERIAL_COM1 + SERIAL_DATA);
}
/* Check if character is available (non-blocking) */
int serial_available() {
return serial_received();
}