pcio.c revision 1.16 1 /* $NetBSD: pcio.c,v 1.16 2004/03/13 22:41:38 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 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the NetBSD Project
18 * by Matthias Drochner.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 */
34
35 /*
36 * console I/O
37 * needs lowlevel routines from conio.S and comio.S
38 */
39
40 #include <lib/libsa/stand.h>
41 #include <lib/libkern/libkern.h>
42 #include <sys/bootblock.h>
43
44 #include "libi386.h"
45 #include "bootinfo.h"
46
47 extern void conputc __P((int));
48 extern int congetc __P((void));
49 extern int coniskey __P((void));
50 extern struct x86_boot_params boot_params;
51
52 struct btinfo_console btinfo_console;
53
54 #ifdef SUPPORT_SERIAL
55 static int iodev;
56
57 #ifdef DIRECT_SERIAL
58 #include "comio_direct.h"
59
60 #define cominit_x() cominit_d(btinfo_console.addr, btinfo_console.speed)
61 #define computc_x(ch) computc_d(ch, btinfo_console.addr)
62 #define comgetc_x() comgetc_d(btinfo_console.addr)
63 #define comstatus_x() comstatus_d(btinfo_console.addr)
64
65 #else
66 #define cominit_x() cominit(iodev - CONSDEV_COM0)
67 #define computc_x(ch) computc(ch, iodev - CONSDEV_COM0)
68 #define comgetc_x() comgetc(iodev - CONSDEV_COM0)
69 #define comstatus_x() comstatus(iodev - CONSDEV_COM0)
70
71 #endif /* DIRECT_SERIAL */
72
73 static int getcomaddr __P((int));
74 #endif /* SUPPORT_SERIAL */
75
76 #define POLL_FREQ 10
77
78 #ifdef SUPPORT_SERIAL
79 static int
80 getcomaddr(idx)
81 int idx;
82 {
83 short addr;
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 - 4;
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()
288 {
289 #ifdef SUPPORT_SERIAL
290 switch (iodev) {
291 default: /* to make gcc -Wall happy... */
292 case CONSDEV_PC:
293 #endif
294 return (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 while (i) {
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()) {
331 /* flush input buffer */
332 while (iskey())
333 c = getchar();
334 if (c == 0)
335 c = -1;
336 goto out;
337 }
338 delay(1000000 / POLL_FREQ);
339 i--;
340 }
341
342 out:
343 if (tell)
344 printf("0 \n");
345
346 return(c);
347 }
348