Home | History | Annotate | Download | only in lib
      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 
     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 
     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