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