#include "serial.h"
#include "uart.h"
#include "io/log.h"
static struct LogDevice s_serial_logdev =
{ .out = serial_out, .chain = NULL };
bool serial_supported = true;
void
serial_setup(void)
{
/* Disable interrupts. */
poutb(SERIAL_UART_COM_IER(SERIAL_UART_COM1), 0x0);
/* Enable DLAB. */
poutb(SERIAL_UART_COM_LCR(SERIAL_UART_COM1), 0x80);
/* Set divisor to 3 (38400 baud)*/
poutb(SERIAL_UART_COM_DLAB_DLL(SERIAL_UART_COM1), 3);
poutb(SERIAL_UART_COM_DLAB_DLH(SERIAL_UART_COM1), 0);
/* Set flags for LCR (8 bits, no parity, one stop)*/
poutb(SERIAL_UART_COM_LCR(SERIAL_UART_COM1), 1 | 2);
/* Enable & clear FIFO, 14-byte threshold */
poutb(SERIAL_UART_COM_FCR(SERIAL_UART_COM1), 1 | 2 | 4 | 0xC0);
/* Enable interrupts, set RTS/DSR. */
poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 1 | 2 | 8);
/* Set loopback mode for testing. */
poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 2 | 4 | 8 | 0x10);
/* Test serial output. */
poutb(SERIAL_UART_COM1, 0xAE);
if(pinb(SERIAL_UART_COM1) != 0xAE) {
serial_supported = false;
return;
}
/* Serial is not faulty.
* No loopback, enable output 1 & 2.*/
poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 1 | 2 | 4 | 8);
klog_newdev(&s_serial_logdev);
}
static ALWAYS_INLINE bool
serial_transmit_empty(uint16_t com)
{
return pinb(SERIAL_UART_COM_LSR(com) & 0x20);
}
static inline void
serial_outb(uint16_t com, uint8_t b)
{
if(b == '\n') serial_outb(com, '\r');
while(!serial_transmit_empty(SERIAL_UART_COM1));
poutb(com, b);
}
void
serial_out(const char *s, size_t len)
{
if(!serial_supported) return;
for(; len > 0; len--)
serial_outb(SERIAL_UART_COM1, *(s++));
}