Annotation of src/usr.bin/pnpinfo/pnpinfo.c, Revision 1.1.1.1
1.1 shawn 1: /* $OpenBSD$ */
2: /*
3: * Copyright (c) 1996, Sujal M. Patel
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: * SUCH DAMAGE.
26: */
27:
28: #include <sys/time.h>
29:
30: #include <stdio.h>
31: #include <stdlib.h>
32: #include <unistd.h>
33: #include <fcntl.h>
34: #include <string.h>
35:
36: #include <machine/cpufunc.h>
37:
38: #if defined(__OpenBSD__)
39: #include <i386/sysarch.h>
40: #include <machine/pio.h>
41: #endif
42:
43: #include "pnpinfo.h"
44:
45:
46: #define SEND(d, r) { outb (ADDRESS, d); outb (WRITE_DATA, r); }
47:
48:
49: /* The READ_DATA port that we are using currently */
50: static int rd_port;
51:
52:
53: void DELAY __P((int i));
54: int power __P((int base, int exp));
55: void send_Initiation_LFSR();
56: int get_serial __P((unsigned char *data));
57: int get_resource_info __P((char *buffer, int len));
58: int handle_small_res __P((unsigned char *resinfo, int item, int len));
59: void handle_large_res __P((unsigned char *resinfo, int item, int len));
60: void dump_resdata __P((unsigned char *data, int csn));
61: int isolation_protocol();
62:
63:
64: /*
65: * DELAY does accurate delaying in user-space.
66: * This function busy-waits.
67: */
68: void
69: DELAY (i)
70: int i;
71: {
72: struct timeval t;
73: long start, stop;
74:
75: gettimeofday (&t, NULL);
76: start = t.tv_sec * 1000000 + t.tv_usec;
77: do {
78: gettimeofday (&t, NULL);
79: stop = t.tv_sec * 1000000 + t.tv_usec;
80: } while (start + i > stop);
81: }
82:
83:
84: int
85: power(base, exp)
86: int base, exp;
87: {
88: if (exp <= 1)
89: return base;
90: else
91: return base * power(base, exp - 1);
92: }
93:
94:
95: /*
96: * Send Initiation LFSR as described in "Plug and Play ISA Specification,
97: * Intel May 94."
98: */
99: void
100: send_Initiation_LFSR()
101: {
102: int cur, i;
103:
104: /* Reset the LSFR */
105: outb(ADDRESS, 0);
106: outb(ADDRESS, 0);
107:
108: cur = 0x6a;
109: outb(ADDRESS, cur);
110:
111: for (i = 1; i < 32; i++) {
112: cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
113: outb(ADDRESS, cur);
114: }
115: }
116:
117:
118: /*
119: * Get the device's serial number. Returns 1 if the serial is valid.
120: */
121: int
122: get_serial(data)
123: unsigned char *data;
124: {
125: int i, bit, valid = 0, sum = 0x6a;
126:
127: bzero(data, sizeof(char) * 9);
128:
129: for (i = 0; i < 72; i++) {
130: bit = inb((rd_port << 2) | 0x3) == 0x55;
131: DELAY(250); /* Delay 250 usec */
132:
133: /* Can't Short Circuit the next evaluation, so 'and' is last */
134: bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit;
135: DELAY(250); /* Delay 250 usec */
136:
137: valid = valid || bit;
138:
139: if (i < 64)
140: sum = (sum >> 1) |
141: (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
142:
143: data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
144: }
145:
146: valid = valid && (data[8] == sum);
147:
148: return valid;
149: }
150:
151:
152: /*
153: * Fill's the buffer with resource info from the device.
154: * Returns 0 if the device fails to report
155: */
156: int
157: get_resource_info(buffer, len)
158: char *buffer;
159: int len;
160: {
161: int i, j;
162:
163: for (i = 0; i < len; i++) {
164: outb(ADDRESS, STATUS);
165: for (j = 0; j < 100; j++) {
166: if ((inb((rd_port << 2) | 0x3)) & 0x1)
167: break;
168: DELAY(1);
169: }
170: if (j == 100) {
171: printf("PnP device failed to report resource data\n");
172: return 0;
173: }
174: outb(ADDRESS, RESOURCE_DATA);
175: buffer[i] = inb((rd_port << 2) | 0x3);
176: }
177: return 1;
178: }
179:
180:
181: void
182: report_dma_info (x)
183: int x;
184: {
185: switch (x & 0x3) {
186: case 0:
187: printf ("DMA: 8-bit only\n");
188: break;
189: case 1:
190: printf ("DMA: 8-bit and 16-bit\n");
191: break;
192: case 2:
193: printf ("DMA: 16-bit only\n");
194: break;
195: #ifdef DIAGNOSTIC
196: case 3:
197: printf ("DMA: Reserved\n");
198: break;
199: #endif
200: }
201:
202: if (x & 0x4)
203: printf ("DMA: Device is a bus master\n");
204: else
205: printf ("DMA: Device is not a bus master\n");
206:
207: if (x & 0x8)
208: printf ("DMA: May execute in count by byte mode\n");
209: else
210: printf ("DMA: May not execute in count by byte mode\n");
211:
212: if (x & 0x10)
213: printf ("DMA: May execute in count by word mode\n");
214: else
215: printf ("DMA: May not execute in count by word mode\n");
216:
217: switch ((x & 0x60) >> 5) {
218: case 0:
219: printf ("DMA: Compatibility mode\n");
220: break;
221: case 1:
222: printf ("DMA: Type A DMA channel\n");
223: break;
224: case 2:
225: printf ("DMA: Type B DMA channel\n");
226: break;
227: case 3:
228: printf ("DMA: Type F DMA channel\n");
229: break;
230: }
231: }
232:
233:
234: void
235: report_memory_info (x)
236: int x;
237: {
238: if (x & 0x1)
239: printf ("Memory Range: Writeable\n");
240: else
241: printf ("Memory Range: Not writeable (ROM)\n");
242:
243: if (x & 0x2)
244: printf ("Memory Range: Read-cacheable, write-through\n");
245: else
246: printf ("Memory Range: Non-cacheable\n");
247:
248: if (x & 0x4)
249: printf ("Memory Range: Decode supports high address\n");
250: else
251: printf ("Memory Range: Decode supports range length\n");
252:
253: switch ((x & 0x18) >> 3) {
254: case 0:
255: printf ("Memory Range: 8-bit memory only\n");
256: break;
257: case 1:
258: printf ("Memory Range: 16-bit memory only\n");
259: break;
260: case 2:
261: printf ("Memory Range: 8-bit and 16-bit memory supported\n");
262: break;
263: #ifdef DIAGNOSTIC
264: case 3:
265: printf ("Memory Range: Reserved\n");
266: break;
267: #endif
268: }
269:
270: if (x & 0x20)
271: printf ("Memory Range: Memory is shadowable\n");
272: else
273: printf ("Memory Range: Memory is not shadowable\n");
274:
275: if (x & 0x40)
276: printf ("Memory Range: Memory is an expansion ROM\n");
277: else
278: printf ("Memory Range: Memory is not an expansion ROM\n");
279:
280: #ifdef DIAGNOSTIC
281: if (x & 0x80)
282: printf ("Memory Range: Reserved (Device is brain-damaged)\n");
283: #endif
284: }
285:
286:
287: /*
288: * Small Resource Tag Handler
289: *
290: * Returns 1 if checksum was valid (and an END_TAG was received).
291: * Returns -1 if checksum was invalid (and an END_TAG was received).
292: * Returns 0 for other tags.
293: */
294: int
295: handle_small_res(resinfo, item, len)
296: int item, len;
297: unsigned char *resinfo;
298: {
299: int i;
300:
301: switch (item) {
302: case PNP_VERSION:
303: printf("PnP Version: %d.%d\n",
304: resinfo[0] >> 4,
305: resinfo[0] & (0xf));
306: printf("Vendor Version: %d\n", resinfo[1]);
307: break;
308: case LOG_DEVICE_ID:
309: printf("Logical Device ID: %c%c%c%02x%02x (%08x)\n",
310: ((resinfo[0] & 0x7c) >> 2) + 64,
311: (((resinfo[0] & 0x03) << 3) |
312: ((resinfo[1] & 0xe0) >> 5)) + 64,
313: (resinfo[1] & 0x1f) + 64,
314: resinfo[2], resinfo[3], *(int *)resinfo);
315:
316: if (resinfo[4] & 0x1)
317: printf ("Device powers up active\n");
318: if (resinfo[4] & 0x2)
319: printf ("Device supports I/O Range Check\n");
320: if (resinfo[4] > 0x3)
321: printf ("Reserved register funcs %02x\n",
322: resinfo[4]);
323:
324: if (len == 6)
325: printf("Vendor register funcs %02x\n", resinfo[5]);
326: break;
327: case COMP_DEVICE_ID:
328: printf("Compatible Device ID: %c%c%c%02x%02x (%08x)\n",
329: ((resinfo[0] & 0x7c) >> 2) + 64,
330: (((resinfo[0] & 0x03) << 3) |
331: ((resinfo[1] & 0xe0) >> 5)) + 64,
332: (resinfo[1] & 0x1f) + 64,
333: resinfo[2], resinfo[3], *(int *)resinfo);
334: break;
335: case IRQ_FORMAT:
336: printf("IRQ: ");
337:
338: for (i = 0; i < 8; i++)
339: if (resinfo[0] & (char) (power(2, i)))
340: printf("%d ", i);
341: for (i = 0; i < 8; i++)
342: if (resinfo[1] & (char) (power(2, i)))
343: printf("%d ", i + 8);
344: printf("\n");
345: if (len == 3) {
346: if (resinfo[2] & 0x1)
347: printf("IRQ: High true edge sensitive\n");
348: if (resinfo[2] & 0x2)
349: printf("IRQ: Low true edge sensitive\n");
350: if (resinfo[2] & 0x4)
351: printf("IRQ: High true level sensitive\n");
352: if (resinfo[2] & 0x8)
353: printf("IRQ: Low true level sensitive\n");
354: }
355: break;
356: case DMA_FORMAT:
357: printf("DMA: ");
358: for (i = 0; i < 8; i++)
359: if (resinfo[0] & (char) (power(2, i)))
360: printf("%d ", i);
361: printf ("\n");
362: report_dma_info (resinfo[1]);
363: break;
364: case START_DEPEND_FUNC:
365: printf("Start Dependent Function\n");
366: if (len == 1) {
367: switch (resinfo[0]) {
368: case 0:
369: printf("Good Configuration\n");
370: break;
371: case 1:
372: printf("Acceptable Configuration\n");
373: break;
374: case 2:
375: printf("Sub-optimal Configuration\n");
376: break;
377: }
378: }
379: break;
380: case END_DEPEND_FUNC:
381: printf("End Dependent Function\n");
382: break;
383: case IO_PORT_DESC:
384: if (resinfo[0])
385: printf("Device decodes the full 16-bit ISA address\n");
386: else
387: printf("Device does not decode the full 16-bit ISA address\n");
388: printf("I/O Range maximum address: 0x%x\n",
389: resinfo[1] + (resinfo[2] << 8));
390: printf("I/O Range maximum address: 0x%x\n",
391: resinfo[3] + (resinfo[4] << 8));
392: printf("I/O alignment for minimum: %d\n",
393: resinfo[5]);
394: printf("I/O length: %d\n", resinfo[6]);
395: break;
396: case FIXED_IO_PORT_DESC:
397: printf ("I/O Range base address: 0x%x\n",
398: resinfo[1] + (resinfo[2] << 8));
399: printf("I/O length: %d\n", resinfo[3]);
400: break;
401: #ifdef DIAGNOSTIC
402: case SM_RES_RESERVED:
403: printf("Reserved Tag Detected\n");
404: break;
405: #endif
406: case SM_VENDOR_DEFINED:
407: printf("*** Small Vendor Tag Detected\n");
408: break;
409: case END_TAG:
410: printf("End Tag\n\n");
411: /* XXX Record and Verify Checksum */
412: return 1;
413: break;
414: }
415: return 0;
416: }
417:
418:
419: void
420: handle_large_res(resinfo, item, len)
421: int item, len;
422: unsigned char *resinfo;
423: {
424: int i;
425:
426: switch (item) {
427: case MEMORY_RANGE_DESC:
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 ID_STRING_ANSI:
439: printf("Device Description: ");
440:
441: for (i = 0; i < len; i++) {
442: printf("%c", resinfo[i]);
443: }
444: printf("\n");
445: break;
446: case ID_STRING_UNICODE:
447: printf("ID String Unicode Detected (Undefined)\n");
448: break;
449: case LG_VENDOR_DEFINED:
450: printf("Large Vendor Defined Detected\n");
451: break;
452: case _32BIT_MEM_RANGE_DESC:
453: printf("32bit Memory Range Desc Unimplemented\n");
454: break;
455: case _32BIT_FIXED_LOC_DESC:
456: printf("32bit Fixed Location Desc Unimplemented\n");
457: break;
458: case LG_RES_RESERVED:
459: printf("Large Reserved Tag Detected\n");
460: break;
461: }
462: }
463:
464:
465: /*
466: * Dump all the information about configurations.
467: */
468: void
469: dump_resdata(data, csn)
470: unsigned char *data;
471: int csn;
472: {
473: int i, large_len;
474: unsigned char tag, *resinfo;
475:
476: #ifdef DEBUG
477: printf("Card assigned CSN #%d\n", csn);
478: #endif
479: printf("Board Vendor ID: %c%c%c%02x%02x\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: printf("Board Serial Number: %08x\n", *(int *)&(data[4]));
484:
485: SEND(SET_CSN, csn); /* Move this out of this function XXX */
486: outb(ADDRESS, STATUS);
487:
488: /* Allows up to 1kb of Resource Info, Should be plenty */
489: for (i = 0; i < 1024; i++) {
490: if (!get_resource_info(&tag, 1))
491: return;
492:
493: #define TYPE (tag >> 7)
494: #define S_ITEM (tag >> 3)
495: #define S_LEN (tag & 0x7)
496: #define L_ITEM (tag & 0x7f)
497:
498: if (TYPE == 0) {
499: /* Handle small resouce data types */
500:
501: resinfo = malloc(S_LEN);
502: if (!get_resource_info(resinfo, S_LEN))
503: return;
504:
505: if (handle_small_res(resinfo, S_ITEM, S_LEN) == 1)
506: return;
507: free(resinfo);
508: } else {
509: /* Handle large resouce data types */
510:
511: if (!get_resource_info((char *) &large_len, 2))
512: return;
513:
514: resinfo = malloc(large_len);
515: if (!get_resource_info(resinfo, large_len))
516: return;
517:
518: handle_large_res(resinfo, L_ITEM, large_len);
519: free(resinfo);
520: }
521: }
522: }
523:
524:
525: /*
526: * Run the isolation protocol. Use rd_port as the READ_DATA port value (caller
527: * should try multiple READ_DATA locations before giving up). Upon exiting,
528: * all cards are aware that they should use rd_port as the READ_DATA port;
529: */
530: int
531: isolation_protocol()
532: {
533: int csn;
534: unsigned char data[9];
535:
536: send_Initiation_LFSR();
537:
538: /* Reset CSN for All Cards */
539: SEND(0x02, 0x04);
540:
541: for (csn = 1; (csn < MAX_CARDS); csn++) {
542: /* Wake up cards without a CSN */
543: SEND(WAKE, 0);
544: SEND(SET_RD_DATA, rd_port);
545: outb(ADDRESS, SERIAL_ISOLATION);
546: DELAY(1000); /* Delay 1 msec */
547:
548: if (get_serial(data))
549: dump_resdata(data, csn);
550: else
551: break;
552: }
553: return csn - 1;
554: }
555:
556:
557: void
558: main()
559: {
560: int num_pnp_devs;
561:
562: #if defined(__OpenBSD__)
563: if (i386_iopl(1)) {
564: perror("i386_iopl");
565: exit(1);
566: }
567: #endif
568: printf("Checking for Plug-n-Play devices...\n");
569:
570: /* Try various READ_DATA ports from 0x203-0x3ff */
571: for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) {
572: #ifdef DEBUG
573: printf("Trying Read_Port at %x\n", (rd_port << 2) | 0x3);
574: #endif
575: num_pnp_devs = isolation_protocol(rd_port);
576: if (num_pnp_devs)
577: break;
578: }
579: if (!num_pnp_devs) {
580: printf("No Plug-n-Play devices were found\n");
581: return;
582: }
583: }