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