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