pnpinfo.c revision 229236
11844Swollman/* 250476Speter * Copyright (c) 1996, Sujal M. Patel 31844Swollman * All rights reserved. 41638Srgrimes * 594940Sru * Redistribution and use in source and binary forms, with or without 61638Srgrimes * modification, are permitted provided that the following conditions 742915Sjdp * are met: 842915Sjdp * 1. Redistributions of source code must retain the above copyright 942915Sjdp * notice, this list of conditions and the following disclaimer. 1042915Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1142915Sjdp * notice, this list of conditions and the following disclaimer in the 1242915Sjdp * documentation and/or other materials provided with the distribution. 1342915Sjdp * 1442915Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1599362Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1642915Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1729141Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18100375Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19100332Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20100332Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2142915Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2242915Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2329141Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24117034Sgordon * SUCH DAMAGE. 25117034Sgordon */ 262827Sjkh 272827Sjkh#include <sys/cdefs.h> 282827Sjkh__FBSDID("$FreeBSD: stable/9/contrib/pnpinfo/pnpinfo.c 229236 2012-01-01 23:26:49Z dim $"); 292827Sjkh 302827Sjkh#include <sys/time.h> 311638Srgrimes 322827Sjkh#include <err.h> 331638Srgrimes#include <stdio.h> 3418529Sbde#include <stdlib.h> 3518529Sbde#include <unistd.h> 361638Srgrimes#include <fcntl.h> 3742450Sjdp#include <string.h> 381638Srgrimes 3995064Sobrien#include <machine/cpufunc.h> 401638Srgrimes 4196512Sru#include <isa/pnpreg.h> 4296512Sru 4396512Sru#ifdef DEBUG 4496512Sru#define DEB(x) x 4596512Sru#else 4696512Sru#define DEB(x) 4796512Sru#endif 4896512Sru#define DDB(x) x 4992491Smarkm 5092491Smarkmvoid 5192553Srupnp_write(int d, u_char r) 5292491Smarkm{ 5392491Smarkm outb (_PNP_ADDRESS, d); 5492553Sru outb (_PNP_WRITE_DATA, r); 5592553Sru} 5692491Smarkm 571638Srgrimes/* The READ_DATA port that we are using currently */ 581844Swollmanstatic int rd_port; 59116855Speter 6038186Speteru_char 611638Srgrimespnp_read(int d) 621638Srgrimes{ 6324761Sjdp outb(_PNP_ADDRESS, d); 64116855Speter return inb( (rd_port << 2) + 3) & 0xff; 6538186Speter} 661638Srgrimes 6742450Sjdpu_short 681844Swollmanpnp_readw(int d) 6996258Sobrien{ 7038186Speter int c = pnp_read(d) << 8 ; 711844Swollman c |= pnp_read(d+1); 7236673Sdt return c; 731844Swollman} 74116855Speter 7538186Speterint logdevs=0; 761844Swollman 7736673Sdtvoid DELAY __P((int i)); 7824761Sjdpvoid send_Initiation_LFSR(); 79116855Speterint get_serial __P((u_char *data)); 8038186Speterint get_resource_info __P((u_char *buffer, int len)); 811844Swollmanint handle_small_res __P((u_char *resinfo, int item, int len)); 8242450Sjdpvoid handle_large_res __P((u_char *resinfo, int item, int len)); 831844Swollmanvoid dump_resdata __P((u_char *data, int csn)); 8496258Sobrienint isolation_protocol(); 8538186Speter 861844Swollman 871844Swollman/* 881844Swollman * DELAY does accurate delaying in user-space. 89116855Speter * This function busy-waits. 9038186Speter */ 911844Swollmanvoid 921844SwollmanDELAY (int i) 9324761Sjdp{ 94116855Speter struct timeval t; 9538186Speter long start, stop; 961844Swollman 9742450Sjdp i *= 4; 981844Swollman 9996258Sobrien gettimeofday (&t, NULL); 10038186Speter start = t.tv_sec * 1000000 + t.tv_usec; 1011844Swollman do { 10236054Sbde gettimeofday (&t, NULL); 10336054Sbde stop = t.tv_sec * 1000000 + t.tv_usec; 104116855Speter } while (start + i > stop); 10538186Speter} 10636054Sbde 10736054Sbde 10836054Sbde/* 109116855Speter * Send Initiation LFSR as described in "Plug and Play ISA Specification, 11038186Speter * Intel May 94." 11136054Sbde */ 11242450Sjdpvoid 11336054Sbdesend_Initiation_LFSR() 11496258Sobrien{ 11538186Speter int cur, i; 11636054Sbde 11795251Sru pnp_write(PNP_CONFIG_CONTROL, 0x2); 11897101Sru 11917510Speter /* Reset the LSFR */ 12096258Sobrien outb(_PNP_ADDRESS, 0); 12138186Speter outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */ 1221638Srgrimes 12395251Sru cur = 0x6a; 12497101Sru 12517510Speter for (i = 0; i < 32; i++) { 12696258Sobrien outb(_PNP_ADDRESS, cur); 12738186Speter cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff); 1281638Srgrimes } 12995251Sru} 13097101Sru 13195216Smarkm/* 132116855Speter * Get the device's serial number. Returns 1 if the serial is valid. 13338186Speter */ 1341638Srgrimesint 1351844Swollmanget_serial(u_char *data) 13697101Sru{ 13796258Sobrien int i, bit, valid = 0, sum = 0x6a; 13838186Speter 1391844Swollman bzero(data, sizeof(char) * 9); 1401844Swollman 14197101Sru for (i = 0; i < 72; i++) { 14296258Sobrien bit = inb((rd_port << 2) | 0x3) == 0x55; 14338186Speter DELAY(250); /* Delay 250 usec */ 1441844Swollman 14542450Sjdp /* Can't Short Circuit the next evaluation, so 'and' is last */ 14697101Sru bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit; 14795216Smarkm DELAY(250); /* Delay 250 usec */ 148116855Speter 14938186Speter valid = valid || bit; 1501844Swollman 15196512Sru if (i < 64) 1521638Srgrimes sum = (sum >> 1) | 15399362Sru (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff); 15499362Sru 15599362Sru data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0); 15699362Sru } 15796512Sru 15896512Sru valid = valid && (data[8] == sum); 1591638Srgrimes 16096512Sru return valid; 16196512Sru} 16296512Sru 16396512Sru 16496512Sru/* 16599362Sru * Fill's the buffer with resource info from the device. 1661638Srgrimes * Returns 0 if the device fails to report 16796512Sru */ 16895114Sobrienint 16999362Sruget_resource_info(u_char *buffer, int len) 17096512Sru{ 17196512Sru int i, j; 17295306Sru 17396512Sru for (i = 0; i < len; i++) { 17496512Sru outb(_PNP_ADDRESS, PNP_STATUS); 17596512Sru for (j = 0; j < 100; j++) { 17696512Sru if ((inb((rd_port << 2) | 0x3)) & 0x1) 17796512Sru break; 17874805Sru DELAY(1); 1791844Swollman } 18099362Sru if (j == 100) { 18199362Sru printf("PnP device failed to report resource data\n"); 18296512Sru return 0; 18399362Sru } 1841844Swollman outb(_PNP_ADDRESS, PNP_RESOURCE_DATA); 18596512Sru buffer[i] = inb((rd_port << 2) | 0x3); 18696512Sru DEB(printf("--- get_resource_info: got 0x%02x\n",(unsigned)buffer[i])); 1871638Srgrimes } 18842915Sjdp return 1; 18942915Sjdp} 19096512Sru 19142915Sjdpvoid 19296512Srureport_dma_info (x) 19342915Sjdp int x; 19496343Sobrien{ 19596512Sru char *s1=NULL, *s2=NULL, *s3=NULL, *s4=NULL, *s5=NULL; 19691011Sru 19728945Speter switch (x & 0x3) { 1981844Swollman case 0: 19999362Sru s1="8-bit"; 20096512Sru break; 20196512Sru case 1: 20296512Sru s1="8/16-bit"; 2032353Sbde break; 20496512Sru case 2: 20596512Sru s1="16-bit"; 20696512Sru break; 2073859Sbde#ifdef DIAGNOSTIC 2081844Swollman case 3: 209103713Smarkm s1="Reserved"; 21096512Sru break; 21196512Sru#endif 21296512Sru } 21396512Sru 21492491Smarkm s2 = (x & 0x4) ? "bus master" : "not a bus master"; 21596512Sru 21696512Sru s3 = (x & 0x8) ? "count by byte" : ""; 21792491Smarkm 21892491Smarkm s4 = (x & 0x10) ? "count by word" : ""; 2191638Srgrimes 22096512Sru switch ((x & 0x60) >> 5) { 22196512Sru case 0: 22296512Sru s5="Compatibility mode"; 22396512Sru break; 22496512Sru case 1: 22596512Sru s5="Type A"; 2261638Srgrimes break; 2271638Srgrimes case 2: 22834179Sbde s5="Type B"; 22924750Sbde break; 23042450Sjdp case 3: 23124750Sbde s5="Type F"; 23224750Sbde break; 23342915Sjdp } 23431809Sbde printf("\t%s, %s, %s, %s, %s\n",s1,s2,s3,s4,s5); 23542915Sjdp} 23627910Sasami 23728945Speter 2381638Srgrimesvoid 2391638Srgrimesreport_memory_info (int x) 2401638Srgrimes{ 24148204Sjmg if (x & 0x1) 2422298Swollman printf ("Memory Range: Writeable\n"); 2432298Swollman else 2442298Swollman printf ("Memory Range: Not writeable (ROM)\n"); 24549328Shoek 24649328Shoek if (x & 0x2) 24749328Shoek printf ("Memory Range: Read-cacheable, write-through\n"); 24849328Shoek else 24956971Sru printf ("Memory Range: Non-cacheable\n"); 25049328Shoek 25149328Shoek if (x & 0x4) 25249328Shoek printf ("Memory Range: Decode supports high address\n"); 25349328Shoek else 25499362Sru printf ("Memory Range: Decode supports range length\n"); 25595306Sru 25699343Sru switch ((x & 0x18) >> 3) { 25795306Sru case 0: 25899362Sru printf ("Memory Range: 8-bit memory only\n"); 25992980Sdes break; 26049328Shoek case 1: 26196512Sru printf ("Memory Range: 16-bit memory only\n"); 26299362Sru break; 26392980Sdes case 2: 26449328Shoek printf ("Memory Range: 8-bit and 16-bit memory supported\n"); 2651638Srgrimes break; 266116144Sobrien#ifdef DIAGNOSTIC 267100872Sru case 3: 26849328Shoek printf ("Memory Range: Reserved\n"); 26942915Sjdp break; 27042915Sjdp#endif 27196512Sru } 2721844Swollman 27328945Speter if (x & 0x20) 27499362Sru printf ("Memory Range: Memory is shadowable\n"); 275100872Sru else 27649328Shoek printf ("Memory Range: Memory is not shadowable\n"); 2771844Swollman 278103713Smarkm if (x & 0x40) 279100872Sru printf ("Memory Range: Memory is an expansion ROM\n"); 28096462Sru else 28196462Sru printf ("Memory Range: Memory is not an expansion ROM\n"); 28299362Sru 28396462Sru#ifdef DIAGNOSTIC 28497769Sru if (x & 0x80) 28596668Sru printf ("Memory Range: Reserved (Device is brain-damaged)\n"); 28699256Sru#endif 28796462Sru} 28896162Sru 28996164Sru 29099343Sru/* 29196162Sru * Small Resource Tag Handler 29296162Sru * 2931638Srgrimes * Returns 1 if checksum was valid (and an END_TAG was received). 2941638Srgrimes * Returns -1 if checksum was invalid (and an END_TAG was received). 2951638Srgrimes * Returns 0 for other tags. 29695306Sru */ 297103713Smarkmint 2981638Srgrimeshandle_small_res(u_char *resinfo, int item, int len) 2991638Srgrimes{ 3001844Swollman int i; 3011638Srgrimes 30274842Sru DEB(printf("*** ITEM 0x%04x len %d detected\n", item, len)); 3031844Swollman 3041844Swollman switch (item) { 30534092Sbde default: 30699362Sru printf("*** ITEM 0x%02x detected\n", item); 30796512Sru break; 30899362Sru case PNP_TAG_VERSION: 30934092Sbde printf("PnP Version %d.%d, Vendor Version %d\n", 31099362Sru resinfo[0] >> 4, resinfo[0] & (0xf), resinfo[1]); 31199362Sru break; 31299362Sru case PNP_TAG_LOGICAL_DEVICE: 31396512Sru printf("\nLogical Device ID: %c%c%c%02x%02x 0x%08x #%d\n", 31499362Sru ((resinfo[0] & 0x7c) >> 2) + 64, 31534092Sbde (((resinfo[0] & 0x03) << 3) | 316100457Sru ((resinfo[1] & 0xe0) >> 5)) + 64, 317100457Sru (resinfo[1] & 0x1f) + 64, 318100457Sru resinfo[2], resinfo[3], *(int *)(resinfo), 319100457Sru logdevs++); 320100457Sru 321100457Sru if (resinfo[4] & 0x1) 322100457Sru printf ("\tDevice powers up active\n"); /* XXX */ 323100457Sru if (resinfo[4] & 0x2) 324100457Sru printf ("\tDevice supports I/O Range Check\n"); 325100457Sru if (resinfo[4] > 0x3) 326100457Sru printf ("\tReserved register funcs %02x\n", 327100457Sru resinfo[4]); 328100457Sru 329100457Sru if (len == 6) 330100457Sru printf("\tVendor register funcs %02x\n", resinfo[5]); 331100457Sru break; 332100457Sru case PNP_TAG_COMPAT_DEVICE: 333100457Sru printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n", 334100457Sru ((resinfo[0] & 0x7c) >> 2) + 64, 335100457Sru (((resinfo[0] & 0x03) << 3) | 336100457Sru ((resinfo[1] & 0xe0) >> 5)) + 64, 337100457Sru (resinfo[1] & 0x1f) + 64, 338100457Sru resinfo[2], resinfo[3], *(int *)resinfo); 339100457Sru break; 340100457Sru case PNP_TAG_IRQ_FORMAT: 341100457Sru printf(" IRQ: "); 342100457Sru 343100457Sru for (i = 0; i < 8; i++) 344100457Sru if (resinfo[0] & (1<<i)) 345100457Sru printf("%d ", i); 346100457Sru for (i = 0; i < 8; i++) 347100457Sru if (resinfo[1] & (1<<i)) 348100457Sru printf("%d ", i + 8); 349100457Sru if (len == 3) { 350100457Sru if (resinfo[2] & 0x1) 351100457Sru printf("IRQ: High true edge sensitive\n"); 35216663Sjkh if (resinfo[2] & 0x2) 35376861Skris printf("IRQ: Low true edge sensitive\n"); 35476861Skris 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 422void 423handle_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 */ 473void 474dump_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 */ 558int 559isolation_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 586int 587main(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(); 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