xref: /netbsd-src/sys/arch/i386/stand/lib/pcio.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
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