• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * The serial port interface routines implement a simple polled i/o
3  * interface to a standard serial port.  Due to the space restrictions
4  * for the boot blocks, no BIOS support is used (since BIOS requires
5  * expensive real/protected mode switches), instead the rudimentary
6  * BIOS support is duplicated here.
7  *
8  * The base address and speed for the i/o port are passed from the
9  * Makefile in the COMCONSOLE and CONSPEED preprocessor macros.  The
10  * line control parameters are currently hard-coded to 8 bits, no
11  * parity, 1 stop bit (8N1).  This can be changed in init_serial().
12  */
13 
14 #include <stddef.h>
15 #include <sys/io.h>
16 #include "serial.h"
17 
18 /* Set default values if none specified */
19 
20 #ifndef COMCONSOLE
21 #define COMCONSOLE	0x3f8
22 #endif
23 
24 #ifndef COMSPEED
25 #define COMSPEED	9600
26 #endif
27 
28 #ifndef COMDATA
29 #define COMDATA		8
30 #endif
31 
32 #ifndef COMPARITY
33 #define COMPARITY	0
34 #endif
35 
36 #ifndef COMSTOP
37 #define COMSTOP		1
38 #endif
39 
40 #undef UART_BASE
41 #define UART_BASE ( COMCONSOLE )
42 
43 #undef UART_BAUD
44 #define UART_BAUD ( COMSPEED )
45 
46 #if ((115200%UART_BAUD) != 0)
47 #error Bad ttys0 baud rate
48 #endif
49 
50 #define COMBRD (115200/UART_BAUD)
51 
52 /* Line Control Settings */
53 #define UART_LCS ( ( ( (COMDATA) - 5 )	<< 0 ) | \
54 		   ( ( (COMPARITY) )	<< 3 ) | \
55 		   ( ( (COMSTOP) - 1 )	<< 2 ) )
56 
57 /* Data */
58 #define UART_RBR 0x00
59 #define UART_TBR 0x00
60 
61 /* Control */
62 #define UART_IER 0x01
63 #define UART_IIR 0x02
64 #define UART_FCR 0x02
65 #define UART_LCR 0x03
66 #define UART_MCR 0x04
67 #define UART_DLL 0x00
68 #define UART_DLM 0x01
69 
70 /* Status */
71 #define UART_LSR 0x05
72 #define  UART_LSR_TEMPT 0x40	/* Transmitter empty */
73 #define  UART_LSR_THRE  0x20	/* Transmit-hold-register empty */
74 #define  UART_LSR_BI	0x10	/* Break interrupt indicator */
75 #define  UART_LSR_FE	0x08	/* Frame error indicator */
76 #define  UART_LSR_PE	0x04	/* Parity error indicator */
77 #define  UART_LSR_OE	0x02	/* Overrun error indicator */
78 #define  UART_LSR_DR	0x01	/* Receiver data ready */
79 
80 #define UART_MSR 0x06
81 #define UART_SCR 0x07
82 
83 #define uart_readb(addr) inb(addr)
84 #define uart_writeb(val,addr) outb((val),(addr))
85 
86 /*
87  * void serial_putc(int ch);
88  *	Write character `ch' to port UART_BASE.
89  */
serial_putc(int ch)90 void serial_putc(int ch)
91 {
92     int status;
93     for (;;) {
94 	status = uart_readb(UART_BASE + UART_LSR);
95 	if (status & UART_LSR_THRE) {
96 	    /* TX buffer emtpy */
97 	    uart_writeb(ch, UART_BASE + UART_TBR);
98 	    break;
99 	}
100     }
101 }
102 
103 /*
104  * int serial_getc(void);
105  *	Read a character from port UART_BASE.
106  */
serial_getc(void)107 int serial_getc(void)
108 {
109     int status;
110     int ch;
111     do {
112 	status = uart_readb(UART_BASE + UART_LSR);
113     } while ((status & 1) == 0);
114     ch = uart_readb(UART_BASE + UART_RBR);	/* fetch (first) character */
115     ch &= 0x7f;			/* remove any parity bits we get */
116     if (ch == 0x7f) {		/* Make DEL... look like BS */
117 	ch = 0x08;
118     }
119     return ch;
120 }
121 
122 /*
123  * int serial_init(void);
124  *	Initialize port UART_BASE to speed COMSPEED, line settings 8N1.
125  */
serial_init(void)126 void serial_init(void)
127 {
128     int status;
129     int divisor, lcs;
130 
131     divisor = COMBRD;
132     lcs = UART_LCS;
133 
134 #ifdef COMPRESERVE
135     lcs = uart_readb(UART_BASE + UART_LCR) & 0x7f;
136     uart_writeb(0x80 | lcs, UART_BASE + UART_LCR);
137     divisor =
138 	(uart_readb(UART_BASE + UART_DLM) << 8) | uart_readb(UART_BASE +
139 							     UART_DLL);
140     uart_writeb(lcs, UART_BASE + UART_LCR);
141 #endif
142 
143     /* Set Baud Rate Divisor to COMSPEED, and test to see if the
144      * serial port appears to be present.
145      */
146     uart_writeb(0x80 | lcs, UART_BASE + UART_LCR);
147     uart_writeb(0xaa, UART_BASE + UART_DLL);
148     if (uart_readb(UART_BASE + UART_DLL) != 0xaa) {
149 	goto out;
150     }
151     uart_writeb(0x55, UART_BASE + UART_DLL);
152     if (uart_readb(UART_BASE + UART_DLL) != 0x55) {
153 	goto out;
154     }
155     uart_writeb(divisor & 0xff, UART_BASE + UART_DLL);
156     if (uart_readb(UART_BASE + UART_DLL) != (divisor & 0xff)) {
157 	goto out;
158     }
159     uart_writeb(0xaa, UART_BASE + UART_DLM);
160     if (uart_readb(UART_BASE + UART_DLM) != 0xaa) {
161 	goto out;
162     }
163     uart_writeb(0x55, UART_BASE + UART_DLM);
164     if (uart_readb(UART_BASE + UART_DLM) != 0x55) {
165 	goto out;
166     }
167     uart_writeb((divisor >> 8) & 0xff, UART_BASE + UART_DLM);
168     if (uart_readb(UART_BASE + UART_DLM) != ((divisor >> 8) & 0xff)) {
169 	goto out;
170     }
171     uart_writeb(lcs, UART_BASE + UART_LCR);
172 
173     /* disable interrupts */
174     uart_writeb(0x0, UART_BASE + UART_IER);
175 
176     /* disable fifo's */
177     uart_writeb(0x00, UART_BASE + UART_FCR);
178 
179     /* Set clear to send, so flow control works... */
180     uart_writeb((1 << 1), UART_BASE + UART_MCR);
181 
182     /* Flush the input buffer. */
183     do {
184 	/* rx buffer reg
185 	 * throw away (unconditionally the first time)
186 	 */
187 	(void)uart_readb(UART_BASE + UART_RBR);
188 	/* line status reg */
189 	status = uart_readb(UART_BASE + UART_LSR);
190     } while (status & UART_LSR_DR);
191 out:
192     return;
193 }
194