[BACK]Return to pnpinfo.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / pnpinfo

Annotation of src/usr.bin/pnpinfo/pnpinfo.c, Revision 1.1.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: }