1 /* $NetBSD: pcio.c,v 1.23 2008/05/21 13:36:45 ad 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 initio(int dev) 91 { 92 #ifdef SUPPORT_SERIAL 93 int i; 94 95 #if defined(DIRECT_SERIAL) && defined(CONSPEED) 96 btinfo_console.speed = CONSPEED; 97 #else 98 btinfo_console.speed = 9600; 99 #endif 100 101 switch (dev) { 102 case CONSDEV_AUTO: 103 for(i = 0; i < 3; i++) { 104 iodev = CONSDEV_COM0 + i; 105 btinfo_console.addr = getcomaddr(i); 106 if(!btinfo_console.addr) 107 break; 108 conputc('0' + i); /* to tell user what happens */ 109 cominit_x(); 110 #ifdef DIRECT_SERIAL 111 /* check for: 112 * 1. successful output 113 * 2. optionally, keypress within 7s 114 */ 115 if ( computc_x(':') && 116 computc_x('-') && 117 computc_x('(') 118 #ifdef COMCONS_KEYPRESS 119 && awaitkey(7, 0) 120 #endif 121 ) 122 goto ok; 123 #else /* ! DIRECT_SERIAL */ 124 /* 125 * serial console must have hardware handshake! 126 * check: 127 * 1. character output without error 128 * 2. status bits for modem ready set 129 * (status seems only useful after character output) 130 * 3. optionally, keypress within 7s 131 */ 132 if (!(computc_x('@') & 0x80) 133 && (comstatus_x() & 0x00b0) 134 #ifdef COMCONS_KEYPRESS 135 && awaitkey(7, 0) 136 #endif 137 ) 138 goto ok; 139 #endif /* DIRECT_SERIAL */ 140 } 141 iodev = CONSDEV_PC; 142 ok: 143 break; 144 case CONSDEV_COM0: 145 case CONSDEV_COM1: 146 case CONSDEV_COM2: 147 case CONSDEV_COM3: 148 iodev = dev; 149 btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0); 150 if(!btinfo_console.addr) 151 goto nocom; 152 cominit_x(); 153 break; 154 case CONSDEV_COM0KBD: 155 case CONSDEV_COM1KBD: 156 case CONSDEV_COM2KBD: 157 case CONSDEV_COM3KBD: 158 iodev = dev - CONSDEV_COM0KBD + CONSDEV_COM0; 159 i = iodev - CONSDEV_COM0; 160 btinfo_console.addr = getcomaddr(i); 161 if(!btinfo_console.addr) 162 goto nocom; 163 conputc('0' + i); /* to tell user what happens */ 164 cominit_x(); 165 #ifdef DIRECT_SERIAL 166 /* check for: 167 * 1. successful output 168 * 2. optionally, keypress within 7s 169 */ 170 if ( computc_x(':') && 171 computc_x('-') && 172 computc_x('(') 173 #ifdef COMCONS_KEYPRESS 174 && awaitkey(7, 0) 175 #endif 176 ) 177 break; 178 #else /* ! DIRECT_SERIAL */ 179 /* 180 * serial console must have hardware handshake! 181 * check: 182 * 1. character output without error 183 * 2. status bits for modem ready set 184 * (status seems only useful after character output) 185 * 3. optionally, keypress within 7s 186 */ 187 if (!(computc_x('@') & 0x80) 188 && (comstatus_x() & 0x00b0) 189 #ifdef COMCONS_KEYPRESS 190 && awaitkey(7, 0) 191 #endif 192 ) 193 break; 194 #endif /* DIRECT_SERIAL */ 195 default: 196 nocom: 197 iodev = CONSDEV_PC; 198 break; 199 } 200 conputc('\015'); 201 conputc('\n'); 202 strncpy(btinfo_console.devname, iodev == CONSDEV_PC ? "pc" : "com", 16); 203 204 if (iodev == CONSDEV_PC) { 205 /* Clear screen if on a glass tty. */ 206 conclr(); 207 } 208 #else /* !SUPPORT_SERIAL */ 209 btinfo_console.devname[0] = 'p'; 210 btinfo_console.devname[1] = 'c'; 211 btinfo_console.devname[2] = 0; 212 #endif /* SUPPORT_SERIAL */ 213 } 214 215 static inline void internal_putchar(int); 216 217 static inline void 218 internal_putchar(int c) 219 { 220 #ifdef SUPPORT_SERIAL 221 switch (iodev) { 222 case CONSDEV_PC: 223 #endif 224 conputc(c); 225 #ifdef SUPPORT_SERIAL 226 break; 227 case CONSDEV_COM0: 228 case CONSDEV_COM1: 229 case CONSDEV_COM2: 230 case CONSDEV_COM3: 231 computc_x(c); 232 break; 233 } 234 #endif 235 } 236 237 void 238 putchar(int c) 239 { 240 if (c == '\n') 241 internal_putchar('\r'); 242 internal_putchar(c); 243 } 244 245 int 246 getchar(void) 247 { 248 int c; 249 #ifdef SUPPORT_SERIAL 250 switch (iodev) { 251 default: /* to make gcc -Wall happy... */ 252 case CONSDEV_PC: 253 #endif 254 c = congetc(); 255 #ifdef CONSOLE_KEYMAP 256 { 257 char *cp = strchr(CONSOLE_KEYMAP, c); 258 if (cp != 0 && cp[1] != 0) 259 c = cp[1]; 260 } 261 #endif 262 return c; 263 #ifdef SUPPORT_SERIAL 264 case CONSDEV_COM0: 265 case CONSDEV_COM1: 266 case CONSDEV_COM2: 267 case CONSDEV_COM3: 268 #ifdef DIRECT_SERIAL 269 c = comgetc_x(); 270 #else 271 do { 272 c = comgetc_x(); 273 } while ((c >> 8) == 0xe0); /* catch timeout */ 274 #ifdef COMDEBUG 275 if (c & 0x8000) { 276 printf("com input %x, status %x\n", 277 c, comstatus_x()); 278 } 279 #endif 280 c &= 0xff; 281 #endif /* DIRECT_SERIAL */ 282 return c; 283 } 284 #endif /* SUPPORT_SERIAL */ 285 } 286 287 int 288 iskey(int intr) 289 { 290 #ifdef SUPPORT_SERIAL 291 switch (iodev) { 292 default: /* to make gcc -Wall happy... */ 293 case CONSDEV_PC: 294 #endif 295 return (intr && conisshift()) || coniskey(); 296 #ifdef SUPPORT_SERIAL 297 case CONSDEV_COM0: 298 case CONSDEV_COM1: 299 case CONSDEV_COM2: 300 case CONSDEV_COM3: 301 #ifdef DIRECT_SERIAL 302 return !!comstatus_x(); 303 #else 304 return !!(comstatus_x() & 0x0100); 305 #endif 306 } 307 #endif /* SUPPORT_SERIAL */ 308 } 309 310 char 311 awaitkey(int timeout, int 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