/* * vdprintf.c */ #include #include #include #include #include #include #include #undef DEBUG #define DEBUG 1 #include #define BUFFER_SIZE 4096 enum serial_port_regs { THR = 0, RBR = 0, DLL = 0, DLM = 1, IER = 1, IIR = 2, FCR = 2, LCR = 3, MCR = 4, LSR = 5, MSR = 6, SCR = 7, }; #ifndef DEBUG_PORT # define DEBUG_PORT 0x03f8 /* I/O base address */ #endif static const uint16_t debug_base = DEBUG_PORT; static void debug_putc(char c) { if (c == '\n') debug_putc('\r'); while ((inb(debug_base + LSR) & 0x20) == 0) cpu_relax(); outb(c, debug_base + THR); } void vdprintf(const char *format, va_list ap) { int rv; char buffer[BUFFER_SIZE]; char *p; static bool debug_init = false; static bool debug_ok = false; rv = vsnprintf(buffer, BUFFER_SIZE, format, ap); if (rv < 0) return; if (rv > BUFFER_SIZE - 1) rv = BUFFER_SIZE - 1; /* * This unconditionally outputs to a serial port at 0x3f8 regardless of * if one is enabled or not (this means we don't have to enable the real * serial console and therefore get conflicting output.) */ if (__unlikely(!debug_init)) { uint8_t dll, dlm, lcr; debug_init = true; cli(); /* Initialize the serial port to 115200 n81 with FIFOs enabled */ outb(0x83, debug_base + LCR); outb(0x01, debug_base + DLL); outb(0x00, debug_base + DLM); (void)inb(debug_base + IER); /* Synchronize */ dll = inb(debug_base + DLL); dlm = inb(debug_base + DLM); lcr = inb(debug_base + LCR); outb(0x03, debug_base + LCR); (void)inb(debug_base + IER); /* Synchronize */ outb(0x00, debug_base + IER); (void)inb(debug_base + IER); /* Synchronize */ sti(); if (dll != 0x01 || dlm != 0x00 || lcr != 0x83) { /* No serial port present */ return; } outb(0x01, debug_base + FCR); (void)inb(debug_base + IER); /* Synchronize */ if (inb(debug_base + IIR) < 0xc0) { outb(0x00, debug_base + FCR); /* Disable non-functional FIFOs */ (void)inb(debug_base + IER); /* Synchronize */ } debug_ok = true; } if (!debug_ok) return; p = buffer; while (rv--) debug_putc(*p++); }