pnpinfo.c revision 31135
1176434Skaiw/*
2176434Skaiw * Copyright (c) 1996, Sujal M. Patel
3176434Skaiw * All rights reserved.
4176434Skaiw *
5176434Skaiw * Redistribution and use in source and binary forms, with or without
6176434Skaiw * modification, are permitted provided that the following conditions
7176434Skaiw * are met:
8176434Skaiw * 1. Redistributions of source code must retain the above copyright
9176434Skaiw *    notice, this list of conditions and the following disclaimer.
10176434Skaiw * 2. Redistributions in binary form must reproduce the above copyright
11176434Skaiw *    notice, this list of conditions and the following disclaimer in the
12176434Skaiw *    documentation and/or other materials provided with the distribution.
13176434Skaiw *
14176434Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15176434Skaiw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16176434Skaiw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17176434Skaiw * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18176434Skaiw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19176434Skaiw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20176434Skaiw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21176434Skaiw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22176434Skaiw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23176434Skaiw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24176434Skaiw * SUCH DAMAGE.
25176434Skaiw *
26176434Skaiw *      $Id: pnpinfo.c,v 1.1.1.1 1997/09/19 15:36:00 jmg Exp $
27176434Skaiw */
28176434Skaiw
29176434Skaiw#include <sys/time.h>
30176434Skaiw
31176434Skaiw#include <stdio.h>
32176434Skaiw#include <stdlib.h>
33176434Skaiw#include <unistd.h>
34176434Skaiw#include <fcntl.h>
35176434Skaiw#include <string.h>
36176434Skaiw
37176434Skaiw#include <machine/cpufunc.h>
38176434Skaiw
39176434Skaiw#include <i386/isa/pnp.h>
40176434Skaiw
41176434Skaiw#ifdef DEBUG
42176434Skaiw#define	DEB(x) x
43176434Skaiw#else
44285224Semaste#define DEB(x)
45176434Skaiw#endif
46176434Skaiw#define DDB(x) x
47176434Skaiw
48176434Skaiwvoid
49176434Skaiwpnp_write(int d, u_char r)
50176434Skaiw{
51176434Skaiw    outb (_PNP_ADDRESS, d);
52176434Skaiw    outb (_PNP_WRITE_DATA, r);
53176434Skaiw}
54176434Skaiw/* The READ_DATA port that we are using currently */
55176434Skaiwstatic int rd_port;
56176434Skaiw
57176434Skaiwu_char
58176434Skaiwpnp_read(int d)
59176434Skaiw{
60176434Skaiw    outb(_PNP_ADDRESS, d);
61176434Skaiw    return inb( (rd_port << 2) + 3) & 0xff;
62224650Semaste}
63176434Skaiw
64176434Skaiwu_short
65285224Semastepnp_readw(int d)
66183218Skaiw{
67183218Skaiw    int c = pnp_read(d) << 8 ;
68176434Skaiw    c |= pnp_read(d+1);
69176434Skaiw    return c;
70176434Skaiw}
71176434Skaiw
72176434Skaiwint logdevs=0;
73176434Skaiw
74176434Skaiwvoid DELAY __P((int i));
75176434Skaiwvoid send_Initiation_LFSR();
76176434Skaiwint get_serial __P((u_char *data));
77176434Skaiwint get_resource_info __P((u_char *buffer, int len));
78176434Skaiwint handle_small_res __P((u_char *resinfo, int item, int len));
79176434Skaiwvoid handle_large_res __P((u_char *resinfo, int item, int len));
80176434Skaiwvoid dump_resdata __P((u_char *data, int csn));
81176434Skaiwint isolation_protocol();
82176434Skaiw
83176434Skaiw
84176434Skaiw/*
85176434Skaiw * DELAY does accurate delaying in user-space.
86176434Skaiw * This function busy-waits.
87176434Skaiw */
88176434Skaiwvoid
89177064SkaiwDELAY (int i)
90177064Skaiw{
91177064Skaiw    struct timeval t;
92177064Skaiw    long start, stop;
93177064Skaiw
94177064Skaiw    i *= 4;
95177064Skaiw
96176434Skaiw    gettimeofday (&t, NULL);
97176434Skaiw    start = t.tv_sec * 1000000 + t.tv_usec;
98176434Skaiw    do {
99176434Skaiw	gettimeofday (&t, NULL);
100176434Skaiw	stop = t.tv_sec * 1000000 + t.tv_usec;
101176434Skaiw    } while (start + i > stop);
102176434Skaiw}
103176434Skaiw
104176434Skaiw
105176434Skaiw/*
106176434Skaiw * Send Initiation LFSR as described in "Plug and Play ISA Specification,
107176434Skaiw * Intel May 94."
108176434Skaiw */
109183218Skaiwvoid
110183218Skaiwsend_Initiation_LFSR()
111183218Skaiw{
112183218Skaiw    int cur, i;
113183218Skaiw
114183218Skaiw    pnp_write(CONFIG_CONTROL, 0x2);
115183218Skaiw
116176434Skaiw    /* Reset the LSFR */
117176434Skaiw    outb(_PNP_ADDRESS, 0);
118176434Skaiw    outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */
119222122Sbcr
120176434Skaiw    cur = 0x6a;
121176434Skaiw
122176434Skaiw    for (i = 0; i < 32; i++) {
123176434Skaiw	outb(_PNP_ADDRESS, cur);
124176434Skaiw	cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
125176434Skaiw    }
126176434Skaiw}
127176434Skaiw
128176434Skaiw/*
129176528Skaiw * Get the device's serial number.  Returns 1 if the serial is valid.
130176434Skaiw */
131176434Skaiwint
132176434Skaiwget_serial(u_char *data)
133176434Skaiw{
134176434Skaiw    int i, bit, valid = 0, sum = 0x6a;
135176434Skaiw
136176434Skaiw    bzero(data, sizeof(char) * 9);
137176528Skaiw
138176434Skaiw    for (i = 0; i < 72; i++) {
139176434Skaiw	bit = inb((rd_port << 2) | 0x3) == 0x55;
140176434Skaiw	DELAY(250);	/* Delay 250 usec */
141176434Skaiw
142176434Skaiw	/* Can't Short Circuit the next evaluation, so 'and' is last */
143176434Skaiw	bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit;
144176434Skaiw	DELAY(250);	/* Delay 250 usec */
145176434Skaiw
146176434Skaiw	valid = valid || bit;
147176434Skaiw
148176434Skaiw	if (i < 64)
149176434Skaiw	    sum = (sum >> 1) |
150176434Skaiw		(((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
151176434Skaiw
152176434Skaiw	data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
153176434Skaiw    }
154176434Skaiw
155176434Skaiw    valid = valid && (data[8] == sum);
156176434Skaiw
157176434Skaiw    return valid;
158176434Skaiw}
159176434Skaiw
160176434Skaiw
161176434Skaiw/*
162176434Skaiw * Fill's the buffer with resource info from the device.
163176434Skaiw * Returns 0 if the device fails to report
164176434Skaiw */
165176434Skaiwint
166176434Skaiwget_resource_info(u_char *buffer, int len)
167176434Skaiw{
168176434Skaiw    int i, j;
169213643Skientzle
170213643Skientzle    for (i = 0; i < len; i++) {
171213643Skientzle	outb(_PNP_ADDRESS, STATUS);
172213643Skientzle	for (j = 0; j < 100; j++) {
173213643Skientzle	    if ((inb((rd_port << 2) | 0x3)) & 0x1)
174213643Skientzle		break;
175213643Skientzle	    DELAY(1);
176213643Skientzle	}
177213643Skientzle	if (j == 100) {
178213643Skientzle	    printf("PnP device failed to report resource data\n");
179213643Skientzle	    return 0;
180213643Skientzle	}
181213643Skientzle	outb(_PNP_ADDRESS, RESOURCE_DATA);
182213643Skientzle	buffer[i] = inb((rd_port << 2) | 0x3);
183213643Skientzle	DEB(printf("--- get_resource_info: got 0x%02x\n",(unsigned)buffer[i]));
184213643Skientzle    }
185213643Skientzle    return 1;
186176434Skaiw}
187176434Skaiw
188176434Skaiwvoid
189176525Skaiwreport_dma_info (x)
190176525Skaiw	int x;
191176525Skaiw{
192176528Skaiw    char *s1=NULL, *s2=NULL, *s3=NULL, *s4=NULL, *s5=NULL;
193176525Skaiw
194176525Skaiw    switch (x & 0x3) {
195176434Skaiw    case 0:
196176434Skaiw	s1="8-bit";
197176434Skaiw	break;
198176434Skaiw    case 1:
199176434Skaiw	s1="8/16-bit";
200176434Skaiw	break;
201176434Skaiw    case 2:
202176434Skaiw	s1="16-bit";
203176434Skaiw	break;
204176528Skaiw#ifdef DIAGNOSTIC
205176434Skaiw    case 3:
206176434Skaiw	s1="Reserved";
207176434Skaiw	break;
208176434Skaiw#endif
209176434Skaiw    }
210176434Skaiw
211176434Skaiw    s2 = (x & 0x4) ? "bus master" : "not a bus master";
212176528Skaiw
213176434Skaiw    s3 = (x & 0x8) ? "count by byte" : "";
214176434Skaiw
215176434Skaiw    s4 = (x & 0x10) ? "count by word" : "";
216224650Semaste
217224650Semaste    switch ((x & 0x60) >> 5) {
218224650Semaste    case 0:
219224650Semaste	s5="Compatibility mode";
220224650Semaste	break;
221224650Semaste    case 1:
222224650Semaste	s5="Type A";
223224650Semaste	break;
224224650Semaste    case 2:
225224650Semaste	s5="Type B";
226224650Semaste	break;
227224650Semaste    case 3:
228224650Semaste	s5="Type F";
229224650Semaste	break;
230224650Semaste    }
231224650Semaste    printf("\t%s, %s, %s, %s, %s\n",s1,s2,s3,s4,s5);
232176434Skaiw}
233176434Skaiw
234176434Skaiw
235176434Skaiwvoid
236176434Skaiwreport_memory_info (int x)
237176434Skaiw{
238176434Skaiw    if (x & 0x1)
239176434Skaiw	printf ("Memory Range: Writeable\n");
240176434Skaiw    else
241176434Skaiw	printf ("Memory Range: Not writeable (ROM)\n");
242222122Sbcr
243176434Skaiw    if (x & 0x2)
244176434Skaiw	printf ("Memory Range: Read-cacheable, write-through\n");
245176434Skaiw    else
246176434Skaiw	printf ("Memory Range: Non-cacheable\n");
247176434Skaiw
248176434Skaiw    if (x & 0x4)
249176434Skaiw	printf ("Memory Range: Decode supports high address\n");
250176434Skaiw    else
251176434Skaiw	printf ("Memory Range: Decode supports range length\n");
252176434Skaiw
253176434Skaiw    switch ((x & 0x18) >> 3) {
254176434Skaiw    case 0:
255176434Skaiw	printf ("Memory Range: 8-bit memory only\n");
256176434Skaiw	break;
257176434Skaiw    case 1:
258176434Skaiw	printf ("Memory Range: 16-bit memory only\n");
259176434Skaiw	break;
260176434Skaiw    case 2:
261176434Skaiw	printf ("Memory Range: 8-bit and 16-bit memory supported\n");
262183218Skaiw	break;
263183218Skaiw#ifdef DIAGNOSTIC
264183218Skaiw    case 3:
265183218Skaiw	printf ("Memory Range: Reserved\n");
266176434Skaiw	break;
267176434Skaiw#endif
268183218Skaiw    }
269176434Skaiw
270176434Skaiw    if (x & 0x20)
271176434Skaiw	printf ("Memory Range: Memory is shadowable\n");
272183218Skaiw    else
273176434Skaiw	printf ("Memory Range: Memory is not shadowable\n");
274176434Skaiw
275176434Skaiw    if (x & 0x40)
276176434Skaiw	printf ("Memory Range: Memory is an expansion ROM\n");
277176434Skaiw    else
278183218Skaiw	printf ("Memory Range: Memory is not an expansion ROM\n");
279176434Skaiw
280176434Skaiw#ifdef DIAGNOSTIC
281176434Skaiw    if (x & 0x80)
282176434Skaiw	printf ("Memory Range: Reserved (Device is brain-damaged)\n");
283183218Skaiw#endif
284176434Skaiw}
285176434Skaiw
286176434Skaiw
287176434Skaiw/*
288176434Skaiw *  Small Resource Tag Handler
289176434Skaiw *
290176434Skaiw *  Returns 1 if checksum was valid (and an END_TAG was received).
291176434Skaiw *  Returns -1 if checksum was invalid (and an END_TAG was received).
292176434Skaiw *  Returns 0 for other tags.
293176434Skaiw */
294176434Skaiwint
295176434Skaiwhandle_small_res(u_char *resinfo, int item, int len)
296176434Skaiw{
297176434Skaiw    int i;
298176434Skaiw
299176434Skaiw    DEB(printf("*** ITEM 0x%04x len %d detected\n", item, len));
300176434Skaiw
301176434Skaiw    switch (item) {
302176434Skaiw    default:
303176434Skaiw	printf("*** ITEM 0x%02x detected\n", item);
304176434Skaiw	break;
305176434Skaiw    case PNP_VERSION:
306183218Skaiw	printf("PnP Version %d.%d, Vendor Version %d\n",
307183218Skaiw	    resinfo[0] >> 4, resinfo[0] & (0xf), resinfo[1]);
308183218Skaiw	break;
309183218Skaiw    case LOG_DEVICE_ID:
310183218Skaiw	printf("\nLogical Device ID: %c%c%c%02x%02x 0x%08x #%d\n",
311183218Skaiw		((resinfo[0] & 0x7c) >> 2) + 64,
312183218Skaiw		(((resinfo[0] & 0x03) << 3) |
313183218Skaiw		((resinfo[1] & 0xe0) >> 5)) + 64,
314183218Skaiw		(resinfo[1] & 0x1f) + 64,
315183218Skaiw		resinfo[2], resinfo[3], *(int *)(resinfo),
316183218Skaiw		logdevs++);
317183218Skaiw
318183218Skaiw	if (resinfo[4] & 0x1)
319183218Skaiw	    printf ("\tDevice powers up active\n"); /* XXX */
320183218Skaiw	if (resinfo[4] & 0x2)
321183218Skaiw	    printf ("\tDevice supports I/O Range Check\n");
322183218Skaiw	if (resinfo[4] > 0x3)
323183218Skaiw	    printf ("\tReserved register funcs %02x\n",
324183218Skaiw		resinfo[4]);
325183218Skaiw
326183218Skaiw	if (len == 6)
327183218Skaiw	    printf("\tVendor register funcs %02x\n", resinfo[5]);
328183218Skaiw	break;
329183218Skaiw    case COMP_DEVICE_ID:
330176434Skaiw	printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n",
331176434Skaiw		((resinfo[0] & 0x7c) >> 2) + 64,
332176728Skaiw		(((resinfo[0] & 0x03) << 3) |
333176728Skaiw		((resinfo[1] & 0xe0) >> 5)) + 64,
334176728Skaiw		(resinfo[1] & 0x1f) + 64,
335176728Skaiw		resinfo[2], resinfo[3], *(int *)resinfo);
336176728Skaiw	break;
337176728Skaiw    case IRQ_FORMAT:
338176728Skaiw	printf("    IRQ: ");
339176728Skaiw
340176728Skaiw	for (i = 0; i < 8; i++)
341176728Skaiw	    if (resinfo[0] & (1<<i))
342176728Skaiw		printf("%d ", i);
343176728Skaiw	for (i = 0; i < 8; i++)
344176728Skaiw	    if (resinfo[1] & (1<<i))
345176434Skaiw		printf("%d ", i + 8);
346176434Skaiw	if (len == 3) {
347176434Skaiw	    if (resinfo[2] & 0x1)
348176434Skaiw		printf("IRQ: High true edge sensitive\n");
349176434Skaiw	    if (resinfo[2] & 0x2)
350176434Skaiw		printf("IRQ: Low true edge sensitive\n");
351176434Skaiw	    if (resinfo[2] & 0x4)
352176434Skaiw		printf("IRQ: High true level sensitive\n");
353176434Skaiw	    if (resinfo[2] & 0x8)
354176434Skaiw		printf("IRQ: Low true level sensitive\n");
355176434Skaiw	} else {
356176434Skaiw	    printf(" - only one type (true/edge)\n");
357176434Skaiw	}
358176434Skaiw	break;
359176434Skaiw    case DMA_FORMAT:
360176434Skaiw	printf("    DMA: channel(s) ");
361176434Skaiw	for (i = 0; i < 8; i++)
362176434Skaiw	    if (resinfo[0] & (1<<i))
363176434Skaiw		printf("%d ", i);
364176434Skaiw	printf ("\n");
365176434Skaiw	report_dma_info (resinfo[1]);
366176434Skaiw	break;
367248612Smm    case START_DEPEND_FUNC:
368183218Skaiw	printf("TAG Start DF\n");
369176434Skaiw	if (len == 1) {
370183218Skaiw	    switch (resinfo[0]) {
371183218Skaiw	    case 0:
372183218Skaiw		printf("Good Configuration\n");
373183218Skaiw		break;
374183218Skaiw	    case 1:
375183218Skaiw		printf("Acceptable Configuration\n");
376183218Skaiw		break;
377183218Skaiw	    case 2:
378183218Skaiw		printf("Sub-optimal Configuration\n");
379183218Skaiw		break;
380183218Skaiw	    }
381183218Skaiw	}
382183218Skaiw	break;
383183218Skaiw    case END_DEPEND_FUNC:
384183218Skaiw	printf("TAG End DF\n");
385183218Skaiw	break;
386183218Skaiw    case IO_PORT_DESC:
387176434Skaiw	printf("    I/O Range 0x%x .. 0x%x, alignment 0x%x, len 0x%x\n",
388183218Skaiw	    resinfo[1] + (resinfo[2] << 8),
389183218Skaiw	    resinfo[3] + (resinfo[4] << 8),
390183218Skaiw	    resinfo[5], resinfo[6] );
391183218Skaiw	if (resinfo[0])
392183218Skaiw	    printf("\t[16-bit addr]\n");
393183218Skaiw	else
394183218Skaiw	    printf("\t[not 16-bit addr]\n");
395183218Skaiw	break;
396183218Skaiw    case FIXED_IO_PORT_DESC:
397183218Skaiw	printf ("    FIXED I/O base address 0x%x length 0x%x\n",
398183218Skaiw	    resinfo[0] + ( (resinfo[1] & 3 ) << 8), /* XXX */
399183218Skaiw	    resinfo[2]);
400183218Skaiw	break;
401183218Skaiw#ifdef DIAGNOSTIC
402183218Skaiw    case SM_RES_RESERVED:
403183218Skaiw	printf("Reserved Tag Detected\n");
404183218Skaiw	break;
405183218Skaiw#endif
406183218Skaiw    case SM_VENDOR_DEFINED:
407183218Skaiw	printf("*** Small Vendor Tag Detected\n");
408183218Skaiw	break;
409183218Skaiw    case END_TAG:
410183218Skaiw	printf("End Tag\n\n");
411183218Skaiw	/* XXX Record and Verify Checksum */
412183218Skaiw	return 1;
413183218Skaiw	break;
414183218Skaiw    }
415183218Skaiw    return 0;
416183218Skaiw}
417176434Skaiw
418176434Skaiw
419176434Skaiwvoid
420176434Skaiwhandle_large_res(u_char *resinfo, int item, int len)
421176434Skaiw{
422176434Skaiw    int i;
423177064Skaiw
424177064Skaiw    DEB(printf("*** Large ITEM %d len %d found\n", item, len));
425177064Skaiw    switch (item) {
426177064Skaiw    case MEMORY_RANGE_DESC:
427177064Skaiw	report_memory_info(resinfo[0]);
428177064Skaiw	printf("Memory range minimum address: 0x%x\n",
429177064Skaiw		(resinfo[1] << 8) + (resinfo[2] << 16));
430177064Skaiw	printf("Memory range maximum address: 0x%x\n",
431183218Skaiw		(resinfo[3] << 8) + (resinfo[4] << 16));
432183218Skaiw	printf("Memory range base alignment: 0x%x\n",
433183218Skaiw		(i = (resinfo[5] + (resinfo[6] << 8))) ? i : (1 << 16));
434183218Skaiw	printf("Memory range length: 0x%x\n",
435183218Skaiw		(resinfo[7] + (resinfo[8] << 8)) * 256);
436183218Skaiw	break;
437183218Skaiw    case ID_STRING_ANSI:
438183218Skaiw	printf("Device Description: ");
439222122Sbcr
440183218Skaiw	for (i = 0; i < len; i++) {
441183218Skaiw	    if (resinfo[i]) /* XXX */
442183218Skaiw		printf("%c", resinfo[i]);
443183218Skaiw	}
444183218Skaiw	printf("\n");
445183218Skaiw	break;
446183218Skaiw    case ID_STRING_UNICODE:
447176434Skaiw	printf("ID String Unicode Detected (Undefined)\n");
448176434Skaiw	break;
449176434Skaiw    case LG_VENDOR_DEFINED:
450176434Skaiw	printf("Large Vendor Defined Detected\n");
451176434Skaiw	break;
452176434Skaiw    case _32BIT_MEM_RANGE_DESC:
453176434Skaiw	printf("32bit Memory Range Desc Unimplemented\n");
454176434Skaiw	break;
455176434Skaiw    case _32BIT_FIXED_LOC_DESC:
456176434Skaiw	printf("32bit Fixed Location Desc Unimplemented\n");
457176434Skaiw	break;
458176434Skaiw    case LG_RES_RESERVED:
459222122Sbcr	printf("Large Reserved Tag Detected\n");
460176434Skaiw	break;
461176434Skaiw    }
462176434Skaiw}
463176434Skaiw
464176434Skaiw
465176434Skaiw/*
466176434Skaiw * Dump all the information about configurations.
467176434Skaiw */
468176434Skaiwvoid
469176434Skaiwdump_resdata(u_char *data, int csn)
470176434Skaiw{
471176434Skaiw    int i, large_len;
472176434Skaiw
473176434Skaiw    u_char tag, *resinfo;
474176434Skaiw
475176434Skaiw    DDB(printf("\nCard assigned CSN #%d\n", csn));
476176434Skaiw    printf("Vendor ID %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n",
477176434Skaiw	    ((data[0] & 0x7c) >> 2) + 64,
478176434Skaiw	    (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64,
479176434Skaiw	    (data[1] & 0x1f) + 64, data[2], data[3],
480176434Skaiw	    *(int *)&(data[0]),
481176434Skaiw	    *(int *)&(data[4]));
482176434Skaiw
483176434Skaiw    pnp_write(SET_CSN, csn); /* Move this out of this function XXX */
484176434Skaiw    outb(_PNP_ADDRESS, STATUS);
485176434Skaiw
486176434Skaiw    /* Allows up to 1kb of Resource Info,  Should be plenty */
487176434Skaiw    for (i = 0; i < 1024; i++) {
488176434Skaiw	if (!get_resource_info(&tag, 1))
489176434Skaiw	    break;
490176434Skaiw
491176434Skaiw#define TYPE	(tag >> 7)
492176434Skaiw#define	S_ITEM	(tag >> 3)
493176434Skaiw#define S_LEN	(tag & 0x7)
494176434Skaiw#define	L_ITEM	(tag & 0x7f)
495224650Semaste
496224650Semaste	if (TYPE == 0) {
497176434Skaiw	    /* Handle small resouce data types */
498176434Skaiw
499176434Skaiw	    resinfo = malloc(S_LEN);
500176434Skaiw	    if (!get_resource_info(resinfo, S_LEN))
501176434Skaiw		break;
502176434Skaiw
503176434Skaiw	    if (handle_small_res(resinfo, S_ITEM, S_LEN) == 1)
504176434Skaiw		break;
505176434Skaiw	    free(resinfo);
506176434Skaiw	} else {
507176434Skaiw	    /* Handle large resouce data types */
508176434Skaiw
509176434Skaiw	    if (!get_resource_info((char *) &large_len, 2))
510176434Skaiw		break;
511176434Skaiw
512176434Skaiw	    resinfo = malloc(large_len);
513177064Skaiw	    if (!get_resource_info(resinfo, large_len))
514177064Skaiw		break;
515177064Skaiw
516176434Skaiw	    handle_large_res(resinfo, L_ITEM, large_len);
517176434Skaiw	    free(resinfo);
518176434Skaiw	}
519177064Skaiw    }
520176434Skaiw    printf("Successfully got %d resources, %d logical fdevs\n", i,
521176434Skaiw	    logdevs);
522176434Skaiw    printf("-- card select # 0x%04x\n", pnp_read(SET_CSN));
523176434Skaiw    printf("\nCSN %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n",
524176434Skaiw	    ((data[0] & 0x7c) >> 2) + 64,
525176434Skaiw	    (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64,
526176434Skaiw	    (data[1] & 0x1f) + 64, data[2], data[3],
527176434Skaiw	    *(int *)&(data[0]),
528176434Skaiw	    *(int *)&(data[4]));
529176434Skaiw
530176434Skaiw    for (i=0; i<logdevs; i++) {
531176434Skaiw	int j;
532176434Skaiw
533176434Skaiw	pnp_write(SET_LDN, i);
534176434Skaiw
535176434Skaiw	printf("\nLogical device #%d\n", pnp_read(SET_LDN) );
536176434Skaiw	printf("IO: ");
537176434Skaiw	for (j=0; j<8; j++)
538176434Skaiw	    printf(" 0x%04x", pnp_readw(IO_CONFIG_BASE + j*2));
539176434Skaiw	printf("\nIRQ %d %d\n",
540176434Skaiw	    pnp_read(IRQ_CONFIG), pnp_read(IRQ_CONFIG+2) );
541176434Skaiw	printf("DMA %d %d\n",
542176434Skaiw	    pnp_read(DRQ_CONFIG), pnp_read(DRQ_CONFIG+1) );
543176434Skaiw	printf("IO range check 0x%02x activate 0x%02x\n",
544224650Semaste	    pnp_read(IO_RANGE_CHECK), pnp_read(ACTIVATE) );
545176434Skaiw    }
546176434Skaiw}
547176434Skaiw
548176434Skaiw
549176434Skaiw/*
550176434Skaiw * Run the isolation protocol. Use rd_port as the READ_DATA port
551176434Skaiw * value (caller should try multiple READ_DATA locations before giving
552176434Skaiw * up). Upon exiting, all cards are aware that they should use rd_port
553176434Skaiw * as the READ_DATA port;
554176434Skaiw *
555176434Skaiw */
556285224Semasteint
557285224Semasteisolation_protocol()
558285224Semaste{
559285224Semaste    int csn;
560285224Semaste    u_char data[9];
561285224Semaste
562285224Semaste    send_Initiation_LFSR();
563285224Semaste
564285224Semaste    /* Reset CSN for All Cards */
565285224Semaste    pnp_write(CONFIG_CONTROL, 0x04);
566285224Semaste
567285224Semaste    for (csn = 1; (csn < MAX_PNP_CARDS); csn++) {
568285224Semaste	/* Wake up cards without a CSN */
569285224Semaste	logdevs = 0 ;
570285224Semaste	pnp_write(WAKE, 0);
571285224Semaste	pnp_write(SET_RD_DATA, rd_port);
572285224Semaste	outb(_PNP_ADDRESS, SERIAL_ISOLATION);
573285224Semaste	DELAY(1000);	/* Delay 1 msec */
574285224Semaste
575285224Semaste	if (get_serial(data))
576285224Semaste	    dump_resdata(data, csn);
577285224Semaste	else
578285224Semaste	    break;
579176434Skaiw    }
580176434Skaiw    return csn - 1;
581176434Skaiw}
582176434Skaiw
583176434Skaiw
584285224Semastevoid
585176434Skaiwmain()
586176434Skaiw{
587176434Skaiw    int num_pnp_devs;
588176434Skaiw
589176434Skaiw    /* Hey what about a i386_iopl() call :) */
590176434Skaiw    if (open("/dev/io", O_RDONLY) < 0) {
591176434Skaiw	fprintf (stderr, "pnpinfo: Can't get I/O privilege.\n");
592176434Skaiw	exit (1);
593176434Skaiw    }
594176434Skaiw    printf("Checking for Plug-n-Play devices...\n");
595176434Skaiw
596176434Skaiw    /* Try various READ_DATA ports from 0x203-0x3ff */
597176434Skaiw    for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) {
598176434Skaiw	DEB(printf("Trying Read_Port at %x...\n", (rd_port << 2) | 0x3) );
599176434Skaiw	num_pnp_devs = isolation_protocol(rd_port);
600176434Skaiw	if (num_pnp_devs)
601176434Skaiw	    break;
602176434Skaiw    }
603176434Skaiw    if (!num_pnp_devs) {
604176434Skaiw	printf("No Plug-n-Play devices were found\n");
605176434Skaiw	return;
606176434Skaiw    }
607176434Skaiw}
608176434Skaiw