pcio.c revision 1.13 1 /* $NetBSD: pcio.c,v 1.13 2003/03/08 21:30:59 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
43 #include "libi386.h"
44 #include "bootinfo.h"
45
46 extern void conputc __P((int));
47 extern int congetc __P((void));
48 extern int coniskey __P((void));
49
50 struct btinfo_console btinfo_console;
51
52 #ifdef SUPPORT_SERIAL
53 static int iodev;
54
55 #ifdef DIRECT_SERIAL
56 #include "comio_direct.h"
57
58 #define cominit cominit_d
59 #define computc computc_d
60 #define comgetc comgetc_d
61 /* comstatus() is different */
62
63 #define SERIAL_ARG btinfo_console.addr
64 #else
65 extern void cominit __P((int));
66 extern int computc __P((int, int));
67 extern int comgetc __P((int));
68 extern int comstatus __P((int));
69
70 #define SERIAL_ARG (iodev - CONSDEV_COM0)
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 switch (dev) {
98 case CONSDEV_AUTO:
99 for(i = 0; i < 3; i++) {
100 iodev = CONSDEV_COM0 + i;
101 btinfo_console.addr = getcomaddr(i);
102 if(!btinfo_console.addr)
103 break;
104 conputc('0' + i); /* to tell user what happens */
105 cominit(SERIAL_ARG);
106 #ifdef DIRECT_SERIAL
107 /* check for:
108 * 1. successful output
109 * 2. optionally, keypress within 7s
110 */
111 if ( computc(':', SERIAL_ARG) &&
112 computc('-', SERIAL_ARG) &&
113 computc('(', SERIAL_ARG)
114 #ifdef COMCONS_KEYPRESS
115 && awaitkey(7, 0)
116 #endif
117 )
118 goto ok;
119 #else /* ! DIRECT_SERIAL */
120 /*
121 * serial console must have hardware handshake!
122 * check:
123 * 1. character output without error
124 * 2. status bits for modem ready set
125 * (status seems only useful after character output)
126 * 3. optionally, keypress within 7s
127 */
128 if (!(computc('@', SERIAL_ARG) & 0x80)
129 && (comstatus(SERIAL_ARG) & 0x00b0)
130 #ifdef COMCONS_KEYPRESS
131 && awaitkey(7, 0)
132 #endif
133 )
134 goto ok;
135 #endif /* DIRECT_SERIAL */
136 }
137 iodev = CONSDEV_PC;
138 ok:
139 break;
140 case CONSDEV_COM0:
141 case CONSDEV_COM1:
142 case CONSDEV_COM2:
143 case CONSDEV_COM3:
144 iodev = dev;
145 btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0);
146 if(!btinfo_console.addr)
147 goto nocom;
148 cominit(SERIAL_ARG);
149 break;
150 case CONSDEV_COM0KBD:
151 case CONSDEV_COM1KBD:
152 case CONSDEV_COM2KBD:
153 case CONSDEV_COM3KBD:
154 iodev = dev - 4;
155 i = iodev - CONSDEV_COM0;
156 btinfo_console.addr = getcomaddr(i);
157 if(!btinfo_console.addr)
158 goto nocom;
159 conputc('0' + i); /* to tell user what happens */
160 cominit(SERIAL_ARG);
161 #ifdef DIRECT_SERIAL
162 /* check for:
163 * 1. successful output
164 * 2. optionally, keypress within 7s
165 */
166 if ( computc(':', SERIAL_ARG) &&
167 computc('-', SERIAL_ARG) &&
168 computc('(', SERIAL_ARG)
169 #ifdef COMCONS_KEYPRESS
170 && awaitkey(7, 0)
171 #endif
172 )
173 break;
174 #else /* ! DIRECT_SERIAL */
175 /*
176 * serial console must have hardware handshake!
177 * check:
178 * 1. character output without error
179 * 2. status bits for modem ready set
180 * (status seems only useful after character output)
181 * 3. optionally, keypress within 7s
182 */
183 if (!(computc('@', SERIAL_ARG) & 0x80)
184 && (comstatus(SERIAL_ARG) & 0x00b0)
185 #ifdef COMCONS_KEYPRESS
186 && awaitkey(7, 0)
187 #endif
188 )
189 break;
190 #endif /* DIRECT_SERIAL */
191 default:
192 nocom:
193 iodev = CONSDEV_PC;
194 break;
195 }
196 conputc('\015');
197 conputc('\n');
198 strncpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16);
199 #if defined(DIRECT_SERIAL) && defined(CONSPEED)
200 btinfo_console.speed = CONSPEED;
201 #else
202 btinfo_console.speed = 9600;
203 #endif
204 #else /* !SUPPORT_SERIAL */
205 btinfo_console.devname[0] = 'p';
206 btinfo_console.devname[1] = 'c';
207 btinfo_console.devname[2] = 0;
208 #endif /* SUPPORT_SERIAL */
209 }
210
211 static inline void internal_putchar __P((int));
212
213 static inline void
214 internal_putchar(c)
215 int c;
216 {
217 #ifdef SUPPORT_SERIAL
218 switch (iodev) {
219 case CONSDEV_PC:
220 #endif
221 conputc(c);
222 #ifdef SUPPORT_SERIAL
223 break;
224 case CONSDEV_COM0:
225 case CONSDEV_COM1:
226 case CONSDEV_COM2:
227 case CONSDEV_COM3:
228 computc(c, SERIAL_ARG);
229 break;
230 }
231 #endif
232 }
233
234 void
235 putchar(c)
236 int c;
237 {
238 if (c == '\n')
239 internal_putchar('\r');
240 internal_putchar(c);
241 }
242
243 int
244 getchar()
245 {
246 #ifdef SUPPORT_SERIAL
247 int c;
248 switch (iodev) {
249 default: /* to make gcc -Wall happy... */
250 case CONSDEV_PC:
251 #endif
252 return (congetc());
253 #ifdef SUPPORT_SERIAL
254 case CONSDEV_COM0:
255 case CONSDEV_COM1:
256 case CONSDEV_COM2:
257 case CONSDEV_COM3:
258 #ifdef DIRECT_SERIAL
259 c = comgetc(SERIAL_ARG);
260 #else
261 do {
262 c = comgetc(SERIAL_ARG);
263 } while ((c >> 8) == 0xe0); /* catch timeout */
264 #ifdef COMDEBUG
265 if (c & 0x8000) {
266 printf("com input %x, status %x\n",
267 c, comstatus(SERIAL_ARG));
268 }
269 #endif
270 c &= 0xff;
271 #endif /* DIRECT_SERIAL */
272 return (c);
273 }
274 #endif /* SUPPORT_SERIAL */
275 }
276
277 int
278 iskey()
279 {
280 #ifdef SUPPORT_SERIAL
281 switch (iodev) {
282 default: /* to make gcc -Wall happy... */
283 case CONSDEV_PC:
284 #endif
285 return (coniskey());
286 #ifdef SUPPORT_SERIAL
287 case CONSDEV_COM0:
288 case CONSDEV_COM1:
289 case CONSDEV_COM2:
290 case CONSDEV_COM3:
291 #ifdef DIRECT_SERIAL
292 return(!!comstatus_d(SERIAL_ARG));
293 #else
294 return (!!(comstatus(SERIAL_ARG) & 0x0100));
295 #endif
296 }
297 #endif /* SUPPORT_SERIAL */
298 }
299
300 char
301 awaitkey(timeout, tell)
302 int timeout, tell;
303 {
304 int i;
305 char c = 0;
306
307 i = timeout * POLL_FREQ;
308
309 while (i) {
310 if (tell && (i % POLL_FREQ) == 0) {
311 char numbuf[20];
312 int len, j;
313
314 sprintf(numbuf, "%d ", i/POLL_FREQ);
315 len = strlen(numbuf);
316 for (j = 0; j < len; j++)
317 numbuf[len + j] = '\b';
318 numbuf[len + j] = '\0';
319 printf(numbuf);
320 }
321 if (iskey()) {
322 /* flush input buffer */
323 while (iskey())
324 c = getchar();
325 if (c == 0)
326 c = -1;
327 goto out;
328 }
329 delay(1000000 / POLL_FREQ);
330 i--;
331 }
332
333 out:
334 if (tell)
335 printf("0\n");
336
337 return(c);
338 }
339