pnpinfo.c revision 124125
1121986Sjhb/*
2121986Sjhb * Copyright (c) 1996, Sujal M. Patel
3121986Sjhb * All rights reserved.
4121986Sjhb *
5121986Sjhb * Redistribution and use in source and binary forms, with or without
6121986Sjhb * modification, are permitted provided that the following conditions
7121986Sjhb * are met:
8121986Sjhb * 1. Redistributions of source code must retain the above copyright
9121986Sjhb *    notice, this list of conditions and the following disclaimer.
10121986Sjhb * 2. Redistributions in binary form must reproduce the above copyright
11121986Sjhb *    notice, this list of conditions and the following disclaimer in the
12121986Sjhb *    documentation and/or other materials provided with the distribution.
13121986Sjhb *
14121986Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15121986Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16121986Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17121986Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18121986Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19121986Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20121986Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21121986Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22121986Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23121986Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24121986Sjhb * SUCH DAMAGE.
25121986Sjhb */
26121986Sjhb
27121986Sjhb#include <sys/cdefs.h>
28121986Sjhb__FBSDID("$FreeBSD: head/contrib/pnpinfo/pnpinfo.c 124125 2004-01-04 11:11:02Z charnier $");
29121986Sjhb
30121986Sjhb#include <sys/time.h>
31121986Sjhb
32121986Sjhb#include <err.h>
33121986Sjhb#include <stdio.h>
34121986Sjhb#include <stdlib.h>
35121986Sjhb#include <unistd.h>
36167240Sjhb#include <fcntl.h>
37121986Sjhb#include <string.h>
38167240Sjhb
39121986Sjhb#include <machine/cpufunc.h>
40148538Sjhb
41121986Sjhb#include <isa/pnpreg.h>
42167240Sjhb
43167240Sjhb#ifdef DEBUG
44167240Sjhb#define	DEB(x) x
45121986Sjhb#else
46121986Sjhb#define DEB(x)
47121986Sjhb#endif
48214631Sjhb#define DDB(x) x
49121986Sjhb
50121986Sjhbvoid
51121986Sjhbpnp_write(int d, u_char r)
52167747Sjhb{
53121986Sjhb    outb (_PNP_ADDRESS, d);
54121986Sjhb    outb (_PNP_WRITE_DATA, r);
55121986Sjhb}
56121986Sjhb
57121986Sjhb/* The READ_DATA port that we are using currently */
58121986Sjhbstatic int rd_port;
59121986Sjhb
60151979Sjhbu_char
61151979Sjhbpnp_read(int d)
62151979Sjhb{
63151979Sjhb    outb(_PNP_ADDRESS, d);
64121986Sjhb    return inb( (rd_port << 2) + 3) & 0xff;
65151897Srwatson}
66121986Sjhb
67121986Sjhbu_short
68151979Sjhbpnp_readw(int d)
69151979Sjhb{
70151979Sjhb    int c = pnp_read(d) << 8 ;
71151979Sjhb    c |= pnp_read(d+1);
72151979Sjhb    return c;
73151979Sjhb}
74151979Sjhb
75152461Sandreint logdevs=0;
76152461Sandre
77152461Sandrevoid DELAY __P((int i));
78152461Sandrevoid send_Initiation_LFSR();
79121986Sjhbint get_serial __P((u_char *data));
80121986Sjhbint get_resource_info __P((u_char *buffer, int len));
81121986Sjhbint handle_small_res __P((u_char *resinfo, int item, int len));
82121986Sjhbvoid handle_large_res __P((u_char *resinfo, int item, int len));
83151979Sjhbvoid dump_resdata __P((u_char *data, int csn));
84122124Sjhbint isolation_protocol();
85122124Sjhb
86156124Sjhb
87122124Sjhb/*
88122124Sjhb * DELAY does accurate delaying in user-space.
89122124Sjhb * This function busy-waits.
90130980Sjhb */
91157541Sjhbvoid
92121986SjhbDELAY (int i)
93121986Sjhb{
94121986Sjhb    struct timeval t;
95121986Sjhb    long start, stop;
96121986Sjhb
97121986Sjhb    i *= 4;
98121986Sjhb
99121986Sjhb    gettimeofday (&t, NULL);
100121986Sjhb    start = t.tv_sec * 1000000 + t.tv_usec;
101167747Sjhb    do {
102121986Sjhb	gettimeofday (&t, NULL);
103121986Sjhb	stop = t.tv_sec * 1000000 + t.tv_usec;
104121986Sjhb    } while (start + i > stop);
105121986Sjhb}
106121986Sjhb
107121986Sjhb
108130980Sjhb/*
109151979Sjhb * Send Initiation LFSR as described in "Plug and Play ISA Specification,
110121986Sjhb * Intel May 94."
111133017Sscottl */
112121986Sjhbvoid
113121986Sjhbsend_Initiation_LFSR()
114169391Sjhb{
115121986Sjhb    int cur, i;
116121986Sjhb
117128931Sjhb    pnp_write(PNP_CONFIG_CONTROL, 0x2);
118128931Sjhb
119163219Sjhb    /* Reset the LSFR */
120195249Sjhb    outb(_PNP_ADDRESS, 0);
121129964Sjhb    outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */
122121986Sjhb
123129097Sjhb    cur = 0x6a;
124121986Sjhb
125121986Sjhb    for (i = 0; i < 32; i++) {
126169391Sjhb	outb(_PNP_ADDRESS, cur);
127169391Sjhb	cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
128156124Sjhb    }
129121986Sjhb}
130156124Sjhb
131156124Sjhb/*
132156124Sjhb * Get the device's serial number.  Returns 1 if the serial is valid.
133248085Smarius */
134148538Sjhbint
135148538Sjhbget_serial(u_char *data)
136148538Sjhb{
137148538Sjhb    int i, bit, valid = 0, sum = 0x6a;
138148538Sjhb
139133017Sscottl    bzero(data, sizeof(char) * 9);
140133017Sscottl
141133017Sscottl    for (i = 0; i < 72; i++) {
142133017Sscottl	bit = inb((rd_port << 2) | 0x3) == 0x55;
143133017Sscottl	DELAY(250);	/* Delay 250 usec */
144133017Sscottl
145121986Sjhb	/* Can't Short Circuit the next evaluation, so 'and' is last */
146121986Sjhb	bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit;
147121986Sjhb	DELAY(250);	/* Delay 250 usec */
148121986Sjhb
149121986Sjhb	valid = valid || bit;
150121986Sjhb
151121986Sjhb	if (i < 64)
152121986Sjhb	    sum = (sum >> 1) |
153121986Sjhb		(((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
154121986Sjhb
155121986Sjhb	data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
156121986Sjhb    }
157121986Sjhb
158121986Sjhb    valid = valid && (data[8] == sum);
159121986Sjhb
160121986Sjhb    return valid;
161121986Sjhb}
162121986Sjhb
163130980Sjhb
164130980Sjhb/*
165130980Sjhb * Fill's the buffer with resource info from the device.
166130980Sjhb * Returns 0 if the device fails to report
167130980Sjhb */
168130980Sjhbint
169130980Sjhbget_resource_info(u_char *buffer, int len)
170130980Sjhb{
171130980Sjhb    int i, j;
172130980Sjhb
173130980Sjhb    for (i = 0; i < len; i++) {
174130980Sjhb	outb(_PNP_ADDRESS, PNP_STATUS);
175130980Sjhb	for (j = 0; j < 100; j++) {
176130980Sjhb	    if ((inb((rd_port << 2) | 0x3)) & 0x1)
177130980Sjhb		break;
178130980Sjhb	    DELAY(1);
179121986Sjhb	}
180151979Sjhb	if (j == 100) {
181130980Sjhb	    printf("PnP device failed to report resource data\n");
182130980Sjhb	    return 0;
183151979Sjhb	}
184151979Sjhb	outb(_PNP_ADDRESS, PNP_RESOURCE_DATA);
185130980Sjhb	buffer[i] = inb((rd_port << 2) | 0x3);
186130980Sjhb	DEB(printf("--- get_resource_info: got 0x%02x\n",(unsigned)buffer[i]));
187151979Sjhb    }
188130980Sjhb    return 1;
189130980Sjhb}
190151979Sjhb
191130980Sjhbvoid
192130980Sjhbreport_dma_info (x)
193151979Sjhb	int x;
194130980Sjhb{
195130980Sjhb    char *s1=NULL, *s2=NULL, *s3=NULL, *s4=NULL, *s5=NULL;
196130980Sjhb
197130980Sjhb    switch (x & 0x3) {
198151979Sjhb    case 0:
199130980Sjhb	s1="8-bit";
200130980Sjhb	break;
201130980Sjhb    case 1:
202130980Sjhb	s1="8/16-bit";
203121986Sjhb	break;
204121986Sjhb    case 2:
205121986Sjhb	s1="16-bit";
206121986Sjhb	break;
207121986Sjhb#ifdef DIAGNOSTIC
208121986Sjhb    case 3:
209121986Sjhb	s1="Reserved";
210121986Sjhb	break;
211157541Sjhb#endif
212121986Sjhb    }
213121986Sjhb
214121986Sjhb    s2 = (x & 0x4) ? "bus master" : "not a bus master";
215121986Sjhb
216121986Sjhb    s3 = (x & 0x8) ? "count by byte" : "";
217121986Sjhb
218121986Sjhb    s4 = (x & 0x10) ? "count by word" : "";
219121986Sjhb
220133017Sscottl    switch ((x & 0x60) >> 5) {
221121986Sjhb    case 0:
222121986Sjhb	s5="Compatibility mode";
223121986Sjhb	break;
224121986Sjhb    case 1:
225121986Sjhb	s5="Type A";
226121986Sjhb	break;
227121986Sjhb    case 2:
228157541Sjhb	s5="Type B";
229121986Sjhb	break;
230121986Sjhb    case 3:
231121986Sjhb	s5="Type F";
232121986Sjhb	break;
233133017Sscottl    }
234133017Sscottl    printf("\t%s, %s, %s, %s, %s\n",s1,s2,s3,s4,s5);
235133017Sscottl}
236133017Sscottl
237121986Sjhb
238121986Sjhbvoid
239121986Sjhbreport_memory_info (int x)
240121986Sjhb{
241121986Sjhb    if (x & 0x1)
242121986Sjhb	printf ("Memory Range: Writeable\n");
243122148Sjhb    else
244133017Sscottl	printf ("Memory Range: Not writeable (ROM)\n");
245121986Sjhb
246121986Sjhb    if (x & 0x2)
247121986Sjhb	printf ("Memory Range: Read-cacheable, write-through\n");
248129964Sjhb    else
249129964Sjhb	printf ("Memory Range: Non-cacheable\n");
250129964Sjhb
251129964Sjhb    if (x & 0x4)
252129964Sjhb	printf ("Memory Range: Decode supports high address\n");
253129964Sjhb    else
254129964Sjhb	printf ("Memory Range: Decode supports range length\n");
255129964Sjhb
256129964Sjhb    switch ((x & 0x18) >> 3) {
257151979Sjhb    case 0:
258151979Sjhb	printf ("Memory Range: 8-bit memory only\n");
259151979Sjhb	break;
260151979Sjhb    case 1:
261208915Sjhb	printf ("Memory Range: 16-bit memory only\n");
262151979Sjhb	break;
263151979Sjhb    case 2:
264129964Sjhb	printf ("Memory Range: 8-bit and 16-bit memory supported\n");
265129964Sjhb	break;
266129964Sjhb#ifdef DIAGNOSTIC
267129964Sjhb    case 3:
268129964Sjhb	printf ("Memory Range: Reserved\n");
269129964Sjhb	break;
270129964Sjhb#endif
271129964Sjhb    }
272129964Sjhb
273129964Sjhb    if (x & 0x20)
274156124Sjhb	printf ("Memory Range: Memory is shadowable\n");
275156124Sjhb    else
276129964Sjhb	printf ("Memory Range: Memory is not shadowable\n");
277129964Sjhb
278129964Sjhb    if (x & 0x40)
279129964Sjhb	printf ("Memory Range: Memory is an expansion ROM\n");
280129964Sjhb    else
281129964Sjhb	printf ("Memory Range: Memory is not an expansion ROM\n");
282129964Sjhb
283129964Sjhb#ifdef DIAGNOSTIC
284129964Sjhb    if (x & 0x80)
285129964Sjhb	printf ("Memory Range: Reserved (Device is brain-damaged)\n");
286129964Sjhb#endif
287129964Sjhb}
288151979Sjhb
289151979Sjhb
290129964Sjhb/*
291148538Sjhb *  Small Resource Tag Handler
292129964Sjhb *
293129964Sjhb *  Returns 1 if checksum was valid (and an END_TAG was received).
294151979Sjhb *  Returns -1 if checksum was invalid (and an END_TAG was received).
295129964Sjhb *  Returns 0 for other tags.
296129964Sjhb */
297129964Sjhbint
298129964Sjhbhandle_small_res(u_char *resinfo, int item, int len)
299151979Sjhb{
300129964Sjhb    int i;
301129964Sjhb
302129964Sjhb    DEB(printf("*** ITEM 0x%04x len %d detected\n", item, len));
303129964Sjhb
304129964Sjhb    switch (item) {
305151979Sjhb    default:
306151979Sjhb	printf("*** ITEM 0x%02x detected\n", item);
307156124Sjhb	break;
308129964Sjhb    case PNP_TAG_VERSION:
309129964Sjhb	printf("PnP Version %d.%d, Vendor Version %d\n",
310129964Sjhb	    resinfo[0] >> 4, resinfo[0] & (0xf), resinfo[1]);
311157541Sjhb	break;
312129964Sjhb    case PNP_TAG_LOGICAL_DEVICE:
313129964Sjhb	printf("\nLogical Device ID: %c%c%c%02x%02x 0x%08x #%d\n",
314129964Sjhb		((resinfo[0] & 0x7c) >> 2) + 64,
315129964Sjhb		(((resinfo[0] & 0x03) << 3) |
316129964Sjhb		((resinfo[1] & 0xe0) >> 5)) + 64,
317129964Sjhb		(resinfo[1] & 0x1f) + 64,
318129964Sjhb		resinfo[2], resinfo[3], *(int *)(resinfo),
319195249Sjhb		logdevs++);
320156124Sjhb
321121986Sjhb	if (resinfo[4] & 0x1)
322156124Sjhb	    printf ("\tDevice powers up active\n"); /* XXX */
323156124Sjhb	if (resinfo[4] & 0x2)
324195415Sjhb	    printf ("\tDevice supports I/O Range Check\n");
325187880Sjeff	if (resinfo[4] > 0x3)
326121986Sjhb	    printf ("\tReserved register funcs %02x\n",
327187880Sjeff		resinfo[4]);
328187880Sjeff
329187880Sjeff	if (len == 6)
330187880Sjeff	    printf("\tVendor register funcs %02x\n", resinfo[5]);
331187880Sjeff	break;
332187880Sjeff    case PNP_TAG_COMPAT_DEVICE:
333187880Sjeff	printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n",
334187880Sjeff		((resinfo[0] & 0x7c) >> 2) + 64,
335187880Sjeff		(((resinfo[0] & 0x03) << 3) |
336187880Sjeff		((resinfo[1] & 0xe0) >> 5)) + 64,
337187880Sjeff		(resinfo[1] & 0x1f) + 64,
338187880Sjeff		resinfo[2], resinfo[3], *(int *)resinfo);
339195249Sjhb	break;
340187880Sjeff    case PNP_TAG_IRQ_FORMAT:
341187880Sjeff	printf("    IRQ: ");
342187880Sjeff
343187880Sjeff	for (i = 0; i < 8; i++)
344187880Sjeff	    if (resinfo[0] & (1<<i))
345195415Sjhb		printf("%d ", i);
346195415Sjhb	for (i = 0; i < 8; i++)
347195249Sjhb	    if (resinfo[1] & (1<<i))
348195249Sjhb		printf("%d ", i + 8);
349208915Sjhb	if (len == 3) {
350208915Sjhb	    if (resinfo[2] & 0x1)
351208915Sjhb		printf("IRQ: High true edge sensitive\n");
352208915Sjhb	    if (resinfo[2] & 0x2)
353208915Sjhb		printf("IRQ: Low true edge sensitive\n");
354208915Sjhb	    if (resinfo[2] & 0x4)
355208915Sjhb		printf("IRQ: High true level sensitive\n");
356208991Smav	    if (resinfo[2] & 0x8)
357208915Sjhb		printf("IRQ: Low true level sensitive\n");
358208915Sjhb	} else {
359216679Sjhb	    printf(" - only one type (true/edge)\n");
360208915Sjhb	}
361216679Sjhb	break;
362208915Sjhb    case PNP_TAG_DMA_FORMAT:
363208915Sjhb	printf("    DMA: channel(s) ");
364195415Sjhb	for (i = 0; i < 8; i++)
365195415Sjhb	    if (resinfo[0] & (1<<i))
366195415Sjhb		printf("%d ", i);
367195415Sjhb	printf ("\n");
368121986Sjhb	report_dma_info (resinfo[1]);
369187880Sjeff	break;
370187880Sjeff    case PNP_TAG_START_DEPENDANT:
371151979Sjhb	printf("TAG Start DF\n");
372187880Sjeff	if (len == 1) {
373187880Sjeff	    switch (resinfo[0]) {
374121986Sjhb	    case 0:
375129964Sjhb		printf("Good Configuration\n");
376208915Sjhb		break;
377208915Sjhb	    case 1:
378187880Sjeff		printf("Acceptable Configuration\n");
379187880Sjeff		break;
380187880Sjeff	    case 2:
381187880Sjeff		printf("Sub-optimal Configuration\n");
382195415Sjhb		break;
383195415Sjhb	    }
384195415Sjhb	}
385187880Sjeff	break;
386195415Sjhb    case PNP_TAG_END_DEPENDANT:
387195249Sjhb	printf("TAG End DF\n");
388121986Sjhb	break;
389121986Sjhb    case PNP_TAG_IO_RANGE:
390121986Sjhb	printf("    I/O Range 0x%x .. 0x%x, alignment 0x%x, len 0x%x\n",
391121986Sjhb	    resinfo[1] + (resinfo[2] << 8),
392121986Sjhb	    resinfo[3] + (resinfo[4] << 8),
393121986Sjhb	    resinfo[5], resinfo[6] );
394121986Sjhb	if (resinfo[0])
395187880Sjeff	    printf("\t[16-bit addr]\n");
396195249Sjhb	else
397195249Sjhb	    printf("\t[not 16-bit addr]\n");
398195249Sjhb	break;
399187880Sjeff    case PNP_TAG_IO_FIXED:
400121986Sjhb	printf ("    FIXED I/O base address 0x%x length 0x%x\n",
401121986Sjhb	    resinfo[0] + ( (resinfo[1] & 3 ) << 8), /* XXX */
402187880Sjeff	    resinfo[2]);
403169391Sjhb	break;
404169391Sjhb#ifdef DIAGNOSTIC
405169391Sjhb    case PNP_TAG_RESERVED:
406169391Sjhb	printf("Reserved Tag Detected\n");
407169391Sjhb	break;
408169391Sjhb#endif
409169391Sjhb    case PNP_TAG_VENDOR:
410169391Sjhb	printf("*** Small Vendor Tag Detected\n");
411169391Sjhb	break;
412187880Sjeff    case PNP_TAG_END:
413208915Sjhb	printf("End Tag\n\n");
414169391Sjhb	/* XXX Record and Verify Checksum */
415169391Sjhb	return 1;
416169391Sjhb	break;
417208915Sjhb    }
418187880Sjeff    return 0;
419169391Sjhb}
420169391Sjhb
421169391Sjhb
422121986Sjhbvoid
423121986Sjhbhandle_large_res(u_char *resinfo, int item, int len)
424121986Sjhb{
425121986Sjhb    int i;
426121986Sjhb
427121986Sjhb    DEB(printf("*** Large ITEM %d len %d found\n", item, len));
428151979Sjhb    switch (item) {
429121986Sjhb    case PNP_TAG_MEMORY_RANGE:
430121986Sjhb	report_memory_info(resinfo[0]);
431121986Sjhb	printf("Memory range minimum address: 0x%x\n",
432121986Sjhb		(resinfo[1] << 8) + (resinfo[2] << 16));
433121986Sjhb	printf("Memory range maximum address: 0x%x\n",
434121986Sjhb		(resinfo[3] << 8) + (resinfo[4] << 16));
435121986Sjhb	printf("Memory range base alignment: 0x%x\n",
436151979Sjhb		(i = (resinfo[5] + (resinfo[6] << 8))) ? i : (1 << 16));
437151979Sjhb	printf("Memory range length: 0x%x\n",
438121986Sjhb		(resinfo[7] + (resinfo[8] << 8)) * 256);
439121986Sjhb	break;
440121986Sjhb    case PNP_TAG_ID_ANSI:
441128931Sjhb	printf("Device Description: ");
442128931Sjhb
443128931Sjhb	for (i = 0; i < len; i++) {
444128931Sjhb	    if (resinfo[i]) /* XXX */
445128931Sjhb		printf("%c", resinfo[i]);
446128931Sjhb	}
447130984Sjhb	printf("\n");
448128931Sjhb	break;
449128931Sjhb    case PNP_TAG_ID_UNICODE:
450128931Sjhb	printf("ID String Unicode Detected (Undefined)\n");
451128931Sjhb	break;
452128931Sjhb    case PNP_TAG_LARGE_VENDOR:
453130984Sjhb	printf("Large Vendor Defined Detected\n");
454130984Sjhb	break;
455130984Sjhb    case PNP_TAG_MEMORY32_RANGE:
456130984Sjhb	printf("32bit Memory Range Desc Unimplemented\n");
457140452Sjhb	break;
458128931Sjhb    case PNP_TAG_MEMORY32_FIXED:
459208915Sjhb	printf("32bit Fixed Location Desc Unimplemented\n");
460130984Sjhb	break;
461130984Sjhb#ifdef DIAGNOSTIC
462130984Sjhb    case PNP_TAG_LARGE_RESERVED:
463130984Sjhb	printf("Large Reserved Tag Detected\n");
464130984Sjhb	break;
465130984Sjhb#endif
466130984Sjhb    }
467130984Sjhb}
468130984Sjhb
469130984Sjhb
470130984Sjhb/*
471130984Sjhb * Dump all the information about configurations.
472130984Sjhb */
473130984Sjhbvoid
474130984Sjhbdump_resdata(u_char *data, int csn)
475130984Sjhb{
476130984Sjhb    int i, large_len;
477130984Sjhb
478130984Sjhb    u_char tag, *resinfo;
479130984Sjhb
480130984Sjhb    DDB(printf("\nCard assigned CSN #%d\n", csn));
481208915Sjhb    printf("Vendor ID %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n",
482128931Sjhb	    ((data[0] & 0x7c) >> 2) + 64,
483128931Sjhb	    (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64,
484128931Sjhb	    (data[1] & 0x1f) + 64, data[2], data[3],
485121986Sjhb	    *(int *)&(data[0]),
486163219Sjhb	    *(int *)&(data[4]));
487121986Sjhb
488163219Sjhb    pnp_write(PNP_SET_CSN, csn); /* Move this out of this function XXX */
489163219Sjhb    outb(_PNP_ADDRESS, PNP_STATUS);
490121986Sjhb
491208915Sjhb    /* Allows up to 1kb of Resource Info,  Should be plenty */
492163219Sjhb    for (i = 0; i < 1024; i++) {
493163219Sjhb	if (!get_resource_info(&tag, 1))
494208915Sjhb	    break;
495121986Sjhb
496121986Sjhb	if (PNP_RES_TYPE(tag) == 0) {
497121986Sjhb	    /* Handle small resouce data types */
498121986Sjhb
499121986Sjhb	    resinfo = malloc(PNP_SRES_LEN(tag));
500121986Sjhb	    if (!get_resource_info(resinfo, PNP_SRES_LEN(tag)))
501167247Sjhb		break;
502121986Sjhb
503121986Sjhb	    if (handle_small_res(resinfo, PNP_SRES_NUM(tag), PNP_SRES_LEN(tag)) == 1)
504121986Sjhb		break;
505121986Sjhb	    free(resinfo);
506121986Sjhb	} else {
507121986Sjhb	    /* Handle large resouce data types */
508121986Sjhb	    u_char buf[2];
509145054Sjhb	    if (!get_resource_info((char *)buf, 2))
510156920Sjhb		break;
511121986Sjhb	    large_len = (buf[1] << 8) + buf[0];
512145054Sjhb
513121986Sjhb	    resinfo = malloc(large_len);
514145054Sjhb	    if (!get_resource_info(resinfo, large_len))
515145054Sjhb		break;
516152528Sjhb
517145057Sjhb	    handle_large_res(resinfo, PNP_LRES_NUM(tag), large_len);
518145054Sjhb	    free(resinfo);
519145054Sjhb	}
520145054Sjhb    }
521145054Sjhb    printf("Successfully got %d resources, %d logical fdevs\n", i,
522145054Sjhb	    logdevs);
523121986Sjhb    printf("-- card select # 0x%04x\n", pnp_read(PNP_SET_CSN));
524121986Sjhb    printf("\nCSN %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n",
525121986Sjhb	    ((data[0] & 0x7c) >> 2) + 64,
526121986Sjhb	    (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64,
527121986Sjhb	    (data[1] & 0x1f) + 64, data[2], data[3],
528195249Sjhb	    *(int *)&(data[0]),
529121986Sjhb	    *(int *)&(data[4]));
530121986Sjhb
531121986Sjhb    for (i=0; i<logdevs; i++) {
532121986Sjhb	int j;
533121986Sjhb
534121986Sjhb	pnp_write(PNP_SET_LDN, i);
535121986Sjhb
536121986Sjhb	printf("\nLogical device #%d\n", pnp_read(PNP_SET_LDN) );
537121986Sjhb	printf("IO: ");
538121986Sjhb	for (j=0; j<8; j++)
539121986Sjhb	    printf(" 0x%02x%02x", pnp_read(PNP_IO_BASE_HIGH(j)),
540121986Sjhb		pnp_read(PNP_IO_BASE_LOW(j)));
541170340Sjhb	printf("\nIRQ %d %d\n",
542121986Sjhb	    pnp_read(PNP_IRQ_LEVEL(0)), pnp_read(PNP_IRQ_LEVEL(1)) );
543121986Sjhb	printf("DMA %d %d\n",
544121986Sjhb	    pnp_read(PNP_DMA_CHANNEL(0)), pnp_read(PNP_DMA_CHANNEL(1)) );
545122124Sjhb	printf("IO range check 0x%02x activate 0x%02x\n",
546121986Sjhb	    pnp_read(PNP_IO_RANGE_CHECK), pnp_read(PNP_ACTIVATE) );
547121986Sjhb    }
548167747Sjhb}
549121986Sjhb
550121986Sjhb
551121986Sjhb/*
552121986Sjhb * Run the isolation protocol. Use rd_port as the READ_DATA port
553121986Sjhb * value (caller should try multiple READ_DATA locations before giving
554121986Sjhb * up). Upon exiting, all cards are aware that they should use rd_port
555121986Sjhb * as the READ_DATA port;
556121986Sjhb *
557121986Sjhb */
558121986Sjhbint
559121986Sjhbisolation_protocol()
560151979Sjhb{
561121986Sjhb    int csn;
562121986Sjhb    u_char data[9];
563145080Sjhb
564142256Sjhb    send_Initiation_LFSR();
565130980Sjhb
566121986Sjhb    /* Reset CSN for All Cards */
567151979Sjhb    pnp_write(PNP_CONFIG_CONTROL, 0x04);
568130980Sjhb
569151979Sjhb    for (csn = 1; (csn < PNP_MAX_CARDS); csn++) {
570130980Sjhb	/* Wake up cards without a CSN */
571121986Sjhb	logdevs = 0 ;
572121986Sjhb	pnp_write(PNP_WAKE, 0);
573121986Sjhb	pnp_write(PNP_SET_RD_DATA, rd_port);
574121986Sjhb	outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION);
575130980Sjhb	DELAY(1000);	/* Delay 1 msec */
576121986Sjhb
577121986Sjhb	if (get_serial(data))
578121986Sjhb	    dump_resdata(data, csn);
579121986Sjhb	else
580121986Sjhb	    break;
581121986Sjhb    }
582156124Sjhb    return csn - 1;
583156124Sjhb}
584121986Sjhb
585156124Sjhb
586121986Sjhbint
587121986Sjhbmain(int argc, char **argv)
588121986Sjhb{
589121986Sjhb    int num_pnp_devs;
590121986Sjhb
591121986Sjhb#ifdef __i386__
592121986Sjhb    /* Hey what about a i386_iopl() call :) */
593121986Sjhb    if (open("/dev/io", O_RDONLY) < 0)
594121986Sjhb	errx(1, "can't get I/O privilege");
595121986Sjhb#endif
596121986Sjhb#ifdef __alpha__
597121986Sjhb    ioperm(0x203, 0x400 - 0x203, 1);
598121986Sjhb#endif
599121986Sjhb
600121986Sjhb    printf("Checking for Plug-n-Play devices...\n");
601121986Sjhb
602151979Sjhb    /* Try various READ_DATA ports from 0x203-0x3ff */
603121986Sjhb    for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) {
604121986Sjhb	DEB(printf("Trying Read_Port at %x...\n", (rd_port << 2) | 0x3) );
605121986Sjhb	num_pnp_devs = isolation_protocol(rd_port);
606121986Sjhb	if (num_pnp_devs)
607121986Sjhb	    break;
608121986Sjhb    }
609121986Sjhb    if (!num_pnp_devs) {
610121986Sjhb	printf("No Plug-n-Play devices were found\n");
611121986Sjhb	return (0);
612121986Sjhb    }
613151979Sjhb    return (0);
614121986Sjhb}
615151979Sjhb