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 Hartman#include <stddef.h> 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <sys/io.h> 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "serial.h" 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Set default values if none specified */ 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef COMCONSOLE 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMCONSOLE 0x3f8 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef COMSPEED 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMSPEED 9600 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef COMDATA 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMDATA 8 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef COMPARITY 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMPARITY 0 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef COMSTOP 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMSTOP 1 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#undef UART_BASE 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_BASE ( COMCONSOLE ) 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#undef UART_BAUD 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_BAUD ( COMSPEED ) 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ((115200%UART_BAUD) != 0) 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#error Bad ttys0 baud rate 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define COMBRD (115200/UART_BAUD) 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Line Control Settings */ 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LCS ( ( ( (COMDATA) - 5 ) << 0 ) | \ 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ( ( (COMPARITY) ) << 3 ) | \ 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ( ( (COMSTOP) - 1 ) << 2 ) ) 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Data */ 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_RBR 0x00 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_TBR 0x00 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Control */ 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_IER 0x01 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_IIR 0x02 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_FCR 0x02 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LCR 0x03 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_MCR 0x04 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_DLL 0x00 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_DLM 0x01 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Status */ 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR 0x05 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_TEMPT 0x40 /* Transmitter empty */ 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_BI 0x10 /* Break interrupt indicator */ 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_FE 0x08 /* Frame error indicator */ 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_PE 0x04 /* Parity error indicator */ 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_OE 0x02 /* Overrun error indicator */ 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_LSR_DR 0x01 /* Receiver data ready */ 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_MSR 0x06 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define UART_SCR 0x07 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define uart_readb(addr) inb(addr) 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define uart_writeb(val,addr) outb((val),(addr)) 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * void serial_putc(int ch); 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write character `ch' to port UART_BASE. 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid serial_putc(int ch) 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status; 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (;;) { 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = uart_readb(UART_BASE + UART_LSR); 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (status & UART_LSR_THRE) { 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* TX buffer emtpy */ 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(ch, UART_BASE + UART_TBR); 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * int serial_getc(void); 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Read a character from port UART_BASE. 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint serial_getc(void) 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status; 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ch; 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = uart_readb(UART_BASE + UART_LSR); 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while ((status & 1) == 0); 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ch = uart_readb(UART_BASE + UART_RBR); /* fetch (first) character */ 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ch &= 0x7f; /* remove any parity bits we get */ 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ch == 0x7f) { /* Make DEL... look like BS */ 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ch = 0x08; 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ch; 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * int serial_init(void); 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initialize port UART_BASE to speed COMSPEED, line settings 8N1. 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid serial_init(void) 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int status; 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int divisor, lcs; 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman divisor = COMBRD; 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lcs = UART_LCS; 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifdef COMPRESERVE 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lcs = uart_readb(UART_BASE + UART_LCR) & 0x7f; 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0x80 | lcs, UART_BASE + UART_LCR); 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman divisor = 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (uart_readb(UART_BASE + UART_DLM) << 8) | uart_readb(UART_BASE + 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman UART_DLL); 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(lcs, UART_BASE + UART_LCR); 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set Baud Rate Divisor to COMSPEED, and test to see if the 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * serial port appears to be present. 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0x80 | lcs, UART_BASE + UART_LCR); 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0xaa, UART_BASE + UART_DLL); 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (uart_readb(UART_BASE + UART_DLL) != 0xaa) { 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0x55, UART_BASE + UART_DLL); 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (uart_readb(UART_BASE + UART_DLL) != 0x55) { 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(divisor & 0xff, UART_BASE + UART_DLL); 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (uart_readb(UART_BASE + UART_DLL) != (divisor & 0xff)) { 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0xaa, UART_BASE + UART_DLM); 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (uart_readb(UART_BASE + UART_DLM) != 0xaa) { 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0x55, UART_BASE + UART_DLM); 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (uart_readb(UART_BASE + UART_DLM) != 0x55) { 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb((divisor >> 8) & 0xff, UART_BASE + UART_DLM); 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (uart_readb(UART_BASE + UART_DLM) != ((divisor >> 8) & 0xff)) { 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(lcs, UART_BASE + UART_LCR); 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* disable interrupts */ 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0x0, UART_BASE + UART_IER); 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* disable fifo's */ 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb(0x00, UART_BASE + UART_FCR); 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set clear to send, so flow control works... */ 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uart_writeb((1 << 1), UART_BASE + UART_MCR); 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Flush the input buffer. */ 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* rx buffer reg 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * throw away (unconditionally the first time) 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (void)uart_readb(UART_BASE + UART_RBR); 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* line status reg */ 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = uart_readb(UART_BASE + UART_LSR); 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while (status & UART_LSR_DR); 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout: 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 194