Home | History | Annotate | Line # | Download | only in lib
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