129615Sjmg/*
229615Sjmg * Copyright (c) 1996, Sujal M. Patel
329615Sjmg * All rights reserved.
429615Sjmg *
529615Sjmg * Redistribution and use in source and binary forms, with or without
629615Sjmg * modification, are permitted provided that the following conditions
729615Sjmg * are met:
829615Sjmg * 1. Redistributions of source code must retain the above copyright
929615Sjmg *    notice, this list of conditions and the following disclaimer.
1029615Sjmg * 2. Redistributions in binary form must reproduce the above copyright
1129615Sjmg *    notice, this list of conditions and the following disclaimer in the
1229615Sjmg *    documentation and/or other materials provided with the distribution.
1329615Sjmg *
1429615Sjmg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1529615Sjmg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1629615Sjmg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1729615Sjmg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1829615Sjmg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1929615Sjmg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2029615Sjmg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2129615Sjmg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2229615Sjmg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2329615Sjmg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2429615Sjmg * SUCH DAMAGE.
2529615Sjmg */
2629615Sjmg
27124125Scharnier#include <sys/cdefs.h>
28124125Scharnier__FBSDID("$FreeBSD$");
29124125Scharnier
3029615Sjmg#include <sys/time.h>
3129615Sjmg
32124125Scharnier#include <err.h>
3329615Sjmg#include <stdio.h>
3429615Sjmg#include <stdlib.h>
3529615Sjmg#include <unistd.h>
3629615Sjmg#include <fcntl.h>
3729615Sjmg#include <string.h>
3829615Sjmg
3929615Sjmg#include <machine/cpufunc.h>
4029615Sjmg
4150786Speter#include <isa/pnpreg.h>
4229615Sjmg
4329615Sjmg#ifdef DEBUG
4429615Sjmg#define	DEB(x) x
4529615Sjmg#else
4629615Sjmg#define DEB(x)
4729615Sjmg#endif
4829615Sjmg#define DDB(x) x
4929615Sjmg
5029615Sjmgvoid
5129615Sjmgpnp_write(int d, u_char r)
5229615Sjmg{
5329615Sjmg    outb (_PNP_ADDRESS, d);
5429615Sjmg    outb (_PNP_WRITE_DATA, r);
5529615Sjmg}
5639144Seivind
5729615Sjmg/* The READ_DATA port that we are using currently */
5829615Sjmgstatic int rd_port;
5929615Sjmg
6029615Sjmgu_char
6129615Sjmgpnp_read(int d)
6229615Sjmg{
6329615Sjmg    outb(_PNP_ADDRESS, d);
6429615Sjmg    return inb( (rd_port << 2) + 3) & 0xff;
6529615Sjmg}
6629615Sjmg
6731135Sjmgu_short
6829615Sjmgpnp_readw(int d)
6929615Sjmg{
7029615Sjmg    int c = pnp_read(d) << 8 ;
7129615Sjmg    c |= pnp_read(d+1);
7229615Sjmg    return c;
7329615Sjmg}
7429615Sjmg
7529615Sjmgint logdevs=0;
7629615Sjmg
7729615Sjmgvoid DELAY __P((int i));
7829615Sjmgvoid send_Initiation_LFSR();
7929615Sjmgint get_serial __P((u_char *data));
8029615Sjmgint get_resource_info __P((u_char *buffer, int len));
8129615Sjmgint handle_small_res __P((u_char *resinfo, int item, int len));
8229615Sjmgvoid handle_large_res __P((u_char *resinfo, int item, int len));
8329615Sjmgvoid dump_resdata __P((u_char *data, int csn));
8429615Sjmgint isolation_protocol();
8529615Sjmg
8629615Sjmg
8729615Sjmg/*
8829615Sjmg * DELAY does accurate delaying in user-space.
8929615Sjmg * This function busy-waits.
9029615Sjmg */
9129615Sjmgvoid
9229615SjmgDELAY (int i)
9329615Sjmg{
9429615Sjmg    struct timeval t;
9529615Sjmg    long start, stop;
9629615Sjmg
9729615Sjmg    i *= 4;
9829615Sjmg
9929615Sjmg    gettimeofday (&t, NULL);
10029615Sjmg    start = t.tv_sec * 1000000 + t.tv_usec;
10129615Sjmg    do {
10229615Sjmg	gettimeofday (&t, NULL);
10329615Sjmg	stop = t.tv_sec * 1000000 + t.tv_usec;
10429615Sjmg    } while (start + i > stop);
10529615Sjmg}
10629615Sjmg
10729615Sjmg
10829615Sjmg/*
10929615Sjmg * Send Initiation LFSR as described in "Plug and Play ISA Specification,
11029615Sjmg * Intel May 94."
11129615Sjmg */
11229615Sjmgvoid
11329615Sjmgsend_Initiation_LFSR()
11429615Sjmg{
11529615Sjmg    int cur, i;
11629615Sjmg
11750786Speter    pnp_write(PNP_CONFIG_CONTROL, 0x2);
11829615Sjmg
11929615Sjmg    /* Reset the LSFR */
12029615Sjmg    outb(_PNP_ADDRESS, 0);
12129615Sjmg    outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */
12229615Sjmg
12329615Sjmg    cur = 0x6a;
12429615Sjmg
12529615Sjmg    for (i = 0; i < 32; i++) {
12629615Sjmg	outb(_PNP_ADDRESS, cur);
12729615Sjmg	cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
12829615Sjmg    }
12929615Sjmg}
13029615Sjmg
13129615Sjmg/*
13229615Sjmg * Get the device's serial number.  Returns 1 if the serial is valid.
13329615Sjmg */
13429615Sjmgint
13529615Sjmgget_serial(u_char *data)
13629615Sjmg{
13729615Sjmg    int i, bit, valid = 0, sum = 0x6a;
13829615Sjmg
13929615Sjmg    bzero(data, sizeof(char) * 9);
14029615Sjmg
14129615Sjmg    for (i = 0; i < 72; i++) {
14229615Sjmg	bit = inb((rd_port << 2) | 0x3) == 0x55;
14329615Sjmg	DELAY(250);	/* Delay 250 usec */
14429615Sjmg
14529615Sjmg	/* Can't Short Circuit the next evaluation, so 'and' is last */
14629615Sjmg	bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit;
14729615Sjmg	DELAY(250);	/* Delay 250 usec */
14829615Sjmg
14929615Sjmg	valid = valid || bit;
15029615Sjmg
15129615Sjmg	if (i < 64)
15229615Sjmg	    sum = (sum >> 1) |
15329615Sjmg		(((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
15429615Sjmg
15529615Sjmg	data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
15629615Sjmg    }
15729615Sjmg
15829615Sjmg    valid = valid && (data[8] == sum);
15929615Sjmg
16029615Sjmg    return valid;
16129615Sjmg}
16229615Sjmg
16329615Sjmg
16429615Sjmg/*
16529615Sjmg * Fill's the buffer with resource info from the device.
16629615Sjmg * Returns 0 if the device fails to report
16729615Sjmg */
16829615Sjmgint
16929615Sjmgget_resource_info(u_char *buffer, int len)
17029615Sjmg{
17129615Sjmg    int i, j;
17229615Sjmg
17329615Sjmg    for (i = 0; i < len; i++) {
17450786Speter	outb(_PNP_ADDRESS, PNP_STATUS);
17529615Sjmg	for (j = 0; j < 100; j++) {
17629615Sjmg	    if ((inb((rd_port << 2) | 0x3)) & 0x1)
17729615Sjmg		break;
17829615Sjmg	    DELAY(1);
17929615Sjmg	}
18029615Sjmg	if (j == 100) {
18129615Sjmg	    printf("PnP device failed to report resource data\n");
18229615Sjmg	    return 0;
18329615Sjmg	}
18450786Speter	outb(_PNP_ADDRESS, PNP_RESOURCE_DATA);
18529615Sjmg	buffer[i] = inb((rd_port << 2) | 0x3);
18629615Sjmg	DEB(printf("--- get_resource_info: got 0x%02x\n",(unsigned)buffer[i]));
18729615Sjmg    }
18829615Sjmg    return 1;
18929615Sjmg}
19029615Sjmg
19129615Sjmgvoid
19229615Sjmgreport_dma_info (x)
19329615Sjmg	int x;
19429615Sjmg{
19529615Sjmg    char *s1=NULL, *s2=NULL, *s3=NULL, *s4=NULL, *s5=NULL;
19629615Sjmg
19729615Sjmg    switch (x & 0x3) {
19829615Sjmg    case 0:
19929615Sjmg	s1="8-bit";
20029615Sjmg	break;
20129615Sjmg    case 1:
20229615Sjmg	s1="8/16-bit";
20329615Sjmg	break;
20429615Sjmg    case 2:
20529615Sjmg	s1="16-bit";
20629615Sjmg	break;
20729615Sjmg#ifdef DIAGNOSTIC
20829615Sjmg    case 3:
20929615Sjmg	s1="Reserved";
21029615Sjmg	break;
21129615Sjmg#endif
21229615Sjmg    }
21329615Sjmg
21429615Sjmg    s2 = (x & 0x4) ? "bus master" : "not a bus master";
21529615Sjmg
21629615Sjmg    s3 = (x & 0x8) ? "count by byte" : "";
21729615Sjmg
21829615Sjmg    s4 = (x & 0x10) ? "count by word" : "";
21929615Sjmg
22029615Sjmg    switch ((x & 0x60) >> 5) {
22129615Sjmg    case 0:
22229615Sjmg	s5="Compatibility mode";
22329615Sjmg	break;
22429615Sjmg    case 1:
22529615Sjmg	s5="Type A";
22629615Sjmg	break;
22729615Sjmg    case 2:
22829615Sjmg	s5="Type B";
22929615Sjmg	break;
23029615Sjmg    case 3:
23129615Sjmg	s5="Type F";
23229615Sjmg	break;
23329615Sjmg    }
23429615Sjmg    printf("\t%s, %s, %s, %s, %s\n",s1,s2,s3,s4,s5);
23529615Sjmg}
23629615Sjmg
23729615Sjmg
23829615Sjmgvoid
23929615Sjmgreport_memory_info (int x)
24029615Sjmg{
24129615Sjmg    if (x & 0x1)
24229615Sjmg	printf ("Memory Range: Writeable\n");
24329615Sjmg    else
24429615Sjmg	printf ("Memory Range: Not writeable (ROM)\n");
24529615Sjmg
24629615Sjmg    if (x & 0x2)
24729615Sjmg	printf ("Memory Range: Read-cacheable, write-through\n");
24829615Sjmg    else
24929615Sjmg	printf ("Memory Range: Non-cacheable\n");
25029615Sjmg
25129615Sjmg    if (x & 0x4)
25229615Sjmg	printf ("Memory Range: Decode supports high address\n");
25329615Sjmg    else
25429615Sjmg	printf ("Memory Range: Decode supports range length\n");
25529615Sjmg
25629615Sjmg    switch ((x & 0x18) >> 3) {
25729615Sjmg    case 0:
25829615Sjmg	printf ("Memory Range: 8-bit memory only\n");
25929615Sjmg	break;
26029615Sjmg    case 1:
26129615Sjmg	printf ("Memory Range: 16-bit memory only\n");
26229615Sjmg	break;
26329615Sjmg    case 2:
26429615Sjmg	printf ("Memory Range: 8-bit and 16-bit memory supported\n");
26529615Sjmg	break;
26629615Sjmg#ifdef DIAGNOSTIC
26729615Sjmg    case 3:
26829615Sjmg	printf ("Memory Range: Reserved\n");
26929615Sjmg	break;
27029615Sjmg#endif
27129615Sjmg    }
27229615Sjmg
27329615Sjmg    if (x & 0x20)
27429615Sjmg	printf ("Memory Range: Memory is shadowable\n");
27529615Sjmg    else
27629615Sjmg	printf ("Memory Range: Memory is not shadowable\n");
27729615Sjmg
27829615Sjmg    if (x & 0x40)
27929615Sjmg	printf ("Memory Range: Memory is an expansion ROM\n");
28029615Sjmg    else
28129615Sjmg	printf ("Memory Range: Memory is not an expansion ROM\n");
28229615Sjmg
28329615Sjmg#ifdef DIAGNOSTIC
28429615Sjmg    if (x & 0x80)
28529615Sjmg	printf ("Memory Range: Reserved (Device is brain-damaged)\n");
28629615Sjmg#endif
28729615Sjmg}
28829615Sjmg
28929615Sjmg
29029615Sjmg/*
29129615Sjmg *  Small Resource Tag Handler
29229615Sjmg *
29329615Sjmg *  Returns 1 if checksum was valid (and an END_TAG was received).
29429615Sjmg *  Returns -1 if checksum was invalid (and an END_TAG was received).
29529615Sjmg *  Returns 0 for other tags.
29629615Sjmg */
29729615Sjmgint
29829615Sjmghandle_small_res(u_char *resinfo, int item, int len)
29929615Sjmg{
30029615Sjmg    int i;
30129615Sjmg
30229615Sjmg    DEB(printf("*** ITEM 0x%04x len %d detected\n", item, len));
30329615Sjmg
30429615Sjmg    switch (item) {
30529615Sjmg    default:
30629615Sjmg	printf("*** ITEM 0x%02x detected\n", item);
30729615Sjmg	break;
30850786Speter    case PNP_TAG_VERSION:
30929615Sjmg	printf("PnP Version %d.%d, Vendor Version %d\n",
31029615Sjmg	    resinfo[0] >> 4, resinfo[0] & (0xf), resinfo[1]);
31129615Sjmg	break;
31250786Speter    case PNP_TAG_LOGICAL_DEVICE:
31329615Sjmg	printf("\nLogical Device ID: %c%c%c%02x%02x 0x%08x #%d\n",
31429615Sjmg		((resinfo[0] & 0x7c) >> 2) + 64,
31529615Sjmg		(((resinfo[0] & 0x03) << 3) |
31629615Sjmg		((resinfo[1] & 0xe0) >> 5)) + 64,
31729615Sjmg		(resinfo[1] & 0x1f) + 64,
31829615Sjmg		resinfo[2], resinfo[3], *(int *)(resinfo),
31929615Sjmg		logdevs++);
32029615Sjmg
32129615Sjmg	if (resinfo[4] & 0x1)
32229615Sjmg	    printf ("\tDevice powers up active\n"); /* XXX */
32329615Sjmg	if (resinfo[4] & 0x2)
32429615Sjmg	    printf ("\tDevice supports I/O Range Check\n");
32529615Sjmg	if (resinfo[4] > 0x3)
32629615Sjmg	    printf ("\tReserved register funcs %02x\n",
32729615Sjmg		resinfo[4]);
32829615Sjmg
32929615Sjmg	if (len == 6)
33029615Sjmg	    printf("\tVendor register funcs %02x\n", resinfo[5]);
33129615Sjmg	break;
33250786Speter    case PNP_TAG_COMPAT_DEVICE:
33329615Sjmg	printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n",
33429615Sjmg		((resinfo[0] & 0x7c) >> 2) + 64,
33529615Sjmg		(((resinfo[0] & 0x03) << 3) |
33629615Sjmg		((resinfo[1] & 0xe0) >> 5)) + 64,
33729615Sjmg		(resinfo[1] & 0x1f) + 64,
33829615Sjmg		resinfo[2], resinfo[3], *(int *)resinfo);
33929615Sjmg	break;
34050786Speter    case PNP_TAG_IRQ_FORMAT:
34129615Sjmg	printf("    IRQ: ");
34229615Sjmg
34329615Sjmg	for (i = 0; i < 8; i++)
34429615Sjmg	    if (resinfo[0] & (1<<i))
34529615Sjmg		printf("%d ", i);
34629615Sjmg	for (i = 0; i < 8; i++)
34729615Sjmg	    if (resinfo[1] & (1<<i))
34829615Sjmg		printf("%d ", i + 8);
34929615Sjmg	if (len == 3) {
35029615Sjmg	    if (resinfo[2] & 0x1)
35129615Sjmg		printf("IRQ: High true edge sensitive\n");
35229615Sjmg	    if (resinfo[2] & 0x2)
35329615Sjmg		printf("IRQ: Low true edge sensitive\n");
35429615Sjmg	    if (resinfo[2] & 0x4)
35529615Sjmg		printf("IRQ: High true level sensitive\n");
35629615Sjmg	    if (resinfo[2] & 0x8)
35729615Sjmg		printf("IRQ: Low true level sensitive\n");
35829615Sjmg	} else {
35929615Sjmg	    printf(" - only one type (true/edge)\n");
36029615Sjmg	}
36129615Sjmg	break;
36250786Speter    case PNP_TAG_DMA_FORMAT:
36329615Sjmg	printf("    DMA: channel(s) ");
36429615Sjmg	for (i = 0; i < 8; i++)
36529615Sjmg	    if (resinfo[0] & (1<<i))
36629615Sjmg		printf("%d ", i);
36729615Sjmg	printf ("\n");
36829615Sjmg	report_dma_info (resinfo[1]);
36929615Sjmg	break;
37050786Speter    case PNP_TAG_START_DEPENDANT:
37129615Sjmg	printf("TAG Start DF\n");
37229615Sjmg	if (len == 1) {
37329615Sjmg	    switch (resinfo[0]) {
37429615Sjmg	    case 0:
37529615Sjmg		printf("Good Configuration\n");
37629615Sjmg		break;
37729615Sjmg	    case 1:
37829615Sjmg		printf("Acceptable Configuration\n");
37929615Sjmg		break;
38029615Sjmg	    case 2:
38129615Sjmg		printf("Sub-optimal Configuration\n");
38229615Sjmg		break;
38329615Sjmg	    }
38429615Sjmg	}
38529615Sjmg	break;
38650786Speter    case PNP_TAG_END_DEPENDANT:
38729615Sjmg	printf("TAG End DF\n");
38829615Sjmg	break;
38950786Speter    case PNP_TAG_IO_RANGE:
39029615Sjmg	printf("    I/O Range 0x%x .. 0x%x, alignment 0x%x, len 0x%x\n",
39129615Sjmg	    resinfo[1] + (resinfo[2] << 8),
39229615Sjmg	    resinfo[3] + (resinfo[4] << 8),
39329615Sjmg	    resinfo[5], resinfo[6] );
39429615Sjmg	if (resinfo[0])
39529615Sjmg	    printf("\t[16-bit addr]\n");
39629615Sjmg	else
39729615Sjmg	    printf("\t[not 16-bit addr]\n");
39829615Sjmg	break;
39950786Speter    case PNP_TAG_IO_FIXED:
40029615Sjmg	printf ("    FIXED I/O base address 0x%x length 0x%x\n",
40129615Sjmg	    resinfo[0] + ( (resinfo[1] & 3 ) << 8), /* XXX */
40229615Sjmg	    resinfo[2]);
40329615Sjmg	break;
40429615Sjmg#ifdef DIAGNOSTIC
40550786Speter    case PNP_TAG_RESERVED:
40629615Sjmg	printf("Reserved Tag Detected\n");
40729615Sjmg	break;
40829615Sjmg#endif
40950786Speter    case PNP_TAG_VENDOR:
41029615Sjmg	printf("*** Small Vendor Tag Detected\n");
41129615Sjmg	break;
41250786Speter    case PNP_TAG_END:
41329615Sjmg	printf("End Tag\n\n");
41429615Sjmg	/* XXX Record and Verify Checksum */
41529615Sjmg	return 1;
41629615Sjmg	break;
41729615Sjmg    }
41829615Sjmg    return 0;
41929615Sjmg}
42029615Sjmg
42129615Sjmg
42229615Sjmgvoid
42329615Sjmghandle_large_res(u_char *resinfo, int item, int len)
42429615Sjmg{
42529615Sjmg    int i;
42629615Sjmg
42729615Sjmg    DEB(printf("*** Large ITEM %d len %d found\n", item, len));
42829615Sjmg    switch (item) {
42950786Speter    case PNP_TAG_MEMORY_RANGE:
43029615Sjmg	report_memory_info(resinfo[0]);
43129615Sjmg	printf("Memory range minimum address: 0x%x\n",
43229615Sjmg		(resinfo[1] << 8) + (resinfo[2] << 16));
43329615Sjmg	printf("Memory range maximum address: 0x%x\n",
43429615Sjmg		(resinfo[3] << 8) + (resinfo[4] << 16));
43529615Sjmg	printf("Memory range base alignment: 0x%x\n",
43629615Sjmg		(i = (resinfo[5] + (resinfo[6] << 8))) ? i : (1 << 16));
43729615Sjmg	printf("Memory range length: 0x%x\n",
43829615Sjmg		(resinfo[7] + (resinfo[8] << 8)) * 256);
43929615Sjmg	break;
44050786Speter    case PNP_TAG_ID_ANSI:
44129615Sjmg	printf("Device Description: ");
44229615Sjmg
44329615Sjmg	for (i = 0; i < len; i++) {
44429615Sjmg	    if (resinfo[i]) /* XXX */
44529615Sjmg		printf("%c", resinfo[i]);
44629615Sjmg	}
44729615Sjmg	printf("\n");
44829615Sjmg	break;
44950786Speter    case PNP_TAG_ID_UNICODE:
45029615Sjmg	printf("ID String Unicode Detected (Undefined)\n");
45129615Sjmg	break;
45250786Speter    case PNP_TAG_LARGE_VENDOR:
45329615Sjmg	printf("Large Vendor Defined Detected\n");
45429615Sjmg	break;
45550786Speter    case PNP_TAG_MEMORY32_RANGE:
45629615Sjmg	printf("32bit Memory Range Desc Unimplemented\n");
45729615Sjmg	break;
45850786Speter    case PNP_TAG_MEMORY32_FIXED:
45929615Sjmg	printf("32bit Fixed Location Desc Unimplemented\n");
46029615Sjmg	break;
46150786Speter#ifdef DIAGNOSTIC
46250786Speter    case PNP_TAG_LARGE_RESERVED:
46329615Sjmg	printf("Large Reserved Tag Detected\n");
46429615Sjmg	break;
46550786Speter#endif
46629615Sjmg    }
46729615Sjmg}
46829615Sjmg
46929615Sjmg
47029615Sjmg/*
47129615Sjmg * Dump all the information about configurations.
47229615Sjmg */
47329615Sjmgvoid
47429615Sjmgdump_resdata(u_char *data, int csn)
47529615Sjmg{
47629615Sjmg    int i, large_len;
47729615Sjmg
47829615Sjmg    u_char tag, *resinfo;
47929615Sjmg
48029615Sjmg    DDB(printf("\nCard assigned CSN #%d\n", csn));
48129615Sjmg    printf("Vendor ID %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n",
48229615Sjmg	    ((data[0] & 0x7c) >> 2) + 64,
48329615Sjmg	    (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64,
48429615Sjmg	    (data[1] & 0x1f) + 64, data[2], data[3],
48529615Sjmg	    *(int *)&(data[0]),
48629615Sjmg	    *(int *)&(data[4]));
48729615Sjmg
48850786Speter    pnp_write(PNP_SET_CSN, csn); /* Move this out of this function XXX */
48950786Speter    outb(_PNP_ADDRESS, PNP_STATUS);
49029615Sjmg
49129615Sjmg    /* Allows up to 1kb of Resource Info,  Should be plenty */
49229615Sjmg    for (i = 0; i < 1024; i++) {
49329615Sjmg	if (!get_resource_info(&tag, 1))
49429615Sjmg	    break;
49529615Sjmg
49639144Seivind	if (PNP_RES_TYPE(tag) == 0) {
49729615Sjmg	    /* Handle small resouce data types */
49829615Sjmg
49939144Seivind	    resinfo = malloc(PNP_SRES_LEN(tag));
50039144Seivind	    if (!get_resource_info(resinfo, PNP_SRES_LEN(tag)))
50129615Sjmg		break;
50229615Sjmg
50339144Seivind	    if (handle_small_res(resinfo, PNP_SRES_NUM(tag), PNP_SRES_LEN(tag)) == 1)
50429615Sjmg		break;
50529615Sjmg	    free(resinfo);
50629615Sjmg	} else {
50729615Sjmg	    /* Handle large resouce data types */
50846422Sluoqi	    u_char buf[2];
50946422Sluoqi	    if (!get_resource_info((char *)buf, 2))
51029615Sjmg		break;
51146422Sluoqi	    large_len = (buf[1] << 8) + buf[0];
51229615Sjmg
51329615Sjmg	    resinfo = malloc(large_len);
51429615Sjmg	    if (!get_resource_info(resinfo, large_len))
51529615Sjmg		break;
51629615Sjmg
51739144Seivind	    handle_large_res(resinfo, PNP_LRES_NUM(tag), large_len);
51829615Sjmg	    free(resinfo);
51929615Sjmg	}
52029615Sjmg    }
52129615Sjmg    printf("Successfully got %d resources, %d logical fdevs\n", i,
52229615Sjmg	    logdevs);
52350786Speter    printf("-- card select # 0x%04x\n", pnp_read(PNP_SET_CSN));
52429615Sjmg    printf("\nCSN %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n",
52529615Sjmg	    ((data[0] & 0x7c) >> 2) + 64,
52629615Sjmg	    (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64,
52729615Sjmg	    (data[1] & 0x1f) + 64, data[2], data[3],
52829615Sjmg	    *(int *)&(data[0]),
52929615Sjmg	    *(int *)&(data[4]));
53029615Sjmg
53129615Sjmg    for (i=0; i<logdevs; i++) {
53229615Sjmg	int j;
53329615Sjmg
53450786Speter	pnp_write(PNP_SET_LDN, i);
53529615Sjmg
53650786Speter	printf("\nLogical device #%d\n", pnp_read(PNP_SET_LDN) );
53729615Sjmg	printf("IO: ");
53829615Sjmg	for (j=0; j<8; j++)
539101611Siedowse	    printf(" 0x%02x%02x", pnp_read(PNP_IO_BASE_HIGH(j)),
540101611Siedowse		pnp_read(PNP_IO_BASE_LOW(j)));
54129615Sjmg	printf("\nIRQ %d %d\n",
54250786Speter	    pnp_read(PNP_IRQ_LEVEL(0)), pnp_read(PNP_IRQ_LEVEL(1)) );
54329615Sjmg	printf("DMA %d %d\n",
54450786Speter	    pnp_read(PNP_DMA_CHANNEL(0)), pnp_read(PNP_DMA_CHANNEL(1)) );
54529615Sjmg	printf("IO range check 0x%02x activate 0x%02x\n",
54650786Speter	    pnp_read(PNP_IO_RANGE_CHECK), pnp_read(PNP_ACTIVATE) );
54729615Sjmg    }
54829615Sjmg}
54929615Sjmg
55029615Sjmg
55129615Sjmg/*
55229615Sjmg * Run the isolation protocol. Use rd_port as the READ_DATA port
55329615Sjmg * value (caller should try multiple READ_DATA locations before giving
55429615Sjmg * up). Upon exiting, all cards are aware that they should use rd_port
55529615Sjmg * as the READ_DATA port;
55629615Sjmg *
55729615Sjmg */
55829615Sjmgint
55929615Sjmgisolation_protocol()
56029615Sjmg{
56129615Sjmg    int csn;
56229615Sjmg    u_char data[9];
56329615Sjmg
56429615Sjmg    send_Initiation_LFSR();
56529615Sjmg
56629615Sjmg    /* Reset CSN for All Cards */
56750786Speter    pnp_write(PNP_CONFIG_CONTROL, 0x04);
56829615Sjmg
56950786Speter    for (csn = 1; (csn < PNP_MAX_CARDS); csn++) {
57029615Sjmg	/* Wake up cards without a CSN */
57129615Sjmg	logdevs = 0 ;
57250786Speter	pnp_write(PNP_WAKE, 0);
57350786Speter	pnp_write(PNP_SET_RD_DATA, rd_port);
57450786Speter	outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION);
57529615Sjmg	DELAY(1000);	/* Delay 1 msec */
57629615Sjmg
57729615Sjmg	if (get_serial(data))
57829615Sjmg	    dump_resdata(data, csn);
57929615Sjmg	else
58029615Sjmg	    break;
58129615Sjmg    }
58229615Sjmg    return csn - 1;
58329615Sjmg}
58429615Sjmg
58529615Sjmg
58647405Sdfrint
58747405Sdfrmain(int argc, char **argv)
58829615Sjmg{
58929615Sjmg    int num_pnp_devs;
59029615Sjmg
59147405Sdfr#ifdef __i386__
59229615Sjmg    /* Hey what about a i386_iopl() call :) */
593124125Scharnier    if (open("/dev/io", O_RDONLY) < 0)
594124125Scharnier	errx(1, "can't get I/O privilege");
59547405Sdfr#endif
59647405Sdfr
59729615Sjmg    printf("Checking for Plug-n-Play devices...\n");
59829615Sjmg
59929615Sjmg    /* Try various READ_DATA ports from 0x203-0x3ff */
60029615Sjmg    for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) {
60129615Sjmg	DEB(printf("Trying Read_Port at %x...\n", (rd_port << 2) | 0x3) );
602229236Sdim	num_pnp_devs = isolation_protocol();
60329615Sjmg	if (num_pnp_devs)
60429615Sjmg	    break;
60529615Sjmg    }
60629615Sjmg    if (!num_pnp_devs) {
60729615Sjmg	printf("No Plug-n-Play devices were found\n");
608124125Scharnier	return (0);
60929615Sjmg    }
610124125Scharnier    return (0);
61129615Sjmg}
612