xref: /netbsd-src/sys/arch/i386/stand/lib/pcio.c (revision 1c9b56c830954ccf3b57004ac65562e3d6afacf6)
1 /*	$NetBSD: pcio.c,v 1.19 2005/01/27 18:20:45 mycroft 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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
29 /*
30  * console I/O
31  * needs lowlevel routines from conio.S and comio.S
32  */
33 
34 #include <lib/libsa/stand.h>
35 #include <lib/libkern/libkern.h>
36 #include <sys/bootblock.h>
37 
38 #include "libi386.h"
39 #include "bootinfo.h"
40 
41 extern void conputc __P((int));
42 extern int congetc __P((void));
43 extern int conisshift __P((void));
44 extern int coniskey __P((void));
45 extern struct x86_boot_params boot_params;
46 
47 struct btinfo_console btinfo_console;
48 
49 #ifdef SUPPORT_SERIAL
50 static int iodev;
51 
52 #ifdef DIRECT_SERIAL
53 #include "comio_direct.h"
54 
55 #define cominit_x()	cominit_d(btinfo_console.addr, btinfo_console.speed)
56 #define computc_x(ch)	computc_d(ch, btinfo_console.addr)
57 #define comgetc_x()	comgetc_d(btinfo_console.addr)
58 #define comstatus_x()	comstatus_d(btinfo_console.addr)
59 
60 #else
61 #define cominit_x()	cominit(iodev - CONSDEV_COM0)
62 #define computc_x(ch)	computc(ch, iodev - CONSDEV_COM0)
63 #define comgetc_x()	comgetc(iodev - CONSDEV_COM0)
64 #define comstatus_x()	comstatus(iodev - CONSDEV_COM0)
65 
66 #endif /* DIRECT_SERIAL */
67 
68 static int getcomaddr __P((int));
69 #endif /* SUPPORT_SERIAL */
70 
71 #define POLL_FREQ 10
72 
73 #ifdef SUPPORT_SERIAL
74 static int
75 getcomaddr(idx)
76 	int idx;
77 {
78 	short addr;
79 #ifdef CONSADDR
80 	if (CONSADDR != 0)
81 		return CONSADDR;
82 #endif
83 	/* read in BIOS data area */
84 	pvbcopy((void *)(0x400 + 2 * idx), &addr, 2);
85 	return(addr);
86 }
87 #endif
88 
89 void
90 initio(dev)
91 	int             dev;
92 {
93 #ifdef SUPPORT_SERIAL
94 	int i;
95 
96 #if defined(DIRECT_SERIAL) && defined(CONSPEED)
97 	btinfo_console.speed = CONSPEED;
98 #else
99 	btinfo_console.speed = 9600;
100 #endif
101 
102 	switch (dev) {
103 	    case CONSDEV_AUTO:
104 		for(i = 0; i < 3; i++) {
105 			iodev = CONSDEV_COM0 + i;
106 			btinfo_console.addr = getcomaddr(i);
107 			if(!btinfo_console.addr)
108 				break;
109 			conputc('0' + i); /* to tell user what happens */
110 			cominit_x();
111 #ifdef DIRECT_SERIAL
112 			/* check for:
113 			 *  1. successful output
114 			 *  2. optionally, keypress within 7s
115 			 */
116 			if (	computc_x(':') &&
117 				computc_x('-') &&
118 				computc_x('(')
119 #ifdef COMCONS_KEYPRESS
120 			   && awaitkey(7, 0)
121 #endif
122 			   )
123 				goto ok;
124 #else /* ! DIRECT_SERIAL */
125 			/*
126 			 * serial console must have hardware handshake!
127 			 * check:
128 			 *  1. character output without error
129 			 *  2. status bits for modem ready set
130 			 *     (status seems only useful after character output)
131 			 *  3. optionally, keypress within 7s
132 			 */
133 			if (!(computc_x('@') & 0x80)
134 			    && (comstatus_x() & 0x00b0)
135 #ifdef COMCONS_KEYPRESS
136 			    && awaitkey(7, 0)
137 #endif
138 			    )
139 				goto ok;
140 #endif /* DIRECT_SERIAL */
141 		}
142 		iodev = CONSDEV_PC;
143 ok:
144 		break;
145 	    case CONSDEV_COM0:
146 	    case CONSDEV_COM1:
147 	    case CONSDEV_COM2:
148 	    case CONSDEV_COM3:
149 		iodev = dev;
150 		btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0);
151 		if(!btinfo_console.addr)
152 			goto nocom;
153 		cominit_x();
154 		break;
155 	    case CONSDEV_COM0KBD:
156 	    case CONSDEV_COM1KBD:
157 	    case CONSDEV_COM2KBD:
158 	    case CONSDEV_COM3KBD:
159 		iodev = dev - CONSDEV_COM0KBD + CONSDEV_COM0;
160 		i = iodev - CONSDEV_COM0;
161 		btinfo_console.addr = getcomaddr(i);
162 		if(!btinfo_console.addr)
163 			goto nocom;
164 		conputc('0' + i); /* to tell user what happens */
165 		cominit_x();
166 #ifdef DIRECT_SERIAL
167 			/* check for:
168 			 *  1. successful output
169 			 *  2. optionally, keypress within 7s
170 			 */
171 			if (	computc_x(':') &&
172 				computc_x('-') &&
173 				computc_x('(')
174 #ifdef COMCONS_KEYPRESS
175 			   && awaitkey(7, 0)
176 #endif
177 			   )
178 				break;
179 #else /* ! DIRECT_SERIAL */
180 			/*
181 			 * serial console must have hardware handshake!
182 			 * check:
183 			 *  1. character output without error
184 			 *  2. status bits for modem ready set
185 			 *     (status seems only useful after character output)
186 			 *  3. optionally, keypress within 7s
187 			 */
188 			if (!(computc_x('@') & 0x80)
189 			    && (comstatus_x() & 0x00b0)
190 #ifdef COMCONS_KEYPRESS
191 			    && awaitkey(7, 0)
192 #endif
193 			    )
194 				break;
195 #endif /* DIRECT_SERIAL */
196 	    default:
197 nocom:
198 		iodev = CONSDEV_PC;
199 		break;
200 	}
201 	conputc('\015');
202 	conputc('\n');
203 	strncpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16);
204 #else /* !SUPPORT_SERIAL */
205 	btinfo_console.devname[0] = 'p';
206 	btinfo_console.devname[1] = 'c';
207 	btinfo_console.devname[2] = 0;
208 #endif /* SUPPORT_SERIAL */
209 }
210 
211 static inline void internal_putchar __P((int));
212 
213 static inline void
214 internal_putchar(c)
215 	int c;
216 {
217 #ifdef SUPPORT_SERIAL
218 	switch (iodev) {
219 	    case CONSDEV_PC:
220 #endif
221 		conputc(c);
222 #ifdef SUPPORT_SERIAL
223 		break;
224 	    case CONSDEV_COM0:
225 	    case CONSDEV_COM1:
226 	    case CONSDEV_COM2:
227 	    case CONSDEV_COM3:
228 		computc_x(c);
229 		break;
230 	}
231 #endif
232 }
233 
234 void
235 putchar(c)
236 	int c;
237 {
238 	if (c == '\n')
239 		internal_putchar('\r');
240 	internal_putchar(c);
241 }
242 
243 int
244 getchar()
245 {
246 	int c;
247 #ifdef SUPPORT_SERIAL
248 	switch (iodev) {
249 	    default: /* to make gcc -Wall happy... */
250 	    case CONSDEV_PC:
251 #endif
252 		c = congetc();
253 #ifdef CONSOLE_KEYMAP
254 		{
255 			char *cp = strchr(CONSOLE_KEYMAP, c);
256 			if (cp != 0 && cp[1] != 0)
257 				c = cp[1];
258 		}
259 #endif
260 		return c;
261 #ifdef SUPPORT_SERIAL
262 	    case CONSDEV_COM0:
263 	    case CONSDEV_COM1:
264 	    case CONSDEV_COM2:
265 	    case CONSDEV_COM3:
266 #ifdef DIRECT_SERIAL
267 		c = comgetc_x();
268 #else
269 		do {
270 			c = comgetc_x();
271 		} while ((c >> 8) == 0xe0); /* catch timeout */
272 #ifdef COMDEBUG
273 		if (c & 0x8000) {
274 			printf("com input %x, status %x\n",
275 			       c, comstatus_x());
276 		}
277 #endif
278 		c &= 0xff;
279 #endif /* DIRECT_SERIAL */
280 		return (c);
281 	}
282 #endif /* SUPPORT_SERIAL */
283 }
284 
285 int
286 iskey(int intr)
287 {
288 #ifdef SUPPORT_SERIAL
289 	switch (iodev) {
290 	    default: /* to make gcc -Wall happy... */
291 	    case CONSDEV_PC:
292 #endif
293 		return ((intr && conisshift()) || coniskey());
294 #ifdef SUPPORT_SERIAL
295 	    case CONSDEV_COM0:
296 	    case CONSDEV_COM1:
297 	    case CONSDEV_COM2:
298 	    case CONSDEV_COM3:
299 #ifdef DIRECT_SERIAL
300 		return(!!comstatus_x());
301 #else
302 		return (!!(comstatus_x() & 0x0100));
303 #endif
304 	}
305 #endif /* SUPPORT_SERIAL */
306 }
307 
308 char
309 awaitkey(timeout, tell)
310 	int timeout, tell;
311 {
312 	int i;
313 	char c = 0;
314 
315 	i = timeout * POLL_FREQ;
316 
317 	for (;;) {
318 		if (tell && (i % POLL_FREQ) == 0) {
319 			char numbuf[20];
320 			int len, j;
321 
322 			sprintf(numbuf, "%d ", i/POLL_FREQ);
323 			len = strlen(numbuf);
324 			for (j = 0; j < len; j++)
325 				numbuf[len + j] = '\b';
326 			numbuf[len + j] = '\0';
327 			printf(numbuf);
328 		}
329 		if (iskey(1)) {
330 			/* flush input buffer */
331 			while (iskey(0))
332 				c = getchar();
333 			if (c == 0)
334 				c = -1;
335 			goto out;
336 		}
337 		if (i--)
338 			delay(1000000 / POLL_FREQ);
339 		else
340 			break;
341 	}
342 
343 out:
344 	if (tell)
345 		printf("0 \n");
346 
347 	return(c);
348 }
349