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