Annotation of src/usr.bin/pnpinfo/pnpinfo.c, Revision 1.1
1.1 ! shawn 1: /* $OpenBSD$ */
! 2: /*
! 3: * Copyright (c) 1996, Sujal M. Patel
! 4: * All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: *
! 15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 16: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 17: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 19: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 25: * SUCH DAMAGE.
! 26: */
! 27:
! 28: #include <sys/time.h>
! 29:
! 30: #include <stdio.h>
! 31: #include <stdlib.h>
! 32: #include <unistd.h>
! 33: #include <fcntl.h>
! 34: #include <string.h>
! 35:
! 36: #include <machine/cpufunc.h>
! 37:
! 38: #if defined(__OpenBSD__)
! 39: #include <i386/sysarch.h>
! 40: #include <machine/pio.h>
! 41: #endif
! 42:
! 43: #include "pnpinfo.h"
! 44:
! 45:
! 46: #define SEND(d, r) { outb (ADDRESS, d); outb (WRITE_DATA, r); }
! 47:
! 48:
! 49: /* The READ_DATA port that we are using currently */
! 50: static int rd_port;
! 51:
! 52:
! 53: void DELAY __P((int i));
! 54: int power __P((int base, int exp));
! 55: void send_Initiation_LFSR();
! 56: int get_serial __P((unsigned char *data));
! 57: int get_resource_info __P((char *buffer, int len));
! 58: int handle_small_res __P((unsigned char *resinfo, int item, int len));
! 59: void handle_large_res __P((unsigned char *resinfo, int item, int len));
! 60: void dump_resdata __P((unsigned char *data, int csn));
! 61: int isolation_protocol();
! 62:
! 63:
! 64: /*
! 65: * DELAY does accurate delaying in user-space.
! 66: * This function busy-waits.
! 67: */
! 68: void
! 69: DELAY (i)
! 70: int i;
! 71: {
! 72: struct timeval t;
! 73: long start, stop;
! 74:
! 75: gettimeofday (&t, NULL);
! 76: start = t.tv_sec * 1000000 + t.tv_usec;
! 77: do {
! 78: gettimeofday (&t, NULL);
! 79: stop = t.tv_sec * 1000000 + t.tv_usec;
! 80: } while (start + i > stop);
! 81: }
! 82:
! 83:
! 84: int
! 85: power(base, exp)
! 86: int base, exp;
! 87: {
! 88: if (exp <= 1)
! 89: return base;
! 90: else
! 91: return base * power(base, exp - 1);
! 92: }
! 93:
! 94:
! 95: /*
! 96: * Send Initiation LFSR as described in "Plug and Play ISA Specification,
! 97: * Intel May 94."
! 98: */
! 99: void
! 100: send_Initiation_LFSR()
! 101: {
! 102: int cur, i;
! 103:
! 104: /* Reset the LSFR */
! 105: outb(ADDRESS, 0);
! 106: outb(ADDRESS, 0);
! 107:
! 108: cur = 0x6a;
! 109: outb(ADDRESS, cur);
! 110:
! 111: for (i = 1; i < 32; i++) {
! 112: cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
! 113: outb(ADDRESS, cur);
! 114: }
! 115: }
! 116:
! 117:
! 118: /*
! 119: * Get the device's serial number. Returns 1 if the serial is valid.
! 120: */
! 121: int
! 122: get_serial(data)
! 123: unsigned char *data;
! 124: {
! 125: int i, bit, valid = 0, sum = 0x6a;
! 126:
! 127: bzero(data, sizeof(char) * 9);
! 128:
! 129: for (i = 0; i < 72; i++) {
! 130: bit = inb((rd_port << 2) | 0x3) == 0x55;
! 131: DELAY(250); /* Delay 250 usec */
! 132:
! 133: /* Can't Short Circuit the next evaluation, so 'and' is last */
! 134: bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit;
! 135: DELAY(250); /* Delay 250 usec */
! 136:
! 137: valid = valid || bit;
! 138:
! 139: if (i < 64)
! 140: sum = (sum >> 1) |
! 141: (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
! 142:
! 143: data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
! 144: }
! 145:
! 146: valid = valid && (data[8] == sum);
! 147:
! 148: return valid;
! 149: }
! 150:
! 151:
! 152: /*
! 153: * Fill's the buffer with resource info from the device.
! 154: * Returns 0 if the device fails to report
! 155: */
! 156: int
! 157: get_resource_info(buffer, len)
! 158: char *buffer;
! 159: int len;
! 160: {
! 161: int i, j;
! 162:
! 163: for (i = 0; i < len; i++) {
! 164: outb(ADDRESS, STATUS);
! 165: for (j = 0; j < 100; j++) {
! 166: if ((inb((rd_port << 2) | 0x3)) & 0x1)
! 167: break;
! 168: DELAY(1);
! 169: }
! 170: if (j == 100) {
! 171: printf("PnP device failed to report resource data\n");
! 172: return 0;
! 173: }
! 174: outb(ADDRESS, RESOURCE_DATA);
! 175: buffer[i] = inb((rd_port << 2) | 0x3);
! 176: }
! 177: return 1;
! 178: }
! 179:
! 180:
! 181: void
! 182: report_dma_info (x)
! 183: int x;
! 184: {
! 185: switch (x & 0x3) {
! 186: case 0:
! 187: printf ("DMA: 8-bit only\n");
! 188: break;
! 189: case 1:
! 190: printf ("DMA: 8-bit and 16-bit\n");
! 191: break;
! 192: case 2:
! 193: printf ("DMA: 16-bit only\n");
! 194: break;
! 195: #ifdef DIAGNOSTIC
! 196: case 3:
! 197: printf ("DMA: Reserved\n");
! 198: break;
! 199: #endif
! 200: }
! 201:
! 202: if (x & 0x4)
! 203: printf ("DMA: Device is a bus master\n");
! 204: else
! 205: printf ("DMA: Device is not a bus master\n");
! 206:
! 207: if (x & 0x8)
! 208: printf ("DMA: May execute in count by byte mode\n");
! 209: else
! 210: printf ("DMA: May not execute in count by byte mode\n");
! 211:
! 212: if (x & 0x10)
! 213: printf ("DMA: May execute in count by word mode\n");
! 214: else
! 215: printf ("DMA: May not execute in count by word mode\n");
! 216:
! 217: switch ((x & 0x60) >> 5) {
! 218: case 0:
! 219: printf ("DMA: Compatibility mode\n");
! 220: break;
! 221: case 1:
! 222: printf ("DMA: Type A DMA channel\n");
! 223: break;
! 224: case 2:
! 225: printf ("DMA: Type B DMA channel\n");
! 226: break;
! 227: case 3:
! 228: printf ("DMA: Type F DMA channel\n");
! 229: break;
! 230: }
! 231: }
! 232:
! 233:
! 234: void
! 235: report_memory_info (x)
! 236: 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: */
! 294: int
! 295: handle_small_res(resinfo, item, len)
! 296: int item, len;
! 297: unsigned char *resinfo;
! 298: {
! 299: int i;
! 300:
! 301: switch (item) {
! 302: case PNP_VERSION:
! 303: printf("PnP Version: %d.%d\n",
! 304: resinfo[0] >> 4,
! 305: resinfo[0] & (0xf));
! 306: printf("Vendor Version: %d\n", resinfo[1]);
! 307: break;
! 308: case LOG_DEVICE_ID:
! 309: printf("Logical Device ID: %c%c%c%02x%02x (%08x)\n",
! 310: ((resinfo[0] & 0x7c) >> 2) + 64,
! 311: (((resinfo[0] & 0x03) << 3) |
! 312: ((resinfo[1] & 0xe0) >> 5)) + 64,
! 313: (resinfo[1] & 0x1f) + 64,
! 314: resinfo[2], resinfo[3], *(int *)resinfo);
! 315:
! 316: if (resinfo[4] & 0x1)
! 317: printf ("Device powers up active\n");
! 318: if (resinfo[4] & 0x2)
! 319: printf ("Device supports I/O Range Check\n");
! 320: if (resinfo[4] > 0x3)
! 321: printf ("Reserved register funcs %02x\n",
! 322: resinfo[4]);
! 323:
! 324: if (len == 6)
! 325: printf("Vendor register funcs %02x\n", resinfo[5]);
! 326: break;
! 327: case COMP_DEVICE_ID:
! 328: printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n",
! 329: ((resinfo[0] & 0x7c) >> 2) + 64,
! 330: (((resinfo[0] & 0x03) << 3) |
! 331: ((resinfo[1] & 0xe0) >> 5)) + 64,
! 332: (resinfo[1] & 0x1f) + 64,
! 333: resinfo[2], resinfo[3], *(int *)resinfo);
! 334: break;
! 335: case IRQ_FORMAT:
! 336: printf("IRQ: ");
! 337:
! 338: for (i = 0; i < 8; i++)
! 339: if (resinfo[0] & (char) (power(2, i)))
! 340: printf("%d ", i);
! 341: for (i = 0; i < 8; i++)
! 342: if (resinfo[1] & (char) (power(2, i)))
! 343: printf("%d ", i + 8);
! 344: printf("\n");
! 345: if (len == 3) {
! 346: if (resinfo[2] & 0x1)
! 347: printf("IRQ: High true edge sensitive\n");
! 348: if (resinfo[2] & 0x2)
! 349: printf("IRQ: Low true edge sensitive\n");
! 350: if (resinfo[2] & 0x4)
! 351: printf("IRQ: High true level sensitive\n");
! 352: if (resinfo[2] & 0x8)
! 353: printf("IRQ: Low true level sensitive\n");
! 354: }
! 355: break;
! 356: case DMA_FORMAT:
! 357: printf("DMA: ");
! 358: for (i = 0; i < 8; i++)
! 359: if (resinfo[0] & (char) (power(2, i)))
! 360: printf("%d ", i);
! 361: printf ("\n");
! 362: report_dma_info (resinfo[1]);
! 363: break;
! 364: case START_DEPEND_FUNC:
! 365: printf("Start Dependent Function\n");
! 366: if (len == 1) {
! 367: switch (resinfo[0]) {
! 368: case 0:
! 369: printf("Good Configuration\n");
! 370: break;
! 371: case 1:
! 372: printf("Acceptable Configuration\n");
! 373: break;
! 374: case 2:
! 375: printf("Sub-optimal Configuration\n");
! 376: break;
! 377: }
! 378: }
! 379: break;
! 380: case END_DEPEND_FUNC:
! 381: printf("End Dependent Function\n");
! 382: break;
! 383: case IO_PORT_DESC:
! 384: if (resinfo[0])
! 385: printf("Device decodes the full 16-bit ISA address\n");
! 386: else
! 387: printf("Device does not decode the full 16-bit ISA address\n");
! 388: printf("I/O Range maximum address: 0x%x\n",
! 389: resinfo[1] + (resinfo[2] << 8));
! 390: printf("I/O Range maximum address: 0x%x\n",
! 391: resinfo[3] + (resinfo[4] << 8));
! 392: printf("I/O alignment for minimum: %d\n",
! 393: resinfo[5]);
! 394: printf("I/O length: %d\n", resinfo[6]);
! 395: break;
! 396: case FIXED_IO_PORT_DESC:
! 397: printf ("I/O Range base address: 0x%x\n",
! 398: resinfo[1] + (resinfo[2] << 8));
! 399: printf("I/O length: %d\n", resinfo[3]);
! 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:
! 419: void
! 420: handle_large_res(resinfo, item, len)
! 421: int item, len;
! 422: unsigned char *resinfo;
! 423: {
! 424: int i;
! 425:
! 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: 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: */
! 468: void
! 469: dump_resdata(data, csn)
! 470: unsigned char *data;
! 471: int csn;
! 472: {
! 473: int i, large_len;
! 474: unsigned char tag, *resinfo;
! 475:
! 476: #ifdef DEBUG
! 477: printf("Card assigned CSN #%d\n", csn);
! 478: #endif
! 479: printf("Board Vendor ID: %c%c%c%02x%02x\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: printf("Board Serial Number: %08x\n", *(int *)&(data[4]));
! 484:
! 485: SEND(SET_CSN, csn); /* Move this out of this function XXX */
! 486: outb(ADDRESS, STATUS);
! 487:
! 488: /* Allows up to 1kb of Resource Info, Should be plenty */
! 489: for (i = 0; i < 1024; i++) {
! 490: if (!get_resource_info(&tag, 1))
! 491: return;
! 492:
! 493: #define TYPE (tag >> 7)
! 494: #define S_ITEM (tag >> 3)
! 495: #define S_LEN (tag & 0x7)
! 496: #define L_ITEM (tag & 0x7f)
! 497:
! 498: if (TYPE == 0) {
! 499: /* Handle small resouce data types */
! 500:
! 501: resinfo = malloc(S_LEN);
! 502: if (!get_resource_info(resinfo, S_LEN))
! 503: return;
! 504:
! 505: if (handle_small_res(resinfo, S_ITEM, S_LEN) == 1)
! 506: return;
! 507: free(resinfo);
! 508: } else {
! 509: /* Handle large resouce data types */
! 510:
! 511: if (!get_resource_info((char *) &large_len, 2))
! 512: return;
! 513:
! 514: resinfo = malloc(large_len);
! 515: if (!get_resource_info(resinfo, large_len))
! 516: return;
! 517:
! 518: handle_large_res(resinfo, L_ITEM, large_len);
! 519: free(resinfo);
! 520: }
! 521: }
! 522: }
! 523:
! 524:
! 525: /*
! 526: * Run the isolation protocol. Use rd_port as the READ_DATA port value (caller
! 527: * should try multiple READ_DATA locations before giving up). Upon exiting,
! 528: * all cards are aware that they should use rd_port as the READ_DATA port;
! 529: */
! 530: int
! 531: isolation_protocol()
! 532: {
! 533: int csn;
! 534: unsigned char data[9];
! 535:
! 536: send_Initiation_LFSR();
! 537:
! 538: /* Reset CSN for All Cards */
! 539: SEND(0x02, 0x04);
! 540:
! 541: for (csn = 1; (csn < MAX_CARDS); csn++) {
! 542: /* Wake up cards without a CSN */
! 543: SEND(WAKE, 0);
! 544: SEND(SET_RD_DATA, rd_port);
! 545: outb(ADDRESS, SERIAL_ISOLATION);
! 546: DELAY(1000); /* Delay 1 msec */
! 547:
! 548: if (get_serial(data))
! 549: dump_resdata(data, csn);
! 550: else
! 551: break;
! 552: }
! 553: return csn - 1;
! 554: }
! 555:
! 556:
! 557: void
! 558: main()
! 559: {
! 560: int num_pnp_devs;
! 561:
! 562: #if defined(__OpenBSD__)
! 563: if (i386_iopl(1)) {
! 564: perror("i386_iopl");
! 565: exit(1);
! 566: }
! 567: #endif
! 568: printf("Checking for Plug-n-Play devices...\n");
! 569:
! 570: /* Try various READ_DATA ports from 0x203-0x3ff */
! 571: for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) {
! 572: #ifdef DEBUG
! 573: printf("Trying Read_Port at %x\n", (rd_port << 2) | 0x3);
! 574: #endif
! 575: num_pnp_devs = isolation_protocol(rd_port);
! 576: if (num_pnp_devs)
! 577: break;
! 578: }
! 579: if (!num_pnp_devs) {
! 580: printf("No Plug-n-Play devices were found\n");
! 581: return;
! 582: }
! 583: }