176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The serial port interface routines implement a simple polled i/o 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * interface to a standard serial port. Due to the space restrictions 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * for the boot blocks, no BIOS support is used (since BIOS requires 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * expensive real/protected mode switches), instead the rudimentary 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * BIOS support is duplicated here. 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The base address and speed for the i/o port are passed from the 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Makefile in the COMCONSOLE and CONSPEED preprocessor macros. The 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * line control parameters are currently hard-coded to 8 bits, no 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * parity, 1 stop bit (8N1). This can be changed in init_serial(). 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1476d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_OR_LATER ); 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "stddef.h" 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/init.h> 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/io.h> 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <unistd.h> 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/serial.h> 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "config/serial.h" 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Set default values if none specified */ 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef COMCONSOLE 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMCONSOLE 0x3f8 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef COMSPEED 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMSPEED 9600 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef COMDATA 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMDATA 8 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef COMPARITY 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMPARITY 0 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef COMSTOP 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMSTOP 1 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#undef UART_BASE 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_BASE ( COMCONSOLE ) 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#undef UART_BAUD 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_BAUD ( COMSPEED ) 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ((115200%UART_BAUD) != 0) 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#error Bad ttys0 baud rate 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMBRD (115200/UART_BAUD) 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Line Control Settings */ 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LCS ( ( ( (COMDATA) - 5 ) << 0 ) | \ 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ( ( (COMPARITY) ) << 3 ) | \ 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ( ( (COMSTOP) - 1 ) << 2 ) ) 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Data */ 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_RBR 0x00 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_TBR 0x00 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Control */ 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_IER 0x01 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_IIR 0x02 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_FCR 0x02 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LCR 0x03 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_MCR 0x04 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_DLL 0x00 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_DLM 0x01 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Status */ 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR 0x05 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_TEMPT 0x40 /* Transmitter empty */ 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_BI 0x10 /* Break interrupt indicator */ 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_FE 0x08 /* Frame error indicator */ 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_PE 0x04 /* Parity error indicator */ 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_OE 0x02 /* Overrun error indicator */ 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_DR 0x01 /* Receiver data ready */ 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_MSR 0x06 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_SCR 0x07 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if defined(UART_MEM) 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define uart_readb(addr) readb((addr)) 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define uart_writeb(val,addr) writeb((val),(addr)) 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define uart_readb(addr) inb((addr)) 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define uart_writeb(val,addr) outb((val),(addr)) 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * void serial_putc(int ch); 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write character `ch' to port UART_BASE. 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid serial_putc ( int ch ) { 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status; 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman i = 1000; /* timeout */ 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while(--i > 0) { 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = uart_readb(UART_BASE + UART_LSR); 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (status & UART_LSR_THRE) { 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* TX buffer emtpy */ 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(ch, UART_BASE + UART_TBR); 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mdelay(2); 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * int serial_getc(void); 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Read a character from port UART_BASE. 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint serial_getc ( void ) { 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status; 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ch; 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = uart_readb(UART_BASE + UART_LSR); 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while((status & 1) == 0); 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ch = uart_readb(UART_BASE + UART_RBR); /* fetch (first) character */ 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ch &= 0x7f; /* remove any parity bits we get */ 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ch == 0x7f) { /* Make DEL... look like BS */ 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ch = 0x08; 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ch; 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * int serial_ischar(void); 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * If there is a character in the input buffer of port UART_BASE, 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * return nonzero; otherwise return 0. 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint serial_ischar ( void ) { 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status; 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = uart_readb(UART_BASE + UART_LSR); /* line status reg; */ 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return status & 1; /* rx char available */ 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * int serial_init(void); 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initialize port UART_BASE to speed COMSPEED, line settings 8N1. 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void serial_init ( void ) { 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status; 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int divisor, lcs; 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Serial port %#x initialising\n", UART_BASE ); 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman divisor = COMBRD; 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lcs = UART_LCS; 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifdef COMPRESERVE 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lcs = uart_readb(UART_BASE + UART_LCR) & 0x7f; 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0x80 | lcs, UART_BASE + UART_LCR); 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman divisor = (uart_readb(UART_BASE + UART_DLM) << 8) | uart_readb(UART_BASE + UART_DLL); 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(lcs, UART_BASE + UART_LCR); 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set Baud Rate Divisor to COMSPEED, and test to see if the 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * serial port appears to be present. 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0x80 | lcs, UART_BASE + UART_LCR); 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0xaa, UART_BASE + UART_DLL); 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (uart_readb(UART_BASE + UART_DLL) != 0xaa) { 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE ); 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0x55, UART_BASE + UART_DLL); 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (uart_readb(UART_BASE + UART_DLL) != 0x55) { 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE ); 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(divisor & 0xff, UART_BASE + UART_DLL); 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (uart_readb(UART_BASE + UART_DLL) != (divisor & 0xff)) { 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Serial port %#x UART_DLL failed\n", UART_BASE ); 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0xaa, UART_BASE + UART_DLM); 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (uart_readb(UART_BASE + UART_DLM) != 0xaa) { 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE ); 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0x55, UART_BASE + UART_DLM); 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (uart_readb(UART_BASE + UART_DLM) != 0x55) { 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE ); 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb((divisor >> 8) & 0xff, UART_BASE + UART_DLM); 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (uart_readb(UART_BASE + UART_DLM) != ((divisor >> 8) & 0xff)) { 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG ( "Serial port %#x UART_DLM failed\n", UART_BASE ); 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(lcs, UART_BASE + UART_LCR); 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* disable interrupts */ 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0x0, UART_BASE + UART_IER); 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* disable fifo's */ 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0x00, UART_BASE + UART_FCR); 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set clear to send, so flow control works... */ 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb((1<<1), UART_BASE + UART_MCR); 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Flush the input buffer. */ 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* rx buffer reg 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * throw away (unconditionally the first time) 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (void) uart_readb(UART_BASE + UART_RBR); 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* line status reg */ 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = uart_readb(UART_BASE + UART_LSR); 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while(status & UART_LSR_DR); 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman out: 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * void serial_fini(void); 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Cleanup our use of the serial port, in particular flush the 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * output buffer so we don't accidentially lose characters. 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void serial_fini ( int flags __unused ) { 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i, status; 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Flush the output buffer to avoid dropping characters, 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * if we are reinitializing the serial port. 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman i = 10000; /* timeout */ 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = uart_readb(UART_BASE + UART_LSR); 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while((--i > 0) && !(status & UART_LSR_TEMPT)); 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Don't mark it as disabled; it's still usable */ 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Serial driver initialisation function 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initialise serial port early on so that it is available to capture 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * early debug messages. 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct init_fn serial_init_fn __init_fn ( INIT_SERIAL ) = { 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .initialise = serial_init, 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Serial driver startup function */ 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct startup_fn serial_startup_fn __startup_fn ( STARTUP_EARLY ) = { 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .shutdown = serial_fini, 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 255