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 getchar(void) 263 { 264 int c; 265 #ifdef SUPPORT_SERIAL 266 switch (iodev) { 267 default: /* to make gcc -Wall happy... */ 268 case CONSDEV_PC: 269 #endif 270 while (!coniskey()) 271 ; 272 c = congetc(); 273 #ifdef CONSOLE_KEYMAP 274 { 275 char *cp = strchr(CONSOLE_KEYMAP, c); 276 if (cp != 0 && cp[1] != 0) 277 c = cp[1]; 278 } 279 #endif 280 return c; 281 #ifdef SUPPORT_SERIAL 282 case CONSDEV_COM0: 283 case CONSDEV_COM1: 284 case CONSDEV_COM2: 285 case CONSDEV_COM3: 286 #ifdef DIRECT_SERIAL 287 c = comgetc_x(); 288 #else 289 do { 290 c = comgetc_x(); 291 } while ((c >> 8) == 0xe0); /* catch timeout */ 292 #ifdef COMDEBUG 293 if (c & 0x8000) { 294 printf("com input %x, status %x\n", 295 c, comstatus_x()); 296 } 297 #endif 298 c &= 0xff; 299 #endif /* DIRECT_SERIAL */ 300 return c; 301 } 302 #endif /* SUPPORT_SERIAL */ 303 } 304 305 int 306 iskey(int intr) 307 { 308 #ifdef SUPPORT_SERIAL 309 switch (iodev) { 310 default: /* to make gcc -Wall happy... */ 311 case CONSDEV_PC: 312 #endif 313 return (intr && conisshift()) || coniskey(); 314 #ifdef SUPPORT_SERIAL 315 case CONSDEV_COM0: 316 case CONSDEV_COM1: 317 case CONSDEV_COM2: 318 case CONSDEV_COM3: 319 #ifdef DIRECT_SERIAL 320 return !!comstatus_x(); 321 #else 322 return !!(comstatus_x() & 0x0100); 323 #endif 324 } 325 #endif /* SUPPORT_SERIAL */ 326 } 327 328 char 329 awaitkey(int timeout, int tell) 330 { 331 int i; 332 char c = 0; 333 334 i = timeout * POLL_FREQ; 335 336 for (;;) { 337 if (tell && (i % POLL_FREQ) == 0) { 338 char numbuf[32]; 339 int len; 340 341 len = snprintf(numbuf, sizeof(numbuf), "%d seconds. ", 342 i/POLL_FREQ); 343 if (len > 0 && len < sizeof(numbuf)) { 344 char *p = numbuf; 345 346 printf("%s", numbuf); 347 while (*p) 348 *p++ = '\b'; 349 printf("%s", numbuf); 350 } 351 } 352 if (iskey(1)) { 353 /* flush input buffer */ 354 while (iskey(0)) 355 c = getchar(); 356 if (c == 0) 357 c = -1; 358 goto out; 359 } 360 if (i--) 361 wait(1000000 / POLL_FREQ); 362 else 363 break; 364 } 365 366 out: 367 if (tell) 368 printf("0 seconds. \n"); 369 370 return c; 371 } 372 373 void 374 wait_sec(int sec) 375 { 376 377 wait(sec * 1000000); 378 } 379