pcio.c revision 1.16 1 1.16 dsl /* $NetBSD: pcio.c,v 1.16 2004/03/13 22:41:38 dsl Exp $ */
2 1.1 perry
3 1.1 perry /*
4 1.5 drochner * Copyright (c) 1996, 1997
5 1.1 perry * Matthias Drochner. All rights reserved.
6 1.1 perry *
7 1.1 perry * Redistribution and use in source and binary forms, with or without
8 1.1 perry * modification, are permitted provided that the following conditions
9 1.1 perry * are met:
10 1.1 perry * 1. Redistributions of source code must retain the above copyright
11 1.1 perry * notice, this list of conditions and the following disclaimer.
12 1.1 perry * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 perry * notice, this list of conditions and the following disclaimer in the
14 1.1 perry * documentation and/or other materials provided with the distribution.
15 1.1 perry * 3. All advertising materials mentioning features or use of this software
16 1.1 perry * must display the following acknowledgement:
17 1.1 perry * This product includes software developed for the NetBSD Project
18 1.1 perry * by Matthias Drochner.
19 1.1 perry * 4. The name of the author may not be used to endorse or promote products
20 1.1 perry * derived from this software without specific prior written permission.
21 1.1 perry *
22 1.1 perry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 1.1 perry * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 1.1 perry * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 1.1 perry * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 1.1 perry * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 1.1 perry * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 1.1 perry * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 1.1 perry * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 1.1 perry * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 1.1 perry * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 1.1 perry *
33 1.1 perry */
34 1.1 perry
35 1.3 thorpej /*
36 1.4 drochner * console I/O
37 1.4 drochner * needs lowlevel routines from conio.S and comio.S
38 1.3 thorpej */
39 1.1 perry
40 1.1 perry #include <lib/libsa/stand.h>
41 1.5 drochner #include <lib/libkern/libkern.h>
42 1.14 dsl #include <sys/bootblock.h>
43 1.1 perry
44 1.1 perry #include "libi386.h"
45 1.5 drochner #include "bootinfo.h"
46 1.1 perry
47 1.1 perry extern void conputc __P((int));
48 1.1 perry extern int congetc __P((void));
49 1.1 perry extern int coniskey __P((void));
50 1.15 lukem extern struct x86_boot_params boot_params;
51 1.1 perry
52 1.5 drochner struct btinfo_console btinfo_console;
53 1.5 drochner
54 1.1 perry #ifdef SUPPORT_SERIAL
55 1.5 drochner static int iodev;
56 1.5 drochner
57 1.5 drochner #ifdef DIRECT_SERIAL
58 1.5 drochner #include "comio_direct.h"
59 1.5 drochner
60 1.14 dsl #define cominit_x() cominit_d(btinfo_console.addr, btinfo_console.speed)
61 1.14 dsl #define computc_x(ch) computc_d(ch, btinfo_console.addr)
62 1.14 dsl #define comgetc_x() comgetc_d(btinfo_console.addr)
63 1.14 dsl #define comstatus_x() comstatus_d(btinfo_console.addr)
64 1.5 drochner
65 1.5 drochner #else
66 1.14 dsl #define cominit_x() cominit(iodev - CONSDEV_COM0)
67 1.14 dsl #define computc_x(ch) computc(ch, iodev - CONSDEV_COM0)
68 1.14 dsl #define comgetc_x() comgetc(iodev - CONSDEV_COM0)
69 1.14 dsl #define comstatus_x() comstatus(iodev - CONSDEV_COM0)
70 1.1 perry
71 1.5 drochner #endif /* DIRECT_SERIAL */
72 1.5 drochner
73 1.5 drochner static int getcomaddr __P((int));
74 1.5 drochner #endif /* SUPPORT_SERIAL */
75 1.5 drochner
76 1.5 drochner #define POLL_FREQ 10
77 1.1 perry
78 1.1 perry #ifdef SUPPORT_SERIAL
79 1.5 drochner static int
80 1.5 drochner getcomaddr(idx)
81 1.9 drochner int idx;
82 1.5 drochner {
83 1.5 drochner short addr;
84 1.5 drochner /* read in BIOS data area */
85 1.8 sommerfe pvbcopy((void *)(0x400 + 2 * idx), &addr, 2);
86 1.5 drochner return(addr);
87 1.5 drochner }
88 1.1 perry #endif
89 1.1 perry
90 1.5 drochner void
91 1.3 thorpej initio(dev)
92 1.3 thorpej int dev;
93 1.1 perry {
94 1.1 perry #ifdef SUPPORT_SERIAL
95 1.5 drochner int i;
96 1.5 drochner
97 1.14 dsl #if defined(DIRECT_SERIAL) && defined(CONSPEED)
98 1.14 dsl btinfo_console.speed = CONSPEED;
99 1.14 dsl #else
100 1.14 dsl btinfo_console.speed = 9600;
101 1.14 dsl #endif
102 1.14 dsl
103 1.3 thorpej switch (dev) {
104 1.5 drochner case CONSDEV_AUTO:
105 1.5 drochner for(i = 0; i < 3; i++) {
106 1.5 drochner iodev = CONSDEV_COM0 + i;
107 1.5 drochner btinfo_console.addr = getcomaddr(i);
108 1.12 dsl if(!btinfo_console.addr)
109 1.12 dsl break;
110 1.5 drochner conputc('0' + i); /* to tell user what happens */
111 1.14 dsl cominit_x();
112 1.5 drochner #ifdef DIRECT_SERIAL
113 1.5 drochner /* check for:
114 1.5 drochner * 1. successful output
115 1.12 dsl * 2. optionally, keypress within 7s
116 1.5 drochner */
117 1.14 dsl if ( computc_x(':') &&
118 1.14 dsl computc_x('-') &&
119 1.14 dsl computc_x('(')
120 1.5 drochner #ifdef COMCONS_KEYPRESS
121 1.7 rvb && awaitkey(7, 0)
122 1.5 drochner #endif
123 1.5 drochner )
124 1.5 drochner goto ok;
125 1.11 thorpej #else /* ! DIRECT_SERIAL */
126 1.5 drochner /*
127 1.5 drochner * serial console must have hardware handshake!
128 1.5 drochner * check:
129 1.5 drochner * 1. character output without error
130 1.5 drochner * 2. status bits for modem ready set
131 1.5 drochner * (status seems only useful after character output)
132 1.12 dsl * 3. optionally, keypress within 7s
133 1.5 drochner */
134 1.14 dsl if (!(computc_x('@') & 0x80)
135 1.14 dsl && (comstatus_x() & 0x00b0)
136 1.5 drochner #ifdef COMCONS_KEYPRESS
137 1.7 rvb && awaitkey(7, 0)
138 1.5 drochner #endif
139 1.5 drochner )
140 1.5 drochner goto ok;
141 1.11 thorpej #endif /* DIRECT_SERIAL */
142 1.3 thorpej }
143 1.5 drochner iodev = CONSDEV_PC;
144 1.5 drochner ok:
145 1.3 thorpej break;
146 1.5 drochner case CONSDEV_COM0:
147 1.5 drochner case CONSDEV_COM1:
148 1.5 drochner case CONSDEV_COM2:
149 1.5 drochner case CONSDEV_COM3:
150 1.5 drochner iodev = dev;
151 1.5 drochner btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0);
152 1.12 dsl if(!btinfo_console.addr)
153 1.12 dsl goto nocom;
154 1.14 dsl cominit_x();
155 1.3 thorpej break;
156 1.7 rvb case CONSDEV_COM0KBD:
157 1.7 rvb case CONSDEV_COM1KBD:
158 1.7 rvb case CONSDEV_COM2KBD:
159 1.7 rvb case CONSDEV_COM3KBD:
160 1.7 rvb iodev = dev - 4;
161 1.7 rvb i = iodev - CONSDEV_COM0;
162 1.7 rvb btinfo_console.addr = getcomaddr(i);
163 1.12 dsl if(!btinfo_console.addr)
164 1.12 dsl goto nocom;
165 1.7 rvb conputc('0' + i); /* to tell user what happens */
166 1.14 dsl cominit_x();
167 1.7 rvb #ifdef DIRECT_SERIAL
168 1.7 rvb /* check for:
169 1.7 rvb * 1. successful output
170 1.12 dsl * 2. optionally, keypress within 7s
171 1.7 rvb */
172 1.14 dsl if ( computc_x(':') &&
173 1.14 dsl computc_x('-') &&
174 1.14 dsl computc_x('(')
175 1.7 rvb #ifdef COMCONS_KEYPRESS
176 1.7 rvb && awaitkey(7, 0)
177 1.7 rvb #endif
178 1.7 rvb )
179 1.7 rvb break;
180 1.11 thorpej #else /* ! DIRECT_SERIAL */
181 1.7 rvb /*
182 1.7 rvb * serial console must have hardware handshake!
183 1.7 rvb * check:
184 1.7 rvb * 1. character output without error
185 1.7 rvb * 2. status bits for modem ready set
186 1.7 rvb * (status seems only useful after character output)
187 1.12 dsl * 3. optionally, keypress within 7s
188 1.7 rvb */
189 1.14 dsl if (!(computc_x('@') & 0x80)
190 1.14 dsl && (comstatus_x() & 0x00b0)
191 1.7 rvb #ifdef COMCONS_KEYPRESS
192 1.7 rvb && awaitkey(7, 0)
193 1.7 rvb #endif
194 1.7 rvb )
195 1.7 rvb break;
196 1.11 thorpej #endif /* DIRECT_SERIAL */
197 1.5 drochner default:
198 1.5 drochner nocom:
199 1.5 drochner iodev = CONSDEV_PC;
200 1.3 thorpej break;
201 1.3 thorpej }
202 1.7 rvb conputc('\015');
203 1.7 rvb conputc('\n');
204 1.5 drochner strncpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16);
205 1.5 drochner #else /* !SUPPORT_SERIAL */
206 1.13 dsl btinfo_console.devname[0] = 'p';
207 1.13 dsl btinfo_console.devname[1] = 'c';
208 1.13 dsl btinfo_console.devname[2] = 0;
209 1.5 drochner #endif /* SUPPORT_SERIAL */
210 1.1 perry }
211 1.1 perry
212 1.9 drochner static inline void internal_putchar __P((int));
213 1.9 drochner
214 1.3 thorpej static inline void
215 1.3 thorpej internal_putchar(c)
216 1.9 drochner int c;
217 1.1 perry {
218 1.1 perry #ifdef SUPPORT_SERIAL
219 1.3 thorpej switch (iodev) {
220 1.5 drochner case CONSDEV_PC:
221 1.1 perry #endif
222 1.3 thorpej conputc(c);
223 1.1 perry #ifdef SUPPORT_SERIAL
224 1.3 thorpej break;
225 1.5 drochner case CONSDEV_COM0:
226 1.5 drochner case CONSDEV_COM1:
227 1.5 drochner case CONSDEV_COM2:
228 1.5 drochner case CONSDEV_COM3:
229 1.14 dsl computc_x(c);
230 1.3 thorpej break;
231 1.3 thorpej }
232 1.1 perry #endif
233 1.1 perry }
234 1.1 perry
235 1.3 thorpej void
236 1.3 thorpej putchar(c)
237 1.9 drochner int c;
238 1.1 perry {
239 1.3 thorpej if (c == '\n')
240 1.3 thorpej internal_putchar('\r');
241 1.3 thorpej internal_putchar(c);
242 1.1 perry }
243 1.1 perry
244 1.3 thorpej int
245 1.3 thorpej getchar()
246 1.3 thorpej {
247 1.16 dsl int c;
248 1.1 perry #ifdef SUPPORT_SERIAL
249 1.3 thorpej switch (iodev) {
250 1.5 drochner default: /* to make gcc -Wall happy... */
251 1.5 drochner case CONSDEV_PC:
252 1.1 perry #endif
253 1.16 dsl c = congetc();
254 1.16 dsl #ifdef CONSOLE_KEYMAP
255 1.16 dsl {
256 1.16 dsl char *cp = strchr(CONSOLE_KEYMAP, c);
257 1.16 dsl if (cp != 0 && cp[1] != 0)
258 1.16 dsl c = cp[1];
259 1.16 dsl }
260 1.16 dsl #endif
261 1.16 dsl return c;
262 1.1 perry #ifdef SUPPORT_SERIAL
263 1.5 drochner case CONSDEV_COM0:
264 1.5 drochner case CONSDEV_COM1:
265 1.5 drochner case CONSDEV_COM2:
266 1.5 drochner case CONSDEV_COM3:
267 1.6 drochner #ifdef DIRECT_SERIAL
268 1.14 dsl c = comgetc_x();
269 1.6 drochner #else
270 1.6 drochner do {
271 1.14 dsl c = comgetc_x();
272 1.6 drochner } while ((c >> 8) == 0xe0); /* catch timeout */
273 1.6 drochner #ifdef COMDEBUG
274 1.6 drochner if (c & 0x8000) {
275 1.6 drochner printf("com input %x, status %x\n",
276 1.14 dsl c, comstatus_x());
277 1.6 drochner }
278 1.6 drochner #endif
279 1.6 drochner c &= 0xff;
280 1.6 drochner #endif /* DIRECT_SERIAL */
281 1.6 drochner return (c);
282 1.3 thorpej }
283 1.6 drochner #endif /* SUPPORT_SERIAL */
284 1.1 perry }
285 1.1 perry
286 1.3 thorpej int
287 1.3 thorpej iskey()
288 1.3 thorpej {
289 1.1 perry #ifdef SUPPORT_SERIAL
290 1.3 thorpej switch (iodev) {
291 1.5 drochner default: /* to make gcc -Wall happy... */
292 1.5 drochner case CONSDEV_PC:
293 1.1 perry #endif
294 1.3 thorpej return (coniskey());
295 1.1 perry #ifdef SUPPORT_SERIAL
296 1.5 drochner case CONSDEV_COM0:
297 1.5 drochner case CONSDEV_COM1:
298 1.5 drochner case CONSDEV_COM2:
299 1.5 drochner case CONSDEV_COM3:
300 1.5 drochner #ifdef DIRECT_SERIAL
301 1.14 dsl return(!!comstatus_x());
302 1.5 drochner #else
303 1.14 dsl return (!!(comstatus_x() & 0x0100));
304 1.5 drochner #endif
305 1.3 thorpej }
306 1.5 drochner #endif /* SUPPORT_SERIAL */
307 1.5 drochner }
308 1.5 drochner
309 1.5 drochner char
310 1.5 drochner awaitkey(timeout, tell)
311 1.5 drochner int timeout, tell;
312 1.5 drochner {
313 1.5 drochner int i;
314 1.5 drochner char c = 0;
315 1.5 drochner
316 1.5 drochner i = timeout * POLL_FREQ;
317 1.5 drochner
318 1.5 drochner while (i) {
319 1.10 drochner if (tell && (i % POLL_FREQ) == 0) {
320 1.10 drochner char numbuf[20];
321 1.10 drochner int len, j;
322 1.10 drochner
323 1.10 drochner sprintf(numbuf, "%d ", i/POLL_FREQ);
324 1.10 drochner len = strlen(numbuf);
325 1.10 drochner for (j = 0; j < len; j++)
326 1.10 drochner numbuf[len + j] = '\b';
327 1.10 drochner numbuf[len + j] = '\0';
328 1.10 drochner printf(numbuf);
329 1.10 drochner }
330 1.5 drochner if (iskey()) {
331 1.5 drochner /* flush input buffer */
332 1.5 drochner while (iskey())
333 1.5 drochner c = getchar();
334 1.12 dsl if (c == 0)
335 1.12 dsl c = -1;
336 1.12 dsl goto out;
337 1.5 drochner }
338 1.5 drochner delay(1000000 / POLL_FREQ);
339 1.5 drochner i--;
340 1.5 drochner }
341 1.5 drochner
342 1.5 drochner out:
343 1.5 drochner if (tell)
344 1.16 dsl printf("0 \n");
345 1.5 drochner
346 1.5 drochner return(c);
347 1.1 perry }
348