xref: /netbsd-src/sys/arch/i386/stand/lib/pcio.c (revision ace896fac114f559f7469472324fbe68bbe378e5)
1 /*	$NetBSD: pcio.c,v 1.6 1997/10/27 19:53:20 drochner Exp $	 */
2 
3 /*
4  * Copyright (c) 1996, 1997
5  *	Matthias Drochner.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed for the NetBSD Project
18  *	by Matthias Drochner.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 
35 /*
36  * console I/O
37  * needs lowlevel routines from conio.S and comio.S
38  */
39 
40 #include <lib/libsa/stand.h>
41 #include <lib/libkern/libkern.h>
42 
43 #include "libi386.h"
44 #include "bootinfo.h"
45 
46 extern void conputc __P((int));
47 extern int congetc __P((void));
48 extern int coniskey __P((void));
49 
50 struct btinfo_console btinfo_console;
51 
52 #ifdef SUPPORT_SERIAL
53 static int iodev;
54 
55 #ifdef DIRECT_SERIAL
56 #include "comio_direct.h"
57 
58 #define cominit cominit_d
59 #define computc computc_d
60 #define comgetc comgetc_d
61 /* comstatus() is different */
62 
63 #define SERIAL_ARG btinfo_console.addr
64 #else
65 extern void cominit __P((int));
66 extern int computc __P((int, int));
67 extern int comgetc __P((int));
68 extern int comstatus __P((int));
69 
70 #define SERIAL_ARG (iodev - CONSDEV_COM0)
71 #endif /* DIRECT_SERIAL */
72 
73 static int getcomaddr __P((int));
74 #endif /* SUPPORT_SERIAL */
75 
76 #define POLL_FREQ 10
77 
78 #ifdef SUPPORT_SERIAL
79 static int
80 getcomaddr(idx)
81 int idx;
82 {
83 	short addr;
84 	/* read in BIOS data area */
85 	pvbcopy(0x400 + 2 * idx, &addr, 2);
86 	return(addr);
87 }
88 #endif
89 
90 void
91 initio(dev)
92 	int             dev;
93 {
94 #ifdef SUPPORT_SERIAL
95 	int i;
96 
97 	switch (dev) {
98 	    case CONSDEV_AUTO:
99 		for(i = 0; i < 3; i++) {
100 			iodev = CONSDEV_COM0 + i;
101 			btinfo_console.addr = getcomaddr(i);
102 			if(!btinfo_console.addr) break;
103 			conputc('0' + i); /* to tell user what happens */
104 			cominit(SERIAL_ARG);
105 #ifdef DIRECT_SERIAL
106 			/* check for:
107 			 *  1. successful output
108 			 *  2. optionally, keypress within 1s
109 			 */
110 			if(computc(' ', SERIAL_ARG)
111 #ifdef COMCONS_KEYPRESS
112 			   && awaitkey(1, 0)
113 #endif
114 			   )
115 				goto ok;
116 #else
117 			/*
118 			 * serial console must have hardware handshake!
119 			 * check:
120 			 *  1. character output without error
121 			 *  2. status bits for modem ready set
122 			 *     (status seems only useful after character output)
123 			 *  3. optionally, keypress within 1s
124 			 */
125 			if (!(computc(' ', SERIAL_ARG) & 0x80)
126 			    && (comstatus(SERIAL_ARG) & 0x00b0)
127 #ifdef COMCONS_KEYPRESS
128 			    && awaitkey(1, 0)
129 #endif
130 			    )
131 				goto ok;
132 #endif
133 		}
134 		iodev = CONSDEV_PC;
135 ok:
136 		break;
137 	    case CONSDEV_COM0:
138 	    case CONSDEV_COM1:
139 	    case CONSDEV_COM2:
140 	    case CONSDEV_COM3:
141 		iodev = dev;
142 		btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0);
143 		if(!btinfo_console.addr) goto nocom;
144 		cominit(SERIAL_ARG);
145 		break;
146 	    default:
147 nocom:
148 		iodev = CONSDEV_PC;
149 		break;
150 	}
151 	strncpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16);
152 #if defined(DIRECT_SERIAL) && defined(CONSPEED)
153 	btinfo_console.speed = CONSPEED;
154 #else
155 	btinfo_console.speed = 9600;
156 #endif
157 #else /* !SUPPORT_SERIAL */
158 	strncpy(btinfo_console.devname, "pc", 16);
159 #endif /* SUPPORT_SERIAL */
160 }
161 
162 static inline void
163 internal_putchar(c)
164 	int             c;
165 {
166 #ifdef SUPPORT_SERIAL
167 	switch (iodev) {
168 	    case CONSDEV_PC:
169 #endif
170 		conputc(c);
171 #ifdef SUPPORT_SERIAL
172 		break;
173 	    case CONSDEV_COM0:
174 	    case CONSDEV_COM1:
175 	    case CONSDEV_COM2:
176 	    case CONSDEV_COM3:
177 		computc(c, SERIAL_ARG);
178 		break;
179 	}
180 #endif
181 }
182 
183 void
184 putchar(c)
185 	int             c;
186 {
187 	if (c == '\n')
188 		internal_putchar('\r');
189 	internal_putchar(c);
190 }
191 
192 int
193 getchar()
194 {
195 #ifdef SUPPORT_SERIAL
196 	int c;
197 	switch (iodev) {
198 	    default: /* to make gcc -Wall happy... */
199 	    case CONSDEV_PC:
200 #endif
201 		return (congetc());
202 #ifdef SUPPORT_SERIAL
203 	    case CONSDEV_COM0:
204 	    case CONSDEV_COM1:
205 	    case CONSDEV_COM2:
206 	    case CONSDEV_COM3:
207 #ifdef DIRECT_SERIAL
208 		c = comgetc(SERIAL_ARG);
209 #else
210 		do {
211 			c = comgetc(SERIAL_ARG);
212 		} while ((c >> 8) == 0xe0); /* catch timeout */
213 #ifdef COMDEBUG
214 		if (c & 0x8000) {
215 			printf("com input %x, status %x\n",
216 			       c, comstatus(SERIAL_ARG));
217 		}
218 #endif
219 		c &= 0xff;
220 #endif /* DIRECT_SERIAL */
221 		return (c);
222 	}
223 #endif /* SUPPORT_SERIAL */
224 }
225 
226 int
227 iskey()
228 {
229 #ifdef SUPPORT_SERIAL
230 	switch (iodev) {
231 	    default: /* to make gcc -Wall happy... */
232 	    case CONSDEV_PC:
233 #endif
234 		return (coniskey());
235 #ifdef SUPPORT_SERIAL
236 	    case CONSDEV_COM0:
237 	    case CONSDEV_COM1:
238 	    case CONSDEV_COM2:
239 	    case CONSDEV_COM3:
240 #ifdef DIRECT_SERIAL
241 		return(!!comstatus_d(SERIAL_ARG));
242 #else
243 		return (!!(comstatus(SERIAL_ARG) & 0x0100));
244 #endif
245 	}
246 #endif /* SUPPORT_SERIAL */
247 }
248 
249 char
250 awaitkey(timeout, tell)
251 	int timeout, tell;
252 {
253 	int i;
254 	char c = 0;
255 
256 	i = timeout * POLL_FREQ;
257 
258 	while (i) {
259 		if (tell && (i % POLL_FREQ) == 0)
260 			printf("%d\b", i/POLL_FREQ);
261 		if (iskey()) {
262 			/* flush input buffer */
263 			while (iskey())
264 				c = getchar();
265 			goto out; /* XXX what happens if c == 0? */
266 		}
267 		delay(1000000 / POLL_FREQ);
268 		i--;
269 	}
270 
271 out:
272 	if (tell)
273 		printf("0\n");
274 
275 	return(c);
276 }
277