pcio.c revision 1.27.4.2 1 /* $NetBSD: pcio.c,v 1.27.4.2 2011/03/05 20:50:45 rmind 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(int);
42 extern int congetc(void);
43 extern int conisshift(void);
44 extern int coniskey(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(int);
70 #endif /* SUPPORT_SERIAL */
71
72 #define POLL_FREQ 10
73
74 static void
75 wait(int us)
76 {
77 int prev = biosgetsystime();
78 int tgt = prev + (20 * us) / 1000000;
79 int new;
80
81 while ((new = biosgetsystime()) < tgt) {
82 if (new < prev) /* XXX timer wrapped */
83 break;
84 prev = new;
85 }
86 }
87
88 #ifdef SUPPORT_SERIAL
89 static int
90 getcomaddr(int idx)
91 {
92 short addr;
93 #ifdef CONSADDR
94 if (CONSADDR != 0)
95 return CONSADDR;
96 #endif
97 /* read in BIOS data area */
98 pvbcopy((void *)(0x400 + 2 * idx), &addr, 2);
99 return addr;
100 }
101 #endif
102
103 void
104 clear_pc_screen(void)
105 {
106 #ifdef SUPPORT_SERIAL
107 /* Clear the screen if we are on a glass tty. */
108 if (iodev == CONSDEV_PC)
109 conclr();
110 #endif
111 }
112
113 void
114 initio(int dev)
115 {
116 #ifdef SUPPORT_SERIAL
117 int i;
118
119 #if defined(DIRECT_SERIAL) && defined(CONSPEED)
120 btinfo_console.speed = CONSPEED;
121 #else
122 btinfo_console.speed = 9600;
123 #endif
124
125 switch (dev) {
126 case CONSDEV_AUTO:
127 for (i = 0; i < 3; i++) {
128 iodev = CONSDEV_COM0 + i;
129 btinfo_console.addr = getcomaddr(i);
130 if (!btinfo_console.addr)
131 break;
132 conputc('0' + i); /* to tell user what happens */
133 cominit_x();
134 #ifdef DIRECT_SERIAL
135 /* check for:
136 * 1. successful output
137 * 2. optionally, keypress within 7s
138 */
139 if ( computc_x(':') &&
140 computc_x('-') &&
141 computc_x('(')
142 #ifdef COMCONS_KEYPRESS
143 && awaitkey(7, 0)
144 #endif
145 )
146 goto ok;
147 #else /* ! DIRECT_SERIAL */
148 /*
149 * serial console must have hardware handshake!
150 * check:
151 * 1. character output without error
152 * 2. status bits for modem ready set
153 * (status seems only useful after character output)
154 * 3. optionally, keypress within 7s
155 */
156 if (!(computc_x('@') & 0x80)
157 && (comstatus_x() & 0x00b0)
158 #ifdef COMCONS_KEYPRESS
159 && awaitkey(7, 0)
160 #endif
161 )
162 goto ok;
163 #endif /* DIRECT_SERIAL */
164 }
165 iodev = CONSDEV_PC;
166 ok:
167 break;
168 case CONSDEV_COM0:
169 case CONSDEV_COM1:
170 case CONSDEV_COM2:
171 case CONSDEV_COM3:
172 iodev = dev;
173 btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0);
174 if (!btinfo_console.addr)
175 goto nocom;
176 cominit_x();
177 break;
178 case CONSDEV_COM0KBD:
179 case CONSDEV_COM1KBD:
180 case CONSDEV_COM2KBD:
181 case CONSDEV_COM3KBD:
182 iodev = dev - CONSDEV_COM0KBD + CONSDEV_COM0;
183 i = iodev - CONSDEV_COM0;
184 btinfo_console.addr = getcomaddr(i);
185 if (!btinfo_console.addr)
186 goto nocom;
187 conputc('0' + i); /* to tell user what happens */
188 cominit_x();
189 #ifdef DIRECT_SERIAL
190 /* check for:
191 * 1. successful output
192 * 2. optionally, keypress within 7s
193 */
194 if ( computc_x(':') &&
195 computc_x('-') &&
196 computc_x('(')
197 #ifdef COMCONS_KEYPRESS
198 && awaitkey(7, 0)
199 #endif
200 )
201 break;
202 #else /* ! DIRECT_SERIAL */
203 /*
204 * serial console must have hardware handshake!
205 * check:
206 * 1. character output without error
207 * 2. status bits for modem ready set
208 * (status seems only useful after character output)
209 * 3. optionally, keypress within 7s
210 */
211 if (!(computc_x('@') & 0x80)
212 && (comstatus_x() & 0x00b0)
213 #ifdef COMCONS_KEYPRESS
214 && awaitkey(7, 0)
215 #endif
216 )
217 break;
218 #endif /* DIRECT_SERIAL */
219 default:
220 nocom:
221 iodev = CONSDEV_PC;
222 break;
223 }
224 conputc('\015');
225 conputc('\n');
226 strncpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16);
227
228 #else /* !SUPPORT_SERIAL */
229 btinfo_console.devname[0] = 'p';
230 btinfo_console.devname[1] = 'c';
231 btinfo_console.devname[2] = 0;
232 #endif /* SUPPORT_SERIAL */
233 }
234
235 static inline void internal_putchar(int);
236
237 static inline void
238 internal_putchar(int c)
239 {
240 #ifdef SUPPORT_SERIAL
241 switch (iodev) {
242 case CONSDEV_PC:
243 #endif
244 conputc(c);
245 #ifdef SUPPORT_SERIAL
246 break;
247 case CONSDEV_COM0:
248 case CONSDEV_COM1:
249 case CONSDEV_COM2:
250 case CONSDEV_COM3:
251 computc_x(c);
252 break;
253 }
254 #endif
255 }
256
257 void
258 putchar(int c)
259 {
260 if (c == '\n')
261 internal_putchar('\r');
262 internal_putchar(c);
263 }
264
265 int
266 getchar(void)
267 {
268 int c;
269 #ifdef SUPPORT_SERIAL
270 switch (iodev) {
271 default: /* to make gcc -Wall happy... */
272 case CONSDEV_PC:
273 #endif
274 while (!coniskey())
275 ;
276 c = congetc();
277 #ifdef CONSOLE_KEYMAP
278 {
279 char *cp = strchr(CONSOLE_KEYMAP, c);
280 if (cp != 0 && cp[1] != 0)
281 c = cp[1];
282 }
283 #endif
284 return c;
285 #ifdef SUPPORT_SERIAL
286 case CONSDEV_COM0:
287 case CONSDEV_COM1:
288 case CONSDEV_COM2:
289 case CONSDEV_COM3:
290 #ifdef DIRECT_SERIAL
291 c = comgetc_x();
292 #else
293 do {
294 c = comgetc_x();
295 } while ((c >> 8) == 0xe0); /* catch timeout */
296 #ifdef COMDEBUG
297 if (c & 0x8000) {
298 printf("com input %x, status %x\n",
299 c, comstatus_x());
300 }
301 #endif
302 c &= 0xff;
303 #endif /* DIRECT_SERIAL */
304 return c;
305 }
306 #endif /* SUPPORT_SERIAL */
307 }
308
309 int
310 iskey(int intr)
311 {
312 #ifdef SUPPORT_SERIAL
313 switch (iodev) {
314 default: /* to make gcc -Wall happy... */
315 case CONSDEV_PC:
316 #endif
317 return (intr && conisshift()) || coniskey();
318 #ifdef SUPPORT_SERIAL
319 case CONSDEV_COM0:
320 case CONSDEV_COM1:
321 case CONSDEV_COM2:
322 case CONSDEV_COM3:
323 #ifdef DIRECT_SERIAL
324 return !!comstatus_x();
325 #else
326 return !!(comstatus_x() & 0x0100);
327 #endif
328 }
329 #endif /* SUPPORT_SERIAL */
330 }
331
332 char
333 awaitkey(int timeout, int tell)
334 {
335 int i;
336 char c = 0;
337
338 i = timeout * POLL_FREQ;
339
340 for (;;) {
341 if (tell && (i % POLL_FREQ) == 0) {
342 char numbuf[32];
343 int len;
344
345 len = snprintf(numbuf, sizeof(numbuf), "%d seconds. ",
346 i/POLL_FREQ);
347 if (len > 0 && len < sizeof(numbuf)) {
348 char *p = numbuf;
349
350 printf("%s", numbuf);
351 while (*p)
352 *p++ = '\b';
353 printf("%s", numbuf);
354 }
355 }
356 if (iskey(1)) {
357 /* flush input buffer */
358 while (iskey(0))
359 c = getchar();
360 if (c == 0)
361 c = -1;
362 goto out;
363 }
364 if (i--)
365 wait(1000000 / POLL_FREQ);
366 else
367 break;
368 }
369
370 out:
371 if (tell)
372 printf("0 seconds. \n");
373
374 return c;
375 }
376
377 void
378 wait_sec(int sec)
379 {
380
381 wait(sec * 1000000);
382 }
383