Import from pcmcia-cs project a dump_cis utility. It reads
machine-readable CIS file and output text representation (which can be
processed by firmware/mkcis utility).

Signed-off-by: Dmitry Eremin-Solenikov <dbarysh...@gmail.com>
---
 Documentation/pcmcia/Makefile   |    3 +-
 Documentation/pcmcia/dump_cis.c | 1992 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 1994 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/pcmcia/dump_cis.c

diff --git a/Documentation/pcmcia/Makefile b/Documentation/pcmcia/Makefile
index accde87..d3a4b40 100644
--- a/Documentation/pcmcia/Makefile
+++ b/Documentation/pcmcia/Makefile
@@ -2,9 +2,10 @@
 obj- := dummy.o
 
 # List of programs to build
-hostprogs-y := crc32hash
+hostprogs-y := crc32hash dump_cis
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
 
 HOSTCFLAGS_crc32hash.o += -I$(objtree)/usr/include
+HOSTCFLAGS_dump_cis.o += -Iinclude/pcmcia
diff --git a/Documentation/pcmcia/dump_cis.c b/Documentation/pcmcia/dump_cis.c
new file mode 100644
index 0000000..4de8641
--- /dev/null
+++ b/Documentation/pcmcia/dump_cis.c
@@ -0,0 +1,1992 @@
+/***********************************************************************
+ *     PC Card CIS dump utility
+ *
+ *     dump_cis.c from pcmcia-cs
+ *
+ *     The contents of this file are subject to the Mozilla Public
+ *     License Version 1.1 (the "License"); you may not use this file
+ *     except in compliance with the License. You may obtain a copy of
+ *     the License at http://www.mozilla.org/MPL/
+ *
+ *     Software distributed under the License is distributed on an "AS
+ *     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ *     implied. See the License for the specific language governing
+ *     rights and limitations under the License.
+ *
+ *     The initial developer of the original code is David A. Hinds
+ *     <dahi...@users.sourceforge.net>.  Portions created by David A. Hinds
+ *     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ *     Alternatively, the contents of this file may be used under the
+ *     terms of the GNU Public License version 2 (the "GPL"), in which
+ *     case the provisions of the GPL are applicable instead of the
+ *     above.  If you wish to allow the use of your version of this file
+ *     only under the terms of the GPL and not to allow others to use
+ *     your version of this file under the MPL, indicate your decision
+ *     by deleting the provisions above and replace them with the notice
+ *     and other provisions required by the GPL.  If you do not delete
+ *     the provisions above, a recipient may use your version of this
+ *     file under either the MPL or the GPL.
+ ***********************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <endian.h>
+
+#ifndef le16toh
+#  include <byteswap.h>
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+#      define le16toh(x) (x)
+#      define le32toh(x) (x)
+#  else
+#      define le16toh(x) bswap_16(x)
+#      define le32toh(x) bswap_32(x)
+#  endif
+#endif
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <cistpl.h>
+
+/* Bits in IRQInfo1 field */
+#define IRQ_MASK                               0x0f
+#define IRQ_NMI_ID                             0x01
+#define IRQ_IOCK_ID                            0x02
+#define IRQ_BERR_ID                            0x04
+#define IRQ_VEND_ID                            0x08
+#define IRQ_INFO2_VALID                                0x10
+#define IRQ_LEVEL_ID                           0x20
+#define IRQ_PULSE_ID                           0x40
+#define IRQ_SHARE_ID                           0x80
+
+typedef struct tuple_parse_t {
+       tuple_t tuple;
+       cisdata_t data[255];
+       cisparse_t parse;
+} tuple_parse_t;
+
+static int get_tuple_buf(int fd, tuple_t * tuple, int first);
+static int parse_tuple(tuple_t * tuple, cisparse_t * parse);
+
+static int verbose;
+static char indent[10] = "  ";
+
+/*====================================================================*/
+
+static void print_tuple(tuple_parse_t * tup)
+{
+       int i;
+       printf("%soffset 0x%2.2x, tuple 0x%2.2x, link 0x%2.2x\n",
+              indent, tup->tuple.CISOffset, tup->tuple.TupleCode,
+              tup->tuple.TupleLink);
+       for (i = 0; i < tup->tuple.TupleDataLen; i++) {
+               if ((i % 16) == 0)
+                       printf("%s  ", indent);
+               printf("%2.2x ", (u_char) tup->data[i]);
+               if ((i % 16) == 15)
+                       putchar('\n');
+       }
+       if ((i % 16) != 0)
+               putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_funcid(cistpl_funcid_t * fn)
+{
+       printf("%sfuncid ", indent);
+       switch (fn->func) {
+       case CISTPL_FUNCID_MULTI:
+               printf("multi_function");
+               break;
+       case CISTPL_FUNCID_MEMORY:
+               printf("memory_card");
+               break;
+       case CISTPL_FUNCID_SERIAL:
+               printf("serial_port");
+               break;
+       case CISTPL_FUNCID_PARALLEL:
+               printf("parallel_port");
+               break;
+       case CISTPL_FUNCID_FIXED:
+               printf("fixed_disk");
+               break;
+       case CISTPL_FUNCID_VIDEO:
+               printf("video_adapter");
+               break;
+       case CISTPL_FUNCID_NETWORK:
+               printf("network_adapter");
+               break;
+       case CISTPL_FUNCID_AIMS:
+               printf("aims_card");
+               break;
+       case CISTPL_FUNCID_SCSI:
+               printf("scsi_adapter");
+               break;
+       default:
+               printf("unknown");
+               break;
+       }
+       if (fn->sysinit & CISTPL_SYSINIT_POST)
+               printf(" [post]");
+       if (fn->sysinit & CISTPL_SYSINIT_ROM)
+               printf(" [rom]");
+       putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_size(u_int size)
+{
+       if (size < 1024)
+               printf("%ub", size);
+       else if (size < 1024 * 1024)
+               printf("%ukb", size / 1024);
+       else
+               printf("%umb", size / (1024 * 1024));
+}
+
+static void print_unit(u_int v, char *unit, char tag)
+{
+       int n;
+       for (n = 0; (v % 1000) == 0; n++)
+               v /= 1000;
+       printf("%u", v);
+       if (n < strlen(unit))
+               putchar(unit[n]);
+       putchar(tag);
+}
+
+static void print_time(u_int tm, u_long scale)
+{
+       print_unit(tm * scale, "num", 's');
+}
+
+static void print_volt(u_int vi)
+{
+       print_unit(vi * 10, "um", 'V');
+}
+
+static void print_current(u_int ii)
+{
+       print_unit(ii / 10, "um", 'A');
+}
+
+static void print_speed(u_int b)
+{
+       if (b < 1000)
+               printf("%u bits/sec", b);
+       else if (b < 1000000)
+               printf("%u kb/sec", b / 1000);
+       else
+               printf("%u mb/sec", b / 1000000);
+}
+
+/*====================================================================*/
+
+static const char *dtype[] = {
+       "NULL", "ROM", "OTPROM", "EPROM", "EEPROM", "FLASH", "SRAM",
+       "DRAM", "rsvd", "rsvd", "rsvd", "rsvd", "rsvd", "fn_specific",
+       "extended", "rsvd"
+};
+
+static void print_device(cistpl_device_t * dev)
+{
+       int i;
+       for (i = 0; i < dev->ndev; i++) {
+               printf("%s  %s ", indent, dtype[dev->dev[i].type]);
+               printf("%uns, ", dev->dev[i].speed);
+               print_size(dev->dev[i].size);
+               putchar('\n');
+       }
+       if (dev->ndev == 0)
+               printf("%s  no_info\n", indent);
+}
+
+/*====================================================================*/
+
+static void print_power(char *tag, cistpl_power_t * power)
+{
+       int i, n;
+       for (i = n = 0; i < 8; i++)
+               if (power->present & (1 << i))
+                       n++;
+       i = 0;
+       printf("%s  %s", indent, tag);
+       if (power->present & (1 << CISTPL_POWER_VNOM)) {
+               printf(" Vnom ");
+               i++;
+               print_volt(power->param[CISTPL_POWER_VNOM]);
+       }
+       if (power->present & (1 << CISTPL_POWER_VMIN)) {
+               printf(" Vmin ");
+               i++;
+               print_volt(power->param[CISTPL_POWER_VMIN]);
+       }
+       if (power->present & (1 << CISTPL_POWER_VMAX)) {
+               printf(" Vmax ");
+               i++;
+               print_volt(power->param[CISTPL_POWER_VMAX]);
+       }
+       if (power->present & (1 << CISTPL_POWER_ISTATIC)) {
+               printf(" Istatic ");
+               i++;
+               print_current(power->param[CISTPL_POWER_ISTATIC]);
+       }
+       if (power->present & (1 << CISTPL_POWER_IAVG)) {
+               if (++i == 5)
+                       printf("\n%s   ", indent);
+               printf(" Iavg ");
+               print_current(power->param[CISTPL_POWER_IAVG]);
+       }
+       if (power->present & (1 << CISTPL_POWER_IPEAK)) {
+               if (++i == 5)
+                       printf("\n%s ", indent);
+               printf(" Ipeak ");
+               print_current(power->param[CISTPL_POWER_IPEAK]);
+       }
+       if (power->present & (1 << CISTPL_POWER_IDOWN)) {
+               if (++i == 5)
+                       printf("\n%s ", indent);
+               printf(" Idown ");
+               print_current(power->param[CISTPL_POWER_IDOWN]);
+       }
+       if (power->flags & CISTPL_POWER_HIGHZ_OK) {
+               if (++i == 5)
+                       printf("\n%s ", indent);
+               printf(" [highz OK]");
+       }
+       if (power->flags & CISTPL_POWER_HIGHZ_REQ) {
+               printf(" [highz]");
+       }
+       putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_cftable_entry(cistpl_cftable_entry_t * entry)
+{
+       int i;
+
+       printf("%scftable_entry 0x%2.2x%s\n", indent, entry->index,
+              (entry->flags & CISTPL_CFTABLE_DEFAULT) ? " [default]" : "");
+
+       if (entry->flags & ~CISTPL_CFTABLE_DEFAULT) {
+               printf("%s ", indent);
+               if (entry->flags & CISTPL_CFTABLE_BVDS)
+                       printf(" [bvd]");
+               if (entry->flags & CISTPL_CFTABLE_WP)
+                       printf(" [wp]");
+               if (entry->flags & CISTPL_CFTABLE_RDYBSY)
+                       printf(" [rdybsy]");
+               if (entry->flags & CISTPL_CFTABLE_MWAIT)
+                       printf(" [mwait]");
+               if (entry->flags & CISTPL_CFTABLE_AUDIO)
+                       printf(" [audio]");
+               if (entry->flags & CISTPL_CFTABLE_READONLY)
+                       printf(" [readonly]");
+               if (entry->flags & CISTPL_CFTABLE_PWRDOWN)
+                       printf(" [pwrdown]");
+               putchar('\n');
+       }
+
+       if (entry->vcc.present)
+               print_power("Vcc", &entry->vcc);
+       if (entry->vpp1.present)
+               print_power("Vpp1", &entry->vpp1);
+       if (entry->vpp2.present)
+               print_power("Vpp2", &entry->vpp2);
+
+       if ((entry->timing.wait != 0) || (entry->timing.ready != 0) ||
+           (entry->timing.reserved != 0)) {
+               printf("%s  timing", indent);
+               if (entry->timing.wait != 0) {
+                       printf(" wait ");
+                       print_time(entry->timing.wait, entry->timing.waitscale);
+               }
+               if (entry->timing.ready != 0) {
+                       printf(" ready ");
+                       print_time(entry->timing.ready, entry->timing.rdyscale);
+               }
+               if (entry->timing.reserved != 0) {
+                       printf(" reserved ");
+                       print_time(entry->timing.reserved,
+                                  entry->timing.rsvscale);
+               }
+               putchar('\n');
+       }
+
+       if (entry->io.nwin) {
+               cistpl_io_t *io = &entry->io;
+               printf("%s  io", indent);
+               for (i = 0; i < io->nwin; i++) {
+                       if (i)
+                               putchar(',');
+                       printf(" 0x%4.4x-0x%4.4x", io->win[i].base,
+                              io->win[i].base + io->win[i].len - 1);
+               }
+               printf(" [lines=%d]", io->flags & CISTPL_IO_LINES_MASK);
+               if (io->flags & CISTPL_IO_8BIT)
+                       printf(" [8bit]");
+               if (io->flags & CISTPL_IO_16BIT)
+                       printf(" [16bit]");
+               if (io->flags & CISTPL_IO_RANGE)
+                       printf(" [range]");
+               putchar('\n');
+       }
+
+       if (entry->irq.IRQInfo1) {
+               printf("%s  irq ", indent);
+               if (entry->irq.IRQInfo1 & IRQ_INFO2_VALID)
+                       printf("mask 0x%04x", entry->irq.IRQInfo2);
+               else
+                       printf("%u", entry->irq.IRQInfo1 & IRQ_MASK);
+               if (entry->irq.IRQInfo1 & IRQ_LEVEL_ID)
+                       printf(" [level]");
+               if (entry->irq.IRQInfo1 & IRQ_PULSE_ID)
+                       printf(" [pulse]");
+               if (entry->irq.IRQInfo1 & IRQ_SHARE_ID)
+                       printf(" [shared]");
+               putchar('\n');
+       }
+
+       if (entry->mem.nwin) {
+               cistpl_mem_t *mem = &entry->mem;
+               printf("%s  memory", indent);
+               for (i = 0; i < mem->nwin; i++) {
+                       if (i)
+                               putchar(',');
+                       printf(" 0x%4.4x-0x%4.4x @ 0x%4.4x",
+                              mem->win[i].card_addr,
+                              mem->win[i].card_addr + mem->win[i].len - 1,
+                              mem->win[i].host_addr);
+               }
+               putchar('\n');
+       }
+
+       if (verbose && entry->subtuples)
+               printf("%s  %d bytes in subtuples\n", indent, entry->subtuples);
+
+}
+
+/*====================================================================*/
+
+static void print_cftable_entry_cb(cistpl_cftable_entry_cb_t * entry)
+{
+       int i;
+
+       printf("%scftable_entry_cb 0x%2.2x%s\n", indent, entry->index,
+              (entry->flags & CISTPL_CFTABLE_DEFAULT) ? " [default]" : "");
+
+       if (entry->flags & ~CISTPL_CFTABLE_DEFAULT) {
+               printf("%s ", indent);
+               if (entry->flags & CISTPL_CFTABLE_MASTER)
+                       printf(" [master]");
+               if (entry->flags & CISTPL_CFTABLE_INVALIDATE)
+                       printf(" [invalidate]");
+               if (entry->flags & CISTPL_CFTABLE_VGA_PALETTE)
+                       printf(" [vga palette]");
+               if (entry->flags & CISTPL_CFTABLE_PARITY)
+                       printf(" [parity]");
+               if (entry->flags & CISTPL_CFTABLE_WAIT)
+                       printf(" [wait]");
+               if (entry->flags & CISTPL_CFTABLE_SERR)
+                       printf(" [serr]");
+               if (entry->flags & CISTPL_CFTABLE_FAST_BACK)
+                       printf(" [fast back]");
+               if (entry->flags & CISTPL_CFTABLE_BINARY_AUDIO)
+                       printf(" [binary audio]");
+               if (entry->flags & CISTPL_CFTABLE_PWM_AUDIO)
+                       printf(" [pwm audio]");
+               putchar('\n');
+       }
+
+       if (entry->vcc.present)
+               print_power("Vcc", &entry->vcc);
+       if (entry->vpp1.present)
+               print_power("Vpp1", &entry->vpp1);
+       if (entry->vpp2.present)
+               print_power("Vpp2", &entry->vpp2);
+
+       if (entry->io) {
+               printf("%s  io_base", indent);
+               for (i = 0; i < 8; i++)
+                       if (entry->io & (1 << i))
+                               printf(" %d", i);
+               putchar('\n');
+       }
+
+       if (entry->irq.IRQInfo1) {
+               printf("%s  irq ", indent);
+               if (entry->irq.IRQInfo1 & IRQ_INFO2_VALID)
+                       printf("mask 0x%4.4x", entry->irq.IRQInfo2);
+               else
+                       printf("%u", entry->irq.IRQInfo1 & IRQ_MASK);
+               if (entry->irq.IRQInfo1 & IRQ_LEVEL_ID)
+                       printf(" [level]");
+               if (entry->irq.IRQInfo1 & IRQ_PULSE_ID)
+                       printf(" [pulse]");
+               if (entry->irq.IRQInfo1 & IRQ_SHARE_ID)
+                       printf(" [shared]");
+               putchar('\n');
+       }
+
+       if (entry->mem) {
+               printf("%s  mem_base", indent);
+               for (i = 0; i < 8; i++)
+                       if (entry->mem & (1 << i))
+                               printf(" %d", i);
+               putchar('\n');
+       }
+
+       if (verbose && entry->subtuples)
+               printf("%s  %d bytes in subtuples\n", indent, entry->subtuples);
+
+}
+
+/*====================================================================*/
+
+static void print_jedec(cistpl_jedec_t * j)
+{
+       int i;
+       for (i = 0; i < j->nid; i++) {
+               if (i != 0)
+                       putchar(',');
+               printf(" 0x%02x 0x%02x", j->id[i].mfr, j->id[i].info);
+       }
+       putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_device_geo(cistpl_device_geo_t * geo)
+{
+       int i;
+       for (i = 0; i < geo->ngeo; i++) {
+               printf("%s  width %d erase 0x%x read 0x%x write 0x%x "
+                      "partition 0x%x interleave 0x%x\n", indent,
+                      geo->geo[i].buswidth, geo->geo[i].erase_block,
+                      geo->geo[i].read_block, geo->geo[i].write_block,
+                      geo->geo[i].partition, geo->geo[i].interleave);
+       }
+}
+
+/*====================================================================*/
+
+static void print_org(cistpl_org_t * org)
+{
+       printf("%sdata_org ", indent);
+       switch (org->data_org) {
+       case CISTPL_ORG_FS:
+               printf("[filesystem]");
+               break;
+       case CISTPL_ORG_APPSPEC:
+               printf("[app_specific]");
+               break;
+       case CISTPL_ORG_XIP:
+               printf("[code]");
+               break;
+       default:
+               if (org->data_org < 0x80)
+                       printf("[reserved]");
+               else
+                       printf("[vendor_specific]");
+       }
+       printf(", \"%s\"\n", org->desc);
+}
+
+/*====================================================================*/
+
+static char *data_mod[] = {
+       "Bell103", "V.21", "V.23", "V.22", "Bell212A", "V.22bis",
+       "V.26", "V.26bis", "V.27bis", "V.29", "V.32", "V.32bis",
+       "V.34", "rfu", "rfu", "rfu"
+};
+
+static char *fax_mod[] = {
+       "V.21-C2", "V.27ter", "V.29", "V.17", "V.33", "rfu", "rfu", "rfu"
+};
+
+static char *fax_features[] = {
+       "T.3", "T.4", "T.6", "error", "voice", "poll", "file", "passwd"
+};
+
+static char *cmd_protocol[] = {
+       "AT1", "AT2", "AT3", "MNP_AT", "V.25bis", "V.25A", "DMCL"
+};
+
+static char *uart[] = {
+       "8250", "16450", "16550", "8251", "8530", "85230"
+};
+static char *parity[] = { "space", "mark", "odd", "even" };
+static char *stop[] = { "1", "1.5", "2" };
+
+static char *flow[] = {
+       "XON/XOFF xmit", "XON/XOFF rcv", "hw xmit", "hw rcv", "transparent"
+};
+
+static void print_serial(cistpl_funce_t * funce)
+{
+       cistpl_serial_t *s;
+       cistpl_data_serv_t *ds;
+       cistpl_fax_serv_t *fs;
+       cistpl_modem_cap_t *cp;
+       int i, j;
+
+       switch (funce->type & 0x0f) {
+       case CISTPL_FUNCE_SERIAL_IF:
+       case CISTPL_FUNCE_SERIAL_IF_DATA:
+       case CISTPL_FUNCE_SERIAL_IF_FAX:
+       case CISTPL_FUNCE_SERIAL_IF_VOICE:
+               s = (cistpl_serial_t *) (funce->data);
+               printf("%sserial_interface", indent);
+               if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_IF_DATA)
+                       printf("_data");
+               else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_IF_FAX)
+                       printf("_fax");
+               else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_IF_VOICE)
+                       printf("_voice");
+               printf("\n%s  uart %s", indent,
+                      (s->uart_type < 6) ? uart[s->uart_type] : "reserved");
+               if (s->uart_cap_0) {
+                       printf(" [");
+                       for (i = 0; i < 4; i++)
+                               if (s->uart_cap_0 & (1 << i))
+                                       printf("%s%s", parity[i],
+                                              (s->uart_cap_0 >=
+                                               (2 << i)) ? "/" : "]");
+               }
+               if (s->uart_cap_1) {
+                       int m = s->uart_cap_1 & 0x0f;
+                       int n = s->uart_cap_1 >> 4;
+                       printf(" [");
+                       for (i = 0; i < 4; i++)
+                               if (m & (1 << i))
+                                       printf("%d%s", i + 5,
+                                              (m >= (2 << i)) ? "/" : "");
+                       printf("] [");
+                       for (i = 0; i < 3; i++)
+                               if (n & (1 << i))
+                                       printf("%s%s", stop[i],
+                                              (n >= (2 << i)) ? "/" : "]");
+               }
+               printf("\n");
+               break;
+       case CISTPL_FUNCE_SERIAL_CAP:
+       case CISTPL_FUNCE_SERIAL_CAP_DATA:
+       case CISTPL_FUNCE_SERIAL_CAP_FAX:
+       case CISTPL_FUNCE_SERIAL_CAP_VOICE:
+               cp = (cistpl_modem_cap_t *) (funce->data);
+               printf("%sserial_modem_cap", indent);
+               if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_CAP_DATA)
+                       printf("_data");
+               else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_CAP_FAX)
+                       printf("_fax");
+               else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_CAP_VOICE)
+                       printf("_voice");
+               if (cp->flow) {
+                       printf("\n%s  flow", indent);
+                       for (i = 0; i < 5; i++)
+                               if (cp->flow & (1 << i))
+                                       printf(" [%s]", flow[i]);
+               }
+               printf("\n%s  cmd_buf %d rcv_buf %d xmit_buf %d\n",
+                      indent, 4 * (cp->cmd_buf + 1),
+                      cp->rcv_buf_0 + (cp->rcv_buf_1 << 8) +
+                      (cp->rcv_buf_2 << 16),
+                      cp->xmit_buf_0 + (cp->xmit_buf_1 << 8) +
+                      (cp->xmit_buf_2 << 16));
+               break;
+       case CISTPL_FUNCE_SERIAL_SERV_DATA:
+               ds = (cistpl_data_serv_t *) (funce->data);
+               printf("%sserial_data_services\n", indent);
+               printf("%s  data_rate %d\n", indent,
+                      75 * ((ds->max_data_0 << 8) + ds->max_data_1));
+               printf("%s  modulation", indent);
+               for (i = j = 0; i < 16; i++)
+                       if (((ds->modulation_1 << 8) +
+                            ds->modulation_0) & (1 << i)) {
+                               if (++j % 6 == 0)
+                                       printf("\n%s   ", indent);
+                               printf(" [%s]", data_mod[i]);
+                       }
+               printf("\n");
+               if (ds->error_control) {
+                       printf("%s  error_control", indent);
+                       if (ds->error_control & CISTPL_SERIAL_ERR_MNP2_4)
+                               printf(" [MNP2-4]");
+                       if (ds->error_control & CISTPL_SERIAL_ERR_V42_LAPM)
+                               printf(" [V.42/LAPM]");
+                       printf("\n");
+               }
+               if (ds->compression) {
+                       printf("%s  compression", indent);
+                       if (ds->compression & CISTPL_SERIAL_CMPR_V42BIS)
+                               printf(" [V.42bis]");
+                       if (ds->compression & CISTPL_SERIAL_CMPR_MNP5)
+                               printf(" [MNP5]");
+                       printf("\n");
+               }
+               if (ds->cmd_protocol) {
+                       printf("%s  cmd_protocol", indent);
+                       for (i = 0; i < 7; i++)
+                               if (ds->cmd_protocol & (1 << i))
+                                       printf(" [%s]", cmd_protocol[i]);
+                       printf("\n");
+               }
+               break;
+
+       case CISTPL_FUNCE_SERIAL_SERV_FAX:
+               fs = (cistpl_fax_serv_t *) (funce->data);
+               printf("%sserial_fax_services [class=%d]\n",
+                      indent, funce->type >> 4);
+               printf("%s  data_rate %d\n", indent,
+                      75 * ((fs->max_data_0 << 8) + fs->max_data_1));
+               printf("%s  modulation", indent);
+               for (i = 0; i < 8; i++)
+                       if (fs->modulation & (1 << i))
+                               printf(" [%s]", fax_mod[i]);
+               printf("\n");
+               if (fs->features_0) {
+                       printf("%s  features", indent);
+                       for (i = 0; i < 8; i++)
+                               if (fs->features_0 & (1 << i))
+                                       printf(" [%s]", fax_features[i]);
+                       printf("\n");
+               }
+               break;
+       }
+}
+
+/*====================================================================*/
+
+static void print_fixed(cistpl_funce_t * funce)
+{
+       cistpl_ide_interface_t *i;
+       cistpl_ide_feature_t *f;
+
+       switch (funce->type) {
+       case CISTPL_FUNCE_IDE_IFACE:
+               i = (cistpl_ide_interface_t *) (funce->data);
+               printf("%sdisk_interface ", indent);
+               if (i->interface == CISTPL_IDE_INTERFACE)
+                       printf("[ide]\n");
+               else
+                       printf("[undefined]\n");
+               break;
+       case CISTPL_FUNCE_IDE_MASTER:
+       case CISTPL_FUNCE_IDE_SLAVE:
+               f = (cistpl_ide_feature_t *) (funce->data);
+               printf("%sdisk_features", indent);
+               if (f->feature1 & CISTPL_IDE_SILICON)
+                       printf(" [silicon]");
+               else
+                       printf(" [rotating]");
+               if (f->feature1 & CISTPL_IDE_UNIQUE)
+                       printf(" [unique]");
+               if (f->feature1 & CISTPL_IDE_DUAL)
+                       printf(" [dual]");
+               else
+                       printf(" [single]");
+               if (f->feature1 && f->feature2)
+                       printf("\n%s ", indent);
+               if (f->feature2 & CISTPL_IDE_HAS_SLEEP)
+                       printf(" [sleep]");
+               if (f->feature2 & CISTPL_IDE_HAS_STANDBY)
+                       printf(" [standby]");
+               if (f->feature2 & CISTPL_IDE_HAS_IDLE)
+                       printf(" [idle]");
+               if (f->feature2 & CISTPL_IDE_LOW_POWER)
+                       printf(" [low power]");
+               if (f->feature2 & CISTPL_IDE_REG_INHIBIT)
+                       printf(" [reg inhibit]");
+               if (f->feature2 & CISTPL_IDE_HAS_INDEX)
+                       printf(" [index]");
+               if (f->feature2 & CISTPL_IDE_IOIS16)
+                       printf(" [iois16]");
+               putchar('\n');
+               break;
+       }
+}
+
+/*====================================================================*/
+
+static const char *tech[] = {
+       "undefined", "ARCnet", "ethernet", "token_ring", "localtalk",
+       "FDDI/CDDI", "ATM", "wireless"
+};
+
+static const char *media[] = {
+       "undefined", "unshielded_twisted_pair", "shielded_twisted_pair",
+       "thin_coax", "thick_coax", "fiber", "900_MHz", "2.4_GHz",
+       "5.4_GHz", "diffuse_infrared", "point_to_point_infrared"
+};
+
+static void print_network(cistpl_funce_t * funce)
+{
+       cistpl_lan_tech_t *t;
+       cistpl_lan_speed_t *s;
+       cistpl_lan_media_t *m;
+       cistpl_lan_node_id_t *n;
+       cistpl_lan_connector_t *c;
+       int i;
+
+       switch (funce->type) {
+       case CISTPL_FUNCE_LAN_TECH:
+               t = (cistpl_lan_tech_t *) (funce->data);
+               printf("%slan_technology %s\n", indent, tech[t->tech]);
+               break;
+       case CISTPL_FUNCE_LAN_SPEED:
+               s = (cistpl_lan_speed_t *) (funce->data);
+               printf("%slan_speed ", indent);
+               print_speed(s->speed);
+               putchar('\n');
+               break;
+       case CISTPL_FUNCE_LAN_MEDIA:
+               m = (cistpl_lan_media_t *) (funce->data);
+               printf("%slan_media %s\n", indent, media[m->media]);
+               break;
+       case CISTPL_FUNCE_LAN_NODE_ID:
+               n = (cistpl_lan_node_id_t *) (funce->data);
+               printf("%slan_node_id", indent);
+               for (i = 0; i < n->nb; i++)
+                       printf(" %02x", n->id[i]);
+               putchar('\n');
+               break;
+       case CISTPL_FUNCE_LAN_CONNECTOR:
+               c = (cistpl_lan_connector_t *) (funce->data);
+               printf("%slan_connector ", indent);
+               if (c->code == 0)
+                       printf("Open connector standard\n");
+               else
+                       printf("Closed connector standard\n");
+               break;
+       }
+}
+
+/*====================================================================*/
+
+static void print_vers_1(cistpl_vers_1_t * v1)
+{
+       int i, n;
+       char s[32];
+       sprintf(s, "%svers_1 %d.%d", indent, v1->major, v1->minor);
+       printf("%s", s);
+       n = strlen(s);
+       for (i = 0; i < v1->ns; i++) {
+               if (n + strlen(v1->str + v1->ofs[i]) + 4 > 72) {
+                       n = strlen(indent) + 2;
+                       printf(",\n%s  ", indent);
+               } else {
+                       printf(", ");
+                       n += 2;
+               }
+               printf("\"%s\"", v1->str + v1->ofs[i]);
+               n += strlen(v1->str + v1->ofs[i]) + 2;
+       }
+       putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_vers_2(cistpl_vers_2_t * v2)
+{
+       printf("%sversion 0x%2.2x, compliance 0x%2.2x, dindex 0x%4.4x\n",
+              indent, v2->vers, v2->comply, v2->dindex);
+       printf("%s  vspec8 0x%2.2x, vspec9 0x%2.2x, nhdr %d\n",
+              indent, v2->vspec8, v2->vspec9, v2->nhdr);
+       printf("%s  vendor \"%s\"\n", indent, v2->str + v2->vendor);
+       printf("%s  info \"%s\"\n", indent, v2->str + v2->info);
+}
+
+/*====================================================================*/
+
+#ifdef CISTPL_FORMAT_DISK
+static void print_format(cistpl_format_t * fmt)
+{
+       if (fmt->type == CISTPL_FORMAT_DISK)
+               printf("%s  [disk]", indent);
+       else if (fmt->type == CISTPL_FORMAT_MEM)
+               printf("%s  [memory]", indent);
+       else
+               printf("%s  [type 0x%02x]\n", indent, fmt->type);
+       if (fmt->edc == CISTPL_EDC_NONE)
+               printf(" [no edc]");
+       else if (fmt->edc == CISTPL_EDC_CKSUM)
+               printf(" [cksum]");
+       else if (fmt->edc == CISTPL_EDC_CRC)
+               printf(" [crc]");
+       else if (fmt->edc == CISTPL_EDC_PCC)
+               printf(" [pcc]");
+       else
+               printf(" [edc 0x%02x]", fmt->edc);
+       printf(" offset 0x%04x length ", fmt->offset);
+       print_size(fmt->length);
+       putchar('\n');
+}
+#endif
+
+/*====================================================================*/
+
+static void print_config(int code, cistpl_config_t * cfg)
+{
+       printf("%sconfig%s base 0x%4.4x", indent,
+              (code == CISTPL_CONFIG_CB) ? "_cb" : "", cfg->base);
+       if (code == CISTPL_CONFIG)
+               printf(" mask 0x%4.4x", cfg->rmask[0]);
+       printf(" last_index 0x%2.2x\n", cfg->last_idx);
+       if (verbose && cfg->subtuples)
+               printf("%s  %d bytes in subtuples\n", indent, cfg->subtuples);
+}
+
+/*====================================================================*/
+
+static int nfn = 0, cur = 0;
+
+static void print_parse(tuple_parse_t * tup)
+{
+       static int func = 0;
+       int i;
+
+       switch (tup->tuple.TupleCode) {
+       case CISTPL_DEVICE:
+       case CISTPL_DEVICE_A:
+               if (tup->tuple.TupleCode == CISTPL_DEVICE)
+                       printf("%sdev_info\n", indent);
+               else
+                       printf("%sattr_dev_info\n", indent);
+               print_device(&tup->parse.device);
+               break;
+       case CISTPL_CHECKSUM:
+               printf("%schecksum 0x%04x-0x%04x = 0x%02x\n",
+                      indent, tup->parse.checksum.addr,
+                      tup->parse.checksum.addr + tup->parse.checksum.len - 1,
+                      tup->parse.checksum.sum);
+               break;
+       case CISTPL_LONGLINK_A:
+               if (verbose)
+                       printf("%slong_link_attr 0x%04x\n", indent,
+                              tup->parse.longlink.addr);
+               break;
+       case CISTPL_LONGLINK_C:
+               if (verbose)
+                       printf("%slong_link 0x%04x\n", indent,
+                              tup->parse.longlink.addr);
+               break;
+       case CISTPL_LONGLINK_MFC:
+               if (verbose) {
+                       printf("%smfc_long_link\n", indent);
+                       for (i = 0; i < tup->parse.longlink_mfc.nfn; i++)
+                               printf("%s function %d: %s 0x%04x\n", indent, i,
+                                      tup->parse.longlink_mfc.fn[i].space ?
+                                      "common" : "attr",
+                                      tup->parse.longlink_mfc.fn[i].addr);
+               }
+
+               printf("%smfc {\n", indent);
+               nfn = tup->parse.longlink_mfc.nfn;
+               cur = 0;
+               strcat(indent, "  ");
+               while (cur < nfn) {
+                       tuple_parse_t tuple_parse = *tup;
+                       tuple_parse.tuple.CISOffset =
+                           tup->parse.longlink_mfc.fn[cur].addr;
+                       tuple_parse.tuple.TupleLink = 0;
+
+                       while (1) {
+                               if (get_tuple_buf(-1, &tuple_parse.tuple, 0))
+                                       break;
+                               if (verbose)
+                                       print_tuple(&tuple_parse);
+                               if (parse_tuple
+                                   (&tuple_parse.tuple,
+                                    &tuple_parse.parse) == 0)
+                                       print_parse(&tuple_parse);
+                               else
+                                       printf("%sparse error\n", indent);
+                               if (verbose)
+                                       putchar('\n');
+                               if (tuple_parse.tuple.TupleCode == CISTPL_END)
+                                       break;
+                       }
+               }
+               break;
+       case CISTPL_NO_LINK:
+               if (verbose)
+                       printf("%sno_long_link\n", indent);
+               break;
+#ifdef CISTPL_INDIRECT
+       case CISTPL_INDIRECT:
+               if (verbose)
+                       printf("%sindirect_access\n", indent);
+               break;
+#endif
+       case CISTPL_LINKTARGET:
+               if (verbose)
+                       printf("%slink_target\n", indent);
+
+               if (cur++)
+                       printf("%s}, {\n", indent + 2);
+               break;
+       case CISTPL_VERS_1:
+               print_vers_1(&tup->parse.version_1);
+               break;
+       case CISTPL_ALTSTR:
+               break;
+       case CISTPL_JEDEC_A:
+       case CISTPL_JEDEC_C:
+               if (tup->tuple.TupleCode == CISTPL_JEDEC_C)
+                       printf("%scommon_jedec", indent);
+               else
+                       printf("%sattr_jedec", indent);
+               print_jedec(&tup->parse.jedec);
+               break;
+       case CISTPL_DEVICE_GEO:
+       case CISTPL_DEVICE_GEO_A:
+               if (tup->tuple.TupleCode == CISTPL_DEVICE_GEO)
+                       printf("%scommon_geometry\n", indent);
+               else
+                       printf("%sattr_geometry\n", indent);
+               print_device_geo(&tup->parse.device_geo);
+               break;
+       case CISTPL_MANFID:
+               printf("%smanfid 0x%4.4x, 0x%4.4x\n", indent,
+                      tup->parse.manfid.manf, tup->parse.manfid.card);
+               break;
+       case CISTPL_FUNCID:
+               print_funcid(&tup->parse.funcid);
+               func = tup->parse.funcid.func;
+               break;
+       case CISTPL_FUNCE:
+               switch (func) {
+               case CISTPL_FUNCID_SERIAL:
+                       print_serial(&tup->parse.funce);
+                       break;
+               case CISTPL_FUNCID_FIXED:
+                       print_fixed(&tup->parse.funce);
+                       break;
+               case CISTPL_FUNCID_NETWORK:
+                       print_network(&tup->parse.funce);
+                       break;
+               }
+               break;
+       case CISTPL_BAR:
+               printf("%sBAR %d size ", indent,
+                      tup->parse.bar.attr & CISTPL_BAR_SPACE);
+               print_size(tup->parse.bar.size);
+               if (tup->parse.bar.attr & CISTPL_BAR_SPACE_IO)
+                       printf(" [io]");
+               else
+                       printf(" [mem]");
+               if (tup->parse.bar.attr & CISTPL_BAR_PREFETCH)
+                       printf(" [prefetch]");
+               if (tup->parse.bar.attr & CISTPL_BAR_CACHEABLE)
+                       printf(" [cacheable]");
+               if (tup->parse.bar.attr & CISTPL_BAR_1MEG_MAP)
+                       printf(" [<1mb]");
+               putchar('\n');
+               break;
+       case CISTPL_CONFIG:
+       case CISTPL_CONFIG_CB:
+               print_config(tup->tuple.TupleCode, &tup->parse.config);
+               break;
+       case CISTPL_CFTABLE_ENTRY:
+               print_cftable_entry(&tup->parse.cftable_entry);
+               break;
+       case CISTPL_CFTABLE_ENTRY_CB:
+               print_cftable_entry_cb(&tup->parse.cftable_entry_cb);
+               break;
+       case CISTPL_VERS_2:
+               print_vers_2(&tup->parse.vers_2);
+               break;
+       case CISTPL_ORG:
+               print_org(&tup->parse.org);
+               break;
+#ifdef CISTPL_FORMAT_DISK
+       case CISTPL_FORMAT:
+       case CISTPL_FORMAT_A:
+               if (tup->tuple.TupleCode == CISTPL_FORMAT)
+                       printf("%scommon_format\n", indent);
+               else
+                       printf("%sattr_format\n", indent);
+               print_format(&tup->parse.format);
+#endif
+       }
+}
+
+/*====================================================================*/
+
+static int get_tuple_buf(int fd, tuple_t * tuple, int first)
+{
+       u_int ofs;
+       static int nb = 0;
+       static u_char buf[1024];
+
+       if (first) {
+               nb = read(fd, buf, sizeof(buf));
+               tuple->TupleLink = tuple->CISOffset = 0;
+       }
+       ofs = tuple->CISOffset + tuple->TupleLink;
+       if (ofs >= nb)
+               return -1;
+       tuple->TupleCode = buf[ofs++];
+       tuple->TupleDataLen = tuple->TupleLink = buf[ofs++];
+       tuple->CISOffset = ofs;
+       memcpy(tuple->TupleData, buf + ofs, tuple->TupleLink);
+       return 0;
+}
+
+/*======================================================================
+
+       Parsing routines for individual tuples
+
+======================================================================*/
+
+static const u_char mantissa[] = {
+       10, 12, 13, 15, 20, 25, 30, 35,
+       40, 45, 50, 55, 60, 70, 80, 90
+};
+
+static const u_int exponent[] = {
+       1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
+};
+
+/* Convert an extended speed byte to a time in nanoseconds */
+#define SPEED_CVT(v) \
+       (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10)
+/* Convert a power byte to a current in 0.1 microamps */
+#define POWER_CVT(v) \
+       (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10)
+#define POWER_SCALE(v)                         (exponent[(v)&7])
+
+static int parse_device(tuple_t * tuple, cistpl_device_t * device)
+{
+       int i;
+       u_char scale;
+       u_char *p, *q;
+
+       p = (u_char *) tuple->TupleData;
+       q = p + tuple->TupleDataLen;
+
+       device->ndev = 0;
+       for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
+
+               if (*p == 0xff)
+                       break;
+               device->dev[i].type = (*p >> 4);
+               device->dev[i].wp = (*p & 0x08) ? 1 : 0;
+               switch (*p & 0x07) {
+               case 0:
+                       device->dev[i].speed = 0;
+                       break;
+               case 1:
+                       device->dev[i].speed = 250;
+                       break;
+               case 2:
+                       device->dev[i].speed = 200;
+                       break;
+               case 3:
+                       device->dev[i].speed = 150;
+                       break;
+               case 4:
+                       device->dev[i].speed = 100;
+                       break;
+               case 7:
+                       if (++p == q)
+                               return -1;
+                       if (p == q)
+                               return -1;
+                       device->dev[i].speed = SPEED_CVT(*p);
+                       while (*p & 0x80)
+                               if (++p == q)
+                                       return -1;
+                       break;
+               default:
+                       return -1;
+               }
+
+               if (++p == q)
+                       return -1;
+               if (*p == 0xff)
+                       break;
+               scale = *p & 7;
+               if (scale == 7)
+                       return -1;
+               device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale * 2));
+               device->ndev++;
+               if (++p == q)
+                       break;
+       }
+
+       return 0;
+}
+
+/*====================================================================*/
+
+static int parse_checksum(tuple_t * tuple, cistpl_checksum_t * csum)
+{
+       u_char *p;
+       if (tuple->TupleDataLen < 5)
+               return -1;
+       p = (u_char *) tuple->TupleData;
+       csum->addr = tuple->CISOffset + (short)le16toh(*(u_short *) p) - 2;
+       csum->len = le16toh(*(u_short *) (p + 2));
+       csum->sum = *(p + 4);
+       return 0;
+}
+
+/*====================================================================*/
+
+static int parse_longlink(tuple_t * tuple, cistpl_longlink_t * link)
+{
+       if (tuple->TupleDataLen < 4)
+               return -1;
+       link->addr = le32toh(*(u_int *) tuple->TupleData);
+       return 0;
+}
+
+/*====================================================================*/
+
+static int parse_longlink_mfc(tuple_t * tuple, cistpl_longlink_mfc_t * link)
+{
+       u_char *p;
+       int i;
+
+       p = (u_char *) tuple->TupleData;
+
+       link->nfn = *p;
+       p++;
+       if (tuple->TupleDataLen <= link->nfn * 5)
+               return -1;
+       for (i = 0; i < link->nfn; i++) {
+               link->fn[i].space = *p;
+               p++;
+               link->fn[i].addr = le32toh(*(u_int *) p);
+               p += 4;
+       }
+       return 0;
+}
+
+/*====================================================================*/
+
+static int parse_strings(u_char * p, u_char * q, int max,
+                        char *s, u_char * ofs, u_char * found)
+{
+       int i, j, ns;
+
+       if (p == q)
+               return -1;
+       ns = 0;
+       j = 0;
+       for (i = 0; i < max; i++) {
+               if (*p == 0xff)
+                       break;
+               ofs[i] = j;
+               ns++;
+               for (;;) {
+                       s[j++] = (*p == 0xff) ? '\0' : *p;
+                       if ((*p == '\0') || (*p == 0xff))
+                               break;
+                       if (++p == q)
+                               return -1;
+               }
+               if ((*p == 0xff) || (++p == q))
+                       break;
+       }
+       if (found) {
+               *found = ns;
+               return 0;
+       } else {
+               return (ns == max) ? 0 : -1;
+       }
+}
+
+/*====================================================================*/
+
+static int parse_vers_1(tuple_t * tuple, cistpl_vers_1_t * vers_1)
+{
+       u_char *p, *q;
+
+       p = (u_char *) tuple->TupleData;
+       q = p + tuple->TupleDataLen;
+
+       vers_1->major = *p;
+       p++;
+       vers_1->minor = *p;
+       p++;
+       if (p >= q)
+               return -1;
+
+       return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
+                            vers_1->str, vers_1->ofs, &vers_1->ns);
+}
+
+/*====================================================================*/
+
+static int parse_altstr(tuple_t * tuple, cistpl_altstr_t * altstr)
+{
+       u_char *p, *q;
+
+       p = (u_char *) tuple->TupleData;
+       q = p + tuple->TupleDataLen;
+
+       return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
+                            altstr->str, altstr->ofs, &altstr->ns);
+}
+
+/*====================================================================*/
+
+static int parse_jedec(tuple_t * tuple, cistpl_jedec_t * jedec)
+{
+       u_char *p, *q;
+       int nid;
+
+       p = (u_char *) tuple->TupleData;
+       q = p + tuple->TupleDataLen;
+
+       for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
+               if (p > q - 2)
+                       break;
+               jedec->id[nid].mfr = p[0];
+               jedec->id[nid].info = p[1];
+               p += 2;
+       }
+       jedec->nid = nid;
+       return 0;
+}
+
+/*====================================================================*/
+
+static int parse_manfid(tuple_t * tuple, cistpl_manfid_t * m)
+{
+       u_short *p;
+       if (tuple->TupleDataLen < 4)
+               return -1;
+       p = (u_short *) tuple->TupleData;
+       m->manf = le16toh(p[0]);
+       m->card = le16toh(p[1]);
+       return 0;
+}
+
+/*====================================================================*/
+
+static int parse_funcid(tuple_t * tuple, cistpl_funcid_t * f)
+{
+       u_char *p;
+       if (tuple->TupleDataLen < 2)
+               return -1;
+       p = (u_char *) tuple->TupleData;
+       f->func = p[0];
+       f->sysinit = p[1];
+       return 0;
+}
+
+/*====================================================================*/
+
+static int parse_funce(tuple_t * tuple, cistpl_funce_t * f)
+{
+       u_char *p;
+       int i;
+       if (tuple->TupleDataLen < 1)
+               return -1;
+       p = (u_char *) tuple->TupleData;
+       f->type = p[0];
+       for (i = 1; i < tuple->TupleDataLen; i++)
+               f->data[i - 1] = p[i];
+       return 0;
+}
+
+/*====================================================================*/
+
+static int parse_config(tuple_t * tuple, cistpl_config_t * config)
+{
+       int rasz, rmsz, i;
+       u_char *p;
+
+       p = (u_char *) tuple->TupleData;
+       rasz = *p & 0x03;
+       rmsz = (*p & 0x3c) >> 2;
+       if (tuple->TupleDataLen < rasz + rmsz + 4)
+               return -1;
+       config->last_idx = *(++p);
+       p++;
+       config->base = 0;
+       for (i = 0; i <= rasz; i++)
+               config->base += p[i] << (8 * i);
+       p += rasz + 1;
+       for (i = 0; i < 4; i++)
+               config->rmask[i] = 0;
+       for (i = 0; i <= rmsz; i++)
+               config->rmask[i >> 2] += p[i] << (8 * (i % 4));
+       config->subtuples = tuple->TupleDataLen - (rasz + rmsz + 4);
+       return 0;
+}
+
+/*======================================================================
+
+       The following routines are all used to parse the nightmarish
+       config table entries.
+
+======================================================================*/
+
+static u_char *parse_power(u_char * p, u_char * q, cistpl_power_t * pwr)
+{
+       int i;
+       u_int scale;
+
+       if (p == q)
+               return NULL;
+       pwr->present = *p;
+       pwr->flags = 0;
+       p++;
+       for (i = 0; i < 7; i++)
+               if (pwr->present & (1 << i)) {
+                       if (p == q)
+                               return NULL;
+                       pwr->param[i] = POWER_CVT(*p);
+                       scale = POWER_SCALE(*p);
+                       while (*p & 0x80) {
+                               if (++p == q)
+                                       return NULL;
+                               if ((*p & 0x7f) < 100)
+                                       pwr->param[i] +=
+                                           (*p & 0x7f) * scale / 100;
+                               else if (*p == 0x7d)
+                                       pwr->flags |= CISTPL_POWER_HIGHZ_OK;
+                               else if (*p == 0x7e)
+                                       pwr->param[i] = 0;
+                               else if (*p == 0x7f)
+                                       pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
+                               else
+                                       return NULL;
+                       }
+                       p++;
+               }
+       return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_timing(u_char * p, u_char * q, cistpl_timing_t * timing)
+{
+       u_char scale;
+
+       if (p == q)
+               return NULL;
+       scale = *p;
+       if ((scale & 3) != 3) {
+               if (++p == q)
+                       return NULL;
+               timing->wait = SPEED_CVT(*p);
+               timing->waitscale = exponent[scale & 3];
+       } else
+               timing->wait = 0;
+       scale >>= 2;
+       if ((scale & 7) != 7) {
+               if (++p == q)
+                       return NULL;
+               timing->ready = SPEED_CVT(*p);
+               timing->rdyscale = exponent[scale & 7];
+       } else
+               timing->ready = 0;
+       scale >>= 3;
+       if (scale != 7) {
+               if (++p == q)
+                       return NULL;
+               timing->reserved = SPEED_CVT(*p);
+               timing->rsvscale = exponent[scale];
+       } else
+               timing->reserved = 0;
+       p++;
+       return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_io(u_char * p, u_char * q, cistpl_io_t * io)
+{
+       int i, j, bsz, lsz;
+
+       if (p == q)
+               return NULL;
+       io->flags = *p;
+
+       if (!(*p & 0x80)) {
+               io->nwin = 1;
+               io->win[0].base = 0;
+               io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
+               return p + 1;
+       }
+
+       if (++p == q)
+               return NULL;
+       io->nwin = (*p & 0x0f) + 1;
+       bsz = (*p & 0x30) >> 4;
+       if (bsz == 3)
+               bsz++;
+       lsz = (*p & 0xc0) >> 6;
+       if (lsz == 3)
+               lsz++;
+       p++;
+
+       for (i = 0; i < io->nwin; i++) {
+               io->win[i].base = 0;
+               io->win[i].len = 1;
+               for (j = 0; j < bsz; j++, p++) {
+                       if (p == q)
+                               return NULL;
+                       io->win[i].base += *p << (j * 8);
+               }
+               for (j = 0; j < lsz; j++, p++) {
+                       if (p == q)
+                               return NULL;
+                       io->win[i].len += *p << (j * 8);
+               }
+       }
+       return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_mem(u_char * p, u_char * q, cistpl_mem_t * mem)
+{
+       int i, j, asz, lsz, has_ha;
+       u_int len, ca, ha;
+
+       if (p == q)
+               return NULL;
+
+       mem->nwin = (*p & 0x07) + 1;
+       lsz = (*p & 0x18) >> 3;
+       asz = (*p & 0x60) >> 5;
+       has_ha = (*p & 0x80);
+       if (++p == q)
+               return NULL;
+
+       for (i = 0; i < mem->nwin; i++) {
+               len = ca = ha = 0;
+               for (j = 0; j < lsz; j++, p++) {
+                       if (p == q)
+                               return NULL;
+                       len += *p << (j * 8);
+               }
+               for (j = 0; j < asz; j++, p++) {
+                       if (p == q)
+                               return NULL;
+                       ca += *p << (j * 8);
+               }
+               if (has_ha)
+                       for (j = 0; j < asz; j++, p++) {
+                               if (p == q)
+                                       return NULL;
+                               ha += *p << (j * 8);
+                       }
+               mem->win[i].len = len << 8;
+               mem->win[i].card_addr = ca << 8;
+               mem->win[i].host_addr = ha << 8;
+       }
+       return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_irq(u_char * p, u_char * q, cistpl_irq_t * irq)
+{
+       if (p == q)
+               return NULL;
+       irq->IRQInfo1 = *p;
+       p++;
+       if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
+               if (p + 2 > q)
+                       return NULL;
+               irq->IRQInfo2 = (p[1] << 8) + p[0];
+               p += 2;
+       }
+       return p;
+}
+
+/*====================================================================*/
+
+static int parse_cftable_entry(tuple_t * tuple, cistpl_cftable_entry_t * entry)
+{
+       u_char *p, *q, features;
+
+       p = tuple->TupleData;
+       q = p + tuple->TupleDataLen;
+       entry->index = *p & 0x3f;
+       entry->flags = 0;
+       if (*p & 0x40)
+               entry->flags |= CISTPL_CFTABLE_DEFAULT;
+       if (*p & 0x80) {
+               if (++p == q)
+                       return -1;
+               if (*p & 0x10)
+                       entry->flags |= CISTPL_CFTABLE_BVDS;
+               if (*p & 0x20)
+                       entry->flags |= CISTPL_CFTABLE_WP;
+               if (*p & 0x40)
+                       entry->flags |= CISTPL_CFTABLE_RDYBSY;
+               if (*p & 0x80)
+                       entry->flags |= CISTPL_CFTABLE_MWAIT;
+               entry->interface = *p & 0x0f;
+       } else
+               entry->interface = 0;
+
+       /* Process optional features */
+       if (++p == q)
+               return -1;
+       features = *p;
+       p++;
+
+       /* Power options */
+       if ((features & 3) > 0) {
+               p = parse_power(p, q, &entry->vcc);
+               if (p == NULL)
+                       return -1;
+       } else
+               entry->vcc.present = 0;
+       if ((features & 3) > 1) {
+               p = parse_power(p, q, &entry->vpp1);
+               if (p == NULL)
+                       return -1;
+       } else
+               entry->vpp1.present = 0;
+       if ((features & 3) > 2) {
+               p = parse_power(p, q, &entry->vpp2);
+               if (p == NULL)
+                       return -1;
+       } else
+               entry->vpp2.present = 0;
+
+       /* Timing options */
+       if (features & 0x04) {
+               p = parse_timing(p, q, &entry->timing);
+               if (p == NULL)
+                       return -1;
+       } else {
+               entry->timing.wait = 0;
+               entry->timing.ready = 0;
+               entry->timing.reserved = 0;
+       }
+
+       /* I/O window options */
+       if (features & 0x08) {
+               p = parse_io(p, q, &entry->io);
+               if (p == NULL)
+                       return -1;
+       } else
+               entry->io.nwin = 0;
+
+       /* Interrupt options */
+       if (features & 0x10) {
+               p = parse_irq(p, q, &entry->irq);
+               if (p == NULL)
+                       return -1;
+       } else
+               entry->irq.IRQInfo1 = 0;
+
+       switch (features & 0x60) {
+       case 0x00:
+               entry->mem.nwin = 0;
+               break;
+       case 0x20:
+               entry->mem.nwin = 1;
+               entry->mem.win[0].len = le16toh(*(u_short *) p) << 8;
+               entry->mem.win[0].card_addr = 0;
+               entry->mem.win[0].host_addr = 0;
+               p += 2;
+               if (p > q)
+                       return -1;
+               break;
+       case 0x40:
+               entry->mem.nwin = 1;
+               entry->mem.win[0].len = le16toh(*(u_short *) p) << 8;
+               entry->mem.win[0].card_addr =
+                   le16toh(*(u_short *) (p + 2)) << 8;
+               entry->mem.win[0].host_addr = 0;
+               p += 4;
+               if (p > q)
+                       return -1;
+               break;
+       case 0x60:
+               p = parse_mem(p, q, &entry->mem);
+               if (p == NULL)
+                       return -1;
+               break;
+       }
+
+       /* Misc features */
+       if (features & 0x80) {
+               if (p == q)
+                       return -1;
+               entry->flags |= (*p << 8);
+               while (*p & 0x80)
+                       if (++p == q)
+                               return -1;
+               p++;
+       }
+
+       entry->subtuples = q - p;
+
+       return 0;
+}
+
+/*====================================================================*/
+
+static int parse_bar(tuple_t * tuple, cistpl_bar_t * bar)
+{
+       u_char *p;
+       if (tuple->TupleDataLen < 6)
+               return -1;
+       p = (u_char *) tuple->TupleData;
+       bar->attr = *p;
+       p += 2;
+       bar->size = le32toh(*(u_int *) p);
+       return 0;
+}
+
+static int parse_config_cb(tuple_t * tuple, cistpl_config_t * config)
+{
+       u_char *p;
+
+       p = (u_char *) tuple->TupleData;
+       if ((*p != 3) || (tuple->TupleDataLen < 6))
+               return -1;
+       config->last_idx = *(++p);
+       p++;
+       config->base = le32toh(*(u_int *) p);
+       config->subtuples = tuple->TupleDataLen - 6;
+       return 0;
+}
+
+static int parse_cftable_entry_cb(tuple_t * tuple,
+                                 cistpl_cftable_entry_cb_t * entry)
+{
+       u_char *p, *q, features;
+
+       p = tuple->TupleData;
+       q = p + tuple->TupleDataLen;
+       entry->index = *p & 0x3f;
+       entry->flags = 0;
+       if (*p & 0x40)
+               entry->flags |= CISTPL_CFTABLE_DEFAULT;
+
+       /* Process optional features */
+       if (++p == q)
+               return -1;
+       features = *p;
+       p++;
+
+       /* Power options */
+       if ((features & 3) > 0) {
+               p = parse_power(p, q, &entry->vcc);
+               if (p == NULL)
+                       return -1;
+       } else
+               entry->vcc.present = 0;
+       if ((features & 3) > 1) {
+               p = parse_power(p, q, &entry->vpp1);
+               if (p == NULL)
+                       return -1;
+       } else
+               entry->vpp1.present = 0;
+       if ((features & 3) > 2) {
+               p = parse_power(p, q, &entry->vpp2);
+               if (p == NULL)
+                       return -1;
+       } else
+               entry->vpp2.present = 0;
+
+       /* I/O window options */
+       if (features & 0x08) {
+               if (p == q)
+                       return -1;
+               entry->io = *p;
+               p++;
+       } else
+               entry->io = 0;
+
+       /* Interrupt options */
+       if (features & 0x10) {
+               p = parse_irq(p, q, &entry->irq);
+               if (p == NULL)
+                       return -1;
+       } else
+               entry->irq.IRQInfo1 = 0;
+
+       if (features & 0x20) {
+               if (p == q)
+                       return -1;
+               entry->mem = *p;
+               p++;
+       } else
+               entry->mem = 0;
+
+       /* Misc features */
+       if (features & 0x80) {
+               if (p == q)
+                       return -1;
+               entry->flags |= (*p << 8);
+               if (*p & 0x80) {
+                       if (++p == q)
+                               return -1;
+                       entry->flags |= (*p << 16);
+               }
+               while (*p & 0x80)
+                       if (++p == q)
+                               return -1;
+               p++;
+       }
+
+       entry->subtuples = q - p;
+
+       return 0;
+}
+
+/*====================================================================*/
+
+static int parse_device_geo(tuple_t * tuple, cistpl_device_geo_t * geo)
+{
+       u_char *p, *q;
+       int n;
+
+       p = (u_char *) tuple->TupleData;
+       q = p + tuple->TupleDataLen;
+
+       for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
+               if (p > q - 6)
+                       break;
+               geo->geo[n].buswidth = p[0];
+               geo->geo[n].erase_block = 1 << (p[1] - 1);
+               geo->geo[n].read_block = 1 << (p[2] - 1);
+               geo->geo[n].write_block = 1 << (p[3] - 1);
+               geo->geo[n].partition = 1 << (p[4] - 1);
+               geo->geo[n].interleave = 1 << (p[5] - 1);
+               p += 6;
+       }
+       geo->ngeo = n;
+       return 0;
+}
+
+/*====================================================================*/
+
+static int parse_vers_2(tuple_t * tuple, cistpl_vers_2_t * v2)
+{
+       u_char *p, *q;
+
+       if (tuple->TupleDataLen < 10)
+               return -1;
+
+       p = tuple->TupleData;
+       q = p + tuple->TupleDataLen;
+
+       v2->vers = p[0];
+       v2->comply = p[1];
+       v2->dindex = le16toh(*(u_short *) (p + 2));
+       v2->vspec8 = p[6];
+       v2->vspec9 = p[7];
+       v2->nhdr = p[8];
+       p += 9;
+       return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
+}
+
+/*====================================================================*/
+
+static int parse_org(tuple_t * tuple, cistpl_org_t * org)
+{
+       u_char *p, *q;
+       int i;
+
+       p = tuple->TupleData;
+       q = p + tuple->TupleDataLen;
+       if (p == q)
+               return -1;
+       org->data_org = *p;
+       if (++p == q)
+               return -1;
+       for (i = 0; i < 30; i++) {
+               org->desc[i] = *p;
+               if (*p == '\0')
+                       break;
+               if (++p == q)
+                       return -1;
+       }
+       return 0;
+}
+
+/*====================================================================*/
+
+static int parse_format(tuple_t * tuple, cistpl_format_t * fmt)
+{
+       u_char *p;
+
+       if (tuple->TupleDataLen < 10)
+               return -1;
+
+       p = tuple->TupleData;
+
+       fmt->type = p[0];
+       fmt->edc = p[1];
+       fmt->offset = le32toh(*(u_int *) (p + 2));
+       fmt->length = le32toh(*(u_int *) (p + 6));
+
+       return 0;
+}
+
+/*====================================================================*/
+
+static int parse_tuple(tuple_t * tuple, cisparse_t * parse)
+{
+       int ret = 0;
+
+       if (tuple->TupleDataLen > tuple->TupleDataMax)
+               return -1;
+       switch (tuple->TupleCode) {
+       case CISTPL_DEVICE:
+       case CISTPL_DEVICE_A:
+               ret = parse_device(tuple, &parse->device);
+               break;
+       case CISTPL_BAR:
+               ret = parse_bar(tuple, &parse->bar);
+               break;
+       case CISTPL_CONFIG_CB:
+               ret = parse_config_cb(tuple, &parse->config);
+               break;
+       case CISTPL_CFTABLE_ENTRY_CB:
+               ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb);
+               break;
+       case CISTPL_CHECKSUM:
+               ret = parse_checksum(tuple, &parse->checksum);
+               break;
+       case CISTPL_LONGLINK_A:
+       case CISTPL_LONGLINK_C:
+               ret = parse_longlink(tuple, &parse->longlink);
+               break;
+       case CISTPL_LONGLINK_MFC:
+               ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
+               break;
+       case CISTPL_VERS_1:
+               ret = parse_vers_1(tuple, &parse->version_1);
+               break;
+       case CISTPL_ALTSTR:
+               ret = parse_altstr(tuple, &parse->altstr);
+               break;
+       case CISTPL_JEDEC_A:
+       case CISTPL_JEDEC_C:
+               ret = parse_jedec(tuple, &parse->jedec);
+               break;
+       case CISTPL_MANFID:
+               ret = parse_manfid(tuple, &parse->manfid);
+               break;
+       case CISTPL_FUNCID:
+               ret = parse_funcid(tuple, &parse->funcid);
+               break;
+       case CISTPL_FUNCE:
+               ret = parse_funce(tuple, &parse->funce);
+               break;
+       case CISTPL_CONFIG:
+               ret = parse_config(tuple, &parse->config);
+               break;
+       case CISTPL_CFTABLE_ENTRY:
+               ret = parse_cftable_entry(tuple, &parse->cftable_entry);
+               break;
+       case CISTPL_DEVICE_GEO:
+       case CISTPL_DEVICE_GEO_A:
+               ret = parse_device_geo(tuple, &parse->device_geo);
+               break;
+       case CISTPL_VERS_2:
+               ret = parse_vers_2(tuple, &parse->vers_2);
+               break;
+       case CISTPL_ORG:
+               ret = parse_org(tuple, &parse->org);
+               break;
+       case CISTPL_FORMAT:
+       case CISTPL_FORMAT_A:
+               ret = parse_format(tuple, &parse->format);
+               break;
+       case CISTPL_NO_LINK:
+       case CISTPL_LINKTARGET:
+               ret = 0;
+               break;
+       case CISTPL_END:
+               ret = 0;
+               break;
+       default:
+               ret = -1;
+               break;
+       }
+       return ret;
+}
+
+/*====================================================================*/
+
+#define MAX_SOCKS 8
+
+int main(int argc, char *argv[])
+{
+       int i, fd;
+       tuple_parse_t tuple_parse;
+       int optch, errflg, first;
+       char *infile = NULL;
+
+       errflg = 0;
+       while ((optch = getopt(argc, argv, "vi:")) != -1) {
+               switch (optch) {
+               case 'v':
+                       verbose = 1;
+                       break;
+               default:
+                       errflg = 1;
+                       break;
+               }
+       }
+       if (errflg || (optind > argc - 1)) {
+               fprintf(stderr, "usage: %s [-v] infile\n", argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       for (i = 0; optind + i < argc; i++) {
+               infile = argv[optind + i];
+
+               nfn = cur = 0;
+               indent[0] = '\0';
+               fd = open(infile, O_RDONLY);
+               if (fd < 0) {
+                       perror("open()");
+                       return -1;
+               }
+
+               if (!verbose && (i > 0))
+                       putchar('\n');
+
+               tuple_parse.tuple.TupleDataMax = sizeof(tuple_parse.data);
+               tuple_parse.tuple.Attributes =
+                   TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
+               tuple_parse.tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+               tuple_parse.tuple.TupleOffset = 0;
+               tuple_parse.tuple.TupleData = tuple_parse.data;
+
+               for (first = 1;; first = 0) {
+                       if (get_tuple_buf(fd, &tuple_parse.tuple, first) != 0)
+                               break;
+                       if (verbose)
+                               print_tuple(&tuple_parse);
+                       if (parse_tuple(&tuple_parse.tuple, &tuple_parse.parse))
+                               printf("%sparse error\n", indent);
+                       else
+                               print_parse(&tuple_parse);
+                       if (verbose)
+                               putchar('\n');
+                       if (tuple_parse.tuple.TupleCode == CISTPL_END)
+                               break;
+               }
+
+               if (!verbose && (nfn > 0))
+                       printf("%s}\n", indent + 2);
+       }
+
+       return 0;
+}
-- 
1.5.6.5


_______________________________________________
Linux PCMCIA reimplementation list
http://lists.infradead.org/mailman/listinfo/linux-pcmcia

Reply via email to