aboutsummaryrefslogtreecommitdiffstats
path: root/com32/sysdump/serial.c
blob: 75bbd48181500b69bee59ea382cdf9e53ebbe42b (plain)
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <stdbool.h>
#include <stdio.h>
#include <sys/io.h>

#include "file.h"

enum {
    THR = 0,
    RBR = 0,
    DLL = 0,
    DLM = 1,
    IER = 1,
    IIR = 2,
    FCR = 2,
    LCR = 3,
    MCR = 4,
    LSR = 5,
    MSR = 6,
    SCR = 7,
};

int serial_init(struct serial_if *sif)
{
    uint16_t port = sif->port;
    uint8_t dll, dlm, lcr;

    /* Set 115200n81 */
    outb(0x83, port + LCR);
    outb(0x01, port + DLL);
    outb(0x00, port + DLM);
    (void)inb(port + IER);	/* Synchronize */
    dll = inb(port + DLL);
    dlm = inb(port + DLM);
    lcr = inb(port + LCR);
    outb(0x03, port + LCR);
    (void)inb(port + IER);	/* Synchronize */

    if (dll != 0x01 || dlm != 0x00 || lcr != 0x83)
	return -1;		/* This doesn't look like a serial port */

    /* Disable interrupts */
    outb(port + IER, 0);

    /* Enable 16550A FIFOs if available */
    outb(port + FCR, 0x01);	/* Enable FIFO */
    (void)inb(port + IER);	/* Synchronize */
    if (inb(port + IIR) < 0xc0)
	outb(port + FCR, 0x00);	/* Disable FIFOs if non-functional */
    (void)inb(port + IER);	/* Synchronize */

    return 0;
}

void serial_write(struct serial_if *sif, const void *data, size_t n)
{
    uint16_t port = sif->port;
    const char *p = data;
    uint8_t lsr;

    while (n--) {
	do {
	    lsr = inb(port + LSR);
	} while (!(lsr & 0x20));

	outb(*p++, port + THR);
    }
}

void serial_read(struct serial_if *sif, void *data, size_t n)
{
    uint16_t port = sif->port;
    char *p = data;
    uint8_t lsr;

    while (n--) {
	do {
	    lsr = inb(port + LSR);
	} while (!(lsr & 0x01));

	*p++ = inb(port + RBR);
    }
}