summaryrefslogtreecommitdiffstats
path: root/arch/x86_64/serial.c
blob: 1b49e3f883de2f1d2e3c3e1fe717a22798f94d10 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#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++));
}