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