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