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