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() 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 (x) 193 int x; 194 { 195 char *s1=NULL, *s2=NULL, *s3=NULL, *s4=NULL, *s5=NULL; 196 197 switch (x & 0x3) { 198 case 0: 199 s1="8-bit"; 200 break; 201 case 1: 202 s1="8/16-bit"; 203 break; 204 case 2: 205 s1="16-bit"; 206 break; 207 #ifdef DIAGNOSTIC 208 case 3: 209 s1="Reserved"; 210 break; 211 #endif 212 } 213 214 s2 = (x & 0x4) ? "bus master" : "not a bus master"; 215 216 s3 = (x & 0x8) ? "count by byte" : ""; 217 218 s4 = (x & 0x10) ? "count by word" : ""; 219 220 switch ((x & 0x60) >> 5) { 221 case 0: 222 s5="Compatibility mode"; 223 break; 224 case 1: 225 s5="Type A"; 226 break; 227 case 2: 228 s5="Type B"; 229 break; 230 case 3: 231 s5="Type F"; 232 break; 233 } 234 printf("\t%s, %s, %s, %s, %s\n",s1,s2,s3,s4,s5); 235 } 236 237 238 void 239 report_memory_info (int x) 240 { 241 if (x & 0x1) 242 printf ("Memory Range: Writeable\n"); 243 else 244 printf ("Memory Range: Not writeable (ROM)\n"); 245 246 if (x & 0x2) 247 printf ("Memory Range: Read-cacheable, write-through\n"); 248 else 249 printf ("Memory Range: Non-cacheable\n"); 250 251 if (x & 0x4) 252 printf ("Memory Range: Decode supports high address\n"); 253 else 254 printf ("Memory Range: Decode supports range length\n"); 255 256 switch ((x & 0x18) >> 3) { 257 case 0: 258 printf ("Memory Range: 8-bit memory only\n"); 259 break; 260 case 1: 261 printf ("Memory Range: 16-bit memory only\n"); 262 break; 263 case 2: 264 printf ("Memory Range: 8-bit and 16-bit memory supported\n"); 265 break; 266 #ifdef DIAGNOSTIC 267 case 3: 268 printf ("Memory Range: Reserved\n"); 269 break; 270 #endif 271 } 272 273 if (x & 0x20) 274 printf ("Memory Range: Memory is shadowable\n"); 275 else 276 printf ("Memory Range: Memory is not shadowable\n"); 277 278 if (x & 0x40) 279 printf ("Memory Range: Memory is an expansion ROM\n"); 280 else 281 printf ("Memory Range: Memory is not an expansion ROM\n"); 282 283 #ifdef DIAGNOSTIC 284 if (x & 0x80) 285 printf ("Memory Range: Reserved (Device is brain-damaged)\n"); 286 #endif 287 } 288 289 290 /* 291 * Small Resource Tag Handler 292 * 293 * Returns 1 if checksum was valid (and an END_TAG was received). 294 * Returns -1 if checksum was invalid (and an END_TAG was received). 295 * Returns 0 for other tags. 296 */ 297 int 298 handle_small_res(u_char *resinfo, int item, int len) 299 { 300 int i; 301 302 DEB(printf("*** ITEM 0x%04x len %d detected\n", item, len)); 303 304 switch (item) { 305 default: 306 printf("*** ITEM 0x%02x detected\n", item); 307 break; 308 case PNP_TAG_VERSION: 309 printf("PnP Version %d.%d, Vendor Version %d\n", 310 resinfo[0] >> 4, resinfo[0] & (0xf), resinfo[1]); 311 break; 312 case PNP_TAG_LOGICAL_DEVICE: 313 printf("\nLogical Device ID: %c%c%c%02x%02x 0x%08x #%d\n", 314 ((resinfo[0] & 0x7c) >> 2) + 64, 315 (((resinfo[0] & 0x03) << 3) | 316 ((resinfo[1] & 0xe0) >> 5)) + 64, 317 (resinfo[1] & 0x1f) + 64, 318 resinfo[2], resinfo[3], *(int *)(resinfo), 319 logdevs++); 320 321 if (resinfo[4] & 0x1) 322 printf ("\tDevice powers up active\n"); /* XXX */ 323 if (resinfo[4] & 0x2) 324 printf ("\tDevice supports I/O Range Check\n"); 325 if (resinfo[4] > 0x3) 326 printf ("\tReserved register funcs %02x\n", 327 resinfo[4]); 328 329 if (len == 6) 330 printf("\tVendor register funcs %02x\n", resinfo[5]); 331 break; 332 case PNP_TAG_COMPAT_DEVICE: 333 printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n", 334 ((resinfo[0] & 0x7c) >> 2) + 64, 335 (((resinfo[0] & 0x03) << 3) | 336 ((resinfo[1] & 0xe0) >> 5)) + 64, 337 (resinfo[1] & 0x1f) + 64, 338 resinfo[2], resinfo[3], *(int *)resinfo); 339 break; 340 case PNP_TAG_IRQ_FORMAT: 341 printf(" IRQ: "); 342 343 for (i = 0; i < 8; i++) 344 if (resinfo[0] & (1<<i)) 345 printf("%d ", i); 346 for (i = 0; i < 8; i++) 347 if (resinfo[1] & (1<<i)) 348 printf("%d ", i + 8); 349 if (len == 3) { 350 if (resinfo[2] & 0x1) 351 printf("IRQ: High true edge sensitive\n"); 352 if (resinfo[2] & 0x2) 353 printf("IRQ: Low true edge sensitive\n"); 354 if (resinfo[2] & 0x4) 355 printf("IRQ: High true level sensitive\n"); 356 if (resinfo[2] & 0x8) 357 printf("IRQ: Low true level sensitive\n"); 358 } else { 359 printf(" - only one type (true/edge)\n"); 360 } 361 break; 362 case PNP_TAG_DMA_FORMAT: 363 printf(" DMA: channel(s) "); 364 for (i = 0; i < 8; i++) 365 if (resinfo[0] & (1<<i)) 366 printf("%d ", i); 367 printf ("\n"); 368 report_dma_info (resinfo[1]); 369 break; 370 case PNP_TAG_START_DEPENDANT: 371 printf("TAG Start DF\n"); 372 if (len == 1) { 373 switch (resinfo[0]) { 374 case 0: 375 printf("Good Configuration\n"); 376 break; 377 case 1: 378 printf("Acceptable Configuration\n"); 379 break; 380 case 2: 381 printf("Sub-optimal Configuration\n"); 382 break; 383 } 384 } 385 break; 386 case PNP_TAG_END_DEPENDANT: 387 printf("TAG End DF\n"); 388 break; 389 case PNP_TAG_IO_RANGE: 390 printf(" I/O Range 0x%x .. 0x%x, alignment 0x%x, len 0x%x\n", 391 resinfo[1] + (resinfo[2] << 8), 392 resinfo[3] + (resinfo[4] << 8), 393 resinfo[5], resinfo[6] ); 394 if (resinfo[0]) 395 printf("\t[16-bit addr]\n"); 396 else 397 printf("\t[not 16-bit addr]\n"); 398 break; 399 case PNP_TAG_IO_FIXED: 400 printf (" FIXED I/O base address 0x%x length 0x%x\n", 401 resinfo[0] + ( (resinfo[1] & 3 ) << 8), /* XXX */ 402 resinfo[2]); 403 break; 404 #ifdef DIAGNOSTIC 405 case PNP_TAG_RESERVED: 406 printf("Reserved Tag Detected\n"); 407 break; 408 #endif 409 case PNP_TAG_VENDOR: 410 printf("*** Small Vendor Tag Detected\n"); 411 break; 412 case PNP_TAG_END: 413 printf("End Tag\n\n"); 414 /* XXX Record and Verify Checksum */ 415 return 1; 416 break; 417 } 418 return 0; 419 } 420 421 422 void 423 handle_large_res(u_char *resinfo, int item, int len) 424 { 425 int i; 426 427 DEB(printf("*** Large ITEM %d len %d found\n", item, len)); 428 switch (item) { 429 case PNP_TAG_MEMORY_RANGE: 430 report_memory_info(resinfo[0]); 431 printf("Memory range minimum address: 0x%x\n", 432 (resinfo[1] << 8) + (resinfo[2] << 16)); 433 printf("Memory range maximum address: 0x%x\n", 434 (resinfo[3] << 8) + (resinfo[4] << 16)); 435 printf("Memory range base alignment: 0x%x\n", 436 (i = (resinfo[5] + (resinfo[6] << 8))) ? i : (1 << 16)); 437 printf("Memory range length: 0x%x\n", 438 (resinfo[7] + (resinfo[8] << 8)) * 256); 439 break; 440 case PNP_TAG_ID_ANSI: 441 printf("Device Description: "); 442 443 for (i = 0; i < len; i++) { 444 if (resinfo[i]) /* XXX */ 445 printf("%c", resinfo[i]); 446 } 447 printf("\n"); 448 break; 449 case PNP_TAG_ID_UNICODE: 450 printf("ID String Unicode Detected (Undefined)\n"); 451 break; 452 case PNP_TAG_LARGE_VENDOR: 453 printf("Large Vendor Defined Detected\n"); 454 break; 455 case PNP_TAG_MEMORY32_RANGE: 456 printf("32bit Memory Range Desc Unimplemented\n"); 457 break; 458 case PNP_TAG_MEMORY32_FIXED: 459 printf("32bit Fixed Location Desc Unimplemented\n"); 460 break; 461 #ifdef DIAGNOSTIC 462 case PNP_TAG_LARGE_RESERVED: 463 printf("Large Reserved Tag Detected\n"); 464 break; 465 #endif 466 } 467 } 468 469 470 /* 471 * Dump all the information about configurations. 472 */ 473 void 474 dump_resdata(u_char *data, int csn) 475 { 476 int i, large_len; 477 478 u_char tag, *resinfo; 479 480 DDB(printf("\nCard assigned CSN #%d\n", csn)); 481 printf("Vendor ID %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n", 482 ((data[0] & 0x7c) >> 2) + 64, 483 (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64, 484 (data[1] & 0x1f) + 64, data[2], data[3], 485 *(int *)&(data[0]), 486 *(int *)&(data[4])); 487 488 pnp_write(PNP_SET_CSN, csn); /* Move this out of this function XXX */ 489 outb(_PNP_ADDRESS, PNP_STATUS); 490 491 /* Allows up to 1kb of Resource Info, Should be plenty */ 492 for (i = 0; i < 1024; i++) { 493 if (!get_resource_info(&tag, 1)) 494 break; 495 496 if (PNP_RES_TYPE(tag) == 0) { 497 /* Handle small resouce data types */ 498 499 resinfo = malloc(PNP_SRES_LEN(tag)); 500 if (!get_resource_info(resinfo, PNP_SRES_LEN(tag))) 501 break; 502 503 if (handle_small_res(resinfo, PNP_SRES_NUM(tag), PNP_SRES_LEN(tag)) == 1) 504 break; 505 free(resinfo); 506 } else { 507 /* Handle large resouce data types */ 508 u_char buf[2]; 509 if (!get_resource_info((char *)buf, 2)) 510 break; 511 large_len = (buf[1] << 8) + buf[0]; 512 513 resinfo = malloc(large_len); 514 if (!get_resource_info(resinfo, large_len)) 515 break; 516 517 handle_large_res(resinfo, PNP_LRES_NUM(tag), large_len); 518 free(resinfo); 519 } 520 } 521 printf("Successfully got %d resources, %d logical fdevs\n", i, 522 logdevs); 523 printf("-- card select # 0x%04x\n", pnp_read(PNP_SET_CSN)); 524 printf("\nCSN %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n", 525 ((data[0] & 0x7c) >> 2) + 64, 526 (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64, 527 (data[1] & 0x1f) + 64, data[2], data[3], 528 *(int *)&(data[0]), 529 *(int *)&(data[4])); 530 531 for (i=0; i<logdevs; i++) { 532 int j; 533 534 pnp_write(PNP_SET_LDN, i); 535 536 printf("\nLogical device #%d\n", pnp_read(PNP_SET_LDN) ); 537 printf("IO: "); 538 for (j=0; j<8; j++) 539 printf(" 0x%02x%02x", pnp_read(PNP_IO_BASE_HIGH(j)), 540 pnp_read(PNP_IO_BASE_LOW(j))); 541 printf("\nIRQ %d %d\n", 542 pnp_read(PNP_IRQ_LEVEL(0)), pnp_read(PNP_IRQ_LEVEL(1)) ); 543 printf("DMA %d %d\n", 544 pnp_read(PNP_DMA_CHANNEL(0)), pnp_read(PNP_DMA_CHANNEL(1)) ); 545 printf("IO range check 0x%02x activate 0x%02x\n", 546 pnp_read(PNP_IO_RANGE_CHECK), pnp_read(PNP_ACTIVATE) ); 547 } 548 } 549 550 551 /* 552 * Run the isolation protocol. Use rd_port as the READ_DATA port 553 * value (caller should try multiple READ_DATA locations before giving 554 * up). Upon exiting, all cards are aware that they should use rd_port 555 * as the READ_DATA port; 556 * 557 */ 558 int 559 isolation_protocol() 560 { 561 int csn; 562 u_char data[9]; 563 564 send_Initiation_LFSR(); 565 566 /* Reset CSN for All Cards */ 567 pnp_write(PNP_CONFIG_CONTROL, 0x04); 568 569 for (csn = 1; (csn < PNP_MAX_CARDS); csn++) { 570 /* Wake up cards without a CSN */ 571 logdevs = 0 ; 572 pnp_write(PNP_WAKE, 0); 573 pnp_write(PNP_SET_RD_DATA, rd_port); 574 outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION); 575 DELAY(1000); /* Delay 1 msec */ 576 577 if (get_serial(data)) 578 dump_resdata(data, csn); 579 else 580 break; 581 } 582 return csn - 1; 583 } 584 585 586 int 587 main(int argc, char **argv) 588 { 589 int num_pnp_devs; 590 591 #ifdef __i386__ 592 /* Hey what about a i386_iopl() call :) */ 593 if (open("/dev/io", O_RDONLY) < 0) 594 errx(1, "can't get I/O privilege"); 595 #endif 596 597 printf("Checking for Plug-n-Play devices...\n"); 598 599 /* Try various READ_DATA ports from 0x203-0x3ff */ 600 for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) { 601 DEB(printf("Trying Read_Port at %x...\n", (rd_port << 2) | 0x3) ); 602 num_pnp_devs = isolation_protocol(rd_port); 603 if (num_pnp_devs) 604 break; 605 } 606 if (!num_pnp_devs) { 607 printf("No Plug-n-Play devices were found\n"); 608 return (0); 609 } 610 return (0); 611 } 612