xref: /netbsd-src/sys/arch/i386/stand/lib/pcio.c (revision f82d7874c259b2a6cc59b714f844919f32bf7b51)
1 /*	$NetBSD: pcio.c,v 1.23 2008/05/21 13:36:45 ad 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 
204 	if (iodev == CONSDEV_PC) {
205 		/* Clear screen if on a glass tty. */
206 		conclr();
207 	}
208 #else /* !SUPPORT_SERIAL */
209 	btinfo_console.devname[0] = 'p';
210 	btinfo_console.devname[1] = 'c';
211 	btinfo_console.devname[2] = 0;
212 #endif /* SUPPORT_SERIAL */
213 }
214 
215 static inline void internal_putchar(int);
216 
217 static inline void
218 internal_putchar(int c)
219 {
220 #ifdef SUPPORT_SERIAL
221 	switch (iodev) {
222 	case CONSDEV_PC:
223 #endif
224 		conputc(c);
225 #ifdef SUPPORT_SERIAL
226 		break;
227 	case CONSDEV_COM0:
228 	case CONSDEV_COM1:
229 	case CONSDEV_COM2:
230 	case CONSDEV_COM3:
231 		computc_x(c);
232 		break;
233 	}
234 #endif
235 }
236 
237 void
238 putchar(int c)
239 {
240 	if (c == '\n')
241 		internal_putchar('\r');
242 	internal_putchar(c);
243 }
244 
245 int
246 getchar(void)
247 {
248 	int c;
249 #ifdef SUPPORT_SERIAL
250 	switch (iodev) {
251 	default: /* to make gcc -Wall happy... */
252 	case CONSDEV_PC:
253 #endif
254 		c = congetc();
255 #ifdef CONSOLE_KEYMAP
256 		{
257 			char *cp = strchr(CONSOLE_KEYMAP, c);
258 			if (cp != 0 && cp[1] != 0)
259 				c = cp[1];
260 		}
261 #endif
262 		return c;
263 #ifdef SUPPORT_SERIAL
264 	case CONSDEV_COM0:
265 	case CONSDEV_COM1:
266 	case CONSDEV_COM2:
267 	case CONSDEV_COM3:
268 #ifdef DIRECT_SERIAL
269 		c = comgetc_x();
270 #else
271 		do {
272 			c = comgetc_x();
273 		} while ((c >> 8) == 0xe0); /* catch timeout */
274 #ifdef COMDEBUG
275 		if (c & 0x8000) {
276 			printf("com input %x, status %x\n",
277 			       c, comstatus_x());
278 		}
279 #endif
280 		c &= 0xff;
281 #endif /* DIRECT_SERIAL */
282 		return c;
283 	}
284 #endif /* SUPPORT_SERIAL */
285 }
286 
287 int
288 iskey(int intr)
289 {
290 #ifdef SUPPORT_SERIAL
291 	switch (iodev) {
292 	default: /* to make gcc -Wall happy... */
293 	case CONSDEV_PC:
294 #endif
295 		return (intr && conisshift()) || coniskey();
296 #ifdef SUPPORT_SERIAL
297 	case CONSDEV_COM0:
298 	case CONSDEV_COM1:
299 	case CONSDEV_COM2:
300 	case CONSDEV_COM3:
301 #ifdef DIRECT_SERIAL
302 		return !!comstatus_x();
303 #else
304 		return !!(comstatus_x() & 0x0100);
305 #endif
306 	}
307 #endif /* SUPPORT_SERIAL */
308 }
309 
310 char
311 awaitkey(int timeout, int tell)
312 {
313 	int i;
314 	char c = 0;
315 
316 	i = timeout * POLL_FREQ;
317 
318 	for (;;) {
319 		if (tell && (i % POLL_FREQ) == 0) {
320 			char numbuf[20];
321 			int len, j;
322 
323 			sprintf(numbuf, "%d ", i/POLL_FREQ);
324 			len = strlen(numbuf);
325 			for (j = 0; j < len; j++)
326 				numbuf[len + j] = '\b';
327 			numbuf[len + j] = '\0';
328 			printf(numbuf);
329 		}
330 		if (iskey(1)) {
331 			/* flush input buffer */
332 			while (iskey(0))
333 				c = getchar();
334 			if (c == 0)
335 				c = -1;
336 			goto out;
337 		}
338 		if (i--)
339 			delay(1000000 / POLL_FREQ);
340 		else
341 			break;
342 	}
343 
344 out:
345 	if (tell)
346 		printf("0 \n");
347 
348 	return c;
349 }
350