2 * Copyright (c) 1996, Sujal M. Patel
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/contrib/pnpinfo/pnpinfo.c,v 1.7 1999/09/05 17:27:05 peter Exp $
27 * $DragonFly: src/contrib/pnpinfo/pnpinfo.c,v 1.3 2003/08/08 04:18:31 dillon Exp $
38 #include <machine/cpufunc.h>
40 #include <bus/isa/pnpreg.h>
50 pnp_write(int d
, u_char r
)
52 outb (_PNP_ADDRESS
, d
);
53 outb (_PNP_WRITE_DATA
, r
);
56 /* The READ_DATA port that we are using currently */
62 outb(_PNP_ADDRESS
, d
);
63 return inb( (rd_port
<< 2) + 3) & 0xff;
69 int c
= pnp_read(d
) << 8 ;
76 void DELAY
__P((int i
));
77 void send_Initiation_LFSR();
78 int get_serial
__P((u_char
*data
));
79 int get_resource_info
__P((u_char
*buffer
, int len
));
80 int handle_small_res
__P((u_char
*resinfo
, int item
, int len
));
81 void handle_large_res
__P((u_char
*resinfo
, int item
, int len
));
82 void dump_resdata
__P((u_char
*data
, int csn
));
83 int isolation_protocol();
87 * DELAY does accurate delaying in user-space.
88 * This function busy-waits.
98 gettimeofday (&t
, NULL
);
99 start
= t
.tv_sec
* 1000000 + t
.tv_usec
;
101 gettimeofday (&t
, NULL
);
102 stop
= t
.tv_sec
* 1000000 + t
.tv_usec
;
103 } while (start
+ i
> stop
);
108 * Send Initiation LFSR as described in "Plug and Play ISA Specification,
112 send_Initiation_LFSR()
116 pnp_write(PNP_CONFIG_CONTROL
, 0x2);
119 outb(_PNP_ADDRESS
, 0);
120 outb(_PNP_ADDRESS
, 0); /* yes, we do need it twice! */
124 for (i
= 0; i
< 32; i
++) {
125 outb(_PNP_ADDRESS
, cur
);
126 cur
= (cur
>> 1) | (((cur
^ (cur
>> 1)) << 7) & 0xff);
131 * Get the device's serial number. Returns 1 if the serial is valid.
134 get_serial(u_char
*data
)
136 int i
, bit
, valid
= 0, sum
= 0x6a;
138 bzero(data
, sizeof(char) * 9);
140 for (i
= 0; i
< 72; i
++) {
141 bit
= inb((rd_port
<< 2) | 0x3) == 0x55;
142 DELAY(250); /* Delay 250 usec */
144 /* Can't Short Circuit the next evaluation, so 'and' is last */
145 bit
= (inb((rd_port
<< 2) | 0x3) == 0xaa) && bit
;
146 DELAY(250); /* Delay 250 usec */
148 valid
= valid
|| bit
;
152 (((sum
^ (sum
>> 1) ^ bit
) << 7) & 0xff);
154 data
[i
/ 8] = (data
[i
/ 8] >> 1) | (bit
? 0x80 : 0);
157 valid
= valid
&& (data
[8] == sum
);
164 * Fill's the buffer with resource info from the device.
165 * Returns 0 if the device fails to report
168 get_resource_info(u_char
*buffer
, int len
)
172 for (i
= 0; i
< len
; i
++) {
173 outb(_PNP_ADDRESS
, PNP_STATUS
);
174 for (j
= 0; j
< 100; j
++) {
175 if ((inb((rd_port
<< 2) | 0x3)) & 0x1)
180 printf("PnP device failed to report resource data\n");
183 outb(_PNP_ADDRESS
, PNP_RESOURCE_DATA
);
184 buffer
[i
] = inb((rd_port
<< 2) | 0x3);
185 DEB(printf("--- get_resource_info: got 0x%02x\n",(unsigned)buffer
[i
]));
194 char *s1
=NULL
, *s2
=NULL
, *s3
=NULL
, *s4
=NULL
, *s5
=NULL
;
213 s2
= (x
& 0x4) ? "bus master" : "not a bus master";
215 s3
= (x
& 0x8) ? "count by byte" : "";
217 s4
= (x
& 0x10) ? "count by word" : "";
219 switch ((x
& 0x60) >> 5) {
221 s5
="Compatibility mode";
233 printf("\t%s, %s, %s, %s, %s\n",s1
,s2
,s3
,s4
,s5
);
238 report_memory_info (int x
)
241 printf ("Memory Range: Writeable\n");
243 printf ("Memory Range: Not writeable (ROM)\n");
246 printf ("Memory Range: Read-cacheable, write-through\n");
248 printf ("Memory Range: Non-cacheable\n");
251 printf ("Memory Range: Decode supports high address\n");
253 printf ("Memory Range: Decode supports range length\n");
255 switch ((x
& 0x18) >> 3) {
257 printf ("Memory Range: 8-bit memory only\n");
260 printf ("Memory Range: 16-bit memory only\n");
263 printf ("Memory Range: 8-bit and 16-bit memory supported\n");
267 printf ("Memory Range: Reserved\n");
273 printf ("Memory Range: Memory is shadowable\n");
275 printf ("Memory Range: Memory is not shadowable\n");
278 printf ("Memory Range: Memory is an expansion ROM\n");
280 printf ("Memory Range: Memory is not an expansion ROM\n");
284 printf ("Memory Range: Reserved (Device is brain-damaged)\n");
290 * Small Resource Tag Handler
292 * Returns 1 if checksum was valid (and an END_TAG was received).
293 * Returns -1 if checksum was invalid (and an END_TAG was received).
294 * Returns 0 for other tags.
297 handle_small_res(u_char
*resinfo
, int item
, int len
)
301 DEB(printf("*** ITEM 0x%04x len %d detected\n", item
, len
));
305 printf("*** ITEM 0x%02x detected\n", item
);
307 case PNP_TAG_VERSION
:
308 printf("PnP Version %d.%d, Vendor Version %d\n",
309 resinfo
[0] >> 4, resinfo
[0] & (0xf), resinfo
[1]);
311 case PNP_TAG_LOGICAL_DEVICE
:
312 printf("\nLogical Device ID: %c%c%c%02x%02x 0x%08x #%d\n",
313 ((resinfo
[0] & 0x7c) >> 2) + 64,
314 (((resinfo
[0] & 0x03) << 3) |
315 ((resinfo
[1] & 0xe0) >> 5)) + 64,
316 (resinfo
[1] & 0x1f) + 64,
317 resinfo
[2], resinfo
[3], *(int *)(resinfo
),
320 if (resinfo
[4] & 0x1)
321 printf ("\tDevice powers up active\n"); /* XXX */
322 if (resinfo
[4] & 0x2)
323 printf ("\tDevice supports I/O Range Check\n");
324 if (resinfo
[4] > 0x3)
325 printf ("\tReserved register funcs %02x\n",
329 printf("\tVendor register funcs %02x\n", resinfo
[5]);
331 case PNP_TAG_COMPAT_DEVICE
:
332 printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n",
333 ((resinfo
[0] & 0x7c) >> 2) + 64,
334 (((resinfo
[0] & 0x03) << 3) |
335 ((resinfo
[1] & 0xe0) >> 5)) + 64,
336 (resinfo
[1] & 0x1f) + 64,
337 resinfo
[2], resinfo
[3], *(int *)resinfo
);
339 case PNP_TAG_IRQ_FORMAT
:
342 for (i
= 0; i
< 8; i
++)
343 if (resinfo
[0] & (1<<i
))
345 for (i
= 0; i
< 8; i
++)
346 if (resinfo
[1] & (1<<i
))
347 printf("%d ", i
+ 8);
349 if (resinfo
[2] & 0x1)
350 printf("IRQ: High true edge sensitive\n");
351 if (resinfo
[2] & 0x2)
352 printf("IRQ: Low true edge sensitive\n");
353 if (resinfo
[2] & 0x4)
354 printf("IRQ: High true level sensitive\n");
355 if (resinfo
[2] & 0x8)
356 printf("IRQ: Low true level sensitive\n");
358 printf(" - only one type (true/edge)\n");
361 case PNP_TAG_DMA_FORMAT
:
362 printf(" DMA: channel(s) ");
363 for (i
= 0; i
< 8; i
++)
364 if (resinfo
[0] & (1<<i
))
367 report_dma_info (resinfo
[1]);
369 case PNP_TAG_START_DEPENDANT
:
370 printf("TAG Start DF\n");
372 switch (resinfo
[0]) {
374 printf("Good Configuration\n");
377 printf("Acceptable Configuration\n");
380 printf("Sub-optimal Configuration\n");
385 case PNP_TAG_END_DEPENDANT
:
386 printf("TAG End DF\n");
388 case PNP_TAG_IO_RANGE
:
389 printf(" I/O Range 0x%x .. 0x%x, alignment 0x%x, len 0x%x\n",
390 resinfo
[1] + (resinfo
[2] << 8),
391 resinfo
[3] + (resinfo
[4] << 8),
392 resinfo
[5], resinfo
[6] );
394 printf("\t[16-bit addr]\n");
396 printf("\t[not 16-bit addr]\n");
398 case PNP_TAG_IO_FIXED
:
399 printf (" FIXED I/O base address 0x%x length 0x%x\n",
400 resinfo
[0] + ( (resinfo
[1] & 3 ) << 8), /* XXX */
404 case PNP_TAG_RESERVED
:
405 printf("Reserved Tag Detected\n");
409 printf("*** Small Vendor Tag Detected\n");
412 printf("End Tag\n\n");
413 /* XXX Record and Verify Checksum */
422 handle_large_res(u_char
*resinfo
, int item
, int len
)
426 DEB(printf("*** Large ITEM %d len %d found\n", item
, len
));
428 case PNP_TAG_MEMORY_RANGE
:
429 report_memory_info(resinfo
[0]);
430 printf("Memory range minimum address: 0x%x\n",
431 (resinfo
[1] << 8) + (resinfo
[2] << 16));
432 printf("Memory range maximum address: 0x%x\n",
433 (resinfo
[3] << 8) + (resinfo
[4] << 16));
434 printf("Memory range base alignment: 0x%x\n",
435 (i
= (resinfo
[5] + (resinfo
[6] << 8))) ? i
: (1 << 16));
436 printf("Memory range length: 0x%x\n",
437 (resinfo
[7] + (resinfo
[8] << 8)) * 256);
439 case PNP_TAG_ID_ANSI
:
440 printf("Device Description: ");
442 for (i
= 0; i
< len
; i
++) {
443 if (resinfo
[i
]) /* XXX */
444 printf("%c", resinfo
[i
]);
448 case PNP_TAG_ID_UNICODE
:
449 printf("ID String Unicode Detected (Undefined)\n");
451 case PNP_TAG_LARGE_VENDOR
:
452 printf("Large Vendor Defined Detected\n");
454 case PNP_TAG_MEMORY32_RANGE
:
455 printf("32bit Memory Range Desc Unimplemented\n");
457 case PNP_TAG_MEMORY32_FIXED
:
458 printf("32bit Fixed Location Desc Unimplemented\n");
461 case PNP_TAG_LARGE_RESERVED
:
462 printf("Large Reserved Tag Detected\n");
470 * Dump all the information about configurations.
473 dump_resdata(u_char
*data
, int csn
)
477 u_char tag
, *resinfo
;
479 DDB(printf("\nCard assigned CSN #%d\n", csn
));
480 printf("Vendor ID %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n",
481 ((data
[0] & 0x7c) >> 2) + 64,
482 (((data
[0] & 0x03) << 3) | ((data
[1] & 0xe0) >> 5)) + 64,
483 (data
[1] & 0x1f) + 64, data
[2], data
[3],
487 pnp_write(PNP_SET_CSN
, csn
); /* Move this out of this function XXX */
488 outb(_PNP_ADDRESS
, PNP_STATUS
);
490 /* Allows up to 1kb of Resource Info, Should be plenty */
491 for (i
= 0; i
< 1024; i
++) {
492 if (!get_resource_info(&tag
, 1))
495 if (PNP_RES_TYPE(tag
) == 0) {
496 /* Handle small resouce data types */
498 resinfo
= malloc(PNP_SRES_LEN(tag
));
499 if (!get_resource_info(resinfo
, PNP_SRES_LEN(tag
)))
502 if (handle_small_res(resinfo
, PNP_SRES_NUM(tag
), PNP_SRES_LEN(tag
)) == 1)
506 /* Handle large resouce data types */
508 if (!get_resource_info((char *)buf
, 2))
510 large_len
= (buf
[1] << 8) + buf
[0];
512 resinfo
= malloc(large_len
);
513 if (!get_resource_info(resinfo
, large_len
))
516 handle_large_res(resinfo
, PNP_LRES_NUM(tag
), large_len
);
520 printf("Successfully got %d resources, %d logical fdevs\n", i
,
522 printf("-- card select # 0x%04x\n", pnp_read(PNP_SET_CSN
));
523 printf("\nCSN %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n",
524 ((data
[0] & 0x7c) >> 2) + 64,
525 (((data
[0] & 0x03) << 3) | ((data
[1] & 0xe0) >> 5)) + 64,
526 (data
[1] & 0x1f) + 64, data
[2], data
[3],
530 for (i
=0; i
<logdevs
; i
++) {
533 pnp_write(PNP_SET_LDN
, i
);
535 printf("\nLogical device #%d\n", pnp_read(PNP_SET_LDN
) );
538 printf(" 0x%02x%02x", pnp_read(PNP_IO_BASE_HIGH(i
)),
539 pnp_read(PNP_IO_BASE_LOW(i
)));
540 printf("\nIRQ %d %d\n",
541 pnp_read(PNP_IRQ_LEVEL(0)), pnp_read(PNP_IRQ_LEVEL(1)) );
542 printf("DMA %d %d\n",
543 pnp_read(PNP_DMA_CHANNEL(0)), pnp_read(PNP_DMA_CHANNEL(1)) );
544 printf("IO range check 0x%02x activate 0x%02x\n",
545 pnp_read(PNP_IO_RANGE_CHECK
), pnp_read(PNP_ACTIVATE
) );
551 * Run the isolation protocol. Use rd_port as the READ_DATA port
552 * value (caller should try multiple READ_DATA locations before giving
553 * up). Upon exiting, all cards are aware that they should use rd_port
554 * as the READ_DATA port;
563 send_Initiation_LFSR();
565 /* Reset CSN for All Cards */
566 pnp_write(PNP_CONFIG_CONTROL
, 0x04);
568 for (csn
= 1; (csn
< PNP_MAX_CARDS
); csn
++) {
569 /* Wake up cards without a CSN */
571 pnp_write(PNP_WAKE
, 0);
572 pnp_write(PNP_SET_RD_DATA
, rd_port
);
573 outb(_PNP_ADDRESS
, PNP_SERIAL_ISOLATION
);
574 DELAY(1000); /* Delay 1 msec */
576 if (get_serial(data
))
577 dump_resdata(data
, csn
);
586 main(int argc
, char **argv
)
591 /* Hey what about a i386_iopl() call :) */
592 if (open("/dev/io", O_RDONLY
) < 0) {
593 fprintf (stderr
, "pnpinfo: Can't get I/O privilege.\n");
598 ioperm(0x203, 0x400 - 0x203, 1);
601 printf("Checking for Plug-n-Play devices...\n");
603 /* Try various READ_DATA ports from 0x203-0x3ff */
604 for (rd_port
= 0x80; (rd_port
< 0xff); rd_port
+= 0x10) {
605 DEB(printf("Trying Read_Port at %x...\n", (rd_port
<< 2) | 0x3) );
606 num_pnp_devs
= isolation_protocol(rd_port
);
611 printf("No Plug-n-Play devices were found\n");