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 41extern struct x86_boot_params boot_params; 42 43struct btinfo_console btinfo_console; 44 45#ifdef SUPPORT_SERIAL 46static 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 65static int getcomaddr(int); 66#endif /* SUPPORT_SERIAL */ 67 68#define POLL_FREQ 10 69 70static void 71wait(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 85static int 86getcomaddr(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 99void 100clear_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 109void 110initio(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; 162ok: 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: 216nocom: 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 231static inline void internal_putchar(int); 232 233static inline void 234internal_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 253void 254putchar(int c) 255{ 256 if (c == '\n') 257 internal_putchar('\r'); 258 internal_putchar(c); 259} 260 261int 262getchar(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 305int 306iskey(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 328char 329awaitkey(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 366out: 367 if (tell) 368 printf("0 seconds. \n"); 369 370 return c; 371} 372 373void 374wait_sec(int sec) 375{ 376 377 wait(sec * 1000000); 378} 379