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