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