xref: /netbsd-src/sys/arch/i386/stand/lib/pcio.c (revision bc843b5e55049b523dad1eb3f7d20db4c4f6cd07)
1*bc843b5eSjoerg /*	$NetBSD: pcio.c,v 1.30 2011/06/08 16:04:40 joerg Exp $	 */
2816bb961Sperry 
3816bb961Sperry /*
4dae95d6cSdrochner  * Copyright (c) 1996, 1997
5816bb961Sperry  *	Matthias Drochner.  All rights reserved.
6816bb961Sperry  *
7816bb961Sperry  * Redistribution and use in source and binary forms, with or without
8816bb961Sperry  * modification, are permitted provided that the following conditions
9816bb961Sperry  * are met:
10816bb961Sperry  * 1. Redistributions of source code must retain the above copyright
11816bb961Sperry  *    notice, this list of conditions and the following disclaimer.
12816bb961Sperry  * 2. Redistributions in binary form must reproduce the above copyright
13816bb961Sperry  *    notice, this list of conditions and the following disclaimer in the
14816bb961Sperry  *    documentation and/or other materials provided with the distribution.
15816bb961Sperry  *
16816bb961Sperry  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17816bb961Sperry  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18816bb961Sperry  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19816bb961Sperry  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20816bb961Sperry  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21816bb961Sperry  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22816bb961Sperry  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23816bb961Sperry  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24816bb961Sperry  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25816bb961Sperry  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26816bb961Sperry  *
27816bb961Sperry  */
28816bb961Sperry 
29f07be036Sthorpej /*
30e242b6feSdrochner  * console I/O
31e242b6feSdrochner  * needs lowlevel routines from conio.S and comio.S
32816bb961Sperry  */
33816bb961Sperry 
34816bb961Sperry #include <lib/libsa/stand.h>
35dae95d6cSdrochner #include <lib/libkern/libkern.h>
36e60ac536Sdsl #include <sys/bootblock.h>
37816bb961Sperry 
38816bb961Sperry #include "libi386.h"
39dae95d6cSdrochner #include "bootinfo.h"
40816bb961Sperry 
411c33b4e6Slukem extern struct x86_boot_params boot_params;
42816bb961Sperry 
43dae95d6cSdrochner struct btinfo_console btinfo_console;
44dae95d6cSdrochner 
45816bb961Sperry #ifdef SUPPORT_SERIAL
46dae95d6cSdrochner static int iodev;
47dae95d6cSdrochner 
48dae95d6cSdrochner #ifdef DIRECT_SERIAL
49dae95d6cSdrochner #include "comio_direct.h"
50dae95d6cSdrochner 
51e70304f7Sdsl #define cominit_x()	btinfo_console.speed = \
52e70304f7Sdsl 			    cominit_d(btinfo_console.addr, btinfo_console.speed)
53e60ac536Sdsl #define computc_x(ch)	computc_d(ch, btinfo_console.addr)
54e60ac536Sdsl #define comgetc_x()	comgetc_d(btinfo_console.addr)
55e60ac536Sdsl #define comstatus_x()	comstatus_d(btinfo_console.addr)
56dae95d6cSdrochner 
57dae95d6cSdrochner #else
58e60ac536Sdsl #define cominit_x()	cominit(iodev - CONSDEV_COM0)
59e60ac536Sdsl #define computc_x(ch)	computc(ch, iodev - CONSDEV_COM0)
60e60ac536Sdsl #define comgetc_x()	comgetc(iodev - CONSDEV_COM0)
61e60ac536Sdsl #define comstatus_x()	comstatus(iodev - CONSDEV_COM0)
62816bb961Sperry 
63dae95d6cSdrochner #endif /* DIRECT_SERIAL */
64816bb961Sperry 
65ed111642Sjunyoung static int getcomaddr(int);
66dae95d6cSdrochner #endif /* SUPPORT_SERIAL */
67dae95d6cSdrochner 
68dae95d6cSdrochner #define POLL_FREQ 10
69dae95d6cSdrochner 
70c07ee161Sjmcneill static void
wait(int us)71c07ee161Sjmcneill wait(int us)
72c07ee161Sjmcneill {
73c07ee161Sjmcneill 	int prev = biosgetsystime();
74c07ee161Sjmcneill 	int tgt = prev + (20 * us) / 1000000;
75c07ee161Sjmcneill 	int new;
76c07ee161Sjmcneill 
77c07ee161Sjmcneill 	while ((new = biosgetsystime()) < tgt) {
78c07ee161Sjmcneill 		if (new < prev) /* XXX timer wrapped */
79c07ee161Sjmcneill 			break;
80c07ee161Sjmcneill 		prev = new;
81c07ee161Sjmcneill 	}
82c07ee161Sjmcneill }
83c07ee161Sjmcneill 
84816bb961Sperry #ifdef SUPPORT_SERIAL
85dae95d6cSdrochner static int
getcomaddr(int idx)86ed111642Sjunyoung getcomaddr(int idx)
87dae95d6cSdrochner {
88dae95d6cSdrochner 	short addr;
89c1eeebc3Sdsl #ifdef CONSADDR
90c1eeebc3Sdsl 	if (CONSADDR != 0)
91c1eeebc3Sdsl 		return CONSADDR;
92c1eeebc3Sdsl #endif
93dae95d6cSdrochner 	/* read in BIOS data area */
94df8e0043Ssommerfe 	pvbcopy((void *)(0x400 + 2 * idx), &addr, 2);
95ed111642Sjunyoung 	return addr;
96dae95d6cSdrochner }
97816bb961Sperry #endif
98816bb961Sperry 
99dae95d6cSdrochner void
clear_pc_screen(void)100f0468ba6Schristos clear_pc_screen(void)
101f0468ba6Schristos {
102f0468ba6Schristos #ifdef SUPPORT_SERIAL
103f0468ba6Schristos 	/* Clear the screen if we are on a glass tty. */
104f0468ba6Schristos 	if (iodev == CONSDEV_PC)
105f0468ba6Schristos 		conclr();
106f0468ba6Schristos #endif
107f0468ba6Schristos }
108f0468ba6Schristos 
109f0468ba6Schristos void
initio(int dev)110ed111642Sjunyoung initio(int dev)
111816bb961Sperry {
112816bb961Sperry #ifdef SUPPORT_SERIAL
113dae95d6cSdrochner 	int i;
114dae95d6cSdrochner 
115e60ac536Sdsl #if defined(DIRECT_SERIAL) && defined(CONSPEED)
116e60ac536Sdsl 	btinfo_console.speed = CONSPEED;
117e60ac536Sdsl #else
118e60ac536Sdsl 	btinfo_console.speed = 9600;
119e60ac536Sdsl #endif
120e60ac536Sdsl 
121816bb961Sperry 	switch (dev) {
122816bb961Sperry 	case CONSDEV_AUTO:
123dae95d6cSdrochner 		for (i = 0; i < 3; i++) {
124dae95d6cSdrochner 			iodev = CONSDEV_COM0 + i;
125dae95d6cSdrochner 			btinfo_console.addr = getcomaddr(i);
12681acacd7Sdsl 			if (!btinfo_console.addr)
12781acacd7Sdsl 				break;
128dae95d6cSdrochner 			conputc('0' + i); /* to tell user what happens */
129e60ac536Sdsl 			cominit_x();
130dae95d6cSdrochner #ifdef DIRECT_SERIAL
131dae95d6cSdrochner 			/* check for:
132dae95d6cSdrochner 			 *  1. successful output
13381acacd7Sdsl 			 *  2. optionally, keypress within 7s
134816bb961Sperry 			 */
135e60ac536Sdsl 			if (	computc_x(':') &&
136e60ac536Sdsl 				computc_x('-') &&
137e60ac536Sdsl 				computc_x('(')
138dae95d6cSdrochner #ifdef COMCONS_KEYPRESS
13967390e1eSrvb 			   && awaitkey(7, 0)
140dae95d6cSdrochner #endif
141dae95d6cSdrochner 			   )
142dae95d6cSdrochner 				goto ok;
143dfeaa108Sthorpej #else /* ! DIRECT_SERIAL */
144dae95d6cSdrochner 			/*
145dae95d6cSdrochner 			 * serial console must have hardware handshake!
146dae95d6cSdrochner 			 * check:
147dae95d6cSdrochner 			 *  1. character output without error
148dae95d6cSdrochner 			 *  2. status bits for modem ready set
149dae95d6cSdrochner 			 *     (status seems only useful after character output)
15081acacd7Sdsl 			 *  3. optionally, keypress within 7s
151dae95d6cSdrochner 			 */
152e60ac536Sdsl 			if (!(computc_x('@') & 0x80)
153e60ac536Sdsl 			    && (comstatus_x() & 0x00b0)
154dae95d6cSdrochner #ifdef COMCONS_KEYPRESS
15567390e1eSrvb 			    && awaitkey(7, 0)
156dae95d6cSdrochner #endif
157dae95d6cSdrochner 			    )
158dae95d6cSdrochner 				goto ok;
159dfeaa108Sthorpej #endif /* DIRECT_SERIAL */
160816bb961Sperry 		}
161dae95d6cSdrochner 		iodev = CONSDEV_PC;
162dae95d6cSdrochner ok:
163816bb961Sperry 		break;
164f07be036Sthorpej 	case CONSDEV_COM0:
165f07be036Sthorpej 	case CONSDEV_COM1:
166dae95d6cSdrochner 	case CONSDEV_COM2:
167dae95d6cSdrochner 	case CONSDEV_COM3:
168dae95d6cSdrochner 		iodev = dev;
169dae95d6cSdrochner 		btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0);
17081acacd7Sdsl 		if (!btinfo_console.addr)
17181acacd7Sdsl 			goto nocom;
172e60ac536Sdsl 		cominit_x();
173f07be036Sthorpej 		break;
17467390e1eSrvb 	case CONSDEV_COM0KBD:
17567390e1eSrvb 	case CONSDEV_COM1KBD:
17667390e1eSrvb 	case CONSDEV_COM2KBD:
17767390e1eSrvb 	case CONSDEV_COM3KBD:
178c1eeebc3Sdsl 		iodev = dev - CONSDEV_COM0KBD + CONSDEV_COM0;
17967390e1eSrvb 		i = iodev - CONSDEV_COM0;
18067390e1eSrvb 		btinfo_console.addr = getcomaddr(i);
18181acacd7Sdsl 		if (!btinfo_console.addr)
18281acacd7Sdsl 			goto nocom;
18367390e1eSrvb 		conputc('0' + i); /* to tell user what happens */
184e60ac536Sdsl 		cominit_x();
18567390e1eSrvb #ifdef DIRECT_SERIAL
18667390e1eSrvb 			/* check for:
18767390e1eSrvb 			 *  1. successful output
18881acacd7Sdsl 			 *  2. optionally, keypress within 7s
18967390e1eSrvb 			 */
190e60ac536Sdsl 			if (	computc_x(':') &&
191e60ac536Sdsl 				computc_x('-') &&
192e60ac536Sdsl 				computc_x('(')
19367390e1eSrvb #ifdef COMCONS_KEYPRESS
19467390e1eSrvb 			   && awaitkey(7, 0)
19567390e1eSrvb #endif
19667390e1eSrvb 			   )
19767390e1eSrvb 				break;
198dfeaa108Sthorpej #else /* ! DIRECT_SERIAL */
19967390e1eSrvb 			/*
20067390e1eSrvb 			 * serial console must have hardware handshake!
20167390e1eSrvb 			 * check:
20267390e1eSrvb 			 *  1. character output without error
20367390e1eSrvb 			 *  2. status bits for modem ready set
20467390e1eSrvb 			 *     (status seems only useful after character output)
20581acacd7Sdsl 			 *  3. optionally, keypress within 7s
20667390e1eSrvb 			 */
207e60ac536Sdsl 			if (!(computc_x('@') & 0x80)
208e60ac536Sdsl 			    && (comstatus_x() & 0x00b0)
20967390e1eSrvb #ifdef COMCONS_KEYPRESS
21067390e1eSrvb 			    && awaitkey(7, 0)
21167390e1eSrvb #endif
21267390e1eSrvb 			    )
21367390e1eSrvb 				break;
214dfeaa108Sthorpej #endif /* DIRECT_SERIAL */
215f07be036Sthorpej 	default:
216dae95d6cSdrochner nocom:
217dae95d6cSdrochner 		iodev = CONSDEV_PC;
218f07be036Sthorpej 		break;
219816bb961Sperry 	}
22067390e1eSrvb 	conputc('\015');
22167390e1eSrvb 	conputc('\n');
222dae95d6cSdrochner 	strncpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16);
22394b6b187Sad 
2242a64c855Sad #else /* !SUPPORT_SERIAL */
2252a64c855Sad 	btinfo_console.devname[0] = 'p';
2262a64c855Sad 	btinfo_console.devname[1] = 'c';
2272a64c855Sad 	btinfo_console.devname[2] = 0;
2282a64c855Sad #endif /* SUPPORT_SERIAL */
229816bb961Sperry }
230816bb961Sperry 
231ed111642Sjunyoung static inline void internal_putchar(int);
2322d1e6a1fSdrochner 
233f07be036Sthorpej static inline void
internal_putchar(int c)234ed111642Sjunyoung internal_putchar(int c)
235816bb961Sperry {
236816bb961Sperry #ifdef SUPPORT_SERIAL
237816bb961Sperry 	switch (iodev) {
238817522ffSperry 	case CONSDEV_PC:
239816bb961Sperry #endif
240816bb961Sperry 		conputc(c);
241816bb961Sperry #ifdef SUPPORT_SERIAL
242816bb961Sperry 		break;
243f07be036Sthorpej 	case CONSDEV_COM0:
244f07be036Sthorpej 	case CONSDEV_COM1:
245dae95d6cSdrochner 	case CONSDEV_COM2:
246dae95d6cSdrochner 	case CONSDEV_COM3:
247e60ac536Sdsl 		computc_x(c);
248f07be036Sthorpej 		break;
249816bb961Sperry 	}
250816bb961Sperry #endif
251816bb961Sperry }
252816bb961Sperry 
253f07be036Sthorpej void
putchar(int c)254ed111642Sjunyoung putchar(int c)
255816bb961Sperry {
256816bb961Sperry 	if (c == '\n')
257816bb961Sperry 		internal_putchar('\r');
258816bb961Sperry 	internal_putchar(c);
259816bb961Sperry }
260816bb961Sperry 
261f07be036Sthorpej int
getchar(void)262ed111642Sjunyoung getchar(void)
263f07be036Sthorpej {
264ec783104Sdrochner 	int c;
265ae7b9243Sdsl #ifdef SUPPORT_SERIAL
266816bb961Sperry 	switch (iodev) {
267e242b6feSdrochner 	default: /* to make gcc -Wall happy... */
268817522ffSperry 	case CONSDEV_PC:
269816bb961Sperry #endif
270540bdd75Sjmcneill 		while (!coniskey())
271540bdd75Sjmcneill 			;
272ae7b9243Sdsl 		c = congetc();
273ae7b9243Sdsl #ifdef CONSOLE_KEYMAP
274ae7b9243Sdsl 		{
275ae7b9243Sdsl 			char *cp = strchr(CONSOLE_KEYMAP, c);
276ae7b9243Sdsl 			if (cp != 0 && cp[1] != 0)
277ae7b9243Sdsl 				c = cp[1];
278ae7b9243Sdsl 		}
279ae7b9243Sdsl #endif
280ae7b9243Sdsl 		return c;
281816bb961Sperry #ifdef SUPPORT_SERIAL
282f07be036Sthorpej 	case CONSDEV_COM0:
283f07be036Sthorpej 	case CONSDEV_COM1:
284dae95d6cSdrochner 	case CONSDEV_COM2:
285dae95d6cSdrochner 	case CONSDEV_COM3:
286ec783104Sdrochner #ifdef DIRECT_SERIAL
287e60ac536Sdsl 		c = comgetc_x();
288ec783104Sdrochner #else
289ec783104Sdrochner 		do {
290e60ac536Sdsl 			c = comgetc_x();
291ec783104Sdrochner 		} while ((c >> 8) == 0xe0); /* catch timeout */
292ec783104Sdrochner #ifdef COMDEBUG
293ec783104Sdrochner 		if (c & 0x8000) {
294ec783104Sdrochner 			printf("com input %x, status %x\n",
295e60ac536Sdsl 			       c, comstatus_x());
296816bb961Sperry 		}
297816bb961Sperry #endif
298ec783104Sdrochner 		c &= 0xff;
299ec783104Sdrochner #endif /* DIRECT_SERIAL */
300ed111642Sjunyoung 		return c;
301ec783104Sdrochner 	}
302ec783104Sdrochner #endif /* SUPPORT_SERIAL */
303816bb961Sperry }
304816bb961Sperry 
305f07be036Sthorpej int
iskey(int intr)3067ecc7a30Smycroft iskey(int intr)
307f07be036Sthorpej {
308816bb961Sperry #ifdef SUPPORT_SERIAL
309816bb961Sperry 	switch (iodev) {
310e242b6feSdrochner 	default: /* to make gcc -Wall happy... */
311817522ffSperry 	case CONSDEV_PC:
312816bb961Sperry #endif
313ed111642Sjunyoung 		return (intr && conisshift()) || coniskey();
314816bb961Sperry #ifdef SUPPORT_SERIAL
315f07be036Sthorpej 	case CONSDEV_COM0:
316f07be036Sthorpej 	case CONSDEV_COM1:
317dae95d6cSdrochner 	case CONSDEV_COM2:
318dae95d6cSdrochner 	case CONSDEV_COM3:
319dae95d6cSdrochner #ifdef DIRECT_SERIAL
320ed111642Sjunyoung 		return !!comstatus_x();
321dae95d6cSdrochner #else
322ed111642Sjunyoung 		return !!(comstatus_x() & 0x0100);
323816bb961Sperry #endif
324816bb961Sperry 	}
325dae95d6cSdrochner #endif /* SUPPORT_SERIAL */
326dae95d6cSdrochner }
327dae95d6cSdrochner 
328dae95d6cSdrochner char
awaitkey(int timeout,int tell)329ed111642Sjunyoung awaitkey(int timeout, int tell)
330dae95d6cSdrochner {
331dae95d6cSdrochner 	int i;
332dae95d6cSdrochner 	char c = 0;
333dae95d6cSdrochner 
334dae95d6cSdrochner 	i = timeout * POLL_FREQ;
335dae95d6cSdrochner 
3367ecc7a30Smycroft 	for (;;) {
3375c48b9a1Sdrochner 		if (tell && (i % POLL_FREQ) == 0) {
33838e0566dSmbalmer 			char numbuf[32];
33938e0566dSmbalmer 			int len;
3405c48b9a1Sdrochner 
34138e0566dSmbalmer 			len = snprintf(numbuf, sizeof(numbuf), "%d seconds. ",
34238e0566dSmbalmer 			    i/POLL_FREQ);
34338e0566dSmbalmer 			if (len > 0 && len < sizeof(numbuf)) {
34438e0566dSmbalmer 				char *p = numbuf;
34538e0566dSmbalmer 
34638e0566dSmbalmer 				printf("%s", numbuf);
34738e0566dSmbalmer 				while (*p)
34838e0566dSmbalmer 					*p++ = '\b';
34938e0566dSmbalmer 				printf("%s", numbuf);
35038e0566dSmbalmer 			}
3515c48b9a1Sdrochner 		}
3527ecc7a30Smycroft 		if (iskey(1)) {
353dae95d6cSdrochner 			/* flush input buffer */
3547ecc7a30Smycroft 			while (iskey(0))
355dae95d6cSdrochner 				c = getchar();
35681acacd7Sdsl 			if (c == 0)
35781acacd7Sdsl 				c = -1;
35881acacd7Sdsl 			goto out;
359dae95d6cSdrochner 		}
3607ecc7a30Smycroft 		if (i--)
361c07ee161Sjmcneill 			wait(1000000 / POLL_FREQ);
3627ecc7a30Smycroft 		else
3637ecc7a30Smycroft 			break;
364dae95d6cSdrochner 	}
365dae95d6cSdrochner 
366dae95d6cSdrochner out:
367dae95d6cSdrochner 	if (tell)
36838e0566dSmbalmer 		printf("0 seconds.     \n");
369dae95d6cSdrochner 
370ed111642Sjunyoung 	return c;
371dae95d6cSdrochner }
372e96b50fcStsutsui 
373e96b50fcStsutsui void
wait_sec(int sec)374e96b50fcStsutsui wait_sec(int sec)
375e96b50fcStsutsui {
376e96b50fcStsutsui 
377e96b50fcStsutsui 	wait(sec * 1000000);
378e96b50fcStsutsui }
379