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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
39 #include <machine/cpufunc.h>
41 #include <isa/pnpreg.h>
51 pnp_write(int d, u_char r)
53 outb (_PNP_ADDRESS, d);
54 outb (_PNP_WRITE_DATA, r);
57 /* The READ_DATA port that we are using currently */
63 outb(_PNP_ADDRESS, d);
64 return inb( (rd_port << 2) + 3) & 0xff;
70 int c = pnp_read(d) << 8 ;
77 void DELAY __P((int i));
78 void send_Initiation_LFSR();
79 int get_serial __P((u_char *data));
80 int get_resource_info __P((u_char *buffer, int len));
81 int handle_small_res __P((u_char *resinfo, int item, int len));
82 void handle_large_res __P((u_char *resinfo, int item, int len));
83 void dump_resdata __P((u_char *data, int csn));
84 int isolation_protocol();
88 * DELAY does accurate delaying in user-space.
89 * This function busy-waits.
99 gettimeofday (&t, NULL);
100 start = t.tv_sec * 1000000 + t.tv_usec;
102 gettimeofday (&t, NULL);
103 stop = t.tv_sec * 1000000 + t.tv_usec;
104 } while (start + i > stop);
109 * Send Initiation LFSR as described in "Plug and Play ISA Specification,
113 send_Initiation_LFSR()
117 pnp_write(PNP_CONFIG_CONTROL, 0x2);
120 outb(_PNP_ADDRESS, 0);
121 outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */
125 for (i = 0; i < 32; i++) {
126 outb(_PNP_ADDRESS, cur);
127 cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
132 * Get the device's serial number. Returns 1 if the serial is valid.
135 get_serial(u_char *data)
137 int i, bit, valid = 0, sum = 0x6a;
139 bzero(data, sizeof(char) * 9);
141 for (i = 0; i < 72; i++) {
142 bit = inb((rd_port << 2) | 0x3) == 0x55;
143 DELAY(250); /* Delay 250 usec */
145 /* Can't Short Circuit the next evaluation, so 'and' is last */
146 bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit;
147 DELAY(250); /* Delay 250 usec */
149 valid = valid || bit;
153 (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
155 data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
158 valid = valid && (data[8] == sum);
165 * Fill's the buffer with resource info from the device.
166 * Returns 0 if the device fails to report
169 get_resource_info(u_char *buffer, int len)
173 for (i = 0; i < len; i++) {
174 outb(_PNP_ADDRESS, PNP_STATUS);
175 for (j = 0; j < 100; j++) {
176 if ((inb((rd_port << 2) | 0x3)) & 0x1)
181 printf("PnP device failed to report resource data\n");
184 outb(_PNP_ADDRESS, PNP_RESOURCE_DATA);
185 buffer[i] = inb((rd_port << 2) | 0x3);
186 DEB(printf("--- get_resource_info: got 0x%02x\n",(unsigned)buffer[i]));
195 char *s1=NULL, *s2=NULL, *s3=NULL, *s4=NULL, *s5=NULL;
214 s2 = (x & 0x4) ? "bus master" : "not a bus master";
216 s3 = (x & 0x8) ? "count by byte" : "";
218 s4 = (x & 0x10) ? "count by word" : "";
220 switch ((x & 0x60) >> 5) {
222 s5="Compatibility mode";
234 printf("\t%s, %s, %s, %s, %s\n",s1,s2,s3,s4,s5);
239 report_memory_info (int x)
242 printf ("Memory Range: Writeable\n");
244 printf ("Memory Range: Not writeable (ROM)\n");
247 printf ("Memory Range: Read-cacheable, write-through\n");
249 printf ("Memory Range: Non-cacheable\n");
252 printf ("Memory Range: Decode supports high address\n");
254 printf ("Memory Range: Decode supports range length\n");
256 switch ((x & 0x18) >> 3) {
258 printf ("Memory Range: 8-bit memory only\n");
261 printf ("Memory Range: 16-bit memory only\n");
264 printf ("Memory Range: 8-bit and 16-bit memory supported\n");
268 printf ("Memory Range: Reserved\n");
274 printf ("Memory Range: Memory is shadowable\n");
276 printf ("Memory Range: Memory is not shadowable\n");
279 printf ("Memory Range: Memory is an expansion ROM\n");
281 printf ("Memory Range: Memory is not an expansion ROM\n");
285 printf ("Memory Range: Reserved (Device is brain-damaged)\n");
291 * Small Resource Tag Handler
293 * Returns 1 if checksum was valid (and an END_TAG was received).
294 * Returns -1 if checksum was invalid (and an END_TAG was received).
295 * Returns 0 for other tags.
298 handle_small_res(u_char *resinfo, int item, int len)
302 DEB(printf("*** ITEM 0x%04x len %d detected\n", item, len));
306 printf("*** ITEM 0x%02x detected\n", item);
308 case PNP_TAG_VERSION:
309 printf("PnP Version %d.%d, Vendor Version %d\n",
310 resinfo[0] >> 4, resinfo[0] & (0xf), resinfo[1]);
312 case PNP_TAG_LOGICAL_DEVICE:
313 printf("\nLogical Device ID: %c%c%c%02x%02x 0x%08x #%d\n",
314 ((resinfo[0] & 0x7c) >> 2) + 64,
315 (((resinfo[0] & 0x03) << 3) |
316 ((resinfo[1] & 0xe0) >> 5)) + 64,
317 (resinfo[1] & 0x1f) + 64,
318 resinfo[2], resinfo[3], *(int *)(resinfo),
321 if (resinfo[4] & 0x1)
322 printf ("\tDevice powers up active\n"); /* XXX */
323 if (resinfo[4] & 0x2)
324 printf ("\tDevice supports I/O Range Check\n");
325 if (resinfo[4] > 0x3)
326 printf ("\tReserved register funcs %02x\n",
330 printf("\tVendor register funcs %02x\n", resinfo[5]);
332 case PNP_TAG_COMPAT_DEVICE:
333 printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n",
334 ((resinfo[0] & 0x7c) >> 2) + 64,
335 (((resinfo[0] & 0x03) << 3) |
336 ((resinfo[1] & 0xe0) >> 5)) + 64,
337 (resinfo[1] & 0x1f) + 64,
338 resinfo[2], resinfo[3], *(int *)resinfo);
340 case PNP_TAG_IRQ_FORMAT:
343 for (i = 0; i < 8; i++)
344 if (resinfo[0] & (1<<i))
346 for (i = 0; i < 8; i++)
347 if (resinfo[1] & (1<<i))
348 printf("%d ", i + 8);
350 if (resinfo[2] & 0x1)
351 printf("IRQ: High true edge sensitive\n");
352 if (resinfo[2] & 0x2)
353 printf("IRQ: Low true edge sensitive\n");
354 if (resinfo[2] & 0x4)
355 printf("IRQ: High true level sensitive\n");
356 if (resinfo[2] & 0x8)
357 printf("IRQ: Low true level sensitive\n");
359 printf(" - only one type (true/edge)\n");
362 case PNP_TAG_DMA_FORMAT:
363 printf(" DMA: channel(s) ");
364 for (i = 0; i < 8; i++)
365 if (resinfo[0] & (1<<i))
368 report_dma_info (resinfo[1]);
370 case PNP_TAG_START_DEPENDANT:
371 printf("TAG Start DF\n");
373 switch (resinfo[0]) {
375 printf("Good Configuration\n");
378 printf("Acceptable Configuration\n");
381 printf("Sub-optimal Configuration\n");
386 case PNP_TAG_END_DEPENDANT:
387 printf("TAG End DF\n");
389 case PNP_TAG_IO_RANGE:
390 printf(" I/O Range 0x%x .. 0x%x, alignment 0x%x, len 0x%x\n",
391 resinfo[1] + (resinfo[2] << 8),
392 resinfo[3] + (resinfo[4] << 8),
393 resinfo[5], resinfo[6] );
395 printf("\t[16-bit addr]\n");
397 printf("\t[not 16-bit addr]\n");
399 case PNP_TAG_IO_FIXED:
400 printf (" FIXED I/O base address 0x%x length 0x%x\n",
401 resinfo[0] + ( (resinfo[1] & 3 ) << 8), /* XXX */
405 case PNP_TAG_RESERVED:
406 printf("Reserved Tag Detected\n");
410 printf("*** Small Vendor Tag Detected\n");
413 printf("End Tag\n\n");
414 /* XXX Record and Verify Checksum */
423 handle_large_res(u_char *resinfo, int item, int len)
427 DEB(printf("*** Large ITEM %d len %d found\n", item, len));
429 case PNP_TAG_MEMORY_RANGE:
430 report_memory_info(resinfo[0]);
431 printf("Memory range minimum address: 0x%x\n",
432 (resinfo[1] << 8) + (resinfo[2] << 16));
433 printf("Memory range maximum address: 0x%x\n",
434 (resinfo[3] << 8) + (resinfo[4] << 16));
435 printf("Memory range base alignment: 0x%x\n",
436 (i = (resinfo[5] + (resinfo[6] << 8))) ? i : (1 << 16));
437 printf("Memory range length: 0x%x\n",
438 (resinfo[7] + (resinfo[8] << 8)) * 256);
440 case PNP_TAG_ID_ANSI:
441 printf("Device Description: ");
443 for (i = 0; i < len; i++) {
444 if (resinfo[i]) /* XXX */
445 printf("%c", resinfo[i]);
449 case PNP_TAG_ID_UNICODE:
450 printf("ID String Unicode Detected (Undefined)\n");
452 case PNP_TAG_LARGE_VENDOR:
453 printf("Large Vendor Defined Detected\n");
455 case PNP_TAG_MEMORY32_RANGE:
456 printf("32bit Memory Range Desc Unimplemented\n");
458 case PNP_TAG_MEMORY32_FIXED:
459 printf("32bit Fixed Location Desc Unimplemented\n");
462 case PNP_TAG_LARGE_RESERVED:
463 printf("Large Reserved Tag Detected\n");
471 * Dump all the information about configurations.
474 dump_resdata(u_char *data, int csn)
478 u_char tag, *resinfo;
480 DDB(printf("\nCard assigned CSN #%d\n", csn));
481 printf("Vendor ID %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n",
482 ((data[0] & 0x7c) >> 2) + 64,
483 (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64,
484 (data[1] & 0x1f) + 64, data[2], data[3],
488 pnp_write(PNP_SET_CSN, csn); /* Move this out of this function XXX */
489 outb(_PNP_ADDRESS, PNP_STATUS);
491 /* Allows up to 1kb of Resource Info, Should be plenty */
492 for (i = 0; i < 1024; i++) {
493 if (!get_resource_info(&tag, 1))
496 if (PNP_RES_TYPE(tag) == 0) {
497 /* Handle small resouce data types */
499 resinfo = malloc(PNP_SRES_LEN(tag));
500 if (!get_resource_info(resinfo, PNP_SRES_LEN(tag)))
503 if (handle_small_res(resinfo, PNP_SRES_NUM(tag), PNP_SRES_LEN(tag)) == 1)
507 /* Handle large resouce data types */
509 if (!get_resource_info((char *)buf, 2))
511 large_len = (buf[1] << 8) + buf[0];
513 resinfo = malloc(large_len);
514 if (!get_resource_info(resinfo, large_len))
517 handle_large_res(resinfo, PNP_LRES_NUM(tag), large_len);
521 printf("Successfully got %d resources, %d logical fdevs\n", i,
523 printf("-- card select # 0x%04x\n", pnp_read(PNP_SET_CSN));
524 printf("\nCSN %c%c%c%02x%02x (0x%08x), Serial Number 0x%08x\n",
525 ((data[0] & 0x7c) >> 2) + 64,
526 (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64,
527 (data[1] & 0x1f) + 64, data[2], data[3],
531 for (i=0; i<logdevs; i++) {
534 pnp_write(PNP_SET_LDN, i);
536 printf("\nLogical device #%d\n", pnp_read(PNP_SET_LDN) );
539 printf(" 0x%02x%02x", pnp_read(PNP_IO_BASE_HIGH(j)),
540 pnp_read(PNP_IO_BASE_LOW(j)));
541 printf("\nIRQ %d %d\n",
542 pnp_read(PNP_IRQ_LEVEL(0)), pnp_read(PNP_IRQ_LEVEL(1)) );
543 printf("DMA %d %d\n",
544 pnp_read(PNP_DMA_CHANNEL(0)), pnp_read(PNP_DMA_CHANNEL(1)) );
545 printf("IO range check 0x%02x activate 0x%02x\n",
546 pnp_read(PNP_IO_RANGE_CHECK), pnp_read(PNP_ACTIVATE) );
552 * Run the isolation protocol. Use rd_port as the READ_DATA port
553 * value (caller should try multiple READ_DATA locations before giving
554 * up). Upon exiting, all cards are aware that they should use rd_port
555 * as the READ_DATA port;
564 send_Initiation_LFSR();
566 /* Reset CSN for All Cards */
567 pnp_write(PNP_CONFIG_CONTROL, 0x04);
569 for (csn = 1; (csn < PNP_MAX_CARDS); csn++) {
570 /* Wake up cards without a CSN */
572 pnp_write(PNP_WAKE, 0);
573 pnp_write(PNP_SET_RD_DATA, rd_port);
574 outb(_PNP_ADDRESS, PNP_SERIAL_ISOLATION);
575 DELAY(1000); /* Delay 1 msec */
577 if (get_serial(data))
578 dump_resdata(data, csn);
587 main(int argc, char **argv)
592 /* Hey what about a i386_iopl() call :) */
593 if (open("/dev/io", O_RDONLY) < 0)
594 errx(1, "can't get I/O privilege");
597 printf("Checking for Plug-n-Play devices...\n");
599 /* Try various READ_DATA ports from 0x203-0x3ff */
600 for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) {
601 DEB(printf("Trying Read_Port at %x...\n", (rd_port << 2) | 0x3) );
602 num_pnp_devs = isolation_protocol();
607 printf("No Plug-n-Play devices were found\n");