1 /*
2  * vdprintf.c
3  */
4 
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdarg.h>
8 #include <unistd.h>
9 #include <inttypes.h>
10 #include <sys/io.h>
11 #include <sys/cpu.h>
12 
13 #ifdef DEBUG_PORT
14 
15 #define BUFFER_SIZE	4096
16 
17 enum serial_port_regs {
18     THR = 0,
19     RBR = 0,
20     DLL = 0,
21     DLM = 1,
22     IER = 1,
23     IIR = 2,
24     FCR = 2,
25     LCR = 3,
26     MCR = 4,
27     LSR = 5,
28     MSR = 6,
29     SCR = 7,
30 };
31 
32 static const uint16_t debug_base = DEBUG_PORT;
33 
debug_putc(char c)34 static void debug_putc(char c)
35 {
36     if (c == '\n')
37 	debug_putc('\r');
38 
39     while ((inb(debug_base + LSR) & 0x20) == 0)
40 	cpu_relax();
41     outb(c, debug_base + THR);
42 }
43 
vdprintf(const char * format,va_list ap)44 void vdprintf(const char *format, va_list ap)
45 {
46     int rv;
47     char buffer[BUFFER_SIZE];
48     char *p;
49     static bool debug_init = false;
50     static bool debug_ok   = false;
51 
52     rv = vsnprintf(buffer, BUFFER_SIZE, format, ap);
53     if (rv < 0)
54 	return;
55 
56     if (rv > BUFFER_SIZE - 1)
57 	rv = BUFFER_SIZE - 1;
58 
59     /*
60      * This unconditionally outputs to a serial port at 0x3f8 regardless of
61      * if one is enabled or not (this means we don't have to enable the real
62      * serial console and therefore get conflicting output.)
63      */
64     if (__unlikely(!debug_init)) {
65 	uint8_t dll, dlm, lcr;
66 
67 	debug_init = true;
68 
69 	cli();
70 
71 	/* Initialize the serial port to 115200 n81 with FIFOs enabled */
72 	outb(0x83, debug_base + LCR);
73 	outb(0x01, debug_base + DLL);
74 	outb(0x00, debug_base + DLM);
75 	(void)inb(debug_base + IER);	/* Synchronize */
76 	dll = inb(debug_base + DLL);
77 	dlm = inb(debug_base + DLM);
78 	lcr = inb(debug_base + LCR);
79 
80 	outb(0x03, debug_base + LCR);
81 	(void)inb(debug_base + IER);	/* Synchronize */
82 
83 	outb(0x00, debug_base + IER);
84 	(void)inb(debug_base + IER);	/* Synchronize */
85 
86 	sti();
87 
88 	if (dll != 0x01 || dlm != 0x00 || lcr != 0x83) {
89 	    /* No serial port present */
90 	    return;
91 	}
92 
93 	outb(0x01, debug_base + FCR);
94 	(void)inb(debug_base + IER);	/* Synchronize */
95 	if (inb(debug_base + IIR) < 0xc0) {
96 	    outb(0x00, debug_base + FCR); /* Disable non-functional FIFOs */
97 	    (void)inb(debug_base + IER);	/* Synchronize */
98 	}
99 
100 	debug_ok = true;
101     }
102 
103     if (!debug_ok)
104 	return;
105 
106     p = buffer;
107     while (rv--)
108 	debug_putc(*p++);
109 }
110 
111 #endif /* DEBUG_PORT */
112