[PATCH 5/5] Documentation: add an utility to parse CIS files to readable form
Dmitry Eremin-Solenikov
dbaryshkov at gmail.com
Thu Sep 23 11:19:57 EDT 2010
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 <dbaryshkov at 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
+ * <dahinds at 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
More information about the linux-pcmcia
mailing list