summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Brodowski <linux@dominikbrodowski.net>2005-12-06 20:25:07 +0100
committerDominik Brodowski <brodo@isilmar.linta.de>2005-12-06 20:30:54 +0100
commit3603bb957419e1d633fe80a4d95bcb09687f54c6 (patch)
treea03f019ab66f1e17c41de561859a4451f1eb0ab7
parent1050829dc4aa7be84652a95a6e2ad56f5f529296 (diff)
downloadpcmciautils-3603bb957419e1d633fe80a4d95bcb09687f54c6.tar.gz
Release of pcmciautils-003 (2005-05-05)
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
-rw-r--r--Makefile16
-rw-r--r--config/config.opts27
-rw-r--r--debug/cbdump.c280
-rw-r--r--debug/dump_cis.c993
-rw-r--r--debug/parse_cis.c876
-rw-r--r--src/cistpl.h6
-rw-r--r--src/pcmcia-check-broken-cis.c6
-rw-r--r--src/read-cis.c28
-rw-r--r--src/startup.c3
9 files changed, 2191 insertions, 44 deletions
diff --git a/Makefile b/Makefile
index 34d3ba4..ea8354f 100644
--- a/Makefile
+++ b/Makefile
@@ -29,8 +29,10 @@ PCCARDCTL = pccardctl
PCMCIA_CHECK_BROKEN_CIS = pcmcia-check-broken-cis
PCMCIA_MODALIAS = pcmcia-modalias
PCMCIA_SOCKET_STARTUP = pcmcia-socket-startup
+CBDUMP = cbdump
+CISDUMP = dump_cis
-VERSION = 002
+VERSION = 003
#INSTALL_DIR = /usr/local/sbin
RELEASE_NAME = pcmciautils-$(VERSION)
@@ -121,6 +123,7 @@ CFLAGS += -I$(PWD)/src
#LIBC =
CFLAGS += $(WARNINGS) -I$(GCCINCDIR)
LIB_OBJS = -lc -lsysfs
+LIB_PCI_OBJS = -lc -lpci
#LDFLAGS =
ifeq ($(strip $(V)),false)
@@ -170,11 +173,22 @@ $(PCMCIA_SOCKET_STARTUP): $(LIBC) src/startup.o src/yacc_config.o src/lex_config
yacc_config.o lex_config.o: %.o: %.c
$(CC) -c -MD -O -pipe $(CPPFLAGS) $<
+
+debugtools: ccdv $(CBDUMP) $(CISDUMP)
+
+$(CBDUMP): $(LIBC) debug/cbdump.o
+ $(QUIET) $(LD) $(LDFLAGS) -o $@ $(CRT0) debug/$(CBDUMP).o $(LIB_PCI_OBJS) $(ARCH_LIB_OBJS)
+ $(QUIET) $(STRIPCMD) $@
+
+$(CISDUMP): $(LIBC) src/read-cis.o debug/parse_cis.o debug/dump_cis.o
+ $(QUIET) $(LD) $(LDFLAGS) -o $@ $(CRT0) debug/$(CISDUMP).o src/read-cis.o debug/parse_cis.o $(LIB_OBJS) $(ARCH_LIB_OBJS)
+ $(QUIET) $(STRIPCMD) $@
clean:
-find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \
| xargs rm -f
-rm -f $(PCCARDCTL) $(PCMCIA_CHECK_BROKEN_CIS) $(PCMCIA_MODALIAS) $(PCMCIA_SOCKET_STARTUP)
+ -rm -f $(CBDUMP) $(CISDUMP)
-rm -f src/yacc_config.c src/yacc_config.d src/lex_config.c src/lex_config.d
-rm -f build/ccdv
diff --git a/config/config.opts b/config/config.opts
index 9ceac75..8e4e090 100644
--- a/config/config.opts
+++ b/config/config.opts
@@ -34,30 +34,3 @@ exclude irq 4
#exclude irq 3
# First built-in parallel port
exclude irq 7
-
-#----------------------------------------------------------------------
-
-# Examples of options for loadable modules
-
-# To fix sluggish network with IBM ethernet adapter...
-#module "pcnet_cs" opts "mem_speed=600"
-
-# Options for IBM Token Ring adapters
-#module "ibmtr_cs" opts "mmiobase=0xd0000 srambase=0xd4000"
-
-# Options for Raylink/WebGear driver: uncomment only one line...
-# Generic ad-hoc network
-module "ray_cs" opts "essid=ADHOC_ESSID hop_dwell=128 beacon_period=256 translate=1"
-# Infrastructure network for older cards
-#module "ray_cs" opts "net_type=1 essid=ESSID1"
-# Infrastructure network for WebGear
-#module "ray_cs" opts "net_type=1 essid=ESSID1 translate=1 hop_dwell=128 beacon_period=256"
-
-# Options for WaveLAN/IEEE driver (AccessPoint mode)...
-#module "wvlan_cs" opts "station_name=MY_PC"
-# Options for WaveLAN/IEEE driver (ad-hoc mode)...
-#module "wvlan_cs" opts "port_type=3 channel=1 station_name=MY_PC"
-
-# Options for Xircom Netwave driver...
-#module "netwave_cs" opts "domain=0x100 scramble_key=0x0"
-
diff --git a/debug/cbdump.c b/debug/cbdump.c
new file mode 100644
index 0000000..1a6fb7c
--- /dev/null
+++ b/debug/cbdump.c
@@ -0,0 +1,280 @@
+/*
+ * cbdump.c - dump cardbus bridge registers
+ *
+ * Copyright (C) 2003 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Build instructions:
+ *
+ * gcc -O2 -o cbdump cbdump.c -lpci
+ */
+
+#include <stdio.h>
+#include <sys/fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <pci/pci.h>
+
+struct dump_data {
+ const char *name;
+ unsigned char offset;
+ unsigned char size;
+};
+
+static void
+__dump_memory(void *mem, const struct dump_data *d, int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++, d++) {
+ u32 val = 0xa5a5a5a5;
+ void *p = (void *) ((unsigned long) mem + d->offset);
+
+ switch (d->size) {
+ case 1: val = *(u8 *)p; break;
+ case 2: val = *(u16 *)p; break;
+ case 4: val = *(u32 *)p; break;
+ }
+
+ printf(" %-31s[%02x] : 0x%0*x\n", d->name,
+ d->offset, d->size * 2, val);
+ }
+}
+
+#define dump_memory(m,d) \
+ __dump_memory(m,d,sizeof(d)/sizeof(struct dump_data))
+
+static void
+__dump_config(struct pci_dev *dev, const struct dump_data *d, int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++, d++) {
+ u32 val = 0xa5a5a5a5;
+
+ switch (d->size) {
+ case 1:
+ val = pci_read_byte(dev, d->offset);
+ break;
+ case 2:
+ val = pci_read_word(dev, d->offset);
+ break;
+ case 4:
+ val = pci_read_long(dev, d->offset);
+ break;
+ }
+
+ printf(" %-31s[%02x] : 0x%0*x\n", d->name,
+ d->offset, d->size * 2, val);
+ }
+}
+
+#define dump_config(m,d) \
+ __dump_config(m,d,sizeof(d)/sizeof(struct dump_data))
+
+static const struct dump_data cb_data[] = {
+ { "CB_SOCKET_EVENT", 0x00, 4 },
+ { "CB_SOCKET_MASK", 0x04, 4 },
+ { "CB_SOCKET_STATE", 0x08, 4 },
+ { "CB_SOCKET_FORCE", 0x0c, 4 },
+ { "CB_SOCKET_CONTROL", 0x10, 4 },
+ { "CB_SOCKET_POWER", 0x20, 4 },
+};
+
+static void dump_cb(void *mem)
+{
+ printf(" -- cardbus registers\n");
+ dump_memory(mem, cb_data);
+}
+
+static const struct dump_data exca_data[] = {
+ { "I365_IDENT", 0x00, 1 },
+ { "I365_STATUS", 0x01, 1 },
+ { "I365_POWER", 0x02, 1 },
+ { "I365_INTCTL", 0x03, 1 },
+ { "I365_CSC", 0x04, 1 },
+ { "I365_CSCINT", 0x05, 1 },
+ { "I365_ADDRWIN", 0x06, 1 },
+ { "I365_IOCTL", 0x07, 1 },
+ { "I365_GENCTL", 0x16, 2 },
+ { "I365_GBLCTL", 0x1e, 2 },
+
+ { "I365_IO0_START", 0x08, 2 },
+ { "I365_IO0_STOP", 0x0a, 2 },
+ { "I365_IO1_START", 0x0c, 2 },
+ { "I365_IO1_STOP", 0x0e, 2 },
+
+ { "I365_MEM0_START", 0x10, 2 },
+ { "I365_MEM0_STOP", 0x12, 2 },
+ { "I365_MEM0_OFF", 0x14, 2 },
+ { "I365_MEM0_PAGE", 0x40, 1 },
+ { "I365_MEM1_START", 0x18, 2 },
+ { "I365_MEM1_STOP", 0x1a, 2 },
+ { "I365_MEM1_OFF", 0x1c, 2 },
+ { "I365_MEM1_PAGE", 0x41, 1 },
+ { "I365_MEM2_START", 0x20, 2 },
+ { "I365_MEM2_STOP", 0x22, 2 },
+ { "I365_MEM2_OFF", 0x24, 2 },
+ { "I365_MEM2_PAGE", 0x42, 1 },
+ { "I365_MEM3_START", 0x28, 2 },
+ { "I365_MEM3_STOP", 0x2a, 2 },
+ { "I365_MEM3_OFF", 0x2c, 2 },
+ { "I365_MEM3_PAGE", 0x43, 1 },
+ { "I365_MEM4_START", 0x30, 2 },
+ { "I365_MEM4_STOP", 0x32, 2 },
+ { "I365_MEM4_OFF", 0x34, 2 },
+ { "I365_MEM4_PAGE", 0x44, 1 },
+};
+
+static void dump_exca(void *mem)
+{
+ printf(" -- exca registers\n");
+ dump_memory((void *) ((unsigned long) mem + 0x800), exca_data);
+}
+
+static void dump_memspace(struct pci_dev *dev, u32 mem)
+{
+ void *base;
+ int fd;
+
+ fd = open("/dev/mem", O_RDONLY);
+ if (fd == -1) {
+ perror("open /dev/mem");
+ return;
+ }
+
+ base = mmap(NULL, 4096, PROT_READ, MAP_SHARED|MAP_FILE, fd, mem);
+ if (base == (void *)-1) {
+ perror("mmap /dev/mem");
+ close(fd);
+ return;
+ }
+
+ close(fd);
+
+ dump_cb(base);
+ dump_exca(base);
+
+ munmap(base, 4096);
+}
+
+static struct dump_data cb_general_data[] = {
+ { "Vendor ID", PCI_VENDOR_ID, 2 },
+ { "Device ID", PCI_DEVICE_ID, 2 },
+ { "PCI command", PCI_COMMAND, 2 },
+ { "Base address", PCI_BASE_ADDRESS_0, 4 },
+ { "Memory Base 0", PCI_CB_MEMORY_BASE_0, 4 },
+ { "Memory Limit 0", PCI_CB_MEMORY_LIMIT_0, 4 },
+ { "Memory Base 1", PCI_CB_MEMORY_BASE_1, 4 },
+ { "Memory Limit 1", PCI_CB_MEMORY_LIMIT_1, 4 },
+ { "IO Base 0", PCI_CB_IO_BASE_0, 4 },
+ { "IO Limit 0", PCI_CB_IO_LIMIT_0, 4 },
+ { "IO Base 1", PCI_CB_IO_BASE_1, 4 },
+ { "IO Limit 1", PCI_CB_IO_LIMIT_1, 4 },
+ { "Bridge control", PCI_CB_BRIDGE_CONTROL, 2 },
+ { "Subsystem vendor ID", PCI_CB_SUBSYSTEM_VENDOR_ID, 2 },
+ { "Subsystem device ID", PCI_CB_SUBSYSTEM_ID, 2 },
+ { "Legacy mode base", PCI_CB_LEGACY_MODE_BASE, 2 },
+};
+
+static const struct dump_data ti_data[] = {
+ { "System control", 0x80, 4 },
+ { "IRQ Mux", 0x8c, 4 },
+ { "Retry", 0x90, 1 },
+ { "Card control", 0x91, 1 },
+ { "Device control", 0x92, 1 },
+ { "Diagnostic", 0x93, 1 },
+};
+
+static const struct dump_data rl5c475_data[] = {
+ { "System configuration", 0x80, 2 },
+ { "Misc Control", 0x82, 2 },
+ { "16-bit Interface Control", 0x84, 2 },
+ { "16-bit I/O Timing 0", 0x88, 2 },
+ { "16-bit Memory Timing 0", 0x8a, 2 },
+ { "DMA Slave", 0x90, 2 },
+};
+
+static const struct dump_data rl5c476II_data[] = {
+ { "Misc Control 2", 0xa0, 2 },
+ { "Misc Control 3", 0xa2, 2 },
+ { "Misc Control 4", 0xa4, 2 },
+ { "GPIO 1", 0xaa, 1 },
+};
+
+static void dump_cardbus(struct pci_dev *dev)
+{
+ char class[256];
+ char name[256];
+ u32 base;
+
+ printf("%02x:%02x.%x %s: %s\n",
+ dev->bus, dev->dev, dev->func,
+ pci_lookup_name(dev->access, class, sizeof(class),
+ PCI_LOOKUP_CLASS,
+ pci_read_word(dev, PCI_CLASS_DEVICE), 0, 0, 0),
+ pci_lookup_name(dev->access, name, sizeof(name),
+ PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
+ dev->vendor_id, dev->device_id, 0, 0));
+
+ base = pci_read_long(dev, PCI_BASE_ADDRESS_0);
+
+ printf(" -- generic cardbus config registers\n");
+ dump_config(dev, cb_general_data);
+
+ if (dev->vendor_id == 0x104c) { /* TI */
+ printf(" -- TI specific config registers\n");
+ dump_config(dev, ti_data);
+ }
+
+ if ((dev->vendor_id == 0x1180) &&
+ (dev->device_id == 0x0475)) { /* Ricoh RL5c475 */
+ printf(" -- Ricoh RL5c475 specific config registers\n");
+ dump_config(dev, rl5c475_data);
+ }
+
+ if ((dev->vendor_id == 0x1180) &&
+ (dev->device_id == 0x0476)) { /* Ricoh RL5c476II */
+ printf(" -- Ricoh RL5c476II specific config registers\n");
+ dump_config(dev, rl5c475_data);
+ dump_config(dev, rl5c476II_data);
+ }
+
+ dump_memspace(dev, base);
+
+ printf("\n");
+}
+
+int main(int argc, char *argv[])
+{
+ struct pci_access *pa;
+ struct pci_dev *dev;
+
+ pa = pci_alloc();
+ if (!pa) {
+ perror("pci_alloc");
+ return 1;
+ }
+
+ pa->writeable = 0;
+ pa->buscentric = 0;
+
+ pci_init(pa);
+ pci_scan_bus(pa);
+
+ for (dev = pa->devices; dev; dev = dev->next) {
+ unsigned int header;
+
+ header = pci_read_word(dev, PCI_HEADER_TYPE);
+ header &= ~0x80;
+ if (header == PCI_HEADER_TYPE_CARDBUS)
+ dump_cardbus(dev);
+ }
+ pci_cleanup(pa);
+
+ return 0;
+}
diff --git a/debug/dump_cis.c b/debug/dump_cis.c
new file mode 100644
index 0000000..c5cdc51
--- /dev/null
+++ b/debug/dump_cis.c
@@ -0,0 +1,993 @@
+/*
+ * cistpl.c -- 16-bit PCMCIA Card Information Structure parser
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * (C) 1999 David A. Hinds
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../src/cistpl.h"
+
+#define MAX_SOCKETS 8
+
+static int verbose = 1;
+
+static void print_tuple(tuple_t *tup)
+{
+ int i;
+ printf("offset 0x%2.2x, tuple 0x%2.2x, link 0x%2.2x\n",
+ tup->CISOffset, tup->TupleCode,
+ tup->TupleLink);
+ for (i = 0; i < tup->TupleDataLen; i++) {
+ if (!(i % 16))
+ printf(" ");
+ printf("%2.2x ", (unsigned char) tup->TupleData[i]);
+ if ((i % 16) == 15)
+ printf("\n");
+ }
+ if ((i % 16) != 0)
+ putchar('\n');
+}
+
+#define IRQ_INFO2_VALID 0x10
+#define IRQ_MASK 0x0f
+#define IRQ_LEVEL_ID 0x20
+#define IRQ_PULSE_ID 0x40
+#define IRQ_SHARE_ID 0x80
+
+static void print_funcid(cistpl_funcid_t *fn)
+{
+ printf("funcid ");
+ 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)
+{
+ unsigned 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 ", dtype[dev->dev[i].type]);
+ printf("%uns, ", dev->dev[i].speed);
+ print_size(dev->dev[i].size);
+ putchar('\n');
+ }
+ if (dev->ndev == 0)
+ printf(" no_info\n");
+}
+
+
+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", 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");
+ printf(" Iavg ");
+ print_current(power->param[CISTPL_POWER_IAVG]);
+ }
+ if (power->present & (1<<CISTPL_POWER_IPEAK)) {
+ if (++i == 5)
+ printf("\n");
+ printf(" Ipeak ");
+ print_current(power->param[CISTPL_POWER_IPEAK]);
+ }
+ if (power->present & (1<<CISTPL_POWER_IDOWN)) {
+ if (++i == 5)
+ printf("\n");
+ printf(" Idown ");
+ print_current(power->param[CISTPL_POWER_IDOWN]);
+ }
+ if (power->flags & CISTPL_POWER_HIGHZ_OK) {
+ if (++i == 5)
+ printf("\n");
+ 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("cftable_entry 0x%2.2x%s\n", entry->index,
+ (entry->flags & CISTPL_CFTABLE_DEFAULT) ? " [default]" : "");
+
+ if (entry->flags & ~CISTPL_CFTABLE_DEFAULT) {
+ 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(" timing");
+ 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(" io");
+ 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(" irq ");
+ 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(" memory");
+ 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(" %d bytes in subtuples\n", entry->subtuples);
+}
+
+/*====================================================================*/
+
+static void print_cftable_entry_cb(cistpl_cftable_entry_cb_t *entry)
+{
+ int i;
+
+ printf("cftable_entry_cb 0x%2.2x%s\n", entry->index,
+ (entry->flags & CISTPL_CFTABLE_DEFAULT) ? " [default]" : "");
+
+ if (entry->flags & ~CISTPL_CFTABLE_DEFAULT) {
+ printf(" ");
+ 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(" io_base");
+ for (i = 0; i < 8; i++)
+ if (entry->io & (1<<i)) printf(" %d", i);
+ putchar('\n');
+ }
+
+ if (entry->irq.IRQInfo1) {
+ printf(" irq ");
+ 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(" mem_base");
+ for (i = 0; i < 8; i++)
+ if (entry->mem & (1<<i))
+ printf(" %d", i);
+ putchar('\n');
+ }
+
+ if (verbose && entry->subtuples)
+ printf(" %d bytes in subtuples\n", 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(" width %d erase 0x%x read 0x%x write 0x%x "
+ "partition 0x%x interleave 0x%x\n",
+ 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("data_org ");
+ 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("serial_interface");
+ 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 uart %s",
+ (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("serial_modem_cap");
+ 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 flow");
+ for (i = 0; i < 5; i++)
+ if (cp->flow & (1<<i))
+ printf(" [%s]", flow[i]);
+ }
+ printf("\n cmd_buf %d rcv_buf %d xmit_buf %d\n",
+ 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("serial_data_services\n");
+ printf(" data_rate %d\n",
+ 75*((ds->max_data_0<<8) + ds->max_data_1));
+ printf(" modulation");
+ for (i = j = 0; i < 16; i++)
+ if (((ds->modulation_1<<8) + ds->modulation_0) & (1<<i)) {
+ if (++j % 6 == 0)
+ printf("\n ");
+ printf(" [%s]", data_mod[i]);
+ }
+ printf("\n");
+ if (ds->error_control) {
+ printf(" error_control");
+ 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(" compression");
+ 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(" cmd_protocol");
+ 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("serial_fax_services [class=%d]\n",
+ funce->type>>4);
+ printf(" data_rate %d\n",
+ 75*((fs->max_data_0<<8) + fs->max_data_1));
+ printf(" modulation");
+ for (i = 0; i < 8; i++)
+ if (fs->modulation & (1<<i))
+ printf(" [%s]", fax_mod[i]);
+ printf("\n");
+ if (fs->features_0) {
+ printf(" features");
+ 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("disk_interface ");
+ 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("disk_features");
+ 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 ");
+ 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("lan_technology %s\n", tech[t->tech]);
+ break;
+ case CISTPL_FUNCE_LAN_SPEED:
+ s = (cistpl_lan_speed_t *)(funce->data);
+ printf("lan_speed ");
+ print_speed(s->speed);
+ putchar('\n');
+ break;
+ case CISTPL_FUNCE_LAN_MEDIA:
+ m = (cistpl_lan_media_t *)(funce->data);
+ printf("lan_media %s\n", media[m->media]);
+ break;
+ case CISTPL_FUNCE_LAN_NODE_ID:
+ n = (cistpl_lan_node_id_t *)(funce->data);
+ printf("lan_node_id");
+ 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("lan_connector ");
+ 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, "vers_1 %d.%d", 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 += 2;
+ printf(",\n ");
+ } 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("version 0x%2.2x, compliance 0x%2.2x, dindex 0x%4.4x\n",
+ v2->vers, v2->comply, v2->dindex);
+ printf(" vspec8 0x%2.2x, vspec9 0x%2.2x, nhdr %d\n",
+ v2->vspec8, v2->vspec9, v2->nhdr);
+ printf(" vendor \"%s\"\n", v2->str+v2->vendor);
+ printf(" info \"%s\"\n", v2->str+v2->info);
+}
+
+
+static void print_format(cistpl_format_t *fmt)
+{
+ if (fmt->type == CISTPL_FORMAT_DISK)
+ printf(" [disk]");
+ else if (fmt->type == CISTPL_FORMAT_MEM)
+ printf(" [memory]");
+ else
+ printf(" [type 0x%02x]\n", 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');
+}
+
+
+static void print_config(int code, cistpl_config_t *cfg)
+{
+ printf("config%s base 0x%4.4x",
+ (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(" %d bytes in subtuples\n", cfg->subtuples);
+}
+
+
+static int nfn = 0, cur = 0;
+
+static void print_parse(tuple_t *tuple, cisparse_t *parse)
+{
+ static int func = 0;
+ int i;
+
+ switch (tuple->TupleCode) {
+ case CISTPL_DEVICE:
+ case CISTPL_DEVICE_A:
+ if (tuple->TupleCode == CISTPL_DEVICE)
+ printf("dev_info\n");
+ else
+ printf("attr_dev_info\n");
+ print_device(&parse->device);
+ break;
+ case CISTPL_CHECKSUM:
+ printf("checksum 0x%04x-0x%04x = 0x%02x\n",
+ parse->checksum.addr,
+ parse->checksum.addr+parse->checksum.len-1,
+ parse->checksum.sum);
+ break;
+ case CISTPL_LONGLINK_A:
+ if (verbose)
+ printf("long_link_attr 0x%04x\n",
+ parse->longlink.addr);
+ break;
+ case CISTPL_LONGLINK_C:
+ if (verbose)
+ printf("long_link 0x%04x\n",
+ parse->longlink.addr);
+ break;
+ case CISTPL_LONGLINK_MFC:
+ if (verbose) {
+ printf("mfc_long_link\n");
+ for (i = 0; i < parse->longlink_mfc.nfn; i++)
+ printf(" function %d: %s 0x%04x\n", i,
+ parse->longlink_mfc.fn[i].space ? "common" : "attr",
+ parse->longlink_mfc.fn[i].addr);
+ } else {
+ printf("mfc {\n");
+ nfn = parse->longlink_mfc.nfn;
+ cur = 0;
+ }
+ break;
+ case CISTPL_NO_LINK:
+ if (verbose)
+ printf("no_long_link\n");
+ break;
+ case CISTPL_INDIRECT:
+ if (verbose)
+ printf("indirect_access\n");
+ break;
+ case CISTPL_LINKTARGET:
+ if (verbose)
+ printf("link_target\n");
+ else {
+ if (cur++)
+ printf("}, {\n");
+ }
+ break;
+ case CISTPL_VERS_1:
+ print_vers_1(&parse->version_1);
+ break;
+ case CISTPL_ALTSTR:
+ break;
+ case CISTPL_JEDEC_A:
+ case CISTPL_JEDEC_C:
+ if (tuple->TupleCode == CISTPL_JEDEC_C)
+ printf("common_jedec");
+ else
+ printf("attr_jedec");
+ print_jedec(&parse->jedec);
+ break;
+ case CISTPL_DEVICE_GEO:
+ case CISTPL_DEVICE_GEO_A:
+ if (tuple->TupleCode == CISTPL_DEVICE_GEO)
+ printf("common_geometry\n");
+ else
+ printf("attr_geometry\n");
+ print_device_geo(&parse->device_geo);
+ break;
+ case CISTPL_MANFID:
+ printf("manfid 0x%4.4x, 0x%4.4x\n",
+ parse->manfid.manf, parse->manfid.card);
+ break;
+ case CISTPL_FUNCID:
+ print_funcid(&parse->funcid);
+ func = parse->funcid.func;
+ break;
+ case CISTPL_FUNCE:
+ switch (func) {
+ case CISTPL_FUNCID_SERIAL:
+ print_serial(&parse->funce);
+ break;
+ case CISTPL_FUNCID_FIXED:
+ print_fixed(&parse->funce);
+ break;
+ case CISTPL_FUNCID_NETWORK:
+ print_network(&parse->funce);
+ break;
+ }
+ break;
+ case CISTPL_BAR:
+ printf("BAR %d size ",
+ parse->bar.attr & CISTPL_BAR_SPACE);
+ print_size(parse->bar.size);
+ if (parse->bar.attr & CISTPL_BAR_SPACE_IO)
+ printf(" [io]");
+ else
+ printf(" [mem]");
+ if (parse->bar.attr & CISTPL_BAR_PREFETCH)
+ printf(" [prefetch]");
+ if (parse->bar.attr & CISTPL_BAR_CACHEABLE)
+ printf(" [cacheable]");
+ if (parse->bar.attr & CISTPL_BAR_1MEG_MAP)
+ printf(" [<1mb]");
+ putchar('\n');
+ break;
+ case CISTPL_CONFIG:
+ case CISTPL_CONFIG_CB:
+ print_config(tuple->TupleCode, &parse->config);
+ break;
+ case CISTPL_CFTABLE_ENTRY:
+ print_cftable_entry(&parse->cftable_entry);
+ break;
+ case CISTPL_CFTABLE_ENTRY_CB:
+ print_cftable_entry_cb(&parse->cftable_entry_cb);
+ break;
+ case CISTPL_VERS_2:
+ print_vers_2(&parse->vers_2);
+ break;
+ case CISTPL_ORG:
+ print_org(&parse->org);
+ break;
+ case CISTPL_FORMAT:
+ case CISTPL_FORMAT_A:
+ if (tuple->TupleCode == CISTPL_FORMAT)
+ printf("common_format\n");
+ else
+ printf("attr_format\n");
+ print_format(&parse->format);
+ }
+}
+
+
+static int parse_cis_one_socket(unsigned int socket_no, FILE *fd)
+{
+ int ret = 0;
+ tuple_t tuple;
+ unsigned char buf[256];
+ cisparse_t parse;
+
+ memset(&tuple, 0, sizeof(tuple_t));
+
+ ret = read_out_cis(socket_no, fd);
+ if (ret)
+ return (ret);
+
+ printf("Socket %u\n", socket_no);
+
+ tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
+ tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+
+ ret = pcmcia_get_first_tuple(BIND_FN_ALL, &tuple);
+ if (ret)
+ return (ret);
+
+ while(tuple.TupleCode != CISTPL_END) {
+ tuple.TupleData = buf;
+ tuple.TupleOffset = 0;
+ tuple.TupleDataMax = 255;
+
+ pcmcia_get_tuple_data(&tuple);
+
+ if (verbose)
+ print_tuple(&tuple);
+
+ ret = pccard_parse_tuple(&tuple, &parse);
+ if (ret) {
+ printf("invalid tuple\n");
+ continue;
+ }
+
+ print_parse(&tuple, &parse);
+
+ printf("\n");
+
+ ret = pcmcia_get_next_tuple(BIND_FN_ALL, &tuple);
+ if (ret)
+ break;
+ }
+
+ return (ret);
+}
+
+int main(int argc, char** argv)
+{
+ unsigned int socket_no = MAX_SOCKETS;
+ int ret = -ENODEV, i;
+ FILE *fd = NULL;
+
+ if (argc == 2) {
+ ret = sscanf(argv[1], "%u", &socket_no);
+ if (ret != 1)
+ socket_no = MAX_SOCKETS;
+ } else if (argc == 3) {
+ if (!strncmp("-f", argv[1], 2)) {
+ if (!strncmp("-", argv[2], 1))
+ fd = stdin;
+ else
+ fd = fopen(argv[2], "r");
+ if (!fd)
+ return -EINVAL;
+ return parse_cis_one_socket(MAX_SOCKETS + 1, fd);
+ }
+ }
+
+ if ((socket_no != MAX_SOCKETS) || fd) {
+ return parse_cis_one_socket(socket_no, fd);
+ } else {
+ for (i=0; i<MAX_SOCKETS; i++)
+ if (!parse_cis_one_socket(i, fd))
+ ret = 0;
+ }
+
+ return (ret);;
+}
diff --git a/debug/parse_cis.c b/debug/parse_cis.c
new file mode 100644
index 0000000..4388394
--- /dev/null
+++ b/debug/parse_cis.c
@@ -0,0 +1,876 @@
+/*
+ * cistpl.c -- 16-bit PCMCIA Card Information Structure parser
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * (C) 1999 David A. Hinds
+ */
+
+/* Parsing routines for individual tuples */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../src/cistpl.h"
+
+#define IRQ_INFO2_VALID 0x10
+
+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])
+
+/* FIXME: how to handle this in userspace? */
+#define le32_to_cpu(value) (value)
+#define le16_to_cpu(value) (value)
+
+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 -EINVAL;
+ device->dev[i].speed = SPEED_CVT(*p);
+ while (*p & 0x80)
+ if (++p == q) return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (++p == q)
+ return -EINVAL;
+ if (*p == 0xff)
+ break;
+ scale = *p & 7;
+ if (scale == 7)
+ return -EINVAL;
+ 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 -EINVAL;
+ p = (u_char *)tuple->TupleData;
+ csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(u_short *)p)-2;
+ csum->len = le16_to_cpu(*(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 -EINVAL;
+ link->addr = le32_to_cpu(*(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 -EINVAL;
+ for (i = 0; i < link->nfn; i++) {
+ link->fn[i].space = *p; p++;
+ link->fn[i].addr = le32_to_cpu(*(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 -EINVAL;
+ 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 -EINVAL;
+ }
+ if ((*p == 0xff) || (++p == q))
+ break;
+ }
+ if (found) {
+ *found = ns;
+ return 0;
+ } else {
+ return (ns == max) ? 0 : -EINVAL;
+ }
+}
+
+/*====================================================================*/
+
+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 -EINVAL;
+
+ 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 -EINVAL;
+ p = (u_short *)tuple->TupleData;
+ m->manf = le16_to_cpu(p[0]);
+ m->card = le16_to_cpu(p[1]);
+ return 0;
+}
+
+/*====================================================================*/
+
+static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
+{
+ u_char *p;
+ if (tuple->TupleDataLen < 2)
+ return -EINVAL;
+ 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 -EINVAL;
+ 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 -EINVAL;
+ 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 -EINVAL;
+ 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 -EINVAL;
+ features = *p; p++;
+
+ /* Power options */
+ if ((features & 3) > 0) {
+ p = parse_power(p, q, &entry->vcc);
+ if (p == NULL)
+ return -EINVAL;
+ } else
+ entry->vcc.present = 0;
+ if ((features & 3) > 1) {
+ p = parse_power(p, q, &entry->vpp1);
+ if (p == NULL)
+ return -EINVAL;
+ } else
+ entry->vpp1.present = 0;
+ if ((features & 3) > 2) {
+ p = parse_power(p, q, &entry->vpp2);
+ if (p == NULL)
+ return -EINVAL;
+ } else
+ entry->vpp2.present = 0;
+
+ /* Timing options */
+ if (features & 0x04) {
+ p = parse_timing(p, q, &entry->timing);
+ if (p == NULL)
+ return -EINVAL;
+ } 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 -EINVAL;
+ } else
+ entry->io.nwin = 0;
+
+ /* Interrupt options */
+ if (features & 0x10) {
+ p = parse_irq(p, q, &entry->irq);
+ if (p == NULL) return -EINVAL;
+ } 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 = le16_to_cpu(*(u_short *)p) << 8;
+ entry->mem.win[0].card_addr = 0;
+ entry->mem.win[0].host_addr = 0;
+ p += 2;
+ if (p > q)
+ return -EINVAL;
+ break;
+ case 0x40:
+ entry->mem.nwin = 1;
+ entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+ entry->mem.win[0].card_addr =
+ le16_to_cpu(*(u_short *)(p+2)) << 8;
+ entry->mem.win[0].host_addr = 0;
+ p += 4;
+ if (p > q)
+ return -EINVAL;
+ break;
+ case 0x60:
+ p = parse_mem(p, q, &entry->mem);
+ if (p == NULL)
+ return -EINVAL;
+ break;
+ }
+
+ /* Misc features */
+ if (features & 0x80) {
+ if (p == q)
+ return -EINVAL;
+ entry->flags |= (*p << 8);
+ while (*p & 0x80)
+ if (++p == q)
+ return -EINVAL;
+ 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 -EINVAL;
+ p = (u_char *)tuple->TupleData;
+ bar->attr = *p;
+ p += 2;
+ bar->size = le32_to_cpu(*(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 -EINVAL;
+ config->last_idx = *(++p);
+ p++;
+ config->base = le32_to_cpu(*(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 -EINVAL;
+ features = *p; p++;
+
+ /* Power options */
+ if ((features & 3) > 0) {
+ p = parse_power(p, q, &entry->vcc);
+ if (p == NULL)
+ return -EINVAL;
+ } else
+ entry->vcc.present = 0;
+ if ((features & 3) > 1) {
+ p = parse_power(p, q, &entry->vpp1);
+ if (p == NULL)
+ return -EINVAL;
+ } else
+ entry->vpp1.present = 0;
+ if ((features & 3) > 2) {
+ p = parse_power(p, q, &entry->vpp2);
+ if (p == NULL)
+ return -EINVAL;
+ } else
+ entry->vpp2.present = 0;
+
+ /* I/O window options */
+ if (features & 0x08) {
+ if (p == q)
+ return -EINVAL;
+ entry->io = *p; p++;
+ } else
+ entry->io = 0;
+
+ /* Interrupt options */
+ if (features & 0x10) {
+ p = parse_irq(p, q, &entry->irq);
+ if (p == NULL)
+ return -EINVAL;
+ } else
+ entry->irq.IRQInfo1 = 0;
+
+ if (features & 0x20) {
+ if (p == q)
+ return -EINVAL;
+ entry->mem = *p; p++;
+ } else
+ entry->mem = 0;
+
+ /* Misc features */
+ if (features & 0x80) {
+ if (p == q)
+ return -EINVAL;
+ entry->flags |= (*p << 8);
+ if (*p & 0x80) {
+ if (++p == q)
+ return -EINVAL;
+ entry->flags |= (*p << 16);
+ }
+ while (*p & 0x80)
+ if (++p == q)
+ return -EINVAL;
+ 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 -EINVAL;
+
+ p = tuple->TupleData;
+ q = p + tuple->TupleDataLen;
+
+ v2->vers = p[0];
+ v2->comply = p[1];
+ v2->dindex = le16_to_cpu(*(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 -EINVAL;
+ org->data_org = *p;
+ if (++p == q)
+ return -EINVAL;
+ for (i = 0; i < 30; i++) {
+ org->desc[i] = *p;
+ if (*p == '\0') break;
+ if (++p == q)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*====================================================================*/
+
+static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
+{
+ u_char *p;
+
+ if (tuple->TupleDataLen < 10)
+ return -EINVAL;
+
+ p = tuple->TupleData;
+
+ fmt->type = p[0];
+ fmt->edc = p[1];
+ fmt->offset = le32_to_cpu(*(u_int *)(p+2));
+ fmt->length = le32_to_cpu(*(u_int *)(p+6));
+
+ return 0;
+}
+
+/*====================================================================*/
+
+int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse)
+{
+ int ret = 0;
+
+ if (tuple->TupleDataLen > tuple->TupleDataMax)
+ return -EINVAL;
+ 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;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
diff --git a/src/cistpl.h b/src/cistpl.h
index e4b07a3..8b833ab 100644
--- a/src/cistpl.h
+++ b/src/cistpl.h
@@ -595,4 +595,10 @@ typedef struct tuple_flags {
#define BIND_FN_ALL 0xff
+int read_out_cis (unsigned int socket_no, FILE *fd);
+int pcmcia_get_first_tuple(unsigned int function, tuple_t *tuple);
+int pcmcia_get_next_tuple(unsigned int function, tuple_t *tuple);
+int pcmcia_get_tuple_data(tuple_t *tuple);
+int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse);
+
#endif /* LINUX_CISTPL_H */
diff --git a/src/pcmcia-check-broken-cis.c b/src/pcmcia-check-broken-cis.c
index b5e4c89..6aa1576 100644
--- a/src/pcmcia-check-broken-cis.c
+++ b/src/pcmcia-check-broken-cis.c
@@ -21,10 +21,6 @@
#include "cistpl.h"
-extern int read_out_cis (unsigned int socket_no);
-extern int pcmcia_get_first_tuple(unsigned int function, tuple_t *tuple);
-extern int pcmcia_get_tuple_data(tuple_t *tuple);
-
struct needs_cis {
unsigned long code;
unsigned long ofs;
@@ -57,7 +53,7 @@ int main(int argc, char **argv) {
if (ret != 1)
return -ENODEV;
- ret = read_out_cis(socket_no);
+ ret = read_out_cis(socket_no, NULL);
if (ret)
return (ret);
diff --git a/src/read-cis.c b/src/read-cis.c
index 2a43f4c..43cc1cc 100644
--- a/src/read-cis.c
+++ b/src/read-cis.c
@@ -33,7 +33,7 @@
static unsigned int functions;
static unsigned char cis_copy[MAX_TUPLES];
-static unsigned int cis_length;
+static unsigned int cis_length = MAX_TUPLES;
#define SPACE(f) (((tuple_flags *)(&(f)))->space)
@@ -225,22 +225,32 @@ int pcmcia_get_tuple_data(tuple_t *tuple)
}
-int read_out_cis (unsigned int socket_no)
+int read_out_cis (unsigned int socket_no, FILE *fd)
{
char file[SYSFS_PATH_MAX];
- int ret;
+ int ret, i;
tuple_t tuple;
unsigned char buf[256];
-
snprintf(file, SYSFS_PATH_MAX, PATH_TO_SOCKET "pcmcia_socket%d/cis",
socket_no);
- ret = sysfs_read_attribute_value(file, cis_copy, MAX_TUPLES);
- if (ret)
- return -EIO;
+ if (!fd) {
+ fd = fopen(file, "r");
+ if (!fd)
+ return -EIO;
+ }
+
+ for (i=0; i<MAX_TUPLES; i++) {
+ ret = fgetc(fd);
+ if (ret == EOF) {
+ cis_length = i + 1;
+ break;
+ }
+ cis_copy[i] = (unsigned char) ret;
+ }
+ fclose(fd);
- cis_length = strlen(cis_copy);
if (cis_length < 4)
return -EINVAL;
@@ -251,7 +261,7 @@ int read_out_cis (unsigned int socket_no)
ret = pcmcia_get_first_tuple(BIND_FN_ALL, &tuple);
if (ret)
- return -EBUSY;
+ functions = 1;
tuple.TupleData = buf;
tuple.TupleOffset = 0;
diff --git a/src/startup.c b/src/startup.c
index 00d1328..393d685 100644
--- a/src/startup.c
+++ b/src/startup.c
@@ -179,7 +179,6 @@ static void load_config(void)
static void adjust_resources(unsigned int socket_no)
{
adjust_list_t *al;
- char tmp[64];
for (al = root_adjust; al; al = al->next) {
switch (al->adj.Resource) {
@@ -199,7 +198,7 @@ static void adjust_resources(unsigned int socket_no)
disallow_irq(socket_no, al->adj.resource.irq.IRQ);
break;
}
- syslog(LOG_WARNING, "could not adjust resource: %s: %m", tmp);
+ syslog(LOG_WARNING, "could not adjust resource!");
}
}