printcis.c revision 15284
1/*
2 * Copyright (c) 1995 Andrew McRae.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 *    derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $Id$
27 */
28#include <stdio.h>
29#include <unistd.h>
30#include <stdlib.h>
31#include <string.h>
32#include <sys/ioctl.h>
33
34#include <pccard/card.h>
35#include <pccard/cis.h>
36
37#include "readcis.h"
38
39int     dump_pwr_desc(unsigned char *);
40void    print_ext_speed(unsigned char, int);
41void    dump_device_desc(unsigned char *p, int len, char *type);
42void    dump_info_v1(unsigned char *p, int len);
43void    dump_config_map(struct tuple *tp);
44void    dump_cis_config(struct tuple *tp);
45void    dump_other_cond(unsigned char *p);
46void    dump_func_ext(unsigned char *p, int len);
47
48void
49dumpcis(struct cis *cp)
50{
51	struct tuple *tp;
52	struct tuple_list *tl;
53	int     count = 0, sz, ad, i;
54	unsigned char *p;
55
56	for (tl = cp->tlist; tl; tl = tl->next)
57		for (tp = tl->tuples; tp; tp = tp->next) {
58			printf("Tuple #%d, code = 0x%x (%s), length = %d\n",
59			    ++count, tp->code, tuple_name(tp->code), tp->length);
60			p = tp->data;
61			sz = tp->length;
62			ad = 0;
63			while (sz > 0) {
64				printf("    %03x: ", ad);
65				for (i = 0; i < ((sz < 16) ? sz : 16); i++)
66					printf(" %02x", p[i]);
67				printf("\n");
68				sz -= 16;
69				p += 16;
70				ad += 16;
71			}
72			switch (tp->code) {
73			default:
74				break;
75			case CIS_MEM_COMMON:	/* 0x01 */
76				dump_device_desc(tp->data, tp->length, "Common");
77				break;
78			case CIS_CHECKSUM:	/* 0x10 */
79				if (tp->length == 5) {
80					printf("\tChecksum from offset %d, length %d, value is 0x%x\n",
81					    (short)((tp->data[1] << 8) | tp->data[0]),
82					    (tp->data[3] << 8) | tp->data[2],
83					    tp->data[4]);
84				} else
85					printf("\tIllegal length for checksum!\n");
86				break;
87			case CIS_LONGLINK_A:	/* 0x11 */
88				printf("\tLong link to attribute memory, address 0x%x\n",
89				    (tp->data[3] << 24) |
90				    (tp->data[2] << 16) |
91				    (tp->data[1] << 8)  |
92				    tp->data[0]);
93				break;
94			case CIS_LONGLINK_C:	/* 0x12 */
95				printf("\tLong link to common memory, address 0x%x\n",
96				    (tp->data[3] << 24) |
97				    (tp->data[2] << 16) |
98				    (tp->data[1] << 8)  |
99				    tp->data[0]);
100				break;
101				break;
102			case CIS_INFO_V1:	/* 0x15 */
103				dump_info_v1(tp->data, tp->length);
104				break;
105			case CIS_ALTSTR:	/* 0x16 */
106				break;
107			case CIS_MEM_ATTR:	/* 0x17 */
108				dump_device_desc(tp->data, tp->length, "Attribute");
109				break;
110			case CIS_JEDEC_C:	/* 0x18 */
111				break;
112			case CIS_JEDEC_A:	/* 0x19 */
113				break;
114			case CIS_CONF_MAP:	/* 0x1A */
115				dump_config_map(tp);
116				break;
117			case CIS_CONFIG:	/* 0x1B */
118				dump_cis_config(tp);
119				break;
120			case CIS_DEVICE_OC:	/* 0x1C */
121				dump_other_cond(tp->data);
122				break;
123			case CIS_DEVICE_OA:	/* 0x1D */
124				dump_other_cond(tp->data);
125				break;
126			case CIS_DEVICEGEO:	/* 0x1E */
127				break;
128			case CIS_DEVICEGEO_A:	/* 0x1F */
129				break;
130			case CIS_MANUF_ID:	/* 0x20 */
131				printf("\tPCMCIA ID = 0x%x, OEM ID = 0x%x\n",
132				    (tp->data[1] << 8) | tp->data[0],
133				    (tp->data[3] << 8) | tp->data[2]);
134				break;
135			case CIS_FUNC_ID:	/* 0x21 */
136				switch (tp->data[0]) {
137				default:
138					printf("\tUnknown function");
139					break;
140				case 0:
141					printf("\tMultifunction card");
142					break;
143				case 1:
144					printf("\tMemory card");
145					break;
146				case 2:
147					printf("\tSerial port/modem");
148					break;
149				case 3:
150					printf("\tParallel port");
151					break;
152				case 4:
153					printf("\tFixed disk card");
154					break;
155				case 5:
156					printf("\tVideo adapter");
157					break;
158				case 6:
159					printf("\tNetwork/LAN adapter");
160					break;
161				case 7:
162					printf("\tAIMS");
163					break;
164				}
165				printf("%s%s\n", (tp->data[1] & 1) ? " - POST initialize" : "",
166				    (tp->data[1] & 2) ? " - Card has ROM" : "");
167				break;
168			case CIS_FUNC_EXT:	/* 0x22 */
169				dump_func_ext(tp->data, tp->length);
170				break;
171			case CIS_VERS_2:	/* 0x40 */
172				break;
173			}
174		}
175}
176
177/*
178 *	Dump configuration map tuple.
179 */
180void
181dump_config_map(struct tuple *tp)
182{
183	unsigned char *p, x;
184	int     rlen, mlen;
185	int     i;
186	union {
187		unsigned long l;
188		unsigned char b[4];
189	} u;
190
191	rlen = (tp->data[0] & 3) + 1;
192	mlen = ((tp->data[0] >> 2) & 3) + 1;
193	u.l = 0;
194	p = tp->data + 2;
195	for (i = 0; i < rlen; i++)
196		u.b[i] = *p++;
197	printf("\tReg len = %d, config register addr = 0x%lx, last config = 0x%x\n",
198	    rlen, u.l, tp->data[1]);
199	if (mlen)
200		printf("\tRegisters: ");
201	for (i = 0; i < mlen; i++, p++) {
202		for (x = 0x1; x; x <<= 1)
203			printf("%c", x & *p ? 'X' : '-');
204		printf(" ");
205	}
206	printf("\n");
207}
208
209/*
210 *	Dump a config entry.
211 */
212void
213dump_cis_config(struct tuple *tp)
214{
215	unsigned char *p, feat;
216	int     i, j;
217	char    c;
218
219	p = tp->data;
220	printf("\tConfig index = 0x%x%s\n", *p & 0x3F,
221	    *p & 0x40 ? "(default)" : "");
222	if (*p & 0x80) {
223		p++;
224		printf("\tInterface byte = 0x%x ", *p);
225		switch (*p & 0xF) {
226		default:
227			printf("(reserved)");
228			break;
229		case 0:
230			printf("(memory)");
231			break;
232		case 1:
233			printf("(I/O)");
234			break;
235		case 4:
236		case 5:
237		case 6:
238		case 7:
239		case 8:
240			printf("(custom)");
241			break;
242		}
243		c = ' ';
244		if (*p & 0x10) {
245			printf(" BVD1/2 active");
246			c = ',';
247		}
248		if (*p & 0x20) {
249			printf("%c card WP active", c);	/* Write protect */
250			c = ',';
251		}
252		if (*p & 0x40) {
253			printf("%c +RDY/-BSY active", c);
254			c = ',';
255		}
256		if (*p & 0x80)
257			printf("%c wait signal supported", c);
258		printf("\n");
259	}
260	p++;
261	feat = *p++;
262	switch (feat & 3) {
263	case 0:
264		break;
265	case 1:
266		printf("\tVcc pwr:\n");
267		p += dump_pwr_desc(p);
268		break;
269	case 2:
270		printf("\tVcc pwr:\n");
271		p += dump_pwr_desc(p);
272		printf("\tVpp pwr:\n");
273		p += dump_pwr_desc(p);
274		break;
275	case 3:
276		printf("\tVcc pwr:\n");
277		p += dump_pwr_desc(p);
278		printf("\tVpp1 pwr:\n");
279		p += dump_pwr_desc(p);
280		printf("\tVpp2 pwr:\n");
281		p += dump_pwr_desc(p);
282		break;
283	}
284	if (feat & 0x4) {
285		i = *p & 3;
286		j = (*p >> 2) & 7;
287		p++;
288		if (i != 3) {
289			printf("\tWait scale ");
290			print_ext_speed(*p, i);
291			while (*p & 0x80)
292				p++;
293			printf("\n");
294		}
295		if (j != 7) {
296			printf("\tRDY/BSY scale ");
297			print_ext_speed(*p, j);
298			while (*p & 0x80)
299				p++;
300			printf("\n");
301		}
302	}
303	if (feat & 0x8) {
304		if (*p & 0x1F)
305			printf("\tCard decodes %d address lines", *p & 0x1F);
306		else
307			printf("\tCard provides address decode");
308		switch ((*p >> 5) & 3) {
309		case 0:
310			break;
311		case 1:
312			printf(", 8 Bit I/O only");
313			break;
314		case 2:
315			printf(", limited 8/16 Bit I/O");
316			break;
317		case 3:
318			printf(", full 8/16 Bit I/O");
319			break;
320		}
321		printf("\n");
322		if (*p & 0x80) {
323			p++;
324			c = *p++;
325			for (i = 0; i <= (c & 0xF); i++) {
326				printf("\t\tI/O address # %d: ", i + 1);
327				switch ((c >> 4) & 3) {
328				case 0:
329					break;
330				case 1:
331					printf("block start = 0x%x", *p++);
332					break;
333				case 2:
334					printf("block start = 0x%x", (p[1] << 8) | *p);
335					p += 2;
336					break;
337				case 3:
338					printf("block start = 0x%x",
339					    (p[3] << 24) | (p[2] << 16) |
340					    (p[1] << 8) | *p);
341					p += 4;
342					break;
343				}
344				switch ((c >> 6) & 3) {
345				case 0:
346					break;
347				case 1:
348					printf(" block length = 0x%x", *p++ + 1);
349					break;
350				case 2:
351					printf(" block length = 0x%x", ((p[1] << 8) | *p) + 1);
352					p += 2;
353					break;
354				case 3:
355					printf(" block length = 0x%x",
356					    ((p[3] << 24) | (p[2] << 16) |
357						(p[1] << 8) | *p) + 1);
358					p += 4;
359					break;
360				}
361				printf("\n");
362			}
363		}
364	}
365
366	/* IRQ descriptor */
367	if (feat & 0x10) {
368		printf("\t\tIRQ modes:");
369		c = ' ';
370		if (*p & 0x20) {
371			printf(" Level");
372			c = ',';
373		}
374		if (*p & 0x40) {
375			printf("%c Pulse", c);
376			c = ',';
377		}
378		if (*p & 0x80)
379			printf("%c Shared", c);
380		printf("\n");
381		if (*p & 0x10) {
382			i = p[0] | (p[1] << 8);
383			printf("\t\tIRQs: ");
384			if (*p & 1)
385				printf(" NMI");
386			if (*p & 0x2)
387				printf(" IOCK");
388			if (*p & 0x4)
389				printf(" BERR");
390			if (*p & 0x8)
391				printf(" VEND");
392			for (j = 0; j < 16; j++)
393				if (i & (1 << j))
394					printf(" %d", j);
395			printf("\n");
396			p += 3;
397		} else {
398			printf("\t\tIRQ level = %d\n", *p & 0xF);
399			p++;
400		}
401	}
402	switch ((feat >> 5) & 3) {
403	case 0:
404		break;
405	case 1:
406		printf("\tMemory space length = 0x%x\n", (p[1] << 8) | p[0]);
407		p += 2;
408		break;
409	case 2:
410		printf("\tMemory space address = 0x%x, length = 0x%x\n",
411		    (p[3] << 8) | p[2],
412		    (p[1] << 8) | p[0]);
413		p += 4;
414		break;
415
416	/* Memory descriptors. */
417	case 3:
418		c = *p++;
419		for (i = 0; i <= (c & 7); i++) {
420			printf("\tMemory descriptor %d\n\t\t", i + 1);
421			switch ((c >> 3) & 3) {
422			case 0:
423				break;
424			case 1:
425				printf(" blk length = 0x%x00", *p++);
426				break;
427			case 2:
428				printf(" blk length = 0x%x00", (p[1] << 8) | *p);
429				p += 2;
430				break;
431			case 3:
432				printf(" blk length = 0x%x00",
433				    (p[3] << 24) | (p[2] << 16) |
434				    (p[1] << 8) | *p);
435				p += 4;
436				break;
437			}
438			switch ((c >> 5) & 3) {
439			case 0:
440				break;
441			case 1:
442				printf(" card addr = 0x%x00", *p++);
443				break;
444			case 2:
445				printf(" card addr = 0x%x00", (p[1] << 8) | *p);
446				p += 2;
447				break;
448			case 3:
449				printf(" card addr = 0x%x00",
450				    (p[3] << 24) | (p[2] << 16) |
451				    (p[1] << 8) | *p);
452				p += 4;
453				break;
454			}
455			if (c & 0x80)
456				switch ((c >> 5) & 3) {
457				case 0:
458					break;
459				case 1:
460					printf(" host addr = 0x%x00", *p++);
461					break;
462				case 2:
463					printf(" host addr = 0x%x00", (p[1] << 8) | *p);
464					p += 2;
465					break;
466				case 3:
467					printf(" host addr = 0x%x00",
468					    (p[3] << 24) | (p[2] << 16) |
469					    (p[1] << 8) | *p);
470					p += 4;
471					break;
472				}
473			printf("\n");
474		}
475		break;
476	}
477	if (feat & 0x80) {
478		printf("\tMax twin cards = %d\n", *p & 7);
479		printf("\tMisc attr:");
480		if (*p & 0x8)
481			printf(" (Audio-BVD2)");
482		if (*p & 0x10)
483			printf(" (Read-only)");
484		if (*p & 0x20)
485			printf(" (Power down supported)");
486		if (*p & 0x80) {
487			printf(" (Ext byte = 0x%x)", p[1]);
488			p++;
489		}
490		printf("\n");
491		p++;
492	}
493}
494
495/*
496 *	dump_other_cond - Dump other conditions.
497 */
498void
499dump_other_cond(unsigned char *p)
500{
501	if (p[0]) {
502		printf("\t");
503		if (p[0] & 1)
504			printf("(MWAIT)");
505		if (p[0] & 2)
506			printf(" (3V card)");
507		if (p[0] & 0x80)
508			printf(" (Extension bytes follow)");
509		printf("\n");
510	}
511}
512
513/*
514 *	Dump power descriptor.
515 */
516int
517dump_pwr_desc(unsigned char *p)
518{
519	int     len = 1, i;
520	unsigned char mask;
521	char  **expp;
522	static char *pname[] =
523	{"Nominal operating supply voltage",
524	 "Minimum operating supply voltage",
525	 "Maximum operating supply voltage",
526	 "Continuous supply current",
527	 "Max current average over 1 second",
528	 "Max current average over 10 ms",
529	 "Power down supply current",
530	 "Reserved"
531	};
532	static char *vexp[] =
533	{"10uV", "100uV", "1mV", "10mV", "100mV", "1V", "10V", "100V"};
534	static char *cexp[] =
535	{"10nA", "1uA", "10uA", "100uA", "1mA", "10mA", "100mA", "1A"};
536	static char *mant[] =
537	{"1", "1.2", "1.3", "1.5", "2", "2.5", "3", "3.5", "4", "4.5",
538	"5", "5.5", "6", "7", "8", "9"};
539
540	mask = *p++;
541	expp = vexp;
542	for (i = 0; i < 8; i++)
543		if (mask & (1 << i)) {
544			len++;
545			if (i >= 3)
546				expp = cexp;
547			printf("\t\t%s: ", pname[i]);
548			printf("%s x %s",
549			    mant[(*p >> 3) & 0xF],
550			    expp[*p & 7]);
551			while (*p & 0x80) {
552				len++;
553				p++;
554				printf(", ext = 0x%x", *p);
555			}
556			printf("\n");
557			p++;
558		}
559	return (len);
560}
561
562void
563dump_device_desc(unsigned char *p, int len, char *type)
564{
565	static char *un_name[] =
566	{"512b", "2Kb", "8Kb", "32Kb", "128Kb", "512Kb", "2Mb", "reserved"};
567	static char *speed[] =
568	{"No speed", "250nS", "200nS", "150nS",
569	"100nS", "Reserved", "Reserved"};
570	static char *dev[] =
571	{"No device", "Mask ROM", "OTPROM", "UV EPROM",
572	 "EEPROM", "FLASH EEPROM", "SRAM", "DRAM",
573	 "Reserved", "Reserved", "Reserved", "Reserved",
574	 "Reserved", "Function specific", "Extended",
575	"Reserved"};
576	int     count = 0;
577
578	while (*p != 0xFF && len > 0) {
579		unsigned char x;
580
581		x = *p++;
582		len -= 2;
583		if (count++ == 0)
584			printf("\t%s memory device information:\n", type);
585		printf("\t\tDevice number %d, type %s, WPS = %s\n",
586		    count, dev[x >> 4], (x & 0x8) ? "ON" : "OFF");
587		if ((x & 7) == 7) {
588			len--;
589			if (*p) {
590				printf("\t\t");
591				print_ext_speed(*p, 0);
592				while (*p & 0x80) {
593					p++;
594					len--;
595				}
596			}
597			p++;
598		} else
599			printf("\t\tSpeed = %s", speed[x & 7]);
600		printf(", Memory block size = %s, %d units\n",
601		    un_name[*p & 7], (*p >> 3) + 1);
602		p++;
603	}
604}
605
606/*
607 *	Print version info
608 */
609void
610dump_info_v1(unsigned char *p, int len)
611{
612	printf("\tVersion = %d.%d", p[0], p[1]);
613	p += 2;
614	printf(", Manuf = [%s],", p);
615	while (*p++);
616	printf("card vers = [%s]\n", p);
617	while (*p++);
618	printf("\tAddit. info = [%s]", p);
619	while (*p++);
620	printf(",[%s]\n", p);
621}
622
623/*
624 *	dump functional extension tuple.
625 */
626void
627dump_func_ext(unsigned char *p, int len)
628{
629	if (len == 0)
630		return;
631	switch (p[0]) {
632	case 0:
633	case 8:
634	case 10:
635		if (len != 4) {
636			printf("\tWrong length for serial extension\n");
637			return;
638		}
639		printf("\tSerial interface extension:\n");
640		switch (p[1] & 0x1F) {
641		default:
642			printf("\t\tUnkn device");
643			break;
644		case 0:
645			printf("\t\t8250 UART");
646			break;
647		case 1:
648			printf("\t\t16450 UART");
649			break;
650		case 2:
651			printf("\t\t16550 UART");
652			break;
653		}
654		printf(", Parity - %s%s%s%s",
655		    (p[2] & 1) ? "Space," : "",
656		    (p[2] & 2) ? "Mark," : "",
657		    (p[2] & 4) ? "Odd," : "",
658		    (p[2] & 8) ? "Even," : "");
659		printf("\n");
660		break;
661	case 1:
662	case 5:
663	case 6:
664	case 7:
665		printf("\tModem interface capabilities:\n");
666		break;
667	case 2:
668		printf("\tData modem services available:\n");
669		break;
670	case 9:
671		printf("\tFax/modem services available:\n");
672		break;
673	case 4:
674		printf("\tVoice services available:\n");
675		break;
676	}
677}
678
679/*
680 *	print_ext_speed - Print extended speed.
681 */
682void
683print_ext_speed(unsigned char x, int scale)
684{
685	static char *mant[] =
686	{"Reserved", "1.0", "1.2", "1.3", "1.5", "2.0", "2.5", "3.0",
687	"3.5", "4.0", "4.5", "5.0", "5.5", "6.0", "7.0", "8.0"};
688	static char *exp[] =
689	{"1 ns", "10 ns", "100 ns", "1 us", "10 us", "100 us",
690	"1 ms", "10 ms"};
691	static char *scale_name[] =
692	{"None", "10", "100", "1,000", "10,000", "100,000",
693	"1,000,000", "10,000,000"};
694
695	printf("Speed = %s x %s", mant[(x >> 3) & 0xF], exp[x & 7]);
696	if (scale)
697		printf(", scaled by %s", scale_name[scale & 7]);
698}
699