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