1/*======================================================================
2
3    PC Card CIS dump utility
4
5    dump_cis.c 1.63 2001/11/30 23:10:17
6
7    The contents of this file are subject to the Mozilla Public
8    License Version 1.1 (the "License"); you may not use this file
9    except in compliance with the License. You may obtain a copy of
10    the License at http://www.mozilla.org/MPL/
11
12    Software distributed under the License is distributed on an "AS
13    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14    implied. See the License for the specific language governing
15    rights and limitations under the License.
16
17    The initial developer of the original code is David A. Hinds
18    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
19    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
20
21    Alternatively, the contents of this file may be used under the
22    terms of the GNU General Public License version 2 (the "GPL"), in
23    which case the provisions of the GPL are applicable instead of the
24    above.  If you wish to allow the use of your version of this file
25    only under the terms of the GPL and not to allow others to use
26    your version of this file under the MPL, indicate your decision
27    by deleting the provisions above and replace them with the notice
28    and other provisions required by the GPL.  If you do not delete
29    the provisions above, a recipient may use your version of this
30    file under either the MPL or the GPL.
31
32======================================================================*/
33#if (defined(__BEOS__) || defined(__HAIKU__))
34#include <OS.h>
35#endif
36#include <sys/types.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41#include <fcntl.h>
42#include <errno.h>
43#include <sys/time.h>
44#include <sys/ioctl.h>
45#include <sys/stat.h>
46
47#include <pcmcia/cs_types.h>
48#include <pcmcia/cs.h>
49#include <pcmcia/cistpl.h>
50#include <pcmcia/ds.h>
51
52static int verbose = 0;
53static char indent[10] = "  ";
54
55/*====================================================================*/
56#if (!defined(__BEOS__) && !defined(__HAIKU__))
57static int major = 0;
58
59static int lookup_dev(char *name)
60{
61    FILE *f;
62    int n;
63    char s[32], t[32];
64
65    f = fopen("/proc/devices", "r");
66    if (f == NULL)
67	return -1;
68    while (fgets(s, 32, f) != NULL) {
69	if (sscanf(s, "%d %s", &n, t) == 2)
70	    if (strcmp(name, t) == 0)
71		break;
72    }
73    fclose(f);
74    if (strcmp(name, t) == 0)
75	return n;
76    else
77	return -1;
78}
79#endif
80/*====================================================================*/
81
82static int open_sock(int sock)
83{
84#if (defined(__BEOS__) || defined(__HAIKU__))
85    char fn[B_OS_NAME_LENGTH];
86    sprintf(fn, "/dev/bus/pcmcia/sock/%d", sock);
87    return open(fn, O_RDONLY);
88#else
89    static char *paths[] = {
90	"/var/lib/pcmcia", "/var/run", "/dev", "/tmp", NULL
91    };
92    int fd;
93    char **p, fn[64];
94    dev_t dev = (major<<8) + sock;
95
96    for (p = paths; *p; p++) {
97	sprintf(fn, "%s/dc%d", *p, getpid());
98	if (mknod(fn, (S_IFCHR|S_IREAD|S_IWRITE), dev) == 0) {
99	    fd = open(fn, O_RDONLY);
100	    unlink(fn);
101	    if (fd >= 0)
102		return fd;
103	    if (errno == ENODEV) break;
104	}
105    }
106    return -1;
107#endif
108} /* open_sock */
109
110/*====================================================================*/
111
112static void print_tuple(tuple_parse_t *tup)
113{
114    int i;
115    printf("%soffset 0x%2.2x, tuple 0x%2.2x, link 0x%2.2x\n",
116	   indent, tup->tuple.CISOffset, tup->tuple.TupleCode,
117	   tup->tuple.TupleLink);
118    for (i = 0; i < tup->tuple.TupleDataLen; i++) {
119	if ((i % 16) == 0) printf("%s  ", indent);
120	printf("%2.2x ", (u_char)tup->data[i]);
121	if ((i % 16) == 15) putchar('\n');
122    }
123    if ((i % 16) != 0) putchar('\n');
124}
125
126/*====================================================================*/
127
128static void print_funcid(cistpl_funcid_t *fn)
129{
130    printf("%sfuncid ", indent);
131    switch (fn->func) {
132    case CISTPL_FUNCID_MULTI:
133	printf("multi_function"); break;
134    case CISTPL_FUNCID_MEMORY:
135	printf("memory_card"); break;
136    case CISTPL_FUNCID_SERIAL:
137	printf("serial_port"); break;
138    case CISTPL_FUNCID_PARALLEL:
139	printf("parallel_port"); break;
140    case CISTPL_FUNCID_FIXED:
141	printf("fixed_disk"); break;
142    case CISTPL_FUNCID_VIDEO:
143	printf("video_adapter"); break;
144    case CISTPL_FUNCID_NETWORK:
145	printf("network_adapter"); break;
146    case CISTPL_FUNCID_AIMS:
147	printf("aims_card"); break;
148    case CISTPL_FUNCID_SCSI:
149	printf("scsi_adapter"); break;
150    default:
151	printf("unknown"); break;
152    }
153    if (fn->sysinit & CISTPL_SYSINIT_POST)
154	printf(" [post]");
155    if (fn->sysinit & CISTPL_SYSINIT_ROM)
156	printf(" [rom]");
157    putchar('\n');
158}
159
160/*====================================================================*/
161
162static void print_size(u_int size)
163{
164    if (size < 1024)
165	printf("%ub", size);
166    else if (size < 1024*1024)
167	printf("%ukb", size/1024);
168    else
169	printf("%umb", size/(1024*1024));
170}
171
172static void print_unit(u_int v, char *unit, char tag)
173{
174    int n;
175    for (n = 0; (v % 1000) == 0; n++) v /= 1000;
176    printf("%u", v);
177    if (n < strlen(unit)) putchar(unit[n]);
178    putchar(tag);
179}
180
181static void print_time(u_int tm, u_long scale)
182{
183    print_unit(tm * scale, "num", 's');
184}
185
186static void print_volt(u_int vi)
187{
188    print_unit(vi * 10, "um", 'V');
189}
190
191static void print_current(u_int ii)
192{
193    print_unit(ii / 10, "um", 'A');
194}
195
196static void print_speed(u_int b)
197{
198    if (b < 1000)
199	printf("%u bits/sec", b);
200    else if (b < 1000000)
201	printf("%u kb/sec", b/1000);
202    else
203	printf("%u mb/sec", b/1000000);
204}
205
206/*====================================================================*/
207
208static const char *dtype[] = {
209    "NULL", "ROM", "OTPROM", "EPROM", "EEPROM", "FLASH", "SRAM",
210    "DRAM", "rsvd", "rsvd", "rsvd", "rsvd", "rsvd", "fn_specific",
211    "extended", "rsvd"
212};
213
214static void print_device(cistpl_device_t *dev)
215{
216    int i;
217    for (i = 0; i < dev->ndev; i++) {
218	printf("%s  %s ", indent, dtype[dev->dev[i].type]);
219	printf("%uns, ", dev->dev[i].speed);
220	print_size(dev->dev[i].size);
221	putchar('\n');
222    }
223    if (dev->ndev == 0)
224	printf("%s  no_info\n", indent);
225}
226
227/*====================================================================*/
228
229static void print_power(char *tag, cistpl_power_t *power)
230{
231    int i, n;
232    for (i = n = 0; i < 8; i++)
233	if (power->present & (1<<i)) n++;
234    i = 0;
235    printf("%s  %s", indent, tag);
236    if (power->present & (1<<CISTPL_POWER_VNOM)) {
237	printf(" Vnom "); i++;
238	print_volt(power->param[CISTPL_POWER_VNOM]);
239    }
240    if (power->present & (1<<CISTPL_POWER_VMIN)) {
241	printf(" Vmin "); i++;
242	print_volt(power->param[CISTPL_POWER_VMIN]);
243    }
244    if (power->present & (1<<CISTPL_POWER_VMAX)) {
245 	printf(" Vmax "); i++;
246	print_volt(power->param[CISTPL_POWER_VMAX]);
247    }
248    if (power->present & (1<<CISTPL_POWER_ISTATIC)) {
249	printf(" Istatic "); i++;
250	print_current(power->param[CISTPL_POWER_ISTATIC]);
251    }
252    if (power->present & (1<<CISTPL_POWER_IAVG)) {
253	if (++i == 5) printf("\n%s   ", indent);
254	printf(" Iavg ");
255	print_current(power->param[CISTPL_POWER_IAVG]);
256    }
257    if (power->present & (1<<CISTPL_POWER_IPEAK)) {
258	if (++i == 5) printf("\n%s ", indent);
259	printf(" Ipeak ");
260	print_current(power->param[CISTPL_POWER_IPEAK]);
261    }
262    if (power->present & (1<<CISTPL_POWER_IDOWN)) {
263	if (++i == 5) printf("\n%s ", indent);
264	printf(" Idown ");
265	print_current(power->param[CISTPL_POWER_IDOWN]);
266    }
267    if (power->flags & CISTPL_POWER_HIGHZ_OK) {
268	if (++i == 5) printf("\n%s ", indent);
269	printf(" [highz OK]");
270    }
271    if (power->flags & CISTPL_POWER_HIGHZ_REQ) {
272	printf(" [highz]");
273    }
274    putchar('\n');
275}
276
277/*====================================================================*/
278
279static void print_cftable_entry(cistpl_cftable_entry_t *entry)
280{
281    int i;
282
283    printf("%scftable_entry 0x%2.2x%s\n", indent, entry->index,
284	   (entry->flags & CISTPL_CFTABLE_DEFAULT) ? " [default]" : "");
285
286    if (entry->flags & ~CISTPL_CFTABLE_DEFAULT) {
287	printf("%s ", indent);
288	if (entry->flags & CISTPL_CFTABLE_BVDS)
289	    printf(" [bvd]");
290	if (entry->flags & CISTPL_CFTABLE_WP)
291	    printf(" [wp]");
292	if (entry->flags & CISTPL_CFTABLE_RDYBSY)
293	    printf(" [rdybsy]");
294	if (entry->flags & CISTPL_CFTABLE_MWAIT)
295	    printf(" [mwait]");
296	if (entry->flags & CISTPL_CFTABLE_AUDIO)
297	    printf(" [audio]");
298	if (entry->flags & CISTPL_CFTABLE_READONLY)
299	    printf(" [readonly]");
300	if (entry->flags & CISTPL_CFTABLE_PWRDOWN)
301	    printf(" [pwrdown]");
302	putchar('\n');
303    }
304
305    if (entry->vcc.present)
306	print_power("Vcc", &entry->vcc);
307    if (entry->vpp1.present)
308	print_power("Vpp1", &entry->vpp1);
309    if (entry->vpp2.present)
310	print_power("Vpp2", &entry->vpp2);
311
312    if ((entry->timing.wait != 0) || (entry->timing.ready != 0) ||
313	(entry->timing.reserved != 0)) {
314	printf("%s  timing", indent);
315	if (entry->timing.wait != 0) {
316	    printf(" wait ");
317	    print_time(entry->timing.wait, entry->timing.waitscale);
318	}
319	if (entry->timing.ready != 0) {
320	    printf(" ready ");
321	    print_time(entry->timing.ready, entry->timing.rdyscale);
322	}
323	if (entry->timing.reserved != 0) {
324	    printf(" reserved ");
325	    print_time(entry->timing.reserved, entry->timing.rsvscale);
326	}
327	putchar('\n');
328    }
329
330    if (entry->io.nwin) {
331	cistpl_io_t *io = &entry->io;
332	printf("%s  io", indent);
333	for (i = 0; i < io->nwin; i++) {
334	    if (i) putchar(',');
335	    printf(" 0x%4.4x-0x%4.4x", io->win[i].base,
336		   io->win[i].base+io->win[i].len-1);
337	}
338	printf(" [lines=%d]", io->flags & CISTPL_IO_LINES_MASK);
339	if (io->flags & CISTPL_IO_8BIT) printf(" [8bit]");
340	if (io->flags & CISTPL_IO_16BIT) printf(" [16bit]");
341	if (io->flags & CISTPL_IO_RANGE) printf(" [range]");
342	putchar('\n');
343    }
344
345    if (entry->irq.IRQInfo1) {
346	printf("%s  irq ", indent);
347	if (entry->irq.IRQInfo1 & IRQ_INFO2_VALID)
348	    printf("mask 0x%04x", entry->irq.IRQInfo2);
349	else
350	    printf("%u", entry->irq.IRQInfo1 & IRQ_MASK);
351	if (entry->irq.IRQInfo1 & IRQ_LEVEL_ID) printf(" [level]");
352	if (entry->irq.IRQInfo1 & IRQ_PULSE_ID) printf(" [pulse]");
353	if (entry->irq.IRQInfo1 & IRQ_SHARE_ID) printf(" [shared]");
354	putchar('\n');
355    }
356
357    if (entry->mem.nwin) {
358	cistpl_mem_t *mem = &entry->mem;
359	printf("%s  memory", indent);
360	for (i = 0; i < mem->nwin; i++) {
361	    if (i) putchar(',');
362	    printf(" 0x%4.4x-0x%4.4x @ 0x%4.4x", mem->win[i].card_addr,
363		   mem->win[i].card_addr + mem->win[i].len-1,
364		   mem->win[i].host_addr);
365	}
366	putchar('\n');
367    }
368
369    if (verbose && entry->subtuples)
370	printf("%s  %d bytes in subtuples\n", indent, entry->subtuples);
371
372}
373
374/*====================================================================*/
375
376static void print_cftable_entry_cb(cistpl_cftable_entry_cb_t *entry)
377{
378    int i;
379
380    printf("%scftable_entry_cb 0x%2.2x%s\n", indent, entry->index,
381	   (entry->flags & CISTPL_CFTABLE_DEFAULT) ? " [default]" : "");
382
383    if (entry->flags & ~CISTPL_CFTABLE_DEFAULT) {
384	printf("%s ", indent);
385	if (entry->flags & CISTPL_CFTABLE_MASTER)
386	    printf(" [master]");
387	if (entry->flags & CISTPL_CFTABLE_INVALIDATE)
388	    printf(" [invalidate]");
389	if (entry->flags & CISTPL_CFTABLE_VGA_PALETTE)
390	    printf(" [vga palette]");
391	if (entry->flags & CISTPL_CFTABLE_PARITY)
392	    printf(" [parity]");
393	if (entry->flags & CISTPL_CFTABLE_WAIT)
394	    printf(" [wait]");
395	if (entry->flags & CISTPL_CFTABLE_SERR)
396	    printf(" [serr]");
397	if (entry->flags & CISTPL_CFTABLE_FAST_BACK)
398	    printf(" [fast back]");
399	if (entry->flags & CISTPL_CFTABLE_BINARY_AUDIO)
400	    printf(" [binary audio]");
401	if (entry->flags & CISTPL_CFTABLE_PWM_AUDIO)
402	    printf(" [pwm audio]");
403	putchar('\n');
404    }
405
406    if (entry->vcc.present)
407	print_power("Vcc", &entry->vcc);
408    if (entry->vpp1.present)
409	print_power("Vpp1", &entry->vpp1);
410    if (entry->vpp2.present)
411	print_power("Vpp2", &entry->vpp2);
412
413    if (entry->io) {
414	printf("%s  io_base", indent);
415	for (i = 0; i < 8; i++)
416	    if (entry->io & (1<<i)) printf(" %d", i);
417	putchar('\n');
418    }
419
420    if (entry->irq.IRQInfo1) {
421	printf("%s  irq ", indent);
422	if (entry->irq.IRQInfo1 & IRQ_INFO2_VALID)
423	    printf("mask 0x%4.4x", entry->irq.IRQInfo2);
424	else
425	    printf("%u", entry->irq.IRQInfo1 & IRQ_MASK);
426	if (entry->irq.IRQInfo1 & IRQ_LEVEL_ID) printf(" [level]");
427	if (entry->irq.IRQInfo1 & IRQ_PULSE_ID) printf(" [pulse]");
428	if (entry->irq.IRQInfo1 & IRQ_SHARE_ID) printf(" [shared]");
429	putchar('\n');
430    }
431
432    if (entry->mem) {
433	printf("%s  mem_base", indent);
434	for (i = 0; i < 8; i++)
435	    if (entry->mem & (1<<i)) printf(" %d", i);
436	putchar('\n');
437    }
438
439    if (verbose && entry->subtuples)
440	printf("%s  %d bytes in subtuples\n", indent,  entry->subtuples);
441
442}
443
444/*====================================================================*/
445
446static void print_jedec(cistpl_jedec_t *j)
447{
448    int i;
449    for (i = 0; i < j->nid; i++) {
450	if (i != 0) putchar(',');
451	printf(" 0x%02x 0x%02x", j->id[i].mfr, j->id[i].info);
452    }
453    putchar('\n');
454}
455
456/*====================================================================*/
457
458static void print_device_geo(cistpl_device_geo_t *geo)
459{
460    int i;
461    for (i = 0; i < geo->ngeo; i++) {
462	printf("%s  width %d erase 0x%x read 0x%x write 0x%x "
463	       "partition 0x%x interleave 0x%x\n", indent,
464	       geo->geo[i].buswidth, geo->geo[i].erase_block,
465	       geo->geo[i].read_block, geo->geo[i].write_block,
466	       geo->geo[i].partition, geo->geo[i].interleave);
467    }
468}
469
470/*====================================================================*/
471
472static void print_org(cistpl_org_t *org)
473{
474    printf("%sdata_org ", indent);
475    switch (org->data_org) {
476    case CISTPL_ORG_FS:
477	printf("[filesystem]"); break;
478    case CISTPL_ORG_APPSPEC:
479	printf("[app_specific]"); break;
480    case CISTPL_ORG_XIP:
481	printf("[code]"); break;
482    default:
483	if (org->data_org < 0x80)
484	    printf("[reserved]");
485	else
486	    printf("[vendor_specific]");
487    }
488    printf(", \"%s\"\n", org->desc);
489}
490
491/*====================================================================*/
492
493static char *data_mod[] = {
494    "Bell103", "V.21", "V.23", "V.22", "Bell212A", "V.22bis",
495    "V.26", "V.26bis", "V.27bis", "V.29", "V.32", "V.32bis",
496    "V.34", "rfu", "rfu", "rfu"
497};
498static char *fax_mod[] = {
499    "V.21-C2", "V.27ter", "V.29", "V.17", "V.33", "rfu", "rfu", "rfu"
500};
501static char *fax_features[] = {
502    "T.3", "T.4", "T.6", "error", "voice", "poll", "file", "passwd"
503};
504static char *cmd_protocol[] = {
505    "AT1", "AT2", "AT3", "MNP_AT", "V.25bis", "V.25A", "DMCL"
506};
507static char *uart[] = {
508    "8250", "16450", "16550", "8251", "8530", "85230"
509};
510static char *parity[] = { "space", "mark", "odd", "even" };
511static char *stop[] = { "1", "1.5", "2" };
512static char *flow[] = {
513    "XON/XOFF xmit", "XON/XOFF rcv", "hw xmit", "hw rcv", "transparent"
514};
515static void print_serial(cistpl_funce_t *funce)
516{
517    cistpl_serial_t *s;
518    cistpl_data_serv_t *ds;
519    cistpl_fax_serv_t *fs;
520    cistpl_modem_cap_t *cp;
521    int i, j;
522
523    switch (funce->type & 0x0f) {
524    case CISTPL_FUNCE_SERIAL_IF:
525    case CISTPL_FUNCE_SERIAL_IF_DATA:
526    case CISTPL_FUNCE_SERIAL_IF_FAX:
527    case CISTPL_FUNCE_SERIAL_IF_VOICE:
528	s = (cistpl_serial_t *)(funce->data);
529	printf("%sserial_interface", indent);
530	if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_IF_DATA)
531	    printf("_data");
532	else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_IF_FAX)
533	    printf("_fax");
534	else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_IF_VOICE)
535	    printf("_voice");
536	printf("\n%s  uart %s", indent,
537	       (s->uart_type < 6) ? uart[s->uart_type] : "reserved");
538	if (s->uart_cap_0) {
539	    printf(" [");
540	    for (i = 0; i < 4; i++)
541	        if (s->uart_cap_0 & (1<<i))
542		    printf("%s%s", parity[i],
543			   (s->uart_cap_0 >= (2<<i)) ? "/" : "]");
544	}
545	if (s->uart_cap_1) {
546	    int m = s->uart_cap_1 & 0x0f;
547	    int n = s->uart_cap_1 >> 4;
548	    printf(" [");
549	    for (i = 0; i < 4; i++)
550		if (m & (1<<i))
551		    printf("%d%s", i+5, (m >= (2<<i)) ? "/" : "");
552	    printf("] [");
553	    for (i = 0; i < 3; i++)
554	        if (n & (1<<i))
555		    printf("%s%s", stop[i], (n >= (2<<i)) ? "/" : "]");
556	}
557	printf("\n");
558	break;
559    case CISTPL_FUNCE_SERIAL_CAP:
560    case CISTPL_FUNCE_SERIAL_CAP_DATA:
561    case CISTPL_FUNCE_SERIAL_CAP_FAX:
562    case CISTPL_FUNCE_SERIAL_CAP_VOICE:
563	cp = (cistpl_modem_cap_t *)(funce->data);
564	printf("%sserial_modem_cap", indent);
565	if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_CAP_DATA)
566	    printf("_data");
567	else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_CAP_FAX)
568	    printf("_fax");
569	else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_CAP_VOICE)
570	    printf("_voice");
571	if (cp->flow) {
572	    printf("\n%s  flow", indent);
573	    for (i = 0; i < 5; i++)
574		if (cp->flow & (1<<i))
575		    printf(" [%s]", flow[i]);
576	}
577	printf("\n%s  cmd_buf %d rcv_buf %d xmit_buf %d\n",
578	       indent, 4*(cp->cmd_buf+1),
579	       cp->rcv_buf_0+(cp->rcv_buf_1<<8)+(cp->rcv_buf_2<<16),
580	       cp->xmit_buf_0+(cp->xmit_buf_1<<8)+(cp->xmit_buf_2<<16));
581	break;
582    case CISTPL_FUNCE_SERIAL_SERV_DATA:
583	ds = (cistpl_data_serv_t *)(funce->data);
584	printf("%sserial_data_services\n", indent);
585	printf("%s  data_rate %d\n", indent,
586	       75*((ds->max_data_0<<8) + ds->max_data_1));
587	printf("%s  modulation", indent);
588	for (i = j = 0; i < 16; i++)
589	    if (((ds->modulation_1<<8) + ds->modulation_0) & (1<<i)) {
590		if (++j % 6 == 0)
591		    printf("\n%s   ", indent);
592		printf(" [%s]", data_mod[i]);
593	    }
594	printf("\n");
595	if (ds->error_control) {
596	    printf("%s  error_control", indent);
597	    if (ds->error_control & CISTPL_SERIAL_ERR_MNP2_4)
598		printf(" [MNP2-4]");
599	    if (ds->error_control & CISTPL_SERIAL_ERR_V42_LAPM)
600		printf(" [V.42/LAPM]");
601	    printf("\n");
602	}
603	if (ds->compression) {
604	    printf("%s  compression", indent);
605	    if (ds->compression & CISTPL_SERIAL_CMPR_V42BIS)
606		printf(" [V.42bis]");
607	    if (ds->compression & CISTPL_SERIAL_CMPR_MNP5)
608		printf(" [MNP5]");
609	    printf("\n");
610	}
611	if (ds->cmd_protocol) {
612	    printf("%s  cmd_protocol", indent);
613	    for (i = 0; i < 7; i++)
614		if (ds->cmd_protocol & (1<<i))
615		    printf(" [%s]", cmd_protocol[i]);
616	    printf("\n");
617	}
618	break;
619
620    case CISTPL_FUNCE_SERIAL_SERV_FAX:
621	fs = (cistpl_fax_serv_t *)(funce->data);
622	printf("%sserial_fax_services [class=%d]\n",
623	       indent, funce->type>>4);
624	printf("%s  data_rate %d\n", indent,
625	       75*((fs->max_data_0<<8) + fs->max_data_1));
626	printf("%s  modulation", indent);
627	for (i = 0; i < 8; i++)
628	    if (fs->modulation & (1<<i))
629		printf(" [%s]", fax_mod[i]);
630	printf("\n");
631	if (fs->features_0) {
632	    printf("%s  features", indent);
633	    for (i = 0; i < 8; i++)
634		if (fs->features_0 & (1<<i))
635		    printf(" [%s]", fax_features[i]);
636	    printf("\n");
637	}
638	break;
639    }
640}
641
642/*====================================================================*/
643
644static void print_fixed(cistpl_funce_t *funce)
645{
646    cistpl_ide_interface_t *i;
647    cistpl_ide_feature_t *f;
648
649    switch (funce->type) {
650    case CISTPL_FUNCE_IDE_IFACE:
651	i = (cistpl_ide_interface_t *)(funce->data);
652	printf("%sdisk_interface ", indent);
653	if (i->interface == CISTPL_IDE_INTERFACE)
654	    printf("[ide]\n");
655	else
656	    printf("[undefined]\n");
657	break;
658    case CISTPL_FUNCE_IDE_MASTER:
659    case CISTPL_FUNCE_IDE_SLAVE:
660	f = (cistpl_ide_feature_t *)(funce->data);
661	printf("%sdisk_features", indent);
662	if (f->feature1 & CISTPL_IDE_SILICON)
663	    printf(" [silicon]");
664	else
665	    printf(" [rotating]");
666	if (f->feature1 & CISTPL_IDE_UNIQUE)
667	    printf(" [unique]");
668	if (f->feature1 & CISTPL_IDE_DUAL)
669	    printf(" [dual]");
670	else
671	    printf(" [single]");
672	if (f->feature1 && f->feature2)
673	    printf("\n%s ", indent);
674	if (f->feature2 & CISTPL_IDE_HAS_SLEEP)
675	    printf(" [sleep]");
676	if (f->feature2 & CISTPL_IDE_HAS_STANDBY)
677	    printf(" [standby]");
678	if (f->feature2 & CISTPL_IDE_HAS_IDLE)
679	    printf(" [idle]");
680	if (f->feature2 & CISTPL_IDE_LOW_POWER)
681	    printf(" [low power]");
682	if (f->feature2 & CISTPL_IDE_REG_INHIBIT)
683	    printf(" [reg inhibit]");
684	if (f->feature2 & CISTPL_IDE_HAS_INDEX)
685	    printf(" [index]");
686	if (f->feature2 & CISTPL_IDE_IOIS16)
687	    printf(" [iois16]");
688	putchar('\n');
689	break;
690    }
691}
692
693/*====================================================================*/
694
695static const char *tech[] = {
696    "undefined", "ARCnet", "ethernet", "token_ring", "localtalk",
697    "FDDI/CDDI", "ATM", "wireless"
698};
699
700static const char *media[] = {
701    "undefined", "unshielded_twisted_pair", "shielded_twisted_pair",
702    "thin_coax", "thick_coax", "fiber", "900_MHz", "2.4_GHz",
703    "5.4_GHz", "diffuse_infrared", "point_to_point_infrared"
704};
705
706static void print_network(cistpl_funce_t *funce)
707{
708    cistpl_lan_tech_t *t;
709    cistpl_lan_speed_t *s;
710    cistpl_lan_media_t *m;
711    cistpl_lan_node_id_t *n;
712    cistpl_lan_connector_t *c;
713    int i;
714
715    switch (funce->type) {
716    case CISTPL_FUNCE_LAN_TECH:
717	t = (cistpl_lan_tech_t *)(funce->data);
718	printf("%slan_technology %s\n", indent, tech[t->tech]);
719	break;
720    case CISTPL_FUNCE_LAN_SPEED:
721	s = (cistpl_lan_speed_t *)(funce->data);
722	printf("%slan_speed ", indent);
723	print_speed(s->speed);
724	putchar('\n');
725	break;
726    case CISTPL_FUNCE_LAN_MEDIA:
727	m = (cistpl_lan_media_t *)(funce->data);
728	printf("%slan_media %s\n", indent, media[m->media]);
729	break;
730    case CISTPL_FUNCE_LAN_NODE_ID:
731	n = (cistpl_lan_node_id_t *)(funce->data);
732	printf("%slan_node_id", indent);
733	for (i = 0; i < n->nb; i++)
734	    printf(" %02x", n->id[i]);
735	putchar('\n');
736	break;
737    case CISTPL_FUNCE_LAN_CONNECTOR:
738	c = (cistpl_lan_connector_t *)(funce->data);
739	printf("%slan_connector ", indent);
740	if (c->code == 0)
741	    printf("Open connector standard\n");
742	else
743	    printf("Closed connector standard\n");
744	break;
745    }
746}
747
748/*====================================================================*/
749
750static void print_vers_1(cistpl_vers_1_t *v1)
751{
752    int i, n;
753    char s[32];
754    sprintf(s, "%svers_1 %d.%d", indent, v1->major, v1->minor);
755    printf("%s", s);
756    n = strlen(s);
757    for (i = 0; i < v1->ns; i++) {
758	if (n + strlen(v1->str + v1->ofs[i]) + 4 > 72) {
759	    n = strlen(indent) + 2;
760	    printf(",\n%s  ", indent);
761	} else {
762	    printf(", ");
763	    n += 2;
764	}
765	printf("\"%s\"", v1->str + v1->ofs[i]);
766	n += strlen(v1->str + v1->ofs[i]) + 2;
767    }
768    putchar('\n');
769}
770
771/*====================================================================*/
772
773static void print_vers_2(cistpl_vers_2_t *v2)
774{
775    printf("%sversion 0x%2.2x, compliance 0x%2.2x, dindex 0x%4.4x\n",
776	   indent, v2->vers, v2->comply, v2->dindex);
777    printf("%s  vspec8 0x%2.2x, vspec9 0x%2.2x, nhdr %d\n",
778	   indent, v2->vspec8, v2->vspec9, v2->nhdr);
779    printf("%s  vendor \"%s\"\n", indent, v2->str+v2->vendor);
780    printf("%s  info \"%s\"\n", indent, v2->str+v2->info);
781}
782
783/*====================================================================*/
784
785#ifdef CISTPL_FORMAT_DISK
786static void print_format(cistpl_format_t *fmt)
787{
788    if (fmt->type == CISTPL_FORMAT_DISK)
789	printf("%s  [disk]", indent);
790    else if (fmt->type == CISTPL_FORMAT_MEM)
791	printf("%s  [memory]", indent);
792    else
793	printf("%s  [type 0x%02x]\n", indent, fmt->type);
794    if (fmt->edc == CISTPL_EDC_NONE)
795	printf(" [no edc]");
796    else if (fmt->edc == CISTPL_EDC_CKSUM)
797	printf(" [cksum]");
798    else if (fmt->edc == CISTPL_EDC_CRC)
799	printf(" [crc]");
800    else if (fmt->edc == CISTPL_EDC_PCC)
801	printf(" [pcc]");
802    else
803	printf(" [edc 0x%02x]", fmt->edc);
804    printf(" offset 0x%04x length ", fmt->offset);
805    print_size(fmt->length);
806    putchar('\n');
807}
808#endif
809
810/*====================================================================*/
811
812static void print_config(int code, cistpl_config_t *cfg)
813{
814    printf("%sconfig%s base 0x%4.4x", indent,
815	   (code == CISTPL_CONFIG_CB) ? "_cb" : "",
816	   cfg->base);
817    if (code == CISTPL_CONFIG)
818	printf(" mask 0x%4.4x", cfg->rmask[0]);
819    printf(" last_index 0x%2.2x\n", cfg->last_idx);
820    if (verbose && cfg->subtuples)
821	printf("%s  %d bytes in subtuples\n", indent, cfg->subtuples);
822}
823
824/*====================================================================*/
825
826static int nfn = 0, cur = 0;
827
828static void print_parse(tuple_parse_t *tup)
829{
830    static int func = 0;
831    int i;
832
833    switch (tup->tuple.TupleCode) {
834    case CISTPL_DEVICE:
835    case CISTPL_DEVICE_A:
836	if (tup->tuple.TupleCode == CISTPL_DEVICE)
837	    printf("%sdev_info\n", indent);
838	else
839	    printf("%sattr_dev_info\n", indent);
840	print_device(&tup->parse.device);
841	break;
842    case CISTPL_CHECKSUM:
843	printf("%schecksum 0x%04x-0x%04x = 0x%02x\n",
844	       indent, tup->parse.checksum.addr,
845	       tup->parse.checksum.addr+tup->parse.checksum.len-1,
846	       tup->parse.checksum.sum);
847	break;
848    case CISTPL_LONGLINK_A:
849	if (verbose)
850	    printf("%slong_link_attr 0x%04x\n", indent,
851		   tup->parse.longlink.addr);
852	break;
853    case CISTPL_LONGLINK_C:
854	if (verbose)
855	    printf("%slong_link 0x%04x\n", indent,
856		   tup->parse.longlink.addr);
857	break;
858    case CISTPL_LONGLINK_MFC:
859	if (verbose) {
860	    printf("%smfc_long_link\n", indent);
861	    for (i = 0; i < tup->parse.longlink_mfc.nfn; i++)
862		printf("%s function %d: %s 0x%04x\n", indent, i,
863		       tup->parse.longlink_mfc.fn[i].space ? "common" : "attr",
864		       tup->parse.longlink_mfc.fn[i].addr);
865	} else {
866	    printf("%smfc {\n", indent);
867	    nfn = tup->parse.longlink_mfc.nfn;
868	    cur = 0;
869	    strcat(indent, "  ");
870	}
871	break;
872    case CISTPL_NO_LINK:
873	if (verbose)
874	    printf("%sno_long_link\n", indent);
875	break;
876#ifdef CISTPL_INDIRECT
877    case CISTPL_INDIRECT:
878	if (verbose)
879	    printf("%sindirect_access\n", indent);
880	break;
881#endif
882    case CISTPL_LINKTARGET:
883	if (verbose)
884	    printf("%slink_target\n", indent);
885	else {
886	    if (cur++) printf("%s}, {\n", indent+2);
887	}
888	break;
889    case CISTPL_VERS_1:
890	print_vers_1(&tup->parse.version_1);
891	break;
892    case CISTPL_ALTSTR:
893	break;
894    case CISTPL_JEDEC_A:
895    case CISTPL_JEDEC_C:
896	if (tup->tuple.TupleCode == CISTPL_JEDEC_C)
897	    printf("%scommon_jedec", indent);
898	else
899	    printf("%sattr_jedec", indent);
900	print_jedec(&tup->parse.jedec);
901	break;
902    case CISTPL_DEVICE_GEO:
903    case CISTPL_DEVICE_GEO_A:
904	if (tup->tuple.TupleCode == CISTPL_DEVICE_GEO)
905	    printf("%scommon_geometry\n", indent);
906	else
907	    printf("%sattr_geometry\n", indent);
908	print_device_geo(&tup->parse.device_geo);
909	break;
910    case CISTPL_MANFID:
911	printf("%smanfid 0x%4.4x, 0x%4.4x\n", indent,
912	       tup->parse.manfid.manf, tup->parse.manfid.card);
913	break;
914    case CISTPL_FUNCID:
915	print_funcid(&tup->parse.funcid);
916	func = tup->parse.funcid.func;
917	break;
918    case CISTPL_FUNCE:
919	switch (func) {
920	case CISTPL_FUNCID_SERIAL:
921	    print_serial(&tup->parse.funce);
922	    break;
923	case CISTPL_FUNCID_FIXED:
924	    print_fixed(&tup->parse.funce);
925	    break;
926	case CISTPL_FUNCID_NETWORK:
927	    print_network(&tup->parse.funce);
928	    break;
929	}
930	break;
931    case CISTPL_BAR:
932	printf("%sBAR %d size ", indent,
933	       tup->parse.bar.attr & CISTPL_BAR_SPACE);
934	print_size(tup->parse.bar.size);
935	if (tup->parse.bar.attr & CISTPL_BAR_SPACE_IO)
936	    printf(" [io]");
937	else
938	    printf(" [mem]");
939	if (tup->parse.bar.attr & CISTPL_BAR_PREFETCH)
940	    printf(" [prefetch]");
941	if (tup->parse.bar.attr & CISTPL_BAR_CACHEABLE)
942	    printf(" [cacheable]");
943	if (tup->parse.bar.attr & CISTPL_BAR_1MEG_MAP)
944	    printf(" [<1mb]");
945	putchar('\n');
946	break;
947    case CISTPL_CONFIG:
948    case CISTPL_CONFIG_CB:
949	print_config(tup->tuple.TupleCode, &tup->parse.config);
950	break;
951    case CISTPL_CFTABLE_ENTRY:
952	print_cftable_entry(&tup->parse.cftable_entry);
953	break;
954    case CISTPL_CFTABLE_ENTRY_CB:
955	print_cftable_entry_cb(&tup->parse.cftable_entry_cb);
956	break;
957    case CISTPL_VERS_2:
958	print_vers_2(&tup->parse.vers_2);
959	break;
960    case CISTPL_ORG:
961	print_org(&tup->parse.org);
962	break;
963#ifdef CISTPL_FORMAT_DISK
964    case CISTPL_FORMAT:
965    case CISTPL_FORMAT_A:
966	if (tup->tuple.TupleCode == CISTPL_FORMAT)
967	    printf("%scommon_format\n", indent);
968	else
969	    printf("%sattr_format\n", indent);
970	print_format(&tup->parse.format);
971#endif
972    }
973}
974
975/*====================================================================*/
976
977static int get_tuple_buf(int fd, ds_ioctl_arg_t *arg, int first)
978{
979    u_int ofs;
980    static int nb = 0;
981    static u_char buf[1024];
982
983    if (first) {
984	nb = read(fd, buf, sizeof(buf));
985	arg->tuple.TupleLink = arg->tuple.CISOffset = 0;
986    }
987    ofs = arg->tuple.CISOffset + arg->tuple.TupleLink;
988    if (ofs >= nb) return -1;
989    arg->tuple.TupleCode = buf[ofs++];
990    arg->tuple.TupleDataLen = arg->tuple.TupleLink = buf[ofs++];
991    arg->tuple.CISOffset = ofs;
992    memcpy(arg->tuple_parse.data, buf+ofs, arg->tuple.TupleLink);
993    return 0;
994}
995
996static int get_tuple(int fd, ds_ioctl_arg_t *arg, int first)
997{
998    int cmd = (first) ? DS_GET_FIRST_TUPLE : DS_GET_NEXT_TUPLE;
999    if (ioctl(fd, cmd, arg) != 0) {
1000	if (errno == ENODEV)
1001	    printf("%sno card\n", indent);
1002	else if (errno != ENODATA)
1003	    printf("%sget tuple: %s\n", indent, strerror(errno));
1004	return -1;
1005    }
1006    if (ioctl(fd, DS_GET_TUPLE_DATA, arg) != 0) {
1007	printf("%sget tuple data: %s\n", indent, strerror(errno));
1008	return -1;
1009    }
1010    return 0;
1011}
1012
1013/*====================================================================*/
1014
1015#define MAX_SOCKS 8
1016
1017int main(int argc, char *argv[])
1018{
1019    int i, fd, pfd = -1;
1020    ds_ioctl_arg_t arg;
1021    int optch, errflg, first;
1022    int force = 0;
1023    char *infile = NULL;
1024
1025    errflg = 0;
1026    while ((optch = getopt(argc, argv, "fvi:")) != -1) {
1027	switch (optch) {
1028	case 'f':
1029	    force = 1; break;
1030	case 'v':
1031	    verbose = 1; break;
1032	case 'i':
1033	    infile = strdup(optarg); break;
1034	default:
1035	    errflg = 1; break;
1036	}
1037    }
1038    if (errflg || (optind < argc)) {
1039	fprintf(stderr, "usage: %s [-v] [-f] [-i infile]\n", argv[0]);
1040	exit(EXIT_FAILURE);
1041    }
1042
1043#if (!defined(__BEOS__) && !defined(__HAIKU__))
1044    major = lookup_dev("pcmcia");
1045    if (major < 0) {
1046	fprintf(stderr, "no pcmcia driver in /proc/devices\n");
1047	exit(EXIT_FAILURE);
1048    }
1049#endif
1050
1051    for (i = 0; (i < MAX_SOCKS) && !(i && infile); i++) {
1052	nfn = cur = 0;
1053	if (infile) {
1054	    indent[0] = '\0';
1055	    fd = open(infile, O_RDONLY);
1056	    if (fd < 0) {
1057		perror("open()");
1058		return -1;
1059	    }
1060	    pfd = open_sock(0);
1061	} else {
1062	    strcpy(indent, "  ");
1063	    fd = pfd = open_sock(i);
1064	}
1065	if (pfd < 0)
1066	    break;
1067	if (!verbose && (i > 0)) putchar('\n');
1068	if (!infile) printf("Socket %d:\n", i);
1069
1070	if (!force && !infile) {
1071	    if (ioctl(fd, DS_VALIDATE_CIS, &arg) != 0) {
1072		printf("%svalidate CIS: %s\n", indent, strerror(errno));
1073		continue;
1074	    }
1075	    if (arg.cisinfo.Chains == 0) {
1076		printf("%sno CIS present\n", indent);
1077		continue;
1078	    }
1079	}
1080
1081	arg.tuple.TupleDataMax = sizeof(arg.tuple_parse.data);
1082	arg.tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
1083	arg.tuple.DesiredTuple = RETURN_FIRST_TUPLE;
1084	arg.tuple.TupleOffset = 0;
1085
1086	for (first = 1; ; first = 0) {
1087	    if (infile) {
1088		if (get_tuple_buf(fd, &arg, first) != 0) break;
1089	    } else {
1090		if (get_tuple(fd, &arg, first) != 0) break;
1091	    }
1092	    if (verbose) print_tuple(&arg.tuple_parse);
1093	    if (ioctl(pfd, DS_PARSE_TUPLE, &arg) == 0)
1094		print_parse(&arg.tuple_parse);
1095	    else if (errno != ENOSYS)
1096		printf("%sparse error: %s\n", indent,
1097		       strerror(errno));
1098	    if (verbose) putchar('\n');
1099	    if (arg.tuple.TupleCode == CISTPL_END)
1100		break;
1101	}
1102
1103	if (!verbose && (nfn > 0))
1104	    printf("%s}\n", indent+2);
1105    }
1106    if ((i == 0) && (pfd < 0)) {
1107	perror("open()");
1108	return -1;
1109    }
1110
1111    return 0;
1112}
1113