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