pcio.c revision 1.12 1 /* $NetBSD: pcio.c,v 1.12 2003/02/01 14:48:18 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 strncpy(btinfo_console.devname, "pc", 16);
206 #endif /* SUPPORT_SERIAL */
207 }
208
209 static inline void internal_putchar __P((int));
210
211 static inline void
212 internal_putchar(c)
213 int c;
214 {
215 #ifdef SUPPORT_SERIAL
216 switch (iodev) {
217 case CONSDEV_PC:
218 #endif
219 conputc(c);
220 #ifdef SUPPORT_SERIAL
221 break;
222 case CONSDEV_COM0:
223 case CONSDEV_COM1:
224 case CONSDEV_COM2:
225 case CONSDEV_COM3:
226 computc(c, SERIAL_ARG);
227 break;
228 }
229 #endif
230 }
231
232 void
233 putchar(c)
234 int c;
235 {
236 if (c == '\n')
237 internal_putchar('\r');
238 internal_putchar(c);
239 }
240
241 int
242 getchar()
243 {
244 #ifdef SUPPORT_SERIAL
245 int c;
246 switch (iodev) {
247 default: /* to make gcc -Wall happy... */
248 case CONSDEV_PC:
249 #endif
250 return (congetc());
251 #ifdef SUPPORT_SERIAL
252 case CONSDEV_COM0:
253 case CONSDEV_COM1:
254 case CONSDEV_COM2:
255 case CONSDEV_COM3:
256 #ifdef DIRECT_SERIAL
257 c = comgetc(SERIAL_ARG);
258 #else
259 do {
260 c = comgetc(SERIAL_ARG);
261 } while ((c >> 8) == 0xe0); /* catch timeout */
262 #ifdef COMDEBUG
263 if (c & 0x8000) {
264 printf("com input %x, status %x\n",
265 c, comstatus(SERIAL_ARG));
266 }
267 #endif
268 c &= 0xff;
269 #endif /* DIRECT_SERIAL */
270 return (c);
271 }
272 #endif /* SUPPORT_SERIAL */
273 }
274
275 int
276 iskey()
277 {
278 #ifdef SUPPORT_SERIAL
279 switch (iodev) {
280 default: /* to make gcc -Wall happy... */
281 case CONSDEV_PC:
282 #endif
283 return (coniskey());
284 #ifdef SUPPORT_SERIAL
285 case CONSDEV_COM0:
286 case CONSDEV_COM1:
287 case CONSDEV_COM2:
288 case CONSDEV_COM3:
289 #ifdef DIRECT_SERIAL
290 return(!!comstatus_d(SERIAL_ARG));
291 #else
292 return (!!(comstatus(SERIAL_ARG) & 0x0100));
293 #endif
294 }
295 #endif /* SUPPORT_SERIAL */
296 }
297
298 char
299 awaitkey(timeout, tell)
300 int timeout, tell;
301 {
302 int i;
303 char c = 0;
304
305 i = timeout * POLL_FREQ;
306
307 while (i) {
308 if (tell && (i % POLL_FREQ) == 0) {
309 char numbuf[20];
310 int len, j;
311
312 sprintf(numbuf, "%d ", i/POLL_FREQ);
313 len = strlen(numbuf);
314 for (j = 0; j < len; j++)
315 numbuf[len + j] = '\b';
316 numbuf[len + j] = '\0';
317 printf(numbuf);
318 }
319 if (iskey()) {
320 /* flush input buffer */
321 while (iskey())
322 c = getchar();
323 if (c == 0)
324 c = -1;
325 goto out;
326 }
327 delay(1000000 / POLL_FREQ);
328 i--;
329 }
330
331 out:
332 if (tell)
333 printf("0\n");
334
335 return(c);
336 }
337