pcio.c revision 1.30 1 1.30 joerg /* $NetBSD: pcio.c,v 1.30 2011/06/08 16:04:40 joerg Exp $ */
2 1.1 perry
3 1.1 perry /*
4 1.5 drochner * Copyright (c) 1996, 1997
5 1.1 perry * Matthias Drochner. All rights reserved.
6 1.1 perry *
7 1.1 perry * Redistribution and use in source and binary forms, with or without
8 1.1 perry * modification, are permitted provided that the following conditions
9 1.1 perry * are met:
10 1.1 perry * 1. Redistributions of source code must retain the above copyright
11 1.1 perry * notice, this list of conditions and the following disclaimer.
12 1.1 perry * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 perry * notice, this list of conditions and the following disclaimer in the
14 1.1 perry * documentation and/or other materials provided with the distribution.
15 1.1 perry *
16 1.1 perry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.1 perry * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 1.1 perry * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 1.1 perry * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 1.1 perry * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 1.1 perry * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 1.1 perry * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 1.1 perry * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 1.1 perry * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 1.1 perry * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 1.1 perry *
27 1.1 perry */
28 1.1 perry
29 1.3 thorpej /*
30 1.4 drochner * console I/O
31 1.4 drochner * needs lowlevel routines from conio.S and comio.S
32 1.3 thorpej */
33 1.1 perry
34 1.1 perry #include <lib/libsa/stand.h>
35 1.5 drochner #include <lib/libkern/libkern.h>
36 1.14 dsl #include <sys/bootblock.h>
37 1.1 perry
38 1.1 perry #include "libi386.h"
39 1.5 drochner #include "bootinfo.h"
40 1.1 perry
41 1.15 lukem extern struct x86_boot_params boot_params;
42 1.1 perry
43 1.5 drochner struct btinfo_console btinfo_console;
44 1.5 drochner
45 1.1 perry #ifdef SUPPORT_SERIAL
46 1.5 drochner static int iodev;
47 1.5 drochner
48 1.5 drochner #ifdef DIRECT_SERIAL
49 1.5 drochner #include "comio_direct.h"
50 1.5 drochner
51 1.20 dsl #define cominit_x() btinfo_console.speed = \
52 1.20 dsl cominit_d(btinfo_console.addr, btinfo_console.speed)
53 1.14 dsl #define computc_x(ch) computc_d(ch, btinfo_console.addr)
54 1.14 dsl #define comgetc_x() comgetc_d(btinfo_console.addr)
55 1.14 dsl #define comstatus_x() comstatus_d(btinfo_console.addr)
56 1.5 drochner
57 1.5 drochner #else
58 1.14 dsl #define cominit_x() cominit(iodev - CONSDEV_COM0)
59 1.14 dsl #define computc_x(ch) computc(ch, iodev - CONSDEV_COM0)
60 1.14 dsl #define comgetc_x() comgetc(iodev - CONSDEV_COM0)
61 1.14 dsl #define comstatus_x() comstatus(iodev - CONSDEV_COM0)
62 1.1 perry
63 1.5 drochner #endif /* DIRECT_SERIAL */
64 1.5 drochner
65 1.21 junyoung static int getcomaddr(int);
66 1.5 drochner #endif /* SUPPORT_SERIAL */
67 1.5 drochner
68 1.5 drochner #define POLL_FREQ 10
69 1.1 perry
70 1.27 jmcneill static void
71 1.27 jmcneill wait(int us)
72 1.27 jmcneill {
73 1.27 jmcneill int prev = biosgetsystime();
74 1.27 jmcneill int tgt = prev + (20 * us) / 1000000;
75 1.27 jmcneill int new;
76 1.27 jmcneill
77 1.27 jmcneill while ((new = biosgetsystime()) < tgt) {
78 1.27 jmcneill if (new < prev) /* XXX timer wrapped */
79 1.27 jmcneill break;
80 1.27 jmcneill prev = new;
81 1.27 jmcneill }
82 1.27 jmcneill }
83 1.27 jmcneill
84 1.1 perry #ifdef SUPPORT_SERIAL
85 1.5 drochner static int
86 1.21 junyoung getcomaddr(int idx)
87 1.5 drochner {
88 1.5 drochner short addr;
89 1.18 dsl #ifdef CONSADDR
90 1.18 dsl if (CONSADDR != 0)
91 1.18 dsl return CONSADDR;
92 1.18 dsl #endif
93 1.5 drochner /* read in BIOS data area */
94 1.8 sommerfe pvbcopy((void *)(0x400 + 2 * idx), &addr, 2);
95 1.21 junyoung return addr;
96 1.5 drochner }
97 1.1 perry #endif
98 1.1 perry
99 1.5 drochner void
100 1.24 christos clear_pc_screen(void)
101 1.24 christos {
102 1.24 christos #ifdef SUPPORT_SERIAL
103 1.24 christos /* Clear the screen if we are on a glass tty. */
104 1.24 christos if (iodev == CONSDEV_PC)
105 1.24 christos conclr();
106 1.24 christos #endif
107 1.24 christos }
108 1.24 christos
109 1.24 christos void
110 1.21 junyoung initio(int dev)
111 1.1 perry {
112 1.1 perry #ifdef SUPPORT_SERIAL
113 1.5 drochner int i;
114 1.5 drochner
115 1.14 dsl #if defined(DIRECT_SERIAL) && defined(CONSPEED)
116 1.14 dsl btinfo_console.speed = CONSPEED;
117 1.14 dsl #else
118 1.14 dsl btinfo_console.speed = 9600;
119 1.14 dsl #endif
120 1.14 dsl
121 1.3 thorpej switch (dev) {
122 1.21 junyoung case CONSDEV_AUTO:
123 1.25 christos for (i = 0; i < 3; i++) {
124 1.5 drochner iodev = CONSDEV_COM0 + i;
125 1.5 drochner btinfo_console.addr = getcomaddr(i);
126 1.25 christos if (!btinfo_console.addr)
127 1.12 dsl break;
128 1.5 drochner conputc('0' + i); /* to tell user what happens */
129 1.14 dsl cominit_x();
130 1.5 drochner #ifdef DIRECT_SERIAL
131 1.5 drochner /* check for:
132 1.5 drochner * 1. successful output
133 1.12 dsl * 2. optionally, keypress within 7s
134 1.5 drochner */
135 1.14 dsl if ( computc_x(':') &&
136 1.14 dsl computc_x('-') &&
137 1.14 dsl computc_x('(')
138 1.5 drochner #ifdef COMCONS_KEYPRESS
139 1.7 rvb && awaitkey(7, 0)
140 1.5 drochner #endif
141 1.5 drochner )
142 1.5 drochner goto ok;
143 1.11 thorpej #else /* ! DIRECT_SERIAL */
144 1.5 drochner /*
145 1.5 drochner * serial console must have hardware handshake!
146 1.5 drochner * check:
147 1.5 drochner * 1. character output without error
148 1.5 drochner * 2. status bits for modem ready set
149 1.5 drochner * (status seems only useful after character output)
150 1.12 dsl * 3. optionally, keypress within 7s
151 1.5 drochner */
152 1.14 dsl if (!(computc_x('@') & 0x80)
153 1.14 dsl && (comstatus_x() & 0x00b0)
154 1.5 drochner #ifdef COMCONS_KEYPRESS
155 1.7 rvb && awaitkey(7, 0)
156 1.5 drochner #endif
157 1.5 drochner )
158 1.5 drochner goto ok;
159 1.11 thorpej #endif /* DIRECT_SERIAL */
160 1.3 thorpej }
161 1.5 drochner iodev = CONSDEV_PC;
162 1.5 drochner ok:
163 1.3 thorpej break;
164 1.21 junyoung case CONSDEV_COM0:
165 1.21 junyoung case CONSDEV_COM1:
166 1.21 junyoung case CONSDEV_COM2:
167 1.21 junyoung case CONSDEV_COM3:
168 1.5 drochner iodev = dev;
169 1.5 drochner btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0);
170 1.25 christos if (!btinfo_console.addr)
171 1.12 dsl goto nocom;
172 1.14 dsl cominit_x();
173 1.3 thorpej break;
174 1.21 junyoung case CONSDEV_COM0KBD:
175 1.21 junyoung case CONSDEV_COM1KBD:
176 1.21 junyoung case CONSDEV_COM2KBD:
177 1.21 junyoung case CONSDEV_COM3KBD:
178 1.18 dsl iodev = dev - CONSDEV_COM0KBD + CONSDEV_COM0;
179 1.7 rvb i = iodev - CONSDEV_COM0;
180 1.7 rvb btinfo_console.addr = getcomaddr(i);
181 1.25 christos if (!btinfo_console.addr)
182 1.12 dsl goto nocom;
183 1.7 rvb conputc('0' + i); /* to tell user what happens */
184 1.14 dsl cominit_x();
185 1.7 rvb #ifdef DIRECT_SERIAL
186 1.7 rvb /* check for:
187 1.7 rvb * 1. successful output
188 1.12 dsl * 2. optionally, keypress within 7s
189 1.7 rvb */
190 1.14 dsl if ( computc_x(':') &&
191 1.14 dsl computc_x('-') &&
192 1.14 dsl computc_x('(')
193 1.7 rvb #ifdef COMCONS_KEYPRESS
194 1.7 rvb && awaitkey(7, 0)
195 1.7 rvb #endif
196 1.7 rvb )
197 1.7 rvb break;
198 1.11 thorpej #else /* ! DIRECT_SERIAL */
199 1.7 rvb /*
200 1.7 rvb * serial console must have hardware handshake!
201 1.7 rvb * check:
202 1.7 rvb * 1. character output without error
203 1.7 rvb * 2. status bits for modem ready set
204 1.7 rvb * (status seems only useful after character output)
205 1.12 dsl * 3. optionally, keypress within 7s
206 1.7 rvb */
207 1.14 dsl if (!(computc_x('@') & 0x80)
208 1.14 dsl && (comstatus_x() & 0x00b0)
209 1.7 rvb #ifdef COMCONS_KEYPRESS
210 1.7 rvb && awaitkey(7, 0)
211 1.7 rvb #endif
212 1.7 rvb )
213 1.7 rvb break;
214 1.11 thorpej #endif /* DIRECT_SERIAL */
215 1.21 junyoung default:
216 1.5 drochner nocom:
217 1.5 drochner iodev = CONSDEV_PC;
218 1.3 thorpej break;
219 1.3 thorpej }
220 1.7 rvb conputc('\015');
221 1.7 rvb conputc('\n');
222 1.5 drochner strncpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16);
223 1.23 ad
224 1.5 drochner #else /* !SUPPORT_SERIAL */
225 1.13 dsl btinfo_console.devname[0] = 'p';
226 1.13 dsl btinfo_console.devname[1] = 'c';
227 1.13 dsl btinfo_console.devname[2] = 0;
228 1.5 drochner #endif /* SUPPORT_SERIAL */
229 1.1 perry }
230 1.1 perry
231 1.21 junyoung static inline void internal_putchar(int);
232 1.9 drochner
233 1.3 thorpej static inline void
234 1.21 junyoung internal_putchar(int c)
235 1.1 perry {
236 1.1 perry #ifdef SUPPORT_SERIAL
237 1.3 thorpej switch (iodev) {
238 1.21 junyoung case CONSDEV_PC:
239 1.1 perry #endif
240 1.3 thorpej conputc(c);
241 1.1 perry #ifdef SUPPORT_SERIAL
242 1.3 thorpej break;
243 1.21 junyoung case CONSDEV_COM0:
244 1.21 junyoung case CONSDEV_COM1:
245 1.21 junyoung case CONSDEV_COM2:
246 1.21 junyoung case CONSDEV_COM3:
247 1.14 dsl computc_x(c);
248 1.3 thorpej break;
249 1.3 thorpej }
250 1.1 perry #endif
251 1.1 perry }
252 1.1 perry
253 1.3 thorpej void
254 1.21 junyoung putchar(int c)
255 1.1 perry {
256 1.3 thorpej if (c == '\n')
257 1.3 thorpej internal_putchar('\r');
258 1.3 thorpej internal_putchar(c);
259 1.1 perry }
260 1.1 perry
261 1.3 thorpej int
262 1.21 junyoung getchar(void)
263 1.3 thorpej {
264 1.16 dsl int c;
265 1.1 perry #ifdef SUPPORT_SERIAL
266 1.3 thorpej switch (iodev) {
267 1.21 junyoung default: /* to make gcc -Wall happy... */
268 1.21 junyoung case CONSDEV_PC:
269 1.1 perry #endif
270 1.29 jmcneill while (!coniskey())
271 1.29 jmcneill ;
272 1.16 dsl c = congetc();
273 1.16 dsl #ifdef CONSOLE_KEYMAP
274 1.16 dsl {
275 1.16 dsl char *cp = strchr(CONSOLE_KEYMAP, c);
276 1.16 dsl if (cp != 0 && cp[1] != 0)
277 1.16 dsl c = cp[1];
278 1.16 dsl }
279 1.16 dsl #endif
280 1.16 dsl return c;
281 1.1 perry #ifdef SUPPORT_SERIAL
282 1.21 junyoung case CONSDEV_COM0:
283 1.21 junyoung case CONSDEV_COM1:
284 1.21 junyoung case CONSDEV_COM2:
285 1.21 junyoung case CONSDEV_COM3:
286 1.6 drochner #ifdef DIRECT_SERIAL
287 1.14 dsl c = comgetc_x();
288 1.6 drochner #else
289 1.6 drochner do {
290 1.14 dsl c = comgetc_x();
291 1.6 drochner } while ((c >> 8) == 0xe0); /* catch timeout */
292 1.6 drochner #ifdef COMDEBUG
293 1.6 drochner if (c & 0x8000) {
294 1.6 drochner printf("com input %x, status %x\n",
295 1.14 dsl c, comstatus_x());
296 1.6 drochner }
297 1.6 drochner #endif
298 1.6 drochner c &= 0xff;
299 1.6 drochner #endif /* DIRECT_SERIAL */
300 1.21 junyoung return c;
301 1.3 thorpej }
302 1.6 drochner #endif /* SUPPORT_SERIAL */
303 1.1 perry }
304 1.1 perry
305 1.3 thorpej int
306 1.19 mycroft iskey(int intr)
307 1.3 thorpej {
308 1.1 perry #ifdef SUPPORT_SERIAL
309 1.3 thorpej switch (iodev) {
310 1.21 junyoung default: /* to make gcc -Wall happy... */
311 1.21 junyoung case CONSDEV_PC:
312 1.1 perry #endif
313 1.21 junyoung return (intr && conisshift()) || coniskey();
314 1.1 perry #ifdef SUPPORT_SERIAL
315 1.21 junyoung case CONSDEV_COM0:
316 1.21 junyoung case CONSDEV_COM1:
317 1.21 junyoung case CONSDEV_COM2:
318 1.21 junyoung case CONSDEV_COM3:
319 1.5 drochner #ifdef DIRECT_SERIAL
320 1.21 junyoung return !!comstatus_x();
321 1.5 drochner #else
322 1.21 junyoung return !!(comstatus_x() & 0x0100);
323 1.5 drochner #endif
324 1.3 thorpej }
325 1.5 drochner #endif /* SUPPORT_SERIAL */
326 1.5 drochner }
327 1.5 drochner
328 1.5 drochner char
329 1.21 junyoung awaitkey(int timeout, int tell)
330 1.5 drochner {
331 1.5 drochner int i;
332 1.5 drochner char c = 0;
333 1.5 drochner
334 1.5 drochner i = timeout * POLL_FREQ;
335 1.5 drochner
336 1.19 mycroft for (;;) {
337 1.10 drochner if (tell && (i % POLL_FREQ) == 0) {
338 1.26 mbalmer char numbuf[32];
339 1.26 mbalmer int len;
340 1.10 drochner
341 1.26 mbalmer len = snprintf(numbuf, sizeof(numbuf), "%d seconds. ",
342 1.26 mbalmer i/POLL_FREQ);
343 1.26 mbalmer if (len > 0 && len < sizeof(numbuf)) {
344 1.26 mbalmer char *p = numbuf;
345 1.26 mbalmer
346 1.26 mbalmer printf("%s", numbuf);
347 1.26 mbalmer while (*p)
348 1.26 mbalmer *p++ = '\b';
349 1.26 mbalmer printf("%s", numbuf);
350 1.26 mbalmer }
351 1.10 drochner }
352 1.19 mycroft if (iskey(1)) {
353 1.5 drochner /* flush input buffer */
354 1.19 mycroft while (iskey(0))
355 1.5 drochner c = getchar();
356 1.12 dsl if (c == 0)
357 1.12 dsl c = -1;
358 1.12 dsl goto out;
359 1.5 drochner }
360 1.19 mycroft if (i--)
361 1.27 jmcneill wait(1000000 / POLL_FREQ);
362 1.19 mycroft else
363 1.19 mycroft break;
364 1.5 drochner }
365 1.5 drochner
366 1.5 drochner out:
367 1.5 drochner if (tell)
368 1.26 mbalmer printf("0 seconds. \n");
369 1.5 drochner
370 1.21 junyoung return c;
371 1.1 perry }
372 1.28 tsutsui
373 1.28 tsutsui void
374 1.28 tsutsui wait_sec(int sec)
375 1.28 tsutsui {
376 1.28 tsutsui
377 1.28 tsutsui wait(sec * 1000000);
378 1.28 tsutsui }
379