1 /* 2 * Copyright (c) 1996, Sujal M. Patel 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/time.h> 31 32 #include <err.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <fcntl.h> 37 #include <string.h> 38 39 #include <machine/cpufunc.h> 40 41 #include <isa/pnpreg.h> 42 43 #ifdef DEBUG 44 #define DEB(x) x 45 #else 46 #define DEB(x) 47 #endif 48 #define DDB(x) x 49 50 void 51 pnp_write(int d, u_char r) 52 { 53 outb (_PNP_ADDRESS, d); 54 outb (_PNP_WRITE_DATA, r); 55 } 56 57 /* The READ_DATA port that we are using currently */ 58 static int rd_port; 59 60 u_char 61 pnp_read(int d) 62 { 63 outb(_PNP_ADDRESS, d); 64 return inb( (rd_port << 2) + 3) & 0xff; 65 } 66 67 u_short 68 pnp_readw(int d) 69 { 70 int c = pnp_read(d) << 8 ; 71 c |= pnp_read(d+1); 72 return c; 73 } 74 75 int logdevs=0; 76 77 void DELAY __P((int i)); 78 void send_Initiation_LFSR(); 79 int get_serial __P((u_char *data)); 80 int get_resource_info __P((u_char *buffer, int len)); 81 int handle_small_res __P((u_char *resinfo, int item, int len)); 82 void handle_large_res __P((u_char *resinfo, int item, int len)); 83 void dump_resdata __P((u_char *data, int csn)); 84 int isolation_protocol(); 85 86 87 /* 88 * DELAY does accurate delaying in user-space. 89 * This function busy-waits. 90 */ 91 void 92 DELAY (int i) 93 { 94 struct timeval t; 95 long start, stop; 96 97 i *= 4; 98 99 gettimeofday (&t, NULL); 100 start = t.tv_sec * 1000000 + t.tv_usec; 101 do { 102 gettimeofday (&t, NULL); 103 stop = t.tv_sec * 1000000 + t.tv_usec; 104 } while (start + i > stop); 105 } 106 107 108 /* 109 * Send Initiation LFSR as described in "Plug and Play ISA Specification, 110 * Intel May 94." 111 */ 112 void 113 send_Initiation_LFSR(void) 114 { 115 int cur, i; 116 117 pnp_write(PNP_CONFIG_CONTROL, 0x2); 118 119 /* Reset the LSFR */ 120 outb(_PNP_ADDRESS, 0); 121 outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */ 122 123 cur = 0x6a; 124 125 for (i = 0; i < 32; i++) { 126 outb(_PNP_ADDRESS, cur); 127 cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff); 128 } 129 } 130 131 /* 132 * Get the device's serial number. Returns 1 if the serial is valid. 133 */ 134 int 135 get_serial(u_char *data) 136 { 137 int i, bit, valid = 0, sum = 0x6a; 138 139 bzero(data, sizeof(char) * 9); 140 141 for (i = 0; i < 72; i++) { 142 bit = inb((rd_port << 2) | 0x3) == 0x55; 143 DELAY(250); /* Delay 250 usec */ 144 145 /* Can't Short Circuit the next evaluation, so 'and' is last */ 146 bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit; 147 DELAY(250); /* Delay 250 usec */ 148 149 valid = valid || bit; 150 151 if (i < 64) 152 sum = (sum >> 1) | 153 (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff); 154 155 data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0); 156 } 157 158 valid = valid && (data[8] == sum); 159 160 return valid; 161 } 162 163 164 /* 165 * Fill's the buffer with resource info from the device. 166 * Returns 0 if the device fails to report 167 */ 168 int 169 get_resource_info(u_char *buffer, int len) 170 { 171 int i, j; 172 173 for (i = 0; i < len; i++) { 174 outb(_PNP_ADDRESS, PNP_STATUS); 175 for (j = 0; j < 100; j++) { 176 if ((inb((rd_port << 2) | 0x3)) & 0x1) 177 break; 178 DELAY(1); 179 } 180 if (j == 100) { 181 printf("PnP device failed to report resource data\n"); 182 return 0; 183 } 184 outb(_PNP_ADDRESS, PNP_RESOURCE_DATA); 185 buffer[i] = inb((rd_port << 2) | 0x3); 186 DEB(printf("--- get_resource_info: got 0x%02x\n",(unsigned)buffer[i])); 187 } 188 return 1; 189 } 190 191 void 192 report_dma_info(int x) 193 { 194 char *s1=NULL, *s2=NULL, *s3=NULL, *s4=NULL, *s5=NULL; 195 196 switch (x & 0x3) { 197 case 0: 198 s1="8-bit"; 199 break; 200 case 1: 201 s1="8/16-bit"; 202 break; 203 case 2: 204 s1="16-bit"; 205 break; 206 #ifdef DIAGNOSTIC 207 case 3: 208 s1="Reserved"; 209 break; 210 #endif 211 } 212 213 s2 = (x & 0x4) ? "bus master" : "not a bus master"; 214 215 s3 = (x & 0x8) ? "count by byte" : ""; 216 217 s4 = (x & 0x10) ? "count by word" : ""; 218 219 switch ((x & 0x60) >> 5) { 220 case 0: 221 s5="Compatibility mode"; 222 break; 223 case 1: 224 s5="Type A"; 225 break; 226 case 2: 227 s5="Type B"; 228 break; 229 case 3: 230 s5="Type F"; 231 break; 232 } 233 printf("\t%s, %s, %s, %s, %s\n",s1,s2,s3,s4,s5); 234 } 235 236 237 void 238 report_memory_info (int x) 239 { 240 if (x & 0x1) 241 printf ("Memory Range: Writeable\n"); 242 else 243 printf ("Memory Range: Not writeable (ROM)\n"); 244 245 if (x & 0x2) 246 printf ("Memory Range: Read-cacheable, write-through\n"); 247 else 248 printf ("Memory Range: Non-cacheable\n"); 249 250 if (x & 0x4) 251 printf ("Memory Range: Decode supports high address\n"); 252 else 253 printf ("Memory Range: Decode supports range length\n"); 254 255 switch ((x & 0x18) >> 3) { 256 case 0: 257 printf ("Memory Range: 8-bit memory only\n"); 258 break; 259 case 1: 260 printf ("Memory Range: 16-bit memory only\n"); 261 break; 262 case 2: 263 printf ("Memory Range: 8-bit and 16-bit memory supported\n"); 264 break; 265 #ifdef DIAGNOSTIC 266 case 3: 267 printf ("Memory Range: Reserved\n"); 268 break; 269 #endif 270 } 271 272 if (x & 0x20) 273 printf ("Memory Range: Memory is shadowable\n"); 274 else 275 printf ("Memory Range: Memory is not shadowable\n"); 276 277 if (x & 0x40) 278 printf ("Memory Range: Memory is an expansion ROM\n"); 279 else 280 printf ("Memory Range: Memory is not an expansion ROM\n"); 281 282 #ifdef DIAGNOSTIC 283 if (x & 0x80) 284 printf ("Memory Range: Reserved (Device is brain-damaged)\n"); 285 #endif 286 } 287 288 289 /* 290 * Small Resource Tag Handler 291 * 292 * Returns 1 if checksum was valid (and an END_TAG was received). 293 * Returns -1 if checksum was invalid (and an END_TAG was received). 294 * Returns 0 for other tags. 295 */ 296 int 297 handle_small_res(u_char *resinfo, int item, int len) 298 { 299 int i; 300 301 DEB(printf("*** ITEM 0x%04x len %d detected\n", item, len)); 302 303 switch (item) { 304 default: 305 printf("*** ITEM 0x%02x detected\n", item); 306 break; 307 case PNP_TAG_VERSION: 308 printf("PnP Version %d.%d, Vendor Version %d\n", 309 resinfo[0] >> 4, resinfo[0] & (0xf), resinfo[1]); 310 break; 311 case PNP_TAG_LOGICAL_DEVICE: 312 printf("\nLogical Device ID: %c%c%c%02x%02x 0x%08x #%d\n", 313 ((resinfo[0] & 0x7c) >> 2) + 64, 314 (((resinfo[0] & 0x03) << 3) | 315 ((resinfo[1] & 0xe0) >> 5)) + 64, 316 (resinfo[1] & 0x1f) + 64, 317 resinfo[2], resinfo[3], *(int *)(resinfo), 318 logdevs++); 319 320 if (resinfo[4] & 0x1) 321 printf ("\tDevice powers up active\n"); /* XXX */ 322 if (resinfo[4] & 0x2) 323 printf ("\tDevice supports I/O Range Check\n"); 324 if (resinfo[4] > 0x3) 325 printf ("\tReserved register funcs %02x\n", 326 resinfo[4]); 327 328 if (len == 6) 329 printf("\tVendor register funcs %02x\n", resinfo[5]); 330 break; 331 case PNP_TAG_COMPAT_DEVICE: 332 printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n", 333 ((resinfo[0] & 0x7c) >> 2) + 64, 334 (((resinfo[0] & 0x03) << 3) | 335 ((resinfo[1] & 0xe0) >> 5)) + 64, 336 (resinfo[1] & 0x1f) + 64, 337 resinfo[2], resinfo[3], *(int *)resinfo); 338 break; 339 case PNP_TAG_IRQ_FORMAT: 340 printf(" IRQ: "); 341 342 for (i = 0; i < 8; i++) 343 if (resinfo[0] & (1<<i)) 344 printf("%d ", i); 345 for (i = 0; i < 8; i++) 346 if (resinfo[1] & (1<<i)) 347 printf("%d ", i + 8); 348 if (len == 3) { 349 if (resinfo[2] & 0x1) 350 printf("IRQ: High true edge sensitive\n"); 351 if (resinfo[2] & 0x2) 352 printf("IRQ: Low true edge sensitive\n"); 353 if (resinfo[2] & 0x4) 354 printf("IRQ: High true level sensitive\n"); 355 if (resinfo[2] & 0x8) 356 printf("IRQ: Low true level sensitive\n"); 357 } else { 358 printf(" - only one type (true/edge)\n"); 359 } 360 break; 361 case PNP_TAG_DMA_FORMAT: 362 printf(" DMA: channel(s) "); 363 for (i = 0; i < 8; i++) 364 if (resinfo[0] & (1<<i)) 365 printf("%d ", i); 366 printf ("\n"); 367 report_dma_info (resinfo[1]); 368 break; 369 case PNP_TAG_START_DEPENDANT: 370 printf("TAG Start DF\n"); 371 if (len == 1) { 372 switch (resinfo[0]) { 373 case 0: 374 printf("Good Configuration\n"); 375 break; 376 case 1: 377 printf("Acceptable Configuration\n"); 378 break; 379 case 2: 380 printf("Sub-optimal Configuration\n"); 381 break; 382 } 383 } 384 break; 385 case PNP_TAG_END_DEPENDANT: 386 printf("TAG End DF\n"); 387 break; 388 case PNP_TAG_IO_RANGE: 389 printf(" I/O Range 0x%x .. 0x%x, alignment 0x%x, len 0x%x\n", 390 resinfo[1] + (resinfo[2] << 8), 391 resinfo[3] + (resinfo[4] << 8), 392 resinfo[5], resinfo[6] ); 393 if (resinfo[0]) 394 printf("\t[16-bit addr]\n"); 395 else 396 printf("\t[not 16-bit addr]\n"); 397 break; 398 case PNP_TAG_IO_FIXED: 399 printf (" FIXED I/O base address 0x%x length 0x%x\n", 400 resinfo[0] + ( (resinfo[1] & 3 ) << 8), /* XXX */ 401 resinfo[2]); 402 break; 403 #ifdef DIAGNOSTIC 404 case PNP_TAG_RESERVED: 405 printf("Reserved Tag Detected\n"); 406 break; 407 #endif 408 case PNP_TAG_VENDOR: 409 printf("*** Small Vendor Tag Detected\n"); 410 break; 411 case PNP_TAG_END: 412 printf("End Tag\n\n"); 413 /* XXX Record and Verify Checksum */ 414 return 1; 415 break; 416 } 417 return 0; 418 } 419 420 421 void 422 handle_large_res(u_char *resinfo, int item, int len) 423 { 424 int i; 425 426 DEB(printf("*** Large ITEM %d len %d found\n", item, len)); 427 switch (item) { 428 case PNP_TAG_MEMORY_RANGE: 429 report_memory_info(resinfo[0]); 430 printf("Memory range minimum address: 0x%x\n", 431 (resinfo[1] << 8) + (resinfo[2] << 16)); 432 printf("Memory range maximum address: 0x%x\n", 433 (resinfo[3] << 8) + (resinfo[4] << 16)); 434 printf("Memory range base alignment: 0x%x\n", 435 (i = (resinfo[5] + (resinfo[6] << 8))) ? i : (1 << 16)); 436 printf("Memory range length: 0x%x\n", 437 (resinfo[7] + (resinfo[8] << 8)) * 256); 438 break; 439 case PNP_TAG_ID_ANSI: 440 printf("Device Description: "); 441 442 for (i = 0; i < len; i++) { 443 if (resinfo[i]) /* XXX */ 444 printf("%c", resinfo[i]); 445 } 446 printf("\n"); 447 break; 448 case PNP_TAG_ID_UNICODE: 449 printf("ID String Unicode Detected (Undefined)\n"); 450 break; 451 case PNP_TAG_LARGE_VENDOR: 452 printf("Large Vendor Defined Detected\n"); 453 break; 454 case PNP_TAG_MEMORY32_RANGE: 455 printf("32bit Memory Range Desc Unimplemented\n"); 456 break; 457 case PNP_TAG_MEMORY32_FIXED: 458 printf("32bit Fixed Location Desc Unimplemented\n"); 459 break; 460 #ifdef DIAGNOSTIC 461 case PNP_TAG_LARGE_RESERVED: 462 printf("Large Reserved Tag Detected\n"); 463 break; 464 #endif 465 } 466 } 467 468 469 /* 470 * Dump all the information about configurations. 471 */ 472 void 473 dump_resdata(u_char *data, int csn) 474 { 475 int i, large_len; 476 477 u_char tag, *resinfo; 478 479 DDB(printf("\nCard assigned CSN #%d\n", csn)); 480 printf("Vendor ID %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n", 481 ((data[0] & 0x7c) >> 2) + 64, 482 (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64, 483 (data[1] & 0x1f) + 64, data[2], data[3], 484 *(int *)&(data[0]), 485 *(int *)&(data[4])); 486 487 pnp_write(PNP_SET_CSN, csn); /* Move this out of this function XXX */ 488 outb(_PNP_ADDRESS, PNP_STATUS); 489 490 /* Allows up to 1kb of Resource Info, Should be plenty */ 491 for (i = 0; i < 1024; i++) { 492 if (!get_resource_info(&tag, 1)) 493 break; 494 495 if (PNP_RES_TYPE(tag) == 0) { 496 /* Handle small resouce data types */ 497 498 resinfo = malloc(PNP_SRES_LEN(tag)); 499 if (!get_resource_info(resinfo, PNP_SRES_LEN(tag))) 500 break; 501 502 if (handle_small_res(resinfo, PNP_SRES_NUM(tag), PNP_SRES_LEN(tag)) == 1) 503 break; 504 free(resinfo); 505 } else { 506 /* Handle large resouce data types */ 507 u_char buf[2]; 508 if (!get_resource_info((char *)buf, 2)) 509 break; 510 large_len = (buf[1] << 8) + buf[0]; 511 512 resinfo = malloc(large_len); 513 if (!get_resource_info(resinfo, large_len)) 514 break; 515 516 handle_large_res(resinfo, PNP_LRES_NUM(tag), large_len); 517 free(resinfo); 518 } 519 } 520 printf("Successfully got %d resources, %d logical fdevs\n", i, 521 logdevs); 522 printf("-- card select # 0x%04x\n", pnp_read(PNP_SET_CSN)); 523 printf("\nCSN %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n", 524 ((data[0] & 0x7c) >> 2) + 64, 525 (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64, 526 (data[1] & 0x1f) + 64, data[2], data[3], 527 *(int *)&(data[0]), 528 *(int *)&(data[4])); 529 530 for (i=0; i<logdevs; i++) { 531 int j; 532 533 pnp_write(PNP_SET_LDN, i); 534 535 printf("\nLogical device #%d\n", pnp_read(PNP_SET_LDN) ); 536 printf("IO: "); 537 for (j=0; j<8; j++) 538 printf(" 0x%02x%02x", pnp_read(PNP_IO_BASE_HIGH(j)), 539 pnp_read(PNP_IO_BASE_LOW(j))); 540 printf("\nIRQ %d %d\n", 541 pnp_read(PNP_IRQ_LEVEL(0)), pnp_read(PNP_IRQ_LEVEL(1)) ); 542 printf("DMA %d %d\n", 543 pnp_read(PNP_DMA_CHANNEL(0)), pnp_read(PNP_DMA_CHANNEL(1)) ); 544 printf("IO range check 0x%02x activate 0x%02x\n", 545 pnp_read(PNP_IO_RANGE_CHECK), pnp_read(PNP_ACTIVATE) ); 546 } 547 } 548 549 550 /* 551 * Run the isolation protocol. Use rd_port as the READ_DATA port 552 * value (caller should try multiple READ_DATA locations before giving 553 * up). Upon exiting, all cards are aware that they should use rd_port 554 * as the READ_DATA port; 555 * 556 */ 557 int 558 isolation_protocol(void) 559 { 560 int csn; 561 u_char data[9]; 562 563 send_Initiation_LFSR(); 564 565 /* Reset CSN for All Cards */ 566 pnp_write(PNP_CONFIG_CONTROL, 0x04); 567 568 for (csn = 1; (csn < PNP_MAX_CARDS); csn++) { 569 /* Wake up cards without a CSN */ 570 logdevs = 0 ; 571 pnp_write(PNP_WAKE, 0); 572 pnp_write(PNP_SET_RD_DATA, rd_port); 573 outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION); 574 DELAY(1000); /* Delay 1 msec */ 575 576 if (get_serial(data)) 577 dump_resdata(data, csn); 578 else 579 break; 580 } 581 return csn - 1; 582 } 583 584 585 int 586 main(int argc, char **argv) 587 { 588 int num_pnp_devs; 589 590 #ifdef __i386__ 591 /* Hey what about a i386_iopl() call :) */ 592 if (open("/dev/io", O_RDONLY) < 0) 593 errx(1, "can't get I/O privilege"); 594 #endif 595 596 printf("Checking for Plug-n-Play devices...\n"); 597 598 /* Try various READ_DATA ports from 0x203-0x3ff */ 599 for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) { 600 DEB(printf("Trying Read_Port at %x...\n", (rd_port << 2) | 0x3) ); 601 num_pnp_devs = isolation_protocol(); 602 if (num_pnp_devs) 603 break; 604 } 605 if (!num_pnp_devs) { 606 printf("No Plug-n-Play devices were found\n"); 607 return (0); 608 } 609 return (0); 610 } 611