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