printcis.c revision 17383
1178848Scokane/*
2178848Scokane * Copyright (c) 1995 Andrew McRae.  All rights reserved.
3178848Scokane *
4178848Scokane * Redistribution and use in source and binary forms, with or without
5178848Scokane * modification, are permitted provided that the following conditions
6178848Scokane * are met:
7178848Scokane * 1. Redistributions of source code must retain the above copyright
8178848Scokane *    notice, this list of conditions and the following disclaimer.
9178848Scokane * 2. Redistributions in binary form must reproduce the above copyright
10178848Scokane *    notice, this list of conditions and the following disclaimer in the
11178848Scokane *    documentation and/or other materials provided with the distribution.
12178848Scokane * 3. The name of the author may not be used to endorse or promote products
13178848Scokane *    derived from this software without specific prior written permission.
14178848Scokane *
15178848Scokane * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16178848Scokane * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17178848Scokane * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18178848Scokane * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19178848Scokane * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20178848Scokane * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21178848Scokane * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22178848Scokane * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23178848Scokane * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24178848Scokane * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25178848Scokane *
26178848Scokane * $Id: printcis.c,v 1.4 1996/04/18 04:24:55 nate Exp $
27178848Scokane */
28178848Scokane#include <stdio.h>
29178848Scokane#include <unistd.h>
30178848Scokane#include <stdlib.h>
31178848Scokane#include <string.h>
32178848Scokane#include <sys/ioctl.h>
33178848Scokane
34178848Scokane#include <pccard/card.h>
35178848Scokane#include <pccard/cis.h>
36178848Scokane
37178848Scokane#include "readcis.h"
38178848Scokane
39178848Scokaneint     dump_pwr_desc(unsigned char *);
40178848Scokanevoid    print_ext_speed(unsigned char, int);
41178848Scokanevoid    dump_device_desc(unsigned char *p, int len, char *type);
42178848Scokanevoid    dump_info_v1(unsigned char *p, int len);
43178848Scokanevoid    dump_config_map(struct tuple *tp);
44178848Scokanevoid    dump_cis_config(struct tuple *tp);
45178848Scokanevoid    dump_other_cond(unsigned char *p);
46178848Scokanevoid    dump_func_ext(unsigned char *p, int len);
47178848Scokane
48178848Scokanevoid
49178848Scokanedumpcis(struct cis *cp)
50178848Scokane{
51178848Scokane	struct tuple *tp;
52178848Scokane	struct tuple_list *tl;
53178848Scokane	int     count = 0, sz, ad, i;
54178848Scokane	unsigned char *p;
55178848Scokane
56178848Scokane	for (tl = cp->tlist; tl; tl = tl->next)
57178848Scokane		for (tp = tl->tuples; tp; tp = tp->next) {
58178848Scokane			printf("Tuple #%d, code = 0x%x (%s), length = %d\n",
59178848Scokane			    ++count, tp->code, tuple_name(tp->code), tp->length);
60178848Scokane			p = tp->data;
61178848Scokane			sz = tp->length;
62178848Scokane			ad = 0;
63178848Scokane			while (sz > 0) {
64178848Scokane				printf("    %03x: ", ad);
65178848Scokane				for (i = 0; i < ((sz < 16) ? sz : 16); i++)
66178848Scokane					printf(" %02x", p[i]);
67178848Scokane				printf("\n");
68178848Scokane				sz -= 16;
69178848Scokane				p += 16;
70178848Scokane				ad += 16;
71178848Scokane			}
72178848Scokane			switch (tp->code) {
73178848Scokane			default:
74178848Scokane				break;
75178848Scokane			case CIS_MEM_COMMON:	/* 0x01 */
76178848Scokane				dump_device_desc(tp->data, tp->length, "Common");
77178848Scokane				break;
78178848Scokane			case CIS_CHECKSUM:	/* 0x10 */
79178848Scokane				if (tp->length == 5) {
80178848Scokane					printf("\tChecksum from offset %d, length %d, value is 0x%x\n",
81178848Scokane					    (short)((tp->data[1] << 8) | tp->data[0]),
82178848Scokane					    (tp->data[3] << 8) | tp->data[2],
83178848Scokane					    tp->data[4]);
84178848Scokane				} else
85178848Scokane					printf("\tIllegal length for checksum!\n");
86178848Scokane				break;
87178848Scokane			case CIS_LONGLINK_A:	/* 0x11 */
88178848Scokane				printf("\tLong link to attribute memory, address 0x%x\n",
89178848Scokane				    (tp->data[3] << 24) |
90178848Scokane				    (tp->data[2] << 16) |
91178848Scokane				    (tp->data[1] << 8)  |
92178848Scokane				    tp->data[0]);
93178848Scokane				break;
94178848Scokane			case CIS_LONGLINK_C:	/* 0x12 */
95178848Scokane				printf("\tLong link to common memory, address 0x%x\n",
96178848Scokane				    (tp->data[3] << 24) |
97178848Scokane				    (tp->data[2] << 16) |
98178848Scokane				    (tp->data[1] << 8)  |
99178848Scokane				    tp->data[0]);
100178848Scokane				break;
101178848Scokane				break;
102178848Scokane			case CIS_INFO_V1:	/* 0x15 */
103178848Scokane				dump_info_v1(tp->data, tp->length);
104178848Scokane				break;
105178848Scokane			case CIS_ALTSTR:	/* 0x16 */
106178848Scokane				break;
107178848Scokane			case CIS_MEM_ATTR:	/* 0x17 */
108178848Scokane				dump_device_desc(tp->data, tp->length, "Attribute");
109178848Scokane				break;
110178848Scokane			case CIS_JEDEC_C:	/* 0x18 */
111178848Scokane				break;
112178848Scokane			case CIS_JEDEC_A:	/* 0x19 */
113178848Scokane				break;
114178848Scokane			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 (CIS_FEAT_POWER(feat)) {
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 & CIS_FEAT_TIMING) {
285		i = CIS_WAIT_SCALE(*p);
286		j = CIS_READY_SCALE(*p);
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 & CIS_FEAT_I_O) {
304		if (CIS_IO_ADDR(*p))
305			printf("\tCard decodes %d address lines",
306				CIS_IO_ADDR(*p));
307		else
308			printf("\tCard provides address decode");
309		switch (CIS_MEM_ADDRSZ(*p)) {
310		case 0:
311			break;
312		case 1:
313			printf(", 8 Bit I/O only");
314			break;
315		case 2:
316			printf(", limited 8/16 Bit I/O");
317			break;
318		case 3:
319			printf(", full 8/16 Bit I/O");
320			break;
321		}
322		printf("\n");
323		if (*p & CIS_IO_RANGE) {
324			p++;
325			c = *p++;
326			for (i = 0; i <= CIS_IO_BLKS(c); i++) {
327				printf("\t\tI/O address # %d: ", i + 1);
328				switch (CIS_IO_ADSZ(c)) {
329				case 0:
330					break;
331				case 1:
332					printf("block start = 0x%x", *p++);
333					break;
334				case 2:
335					printf("block start = 0x%x", (p[1] << 8) | *p);
336					p += 2;
337					break;
338				case 3:
339					printf("block start = 0x%x",
340					    (p[3] << 24) | (p[2] << 16) |
341					    (p[1] << 8) | *p);
342					p += 4;
343					break;
344				}
345				switch (CIS_IO_BLKSZ(c)) {
346				case 0:
347					break;
348				case 1:
349					printf(" block length = 0x%x", *p++ + 1);
350					break;
351				case 2:
352					printf(" block length = 0x%x", ((p[1] << 8) | *p) + 1);
353					p += 2;
354					break;
355				case 3:
356					printf(" block length = 0x%x",
357					    ((p[3] << 24) | (p[2] << 16) |
358						(p[1] << 8) | *p) + 1);
359					p += 4;
360					break;
361				}
362				printf("\n");
363			}
364		}
365	}
366
367	/* IRQ descriptor */
368	if (feat & CIS_FEAT_IRQ) {
369		printf("\t\tIRQ modes:");
370		c = ' ';
371		if (*p & CIS_IRQ_LEVEL) {
372			printf(" Level");
373			c = ',';
374		}
375		if (*p & CIS_IRQ_PULSE) {
376			printf("%c Pulse", c);
377			c = ',';
378		}
379		if (*p & CIS_IRQ_SHARING)
380			printf("%c Shared", c);
381		printf("\n");
382		if (*p & CIS_IRQ_MASK) {
383			i = p[0] | (p[1] << 8);
384			printf("\t\tIRQs: ");
385			if (*p & 1)
386				printf(" NMI");
387			if (*p & 0x2)
388				printf(" IOCK");
389			if (*p & 0x4)
390				printf(" BERR");
391			if (*p & 0x8)
392				printf(" VEND");
393			for (j = 0; j < 16; j++)
394				if (i & (1 << j))
395					printf(" %d", j);
396			printf("\n");
397			p += 3;
398		} else {
399			printf("\t\tIRQ level = %d\n", CIS_IRQ_IRQN(*p));
400			p++;
401		}
402	}
403	switch (CIS_FEAT_MEMORY(feat)) {
404	case 0:
405		break;
406	case 1:
407		printf("\tMemory space length = 0x%x\n", (p[1] << 8) | p[0]);
408		p += 2;
409		break;
410	case 2:
411		printf("\tMemory space address = 0x%x, length = 0x%x\n",
412		    (p[3] << 8) | p[2],
413		    (p[1] << 8) | p[0]);
414		p += 4;
415		break;
416
417	/* Memory descriptors. */
418	case 3:
419		c = *p++;
420		for (i = 0; i <= (c & 7); i++) {
421			printf("\tMemory descriptor %d\n\t\t", i + 1);
422			switch (CIS_MEM_LENSZ(c)) {
423			case 0:
424				break;
425			case 1:
426				printf(" blk length = 0x%x00", *p++);
427				break;
428			case 2:
429				printf(" blk length = 0x%x00", (p[1] << 8) | *p);
430				p += 2;
431				break;
432			case 3:
433				printf(" blk length = 0x%x00",
434				    (p[3] << 24) | (p[2] << 16) |
435				    (p[1] << 8) | *p);
436				p += 4;
437				break;
438			}
439			switch (CIS_MEM_ADDRSZ(c)) {
440			case 0:
441				break;
442			case 1:
443				printf(" card addr = 0x%x00", *p++);
444				break;
445			case 2:
446				printf(" card addr = 0x%x00", (p[1] << 8) | *p);
447				p += 2;
448				break;
449			case 3:
450				printf(" card addr = 0x%x00",
451				    (p[3] << 24) | (p[2] << 16) |
452				    (p[1] << 8) | *p);
453				p += 4;
454				break;
455			}
456			if (c & CIS_MEM_HOST)
457				switch ((c >> 5) & 3) {
458				case 0:
459					break;
460				case 1:
461					printf(" host addr = 0x%x00", *p++);
462					break;
463				case 2:
464					printf(" host addr = 0x%x00", (p[1] << 8) | *p);
465					p += 2;
466					break;
467				case 3:
468					printf(" host addr = 0x%x00",
469					    (p[3] << 24) | (p[2] << 16) |
470					    (p[1] << 8) | *p);
471					p += 4;
472					break;
473				}
474			printf("\n");
475		}
476		break;
477	}
478	if (feat & CIS_FEAT_MISC) {
479		printf("\tMax twin cards = %d\n", *p & 7);
480		printf("\tMisc attr:");
481		if (*p & 0x8)
482			printf(" (Audio-BVD2)");
483		if (*p & 0x10)
484			printf(" (Read-only)");
485		if (*p & 0x20)
486			printf(" (Power down supported)");
487		if (*p & 0x80) {
488			printf(" (Ext byte = 0x%x)", p[1]);
489			p++;
490		}
491		printf("\n");
492		p++;
493	}
494}
495
496/*
497 *	dump_other_cond - Dump other conditions.
498 */
499void
500dump_other_cond(unsigned char *p)
501{
502	if (p[0]) {
503		printf("\t");
504		if (p[0] & 1)
505			printf("(MWAIT)");
506		if (p[0] & 2)
507			printf(" (3V card)");
508		if (p[0] & 0x80)
509			printf(" (Extension bytes follow)");
510		printf("\n");
511	}
512}
513
514/*
515 *	Dump power descriptor.
516 */
517int
518dump_pwr_desc(unsigned char *p)
519{
520	int     len = 1, i;
521	unsigned char mask;
522	char  **expp;
523	static char *pname[] =
524	{"Nominal operating supply voltage",
525	 "Minimum operating supply voltage",
526	 "Maximum operating supply voltage",
527	 "Continuous supply current",
528	 "Max current average over 1 second",
529	 "Max current average over 10 ms",
530	 "Power down supply current",
531	 "Reserved"
532	};
533	static char *vexp[] =
534	{"10uV", "100uV", "1mV", "10mV", "100mV", "1V", "10V", "100V"};
535	static char *cexp[] =
536	{"10nA", "1uA", "10uA", "100uA", "1mA", "10mA", "100mA", "1A"};
537	static char *mant[] =
538	{"1", "1.2", "1.3", "1.5", "2", "2.5", "3", "3.5", "4", "4.5",
539	"5", "5.5", "6", "7", "8", "9"};
540
541	mask = *p++;
542	expp = vexp;
543	for (i = 0; i < 8; i++)
544		if (mask & (1 << i)) {
545			len++;
546			if (i >= 3)
547				expp = cexp;
548			printf("\t\t%s: ", pname[i]);
549			printf("%s x %s",
550			    mant[(*p >> 3) & 0xF],
551			    expp[*p & 7]);
552			while (*p & 0x80) {
553				len++;
554				p++;
555				printf(", ext = 0x%x", *p);
556			}
557			printf("\n");
558			p++;
559		}
560	return (len);
561}
562
563void
564dump_device_desc(unsigned char *p, int len, char *type)
565{
566	static char *un_name[] =
567	{"512b", "2Kb", "8Kb", "32Kb", "128Kb", "512Kb", "2Mb", "reserved"};
568	static char *speed[] =
569	{"No speed", "250nS", "200nS", "150nS",
570	"100nS", "Reserved", "Reserved"};
571	static char *dev[] =
572	{"No device", "Mask ROM", "OTPROM", "UV EPROM",
573	 "EEPROM", "FLASH EEPROM", "SRAM", "DRAM",
574	 "Reserved", "Reserved", "Reserved", "Reserved",
575	 "Reserved", "Function specific", "Extended",
576	"Reserved"};
577	int     count = 0;
578
579	while (*p != 0xFF && len > 0) {
580		unsigned char x;
581
582		x = *p++;
583		len -= 2;
584		if (count++ == 0)
585			printf("\t%s memory device information:\n", type);
586		printf("\t\tDevice number %d, type %s, WPS = %s\n",
587		    count, dev[x >> 4], (x & 0x8) ? "ON" : "OFF");
588		if ((x & 7) == 7) {
589			len--;
590			if (*p) {
591				printf("\t\t");
592				print_ext_speed(*p, 0);
593				while (*p & 0x80) {
594					p++;
595					len--;
596				}
597			}
598			p++;
599		} else
600			printf("\t\tSpeed = %s", speed[x & 7]);
601		printf(", Memory block size = %s, %d units\n",
602		    un_name[*p & 7], (*p >> 3) + 1);
603		p++;
604	}
605}
606
607/*
608 *	Print version info
609 */
610void
611dump_info_v1(unsigned char *p, int len)
612{
613	printf("\tVersion = %d.%d", p[0], p[1]);
614	p += 2;
615	printf(", Manuf = [%s],", p);
616	while (*p++);
617	printf("card vers = [%s]\n", p);
618	while (*p++);
619	printf("\tAddit. info = [%s]", p);
620	while (*p++);
621	printf(",[%s]\n", p);
622}
623
624/*
625 *	dump functional extension tuple.
626 */
627void
628dump_func_ext(unsigned char *p, int len)
629{
630	if (len == 0)
631		return;
632	switch (p[0]) {
633	case 0:
634	case 8:
635	case 10:
636		if (len != 4) {
637			printf("\tWrong length for serial extension\n");
638			return;
639		}
640		printf("\tSerial interface extension:\n");
641		switch (p[1] & 0x1F) {
642		default:
643			printf("\t\tUnkn device");
644			break;
645		case 0:
646			printf("\t\t8250 UART");
647			break;
648		case 1:
649			printf("\t\t16450 UART");
650			break;
651		case 2:
652			printf("\t\t16550 UART");
653			break;
654		}
655		printf(", Parity - %s%s%s%s",
656		    (p[2] & 1) ? "Space," : "",
657		    (p[2] & 2) ? "Mark," : "",
658		    (p[2] & 4) ? "Odd," : "",
659		    (p[2] & 8) ? "Even," : "");
660		printf("\n");
661		break;
662	case 1:
663	case 5:
664	case 6:
665	case 7:
666		printf("\tModem interface capabilities:\n");
667		break;
668	case 2:
669		printf("\tData modem services available:\n");
670		break;
671	case 9:
672		printf("\tFax/modem services available:\n");
673		break;
674	case 4:
675		printf("\tVoice services available:\n");
676		break;
677	}
678}
679
680/*
681 *	print_ext_speed - Print extended speed.
682 */
683void
684print_ext_speed(unsigned char x, int scale)
685{
686	static char *mant[] =
687	{"Reserved", "1.0", "1.2", "1.3", "1.5", "2.0", "2.5", "3.0",
688	"3.5", "4.0", "4.5", "5.0", "5.5", "6.0", "7.0", "8.0"};
689	static char *exp[] =
690	{"1 ns", "10 ns", "100 ns", "1 us", "10 us", "100 us",
691	"1 ms", "10 ms"};
692	static char *scale_name[] =
693	{"None", "10", "100", "1,000", "10,000", "100,000",
694	"1,000,000", "10,000,000"};
695
696	printf("Speed = %s x %s", mant[(x >> 3) & 0xF], exp[x & 7]);
697	if (scale)
698		printf(", scaled by %s", scale_name[scale & 7]);
699}
700