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