pnpinfo.c revision 101611
139211Sgibbs/*
239211Sgibbs * Copyright (c) 1996, Sujal M. Patel
339211Sgibbs * All rights reserved.
439211Sgibbs *
539211Sgibbs * Redistribution and use in source and binary forms, with or without
639211Sgibbs * modification, are permitted provided that the following conditions
739211Sgibbs * are met:
839211Sgibbs * 1. Redistributions of source code must retain the above copyright
939211Sgibbs *    notice, this list of conditions and the following disclaimer.
1039211Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1139211Sgibbs *    notice, this list of conditions and the following disclaimer in the
1239211Sgibbs *    documentation and/or other materials provided with the distribution.
1339211Sgibbs *
1439211Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1539211Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1639211Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1739211Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1839211Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1939211Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2039211Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2139211Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2239211Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2339211Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2439211Sgibbs * SUCH DAMAGE.
2539211Sgibbs *
2639211Sgibbs * $FreeBSD: head/contrib/pnpinfo/pnpinfo.c 101611 2002-08-09 22:04:54Z iedowse $
2739211Sgibbs */
2839211Sgibbs
2983551Sdillon#include <sys/time.h>
3083551Sdillon
3183551Sdillon#include <stdio.h>
3239211Sgibbs#include <stdlib.h>
3339211Sgibbs#include <unistd.h>
3439211Sgibbs#include <fcntl.h>
35110998Sphk#include <string.h>
3681133Stmm
3739211Sgibbs#include <machine/cpufunc.h>
3839451Sken
3939211Sgibbs#include <isa/pnpreg.h>
4081133Stmm
4181133Stmm#ifdef DEBUG
4239211Sgibbs#define	DEB(x) x
4339211Sgibbs#else
4439211Sgibbs#define DEB(x)
4581133Stmm#endif
4681133Stmm#define DDB(x) x
47121064Sbde
4839211Sgibbsvoid
4939211Sgibbspnp_write(int d, u_char r)
5039211Sgibbs{
51113710Sphk    outb (_PNP_ADDRESS, d);
52113710Sphk    outb (_PNP_WRITE_DATA, r);
53113710Sphk}
54113710Sphk
55113710Sphk/* The READ_DATA port that we are using currently */
56113710Sphkstatic int rd_port;
57113710Sphk
58113710Sphku_char
5981133Stmmpnp_read(int d)
6081133Stmm{
6181133Stmm    outb(_PNP_ADDRESS, d);
6281883Sken    return inb( (rd_port << 2) + 3) & 0xff;
6381883Sken}
6481133Stmm
6581133Stmmu_short
6639211Sgibbspnp_readw(int d)
6739211Sgibbs{
6839211Sgibbs    int c = pnp_read(d) << 8 ;
6939211Sgibbs    c |= pnp_read(d+1);
7039211Sgibbs    return c;
7139211Sgibbs}
7239211Sgibbs
7339211Sgibbsint logdevs=0;
7439211Sgibbs
7539211Sgibbsvoid DELAY __P((int i));
7639211Sgibbsvoid send_Initiation_LFSR();
7739211Sgibbsint get_serial __P((u_char *data));
7839211Sgibbsint get_resource_info __P((u_char *buffer, int len));
7939211Sgibbsint handle_small_res __P((u_char *resinfo, int item, int len));
8039211Sgibbsvoid handle_large_res __P((u_char *resinfo, int item, int len));
8139211Sgibbsvoid dump_resdata __P((u_char *data, int csn));
8239211Sgibbsint isolation_protocol();
8339211Sgibbs
8439211Sgibbs
8539211Sgibbs/*
8639211Sgibbs * DELAY does accurate delaying in user-space.
8739211Sgibbs * This function busy-waits.
8839211Sgibbs */
8939211Sgibbsvoid
9039211SgibbsDELAY (int i)
9139211Sgibbs{
9239211Sgibbs    struct timeval t;
9381133Stmm    long start, stop;
9481133Stmm
9581133Stmm    i *= 4;
9681133Stmm
9781133Stmm    gettimeofday (&t, NULL);
9881133Stmm    start = t.tv_sec * 1000000 + t.tv_usec;
9981133Stmm    do {
10081133Stmm	gettimeofday (&t, NULL);
10181133Stmm	stop = t.tv_sec * 1000000 + t.tv_usec;
10281133Stmm    } while (start + i > stop);
10381133Stmm}
104112405Sphk
10581133Stmm
10681133Stmm/*
10781133Stmm * Send Initiation LFSR as described in "Plug and Play ISA Specification,
10881133Stmm * Intel May 94."
10981133Stmm */
11081133Stmmvoid
11181133Stmmsend_Initiation_LFSR()
11281133Stmm{
11381133Stmm    int cur, i;
11481133Stmm
11581133Stmm    pnp_write(PNP_CONFIG_CONTROL, 0x2);
11681133Stmm
11781133Stmm    /* Reset the LSFR */
11881133Stmm    outb(_PNP_ADDRESS, 0);
11981133Stmm    outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */
12081133Stmm
12181133Stmm    cur = 0x6a;
12281133Stmm
12381883Sken    for (i = 0; i < 32; i++) {
124112406Sphk	outb(_PNP_ADDRESS, cur);
125112405Sphk	cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
126112405Sphk    }
127112405Sphk}
128112405Sphk
129112405Sphk/*
130112405Sphk * Get the device's serial number.  Returns 1 if the serial is valid.
131112405Sphk */
132112405Sphkint
133112373Sphkget_serial(u_char *data)
134112373Sphk{
135112373Sphk    int i, bit, valid = 0, sum = 0x6a;
136244270Strociny
137244270Strociny    bzero(data, sizeof(char) * 9);
138244270Strociny
139244270Strociny    for (i = 0; i < 72; i++) {
140244270Strociny	bit = inb((rd_port << 2) | 0x3) == 0x55;
141244270Strociny	DELAY(250);	/* Delay 250 usec */
14281133Stmm
14381133Stmm	/* Can't Short Circuit the next evaluation, so 'and' is last */
14483868Sken	bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit;
14581133Stmm	DELAY(250);	/* Delay 250 usec */
14681133Stmm
14781133Stmm	valid = valid || bit;
14881133Stmm
14981133Stmm	if (i < 64)
15081133Stmm	    sum = (sum >> 1) |
15181133Stmm		(((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
15281133Stmm
15381133Stmm	data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
15481133Stmm    }
15581133Stmm
15639211Sgibbs    valid = valid && (data[8] == sum);
15739211Sgibbs
15839211Sgibbs    return valid;
15939211Sgibbs}
16081133Stmm
16183868Sken
16281133Stmm/*
16339211Sgibbs * Fill's the buffer with resource info from the device.
16481133Stmm * Returns 0 if the device fails to report
16581133Stmm */
16681133Stmmint
16739211Sgibbsget_resource_info(u_char *buffer, int len)
16881133Stmm{
16939211Sgibbs    int i, j;
17039211Sgibbs
17139211Sgibbs    for (i = 0; i < len; i++) {
17239211Sgibbs	outb(_PNP_ADDRESS, PNP_STATUS);
17339211Sgibbs	for (j = 0; j < 100; j++) {
17439211Sgibbs	    if ((inb((rd_port << 2) | 0x3)) & 0x1)
17539211Sgibbs		break;
17639211Sgibbs	    DELAY(1);
17739211Sgibbs	}
17881133Stmm	if (j == 100) {
17981133Stmm	    printf("PnP device failed to report resource data\n");
18081133Stmm	    return 0;
18181133Stmm	}
18282028Sken	outb(_PNP_ADDRESS, PNP_RESOURCE_DATA);
183145553Smux	buffer[i] = inb((rd_port << 2) | 0x3);
18482028Sken	DEB(printf("--- get_resource_info: got 0x%02x\n",(unsigned)buffer[i]));
18581133Stmm    }
18681133Stmm    return 1;
18781133Stmm}
18881133Stmm
18983868Skenvoid
19081133Stmmreport_dma_info (x)
19181133Stmm	int x;
19281133Stmm{
19381133Stmm    char *s1=NULL, *s2=NULL, *s3=NULL, *s4=NULL, *s5=NULL;
19481133Stmm
19539211Sgibbs    switch (x & 0x3) {
19639211Sgibbs    case 0:
19739211Sgibbs	s1="8-bit";
19839211Sgibbs	break;
19939211Sgibbs    case 1:
20039211Sgibbs	s1="8/16-bit";
20139211Sgibbs	break;
20239211Sgibbs    case 2:
20339211Sgibbs	s1="16-bit";
20439498Sken	break;
20581133Stmm#ifdef DIAGNOSTIC
20639211Sgibbs    case 3:
20739211Sgibbs	s1="Reserved";
20839498Sken	break;
20939211Sgibbs#endif
21039498Sken    }
21139211Sgibbs
21239211Sgibbs    s2 = (x & 0x4) ? "bus master" : "not a bus master";
21339211Sgibbs
21439211Sgibbs    s3 = (x & 0x8) ? "count by byte" : "";
21581133Stmm
21681133Stmm    s4 = (x & 0x10) ? "count by word" : "";
21781133Stmm
21881133Stmm    switch ((x & 0x60) >> 5) {
21982028Sken    case 0:
220145553Smux	s5="Compatibility mode";
22181133Stmm	break;
22281133Stmm    case 1:
22381133Stmm	s5="Type A";
22481133Stmm	break;
22581133Stmm    case 2:
22681133Stmm	s5="Type B";
22781133Stmm	break;
22881133Stmm    case 3:
22981133Stmm	s5="Type F";
23039211Sgibbs	break;
23139211Sgibbs    }
23239211Sgibbs    printf("\t%s, %s, %s, %s, %s\n",s1,s2,s3,s4,s5);
23339211Sgibbs}
23439211Sgibbs
23539211Sgibbs
23639211Sgibbsvoid
23739211Sgibbsreport_memory_info (int x)
23839211Sgibbs{
23981133Stmm    if (x & 0x1)
24039211Sgibbs	printf ("Memory Range: Writeable\n");
24139211Sgibbs    else
24239211Sgibbs	printf ("Memory Range: Not writeable (ROM)\n");
24339211Sgibbs
24439211Sgibbs    if (x & 0x2)
24539211Sgibbs	printf ("Memory Range: Read-cacheable, write-through\n");
24639211Sgibbs    else
24739211Sgibbs	printf ("Memory Range: Non-cacheable\n");
24839211Sgibbs
24981133Stmm    if (x & 0x4)
25081133Stmm	printf ("Memory Range: Decode supports high address\n");
25181133Stmm    else
25281133Stmm	printf ("Memory Range: Decode supports range length\n");
25382028Sken
254145553Smux    switch ((x & 0x18) >> 3) {
25581133Stmm    case 0:
25681133Stmm	printf ("Memory Range: 8-bit memory only\n");
25781133Stmm	break;
25881133Stmm    case 1:
25981133Stmm	printf ("Memory Range: 16-bit memory only\n");
26081133Stmm	break;
26181133Stmm    case 2:
26281133Stmm	printf ("Memory Range: 8-bit and 16-bit memory supported\n");
26381133Stmm	break;
26439211Sgibbs#ifdef DIAGNOSTIC
26539211Sgibbs    case 3:
26639211Sgibbs	printf ("Memory Range: Reserved\n");
26739211Sgibbs	break;
26839211Sgibbs#endif
26939211Sgibbs    }
27039211Sgibbs
27139211Sgibbs    if (x & 0x20)
27281133Stmm	printf ("Memory Range: Memory is shadowable\n");
27339211Sgibbs    else
27481984Sbrian	printf ("Memory Range: Memory is not shadowable\n");
27539211Sgibbs
27681133Stmm    if (x & 0x40)
27739451Sken	printf ("Memory Range: Memory is an expansion ROM\n");
27839451Sken    else
27939451Sken	printf ("Memory Range: Memory is not an expansion ROM\n");
28081984Sbrian
28139451Sken#ifdef DIAGNOSTIC
28239451Sken    if (x & 0x80)
28339451Sken	printf ("Memory Range: Reserved (Device is brain-damaged)\n");
28439451Sken#endif
28581984Sbrian}
28639451Sken
28781984Sbrian
28881984Sbrian/*
28939451Sken *  Small Resource Tag Handler
29081984Sbrian *
29182028Sken *  Returns 1 if checksum was valid (and an END_TAG was received).
29282028Sken *  Returns -1 if checksum was invalid (and an END_TAG was received).
29382028Sken *  Returns 0 for other tags.
29482028Sken */
295145553Smuxint
29639211Sgibbshandle_small_res(u_char *resinfo, int item, int len)
29781984Sbrian{
29881984Sbrian    int i;
29939451Sken
30081984Sbrian    DEB(printf("*** ITEM 0x%04x len %d detected\n", item, len));
30182028Sken
30281984Sbrian    switch (item) {
30382028Sken    default:
30482028Sken	printf("*** ITEM 0x%02x detected\n", item);
305145553Smux	break;
30682028Sken    case PNP_TAG_VERSION:
30781984Sbrian	printf("PnP Version %d.%d, Vendor Version %d\n",
30882028Sken	    resinfo[0] >> 4, resinfo[0] & (0xf), resinfo[1]);
30982028Sken	break;
310145553Smux    case PNP_TAG_LOGICAL_DEVICE:
31139211Sgibbs	printf("\nLogical Device ID: %c%c%c%02x%02x 0x%08x #%d\n",
31281984Sbrian		((resinfo[0] & 0x7c) >> 2) + 64,
31381984Sbrian		(((resinfo[0] & 0x03) << 3) |
31439211Sgibbs		((resinfo[1] & 0xe0) >> 5)) + 64,
31539211Sgibbs		(resinfo[1] & 0x1f) + 64,
31639211Sgibbs		resinfo[2], resinfo[3], *(int *)(resinfo),
31739211Sgibbs		logdevs++);
31839211Sgibbs
31939211Sgibbs	if (resinfo[4] & 0x1)
32039211Sgibbs	    printf ("\tDevice powers up active\n"); /* XXX */
32139211Sgibbs	if (resinfo[4] & 0x2)
32239211Sgibbs	    printf ("\tDevice supports I/O Range Check\n");
32339211Sgibbs	if (resinfo[4] > 0x3)
32439211Sgibbs	    printf ("\tReserved register funcs %02x\n",
32539211Sgibbs		resinfo[4]);
32639211Sgibbs
32739211Sgibbs	if (len == 6)
32839211Sgibbs	    printf("\tVendor register funcs %02x\n", resinfo[5]);
32939211Sgibbs	break;
33039211Sgibbs    case PNP_TAG_COMPAT_DEVICE:
33181133Stmm	printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n",
33239211Sgibbs		((resinfo[0] & 0x7c) >> 2) + 64,
33339211Sgibbs		(((resinfo[0] & 0x03) << 3) |
33439211Sgibbs		((resinfo[1] & 0xe0) >> 5)) + 64,
33539498Sken		(resinfo[1] & 0x1f) + 64,
33639498Sken		resinfo[2], resinfo[3], *(int *)resinfo);
33739211Sgibbs	break;
33839211Sgibbs    case PNP_TAG_IRQ_FORMAT:
339112288Sphk	printf("    IRQ: ");
34039211Sgibbs
34139211Sgibbs	for (i = 0; i < 8; i++)
34239211Sgibbs	    if (resinfo[0] & (1<<i))
34339211Sgibbs		printf("%d ", i);
34481133Stmm	for (i = 0; i < 8; i++)
345145553Smux	    if (resinfo[1] & (1<<i))
34639211Sgibbs		printf("%d ", i + 8);
34739211Sgibbs	if (len == 3) {
34839211Sgibbs	    if (resinfo[2] & 0x1)
34939211Sgibbs		printf("IRQ: High true edge sensitive\n");
35039211Sgibbs	    if (resinfo[2] & 0x2)
35139211Sgibbs		printf("IRQ: Low true edge sensitive\n");
352112288Sphk	    if (resinfo[2] & 0x4)
353112288Sphk		printf("IRQ: High true level sensitive\n");
35439211Sgibbs	    if (resinfo[2] & 0x8)
35581133Stmm		printf("IRQ: Low true level sensitive\n");
35681133Stmm	} else {
35781133Stmm	    printf(" - only one type (true/edge)\n");
35839211Sgibbs	}
35981133Stmm	break;
36081133Stmm    case PNP_TAG_DMA_FORMAT:
36181133Stmm	printf("    DMA: channel(s) ");
36239211Sgibbs	for (i = 0; i < 8; i++)
363112293Sphk	    if (resinfo[0] & (1<<i))
36439211Sgibbs		printf("%d ", i);
36581133Stmm	printf ("\n");
36681133Stmm	report_dma_info (resinfo[1]);
36781133Stmm	break;
36881133Stmm    case PNP_TAG_START_DEPENDANT:
36981133Stmm	printf("TAG Start DF\n");
37081133Stmm	if (len == 1) {
37181133Stmm	    switch (resinfo[0]) {
37281133Stmm	    case 0:
37381133Stmm		printf("Good Configuration\n");
374229735Sghelmer		break;
375229735Sghelmer	    case 1:
376229735Sghelmer		printf("Acceptable Configuration\n");
377229735Sghelmer		break;
378229735Sghelmer	    case 2:
379229735Sghelmer		printf("Sub-optimal Configuration\n");
38081133Stmm		break;
38181133Stmm	    }
38281133Stmm	}
38339211Sgibbs	break;
38481133Stmm    case PNP_TAG_END_DEPENDANT:
38581133Stmm	printf("TAG End DF\n");
38681133Stmm	break;
38781133Stmm    case PNP_TAG_IO_RANGE:
38881133Stmm	printf("    I/O Range 0x%x .. 0x%x, alignment 0x%x, len 0x%x\n",
38981133Stmm	    resinfo[1] + (resinfo[2] << 8),
39081133Stmm	    resinfo[3] + (resinfo[4] << 8),
39181133Stmm	    resinfo[5], resinfo[6] );
392112373Sphk	if (resinfo[0])
393112373Sphk	    printf("\t[16-bit addr]\n");
394112373Sphk	else
395112373Sphk	    printf("\t[not 16-bit addr]\n");
396112373Sphk	break;
397112373Sphk    case PNP_TAG_IO_FIXED:
398112373Sphk	printf ("    FIXED I/O base address 0x%x length 0x%x\n",
399112373Sphk	    resinfo[0] + ( (resinfo[1] & 3 ) << 8), /* XXX */
40081133Stmm	    resinfo[2]);
40181133Stmm	break;
40281133Stmm#ifdef DIAGNOSTIC
40381133Stmm    case PNP_TAG_RESERVED:
40481133Stmm	printf("Reserved Tag Detected\n");
40581133Stmm	break;
40681133Stmm#endif
40781133Stmm    case PNP_TAG_VENDOR:
408112288Sphk	printf("*** Small Vendor Tag Detected\n");
40981133Stmm	break;
410112293Sphk    case PNP_TAG_END:
41181133Stmm	printf("End Tag\n\n");
41281133Stmm	/* XXX Record and Verify Checksum */
41381133Stmm	return 1;
41481133Stmm	break;
41581133Stmm    }
41681133Stmm    return 0;
41781133Stmm}
41881133Stmm
41981133Stmm
42082028Skenvoid
42182028Skenhandle_large_res(u_char *resinfo, int item, int len)
422145553Smux{
423145553Smux    int i;
42481133Stmm
42581133Stmm    DEB(printf("*** Large ITEM %d len %d found\n", item, len));
42681133Stmm    switch (item) {
42781133Stmm    case PNP_TAG_MEMORY_RANGE:
42882028Sken	report_memory_info(resinfo[0]);
429145553Smux	printf("Memory range minimum address: 0x%x\n",
43082028Sken		(resinfo[1] << 8) + (resinfo[2] << 16));
43139211Sgibbs	printf("Memory range maximum address: 0x%x\n",
43239211Sgibbs		(resinfo[3] << 8) + (resinfo[4] << 16));
43381133Stmm	printf("Memory range base alignment: 0x%x\n",
43481133Stmm		(i = (resinfo[5] + (resinfo[6] << 8))) ? i : (1 << 16));
43581133Stmm	printf("Memory range length: 0x%x\n",
43681133Stmm		(resinfo[7] + (resinfo[8] << 8)) * 256);
43781133Stmm	break;
43881133Stmm    case PNP_TAG_ID_ANSI:
43981133Stmm	printf("Device Description: ");
440112293Sphk
44139211Sgibbs	for (i = 0; i < len; i++) {
442145549Smux	    if (resinfo[i]) /* XXX */
44381133Stmm		printf("%c", resinfo[i]);
44481133Stmm	}
44539211Sgibbs	printf("\n");
44639211Sgibbs	break;
44739211Sgibbs    case PNP_TAG_ID_UNICODE:
44839211Sgibbs	printf("ID String Unicode Detected (Undefined)\n");
44939498Sken	break;
45039211Sgibbs    case PNP_TAG_LARGE_VENDOR:
45139211Sgibbs	printf("Large Vendor Defined Detected\n");
45239211Sgibbs	break;
45339211Sgibbs    case PNP_TAG_MEMORY32_RANGE:
45439211Sgibbs	printf("32bit Memory Range Desc Unimplemented\n");
45539211Sgibbs	break;
45639211Sgibbs    case PNP_TAG_MEMORY32_FIXED:
45739211Sgibbs	printf("32bit Fixed Location Desc Unimplemented\n");
45839211Sgibbs	break;
45939211Sgibbs#ifdef DIAGNOSTIC
46039211Sgibbs    case PNP_TAG_LARGE_RESERVED:
46139211Sgibbs	printf("Large Reserved Tag Detected\n");
46239211Sgibbs	break;
46339211Sgibbs#endif
46439211Sgibbs    }
46539211Sgibbs}
46639211Sgibbs
467112293Sphk
468112293Sphk/*
46939211Sgibbs * Dump all the information about configurations.
47039211Sgibbs */
47139498Skenvoid
47239211Sgibbsdump_resdata(u_char *data, int csn)
47339211Sgibbs{
47439211Sgibbs    int i, large_len;
47539211Sgibbs
47639211Sgibbs    u_char tag, *resinfo;
47739211Sgibbs
47839498Sken    DDB(printf("\nCard assigned CSN #%d\n", csn));
47939211Sgibbs    printf("Vendor ID %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n",
48039211Sgibbs	    ((data[0] & 0x7c) >> 2) + 64,
48139211Sgibbs	    (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64,
48239211Sgibbs	    (data[1] & 0x1f) + 64, data[2], data[3],
48339211Sgibbs	    *(int *)&(data[0]),
48439211Sgibbs	    *(int *)&(data[4]));
48539211Sgibbs
48639211Sgibbs    pnp_write(PNP_SET_CSN, csn); /* Move this out of this function XXX */
48739211Sgibbs    outb(_PNP_ADDRESS, PNP_STATUS);
48839211Sgibbs
48939211Sgibbs    /* Allows up to 1kb of Resource Info,  Should be plenty */
49039211Sgibbs    for (i = 0; i < 1024; i++) {
49139211Sgibbs	if (!get_resource_info(&tag, 1))
49239211Sgibbs	    break;
49339211Sgibbs
49439211Sgibbs	if (PNP_RES_TYPE(tag) == 0) {
49539211Sgibbs	    /* Handle small resouce data types */
49639211Sgibbs
49739211Sgibbs	    resinfo = malloc(PNP_SRES_LEN(tag));
49839211Sgibbs	    if (!get_resource_info(resinfo, PNP_SRES_LEN(tag)))
49939211Sgibbs		break;
50039211Sgibbs
50139211Sgibbs	    if (handle_small_res(resinfo, PNP_SRES_NUM(tag), PNP_SRES_LEN(tag)) == 1)
50239211Sgibbs		break;
50339211Sgibbs	    free(resinfo);
50439211Sgibbs	} else {
50539211Sgibbs	    /* Handle large resouce data types */
50639211Sgibbs	    u_char buf[2];
50739211Sgibbs	    if (!get_resource_info((char *)buf, 2))
50839211Sgibbs		break;
50939211Sgibbs	    large_len = (buf[1] << 8) + buf[0];
51039211Sgibbs
51139211Sgibbs	    resinfo = malloc(large_len);
51239211Sgibbs	    if (!get_resource_info(resinfo, large_len))
51339211Sgibbs		break;
51439211Sgibbs
51539211Sgibbs	    handle_large_res(resinfo, PNP_LRES_NUM(tag), large_len);
51639211Sgibbs	    free(resinfo);
51739211Sgibbs	}
51839211Sgibbs    }
51939211Sgibbs    printf("Successfully got %d resources, %d logical fdevs\n", i,
52039211Sgibbs	    logdevs);
52139211Sgibbs    printf("-- card select # 0x%04x\n", pnp_read(PNP_SET_CSN));
52239211Sgibbs    printf("\nCSN %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n",
52339211Sgibbs	    ((data[0] & 0x7c) >> 2) + 64,
52439211Sgibbs	    (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64,
52539211Sgibbs	    (data[1] & 0x1f) + 64, data[2], data[3],
52639211Sgibbs	    *(int *)&(data[0]),
52739211Sgibbs	    *(int *)&(data[4]));
52839211Sgibbs
52939211Sgibbs    for (i=0; i<logdevs; i++) {
53039211Sgibbs	int j;
53139211Sgibbs
53239211Sgibbs	pnp_write(PNP_SET_LDN, i);
53339211Sgibbs
53439211Sgibbs	printf("\nLogical device #%d\n", pnp_read(PNP_SET_LDN) );
53539211Sgibbs	printf("IO: ");
53639211Sgibbs	for (j=0; j<8; j++)
53739211Sgibbs	    printf(" 0x%02x%02x", pnp_read(PNP_IO_BASE_HIGH(j)),
53839211Sgibbs		pnp_read(PNP_IO_BASE_LOW(j)));
53939211Sgibbs	printf("\nIRQ %d %d\n",
54039211Sgibbs	    pnp_read(PNP_IRQ_LEVEL(0)), pnp_read(PNP_IRQ_LEVEL(1)) );
54139211Sgibbs	printf("DMA %d %d\n",
54239211Sgibbs	    pnp_read(PNP_DMA_CHANNEL(0)), pnp_read(PNP_DMA_CHANNEL(1)) );
54339211Sgibbs	printf("IO range check 0x%02x activate 0x%02x\n",
54439211Sgibbs	    pnp_read(PNP_IO_RANGE_CHECK), pnp_read(PNP_ACTIVATE) );
54581133Stmm    }
54681133Stmm}
54781133Stmm
54881133Stmm
54981133Stmm/*
55081133Stmm * Run the isolation protocol. Use rd_port as the READ_DATA port
55181133Stmm * value (caller should try multiple READ_DATA locations before giving
55239211Sgibbs * up). Upon exiting, all cards are aware that they should use rd_port
55392913Sobrien * as the READ_DATA port;
55439211Sgibbs *
55539211Sgibbs */
55639211Sgibbsint
55739211Sgibbsisolation_protocol()
55839211Sgibbs{
55939211Sgibbs    int csn;
560119029Sphk    u_char data[9];
56139211Sgibbs
56239211Sgibbs    send_Initiation_LFSR();
56339211Sgibbs
56439211Sgibbs    /* Reset CSN for All Cards */
56539211Sgibbs    pnp_write(PNP_CONFIG_CONTROL, 0x04);
56639211Sgibbs
56739211Sgibbs    for (csn = 1; (csn < PNP_MAX_CARDS); csn++) {
56839211Sgibbs	/* Wake up cards without a CSN */
56939211Sgibbs	logdevs = 0 ;
57039211Sgibbs	pnp_write(PNP_WAKE, 0);
57139211Sgibbs	pnp_write(PNP_SET_RD_DATA, rd_port);
57239211Sgibbs	outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION);
57339211Sgibbs	DELAY(1000);	/* Delay 1 msec */
57439211Sgibbs
57539211Sgibbs	if (get_serial(data))
57639211Sgibbs	    dump_resdata(data, csn);
57739211Sgibbs	else
57839211Sgibbs	    break;
57939211Sgibbs    }
58039211Sgibbs    return csn - 1;
58139211Sgibbs}
582229735Sghelmer
58339211Sgibbs
58439211Sgibbsint
58539211Sgibbsmain(int argc, char **argv)
58639211Sgibbs{
58739211Sgibbs    int num_pnp_devs;
58839211Sgibbs
58939211Sgibbs#ifdef __i386__
59039211Sgibbs    /* Hey what about a i386_iopl() call :) */
59139211Sgibbs    if (open("/dev/io", O_RDONLY) < 0) {
59239211Sgibbs	fprintf (stderr, "pnpinfo: Can't get I/O privilege.\n");
59339211Sgibbs	exit (1);
59439211Sgibbs    }
59539211Sgibbs#endif
596229735Sghelmer#ifdef __alpha__
597229735Sghelmer    ioperm(0x203, 0x400 - 0x203, 1);
598229735Sghelmer#endif
599229735Sghelmer
600229735Sghelmer    printf("Checking for Plug-n-Play devices...\n");
601229735Sghelmer
602229735Sghelmer    /* Try various READ_DATA ports from 0x203-0x3ff */
60339211Sgibbs    for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) {
60439211Sgibbs	DEB(printf("Trying Read_Port at %x...\n", (rd_port << 2) | 0x3) );
60539211Sgibbs	num_pnp_devs = isolation_protocol(rd_port);
60639211Sgibbs	if (num_pnp_devs)
60739211Sgibbs	    break;
60839211Sgibbs    }
60939211Sgibbs    if (!num_pnp_devs) {
61039211Sgibbs	printf("No Plug-n-Play devices were found\n");
61139211Sgibbs	return 0;
61239211Sgibbs    }
61339211Sgibbs}
61439211Sgibbs