1 1.30 joerg /* $NetBSD: pcio.c,v 1.30 2011/06/08 16:04:40 joerg Exp $ */ 2 1.1 perry 3 1.1 perry /* 4 1.5 drochner * Copyright (c) 1996, 1997 5 1.1 perry * Matthias Drochner. All rights reserved. 6 1.1 perry * 7 1.1 perry * Redistribution and use in source and binary forms, with or without 8 1.1 perry * modification, are permitted provided that the following conditions 9 1.1 perry * are met: 10 1.1 perry * 1. Redistributions of source code must retain the above copyright 11 1.1 perry * notice, this list of conditions and the following disclaimer. 12 1.1 perry * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 perry * notice, this list of conditions and the following disclaimer in the 14 1.1 perry * documentation and/or other materials provided with the distribution. 15 1.1 perry * 16 1.1 perry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 perry * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 perry * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 perry * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 perry * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 1.1 perry * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.1 perry * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 1.1 perry * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 1.1 perry * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 1.1 perry * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 1.1 perry * 27 1.1 perry */ 28 1.1 perry 29 1.3 thorpej /* 30 1.4 drochner * console I/O 31 1.4 drochner * needs lowlevel routines from conio.S and comio.S 32 1.3 thorpej */ 33 1.1 perry 34 1.1 perry #include <lib/libsa/stand.h> 35 1.5 drochner #include <lib/libkern/libkern.h> 36 1.14 dsl #include <sys/bootblock.h> 37 1.1 perry 38 1.1 perry #include "libi386.h" 39 1.5 drochner #include "bootinfo.h" 40 1.1 perry 41 1.15 lukem extern struct x86_boot_params boot_params; 42 1.1 perry 43 1.5 drochner struct btinfo_console btinfo_console; 44 1.5 drochner 45 1.1 perry #ifdef SUPPORT_SERIAL 46 1.5 drochner static int iodev; 47 1.5 drochner 48 1.5 drochner #ifdef DIRECT_SERIAL 49 1.5 drochner #include "comio_direct.h" 50 1.5 drochner 51 1.20 dsl #define cominit_x() btinfo_console.speed = \ 52 1.20 dsl cominit_d(btinfo_console.addr, btinfo_console.speed) 53 1.14 dsl #define computc_x(ch) computc_d(ch, btinfo_console.addr) 54 1.14 dsl #define comgetc_x() comgetc_d(btinfo_console.addr) 55 1.14 dsl #define comstatus_x() comstatus_d(btinfo_console.addr) 56 1.5 drochner 57 1.5 drochner #else 58 1.14 dsl #define cominit_x() cominit(iodev - CONSDEV_COM0) 59 1.14 dsl #define computc_x(ch) computc(ch, iodev - CONSDEV_COM0) 60 1.14 dsl #define comgetc_x() comgetc(iodev - CONSDEV_COM0) 61 1.14 dsl #define comstatus_x() comstatus(iodev - CONSDEV_COM0) 62 1.1 perry 63 1.5 drochner #endif /* DIRECT_SERIAL */ 64 1.5 drochner 65 1.21 junyoung static int getcomaddr(int); 66 1.5 drochner #endif /* SUPPORT_SERIAL */ 67 1.5 drochner 68 1.5 drochner #define POLL_FREQ 10 69 1.1 perry 70 1.27 jmcneill static void 71 1.27 jmcneill wait(int us) 72 1.27 jmcneill { 73 1.27 jmcneill int prev = biosgetsystime(); 74 1.27 jmcneill int tgt = prev + (20 * us) / 1000000; 75 1.27 jmcneill int new; 76 1.27 jmcneill 77 1.27 jmcneill while ((new = biosgetsystime()) < tgt) { 78 1.27 jmcneill if (new < prev) /* XXX timer wrapped */ 79 1.27 jmcneill break; 80 1.27 jmcneill prev = new; 81 1.27 jmcneill } 82 1.27 jmcneill } 83 1.27 jmcneill 84 1.1 perry #ifdef SUPPORT_SERIAL 85 1.5 drochner static int 86 1.21 junyoung getcomaddr(int idx) 87 1.5 drochner { 88 1.5 drochner short addr; 89 1.18 dsl #ifdef CONSADDR 90 1.18 dsl if (CONSADDR != 0) 91 1.18 dsl return CONSADDR; 92 1.18 dsl #endif 93 1.5 drochner /* read in BIOS data area */ 94 1.8 sommerfe pvbcopy((void *)(0x400 + 2 * idx), &addr, 2); 95 1.21 junyoung return addr; 96 1.5 drochner } 97 1.1 perry #endif 98 1.1 perry 99 1.5 drochner void 100 1.24 christos clear_pc_screen(void) 101 1.24 christos { 102 1.24 christos #ifdef SUPPORT_SERIAL 103 1.24 christos /* Clear the screen if we are on a glass tty. */ 104 1.24 christos if (iodev == CONSDEV_PC) 105 1.24 christos conclr(); 106 1.24 christos #endif 107 1.24 christos } 108 1.24 christos 109 1.24 christos void 110 1.21 junyoung initio(int dev) 111 1.1 perry { 112 1.1 perry #ifdef SUPPORT_SERIAL 113 1.5 drochner int i; 114 1.5 drochner 115 1.14 dsl #if defined(DIRECT_SERIAL) && defined(CONSPEED) 116 1.14 dsl btinfo_console.speed = CONSPEED; 117 1.14 dsl #else 118 1.14 dsl btinfo_console.speed = 9600; 119 1.14 dsl #endif 120 1.14 dsl 121 1.3 thorpej switch (dev) { 122 1.21 junyoung case CONSDEV_AUTO: 123 1.25 christos for (i = 0; i < 3; i++) { 124 1.5 drochner iodev = CONSDEV_COM0 + i; 125 1.5 drochner btinfo_console.addr = getcomaddr(i); 126 1.25 christos if (!btinfo_console.addr) 127 1.12 dsl break; 128 1.5 drochner conputc('0' + i); /* to tell user what happens */ 129 1.14 dsl cominit_x(); 130 1.5 drochner #ifdef DIRECT_SERIAL 131 1.5 drochner /* check for: 132 1.5 drochner * 1. successful output 133 1.12 dsl * 2. optionally, keypress within 7s 134 1.5 drochner */ 135 1.14 dsl if ( computc_x(':') && 136 1.14 dsl computc_x('-') && 137 1.14 dsl computc_x('(') 138 1.5 drochner #ifdef COMCONS_KEYPRESS 139 1.7 rvb && awaitkey(7, 0) 140 1.5 drochner #endif 141 1.5 drochner ) 142 1.5 drochner goto ok; 143 1.11 thorpej #else /* ! DIRECT_SERIAL */ 144 1.5 drochner /* 145 1.5 drochner * serial console must have hardware handshake! 146 1.5 drochner * check: 147 1.5 drochner * 1. character output without error 148 1.5 drochner * 2. status bits for modem ready set 149 1.5 drochner * (status seems only useful after character output) 150 1.12 dsl * 3. optionally, keypress within 7s 151 1.5 drochner */ 152 1.14 dsl if (!(computc_x('@') & 0x80) 153 1.14 dsl && (comstatus_x() & 0x00b0) 154 1.5 drochner #ifdef COMCONS_KEYPRESS 155 1.7 rvb && awaitkey(7, 0) 156 1.5 drochner #endif 157 1.5 drochner ) 158 1.5 drochner goto ok; 159 1.11 thorpej #endif /* DIRECT_SERIAL */ 160 1.3 thorpej } 161 1.5 drochner iodev = CONSDEV_PC; 162 1.5 drochner ok: 163 1.3 thorpej break; 164 1.21 junyoung case CONSDEV_COM0: 165 1.21 junyoung case CONSDEV_COM1: 166 1.21 junyoung case CONSDEV_COM2: 167 1.21 junyoung case CONSDEV_COM3: 168 1.5 drochner iodev = dev; 169 1.5 drochner btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0); 170 1.25 christos if (!btinfo_console.addr) 171 1.12 dsl goto nocom; 172 1.14 dsl cominit_x(); 173 1.3 thorpej break; 174 1.21 junyoung case CONSDEV_COM0KBD: 175 1.21 junyoung case CONSDEV_COM1KBD: 176 1.21 junyoung case CONSDEV_COM2KBD: 177 1.21 junyoung case CONSDEV_COM3KBD: 178 1.18 dsl iodev = dev - CONSDEV_COM0KBD + CONSDEV_COM0; 179 1.7 rvb i = iodev - CONSDEV_COM0; 180 1.7 rvb btinfo_console.addr = getcomaddr(i); 181 1.25 christos if (!btinfo_console.addr) 182 1.12 dsl goto nocom; 183 1.7 rvb conputc('0' + i); /* to tell user what happens */ 184 1.14 dsl cominit_x(); 185 1.7 rvb #ifdef DIRECT_SERIAL 186 1.7 rvb /* check for: 187 1.7 rvb * 1. successful output 188 1.12 dsl * 2. optionally, keypress within 7s 189 1.7 rvb */ 190 1.14 dsl if ( computc_x(':') && 191 1.14 dsl computc_x('-') && 192 1.14 dsl computc_x('(') 193 1.7 rvb #ifdef COMCONS_KEYPRESS 194 1.7 rvb && awaitkey(7, 0) 195 1.7 rvb #endif 196 1.7 rvb ) 197 1.7 rvb break; 198 1.11 thorpej #else /* ! DIRECT_SERIAL */ 199 1.7 rvb /* 200 1.7 rvb * serial console must have hardware handshake! 201 1.7 rvb * check: 202 1.7 rvb * 1. character output without error 203 1.7 rvb * 2. status bits for modem ready set 204 1.7 rvb * (status seems only useful after character output) 205 1.12 dsl * 3. optionally, keypress within 7s 206 1.7 rvb */ 207 1.14 dsl if (!(computc_x('@') & 0x80) 208 1.14 dsl && (comstatus_x() & 0x00b0) 209 1.7 rvb #ifdef COMCONS_KEYPRESS 210 1.7 rvb && awaitkey(7, 0) 211 1.7 rvb #endif 212 1.7 rvb ) 213 1.7 rvb break; 214 1.11 thorpej #endif /* DIRECT_SERIAL */ 215 1.21 junyoung default: 216 1.5 drochner nocom: 217 1.5 drochner iodev = CONSDEV_PC; 218 1.3 thorpej break; 219 1.3 thorpej } 220 1.7 rvb conputc('\015'); 221 1.7 rvb conputc('\n'); 222 1.5 drochner strncpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16); 223 1.23 ad 224 1.5 drochner #else /* !SUPPORT_SERIAL */ 225 1.13 dsl btinfo_console.devname[0] = 'p'; 226 1.13 dsl btinfo_console.devname[1] = 'c'; 227 1.13 dsl btinfo_console.devname[2] = 0; 228 1.5 drochner #endif /* SUPPORT_SERIAL */ 229 1.1 perry } 230 1.1 perry 231 1.21 junyoung static inline void internal_putchar(int); 232 1.9 drochner 233 1.3 thorpej static inline void 234 1.21 junyoung internal_putchar(int c) 235 1.1 perry { 236 1.1 perry #ifdef SUPPORT_SERIAL 237 1.3 thorpej switch (iodev) { 238 1.21 junyoung case CONSDEV_PC: 239 1.1 perry #endif 240 1.3 thorpej conputc(c); 241 1.1 perry #ifdef SUPPORT_SERIAL 242 1.3 thorpej break; 243 1.21 junyoung case CONSDEV_COM0: 244 1.21 junyoung case CONSDEV_COM1: 245 1.21 junyoung case CONSDEV_COM2: 246 1.21 junyoung case CONSDEV_COM3: 247 1.14 dsl computc_x(c); 248 1.3 thorpej break; 249 1.3 thorpej } 250 1.1 perry #endif 251 1.1 perry } 252 1.1 perry 253 1.3 thorpej void 254 1.21 junyoung putchar(int c) 255 1.1 perry { 256 1.3 thorpej if (c == '\n') 257 1.3 thorpej internal_putchar('\r'); 258 1.3 thorpej internal_putchar(c); 259 1.1 perry } 260 1.1 perry 261 1.3 thorpej int 262 1.21 junyoung getchar(void) 263 1.3 thorpej { 264 1.16 dsl int c; 265 1.1 perry #ifdef SUPPORT_SERIAL 266 1.3 thorpej switch (iodev) { 267 1.21 junyoung default: /* to make gcc -Wall happy... */ 268 1.21 junyoung case CONSDEV_PC: 269 1.1 perry #endif 270 1.29 jmcneill while (!coniskey()) 271 1.29 jmcneill ; 272 1.16 dsl c = congetc(); 273 1.16 dsl #ifdef CONSOLE_KEYMAP 274 1.16 dsl { 275 1.16 dsl char *cp = strchr(CONSOLE_KEYMAP, c); 276 1.16 dsl if (cp != 0 && cp[1] != 0) 277 1.16 dsl c = cp[1]; 278 1.16 dsl } 279 1.16 dsl #endif 280 1.16 dsl return c; 281 1.1 perry #ifdef SUPPORT_SERIAL 282 1.21 junyoung case CONSDEV_COM0: 283 1.21 junyoung case CONSDEV_COM1: 284 1.21 junyoung case CONSDEV_COM2: 285 1.21 junyoung case CONSDEV_COM3: 286 1.6 drochner #ifdef DIRECT_SERIAL 287 1.14 dsl c = comgetc_x(); 288 1.6 drochner #else 289 1.6 drochner do { 290 1.14 dsl c = comgetc_x(); 291 1.6 drochner } while ((c >> 8) == 0xe0); /* catch timeout */ 292 1.6 drochner #ifdef COMDEBUG 293 1.6 drochner if (c & 0x8000) { 294 1.6 drochner printf("com input %x, status %x\n", 295 1.14 dsl c, comstatus_x()); 296 1.6 drochner } 297 1.6 drochner #endif 298 1.6 drochner c &= 0xff; 299 1.6 drochner #endif /* DIRECT_SERIAL */ 300 1.21 junyoung return c; 301 1.3 thorpej } 302 1.6 drochner #endif /* SUPPORT_SERIAL */ 303 1.1 perry } 304 1.1 perry 305 1.3 thorpej int 306 1.19 mycroft iskey(int intr) 307 1.3 thorpej { 308 1.1 perry #ifdef SUPPORT_SERIAL 309 1.3 thorpej switch (iodev) { 310 1.21 junyoung default: /* to make gcc -Wall happy... */ 311 1.21 junyoung case CONSDEV_PC: 312 1.1 perry #endif 313 1.21 junyoung return (intr && conisshift()) || coniskey(); 314 1.1 perry #ifdef SUPPORT_SERIAL 315 1.21 junyoung case CONSDEV_COM0: 316 1.21 junyoung case CONSDEV_COM1: 317 1.21 junyoung case CONSDEV_COM2: 318 1.21 junyoung case CONSDEV_COM3: 319 1.5 drochner #ifdef DIRECT_SERIAL 320 1.21 junyoung return !!comstatus_x(); 321 1.5 drochner #else 322 1.21 junyoung return !!(comstatus_x() & 0x0100); 323 1.5 drochner #endif 324 1.3 thorpej } 325 1.5 drochner #endif /* SUPPORT_SERIAL */ 326 1.5 drochner } 327 1.5 drochner 328 1.5 drochner char 329 1.21 junyoung awaitkey(int timeout, int tell) 330 1.5 drochner { 331 1.5 drochner int i; 332 1.5 drochner char c = 0; 333 1.5 drochner 334 1.5 drochner i = timeout * POLL_FREQ; 335 1.5 drochner 336 1.19 mycroft for (;;) { 337 1.10 drochner if (tell && (i % POLL_FREQ) == 0) { 338 1.26 mbalmer char numbuf[32]; 339 1.26 mbalmer int len; 340 1.10 drochner 341 1.26 mbalmer len = snprintf(numbuf, sizeof(numbuf), "%d seconds. ", 342 1.26 mbalmer i/POLL_FREQ); 343 1.26 mbalmer if (len > 0 && len < sizeof(numbuf)) { 344 1.26 mbalmer char *p = numbuf; 345 1.26 mbalmer 346 1.26 mbalmer printf("%s", numbuf); 347 1.26 mbalmer while (*p) 348 1.26 mbalmer *p++ = '\b'; 349 1.26 mbalmer printf("%s", numbuf); 350 1.26 mbalmer } 351 1.10 drochner } 352 1.19 mycroft if (iskey(1)) { 353 1.5 drochner /* flush input buffer */ 354 1.19 mycroft while (iskey(0)) 355 1.5 drochner c = getchar(); 356 1.12 dsl if (c == 0) 357 1.12 dsl c = -1; 358 1.12 dsl goto out; 359 1.5 drochner } 360 1.19 mycroft if (i--) 361 1.27 jmcneill wait(1000000 / POLL_FREQ); 362 1.19 mycroft else 363 1.19 mycroft break; 364 1.5 drochner } 365 1.5 drochner 366 1.5 drochner out: 367 1.5 drochner if (tell) 368 1.26 mbalmer printf("0 seconds. \n"); 369 1.5 drochner 370 1.21 junyoung return c; 371 1.1 perry } 372 1.28 tsutsui 373 1.28 tsutsui void 374 1.28 tsutsui wait_sec(int sec) 375 1.28 tsutsui { 376 1.28 tsutsui 377 1.28 tsutsui wait(sec * 1000000); 378 1.28 tsutsui } 379