pnpinfo.c revision 50786
1279377Simp/*
2279377Simp * Copyright (c) 1996, Sujal M. Patel
3279377Simp * All rights reserved.
4279377Simp *
5279377Simp * Redistribution and use in source and binary forms, with or without
6279377Simp * modification, are permitted provided that the following conditions
7279377Simp * are met:
8279377Simp * 1. Redistributions of source code must retain the above copyright
9279377Simp *    notice, this list of conditions and the following disclaimer.
10279377Simp * 2. Redistributions in binary form must reproduce the above copyright
11279377Simp *    notice, this list of conditions and the following disclaimer in the
12279377Simp *    documentation and/or other materials provided with the distribution.
13279377Simp *
14279377Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15279377Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16279377Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17279377Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18279377Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19279377Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20279377Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21279377Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22279377Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23279377Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24279377Simp * SUCH DAMAGE.
25279377Simp *
26279377Simp *      $Id: pnpinfo.c,v 1.5 1999/05/22 17:35:43 dfr Exp $
27279377Simp */
28279377Simp
29279377Simp#include <sys/time.h>
30279377Simp
31279377Simp#include <stdio.h>
32279377Simp#include <stdlib.h>
33279377Simp#include <unistd.h>
34279377Simp#include <fcntl.h>
35279377Simp#include <string.h>
36279377Simp
37279377Simp#include <machine/cpufunc.h>
38279377Simp
39279377Simp#include <isa/pnpreg.h>
40279377Simp
41279377Simp#ifdef DEBUG
42279377Simp#define	DEB(x) x
43279377Simp#else
44279377Simp#define DEB(x)
45279377Simp#endif
46279377Simp#define DDB(x) x
47279377Simp
48279377Simpvoid
49279377Simppnp_write(int d, u_char r)
50279377Simp{
51279377Simp    outb (_PNP_ADDRESS, d);
52279377Simp    outb (_PNP_WRITE_DATA, r);
53279377Simp}
54279377Simp
55279377Simp/* The READ_DATA port that we are using currently */
56279377Simpstatic int rd_port;
57279377Simp
58279377Simpu_char
59279377Simppnp_read(int d)
60279377Simp{
61279377Simp    outb(_PNP_ADDRESS, d);
62279377Simp    return inb( (rd_port << 2) + 3) & 0xff;
63279377Simp}
64279377Simp
65279377Simpu_short
66279377Simppnp_readw(int d)
67279377Simp{
68279377Simp    int c = pnp_read(d) << 8 ;
69279377Simp    c |= pnp_read(d+1);
70279377Simp    return c;
71279377Simp}
72279377Simp
73279377Simpint logdevs=0;
74279377Simp
75279377Simpvoid DELAY __P((int i));
76279377Simpvoid send_Initiation_LFSR();
77279377Simpint get_serial __P((u_char *data));
78279377Simpint get_resource_info __P((u_char *buffer, int len));
79279377Simpint handle_small_res __P((u_char *resinfo, int item, int len));
80279377Simpvoid handle_large_res __P((u_char *resinfo, int item, int len));
81279377Simpvoid dump_resdata __P((u_char *data, int csn));
82279377Simpint isolation_protocol();
83279377Simp
84279377Simp
85279377Simp/*
86279377Simp * DELAY does accurate delaying in user-space.
87279377Simp * This function busy-waits.
88279377Simp */
89279377Simpvoid
90279377SimpDELAY (int i)
91279377Simp{
92279377Simp    struct timeval t;
93279377Simp    long start, stop;
94279377Simp
95279377Simp    i *= 4;
96279377Simp
97279377Simp    gettimeofday (&t, NULL);
98279377Simp    start = t.tv_sec * 1000000 + t.tv_usec;
99279377Simp    do {
100279377Simp	gettimeofday (&t, NULL);
101279377Simp	stop = t.tv_sec * 1000000 + t.tv_usec;
102279377Simp    } while (start + i > stop);
103279377Simp}
104279377Simp
105279377Simp
106279377Simp/*
107279377Simp * Send Initiation LFSR as described in "Plug and Play ISA Specification,
108279377Simp * Intel May 94."
109279377Simp */
110279377Simpvoid
111279377Simpsend_Initiation_LFSR()
112279377Simp{
113279377Simp    int cur, i;
114279377Simp
115279377Simp    pnp_write(PNP_CONFIG_CONTROL, 0x2);
116279377Simp
117279377Simp    /* Reset the LSFR */
118279377Simp    outb(_PNP_ADDRESS, 0);
119279377Simp    outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */
120279377Simp
121279377Simp    cur = 0x6a;
122279377Simp
123279377Simp    for (i = 0; i < 32; i++) {
124279377Simp	outb(_PNP_ADDRESS, cur);
125279377Simp	cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
126279377Simp    }
127279377Simp}
128279377Simp
129279377Simp/*
130279377Simp * Get the device's serial number.  Returns 1 if the serial is valid.
131279377Simp */
132279377Simpint
133279377Simpget_serial(u_char *data)
134279377Simp{
135279377Simp    int i, bit, valid = 0, sum = 0x6a;
136279377Simp
137279377Simp    bzero(data, sizeof(char) * 9);
138279377Simp
139279377Simp    for (i = 0; i < 72; i++) {
140279377Simp	bit = inb((rd_port << 2) | 0x3) == 0x55;
141279377Simp	DELAY(250);	/* Delay 250 usec */
142279377Simp
143279377Simp	/* Can't Short Circuit the next evaluation, so 'and' is last */
144279377Simp	bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit;
145279377Simp	DELAY(250);	/* Delay 250 usec */
146279377Simp
147279377Simp	valid = valid || bit;
148279377Simp
149279377Simp	if (i < 64)
150279377Simp	    sum = (sum >> 1) |
151279377Simp		(((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
152279377Simp
153279377Simp	data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
154279377Simp    }
155279377Simp
156279377Simp    valid = valid && (data[8] == sum);
157279377Simp
158279377Simp    return valid;
159279377Simp}
160279377Simp
161279377Simp
162279377Simp/*
163279377Simp * Fill's the buffer with resource info from the device.
164279377Simp * Returns 0 if the device fails to report
165279377Simp */
166279377Simpint
167279377Simpget_resource_info(u_char *buffer, int len)
168279377Simp{
169279377Simp    int i, j;
170279377Simp
171279377Simp    for (i = 0; i < len; i++) {
172279377Simp	outb(_PNP_ADDRESS, PNP_STATUS);
173279377Simp	for (j = 0; j < 100; j++) {
174279377Simp	    if ((inb((rd_port << 2) | 0x3)) & 0x1)
175279377Simp		break;
176279377Simp	    DELAY(1);
177279377Simp	}
178279377Simp	if (j == 100) {
179279377Simp	    printf("PnP device failed to report resource data\n");
180279377Simp	    return 0;
181279377Simp	}
182279377Simp	outb(_PNP_ADDRESS, PNP_RESOURCE_DATA);
183279377Simp	buffer[i] = inb((rd_port << 2) | 0x3);
184279377Simp	DEB(printf("--- get_resource_info: got 0x%02x\n",(unsigned)buffer[i]));
185279377Simp    }
186279377Simp    return 1;
187279377Simp}
188279377Simp
189279377Simpvoid
190279377Simpreport_dma_info (x)
191279377Simp	int x;
192279377Simp{
193279377Simp    char *s1=NULL, *s2=NULL, *s3=NULL, *s4=NULL, *s5=NULL;
194279377Simp
195279377Simp    switch (x & 0x3) {
196279377Simp    case 0:
197279377Simp	s1="8-bit";
198279377Simp	break;
199279377Simp    case 1:
200279377Simp	s1="8/16-bit";
201279377Simp	break;
202279377Simp    case 2:
203279377Simp	s1="16-bit";
204279377Simp	break;
205279377Simp#ifdef DIAGNOSTIC
206279377Simp    case 3:
207279377Simp	s1="Reserved";
208279377Simp	break;
209279377Simp#endif
210279377Simp    }
211279377Simp
212279377Simp    s2 = (x & 0x4) ? "bus master" : "not a bus master";
213279377Simp
214279377Simp    s3 = (x & 0x8) ? "count by byte" : "";
215279377Simp
216279377Simp    s4 = (x & 0x10) ? "count by word" : "";
217279377Simp
218279377Simp    switch ((x & 0x60) >> 5) {
219279377Simp    case 0:
220279377Simp	s5="Compatibility mode";
221279377Simp	break;
222279377Simp    case 1:
223279377Simp	s5="Type A";
224279377Simp	break;
225279377Simp    case 2:
226279377Simp	s5="Type B";
227279377Simp	break;
228279377Simp    case 3:
229279377Simp	s5="Type F";
230279377Simp	break;
231279377Simp    }
232279377Simp    printf("\t%s, %s, %s, %s, %s\n",s1,s2,s3,s4,s5);
233279377Simp}
234279377Simp
235279377Simp
236279377Simpvoid
237279377Simpreport_memory_info (int x)
238279377Simp{
239279377Simp    if (x & 0x1)
240279377Simp	printf ("Memory Range: Writeable\n");
241279377Simp    else
242279377Simp	printf ("Memory Range: Not writeable (ROM)\n");
243279377Simp
244279377Simp    if (x & 0x2)
245279377Simp	printf ("Memory Range: Read-cacheable, write-through\n");
246279377Simp    else
247279377Simp	printf ("Memory Range: Non-cacheable\n");
248279377Simp
249279377Simp    if (x & 0x4)
250279377Simp	printf ("Memory Range: Decode supports high address\n");
251279377Simp    else
252279377Simp	printf ("Memory Range: Decode supports range length\n");
253279377Simp
254279377Simp    switch ((x & 0x18) >> 3) {
255279377Simp    case 0:
256279377Simp	printf ("Memory Range: 8-bit memory only\n");
257279377Simp	break;
258279377Simp    case 1:
259279377Simp	printf ("Memory Range: 16-bit memory only\n");
260279377Simp	break;
261279377Simp    case 2:
262279377Simp	printf ("Memory Range: 8-bit and 16-bit memory supported\n");
263279377Simp	break;
264279377Simp#ifdef DIAGNOSTIC
265279377Simp    case 3:
266279377Simp	printf ("Memory Range: Reserved\n");
267279377Simp	break;
268279377Simp#endif
269279377Simp    }
270279377Simp
271279377Simp    if (x & 0x20)
272279377Simp	printf ("Memory Range: Memory is shadowable\n");
273279377Simp    else
274279377Simp	printf ("Memory Range: Memory is not shadowable\n");
275279377Simp
276279377Simp    if (x & 0x40)
277279377Simp	printf ("Memory Range: Memory is an expansion ROM\n");
278279377Simp    else
279279377Simp	printf ("Memory Range: Memory is not an expansion ROM\n");
280279377Simp
281279377Simp#ifdef DIAGNOSTIC
282279377Simp    if (x & 0x80)
283279377Simp	printf ("Memory Range: Reserved (Device is brain-damaged)\n");
284279377Simp#endif
285279377Simp}
286279377Simp
287279377Simp
288279377Simp/*
289279377Simp *  Small Resource Tag Handler
290279377Simp *
291279377Simp *  Returns 1 if checksum was valid (and an END_TAG was received).
292279377Simp *  Returns -1 if checksum was invalid (and an END_TAG was received).
293279377Simp *  Returns 0 for other tags.
294279377Simp */
295279377Simpint
296279377Simphandle_small_res(u_char *resinfo, int item, int len)
297279377Simp{
298279377Simp    int i;
299279377Simp
300279377Simp    DEB(printf("*** ITEM 0x%04x len %d detected\n", item, len));
301279377Simp
302279377Simp    switch (item) {
303279377Simp    default:
304279377Simp	printf("*** ITEM 0x%02x detected\n", item);
305279377Simp	break;
306279377Simp    case PNP_TAG_VERSION:
307279377Simp	printf("PnP Version %d.%d, Vendor Version %d\n",
308279377Simp	    resinfo[0] >> 4, resinfo[0] & (0xf), resinfo[1]);
309279377Simp	break;
310279377Simp    case PNP_TAG_LOGICAL_DEVICE:
311279377Simp	printf("\nLogical Device ID: %c%c%c%02x%02x 0x%08x #%d\n",
312279377Simp		((resinfo[0] & 0x7c) >> 2) + 64,
313279377Simp		(((resinfo[0] & 0x03) << 3) |
314279377Simp		((resinfo[1] & 0xe0) >> 5)) + 64,
315279377Simp		(resinfo[1] & 0x1f) + 64,
316279377Simp		resinfo[2], resinfo[3], *(int *)(resinfo),
317279377Simp		logdevs++);
318279377Simp
319279377Simp	if (resinfo[4] & 0x1)
320279377Simp	    printf ("\tDevice powers up active\n"); /* XXX */
321279377Simp	if (resinfo[4] & 0x2)
322279377Simp	    printf ("\tDevice supports I/O Range Check\n");
323279377Simp	if (resinfo[4] > 0x3)
324279377Simp	    printf ("\tReserved register funcs %02x\n",
325279377Simp		resinfo[4]);
326279377Simp
327279377Simp	if (len == 6)
328279377Simp	    printf("\tVendor register funcs %02x\n", resinfo[5]);
329279377Simp	break;
330279377Simp    case PNP_TAG_COMPAT_DEVICE:
331279377Simp	printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n",
332279377Simp		((resinfo[0] & 0x7c) >> 2) + 64,
333279377Simp		(((resinfo[0] & 0x03) << 3) |
334279377Simp		((resinfo[1] & 0xe0) >> 5)) + 64,
335279377Simp		(resinfo[1] & 0x1f) + 64,
336279377Simp		resinfo[2], resinfo[3], *(int *)resinfo);
337279377Simp	break;
338279377Simp    case PNP_TAG_IRQ_FORMAT:
339279377Simp	printf("    IRQ: ");
340279377Simp
341279377Simp	for (i = 0; i < 8; i++)
342279377Simp	    if (resinfo[0] & (1<<i))
343279377Simp		printf("%d ", i);
344279377Simp	for (i = 0; i < 8; i++)
345279377Simp	    if (resinfo[1] & (1<<i))
346279377Simp		printf("%d ", i + 8);
347279377Simp	if (len == 3) {
348279377Simp	    if (resinfo[2] & 0x1)
349279377Simp		printf("IRQ: High true edge sensitive\n");
350	    if (resinfo[2] & 0x2)
351		printf("IRQ: Low true edge sensitive\n");
352	    if (resinfo[2] & 0x4)
353		printf("IRQ: High true level sensitive\n");
354	    if (resinfo[2] & 0x8)
355		printf("IRQ: Low true level sensitive\n");
356	} else {
357	    printf(" - only one type (true/edge)\n");
358	}
359	break;
360    case PNP_TAG_DMA_FORMAT:
361	printf("    DMA: channel(s) ");
362	for (i = 0; i < 8; i++)
363	    if (resinfo[0] & (1<<i))
364		printf("%d ", i);
365	printf ("\n");
366	report_dma_info (resinfo[1]);
367	break;
368    case PNP_TAG_START_DEPENDANT:
369	printf("TAG Start DF\n");
370	if (len == 1) {
371	    switch (resinfo[0]) {
372	    case 0:
373		printf("Good Configuration\n");
374		break;
375	    case 1:
376		printf("Acceptable Configuration\n");
377		break;
378	    case 2:
379		printf("Sub-optimal Configuration\n");
380		break;
381	    }
382	}
383	break;
384    case PNP_TAG_END_DEPENDANT:
385	printf("TAG End DF\n");
386	break;
387    case PNP_TAG_IO_RANGE:
388	printf("    I/O Range 0x%x .. 0x%x, alignment 0x%x, len 0x%x\n",
389	    resinfo[1] + (resinfo[2] << 8),
390	    resinfo[3] + (resinfo[4] << 8),
391	    resinfo[5], resinfo[6] );
392	if (resinfo[0])
393	    printf("\t[16-bit addr]\n");
394	else
395	    printf("\t[not 16-bit addr]\n");
396	break;
397    case PNP_TAG_IO_FIXED:
398	printf ("    FIXED I/O base address 0x%x length 0x%x\n",
399	    resinfo[0] + ( (resinfo[1] & 3 ) << 8), /* XXX */
400	    resinfo[2]);
401	break;
402#ifdef DIAGNOSTIC
403    case PNP_TAG_RESERVED:
404	printf("Reserved Tag Detected\n");
405	break;
406#endif
407    case PNP_TAG_VENDOR:
408	printf("*** Small Vendor Tag Detected\n");
409	break;
410    case PNP_TAG_END:
411	printf("End Tag\n\n");
412	/* XXX Record and Verify Checksum */
413	return 1;
414	break;
415    }
416    return 0;
417}
418
419
420void
421handle_large_res(u_char *resinfo, int item, int len)
422{
423    int i;
424
425    DEB(printf("*** Large ITEM %d len %d found\n", item, len));
426    switch (item) {
427    case PNP_TAG_MEMORY_RANGE:
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 PNP_TAG_ID_ANSI:
439	printf("Device Description: ");
440
441	for (i = 0; i < len; i++) {
442	    if (resinfo[i]) /* XXX */
443		printf("%c", resinfo[i]);
444	}
445	printf("\n");
446	break;
447    case PNP_TAG_ID_UNICODE:
448	printf("ID String Unicode Detected (Undefined)\n");
449	break;
450    case PNP_TAG_LARGE_VENDOR:
451	printf("Large Vendor Defined Detected\n");
452	break;
453    case PNP_TAG_MEMORY32_RANGE:
454	printf("32bit Memory Range Desc Unimplemented\n");
455	break;
456    case PNP_TAG_MEMORY32_FIXED:
457	printf("32bit Fixed Location Desc Unimplemented\n");
458	break;
459#ifdef DIAGNOSTIC
460    case PNP_TAG_LARGE_RESERVED:
461	printf("Large Reserved Tag Detected\n");
462	break;
463#endif
464    }
465}
466
467
468/*
469 * Dump all the information about configurations.
470 */
471void
472dump_resdata(u_char *data, int csn)
473{
474    int i, large_len;
475
476    u_char tag, *resinfo;
477
478    DDB(printf("\nCard assigned CSN #%d\n", csn));
479    printf("Vendor ID %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\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	    *(int *)&(data[0]),
484	    *(int *)&(data[4]));
485
486    pnp_write(PNP_SET_CSN, csn); /* Move this out of this function XXX */
487    outb(_PNP_ADDRESS, PNP_STATUS);
488
489    /* Allows up to 1kb of Resource Info,  Should be plenty */
490    for (i = 0; i < 1024; i++) {
491	if (!get_resource_info(&tag, 1))
492	    break;
493
494	if (PNP_RES_TYPE(tag) == 0) {
495	    /* Handle small resouce data types */
496
497	    resinfo = malloc(PNP_SRES_LEN(tag));
498	    if (!get_resource_info(resinfo, PNP_SRES_LEN(tag)))
499		break;
500
501	    if (handle_small_res(resinfo, PNP_SRES_NUM(tag), PNP_SRES_LEN(tag)) == 1)
502		break;
503	    free(resinfo);
504	} else {
505	    /* Handle large resouce data types */
506	    u_char buf[2];
507	    if (!get_resource_info((char *)buf, 2))
508		break;
509	    large_len = (buf[1] << 8) + buf[0];
510
511	    resinfo = malloc(large_len);
512	    if (!get_resource_info(resinfo, large_len))
513		break;
514
515	    handle_large_res(resinfo, PNP_LRES_NUM(tag), large_len);
516	    free(resinfo);
517	}
518    }
519    printf("Successfully got %d resources, %d logical fdevs\n", i,
520	    logdevs);
521    printf("-- card select # 0x%04x\n", pnp_read(PNP_SET_CSN));
522    printf("\nCSN %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n",
523	    ((data[0] & 0x7c) >> 2) + 64,
524	    (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64,
525	    (data[1] & 0x1f) + 64, data[2], data[3],
526	    *(int *)&(data[0]),
527	    *(int *)&(data[4]));
528
529    for (i=0; i<logdevs; i++) {
530	int j;
531
532	pnp_write(PNP_SET_LDN, i);
533
534	printf("\nLogical device #%d\n", pnp_read(PNP_SET_LDN) );
535	printf("IO: ");
536	for (j=0; j<8; j++)
537	    printf(" 0x%02x%02x", pnp_read(PNP_IO_BASE_HIGH(i)),
538		pnp_read(PNP_IO_BASE_LOW(i)));
539	printf("\nIRQ %d %d\n",
540	    pnp_read(PNP_IRQ_LEVEL(0)), pnp_read(PNP_IRQ_LEVEL(1)) );
541	printf("DMA %d %d\n",
542	    pnp_read(PNP_DMA_CHANNEL(0)), pnp_read(PNP_DMA_CHANNEL(1)) );
543	printf("IO range check 0x%02x activate 0x%02x\n",
544	    pnp_read(PNP_IO_RANGE_CHECK), pnp_read(PNP_ACTIVATE) );
545    }
546}
547
548
549/*
550 * Run the isolation protocol. Use rd_port as the READ_DATA port
551 * value (caller should try multiple READ_DATA locations before giving
552 * up). Upon exiting, all cards are aware that they should use rd_port
553 * as the READ_DATA port;
554 *
555 */
556int
557isolation_protocol()
558{
559    int csn;
560    u_char data[9];
561
562    send_Initiation_LFSR();
563
564    /* Reset CSN for All Cards */
565    pnp_write(PNP_CONFIG_CONTROL, 0x04);
566
567    for (csn = 1; (csn < PNP_MAX_CARDS); csn++) {
568	/* Wake up cards without a CSN */
569	logdevs = 0 ;
570	pnp_write(PNP_WAKE, 0);
571	pnp_write(PNP_SET_RD_DATA, rd_port);
572	outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION);
573	DELAY(1000);	/* Delay 1 msec */
574
575	if (get_serial(data))
576	    dump_resdata(data, csn);
577	else
578	    break;
579    }
580    return csn - 1;
581}
582
583
584int
585main(int argc, char **argv)
586{
587    int num_pnp_devs;
588
589#ifdef __i386__
590    /* Hey what about a i386_iopl() call :) */
591    if (open("/dev/io", O_RDONLY) < 0) {
592	fprintf (stderr, "pnpinfo: Can't get I/O privilege.\n");
593	exit (1);
594    }
595#endif
596#ifdef __alpha__
597    ioperm(0x203, 0x400 - 0x203, 1);
598#endif
599
600    printf("Checking for Plug-n-Play devices...\n");
601
602    /* Try various READ_DATA ports from 0x203-0x3ff */
603    for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) {
604	DEB(printf("Trying Read_Port at %x...\n", (rd_port << 2) | 0x3) );
605	num_pnp_devs = isolation_protocol(rd_port);
606	if (num_pnp_devs)
607	    break;
608    }
609    if (!num_pnp_devs) {
610	printf("No Plug-n-Play devices were found\n");
611	return 0;
612    }
613}
614