diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2005-12-06 20:25:07 +0100 |
---|---|---|
committer | Dominik Brodowski <brodo@isilmar.linta.de> | 2005-12-06 20:30:54 +0100 |
commit | 3603bb957419e1d633fe80a4d95bcb09687f54c6 (patch) | |
tree | a03f019ab66f1e17c41de561859a4451f1eb0ab7 | |
parent | 1050829dc4aa7be84652a95a6e2ad56f5f529296 (diff) | |
download | pcmciautils-3603bb957419e1d633fe80a4d95bcb09687f54c6.tar.gz |
Release of pcmciautils-003 (2005-05-05)
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
-rw-r--r-- | Makefile | 16 | ||||
-rw-r--r-- | config/config.opts | 27 | ||||
-rw-r--r-- | debug/cbdump.c | 280 | ||||
-rw-r--r-- | debug/dump_cis.c | 993 | ||||
-rw-r--r-- | debug/parse_cis.c | 876 | ||||
-rw-r--r-- | src/cistpl.h | 6 | ||||
-rw-r--r-- | src/pcmcia-check-broken-cis.c | 6 | ||||
-rw-r--r-- | src/read-cis.c | 28 | ||||
-rw-r--r-- | src/startup.c | 3 |
9 files changed, 2191 insertions, 44 deletions
@@ -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!"); } } |