pnpinfo.c revision 50786
1279377Simp/* 2279377Simp * Copyright (c) 1996, Sujal M. Patel 3279377Simp * All rights reserved. 4279377Simp * 5279377Simp * Redistribution and use in source and binary forms, with or without 6279377Simp * modification, are permitted provided that the following conditions 7279377Simp * are met: 8279377Simp * 1. Redistributions of source code must retain the above copyright 9279377Simp * notice, this list of conditions and the following disclaimer. 10279377Simp * 2. Redistributions in binary form must reproduce the above copyright 11279377Simp * notice, this list of conditions and the following disclaimer in the 12279377Simp * documentation and/or other materials provided with the distribution. 13279377Simp * 14279377Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15279377Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16279377Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17279377Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18279377Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19279377Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20279377Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21279377Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22279377Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23279377Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24279377Simp * SUCH DAMAGE. 25279377Simp * 26279377Simp * $Id: pnpinfo.c,v 1.5 1999/05/22 17:35:43 dfr Exp $ 27279377Simp */ 28279377Simp 29279377Simp#include <sys/time.h> 30279377Simp 31279377Simp#include <stdio.h> 32279377Simp#include <stdlib.h> 33279377Simp#include <unistd.h> 34279377Simp#include <fcntl.h> 35279377Simp#include <string.h> 36279377Simp 37279377Simp#include <machine/cpufunc.h> 38279377Simp 39279377Simp#include <isa/pnpreg.h> 40279377Simp 41279377Simp#ifdef DEBUG 42279377Simp#define DEB(x) x 43279377Simp#else 44279377Simp#define DEB(x) 45279377Simp#endif 46279377Simp#define DDB(x) x 47279377Simp 48279377Simpvoid 49279377Simppnp_write(int d, u_char r) 50279377Simp{ 51279377Simp outb (_PNP_ADDRESS, d); 52279377Simp outb (_PNP_WRITE_DATA, r); 53279377Simp} 54279377Simp 55279377Simp/* The READ_DATA port that we are using currently */ 56279377Simpstatic int rd_port; 57279377Simp 58279377Simpu_char 59279377Simppnp_read(int d) 60279377Simp{ 61279377Simp outb(_PNP_ADDRESS, d); 62279377Simp return inb( (rd_port << 2) + 3) & 0xff; 63279377Simp} 64279377Simp 65279377Simpu_short 66279377Simppnp_readw(int d) 67279377Simp{ 68279377Simp int c = pnp_read(d) << 8 ; 69279377Simp c |= pnp_read(d+1); 70279377Simp return c; 71279377Simp} 72279377Simp 73279377Simpint logdevs=0; 74279377Simp 75279377Simpvoid DELAY __P((int i)); 76279377Simpvoid send_Initiation_LFSR(); 77279377Simpint get_serial __P((u_char *data)); 78279377Simpint get_resource_info __P((u_char *buffer, int len)); 79279377Simpint handle_small_res __P((u_char *resinfo, int item, int len)); 80279377Simpvoid handle_large_res __P((u_char *resinfo, int item, int len)); 81279377Simpvoid dump_resdata __P((u_char *data, int csn)); 82279377Simpint isolation_protocol(); 83279377Simp 84279377Simp 85279377Simp/* 86279377Simp * DELAY does accurate delaying in user-space. 87279377Simp * This function busy-waits. 88279377Simp */ 89279377Simpvoid 90279377SimpDELAY (int i) 91279377Simp{ 92279377Simp struct timeval t; 93279377Simp long start, stop; 94279377Simp 95279377Simp i *= 4; 96279377Simp 97279377Simp gettimeofday (&t, NULL); 98279377Simp start = t.tv_sec * 1000000 + t.tv_usec; 99279377Simp do { 100279377Simp gettimeofday (&t, NULL); 101279377Simp stop = t.tv_sec * 1000000 + t.tv_usec; 102279377Simp } while (start + i > stop); 103279377Simp} 104279377Simp 105279377Simp 106279377Simp/* 107279377Simp * Send Initiation LFSR as described in "Plug and Play ISA Specification, 108279377Simp * Intel May 94." 109279377Simp */ 110279377Simpvoid 111279377Simpsend_Initiation_LFSR() 112279377Simp{ 113279377Simp int cur, i; 114279377Simp 115279377Simp pnp_write(PNP_CONFIG_CONTROL, 0x2); 116279377Simp 117279377Simp /* Reset the LSFR */ 118279377Simp outb(_PNP_ADDRESS, 0); 119279377Simp outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */ 120279377Simp 121279377Simp cur = 0x6a; 122279377Simp 123279377Simp for (i = 0; i < 32; i++) { 124279377Simp outb(_PNP_ADDRESS, cur); 125279377Simp cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff); 126279377Simp } 127279377Simp} 128279377Simp 129279377Simp/* 130279377Simp * Get the device's serial number. Returns 1 if the serial is valid. 131279377Simp */ 132279377Simpint 133279377Simpget_serial(u_char *data) 134279377Simp{ 135279377Simp int i, bit, valid = 0, sum = 0x6a; 136279377Simp 137279377Simp bzero(data, sizeof(char) * 9); 138279377Simp 139279377Simp for (i = 0; i < 72; i++) { 140279377Simp bit = inb((rd_port << 2) | 0x3) == 0x55; 141279377Simp DELAY(250); /* Delay 250 usec */ 142279377Simp 143279377Simp /* Can't Short Circuit the next evaluation, so 'and' is last */ 144279377Simp bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit; 145279377Simp DELAY(250); /* Delay 250 usec */ 146279377Simp 147279377Simp valid = valid || bit; 148279377Simp 149279377Simp if (i < 64) 150279377Simp sum = (sum >> 1) | 151279377Simp (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff); 152279377Simp 153279377Simp data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0); 154279377Simp } 155279377Simp 156279377Simp valid = valid && (data[8] == sum); 157279377Simp 158279377Simp return valid; 159279377Simp} 160279377Simp 161279377Simp 162279377Simp/* 163279377Simp * Fill's the buffer with resource info from the device. 164279377Simp * Returns 0 if the device fails to report 165279377Simp */ 166279377Simpint 167279377Simpget_resource_info(u_char *buffer, int len) 168279377Simp{ 169279377Simp int i, j; 170279377Simp 171279377Simp for (i = 0; i < len; i++) { 172279377Simp outb(_PNP_ADDRESS, PNP_STATUS); 173279377Simp for (j = 0; j < 100; j++) { 174279377Simp if ((inb((rd_port << 2) | 0x3)) & 0x1) 175279377Simp break; 176279377Simp DELAY(1); 177279377Simp } 178279377Simp if (j == 100) { 179279377Simp printf("PnP device failed to report resource data\n"); 180279377Simp return 0; 181279377Simp } 182279377Simp outb(_PNP_ADDRESS, PNP_RESOURCE_DATA); 183279377Simp buffer[i] = inb((rd_port << 2) | 0x3); 184279377Simp DEB(printf("--- get_resource_info: got 0x%02x\n",(unsigned)buffer[i])); 185279377Simp } 186279377Simp return 1; 187279377Simp} 188279377Simp 189279377Simpvoid 190279377Simpreport_dma_info (x) 191279377Simp int x; 192279377Simp{ 193279377Simp char *s1=NULL, *s2=NULL, *s3=NULL, *s4=NULL, *s5=NULL; 194279377Simp 195279377Simp switch (x & 0x3) { 196279377Simp case 0: 197279377Simp s1="8-bit"; 198279377Simp break; 199279377Simp case 1: 200279377Simp s1="8/16-bit"; 201279377Simp break; 202279377Simp case 2: 203279377Simp s1="16-bit"; 204279377Simp break; 205279377Simp#ifdef DIAGNOSTIC 206279377Simp case 3: 207279377Simp s1="Reserved"; 208279377Simp break; 209279377Simp#endif 210279377Simp } 211279377Simp 212279377Simp s2 = (x & 0x4) ? "bus master" : "not a bus master"; 213279377Simp 214279377Simp s3 = (x & 0x8) ? "count by byte" : ""; 215279377Simp 216279377Simp s4 = (x & 0x10) ? "count by word" : ""; 217279377Simp 218279377Simp switch ((x & 0x60) >> 5) { 219279377Simp case 0: 220279377Simp s5="Compatibility mode"; 221279377Simp break; 222279377Simp case 1: 223279377Simp s5="Type A"; 224279377Simp break; 225279377Simp case 2: 226279377Simp s5="Type B"; 227279377Simp break; 228279377Simp case 3: 229279377Simp s5="Type F"; 230279377Simp break; 231279377Simp } 232279377Simp printf("\t%s, %s, %s, %s, %s\n",s1,s2,s3,s4,s5); 233279377Simp} 234279377Simp 235279377Simp 236279377Simpvoid 237279377Simpreport_memory_info (int x) 238279377Simp{ 239279377Simp if (x & 0x1) 240279377Simp printf ("Memory Range: Writeable\n"); 241279377Simp else 242279377Simp printf ("Memory Range: Not writeable (ROM)\n"); 243279377Simp 244279377Simp if (x & 0x2) 245279377Simp printf ("Memory Range: Read-cacheable, write-through\n"); 246279377Simp else 247279377Simp printf ("Memory Range: Non-cacheable\n"); 248279377Simp 249279377Simp if (x & 0x4) 250279377Simp printf ("Memory Range: Decode supports high address\n"); 251279377Simp else 252279377Simp printf ("Memory Range: Decode supports range length\n"); 253279377Simp 254279377Simp switch ((x & 0x18) >> 3) { 255279377Simp case 0: 256279377Simp printf ("Memory Range: 8-bit memory only\n"); 257279377Simp break; 258279377Simp case 1: 259279377Simp printf ("Memory Range: 16-bit memory only\n"); 260279377Simp break; 261279377Simp case 2: 262279377Simp printf ("Memory Range: 8-bit and 16-bit memory supported\n"); 263279377Simp break; 264279377Simp#ifdef DIAGNOSTIC 265279377Simp case 3: 266279377Simp printf ("Memory Range: Reserved\n"); 267279377Simp break; 268279377Simp#endif 269279377Simp } 270279377Simp 271279377Simp if (x & 0x20) 272279377Simp printf ("Memory Range: Memory is shadowable\n"); 273279377Simp else 274279377Simp printf ("Memory Range: Memory is not shadowable\n"); 275279377Simp 276279377Simp if (x & 0x40) 277279377Simp printf ("Memory Range: Memory is an expansion ROM\n"); 278279377Simp else 279279377Simp printf ("Memory Range: Memory is not an expansion ROM\n"); 280279377Simp 281279377Simp#ifdef DIAGNOSTIC 282279377Simp if (x & 0x80) 283279377Simp printf ("Memory Range: Reserved (Device is brain-damaged)\n"); 284279377Simp#endif 285279377Simp} 286279377Simp 287279377Simp 288279377Simp/* 289279377Simp * Small Resource Tag Handler 290279377Simp * 291279377Simp * Returns 1 if checksum was valid (and an END_TAG was received). 292279377Simp * Returns -1 if checksum was invalid (and an END_TAG was received). 293279377Simp * Returns 0 for other tags. 294279377Simp */ 295279377Simpint 296279377Simphandle_small_res(u_char *resinfo, int item, int len) 297279377Simp{ 298279377Simp int i; 299279377Simp 300279377Simp DEB(printf("*** ITEM 0x%04x len %d detected\n", item, len)); 301279377Simp 302279377Simp switch (item) { 303279377Simp default: 304279377Simp printf("*** ITEM 0x%02x detected\n", item); 305279377Simp break; 306279377Simp case PNP_TAG_VERSION: 307279377Simp printf("PnP Version %d.%d, Vendor Version %d\n", 308279377Simp resinfo[0] >> 4, resinfo[0] & (0xf), resinfo[1]); 309279377Simp break; 310279377Simp case PNP_TAG_LOGICAL_DEVICE: 311279377Simp printf("\nLogical Device ID: %c%c%c%02x%02x 0x%08x #%d\n", 312279377Simp ((resinfo[0] & 0x7c) >> 2) + 64, 313279377Simp (((resinfo[0] & 0x03) << 3) | 314279377Simp ((resinfo[1] & 0xe0) >> 5)) + 64, 315279377Simp (resinfo[1] & 0x1f) + 64, 316279377Simp resinfo[2], resinfo[3], *(int *)(resinfo), 317279377Simp logdevs++); 318279377Simp 319279377Simp if (resinfo[4] & 0x1) 320279377Simp printf ("\tDevice powers up active\n"); /* XXX */ 321279377Simp if (resinfo[4] & 0x2) 322279377Simp printf ("\tDevice supports I/O Range Check\n"); 323279377Simp if (resinfo[4] > 0x3) 324279377Simp printf ("\tReserved register funcs %02x\n", 325279377Simp resinfo[4]); 326279377Simp 327279377Simp if (len == 6) 328279377Simp printf("\tVendor register funcs %02x\n", resinfo[5]); 329279377Simp break; 330279377Simp case PNP_TAG_COMPAT_DEVICE: 331279377Simp printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n", 332279377Simp ((resinfo[0] & 0x7c) >> 2) + 64, 333279377Simp (((resinfo[0] & 0x03) << 3) | 334279377Simp ((resinfo[1] & 0xe0) >> 5)) + 64, 335279377Simp (resinfo[1] & 0x1f) + 64, 336279377Simp resinfo[2], resinfo[3], *(int *)resinfo); 337279377Simp break; 338279377Simp case PNP_TAG_IRQ_FORMAT: 339279377Simp printf(" IRQ: "); 340279377Simp 341279377Simp for (i = 0; i < 8; i++) 342279377Simp if (resinfo[0] & (1<<i)) 343279377Simp printf("%d ", i); 344279377Simp for (i = 0; i < 8; i++) 345279377Simp if (resinfo[1] & (1<<i)) 346279377Simp printf("%d ", i + 8); 347279377Simp if (len == 3) { 348279377Simp if (resinfo[2] & 0x1) 349279377Simp 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 PNP_TAG_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 PNP_TAG_START_DEPENDANT: 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 PNP_TAG_END_DEPENDANT: 385 printf("TAG End DF\n"); 386 break; 387 case PNP_TAG_IO_RANGE: 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 PNP_TAG_IO_FIXED: 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 PNP_TAG_RESERVED: 404 printf("Reserved Tag Detected\n"); 405 break; 406#endif 407 case PNP_TAG_VENDOR: 408 printf("*** Small Vendor Tag Detected\n"); 409 break; 410 case PNP_TAG_END: 411 printf("End Tag\n\n"); 412 /* XXX Record and Verify Checksum */ 413 return 1; 414 break; 415 } 416 return 0; 417} 418 419 420void 421handle_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 PNP_TAG_MEMORY_RANGE: 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 PNP_TAG_ID_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 PNP_TAG_ID_UNICODE: 448 printf("ID String Unicode Detected (Undefined)\n"); 449 break; 450 case PNP_TAG_LARGE_VENDOR: 451 printf("Large Vendor Defined Detected\n"); 452 break; 453 case PNP_TAG_MEMORY32_RANGE: 454 printf("32bit Memory Range Desc Unimplemented\n"); 455 break; 456 case PNP_TAG_MEMORY32_FIXED: 457 printf("32bit Fixed Location Desc Unimplemented\n"); 458 break; 459#ifdef DIAGNOSTIC 460 case PNP_TAG_LARGE_RESERVED: 461 printf("Large Reserved Tag Detected\n"); 462 break; 463#endif 464 } 465} 466 467 468/* 469 * Dump all the information about configurations. 470 */ 471void 472dump_resdata(u_char *data, int csn) 473{ 474 int i, large_len; 475 476 u_char tag, *resinfo; 477 478 DDB(printf("\nCard assigned CSN #%d\n", csn)); 479 printf("Vendor ID %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n", 480 ((data[0] & 0x7c) >> 2) + 64, 481 (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64, 482 (data[1] & 0x1f) + 64, data[2], data[3], 483 *(int *)&(data[0]), 484 *(int *)&(data[4])); 485 486 pnp_write(PNP_SET_CSN, csn); /* Move this out of this function XXX */ 487 outb(_PNP_ADDRESS, PNP_STATUS); 488 489 /* Allows up to 1kb of Resource Info, Should be plenty */ 490 for (i = 0; i < 1024; i++) { 491 if (!get_resource_info(&tag, 1)) 492 break; 493 494 if (PNP_RES_TYPE(tag) == 0) { 495 /* Handle small resouce data types */ 496 497 resinfo = malloc(PNP_SRES_LEN(tag)); 498 if (!get_resource_info(resinfo, PNP_SRES_LEN(tag))) 499 break; 500 501 if (handle_small_res(resinfo, PNP_SRES_NUM(tag), PNP_SRES_LEN(tag)) == 1) 502 break; 503 free(resinfo); 504 } else { 505 /* Handle large resouce data types */ 506 u_char buf[2]; 507 if (!get_resource_info((char *)buf, 2)) 508 break; 509 large_len = (buf[1] << 8) + buf[0]; 510 511 resinfo = malloc(large_len); 512 if (!get_resource_info(resinfo, large_len)) 513 break; 514 515 handle_large_res(resinfo, PNP_LRES_NUM(tag), large_len); 516 free(resinfo); 517 } 518 } 519 printf("Successfully got %d resources, %d logical fdevs\n", i, 520 logdevs); 521 printf("-- card select # 0x%04x\n", pnp_read(PNP_SET_CSN)); 522 printf("\nCSN %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n", 523 ((data[0] & 0x7c) >> 2) + 64, 524 (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64, 525 (data[1] & 0x1f) + 64, data[2], data[3], 526 *(int *)&(data[0]), 527 *(int *)&(data[4])); 528 529 for (i=0; i<logdevs; i++) { 530 int j; 531 532 pnp_write(PNP_SET_LDN, i); 533 534 printf("\nLogical device #%d\n", pnp_read(PNP_SET_LDN) ); 535 printf("IO: "); 536 for (j=0; j<8; j++) 537 printf(" 0x%02x%02x", pnp_read(PNP_IO_BASE_HIGH(i)), 538 pnp_read(PNP_IO_BASE_LOW(i))); 539 printf("\nIRQ %d %d\n", 540 pnp_read(PNP_IRQ_LEVEL(0)), pnp_read(PNP_IRQ_LEVEL(1)) ); 541 printf("DMA %d %d\n", 542 pnp_read(PNP_DMA_CHANNEL(0)), pnp_read(PNP_DMA_CHANNEL(1)) ); 543 printf("IO range check 0x%02x activate 0x%02x\n", 544 pnp_read(PNP_IO_RANGE_CHECK), pnp_read(PNP_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(PNP_CONFIG_CONTROL, 0x04); 566 567 for (csn = 1; (csn < PNP_MAX_CARDS); csn++) { 568 /* Wake up cards without a CSN */ 569 logdevs = 0 ; 570 pnp_write(PNP_WAKE, 0); 571 pnp_write(PNP_SET_RD_DATA, rd_port); 572 outb(_PNP_ADDRESS, PNP_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 584int 585main(int argc, char **argv) 586{ 587 int num_pnp_devs; 588 589#ifdef __i386__ 590 /* Hey what about a i386_iopl() call :) */ 591 if (open("/dev/io", O_RDONLY) < 0) { 592 fprintf (stderr, "pnpinfo: Can't get I/O privilege.\n"); 593 exit (1); 594 } 595#endif 596#ifdef __alpha__ 597 ioperm(0x203, 0x400 - 0x203, 1); 598#endif 599 600 printf("Checking for Plug-n-Play devices...\n"); 601 602 /* Try various READ_DATA ports from 0x203-0x3ff */ 603 for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) { 604 DEB(printf("Trying Read_Port at %x...\n", (rd_port << 2) | 0x3) ); 605 num_pnp_devs = isolation_protocol(rd_port); 606 if (num_pnp_devs) 607 break; 608 } 609 if (!num_pnp_devs) { 610 printf("No Plug-n-Play devices were found\n"); 611 return 0; 612 } 613} 614