1 /* $NetBSD: pcio.c,v 1.11 2002/02/19 20:18:36 thorpej 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project 18 * by Matthias Drochner. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35 /* 36 * console I/O 37 * needs lowlevel routines from conio.S and comio.S 38 */ 39 40 #include <lib/libsa/stand.h> 41 #include <lib/libkern/libkern.h> 42 43 #include "libi386.h" 44 #include "bootinfo.h" 45 46 extern void conputc __P((int)); 47 extern int congetc __P((void)); 48 extern int coniskey __P((void)); 49 50 struct btinfo_console btinfo_console; 51 52 #ifdef SUPPORT_SERIAL 53 static int iodev; 54 55 #ifdef DIRECT_SERIAL 56 #include "comio_direct.h" 57 58 #define cominit cominit_d 59 #define computc computc_d 60 #define comgetc comgetc_d 61 /* comstatus() is different */ 62 63 #define SERIAL_ARG btinfo_console.addr 64 #else 65 extern void cominit __P((int)); 66 extern int computc __P((int, int)); 67 extern int comgetc __P((int)); 68 extern int comstatus __P((int)); 69 70 #define SERIAL_ARG (iodev - CONSDEV_COM0) 71 #endif /* DIRECT_SERIAL */ 72 73 static int getcomaddr __P((int)); 74 #endif /* SUPPORT_SERIAL */ 75 76 #define POLL_FREQ 10 77 78 #ifdef SUPPORT_SERIAL 79 static int 80 getcomaddr(idx) 81 int idx; 82 { 83 short addr; 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 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) break; 103 conputc('0' + i); /* to tell user what happens */ 104 cominit(SERIAL_ARG); 105 #ifdef DIRECT_SERIAL 106 /* check for: 107 * 1. successful output 108 * 2. optionally, keypress within 1s 109 */ 110 if ( computc(':', SERIAL_ARG) && 111 computc('-', SERIAL_ARG) && 112 computc('(', SERIAL_ARG) 113 #ifdef COMCONS_KEYPRESS 114 && awaitkey(7, 0) 115 #endif 116 ) 117 goto ok; 118 #else /* ! DIRECT_SERIAL */ 119 /* 120 * serial console must have hardware handshake! 121 * check: 122 * 1. character output without error 123 * 2. status bits for modem ready set 124 * (status seems only useful after character output) 125 * 3. optionally, keypress within 1s 126 */ 127 if (!(computc('@', SERIAL_ARG) & 0x80) 128 && (comstatus(SERIAL_ARG) & 0x00b0) 129 #ifdef COMCONS_KEYPRESS 130 && awaitkey(7, 0) 131 #endif 132 ) 133 goto ok; 134 #endif /* DIRECT_SERIAL */ 135 } 136 iodev = CONSDEV_PC; 137 ok: 138 break; 139 case CONSDEV_COM0: 140 case CONSDEV_COM1: 141 case CONSDEV_COM2: 142 case CONSDEV_COM3: 143 iodev = dev; 144 btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0); 145 if(!btinfo_console.addr) goto nocom; 146 cominit(SERIAL_ARG); 147 break; 148 case CONSDEV_COM0KBD: 149 case CONSDEV_COM1KBD: 150 case CONSDEV_COM2KBD: 151 case CONSDEV_COM3KBD: 152 iodev = dev - 4; 153 i = iodev - CONSDEV_COM0; 154 btinfo_console.addr = getcomaddr(i); 155 if(!btinfo_console.addr) goto nocom; 156 conputc('0' + i); /* to tell user what happens */ 157 cominit(SERIAL_ARG); 158 #ifdef DIRECT_SERIAL 159 /* check for: 160 * 1. successful output 161 * 2. optionally, keypress within 1s 162 */ 163 if ( computc(':', SERIAL_ARG) && 164 computc('-', SERIAL_ARG) && 165 computc('(', SERIAL_ARG) 166 #ifdef COMCONS_KEYPRESS 167 && awaitkey(7, 0) 168 #endif 169 ) 170 break; 171 #else /* ! DIRECT_SERIAL */ 172 /* 173 * serial console must have hardware handshake! 174 * check: 175 * 1. character output without error 176 * 2. status bits for modem ready set 177 * (status seems only useful after character output) 178 * 3. optionally, keypress within 1s 179 */ 180 if (!(computc('@', SERIAL_ARG) & 0x80) 181 && (comstatus(SERIAL_ARG) & 0x00b0) 182 #ifdef COMCONS_KEYPRESS 183 && awaitkey(7, 0) 184 #endif 185 ) 186 break; 187 #endif /* DIRECT_SERIAL */ 188 default: 189 nocom: 190 iodev = CONSDEV_PC; 191 break; 192 } 193 conputc('\015'); 194 conputc('\n'); 195 strncpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16); 196 #if defined(DIRECT_SERIAL) && defined(CONSPEED) 197 btinfo_console.speed = CONSPEED; 198 #else 199 btinfo_console.speed = 9600; 200 #endif 201 #else /* !SUPPORT_SERIAL */ 202 strncpy(btinfo_console.devname, "pc", 16); 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(c, SERIAL_ARG); 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 #ifdef SUPPORT_SERIAL 242 int c; 243 switch (iodev) { 244 default: /* to make gcc -Wall happy... */ 245 case CONSDEV_PC: 246 #endif 247 return (congetc()); 248 #ifdef SUPPORT_SERIAL 249 case CONSDEV_COM0: 250 case CONSDEV_COM1: 251 case CONSDEV_COM2: 252 case CONSDEV_COM3: 253 #ifdef DIRECT_SERIAL 254 c = comgetc(SERIAL_ARG); 255 #else 256 do { 257 c = comgetc(SERIAL_ARG); 258 } while ((c >> 8) == 0xe0); /* catch timeout */ 259 #ifdef COMDEBUG 260 if (c & 0x8000) { 261 printf("com input %x, status %x\n", 262 c, comstatus(SERIAL_ARG)); 263 } 264 #endif 265 c &= 0xff; 266 #endif /* DIRECT_SERIAL */ 267 return (c); 268 } 269 #endif /* SUPPORT_SERIAL */ 270 } 271 272 int 273 iskey() 274 { 275 #ifdef SUPPORT_SERIAL 276 switch (iodev) { 277 default: /* to make gcc -Wall happy... */ 278 case CONSDEV_PC: 279 #endif 280 return (coniskey()); 281 #ifdef SUPPORT_SERIAL 282 case CONSDEV_COM0: 283 case CONSDEV_COM1: 284 case CONSDEV_COM2: 285 case CONSDEV_COM3: 286 #ifdef DIRECT_SERIAL 287 return(!!comstatus_d(SERIAL_ARG)); 288 #else 289 return (!!(comstatus(SERIAL_ARG) & 0x0100)); 290 #endif 291 } 292 #endif /* SUPPORT_SERIAL */ 293 } 294 295 char 296 awaitkey(timeout, tell) 297 int timeout, tell; 298 { 299 int i; 300 char c = 0; 301 302 i = timeout * POLL_FREQ; 303 304 while (i) { 305 if (tell && (i % POLL_FREQ) == 0) { 306 char numbuf[20]; 307 int len, j; 308 309 sprintf(numbuf, "%d ", i/POLL_FREQ); 310 len = strlen(numbuf); 311 for (j = 0; j < len; j++) 312 numbuf[len + j] = '\b'; 313 numbuf[len + j] = '\0'; 314 printf(numbuf); 315 } 316 if (iskey()) { 317 /* flush input buffer */ 318 while (iskey()) 319 c = getchar(); 320 goto out; /* XXX what happens if c == 0? */ 321 } 322 delay(1000000 / POLL_FREQ); 323 i--; 324 } 325 326 out: 327 if (tell) 328 printf("0\n"); 329 330 return(c); 331 } 332