xref: /netbsd-src/sys/arch/i386/stand/lib/pcio.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: pcio.c,v 1.20 2005/11/11 22:25:09 dsl 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()	btinfo_console.speed = \
56 			    cominit_d(btinfo_console.addr, btinfo_console.speed)
57 #define computc_x(ch)	computc_d(ch, btinfo_console.addr)
58 #define comgetc_x()	comgetc_d(btinfo_console.addr)
59 #define comstatus_x()	comstatus_d(btinfo_console.addr)
60 
61 #else
62 #define cominit_x()	cominit(iodev - CONSDEV_COM0)
63 #define computc_x(ch)	computc(ch, iodev - CONSDEV_COM0)
64 #define comgetc_x()	comgetc(iodev - CONSDEV_COM0)
65 #define comstatus_x()	comstatus(iodev - CONSDEV_COM0)
66 
67 #endif /* DIRECT_SERIAL */
68 
69 static int getcomaddr __P((int));
70 #endif /* SUPPORT_SERIAL */
71 
72 #define POLL_FREQ 10
73 
74 #ifdef SUPPORT_SERIAL
75 static int
76 getcomaddr(idx)
77 	int idx;
78 {
79 	short addr;
80 #ifdef CONSADDR
81 	if (CONSADDR != 0)
82 		return CONSADDR;
83 #endif
84 	/* read in BIOS data area */
85 	pvbcopy((void *)(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 #if defined(DIRECT_SERIAL) && defined(CONSPEED)
98 	btinfo_console.speed = CONSPEED;
99 #else
100 	btinfo_console.speed = 9600;
101 #endif
102 
103 	switch (dev) {
104 	    case CONSDEV_AUTO:
105 		for(i = 0; i < 3; i++) {
106 			iodev = CONSDEV_COM0 + i;
107 			btinfo_console.addr = getcomaddr(i);
108 			if(!btinfo_console.addr)
109 				break;
110 			conputc('0' + i); /* to tell user what happens */
111 			cominit_x();
112 #ifdef DIRECT_SERIAL
113 			/* check for:
114 			 *  1. successful output
115 			 *  2. optionally, keypress within 7s
116 			 */
117 			if (	computc_x(':') &&
118 				computc_x('-') &&
119 				computc_x('(')
120 #ifdef COMCONS_KEYPRESS
121 			   && awaitkey(7, 0)
122 #endif
123 			   )
124 				goto ok;
125 #else /* ! DIRECT_SERIAL */
126 			/*
127 			 * serial console must have hardware handshake!
128 			 * check:
129 			 *  1. character output without error
130 			 *  2. status bits for modem ready set
131 			 *     (status seems only useful after character output)
132 			 *  3. optionally, keypress within 7s
133 			 */
134 			if (!(computc_x('@') & 0x80)
135 			    && (comstatus_x() & 0x00b0)
136 #ifdef COMCONS_KEYPRESS
137 			    && awaitkey(7, 0)
138 #endif
139 			    )
140 				goto ok;
141 #endif /* DIRECT_SERIAL */
142 		}
143 		iodev = CONSDEV_PC;
144 ok:
145 		break;
146 	    case CONSDEV_COM0:
147 	    case CONSDEV_COM1:
148 	    case CONSDEV_COM2:
149 	    case CONSDEV_COM3:
150 		iodev = dev;
151 		btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0);
152 		if(!btinfo_console.addr)
153 			goto nocom;
154 		cominit_x();
155 		break;
156 	    case CONSDEV_COM0KBD:
157 	    case CONSDEV_COM1KBD:
158 	    case CONSDEV_COM2KBD:
159 	    case CONSDEV_COM3KBD:
160 		iodev = dev - CONSDEV_COM0KBD + CONSDEV_COM0;
161 		i = iodev - CONSDEV_COM0;
162 		btinfo_console.addr = getcomaddr(i);
163 		if(!btinfo_console.addr)
164 			goto nocom;
165 		conputc('0' + i); /* to tell user what happens */
166 		cominit_x();
167 #ifdef DIRECT_SERIAL
168 			/* check for:
169 			 *  1. successful output
170 			 *  2. optionally, keypress within 7s
171 			 */
172 			if (	computc_x(':') &&
173 				computc_x('-') &&
174 				computc_x('(')
175 #ifdef COMCONS_KEYPRESS
176 			   && awaitkey(7, 0)
177 #endif
178 			   )
179 				break;
180 #else /* ! DIRECT_SERIAL */
181 			/*
182 			 * serial console must have hardware handshake!
183 			 * check:
184 			 *  1. character output without error
185 			 *  2. status bits for modem ready set
186 			 *     (status seems only useful after character output)
187 			 *  3. optionally, keypress within 7s
188 			 */
189 			if (!(computc_x('@') & 0x80)
190 			    && (comstatus_x() & 0x00b0)
191 #ifdef COMCONS_KEYPRESS
192 			    && awaitkey(7, 0)
193 #endif
194 			    )
195 				break;
196 #endif /* DIRECT_SERIAL */
197 	    default:
198 nocom:
199 		iodev = CONSDEV_PC;
200 		break;
201 	}
202 	conputc('\015');
203 	conputc('\n');
204 	strncpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16);
205 #else /* !SUPPORT_SERIAL */
206 	btinfo_console.devname[0] = 'p';
207 	btinfo_console.devname[1] = 'c';
208 	btinfo_console.devname[2] = 0;
209 #endif /* SUPPORT_SERIAL */
210 }
211 
212 static inline void internal_putchar __P((int));
213 
214 static inline void
215 internal_putchar(c)
216 	int c;
217 {
218 #ifdef SUPPORT_SERIAL
219 	switch (iodev) {
220 	    case CONSDEV_PC:
221 #endif
222 		conputc(c);
223 #ifdef SUPPORT_SERIAL
224 		break;
225 	    case CONSDEV_COM0:
226 	    case CONSDEV_COM1:
227 	    case CONSDEV_COM2:
228 	    case CONSDEV_COM3:
229 		computc_x(c);
230 		break;
231 	}
232 #endif
233 }
234 
235 void
236 putchar(c)
237 	int c;
238 {
239 	if (c == '\n')
240 		internal_putchar('\r');
241 	internal_putchar(c);
242 }
243 
244 int
245 getchar()
246 {
247 	int c;
248 #ifdef SUPPORT_SERIAL
249 	switch (iodev) {
250 	    default: /* to make gcc -Wall happy... */
251 	    case CONSDEV_PC:
252 #endif
253 		c = congetc();
254 #ifdef CONSOLE_KEYMAP
255 		{
256 			char *cp = strchr(CONSOLE_KEYMAP, c);
257 			if (cp != 0 && cp[1] != 0)
258 				c = cp[1];
259 		}
260 #endif
261 		return c;
262 #ifdef SUPPORT_SERIAL
263 	    case CONSDEV_COM0:
264 	    case CONSDEV_COM1:
265 	    case CONSDEV_COM2:
266 	    case CONSDEV_COM3:
267 #ifdef DIRECT_SERIAL
268 		c = comgetc_x();
269 #else
270 		do {
271 			c = comgetc_x();
272 		} while ((c >> 8) == 0xe0); /* catch timeout */
273 #ifdef COMDEBUG
274 		if (c & 0x8000) {
275 			printf("com input %x, status %x\n",
276 			       c, comstatus_x());
277 		}
278 #endif
279 		c &= 0xff;
280 #endif /* DIRECT_SERIAL */
281 		return (c);
282 	}
283 #endif /* SUPPORT_SERIAL */
284 }
285 
286 int
287 iskey(int intr)
288 {
289 #ifdef SUPPORT_SERIAL
290 	switch (iodev) {
291 	    default: /* to make gcc -Wall happy... */
292 	    case CONSDEV_PC:
293 #endif
294 		return ((intr && conisshift()) || coniskey());
295 #ifdef SUPPORT_SERIAL
296 	    case CONSDEV_COM0:
297 	    case CONSDEV_COM1:
298 	    case CONSDEV_COM2:
299 	    case CONSDEV_COM3:
300 #ifdef DIRECT_SERIAL
301 		return(!!comstatus_x());
302 #else
303 		return (!!(comstatus_x() & 0x0100));
304 #endif
305 	}
306 #endif /* SUPPORT_SERIAL */
307 }
308 
309 char
310 awaitkey(timeout, tell)
311 	int timeout, tell;
312 {
313 	int i;
314 	char c = 0;
315 
316 	i = timeout * POLL_FREQ;
317 
318 	for (;;) {
319 		if (tell && (i % POLL_FREQ) == 0) {
320 			char numbuf[20];
321 			int len, j;
322 
323 			sprintf(numbuf, "%d ", i/POLL_FREQ);
324 			len = strlen(numbuf);
325 			for (j = 0; j < len; j++)
326 				numbuf[len + j] = '\b';
327 			numbuf[len + j] = '\0';
328 			printf(numbuf);
329 		}
330 		if (iskey(1)) {
331 			/* flush input buffer */
332 			while (iskey(0))
333 				c = getchar();
334 			if (c == 0)
335 				c = -1;
336 			goto out;
337 		}
338 		if (i--)
339 			delay(1000000 / POLL_FREQ);
340 		else
341 			break;
342 	}
343 
344 out:
345 	if (tell)
346 		printf("0 \n");
347 
348 	return(c);
349 }
350