summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBob Gilligan <gilligan@vyatta.com>2010-02-05 09:54:11 -0800
committerBob Gilligan <gilligan@vyatta.com>2010-02-05 09:54:11 -0800
commite1971e4774a6ebb5ed33a09bdd60afa2c0534b6f (patch)
treef4fc5aaccb4d9dac43ae7a825df9006532c1a059 /src
downloadvyatta-biosdevname-e1971e4774a6ebb5ed33a09bdd60afa2c0534b6f.tar.gz
vyatta-biosdevname-e1971e4774a6ebb5ed33a09bdd60afa2c0534b6f.zip
Initial commit.debian/0.1
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am44
-rw-r--r--src/bios_dev_name.c139
-rw-r--r--src/bios_dev_name.h21
-rw-r--r--src/bios_device.c387
-rw-r--r--src/bios_device.h35
-rw-r--r--src/cistpl.h605
-rw-r--r--src/dmidecode/config.h29
-rw-r--r--src/dmidecode/dmidecode.c382
-rw-r--r--src/dmidecode/dmidecode.h55
-rw-r--r--src/dmidecode/dmioem.c120
-rw-r--r--src/dmidecode/dmioem.h26
-rw-r--r--src/dmidecode/types.h27
-rw-r--r--src/dmidecode/util.c165
-rw-r--r--src/dmidecode/util.h8
-rw-r--r--src/eths.c218
-rw-r--r--src/eths.h57
-rw-r--r--src/ethtool-copy.h375
-rw-r--r--src/ethtool-util.h22
-rw-r--r--src/libbiosdevname.h29
-rw-r--r--src/list.h422
-rw-r--r--src/naming_policy.c107
-rw-r--r--src/naming_policy.h14
-rw-r--r--src/parse_cis.c882
-rw-r--r--src/pci.c244
-rw-r--r--src/pci.h53
-rw-r--r--src/pcmcia.c295
-rw-r--r--src/pcmcia.h35
-rw-r--r--src/pirq.c150
-rw-r--r--src/pirq.h58
-rw-r--r--src/read-cis.c275
-rw-r--r--src/read_proc.c108
-rw-r--r--src/state.h18
32 files changed, 5405 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..5d3562c
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,44 @@
+INCLUDES = -I..
+AM_CFLAGS = -Wall -fno-strict-aliasing
+
+srcPath=src/
+man_MANS = biosdevname.1
+
+sbin_PROGRAMS = src/biosdevname src/biosdevnameS
+src_biosdevname_SOURCES = \
+ src/bios_dev_name.c \
+ src/bios_device.c \
+ src/pirq.c \
+ src/pci.c \
+ src/eths.c \
+ src/read_proc.c \
+ src/naming_policy.c \
+ src/pcmcia.c \
+ src/read-cis.c \
+ src/parse_cis.c \
+ src/dmidecode/dmidecode.c \
+ src/dmidecode/dmioem.c \
+ src/dmidecode/util.c
+
+src_biosdevnameS_SOURCES = $(src_biosdevname_SOURCES)
+src_biosdevnameS_LDFLAGS = -all-static
+
+EXTRA_DIST = \
+ src/bios_dev_name.h \
+ src/bios_device.h \
+ src/pirq.h \
+ src/pci.h \
+ src/eths.h \
+ src/ethtool-util.h \
+ src/ethtool-copy.h \
+ src/list.h \
+ src/naming_policy.h \
+ src/pcmcia.h \
+ src/cistpl.h \
+ src/state.h \
+ src/libbiosdevname.h \
+ src/dmidecode/config.h \
+ src/dmidecode/dmidecode.h \
+ src/dmidecode/dmioem.h \
+ src/dmidecode/types.h \
+ src/dmidecode/util.h
diff --git a/src/bios_dev_name.c b/src/bios_dev_name.c
new file mode 100644
index 0000000..ce13742
--- /dev/null
+++ b/src/bios_dev_name.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include "libbiosdevname.h"
+#include "bios_dev_name.h"
+
+static struct bios_dev_name_opts opts;
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: biosdevname [options] [args]...\n");
+ fprintf(stderr, " Options:\n");
+ fprintf(stderr, " -i or --interface treat [args] as ethernet devs\n");
+ fprintf(stderr, " -d or --debug enable debugging\n");
+ fprintf(stderr, " -n or --nosort don't sort the PCI device list breadth-first\n");
+ fprintf(stderr, " --policy [kernelnames | all_ethN | all_names | embedded_ethN_slots_names]\n");
+ fprintf(stderr, " Example: biosdevname -i eth0\n");
+ fprintf(stderr, " returns: eth0\n");
+ fprintf(stderr, " when the BIOS name and kernel name are both eth0.\n");
+ fprintf(stderr, " --nosort implies --policy kernelnames.\n");
+ fprintf(stderr, " You must be root to run this, as it must read from /dev/mem.\n");
+}
+
+static int
+set_policy(const char *arg)
+{
+ int rc = all_ethN;
+ if (!strncmp("kernelnames", arg, sizeof("kernelnames")))
+ rc = kernelnames;
+ else if (!strncmp("all_ethN", arg, sizeof("all_ethN")))
+ rc = all_ethN;
+ else if (!strncmp("all_names", arg, sizeof("all_names")))
+ rc = all_names;
+ else if (!strncmp("embedded_ethN_slots_names", arg, sizeof("embedded_ethN_slots_names")))
+ rc = embedded_ethN_slots_names;
+ return rc;
+}
+
+static void
+parse_opts(int argc, char **argv)
+{
+ int c;
+ int option_index = 0;
+
+ while (1) {
+ static struct option long_options[] =
+ /* name, has_arg, flag, val */
+ {
+ {"debug", no_argument, 0, 'd'},
+ {"interface", no_argument, 0, 'i'},
+ {"nosort", no_argument, 0, 'n'},
+ {"policy", required_argument, 0, 'p'},
+ {0, 0, 0, 0}
+ };
+ c = getopt_long(argc, argv,
+ "dinp:",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+ switch(c) {
+ case 'd':
+ opts.debug = 1;
+ break;
+ case 'i':
+ opts.interface = 1;
+ break;
+ case 'n':
+ opts.sortroutine = nosort;
+ break;
+ case 'p':
+ opts.namingpolicy = set_policy(optarg);
+ break;
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ if (optind < argc) {
+ opts.argc = argc-optind;
+ opts.argv = &argv[optind];
+ opts.optind = optind;
+ }
+
+ if (opts.sortroutine == nosort)
+ opts.namingpolicy = kernelnames;
+}
+
+int main(int argc, char *argv[])
+{
+ int i, rc=0;
+ char *name;
+ void *cookie = NULL;
+
+ parse_opts(argc, argv);
+ cookie = setup_bios_devices(opts.sortroutine, opts.namingpolicy);
+ if (!cookie) {
+ usage();
+ rc = 1;
+ goto out;
+ }
+
+ if (opts.debug) {
+ unparse_bios_devices(cookie);
+ rc = 0;
+ goto out_cleanup;
+ }
+
+
+ if (!opts.interface) {
+ fprintf(stderr, "Unknown device type, try passing an option like -i\n");
+ rc = 1;
+ goto out_usage;
+ }
+
+ for (i=0; i<opts.argc; i++) {
+ name = kern_to_bios(cookie, opts.argv[i]);
+ if (name) {
+ printf("%s\n", name);
+ }
+ else
+ rc |= 2; /* one or more given devices weren't found */
+ }
+ goto out_cleanup;
+
+ out_usage:
+ usage();
+ out_cleanup:
+ cleanup_bios_devices(cookie);
+ out:
+ return rc;
+}
diff --git a/src/bios_dev_name.h b/src/bios_dev_name.h
new file mode 100644
index 0000000..658bfa3
--- /dev/null
+++ b/src/bios_dev_name.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+#ifndef GLUE_H_INCLUDED
+#define GLUE_H_INCLUDED
+
+struct bios_dev_name_opts {
+ int argc;
+ char **argv;
+ int optind;
+ int sortroutine;
+ int namingpolicy;
+ unsigned int verbose:1;
+ unsigned int show_all:1;
+ unsigned int debug:1;
+ unsigned int interface:1;
+};
+
+#endif /* GLUE_H_INCLUDED */
diff --git a/src/bios_device.c b/src/bios_device.c
new file mode 100644
index 0000000..5c275c8
--- /dev/null
+++ b/src/bios_device.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <net/if.h>
+#include "list.h"
+#include "bios_device.h"
+#include "state.h"
+#include "libbiosdevname.h"
+#include "dmidecode/dmidecode.h"
+
+void free_bios_devices(void *cookie)
+{
+ struct libbiosdevname_state *state = cookie;
+ struct bios_device *dev, *n;
+ if (!state)
+ return;
+ list_for_each_entry_safe(dev, n, &state->bios_devices, node) {
+ list_del(&(dev->node));
+ free(dev);
+ }
+}
+
+
+static void unparse_bios_device(struct bios_device *dev)
+{
+ char buf[200];
+ printf("BIOS device: %s\n", dev->bios_name);
+ if (dev->netdev) {
+ unparse_network_device(buf, sizeof(buf), dev->netdev);
+ printf("%s", buf);
+ }
+ else
+ printf(" No driver loaded for this device.\n");
+
+ if (is_pci(dev)) {
+ unparse_pci_device(buf, sizeof(buf), dev->pcidev);
+ printf("%s", buf);
+ }
+ else if (is_pcmcia(dev)) {
+ unparse_pcmcia_device(buf, sizeof(buf), dev->pcmciadev);
+ printf("%s", buf);
+ }
+
+ printf("\n");
+}
+
+void unparse_bios_devices(void *cookie)
+{
+ struct libbiosdevname_state *state = cookie;
+ struct bios_device *dev;
+ if (!state)
+ return;
+ list_for_each_entry(dev, &state->bios_devices, node) {
+ unparse_bios_device(dev);
+ }
+}
+
+void unparse_bios_device_by_name(void *cookie,
+ const char *name)
+{
+
+ struct libbiosdevname_state *state = cookie;
+ struct bios_device *dev;
+ if (!state)
+ return;
+ list_for_each_entry(dev, &state->bios_devices, node) {
+ if (dev->netdev && !strcmp(dev->netdev->kernel_name, name))
+ unparse_bios_device(dev);
+ }
+}
+
+char * kern_to_bios(void *cookie,
+ const char *name)
+{
+ struct libbiosdevname_state *state = cookie;
+ struct bios_device *dev;
+ if (!state)
+ return NULL;
+ list_for_each_entry(dev, &state->bios_devices, node) {
+ if (dev->netdev && !strcmp(dev->netdev->kernel_name, name))
+ return dev->bios_name;
+ }
+ return NULL;
+}
+
+void unparse_bios_device_list(void *cookie)
+{
+ struct libbiosdevname_state *state = cookie;
+ struct bios_device *dev;
+ if (!state)
+ return;
+ list_for_each_entry(dev, &state->bios_devices, node) {
+ unparse_bios_device(dev);
+ }
+}
+
+
+
+/*
+ * This sorts all the embedded devices first; by PCI bus/dev/fn, then
+ * all the add-in devices by slot number, by pci bus/dev/fn.
+ * Unknown location devices show up as physical slot INT_MAX, so they
+ * come last.
+ */
+
+static int sort_pci(const struct bios_device *bdev_a, const struct bios_device *bdev_b)
+{
+ const struct pci_device *a = bdev_a->pcidev;
+ const struct pci_device *b = bdev_b->pcidev;
+
+ if (a->physical_slot < b->physical_slot) return -1;
+ else if (a->physical_slot > b->physical_slot) return 1;
+
+ if (a->pci_dev.domain < b->pci_dev.domain) return -1;
+ else if (a->pci_dev.domain > b->pci_dev.domain) return 1;
+
+ if (a->pci_dev.bus < b->pci_dev.bus) return -1;
+ else if (a->pci_dev.bus > b->pci_dev.bus) return 1;
+
+ if (a->pci_dev.dev < b->pci_dev.dev) return -1;
+ else if (a->pci_dev.dev > b->pci_dev.dev) return 1;
+
+ if (a->pci_dev.func < b->pci_dev.func) return -1;
+ else if (a->pci_dev.func > b->pci_dev.func) return 1;
+
+ return 0;
+}
+
+static int sort_smbios(const struct bios_device *x, const struct bios_device *y)
+{
+ struct pci_device *a, *b;
+
+ if (x->pcidev && !y->pcidev) return -1;
+ else if (!x->pcidev && y->pcidev) return 1;
+
+ a = x->pcidev;
+ b = y->pcidev;
+
+ if (a->physical_slot == 0 && b->physical_slot == 0) {
+ if ( a->smbios_type == b->smbios_type) {
+ if ( a->smbios_instance < b->smbios_instance) return -1;
+ else if (a->smbios_instance > b->smbios_instance) return 1;
+ }
+ }
+ else {
+ if (a->physical_slot < b->physical_slot) return -1;
+ else if (a->physical_slot > b->physical_slot) return 1;
+ }
+
+ return sort_pci(x, y);
+}
+
+
+static int sort_pcmcia(const struct bios_device *bdev_a, const struct bios_device *bdev_b)
+{
+ const struct pcmcia_device *a = bdev_a->pcmciadev;
+ const struct pcmcia_device *b = bdev_b->pcmciadev;
+
+ if (a->socket < b->socket) return -1;
+ else if (a->socket > b->socket) return 1;
+
+ if (a->function < b->function) return -1;
+ else if (a->function > b->function) return 1;
+
+ return 0;
+}
+
+enum bios_device_types {
+ IS_PCI,
+ IS_PCMCIA,
+ IS_UNKNOWN_TYPE,
+};
+
+static int bios_device_type_num(const struct bios_device *dev)
+{
+ if (is_pci(dev))
+ return IS_PCI;
+ else if (is_pcmcia(dev))
+ return IS_PCMCIA;
+ return IS_UNKNOWN_TYPE;
+}
+
+static int sort_by_type(const struct bios_device *a, const struct bios_device *b)
+{
+ if (bios_device_type_num(a) < bios_device_type_num(b))
+ return -1;
+ else if (bios_device_type_num(a) == bios_device_type_num(b)) {
+ if (is_pci(a))
+ return sort_smbios(a, b);
+ else if (is_pcmcia(a))
+ return sort_pcmcia(a, b);
+ else return 0;
+ }
+ else if (bios_device_type_num(a) > bios_device_type_num(b))
+ return 1;
+ return 0;
+}
+
+
+static void insertion_sort_devices(struct bios_device *a, struct list_head *list,
+ int (*cmp)(const struct bios_device *, const struct bios_device *))
+{
+ struct bios_device *b;
+ list_for_each_entry(b, list, node) {
+ if (cmp(a, b) <= 0) {
+ list_move_tail(&a->node, &b->node);
+ return;
+ }
+ }
+ list_move_tail(&a->node, list);
+}
+
+static int set_slot_index(struct libbiosdevname_state *state)
+{
+ struct bios_device *dev;
+ int prevslot=-1;
+ int index=0;
+
+ list_for_each_entry(dev, &state->bios_devices, node) {
+ if (!dev->pcidev)
+ continue;
+ if (dev->pcidev->physical_slot != prevslot)
+ index=0;
+ else
+ index++;
+ dev->pcidev->index_in_slot = index;
+ prevslot = dev->pcidev->physical_slot;
+ }
+ return 0;
+}
+
+static void sort_device_list(struct libbiosdevname_state *state)
+{
+ LIST_HEAD(sorted_devices);
+ struct bios_device *dev, *tmp;
+ list_for_each_entry_safe(dev, tmp, &state->bios_devices, node) {
+ insertion_sort_devices(dev, &sorted_devices, sort_by_type);
+ }
+ list_splice(&sorted_devices, &state->bios_devices);
+ set_slot_index(state);
+}
+
+static void match_eth_and_pci_devs(struct libbiosdevname_state *state)
+{
+ struct pci_device *p;
+ struct bios_device *b;
+ struct network_device *n;
+ char pci_name[40];
+
+ list_for_each_entry(p, &state->pci_devices, node) {
+ if (!is_pci_network(p))
+ continue;
+
+ unparse_pci_name(pci_name, sizeof(pci_name), &p->pci_dev);
+ n = find_net_device_by_bus_info(state, pci_name);
+ if (!n)
+ continue;
+
+ b = malloc(sizeof(*b));
+ if (!b)
+ continue;
+ memset(b, 0, sizeof(*b));
+ INIT_LIST_HEAD(&b->node);
+ b->pcidev = p;
+ b->netdev = n;
+ claim_netdev(b->netdev);
+ list_add(&b->node, &state->bios_devices);
+ }
+}
+
+static void match_eth_and_pcmcia(struct libbiosdevname_state *state)
+{
+ struct pcmcia_device *p;
+ struct bios_device *b;
+ char pcmcia_name[40];
+
+ list_for_each_entry(p, &state->pcmcia_devices, node) {
+ if (!is_pcmcia_network(p))
+ continue;
+
+ b = malloc(sizeof(*b));
+ if (!b)
+ continue;
+ memset(b, 0, sizeof(*b));
+ INIT_LIST_HEAD(&b->node);
+ b->pcmciadev = p;
+
+ unparse_pcmcia_name(pcmcia_name, sizeof(pcmcia_name), p);
+ b->netdev = find_net_device_by_bus_info(state, pcmcia_name);
+
+ memset(b->bios_name, 0, sizeof(b->bios_name));
+ claim_netdev(b->netdev);
+ list_add(&b->node, &state->bios_devices);
+ }
+}
+
+static void match_unknown_eths(struct libbiosdevname_state *state)
+{
+ struct bios_device *b;
+ struct network_device *n;
+ list_for_each_entry(n, &state->network_devices, node)
+ {
+ if (netdev_is_claimed(n))
+ continue;
+ if (!drvinfo_valid(n))
+ continue;
+ if (!is_ethernet(n)) /* for virtual interfaces */
+ continue;
+ b = malloc(sizeof(*b));
+ if (!b)
+ continue;
+ memset(b, 0, sizeof(*b));
+ INIT_LIST_HEAD(&b->node);
+ b->netdev = n;
+ list_add(&b->node, &state->bios_devices);
+ }
+}
+
+
+static void match_all(struct libbiosdevname_state *state)
+{
+ match_eth_and_pci_devs(state);
+ match_eth_and_pcmcia(state);
+ match_unknown_eths(state);
+}
+
+static struct libbiosdevname_state * alloc_state(void)
+{
+ struct libbiosdevname_state *state;
+ state = malloc(sizeof(*state));
+ if (!state)
+ return NULL;
+ INIT_LIST_HEAD(&state->bios_devices);
+ INIT_LIST_HEAD(&state->pci_devices);
+ INIT_LIST_HEAD(&state->network_devices);
+ INIT_LIST_HEAD(&state->pcmcia_devices);
+ return state;
+}
+
+void cleanup_bios_devices(void *cookie)
+{
+ struct libbiosdevname_state *state = cookie;
+ if (!state)
+ return;
+ free_bios_devices(state);
+ free_eths(state);
+ free_pcmcia_devices(state);
+ free_pci_devices(state);
+}
+
+void * setup_bios_devices(int sortroutine, int namingpolicy)
+{
+ int rc=1;
+ struct libbiosdevname_state *state = alloc_state();
+
+ if (!state)
+ return NULL;
+
+ rc = get_pci_devices(state);
+ if (rc)
+ goto out;
+
+ rc = get_pcmcia_devices(state);
+ if (rc)
+ goto out;
+ rc = dmidecode_main(state);
+ if (rc)
+ goto out;
+ get_eths(state);
+ match_all(state);
+ if (sortroutine != nosort) {
+ sort_device_list(state);
+ }
+ assign_bios_network_names(state, sortroutine, namingpolicy);
+ return state;
+
+out:
+ cleanup_bios_devices(state);
+ free(state);
+ return NULL;
+}
+
diff --git a/src/bios_device.h b/src/bios_device.h
new file mode 100644
index 0000000..8e76e1a
--- /dev/null
+++ b/src/bios_device.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+#ifndef BIOS_DEVICE_H_INCLUDED
+#define BIOS_DEVICE_H_INCLUDED
+
+#include <pci/pci.h>
+#include "list.h"
+#include "eths.h"
+#include "pci.h"
+#include "pcmcia.h"
+#include "naming_policy.h"
+
+
+struct bios_device {
+ struct list_head node;
+ struct network_device *netdev;
+ struct pci_device *pcidev;
+ struct pcmcia_device *pcmciadev;
+ char bios_name[IFNAMSIZ];
+};
+
+static inline int is_pci(const struct bios_device *dev)
+{
+ return dev->pcidev != NULL;
+}
+
+static inline int is_pcmcia(const struct bios_device *dev)
+{
+ return dev->pcmciadev != NULL;
+}
+
+#endif /* BIOS_DEVICE_H_INCLUDED */
diff --git a/src/cistpl.h b/src/cistpl.h
new file mode 100644
index 0000000..8a2f270
--- /dev/null
+++ b/src/cistpl.h
@@ -0,0 +1,605 @@
+/*
+ * cistpl.h
+ *
+ * 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
+ */
+
+#ifndef _LINUX_CISTPL_H
+#define _LINUX_CISTPL_H
+
+#define CISTPL_NULL 0x00
+#define CISTPL_DEVICE 0x01
+#define CISTPL_LONGLINK_CB 0x02
+#define CISTPL_INDIRECT 0x03
+#define CISTPL_CONFIG_CB 0x04
+#define CISTPL_CFTABLE_ENTRY_CB 0x05
+#define CISTPL_LONGLINK_MFC 0x06
+#define CISTPL_BAR 0x07
+#define CISTPL_PWR_MGMNT 0x08
+#define CISTPL_EXTDEVICE 0x09
+#define CISTPL_CHECKSUM 0x10
+#define CISTPL_LONGLINK_A 0x11
+#define CISTPL_LONGLINK_C 0x12
+#define CISTPL_LINKTARGET 0x13
+#define CISTPL_NO_LINK 0x14
+#define CISTPL_VERS_1 0x15
+#define CISTPL_ALTSTR 0x16
+#define CISTPL_DEVICE_A 0x17
+#define CISTPL_JEDEC_C 0x18
+#define CISTPL_JEDEC_A 0x19
+#define CISTPL_CONFIG 0x1a
+#define CISTPL_CFTABLE_ENTRY 0x1b
+#define CISTPL_DEVICE_OC 0x1c
+#define CISTPL_DEVICE_OA 0x1d
+#define CISTPL_DEVICE_GEO 0x1e
+#define CISTPL_DEVICE_GEO_A 0x1f
+#define CISTPL_MANFID 0x20
+#define CISTPL_FUNCID 0x21
+#define CISTPL_FUNCE 0x22
+#define CISTPL_SWIL 0x23
+#define CISTPL_END 0xff
+/* Layer 2 tuples */
+#define CISTPL_VERS_2 0x40
+#define CISTPL_FORMAT 0x41
+#define CISTPL_GEOMETRY 0x42
+#define CISTPL_BYTEORDER 0x43
+#define CISTPL_DATE 0x44
+#define CISTPL_BATTERY 0x45
+#define CISTPL_FORMAT_A 0x47
+/* Layer 3 tuples */
+#define CISTPL_ORG 0x46
+#define CISTPL_SPCL 0x90
+
+typedef struct cistpl_longlink_t {
+ unsigned int addr;
+} cistpl_longlink_t;
+
+typedef struct cistpl_checksum_t {
+ unsigned short addr;
+ unsigned short len;
+ unsigned char sum;
+} cistpl_checksum_t;
+
+#define CISTPL_MAX_FUNCTIONS 8
+#define CISTPL_MFC_ATTR 0x00
+#define CISTPL_MFC_COMMON 0x01
+
+typedef struct cistpl_longlink_mfc_t {
+ unsigned char nfn;
+ struct {
+ unsigned char space;
+ unsigned int addr;
+ } fn[CISTPL_MAX_FUNCTIONS];
+} cistpl_longlink_mfc_t;
+
+#define CISTPL_MAX_ALTSTR_STRINGS 4
+
+typedef struct cistpl_altstr_t {
+ unsigned char ns;
+ unsigned char ofs[CISTPL_MAX_ALTSTR_STRINGS];
+ char str[254];
+} cistpl_altstr_t;
+
+#define CISTPL_DTYPE_NULL 0x00
+#define CISTPL_DTYPE_ROM 0x01
+#define CISTPL_DTYPE_OTPROM 0x02
+#define CISTPL_DTYPE_EPROM 0x03
+#define CISTPL_DTYPE_EEPROM 0x04
+#define CISTPL_DTYPE_FLASH 0x05
+#define CISTPL_DTYPE_SRAM 0x06
+#define CISTPL_DTYPE_DRAM 0x07
+#define CISTPL_DTYPE_FUNCSPEC 0x0d
+#define CISTPL_DTYPE_EXTEND 0x0e
+
+#define CISTPL_MAX_DEVICES 4
+
+typedef struct cistpl_device_t {
+ unsigned char ndev;
+ struct {
+ unsigned char type;
+ unsigned char wp;
+ unsigned int speed;
+ unsigned int size;
+ } dev[CISTPL_MAX_DEVICES];
+} cistpl_device_t;
+
+#define CISTPL_DEVICE_MWAIT 0x01
+#define CISTPL_DEVICE_3VCC 0x02
+
+typedef struct cistpl_device_o_t {
+ unsigned char flags;
+ cistpl_device_t device;
+} cistpl_device_o_t;
+
+#define CISTPL_VERS_1_MAX_PROD_STRINGS 4
+
+typedef struct cistpl_vers_1_t {
+ unsigned char major;
+ unsigned char minor;
+ unsigned char ns;
+ unsigned char ofs[CISTPL_VERS_1_MAX_PROD_STRINGS];
+ char str[254];
+} cistpl_vers_1_t;
+
+typedef struct cistpl_jedec_t {
+ unsigned char nid;
+ struct {
+ unsigned char mfr;
+ unsigned char info;
+ } id[CISTPL_MAX_DEVICES];
+} cistpl_jedec_t;
+
+typedef struct cistpl_manfid_t {
+ unsigned short manf;
+ unsigned short card;
+} cistpl_manfid_t;
+
+#define CISTPL_FUNCID_MULTI 0x00
+#define CISTPL_FUNCID_MEMORY 0x01
+#define CISTPL_FUNCID_SERIAL 0x02
+#define CISTPL_FUNCID_PARALLEL 0x03
+#define CISTPL_FUNCID_FIXED 0x04
+#define CISTPL_FUNCID_VIDEO 0x05
+#define CISTPL_FUNCID_NETWORK 0x06
+#define CISTPL_FUNCID_AIMS 0x07
+#define CISTPL_FUNCID_SCSI 0x08
+
+#define CISTPL_SYSINIT_POST 0x01
+#define CISTPL_SYSINIT_ROM 0x02
+
+typedef struct cistpl_funcid_t {
+ unsigned char func;
+ unsigned char sysinit;
+} cistpl_funcid_t;
+
+typedef struct cistpl_funce_t {
+ unsigned char type;
+ unsigned char data[0];
+} cistpl_funce_t;
+
+/*======================================================================
+
+ Modem Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_FUNCE_SERIAL_IF 0x00
+#define CISTPL_FUNCE_SERIAL_CAP 0x01
+#define CISTPL_FUNCE_SERIAL_SERV_DATA 0x02
+#define CISTPL_FUNCE_SERIAL_SERV_FAX 0x03
+#define CISTPL_FUNCE_SERIAL_SERV_VOICE 0x04
+#define CISTPL_FUNCE_SERIAL_CAP_DATA 0x05
+#define CISTPL_FUNCE_SERIAL_CAP_FAX 0x06
+#define CISTPL_FUNCE_SERIAL_CAP_VOICE 0x07
+#define CISTPL_FUNCE_SERIAL_IF_DATA 0x08
+#define CISTPL_FUNCE_SERIAL_IF_FAX 0x09
+#define CISTPL_FUNCE_SERIAL_IF_VOICE 0x0a
+
+/* UART identification */
+#define CISTPL_SERIAL_UART_8250 0x00
+#define CISTPL_SERIAL_UART_16450 0x01
+#define CISTPL_SERIAL_UART_16550 0x02
+#define CISTPL_SERIAL_UART_8251 0x03
+#define CISTPL_SERIAL_UART_8530 0x04
+#define CISTPL_SERIAL_UART_85230 0x05
+
+/* UART capabilities */
+#define CISTPL_SERIAL_UART_SPACE 0x01
+#define CISTPL_SERIAL_UART_MARK 0x02
+#define CISTPL_SERIAL_UART_ODD 0x04
+#define CISTPL_SERIAL_UART_EVEN 0x08
+#define CISTPL_SERIAL_UART_5BIT 0x01
+#define CISTPL_SERIAL_UART_6BIT 0x02
+#define CISTPL_SERIAL_UART_7BIT 0x04
+#define CISTPL_SERIAL_UART_8BIT 0x08
+#define CISTPL_SERIAL_UART_1STOP 0x10
+#define CISTPL_SERIAL_UART_MSTOP 0x20
+#define CISTPL_SERIAL_UART_2STOP 0x40
+
+typedef struct cistpl_serial_t {
+ unsigned char uart_type;
+ unsigned char uart_cap_0;
+ unsigned char uart_cap_1;
+} cistpl_serial_t;
+
+typedef struct cistpl_modem_cap_t {
+ unsigned char flow;
+ unsigned char cmd_buf;
+ unsigned char rcv_buf_0, rcv_buf_1, rcv_buf_2;
+ unsigned char xmit_buf_0, xmit_buf_1, xmit_buf_2;
+} cistpl_modem_cap_t;
+
+#define CISTPL_SERIAL_MOD_103 0x01
+#define CISTPL_SERIAL_MOD_V21 0x02
+#define CISTPL_SERIAL_MOD_V23 0x04
+#define CISTPL_SERIAL_MOD_V22 0x08
+#define CISTPL_SERIAL_MOD_212A 0x10
+#define CISTPL_SERIAL_MOD_V22BIS 0x20
+#define CISTPL_SERIAL_MOD_V26 0x40
+#define CISTPL_SERIAL_MOD_V26BIS 0x80
+#define CISTPL_SERIAL_MOD_V27BIS 0x01
+#define CISTPL_SERIAL_MOD_V29 0x02
+#define CISTPL_SERIAL_MOD_V32 0x04
+#define CISTPL_SERIAL_MOD_V32BIS 0x08
+#define CISTPL_SERIAL_MOD_V34 0x10
+
+#define CISTPL_SERIAL_ERR_MNP2_4 0x01
+#define CISTPL_SERIAL_ERR_V42_LAPM 0x02
+
+#define CISTPL_SERIAL_CMPR_V42BIS 0x01
+#define CISTPL_SERIAL_CMPR_MNP5 0x02
+
+#define CISTPL_SERIAL_CMD_AT1 0x01
+#define CISTPL_SERIAL_CMD_AT2 0x02
+#define CISTPL_SERIAL_CMD_AT3 0x04
+#define CISTPL_SERIAL_CMD_MNP_AT 0x08
+#define CISTPL_SERIAL_CMD_V25BIS 0x10
+#define CISTPL_SERIAL_CMD_V25A 0x20
+#define CISTPL_SERIAL_CMD_DMCL 0x40
+
+typedef struct cistpl_data_serv_t {
+ unsigned char max_data_0;
+ unsigned char max_data_1;
+ unsigned char modulation_0;
+ unsigned char modulation_1;
+ unsigned char error_control;
+ unsigned char compression;
+ unsigned char cmd_protocol;
+ unsigned char escape;
+ unsigned char encrypt;
+ unsigned char misc_features;
+ unsigned char ccitt_code[0];
+} cistpl_data_serv_t;
+
+typedef struct cistpl_fax_serv_t {
+ unsigned char max_data_0;
+ unsigned char max_data_1;
+ unsigned char modulation;
+ unsigned char encrypt;
+ unsigned char features_0;
+ unsigned char features_1;
+ unsigned char ccitt_code[0];
+} cistpl_fax_serv_t;
+
+typedef struct cistpl_voice_serv_t {
+ unsigned char max_data_0;
+ unsigned char max_data_1;
+} cistpl_voice_serv_t;
+
+/*======================================================================
+
+ LAN Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_FUNCE_LAN_TECH 0x01
+#define CISTPL_FUNCE_LAN_SPEED 0x02
+#define CISTPL_FUNCE_LAN_MEDIA 0x03
+#define CISTPL_FUNCE_LAN_NODE_ID 0x04
+#define CISTPL_FUNCE_LAN_CONNECTOR 0x05
+
+/* LAN technologies */
+#define CISTPL_LAN_TECH_ARCNET 0x01
+#define CISTPL_LAN_TECH_ETHERNET 0x02
+#define CISTPL_LAN_TECH_TOKENRING 0x03
+#define CISTPL_LAN_TECH_LOCALTALK 0x04
+#define CISTPL_LAN_TECH_FDDI 0x05
+#define CISTPL_LAN_TECH_ATM 0x06
+#define CISTPL_LAN_TECH_WIRELESS 0x07
+
+typedef struct cistpl_lan_tech_t {
+ unsigned char tech;
+} cistpl_lan_tech_t;
+
+typedef struct cistpl_lan_speed_t {
+ unsigned int speed;
+} cistpl_lan_speed_t;
+
+/* LAN media definitions */
+#define CISTPL_LAN_MEDIA_UTP 0x01
+#define CISTPL_LAN_MEDIA_STP 0x02
+#define CISTPL_LAN_MEDIA_THIN_COAX 0x03
+#define CISTPL_LAN_MEDIA_THICK_COAX 0x04
+#define CISTPL_LAN_MEDIA_FIBER 0x05
+#define CISTPL_LAN_MEDIA_900MHZ 0x06
+#define CISTPL_LAN_MEDIA_2GHZ 0x07
+#define CISTPL_LAN_MEDIA_5GHZ 0x08
+#define CISTPL_LAN_MEDIA_DIFF_IR 0x09
+#define CISTPL_LAN_MEDIA_PTP_IR 0x0a
+
+typedef struct cistpl_lan_media_t {
+ unsigned char media;
+} cistpl_lan_media_t;
+
+typedef struct cistpl_lan_node_id_t {
+ unsigned char nb;
+ unsigned char id[16];
+} cistpl_lan_node_id_t;
+
+typedef struct cistpl_lan_connector_t {
+ unsigned char code;
+} cistpl_lan_connector_t;
+
+/*======================================================================
+
+ IDE Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_IDE_INTERFACE 0x01
+
+typedef struct cistpl_ide_interface_t {
+ unsigned char interface;
+} cistpl_ide_interface_t;
+
+/* First feature byte */
+#define CISTPL_IDE_SILICON 0x04
+#define CISTPL_IDE_UNIQUE 0x08
+#define CISTPL_IDE_DUAL 0x10
+
+/* Second feature byte */
+#define CISTPL_IDE_HAS_SLEEP 0x01
+#define CISTPL_IDE_HAS_STANDBY 0x02
+#define CISTPL_IDE_HAS_IDLE 0x04
+#define CISTPL_IDE_LOW_POWER 0x08
+#define CISTPL_IDE_REG_INHIBIT 0x10
+#define CISTPL_IDE_HAS_INDEX 0x20
+#define CISTPL_IDE_IOIS16 0x40
+
+typedef struct cistpl_ide_feature_t {
+ unsigned char feature1;
+ unsigned char feature2;
+} cistpl_ide_feature_t;
+
+#define CISTPL_FUNCE_IDE_IFACE 0x01
+#define CISTPL_FUNCE_IDE_MASTER 0x02
+#define CISTPL_FUNCE_IDE_SLAVE 0x03
+
+/*======================================================================
+
+ Configuration Table Entries
+
+======================================================================*/
+
+#define CISTPL_BAR_SPACE 0x07
+#define CISTPL_BAR_SPACE_IO 0x10
+#define CISTPL_BAR_PREFETCH 0x20
+#define CISTPL_BAR_CACHEABLE 0x40
+#define CISTPL_BAR_1MEG_MAP 0x80
+
+typedef struct cistpl_bar_t {
+ unsigned char attr;
+ unsigned int size;
+} cistpl_bar_t;
+
+typedef struct cistpl_config_t {
+ unsigned char last_idx;
+ unsigned int base;
+ unsigned int rmask[4];
+ unsigned char subtuples;
+} cistpl_config_t;
+
+/* These are bits in the 'present' field, and indices in 'param' */
+#define CISTPL_POWER_VNOM 0
+#define CISTPL_POWER_VMIN 1
+#define CISTPL_POWER_VMAX 2
+#define CISTPL_POWER_ISTATIC 3
+#define CISTPL_POWER_IAVG 4
+#define CISTPL_POWER_IPEAK 5
+#define CISTPL_POWER_IDOWN 6
+
+#define CISTPL_POWER_HIGHZ_OK 0x01
+#define CISTPL_POWER_HIGHZ_REQ 0x02
+
+typedef struct cistpl_power_t {
+ unsigned char present;
+ unsigned char flags;
+ unsigned int param[7];
+} cistpl_power_t;
+
+typedef struct cistpl_timing_t {
+ unsigned int wait, waitscale;
+ unsigned int ready, rdyscale;
+ unsigned int reserved, rsvscale;
+} cistpl_timing_t;
+
+#define CISTPL_IO_LINES_MASK 0x1f
+#define CISTPL_IO_8BIT 0x20
+#define CISTPL_IO_16BIT 0x40
+#define CISTPL_IO_RANGE 0x80
+
+#define CISTPL_IO_MAX_WIN 16
+
+typedef struct cistpl_io_t {
+ unsigned char flags;
+ unsigned char nwin;
+ struct {
+ unsigned int base;
+ unsigned int len;
+ } win[CISTPL_IO_MAX_WIN];
+} cistpl_io_t;
+
+typedef struct cistpl_irq_t {
+ unsigned int IRQInfo1;
+ unsigned int IRQInfo2;
+} cistpl_irq_t;
+
+#define CISTPL_MEM_MAX_WIN 8
+
+typedef struct cistpl_mem_t {
+ unsigned char flags;
+ unsigned char nwin;
+ struct {
+ unsigned int len;
+ unsigned int card_addr;
+ unsigned int host_addr;
+ } win[CISTPL_MEM_MAX_WIN];
+} cistpl_mem_t;
+
+#define CISTPL_CFTABLE_DEFAULT 0x0001
+#define CISTPL_CFTABLE_BVDS 0x0002
+#define CISTPL_CFTABLE_WP 0x0004
+#define CISTPL_CFTABLE_RDYBSY 0x0008
+#define CISTPL_CFTABLE_MWAIT 0x0010
+#define CISTPL_CFTABLE_AUDIO 0x0800
+#define CISTPL_CFTABLE_READONLY 0x1000
+#define CISTPL_CFTABLE_PWRDOWN 0x2000
+
+typedef struct cistpl_cftable_entry_t {
+ unsigned char index;
+ unsigned short flags;
+ unsigned char interface;
+ cistpl_power_t vcc, vpp1, vpp2;
+ cistpl_timing_t timing;
+ cistpl_io_t io;
+ cistpl_irq_t irq;
+ cistpl_mem_t mem;
+ unsigned char subtuples;
+} cistpl_cftable_entry_t;
+
+#define CISTPL_CFTABLE_MASTER 0x000100
+#define CISTPL_CFTABLE_INVALIDATE 0x000200
+#define CISTPL_CFTABLE_VGA_PALETTE 0x000400
+#define CISTPL_CFTABLE_PARITY 0x000800
+#define CISTPL_CFTABLE_WAIT 0x001000
+#define CISTPL_CFTABLE_SERR 0x002000
+#define CISTPL_CFTABLE_FAST_BACK 0x004000
+#define CISTPL_CFTABLE_BINARY_AUDIO 0x010000
+#define CISTPL_CFTABLE_PWM_AUDIO 0x020000
+
+typedef struct cistpl_cftable_entry_cb_t {
+ unsigned char index;
+ unsigned int flags;
+ cistpl_power_t vcc, vpp1, vpp2;
+ unsigned char io;
+ cistpl_irq_t irq;
+ unsigned char mem;
+ unsigned char subtuples;
+} cistpl_cftable_entry_cb_t;
+
+typedef struct cistpl_device_geo_t {
+ unsigned char ngeo;
+ struct {
+ unsigned char buswidth;
+ unsigned int erase_block;
+ unsigned int read_block;
+ unsigned int write_block;
+ unsigned int partition;
+ unsigned int interleave;
+ } geo[CISTPL_MAX_DEVICES];
+} cistpl_device_geo_t;
+
+typedef struct cistpl_vers_2_t {
+ unsigned char vers;
+ unsigned char comply;
+ unsigned short dindex;
+ unsigned char vspec8, vspec9;
+ unsigned char nhdr;
+ unsigned char vendor, info;
+ char str[244];
+} cistpl_vers_2_t;
+
+typedef struct cistpl_org_t {
+ unsigned char data_org;
+ char desc[30];
+} cistpl_org_t;
+
+#define CISTPL_ORG_FS 0x00
+#define CISTPL_ORG_APPSPEC 0x01
+#define CISTPL_ORG_XIP 0x02
+
+typedef struct cistpl_format_t {
+ unsigned char type;
+ unsigned char edc;
+ unsigned int offset;
+ unsigned int length;
+} cistpl_format_t;
+
+#define CISTPL_FORMAT_DISK 0x00
+#define CISTPL_FORMAT_MEM 0x01
+
+#define CISTPL_EDC_NONE 0x00
+#define CISTPL_EDC_CKSUM 0x01
+#define CISTPL_EDC_CRC 0x02
+#define CISTPL_EDC_PCC 0x03
+
+typedef union cisparse_t {
+ cistpl_device_t device;
+ cistpl_checksum_t checksum;
+ cistpl_longlink_t longlink;
+ cistpl_longlink_mfc_t longlink_mfc;
+ cistpl_vers_1_t version_1;
+ cistpl_altstr_t altstr;
+ cistpl_jedec_t jedec;
+ cistpl_manfid_t manfid;
+ cistpl_funcid_t funcid;
+ cistpl_funce_t funce;
+ cistpl_bar_t bar;
+ cistpl_config_t config;
+ cistpl_cftable_entry_t cftable_entry;
+ cistpl_cftable_entry_cb_t cftable_entry_cb;
+ cistpl_device_geo_t device_geo;
+ cistpl_vers_2_t vers_2;
+ cistpl_org_t org;
+ cistpl_format_t format;
+} cisparse_t;
+
+typedef struct tuple_t {
+ unsigned int Attributes;
+ unsigned char DesiredTuple;
+ unsigned int Flags; /* internal use */
+ unsigned int LinkOffset; /* internal use */
+ unsigned int CISOffset; /* internal use */
+ unsigned char TupleCode;
+ unsigned char TupleLink;
+ unsigned char TupleOffset;
+ unsigned char TupleDataMax;
+ unsigned char TupleDataLen;
+ unsigned char *TupleData;
+} tuple_t;
+
+/* Special unsigned char value */
+#define RETURN_FIRST_TUPLE 0xff
+
+/* Attributes for tuple calls */
+#define TUPLE_RETURN_LINK 0x01
+#define TUPLE_RETURN_COMMON 0x02
+
+/* For ValidateCIS */
+typedef struct cisinfo_t {
+ unsigned int Chains;
+} cisinfo_t;
+
+#define CISTPL_MAX_CIS_SIZE 0x200
+
+/* For ReplaceCIS */
+typedef struct cisdump_t {
+ unsigned int Length;
+ unsigned char Data[CISTPL_MAX_CIS_SIZE];
+} cisdump_t;
+
+typedef struct tuple_flags {
+ unsigned int link_space:4;
+ unsigned int has_link:1;
+ unsigned int mfc_fn:3;
+ unsigned int space:4;
+} tuple_flags;
+
+#define BIND_FN_ALL 0xff
+
+extern int read_out_cis (unsigned int socket_no, FILE *fd);
+extern int pcmcia_get_first_tuple(unsigned int function, tuple_t *tuple);
+extern int pcmcia_get_next_tuple(unsigned int function, tuple_t *tuple);
+extern int pcmcia_get_tuple_data(tuple_t *tuple);
+extern int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse);
+extern int parse_cis_one_socket(unsigned int socket_no);
+
+#endif /* LINUX_CISTPL_H */
diff --git a/src/dmidecode/config.h b/src/dmidecode/config.h
new file mode 100644
index 0000000..52fd3c3
--- /dev/null
+++ b/src/dmidecode/config.h
@@ -0,0 +1,29 @@
+/*
+ * Configuration
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* Default memory device file */
+#ifdef __BEOS__
+#define DEFAULT_MEM_DEV "/dev/misc/mem"
+#else
+#ifdef __sun
+#define DEFAULT_MEM_DEV "/dev/xsvc"
+#else
+#define DEFAULT_MEM_DEV "/dev/mem"
+#endif
+#endif
+
+/* Use mmap or not */
+#ifndef __BEOS__
+#define USE_MMAP
+#endif
+
+/* Use memory alignment workaround or not */
+#ifdef __ia64__
+#define ALIGNMENT_WORKAROUND
+#endif
+
+#endif
diff --git a/src/dmidecode/dmidecode.c b/src/dmidecode/dmidecode.c
new file mode 100644
index 0000000..5c542a6
--- /dev/null
+++ b/src/dmidecode/dmidecode.c
@@ -0,0 +1,382 @@
+/*
+ * Trimmed from DMI Decode http://savannah.nongnu.org/projects/dmidecode
+ *
+ * (C) 2000-2002 Alan Cox <alan@redhat.com>
+ * (C) 2002-2007 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open unpatent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "types.h"
+#include "util.h"
+#include "dmidecode.h"
+#include "dmioem.h"
+#include "../state.h"
+#include "../pci.h"
+
+static const char *out_of_spec = "<OUT OF SPEC>";
+static const char *bad_index = "<BAD INDEX>";
+
+/*
+ * Type-independant Stuff
+ */
+
+const char *dmi_string(struct dmi_header *dm, u8 s)
+{
+ char *bp=(char *)dm->data;
+ size_t i, len;
+
+ if(s==0)
+ return "Not Specified";
+
+ bp+=dm->length;
+ while(s>1 && *bp)
+ {
+ bp+=strlen(bp);
+ bp++;
+ s--;
+ }
+
+ if(!*bp)
+ return bad_index;
+
+ /* ASCII filtering */
+ len=strlen(bp);
+ for(i=0; i<len; i++)
+ if(bp[i]<32 || bp[i]==127)
+ bp[i]='.';
+
+ return bp;
+}
+
+static const char *dmi_slot_current_usage(u8 code)
+{
+ /* 3.3.10.3 */
+ static const char *usage[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Available",
+ "In Use" /* 0x04 */
+ };
+
+ if(code>=0x01 && code<=0x04)
+ return usage[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_slot_segment_bus_func(u16 code1, u8 code2, u8 code3, u8 type, const char *prefix)
+{
+ /* 3.3.10.8 */
+ if (!(code1==0xFFFF && code2==0xFF && code3==0xFF))
+ printf("%sSegment Group %u, Bus %u, Device %u, Function %u ",
+ prefix, code1, code2, (code3>>3)&0x1F, (code3&0x7));
+ switch(type)
+ {
+ case 0x06: /* PCI */
+ case 0x0E: /* PCI */
+ case 0x0F: /* AGP */
+ case 0x10: /* AGP */
+ case 0x11: /* AGP */
+ case 0x12: /* PCI-X */
+ case 0x13: /* AGP */
+ case 0xA5: /* PCI Express */
+ printf("\n");
+ break;
+ default:
+ if (code1 != 0xFF || code2 != 0xFF || code3 != 0xFF)
+ printf("%s\n", out_of_spec);
+ break;
+ }
+}
+
+static u8 onboard_device_type(u8 code, const char *prefix)
+{
+ /* 3.3.x.2 */
+ u8 e = (code & 0x80)>>7;
+ static const char *type[]={
+ "Other", /* 1 */
+ "Unknown",
+ "Video",
+ "SCSI Controller",
+ "Ethernet",
+ "Token Ring",
+ "Sound",
+ "PATA Controller",
+ "SATA Controller",
+ "SAS Controller" /* 0x0A */
+ };
+ code = code & 0x7F;
+ if(code>=0x01 && code<=0x0A) {
+ printf("%sStatus: %s\n", prefix, e?"Enabled":"Disabled");
+ printf("%sDevice Type: %s\n", prefix, type[code-0x01]);
+ }
+ else
+ printf("%sDevice Type: %s\n", prefix, out_of_spec);
+}
+
+/*
+ * Main
+ */
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+static void dmi_decode(struct dmi_header *h, u16 ver, const struct libbiosdevname_state *state)
+{
+ u8 *data=h->data;
+ int domain, bus, device, function;
+ struct pci_device *pdev;
+ switch(h->type)
+ {
+ case 9: /* 3.3.10 System Slots */
+ if (h->length >= 0x0E && h->length >=0x11) {
+ domain = WORD(data+0x0D);
+ bus = data[0x0F];
+ device = (data[0x10]>>3)&0x1F;
+ function = data[0x10] & 7;
+ if (! (domain == 0xFFFF && bus == 0xFF && data[0x10] == 0xFF)) {
+ device = (data[0x10]>>3)&0x1F;
+ function = data[0x10] & 7;
+ pdev = find_pci_dev_by_pci_addr(state, domain, bus, device, function);
+ if (pdev) {
+ pdev->physical_slot = WORD(data+0x09);
+ pdev->smbios_type = 0;
+ pdev->smbios_instance = 0;
+ }
+ }
+ }
+ break;
+ case 41: /* 3.3.xx Onboard Device Information */
+ domain = WORD(data+0x07);
+ bus = data[0x09];
+ device = (data[0xa]>>3) & 0x1F;
+ function = data[0xa] & 0x7;
+ pdev = find_pci_dev_by_pci_addr(state, domain, bus, device, function);
+ if (pdev) {
+ pdev->physical_slot = 0;
+ pdev->smbios_enabled = !!(data[0x05] & 0x80);
+ pdev->smbios_type = data[0x05] & 0x7F;
+ pdev->smbios_instance = data[0x06];
+ }
+ break;
+
+ default:
+ if(dmi_decode_oem(h, state))
+ break;
+ }
+}
+
+static void to_dmi_header(struct dmi_header *h, u8 *data)
+{
+ h->type=data[0];
+ h->length=data[1];
+ h->handle=WORD(data+2);
+ h->data=data;
+}
+
+static void dmi_table(u32 base, u16 len, u16 num, u16 ver, const char *devmem, const struct libbiosdevname_state *state)
+{
+ u8 *buf;
+ u8 *data;
+ int i=0;
+
+ if((buf=mem_chunk(base, len, devmem))==NULL)
+ {
+#ifndef USE_MMAP
+ printf("Table is unreachable, sorry. Try compiling dmidecode with -DUSE_MMAP.\n");
+#endif
+ return;
+ }
+
+ data=buf;
+ while(i<num && data+4<=buf+len) /* 4 is the length of an SMBIOS structure header */
+ {
+ u8 *next;
+ struct dmi_header h;
+
+ to_dmi_header(&h, data);
+
+ /*
+ * If a short entry is found (less than 4 bytes), not only it
+ * is invalid, but we cannot reliably locate the next entry.
+ * Better stop at this point, and let the user know his/her
+ * table is broken.
+ */
+ if(h.length<4)
+ break;
+
+ /* assign vendor for vendor-specific decodes later */
+ if(h.type==0 && h.length>=5)
+ dmi_set_vendor(dmi_string(&h, data[0x04]));
+
+ /* look for the next handle */
+ next=data+h.length;
+ while(next-buf+1<len && (next[0]!=0 || next[1]!=0))
+ next++;
+ next+=2;
+ if(next-buf<=len)
+ dmi_decode(&h, ver, state);
+
+ data=next;
+ i++;
+ }
+ free(buf);
+}
+
+
+static int smbios_decode(u8 *buf, const char *devmem, const struct libbiosdevname_state *state)
+{
+ if(checksum(buf, buf[0x05])
+ && memcmp(buf+0x10, "_DMI_", 5)==0
+ && checksum(buf+0x10, 0x0F))
+ {
+ dmi_table(DWORD(buf+0x18), WORD(buf+0x16), WORD(buf+0x1C),
+ (buf[0x06]<<8)+buf[0x07], devmem, state);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int legacy_decode(u8 *buf, const char *devmem, const struct libbiosdevname_state *state)
+{
+ if(checksum(buf, 0x0F))
+ {
+ dmi_table(DWORD(buf+0x08), WORD(buf+0x06), WORD(buf+0x0C),
+ ((buf[0x0E]&0xF0)<<4)+(buf[0x0E]&0x0F), devmem, state);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Probe for EFI interface
+ */
+#define EFI_NOT_FOUND (-1)
+#define EFI_NO_SMBIOS (-2)
+static int address_from_efi(size_t *address)
+{
+ FILE *efi_systab;
+ const char *filename;
+ char linebuf[64];
+ int ret;
+
+ *address=0; /* Prevent compiler warning */
+
+ /*
+ * Linux up to 2.6.6: /proc/efi/systab
+ * Linux 2.6.7 and up: /sys/firmware/efi/systab
+ */
+ if((efi_systab=fopen(filename="/sys/firmware/efi/systab", "r"))==NULL
+ && (efi_systab=fopen(filename="/proc/efi/systab", "r"))==NULL)
+ {
+ /* No EFI interface, fallback to memory scan */
+ return EFI_NOT_FOUND;
+ }
+ ret=EFI_NO_SMBIOS;
+ while((fgets(linebuf, sizeof(linebuf)-1, efi_systab))!=NULL)
+ {
+ char *addrp=strchr(linebuf, '=');
+ *(addrp++)='\0';
+ if(strcmp(linebuf, "SMBIOS")==0)
+ {
+ *address=strtoul(addrp, NULL, 0);
+ ret=0;
+ break;
+ }
+ }
+ if(fclose(efi_systab)!=0)
+ perror(filename);
+
+ if(ret==EFI_NO_SMBIOS)
+ fprintf(stderr, "%s: SMBIOS entry point missing\n", filename);
+ return ret;
+}
+
+static const char *devmem = "/dev/mem";
+
+int dmidecode_main(const struct libbiosdevname_state *state)
+{
+ int ret=0; /* Returned value */
+ int found=0;
+ size_t fp;
+ int efi;
+ u8 *buf;
+
+ /* First try EFI (ia64, Intel-based Mac) */
+ efi=address_from_efi(&fp);
+ switch(efi)
+ {
+ case EFI_NOT_FOUND:
+ goto memory_scan;
+ case EFI_NO_SMBIOS:
+ ret=1;
+ goto exit_free;
+ }
+
+ if((buf=mem_chunk(fp, 0x20, devmem))==NULL)
+ {
+ ret=1;
+ goto exit_free;
+ }
+
+ if(smbios_decode(buf, devmem, state))
+ found++;
+ goto done;
+
+memory_scan:
+ /* Fallback to memory scan (x86, x86_64) */
+ if((buf=mem_chunk(0xF0000, 0x10000, devmem))==NULL)
+ {
+ ret=1;
+ goto exit_free;
+ }
+
+ for(fp=0; fp<=0xFFF0; fp+=16)
+ {
+ if(memcmp(buf+fp, "_SM_", 4)==0 && fp<=0xFFE0)
+ {
+ if(smbios_decode(buf+fp, devmem, state))
+ {
+ found++;
+ fp+=16;
+ }
+ }
+ else if(memcmp(buf+fp, "_DMI_", 5)==0)
+ {
+ if (legacy_decode(buf+fp, devmem, state))
+ found++;
+ }
+ }
+
+done:
+ free(buf);
+
+
+exit_free:
+ return ret;
+}
diff --git a/src/dmidecode/dmidecode.h b/src/dmidecode/dmidecode.h
new file mode 100644
index 0000000..db8f7bd
--- /dev/null
+++ b/src/dmidecode/dmidecode.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the dmidecode project.
+ *
+ * (C) 2005-2007 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+struct dmi_header
+{
+ u8 type;
+ u8 length;
+ u16 handle;
+ u8 *data;
+};
+
+const char *dmi_string(struct dmi_header *dm, u8 s);
+
+struct dmi_embedded_device
+{
+ u8 type;
+ u8 instance;
+ u16 domain;
+ u8 bus;
+ u8 device;
+ u8 function;
+ const char *reference_designation;
+};
+
+struct dmi_addon_device
+{
+ u8 type;
+ u8 instance;
+ u16 domain;
+ u8 bus;
+ u8 device;
+ u8 function;
+ const char *reference_designation;
+};
+
+struct libbiosdevname_state;
+int dmidecode_main(const struct libbiosdevname_state *state);
+
diff --git a/src/dmidecode/dmioem.c b/src/dmidecode/dmioem.c
new file mode 100644
index 0000000..217c13a
--- /dev/null
+++ b/src/dmidecode/dmioem.c
@@ -0,0 +1,120 @@
+/*
+ * Decoding of OEM-specific entries
+ * This file is part of the dmidecode project.
+ *
+ * (C) 2007 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "types.h"
+#include "dmidecode.h"
+#include "dmioem.h"
+#include "../pci.h"
+
+/*
+ * Globals for vendor-specific decodes
+ */
+
+enum DMI_VENDORS { VENDOR_UNKNOWN, VENDOR_HP };
+
+static enum DMI_VENDORS dmi_vendor=VENDOR_UNKNOWN;
+
+/*
+ * Remember the system vendor for later use. We only actually store the
+ * value if we know how to decode at least one specific entry type for
+ * that vendor.
+ */
+void dmi_set_vendor(const char *s)
+{
+ if(strcmp(s, "HP")==0)
+ dmi_vendor=VENDOR_HP;
+}
+
+/*
+ * HP-specific data structures are decoded here.
+ *
+ * Code contributed by John Cagle.
+ */
+
+static int dmi_decode_hp(struct dmi_header *h, const struct libbiosdevname_state *state)
+{
+ u8 *data=h->data;
+ int nic, ptr;
+ u8 smbios_type = 0;
+ u8 bus, device, func;
+ struct pci_device *pdev;
+
+ switch(h->type)
+ {
+ case 209:
+ case 221:
+ /*
+ * Vendor Specific: HP ProLiant NIC MAC Information
+ *
+ * This prints the BIOS NIC number,
+ * PCI bus/device/function, and MAC address
+ */
+ if (h->type == 221)
+ smbios_type=0;
+ else
+ smbios_type=0x05;
+
+ nic=1;
+ ptr=4;
+ while(h->length>=ptr+8)
+ {
+ bus = data[ptr+1];
+ device = data[ptr]>>3;
+ func = data[ptr]&7;
+ pdev = find_pci_dev_by_pci_addr(state, 0, bus, device, func);
+ if (pdev) {
+ if((data[ptr]==0x00 && data[ptr+1]==0x00) ||
+ (data[ptr]==0xFF && data[ptr+1]==0xFF))
+ pdev->smbios_enabled = 0;
+ else {
+ pdev->smbios_enabled = 1;
+ pdev->smbios_type = smbios_type;
+ pdev->smbios_instance = nic;
+ }
+ }
+ nic++;
+ ptr+=8;
+ }
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Dispatch vendor-specific entries decoding
+ * Return 1 if decoding was successful, 0 otherwise
+ */
+int dmi_decode_oem(struct dmi_header *h, const struct libbiosdevname_state *state)
+{
+ switch(dmi_vendor)
+ {
+ case VENDOR_HP:
+ return dmi_decode_hp(h, state);
+ default:
+ return 0;
+ }
+}
diff --git a/src/dmidecode/dmioem.h b/src/dmidecode/dmioem.h
new file mode 100644
index 0000000..bacdab7
--- /dev/null
+++ b/src/dmidecode/dmioem.h
@@ -0,0 +1,26 @@
+/*
+ * Decoding of OEM-specific entries
+ * This file is part of the dmidecode project.
+ *
+ * (C) 2007 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "../state.h"
+struct dmi_header;
+
+void dmi_set_vendor(const char *s);
+int dmi_decode_oem(struct dmi_header *h, const struct libbiosdevname_state *state);
diff --git a/src/dmidecode/types.h b/src/dmidecode/types.h
new file mode 100644
index 0000000..12f3c65
--- /dev/null
+++ b/src/dmidecode/types.h
@@ -0,0 +1,27 @@
+#ifndef TYPES_H
+#define TYPES_H
+
+#include "config.h"
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef signed short i16;
+typedef unsigned int u32;
+
+#ifdef ALIGNMENT_WORKAROUND
+# ifdef BIGENDIAN
+# define WORD(x) (u16)((x)[1]+((x)[0]<<8))
+# define DWORD(x) (u32)((x)[3]+((x)[2]<<8)+((x)[1]<<16)+((x)[0]<<24))
+# define QWORD(x) (U64(DWORD(x+4), DWORD(x)))
+# else /* BIGENDIAN */
+# define WORD(x) (u16)((x)[0]+((x)[1]<<8))
+# define DWORD(x) (u32)((x)[0]+((x)[1]<<8)+((x)[2]<<16)+((x)[3]<<24))
+# define QWORD(x) (U64(DWORD(x), DWORD(x+4)))
+# endif /* BIGENDIAN */
+#else /* ALIGNMENT_WORKAROUND */
+#define WORD(x) (u16)(*(const u16 *)(x))
+#define DWORD(x) (u32)(*(const u32 *)(x))
+#define QWORD(x) (*(const u64 *)(x))
+#endif /* ALIGNMENT_WORKAROUND */
+
+#endif
diff --git a/src/dmidecode/util.c b/src/dmidecode/util.c
new file mode 100644
index 0000000..9eda714
--- /dev/null
+++ b/src/dmidecode/util.c
@@ -0,0 +1,165 @@
+/*
+ * Common "util" functions
+ * This file is part of the dmidecode project.
+ *
+ * (C) 2002-2005 Jean Delvare <khali@linux-fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open unpatent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "config.h"
+
+#ifdef USE_MMAP
+#include <sys/mman.h>
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *) -1)
+#endif /* !MAP_FAILED */
+#endif /* USE MMAP */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "types.h"
+#include "util.h"
+
+#ifndef USE_MMAP
+static int myread(int fd, u8 *buf, size_t count, const char *prefix)
+{
+ ssize_t r=1;
+ size_t r2=0;
+
+ while(r2!=count && r!=0)
+ {
+ r=read(fd, buf+r2, count-r2);
+ if(r==-1)
+ {
+ if(errno!=EINTR)
+ {
+ close(fd);
+ perror(prefix);
+ return -1;
+ }
+ }
+ else
+ r2+=r;
+ }
+
+ if(r2!=count)
+ {
+ close(fd);
+ fprintf(stderr, "%s: Unexpected end of file\n", prefix);
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+int checksum(const u8 *buf, size_t len)
+{
+ u8 sum=0;
+ size_t a;
+
+ for(a=0; a<len; a++)
+ sum+=buf[a];
+ return (sum==0);
+}
+
+/*
+ * Copy a physical memory chunk into a memory buffer.
+ * This function allocates memory.
+ */
+void *mem_chunk(size_t base, size_t len, const char *devmem)
+{
+ void *p;
+ int fd;
+#ifdef USE_MMAP
+ size_t mmoffset;
+ void *mmp;
+#endif
+
+ if((fd=open(devmem, O_RDONLY))==-1)
+ {
+ perror(devmem);
+ return NULL;
+ }
+
+ if((p=malloc(len))==NULL)
+ {
+ perror("malloc");
+ return NULL;
+ }
+
+#ifdef USE_MMAP
+#ifdef _SC_PAGESIZE
+ mmoffset=base%sysconf(_SC_PAGESIZE);
+#else
+ mmoffset=base%getpagesize();
+#endif /* _SC_PAGESIZE */
+ /*
+ * Please note that we don't use mmap() for performance reasons here,
+ * but to workaround problems many people encountered when trying
+ * to read from /dev/mem using regular read() calls.
+ */
+ mmp=mmap(0, mmoffset+len, PROT_READ, MAP_SHARED, fd, base-mmoffset);
+ if(mmp==MAP_FAILED)
+ {
+ fprintf(stderr, "%s: ", devmem);
+ perror("mmap");
+ free(p);
+ return NULL;
+ }
+
+ memcpy(p, (u8 *)mmp+mmoffset, len);
+
+ if(munmap(mmp, mmoffset+len)==-1)
+ {
+ fprintf(stderr, "%s: ", devmem);
+ perror("munmap");
+ }
+#else /* USE_MMAP */
+ if(lseek(fd, base, SEEK_SET)==-1)
+ {
+ fprintf(stderr, "%s: ", devmem);
+ perror("lseek");
+ free(p);
+ return NULL;
+ }
+
+ if(myread(fd, p, len, devmem)==-1)
+ {
+ free(p);
+ return NULL;
+ }
+#endif /* USE_MMAP */
+
+ if(close(fd)==-1)
+ perror(devmem);
+
+ return p;
+}
diff --git a/src/dmidecode/util.h b/src/dmidecode/util.h
new file mode 100644
index 0000000..b546f64
--- /dev/null
+++ b/src/dmidecode/util.h
@@ -0,0 +1,8 @@
+#include <sys/types.h>
+
+#include "types.h"
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+int checksum(const u8 *buf, size_t len);
+void *mem_chunk(size_t base, size_t len, const char *devmem);
diff --git a/src/eths.c b/src/eths.c
new file mode 100644
index 0000000..6ad5878
--- /dev/null
+++ b/src/eths.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+#define _GNU_SOURCE
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/sockios.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include "ethtool-util.h"
+#include "pci.h"
+#include "eths.h"
+#include "state.h"
+
+/* Display an Ethernet address in readable format. */
+char *pr_ether(char *buf, const int size, const unsigned char *s)
+{
+ snprintf(buf, size, "%02X:%02X:%02X:%02X:%02X:%02X",
+ (s[0] & 0377), (s[1] & 0377), (s[2] & 0377),
+ (s[3] & 0377), (s[4] & 0377), (s[5] & 0377)
+ );
+ return (buf);
+}
+
+static int eths_get_hwaddr(const char *devname, unsigned char *buf, int size, int *type)
+{
+ int fd, err;
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name));
+
+ /* Open control socket. */
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ perror("Cannot get control socket");
+ return 1;
+ }
+
+ err = ioctl(fd, SIOCGIFHWADDR, &ifr);
+ if (!err) {
+ memcpy(buf, ifr.ifr_hwaddr.sa_data, min(size, sizeof(ifr.ifr_hwaddr.sa_data)));
+ *type = ifr.ifr_hwaddr.sa_family;
+ }
+ else {
+ perror("SIOCGIFHWADDR failed");
+ }
+ close(fd);
+ return err;
+}
+
+static int eths_get_info(const char *devname, struct ethtool_drvinfo *drvinfo)
+{
+ int fd, err;
+ struct ifreq ifr;
+
+ /* Setup our control structures. */
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name));
+
+ /* Open control socket. */
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ perror("Cannot get control socket");
+ return 1;
+ }
+
+ drvinfo->cmd = ETHTOOL_GDRVINFO;
+ ifr.ifr_data = (caddr_t)drvinfo;
+ err = ioctl(fd, SIOCETHTOOL, &ifr);
+ close(fd);
+ return err;
+}
+
+static int eths_get_permaddr(const char *devname, unsigned char *buf, int size)
+{
+ int fd, err;
+ struct ifreq ifr;
+ struct ethtool_perm_addr *permaddr;
+ int s = sizeof(*permaddr) + MAX_ADDR_LEN;
+
+ permaddr = malloc(s);
+ if (!permaddr)
+ return 1;
+ memset(permaddr, 0, s);
+
+ /* Setup our control structures. */
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, devname, sizeof(ifr.ifr_name));
+
+
+
+ /* Open control socket. */
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ perror("Cannot get control socket");
+ return 1;
+ }
+
+ permaddr->cmd = ETHTOOL_GPERMADDR;
+ permaddr->size = MAX_ADDR_LEN;
+ ifr.ifr_data = (caddr_t)permaddr;
+ err = ioctl(fd, SIOCETHTOOL, &ifr);
+ if (err < 0) {
+ close(fd);
+ return err;
+ }
+ memcpy(buf, permaddr->data, min(permaddr->size, size));
+ free(permaddr);
+ close(fd);
+ return err;
+}
+
+static void fill_eth_dev(struct network_device *dev)
+{
+ int rc;
+ eths_get_hwaddr(dev->kernel_name, dev->dev_addr, sizeof(dev->dev_addr), &dev->arphrd_type);
+ eths_get_permaddr(dev->kernel_name, dev->perm_addr, sizeof(dev->perm_addr));
+ rc = eths_get_info(dev->kernel_name, &dev->drvinfo);
+ if (rc == 0)
+ dev->drvinfo_valid = 1;
+}
+
+void free_eths(struct libbiosdevname_state *state)
+{
+ struct network_device *pos, *next;
+ list_for_each_entry_safe(pos, next, &state->network_devices, node) {
+ list_del(&pos->node);
+ free(pos);
+ }
+}
+
+/* read_proc.c */
+extern int get_interfaces(struct libbiosdevname_state *state);
+
+void get_eths(struct libbiosdevname_state *state)
+{
+ struct network_device *pos;
+ get_interfaces(state);
+ list_for_each_entry(pos, &state->network_devices, node) {
+ fill_eth_dev(pos);
+ }
+}
+
+int zero_mac(const void *addr)
+{
+ char zero_mac[MAX_ADDR_LEN];
+ memset(zero_mac, 0, sizeof(zero_mac));
+ return !memcmp(zero_mac, addr, sizeof(zero_mac));
+}
+
+
+int unparse_network_device(char *buf, const int size, struct network_device *dev)
+{
+ char buffer[40];
+ char *s = buf;
+ s += snprintf(s, size-(s-buf), "Kernel name: %s\n", dev->kernel_name);
+ if (!zero_mac(dev->perm_addr))
+ s += snprintf(s, size-(s-buf), "Permanant MAC: %s\n", pr_ether(buffer, sizeof(buffer), dev->perm_addr));
+ s += snprintf(s, size-(s-buf), "Assigned MAC : %s\n", pr_ether(buffer, sizeof(buffer), dev->dev_addr));
+ if (drvinfo_valid(dev)) {
+ s += snprintf(s, size-(s-buf), "Driver: %s\n", dev->drvinfo.driver);
+ s += snprintf(s, size-(s-buf), "Driver version: %s\n", dev->drvinfo.version);
+ s += snprintf(s, size-(s-buf), "Firmware version: %s\n", dev->drvinfo.fw_version);
+ s += snprintf(s, size-(s-buf), "Bus Info: %s\n", dev->drvinfo.bus_info);
+ }
+ return (s-buf);
+};
+
+struct network_device * find_net_device_by_bus_info(struct libbiosdevname_state *state,
+ const char *bus_info)
+{
+ struct network_device *n;
+ list_for_each_entry(n, &state->network_devices, node) {
+ if (!strncmp(n->drvinfo.bus_info, bus_info, sizeof(n->drvinfo.bus_info)))
+ return n;
+ }
+ return NULL;
+}
+
+int is_ethernet(struct network_device *dev)
+{
+ int i;
+ int rc = 0;
+
+ /* FIXME: /sys/class/net/$kernel_name/device will be a symlink if there's underlying hardware,
+ * or not exist if it's virtual. Try using that if this isn't good enough already.
+ */
+
+ /* No bus means not visible to BIOS */
+ if (strncmp("N/A", dev->drvinfo.bus_info, sizeof(dev->drvinfo.bus_info)) == 0)
+ goto out;
+
+ const char *nonethernet_drivers[] = {
+ "bridge",
+ "tun",
+ };
+ for (i=0; i<sizeof(nonethernet_drivers)/sizeof(nonethernet_drivers[0]); i++) {
+ if (strncmp(dev->drvinfo.driver, nonethernet_drivers[i], sizeof(dev->drvinfo.driver)) == 0)
+ goto out;
+ }
+
+ rc = dev->arphrd_type == ARPHRD_ETHER;
+out:
+ return rc;
+}
diff --git a/src/eths.h b/src/eths.h
new file mode 100644
index 0000000..09a20ad
--- /dev/null
+++ b/src/eths.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+#ifndef __ETHS_H_INCLUDED
+#define __ETHS_H_INCLUDED
+
+#include <net/if.h>
+#include <net/if_arp.h>
+
+/* Bogus */
+#undef MAX_ADDR_LEN
+#define MAX_ADDR_LEN 32
+
+#include "list.h"
+#include "ethtool-util.h"
+#include "state.h"
+
+struct network_device {
+ struct list_head node;
+ char kernel_name[IFNAMSIZ]; /* ethN */
+ unsigned char perm_addr[MAX_ADDR_LEN];
+ unsigned char dev_addr[MAX_ADDR_LEN]; /* mutable MAC address, not unparsed */
+ struct ethtool_drvinfo drvinfo;
+ int drvinfo_valid;
+ int arphrd_type; /* e.g. ARPHDR_ETHER */
+ int hardware_claimed; /* true when recognized as PCI or PCMCIA and added to list of bios_devices */
+};
+
+extern void get_eths(struct libbiosdevname_state *state);
+extern void free_eths(struct libbiosdevname_state *state);
+extern int unparse_network_device(char *buf, const int size, struct network_device *dev);
+extern struct network_device * find_net_device_by_bus_info(struct libbiosdevname_state *state,
+ const char *bus_info);
+extern int is_ethernet(struct network_device *dev);
+
+extern int zero_mac(const void *addr);
+
+#define min(a,b) ((a) <= (b) ? (a) : (b))
+
+static inline void claim_netdev(struct network_device *dev)
+{
+ dev->hardware_claimed = 1;
+}
+
+static inline int netdev_is_claimed(const struct network_device *dev)
+{
+ return dev->hardware_claimed != 0;
+}
+
+static inline int drvinfo_valid(const struct network_device *dev)
+{
+ return dev->drvinfo_valid != 0;
+}
+
+#endif /* __ETHS_H_INCLUDED */
diff --git a/src/ethtool-copy.h b/src/ethtool-copy.h
new file mode 100644
index 0000000..2aec47c
--- /dev/null
+++ b/src/ethtool-copy.h
@@ -0,0 +1,375 @@
+/*
+ * ethtool.h: Defines for Linux ethtool.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
+ * Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Portions Copyright 2001 Sun Microsystems (thockin@sun.com)
+ * Portions Copyright 2002 Intel (eli.kupermann@intel.com,
+ * christopher.leech@intel.com,
+ * scott.feldman@intel.com)
+ */
+
+#ifndef _LINUX_ETHTOOL_H
+#define _LINUX_ETHTOOL_H
+
+
+/* This should work for both 32 and 64 bit userland. */
+struct ethtool_cmd {
+ u32 cmd;
+ u32 supported; /* Features this interface supports */
+ u32 advertising; /* Features this interface advertises */
+ u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */
+ u8 duplex; /* Duplex, half or full */
+ u8 port; /* Which connector port */
+ u8 phy_address;
+ u8 transceiver; /* Which tranceiver to use */
+ u8 autoneg; /* Enable or disable autonegotiation */
+ u32 maxtxpkt; /* Tx pkts before generating tx int */
+ u32 maxrxpkt; /* Rx pkts before generating rx int */
+ u32 reserved[4];
+};
+
+#define ETHTOOL_BUSINFO_LEN 32
+/* these strings are set to whatever the driver author decides... */
+struct ethtool_drvinfo {
+ u32 cmd;
+ char driver[32]; /* driver short name, "tulip", "eepro100" */
+ char version[32]; /* driver version string */
+ char fw_version[32]; /* firmware version string, if applicable */
+ char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
+ /* For PCI devices, use pci_dev->slot_name. */
+ char reserved1[32];
+ char reserved2[16];
+ u32 n_stats; /* number of u64's from ETHTOOL_GSTATS */
+ u32 testinfo_len;
+ u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */
+ u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */
+};
+
+#define SOPASS_MAX 6
+/* wake-on-lan settings */
+struct ethtool_wolinfo {
+ u32 cmd;
+ u32 supported;
+ u32 wolopts;
+ u8 sopass[SOPASS_MAX]; /* SecureOn(tm) password */
+};
+
+/* for passing single values */
+struct ethtool_value {
+ u32 cmd;
+ u32 data;
+};
+
+/* for passing big chunks of data */
+struct ethtool_regs {
+ u32 cmd;
+ u32 version; /* driver-specific, indicates different chips/revs */
+ u32 len; /* bytes */
+ u8 data[0];
+};
+
+/* for passing EEPROM chunks */
+struct ethtool_eeprom {
+ u32 cmd;
+ u32 magic;
+ u32 offset; /* in bytes */
+ u32 len; /* in bytes */
+ u8 data[0];
+};
+
+/* for configuring coalescing parameters of chip */
+struct ethtool_coalesce {
+ u32 cmd; /* ETHTOOL_{G,S}COALESCE */
+
+ /* How many usecs to delay an RX interrupt after
+ * a packet arrives. If 0, only rx_max_coalesced_frames
+ * is used.
+ */
+ u32 rx_coalesce_usecs;
+
+ /* How many packets to delay an RX interrupt after
+ * a packet arrives. If 0, only rx_coalesce_usecs is
+ * used. It is illegal to set both usecs and max frames
+ * to zero as this would cause RX interrupts to never be
+ * generated.
+ */
+ u32 rx_max_coalesced_frames;
+
+ /* Same as above two parameters, except that these values
+ * apply while an IRQ is being services by the host. Not
+ * all cards support this feature and the values are ignored
+ * in that case.
+ */
+ u32 rx_coalesce_usecs_irq;
+ u32 rx_max_coalesced_frames_irq;
+
+ /* How many usecs to delay a TX interrupt after
+ * a packet is sent. If 0, only tx_max_coalesced_frames
+ * is used.
+ */
+ u32 tx_coalesce_usecs;
+
+ /* How many packets to delay a TX interrupt after
+ * a packet is sent. If 0, only tx_coalesce_usecs is
+ * used. It is illegal to set both usecs and max frames
+ * to zero as this would cause TX interrupts to never be
+ * generated.
+ */
+ u32 tx_max_coalesced_frames;
+
+ /* Same as above two parameters, except that these values
+ * apply while an IRQ is being services by the host. Not
+ * all cards support this feature and the values are ignored
+ * in that case.
+ */
+ u32 tx_coalesce_usecs_irq;
+ u32 tx_max_coalesced_frames_irq;
+
+ /* How many usecs to delay in-memory statistics
+ * block updates. Some drivers do not have an in-memory
+ * statistic block, and in such cases this value is ignored.
+ * This value must not be zero.
+ */
+ u32 stats_block_coalesce_usecs;
+
+ /* Adaptive RX/TX coalescing is an algorithm implemented by
+ * some drivers to improve latency under low packet rates and
+ * improve throughput under high packet rates. Some drivers
+ * only implement one of RX or TX adaptive coalescing. Anything
+ * not implemented by the driver causes these values to be
+ * silently ignored.
+ */
+ u32 use_adaptive_rx_coalesce;
+ u32 use_adaptive_tx_coalesce;
+
+ /* When the packet rate (measured in packets per second)
+ * is below pkt_rate_low, the {rx,tx}_*_low parameters are
+ * used.
+ */
+ u32 pkt_rate_low;
+ u32 rx_coalesce_usecs_low;
+ u32 rx_max_coalesced_frames_low;
+ u32 tx_coalesce_usecs_low;
+ u32 tx_max_coalesced_frames_low;
+
+ /* When the packet rate is below pkt_rate_high but above
+ * pkt_rate_low (both measured in packets per second) the
+ * normal {rx,tx}_* coalescing parameters are used.
+ */
+
+ /* When the packet rate is (measured in packets per second)
+ * is above pkt_rate_high, the {rx,tx}_*_high parameters are
+ * used.
+ */
+ u32 pkt_rate_high;
+ u32 rx_coalesce_usecs_high;
+ u32 rx_max_coalesced_frames_high;
+ u32 tx_coalesce_usecs_high;
+ u32 tx_max_coalesced_frames_high;
+
+ /* How often to do adaptive coalescing packet rate sampling,
+ * measured in seconds. Must not be zero.
+ */
+ u32 rate_sample_interval;
+};
+
+/* for configuring RX/TX ring parameters */
+struct ethtool_ringparam {
+ u32 cmd; /* ETHTOOL_{G,S}RINGPARAM */
+
+ /* Read only attributes. These indicate the maximum number
+ * of pending RX/TX ring entries the driver will allow the
+ * user to set.
+ */
+ u32 rx_max_pending;
+ u32 rx_mini_max_pending;
+ u32 rx_jumbo_max_pending;
+ u32 tx_max_pending;
+
+ /* Values changeable by the user. The valid values are
+ * in the range 1 to the "*_max_pending" counterpart above.
+ */
+ u32 rx_pending;
+ u32 rx_mini_pending;
+ u32 rx_jumbo_pending;
+ u32 tx_pending;
+};
+
+/* for configuring link flow control parameters */
+struct ethtool_pauseparam {
+ u32 cmd; /* ETHTOOL_{G,S}PAUSEPARAM */
+
+ /* If the link is being auto-negotiated (via ethtool_cmd.autoneg
+ * being true) the user may set 'autonet' here non-zero to have the
+ * pause parameters be auto-negotiated too. In such a case, the
+ * {rx,tx}_pause values below determine what capabilities are
+ * advertised.
+ *
+ * If 'autoneg' is zero or the link is not being auto-negotiated,
+ * then {rx,tx}_pause force the driver to use/not-use pause
+ * flow control.
+ */
+ u32 autoneg;
+ u32 rx_pause;
+ u32 tx_pause;
+};
+
+#define ETH_GSTRING_LEN 32
+enum ethtool_stringset {
+ ETH_SS_TEST = 0,
+ ETH_SS_STATS,
+};
+
+/* for passing string sets for data tagging */
+struct ethtool_gstrings {
+ u32 cmd; /* ETHTOOL_GSTRINGS */
+ u32 string_set; /* string set id e.c. ETH_SS_TEST, etc*/
+ u32 len; /* number of strings in the string set */
+ u8 data[0];
+};
+
+enum ethtool_test_flags {
+ ETH_TEST_FL_OFFLINE = (1 << 0), /* online / offline */
+ ETH_TEST_FL_FAILED = (1 << 1), /* test passed / failed */
+};
+
+/* for requesting NIC test and getting results*/
+struct ethtool_test {
+ u32 cmd; /* ETHTOOL_TEST */
+ u32 flags; /* ETH_TEST_FL_xxx */
+ u32 reserved;
+ u32 len; /* result length, in number of u64 elements */
+ u64 data[0];
+};
+
+/* for dumping NIC-specific statistics */
+struct ethtool_stats {
+ u32 cmd; /* ETHTOOL_GSTATS */
+ u32 n_stats; /* number of u64's being returned */
+ u64 data[0];
+};
+
+struct ethtool_perm_addr {
+ u32 cmd; /* ETHTOOL_GPERMADDR */
+ u32 size;
+ u8 data[0];
+};
+
+
+
+/* CMDs currently supported */
+#define ETHTOOL_GSET 0x00000001 /* Get settings. */
+#define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */
+#define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */
+#define ETHTOOL_GREGS 0x00000004 /* Get NIC registers, privileged. */
+#define ETHTOOL_GWOL 0x00000005 /* Get wake-on-lan options. */
+#define ETHTOOL_SWOL 0x00000006 /* Set wake-on-lan options, priv. */
+#define ETHTOOL_GMSGLVL 0x00000007 /* Get driver message level */
+#define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level, priv. */
+#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation, priv. */
+#define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */
+#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */
+#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data, priv. */
+#define ETHTOOL_GCOALESCE 0x0000000e /* Get coalesce config */
+#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config, priv. */
+#define ETHTOOL_GRINGPARAM 0x00000010 /* Get ring parameters */
+#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters, priv. */
+#define ETHTOOL_GPAUSEPARAM 0x00000012 /* Get pause parameters */
+#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters, priv. */
+#define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */
+#define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */
+#define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */
+#define ETHTOOL_STXCSUM 0x00000017 /* Set TX hw csum enable (ethtool_value) */
+#define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable
+ * (ethtool_value) */
+#define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable
+ * (ethtool_value), priv. */
+#define ETHTOOL_TEST 0x0000001a /* execute NIC self-test, priv. */
+#define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */
+#define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */
+#define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */
+#define ETHTOOL_GTSO 0x0000001e /* Get TSO enable (ethtool_value) */
+#define ETHTOOL_STSO 0x0000001f /* Set TSO enable (ethtool_value) */
+#define ETHTOOL_GPERMADDR 0x00000020 /* Get permanent hardware address */
+
+/* compatibility with older code */
+#define SPARC_ETH_GSET ETHTOOL_GSET
+#define SPARC_ETH_SSET ETHTOOL_SSET
+
+/* Indicates what features are supported by the interface. */
+#define SUPPORTED_10baseT_Half (1 << 0)
+#define SUPPORTED_10baseT_Full (1 << 1)
+#define SUPPORTED_100baseT_Half (1 << 2)
+#define SUPPORTED_100baseT_Full (1 << 3)
+#define SUPPORTED_1000baseT_Half (1 << 4)
+#define SUPPORTED_1000baseT_Full (1 << 5)
+#define SUPPORTED_Autoneg (1 << 6)
+#define SUPPORTED_TP (1 << 7)
+#define SUPPORTED_AUI (1 << 8)
+#define SUPPORTED_MII (1 << 9)
+#define SUPPORTED_FIBRE (1 << 10)
+#define SUPPORTED_BNC (1 << 11)
+#define SUPPORTED_10000baseT_Full (1 << 12)
+
+/* Indicates what features are advertised by the interface. */
+#define ADVERTISED_10baseT_Half (1 << 0)
+#define ADVERTISED_10baseT_Full (1 << 1)
+#define ADVERTISED_100baseT_Half (1 << 2)
+#define ADVERTISED_100baseT_Full (1 << 3)
+#define ADVERTISED_1000baseT_Half (1 << 4)
+#define ADVERTISED_1000baseT_Full (1 << 5)
+#define ADVERTISED_Autoneg (1 << 6)
+#define ADVERTISED_TP (1 << 7)
+#define ADVERTISED_AUI (1 << 8)
+#define ADVERTISED_MII (1 << 9)
+#define ADVERTISED_FIBRE (1 << 10)
+#define ADVERTISED_BNC (1 << 11)
+#define ADVERTISED_10000baseT_Full (1 << 12)
+
+/* The following are all involved in forcing a particular link
+ * mode for the device for setting things. When getting the
+ * devices settings, these indicate the current mode and whether
+ * it was foced up into this mode or autonegotiated.
+ */
+
+/* The forced speed, 10Mb, 100Mb, gigabit, 10GbE. */
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define SPEED_10000 10000
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF 0x00
+#define DUPLEX_FULL 0x01
+
+/* Which connector port. */
+#define PORT_TP 0x00
+#define PORT_AUI 0x01
+#define PORT_MII 0x02
+#define PORT_FIBRE 0x03
+#define PORT_BNC 0x04
+
+/* Which tranceiver to use. */
+#define XCVR_INTERNAL 0x00
+#define XCVR_EXTERNAL 0x01
+#define XCVR_DUMMY1 0x02
+#define XCVR_DUMMY2 0x03
+#define XCVR_DUMMY3 0x04
+
+/* Enable or disable autonegotiation. If this is set to enable,
+ * the forced link modes above are completely ignored.
+ */
+#define AUTONEG_DISABLE 0x00
+#define AUTONEG_ENABLE 0x01
+
+/* Wake-On-Lan options. */
+#define WAKE_PHY (1 << 0)
+#define WAKE_UCAST (1 << 1)
+#define WAKE_MCAST (1 << 2)
+#define WAKE_BCAST (1 << 3)
+#define WAKE_ARP (1 << 4)
+#define WAKE_MAGIC (1 << 5)
+#define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */
+
+#endif /* _LINUX_ETHTOOL_H */
diff --git a/src/ethtool-util.h b/src/ethtool-util.h
new file mode 100644
index 0000000..a724343
--- /dev/null
+++ b/src/ethtool-util.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+#ifndef ETHTOOL_UTIL_H__
+#define ETHTOOL_UTIL_H__
+
+#include <pci/pci.h>
+
+#include <limits.h>
+#if ULONG_MAX > 0xffffffff
+typedef unsigned long u64;
+#else
+typedef unsigned long long u64;
+#endif
+
+#include "ethtool-copy.h"
+
+int ethtool_get_info(const char *devname, struct ethtool_drvinfo *drvinfo);
+
+#endif
diff --git a/src/libbiosdevname.h b/src/libbiosdevname.h
new file mode 100644
index 0000000..c106a04
--- /dev/null
+++ b/src/libbiosdevname.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+#ifndef LIBBIOSDEVNAME_H_INCLUDED
+#define LIBBIOSDEVNAME_H_INCLUDED
+
+enum sortroutine {
+ defaultsort,
+ nosort,
+};
+
+enum namingpolicy {
+ all_ethN,
+ all_names,
+ embedded_ethN_slots_names,
+ kernelnames,
+};
+
+extern void * setup_bios_devices(int sortroutine, int namingpolicy);
+extern void cleanup_bios_devices(void *cookie);
+extern char * kern_to_bios(void *cookie, const char *devname);
+extern void unparse_bios_devices(void *cookie);
+extern void unparse_bios_device_by_name(void *cookie, const char *name);
+
+
+
+#endif /* LIBBIOSDEVNAME_H_INCLUDED */
diff --git a/src/list.h b/src/list.h
new file mode 100644
index 0000000..6e9bfb8
--- /dev/null
+++ b/src/list.h
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ * Copied from the Linux kernel version 2.6.18, modfied for use here.
+ */
+
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include <stddef.h>
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+/*
+ * Simple doubly linked list implementation, from Linux kernel 2.6.18
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = NULL;
+ entry->prev = NULL;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ * Note: if 'old' was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+ struct list_head *new)
+{
+ list_replace(old, new);
+ INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+ return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); \
+ pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) \
+ for (; &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ n = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+#endif /* _LINUX_LIST_H */
diff --git a/src/naming_policy.c b/src/naming_policy.c
new file mode 100644
index 0000000..ffa33c8
--- /dev/null
+++ b/src/naming_policy.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2006, 2007 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+#include "bios_device.h"
+#include "naming_policy.h"
+#include "libbiosdevname.h"
+#include "state.h"
+
+static void use_all_ethN(const struct libbiosdevname_state *state)
+{
+ struct bios_device *dev;
+ unsigned int i=0;
+
+ list_for_each_entry(dev, &state->bios_devices, node) {
+ if (dev->netdev)
+ snprintf(dev->bios_name, sizeof(dev->bios_name), "eth%u", i++);
+ }
+}
+
+static void use_kernel_names(const struct libbiosdevname_state *state)
+{
+ struct bios_device *dev;
+
+ list_for_each_entry(dev, &state->bios_devices, node) {
+ if (dev->netdev)
+ strncpy(dev->bios_name, dev->netdev->kernel_name, sizeof(dev->bios_name)-1);
+ }
+}
+
+
+static void pcmcia_names(struct bios_device *dev)
+{
+ snprintf(dev->bios_name, sizeof(dev->bios_name), "eth_pccard_%u.%u",
+ dev->pcmciadev->socket, dev->pcmciadev->function);
+}
+
+static void use_embedded_ethN_slots_names(const struct libbiosdevname_state *state)
+{
+ struct bios_device *dev;
+ unsigned int i=0;
+
+ list_for_each_entry(dev, &state->bios_devices, node) {
+ if (is_pci(dev)) {
+ if (dev->pcidev->physical_slot == 0)
+ snprintf(dev->bios_name, sizeof(dev->bios_name), "eth%u", i++);
+ else if (dev->pcidev->physical_slot < INT_MAX)
+ snprintf(dev->bios_name, sizeof(dev->bios_name), "eth_s%d_%u",
+ dev->pcidev->physical_slot,
+ dev->pcidev->index_in_slot);
+ else if (dev->pcidev->physical_slot == INT_MAX)
+ snprintf(dev->bios_name, sizeof(dev->bios_name), "eth_unknown_%u", i++);
+ }
+ else if (is_pcmcia(dev))
+ pcmcia_names(dev);
+ }
+}
+
+static void use_all_names(const struct libbiosdevname_state *state)
+{
+ struct bios_device *dev;
+ unsigned int i=0;
+
+ list_for_each_entry(dev, &state->bios_devices, node) {
+ if (is_pci(dev)) {
+ if (dev->pcidev->physical_slot < INT_MAX)
+ snprintf(dev->bios_name, sizeof(dev->bios_name), "eth_s%d_%u",
+ dev->pcidev->physical_slot,
+ dev->pcidev->index_in_slot);
+ else
+ snprintf(dev->bios_name, sizeof(dev->bios_name), "eth_unknown_%u", i++);
+ }
+ else if (is_pcmcia(dev))
+ pcmcia_names(dev);
+ }
+}
+
+int assign_bios_network_names(const struct libbiosdevname_state *state, int sort, int policy)
+{
+ if (sort != nosort) {
+ switch (policy) {
+ case all_ethN:
+ use_all_ethN(state);
+ break;
+ case embedded_ethN_slots_names:
+ use_embedded_ethN_slots_names(state);
+ break;
+ case all_names:
+ use_all_names(state);
+ break;
+ case kernelnames:
+ default:
+ use_kernel_names(state);
+ break;
+ }
+ }
+ else
+ use_kernel_names(state);
+
+ return 0;
+}
+
diff --git a/src/naming_policy.h b/src/naming_policy.h
new file mode 100644
index 0000000..9d61b42
--- /dev/null
+++ b/src/naming_policy.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+#ifndef NAMING_POLICY_H_INCLUDED
+#define NAMING_POLICY_H_INCLUDED
+
+#include "state.h"
+
+extern int assign_bios_network_names(const struct libbiosdevname_state *state,
+ int sortroutine, int namingpolicy);
+
+#endif /* NAMING_POLICY_H_INCLUDED */
diff --git a/src/parse_cis.c b/src/parse_cis.c
new file mode 100644
index 0000000..b03d2dc
--- /dev/null
+++ b/src/parse_cis.c
@@ -0,0 +1,882 @@
+/*
+ * 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 <endian.h>
+#include <byteswap.h>
+
+#include "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])
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define le32_to_cpu(value) bswap_32(value)
+# define le16_to_cpu(value) bswap_16(value)
+#else
+# define le32_to_cpu(value) (value)
+# define le16_to_cpu(value) (value)
+#endif
+
+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/pci.c b/src/pci.c
new file mode 100644
index 0000000..c5ae788
--- /dev/null
+++ b/src/pci.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "pirq.h"
+#include <pci/pci.h>
+#include "pci.h"
+
+static int
+is_parent_bridge(struct pci_dev *p, unsigned int target_bus)
+{
+ unsigned int primary, secondary;
+
+ if ( (pci_read_word(p, PCI_HEADER_TYPE) & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ return 0;
+
+ primary=pci_read_byte(p, PCI_PRIMARY_BUS);
+ secondary=pci_read_byte(p, PCI_SECONDARY_BUS);
+
+ if (secondary != target_bus)
+ return 0;
+
+ return 1;
+}
+
+static struct pci_dev *
+find_parent(struct pci_access *pacc, unsigned int target_bus)
+{
+ struct pci_dev *p;
+
+ for (p=pacc->devices; p; p=p->next)
+ if (is_parent_bridge(p, target_bus))
+ return p;
+
+ return NULL;
+}
+
+/*
+ * Check our parent in case the device itself isn't listed
+ * in the PCI IRQ Routing Table. This has a problem, as
+ * our parent bridge on a card may not be included
+ * in the $PIR table. In that case, it falls back to "unknown".
+ */
+static int pci_dev_to_slot(struct routing_table *table, struct pci_access *pacc, struct pci_dev *p)
+{
+ int rc;
+ rc = pirq_pci_dev_to_slot(table, p->bus, p->dev);
+ if (rc == INT_MAX) {
+ p = find_parent(pacc, p->bus);
+ if (p)
+ rc = pirq_pci_dev_to_slot(table, p->bus, p->dev);
+ }
+ return rc;
+}
+
+static void add_pci_dev(struct libbiosdevname_state *state,
+ struct routing_table *table,
+ struct pci_access *pacc, struct pci_dev *p)
+{
+ struct pci_device *dev;
+ dev = malloc(sizeof(*dev));
+ if (!dev) {
+ fprintf(stderr, "out of memory\n");
+ return;
+ }
+ memset(dev, 0, sizeof(*dev));
+ INIT_LIST_HEAD(&dev->node);
+ memcpy(&dev->pci_dev, p, sizeof(*p)); /* This doesn't allow us to call PCI functions though */
+ dev->physical_slot = pci_dev_to_slot(table, pacc, p);
+ dev->class = pci_read_word(p, PCI_CLASS_DEVICE);
+ list_add(&dev->node, &state->pci_devices);
+}
+
+void free_pci_devices(struct libbiosdevname_state *state)
+{
+ struct pci_device *pos, *next;
+ list_for_each_entry_safe(pos, next, &state->pci_devices, node) {
+ list_del(&pos->node);
+ free(pos);
+ }
+}
+
+int get_pci_devices(struct libbiosdevname_state *state)
+{
+ struct pci_access *pacc;
+ struct pci_dev *p;
+ struct pci_device *dev;
+ struct routing_table *table;
+ int rc=0;
+
+ pacc = pci_alloc();
+ if (!pacc)
+ return rc;
+
+ pci_init(pacc);
+ pci_scan_bus(pacc);
+
+ table = pirq_alloc_read_table();
+ if (!table)
+ goto out;
+
+ for (p=pacc->devices; p; p=p->next) {
+ dev = find_dev_by_pci(state, p);
+ if (!dev)
+ add_pci_dev(state, table, pacc, p);
+ }
+
+ pirq_free_table(table);
+out:
+ pci_cleanup(pacc);
+ return rc;
+}
+
+
+static int parse_pci_name(const char *s, int *domain, int *bus, int *dev, int *func)
+{
+ int err;
+/* The domain part was added in 2.6 kernels. Test for that first. */
+ err = sscanf(s, "%x:%2x:%2x.%x", domain, bus, dev, func);
+ if (err != 4) {
+ err = sscanf(s, "%2x:%2x.%x", bus, dev, func);
+ if (err != 3) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int unparse_pci_name(char *buf, int size, const struct pci_dev *pdev)
+{
+ return snprintf(buf, size, "%04x:%02x:%02x.%d",
+ pci_domain_nr(pdev), pdev->bus, pdev->dev, pdev->func);
+}
+
+static int unparse_location(char *buf, const int size, const int location)
+{
+ char *s = buf;
+ if (location == 0)
+ s += snprintf(s, size-(s-buf), "embedded");
+ else if (location == INT_MAX)
+ s += snprintf(s, size-(s-buf), "unknown");
+ else if (location > 0)
+ s += snprintf(s, size-(s-buf), "%u", location);
+ else
+ s += snprintf(s, size-(s-buf), "unknown");
+ return (s-buf);
+}
+
+static int unparse_smbios_type41_type(char *buf, const int size, const int type)
+{
+ char *s = buf;
+ const char *msg[] = {"Other",
+ "Unknown",
+ "Video",
+ "SCSI Controller",
+ "Ethernet",
+ "Token Ring",
+ "Sound",
+ "PATA Controller",
+ "SATA Controller",
+ "SAS Controller",
+ };
+ if (type > 0 && type <= sizeof(msg))
+ s += snprintf(s, size-(s-buf), "%s\n", msg[type-1]);
+ else
+ s += snprintf(s, size-(s-buf), "<OUT OF SPEC>\n");
+ return (s-buf);
+}
+
+
+int unparse_pci_device(char *buf, const int size, const struct pci_device *p)
+{
+ char *s = buf;
+ s += snprintf(s, size-(s-buf), "PCI name : ");
+ s += unparse_pci_name(s, size-(s-buf), &p->pci_dev);
+ s += snprintf(s, size-(s-buf), "\n");
+ s += snprintf(s, size-(s-buf), "PCI Slot : ");
+ s += unparse_location(s, size-(s-buf), p->physical_slot);
+ s += snprintf(s, size-(s-buf), "\n");
+ if (p->smbios_type) {
+ s += snprintf(s, size-(s-buf), "SMBIOS Device Type: ");
+ s += unparse_smbios_type41_type(s, size-(s-buf), p->smbios_type);
+ s += snprintf(s, size-(s-buf), "SMBIOS Instance: %u\n", p->smbios_instance);
+ s += snprintf(s, size-(s-buf), "SMBIOS Enabled: %s\n", p->smbios_instance?"True":"False");
+ }
+ return (s-buf);
+}
+
+static int is_same_pci(const struct pci_dev *a, const struct pci_dev *b)
+{
+ if (pci_domain_nr(a) == pci_domain_nr(b) &&
+ a->bus == b->bus &&
+ a->dev == b->dev &&
+ a->func == b->func)
+ return 1;
+ return 0;
+}
+
+struct pci_device * find_dev_by_pci(const struct libbiosdevname_state *state,
+ const struct pci_dev *p)
+{
+ struct pci_device *dev;
+ list_for_each_entry(dev, &state->pci_devices, node) {
+ if (is_same_pci(p, &dev->pci_dev))
+ return dev;
+ }
+ return NULL;
+}
+
+struct pci_device * find_pci_dev_by_pci_addr(const struct libbiosdevname_state *state,
+ const int domain, const int bus, const int device, const int func)
+{
+ struct pci_device *dev;
+ struct pci_device p;
+
+#ifdef HAVE_STRUCT_PCI_DEV_DOMAIN
+ p.pci_dev.domain = domain;
+#endif
+ p.pci_dev.bus = bus;
+ p.pci_dev.dev = device;
+ p.pci_dev.func = func;
+
+ list_for_each_entry(dev, &state->pci_devices, node) {
+ if (is_same_pci(&p.pci_dev, &dev->pci_dev))
+ return dev;
+ }
+ return NULL;
+}
+
+struct pci_device * find_dev_by_pci_name(const struct libbiosdevname_state *state,
+ const char *s)
+{
+ int domain=0, bus=0, device=0, func=0;
+ if (parse_pci_name(s, &domain, &bus, &device, &func))
+ return NULL;
+
+ return find_pci_dev_by_pci_addr(state, domain, bus, device, func);
+}
diff --git a/src/pci.h b/src/pci.h
new file mode 100644
index 0000000..fbd195a
--- /dev/null
+++ b/src/pci.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+
+#ifndef PCI_H_INCLUDED
+#define PCI_H_INCLUDED
+
+#include <pci/pci.h>
+#include "list.h"
+#include "state.h"
+#include "config.h"
+
+struct pci_device {
+ struct list_head node;
+ struct pci_dev pci_dev;
+ int physical_slot;
+ unsigned int index_in_slot;
+ unsigned short int class;
+ unsigned char smbios_type;
+ unsigned char smbios_instance;
+ unsigned char smbios_enabled;
+};
+
+extern int get_pci_devices(struct libbiosdevname_state *state);
+extern void free_pci_devices(struct libbiosdevname_state *state);
+
+extern struct pci_device * find_dev_by_pci(const struct libbiosdevname_state *state, const struct pci_dev *p);
+extern struct pci_device * find_pci_dev_by_pci_addr(const struct libbiosdevname_state *state, const int domain, const int bus, const int device, const int func);
+extern struct pci_device * find_dev_by_pci_name(const struct libbiosdevname_state *state, const char *s);
+extern int unparse_pci_device(char *buf, const int size, const struct pci_device *p);
+extern int unparse_pci_name(char *buf, int size, const struct pci_dev *pdev);
+
+static inline int is_pci_network(struct pci_device *dev)
+{
+ return (dev->class & 0xFF00) == 0x0200;
+}
+
+#ifdef HAVE_STRUCT_PCI_DEV_DOMAIN
+static inline int pci_domain_nr(const struct pci_dev *dev)
+{
+ return dev->domain;
+}
+#else
+static inline int pci_domain_nr(const struct pci_dev *dev)
+{
+ return 0;
+}
+#endif
+
+
+#endif /* PCI_H_INCLUDED */
diff --git a/src/pcmcia.c b/src/pcmcia.c
new file mode 100644
index 0000000..a2c2ff5
--- /dev/null
+++ b/src/pcmcia.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ *
+ * Partly based on tools from pcmciautils-014, which states
+ * in its header:
+ * (C) 2004-2005 Dominik Brodowski <linux@brodo.de>
+ *
+ * Partly based on cardctl.c from pcmcia-cs-3.2.7/cardmgr/, which states
+ * in its header:
+ *
+ * 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.
+ *
+ * Licensed under the terms of the GNU GPL License version 2.
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <libgen.h>
+#include <linux/limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
+#include "state.h"
+#include "pcmcia.h"
+
+#define MAX_SOCKET 8
+
+static unsigned char get_lan_tech(cistpl_funce_t *funce)
+{
+ cistpl_lan_tech_t *t;
+
+ if (funce->type == CISTPL_FUNCE_LAN_TECH) {
+ t = (cistpl_lan_tech_t *)(funce->data);
+ return t->tech;
+ }
+ return 0;
+}
+
+static unsigned char parse_tuple_for_network(tuple_t *tuple, cisparse_t *parse)
+{
+ static int func = 0;
+ unsigned char rc = 0;
+
+ switch (tuple->TupleCode) {
+ case CISTPL_FUNCID:
+ func = parse->funcid.func;
+ break;
+ case CISTPL_FUNCE:
+ if (func == CISTPL_FUNCID_NETWORK)
+ rc = get_lan_tech(&parse->funce);
+ break;
+ default:
+ break;
+ }
+ return rc;
+}
+
+int get_network_type(unsigned int socket_no, unsigned char *network_type)
+{
+ int ret = 0;
+ tuple_t tuple;
+ unsigned char buf[256];
+ cisparse_t parse;
+ unsigned char n;
+
+ memset(&tuple, 0, sizeof(tuple_t));
+
+ ret = read_out_cis(socket_no, NULL);
+ if (ret)
+ return (ret);
+
+ 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);
+
+ ret = pccard_parse_tuple(&tuple, &parse);
+ if (ret == 0) {
+ n = parse_tuple_for_network(&tuple, &parse);
+ if (n) {
+ *network_type = n;
+ break;
+ }
+ }
+
+ ret = pcmcia_get_next_tuple(BIND_FN_ALL, &tuple);
+ if (ret)
+ break;
+ }
+
+ return (ret);
+}
+
+/**
+ * sysfs_path_is_file: Check if the path supplied points to a file
+ * @path: path to validate
+ * Returns 0 if path points to file, 1 otherwise
+ * Copied from sysfsutils-2.1.0 (which is LGPL2.1 or later), relicensed GPLv2 for use here.
+ */
+static int sysfs_path_is_file(const char *path)
+{
+ struct stat astats;
+
+ if (!path) {
+ errno = EINVAL;
+ return 1;
+ }
+ if ((lstat(path, &astats)) != 0) {
+ return 1;
+ }
+ if (S_ISREG(astats.st_mode))
+ return 0;
+
+ return 1;
+}
+
+
+
+static int pccardctl_socket_exists(unsigned long socket_no)
+{
+ char file[PATH_MAX];
+
+ snprintf(file, sizeof(file),
+ "/sys/class/pcmcia_socket/pcmcia_socket%lu/card_insert",
+ socket_no);
+
+ return (!(sysfs_path_is_file(file)));
+}
+
+static int read_out_file(char * file, char **output)
+{
+ int ret;
+ char *result = NULL;
+ int fd;
+ unsigned long resultsize = 0;
+ ssize_t length = 0;
+
+
+ *output = NULL;
+
+ resultsize = getpagesize() + 1;
+ result = malloc(resultsize);
+ if (!result)
+ return -ENOMEM;
+ memset(result, 0, resultsize);
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0) {
+ ret = -1;
+ goto free_out;
+ }
+
+ length = read(fd, result, resultsize-1);
+ if (length < 0) {
+ close(fd);
+ ret = -1;
+ goto free_out;
+ }
+ result[length] = '\0';
+ if (result[length-1] == '\n')
+ result[length-1] = '\0';
+ *output = result;
+ ret = 0;
+ goto out;
+free_out:
+ free(result);
+out:
+ return ret;
+}
+
+static int pccardctl_get_one_f(unsigned long socket_no, unsigned int dev, const char *in_file, unsigned int *result)
+{
+ char *value;
+ char file[PATH_MAX];
+ int ret;
+
+ snprintf(file, sizeof(file), "/sys/bus/pcmcia/devices/%lu.%u/%s",
+ socket_no, dev, in_file);
+ ret = read_out_file(file, &value);
+ if (ret || !value)
+ return -EINVAL;
+
+ if (sscanf(value, "0x%X", result) != 1)
+ return -EIO;
+ return 0;
+}
+
+static int pccardctl_get_one(unsigned long socket_no, const char *in_file, unsigned int *result)
+{
+ return pccardctl_get_one_f(socket_no, 0, in_file, result);
+}
+
+static int alloc_pcmcia(struct libbiosdevname_state *state,
+ unsigned long int socket_no)
+{
+ char file[PATH_MAX];
+ char dev_s[PATH_MAX];
+ char *dev;
+ int ret, i;
+ int rc;
+
+ if (!pccardctl_socket_exists(socket_no))
+ return -ENODEV;
+
+ snprintf(file, sizeof(file), "/sys/class/pcmcia_socket/pcmcia_socket%lu/device", socket_no);
+ ret = readlink(file, dev_s, sizeof(dev_s) - 1);
+ if (ret > 0) {
+ dev_s[ret]='\0';
+ dev = basename(dev_s);
+ } else {
+ snprintf(file, sizeof(file), "/sys/class/pcmcia_socket/pcmcia_socket%lu", socket_no);
+ ret = readlink(file, dev_s, sizeof(dev_s) - 1);
+ if (ret <= 0)
+ return -ENODEV;
+ dev_s[ret]='\0';
+ dev = basename(dirname(dev_s));
+ }
+
+ for (i=0; i<4; i++) {
+ unsigned int function;
+ unsigned int function_id;
+ struct pcmcia_device *pdev;
+ unsigned char network_type = 0;
+
+ if (pccardctl_get_one_f(socket_no, i, "function", &function))
+ continue;
+
+ pdev = malloc(sizeof(*pdev));
+ if (!pdev)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&pdev->node);
+ pdev->socket = socket_no;
+ pdev->function = i;
+ if (!pccardctl_get_one(socket_no, "func_id", &function_id))
+ pdev->function_id = function_id;
+
+ rc = get_network_type(socket_no, &network_type);
+ if (!rc)
+ pdev->network_type = network_type;
+
+ list_add_tail(&pdev->node, &state->pcmcia_devices);
+ }
+ return 0;
+}
+
+void free_pcmcia_devices(struct libbiosdevname_state *state)
+{
+ struct pcmcia_device *pos, *next;
+ list_for_each_entry_safe(pos, next, &state->pcmcia_devices, node) {
+ list_del(&pos->node);
+ free(pos);
+ }
+}
+
+int get_pcmcia_devices(struct libbiosdevname_state *state)
+{
+ unsigned long int socket_no;
+ for (socket_no = 0; socket_no < MAX_SOCKET; socket_no++) {
+ alloc_pcmcia(state, socket_no);
+ }
+ return 0;
+}
+
+int unparse_pcmcia_name(char *buf, int size, const struct pcmcia_device *pdev)
+{
+ return snprintf(buf, size, "%u.%u", pdev->socket, pdev->function);
+}
+
+int unparse_pcmcia_device(char *buf, const int size, const struct pcmcia_device *p)
+{
+ char *s = buf;
+ s += snprintf(s, size-(s-buf), "PCMCIA location : ");
+ s += unparse_pcmcia_name(s, size-(s-buf), p);
+ s += snprintf(s, size-(s-buf), "\n");
+ return (s-buf);
+}
+
diff --git a/src/pcmcia.h b/src/pcmcia.h
new file mode 100644
index 0000000..a8aea93
--- /dev/null
+++ b/src/pcmcia.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+
+#ifndef PCMCIA_H_INCLUDED
+#define PCMCIA_H_INCLUDED
+
+#include "list.h"
+#include "cistpl.h"
+#include "state.h"
+
+struct pcmcia_device {
+ struct list_head node;
+ unsigned int socket;
+ unsigned int function;
+ int function_id;
+ int network_type;
+};
+
+extern int get_pcmcia_devices(struct libbiosdevname_state *state);
+extern void free_pcmcia_devices(struct libbiosdevname_state *state);
+extern int unparse_pcmcia_name(char *buf, int size, const struct pcmcia_device *pdev);
+extern int unparse_pcmcia_device(char *buf, const int size, const struct pcmcia_device *p);
+
+static inline int is_pcmcia_network(struct pcmcia_device *dev)
+{
+ return dev->function_id == CISTPL_FUNCID_NETWORK &&
+ (dev->network_type == CISTPL_LAN_TECH_ETHERNET ||
+ dev->network_type == CISTPL_LAN_TECH_WIRELESS);
+}
+
+
+#endif /* PCMCIA_H_INCLUDED */
diff --git a/src/pirq.c b/src/pirq.c
new file mode 100644
index 0000000..a342ac3
--- /dev/null
+++ b/src/pirq.c
@@ -0,0 +1,150 @@
+/*
+ * PCI IRQ Routing Table dumper
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ *
+ * Based on the description of said table found at
+ * http://www.microsoft.com/hwdev/busbios/pciirq.htm
+ * Licensed under the GNU General Public license, version 2.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include <sys/mman.h>
+#include "pirq.h"
+
+/* If unknown, use INT_MAX so they get sorted last */
+int pirq_pci_dev_to_slot(struct routing_table *table, int bus, int dev)
+{
+ int i, num_slots;
+ struct slot_entry *slot;
+
+ if (!table)
+ return INT_MAX;
+
+ num_slots = (table->size - 32) / sizeof(*slot);
+ for (i=0; i<num_slots; i++) {
+ slot = &table->slot[i];
+ if (slot->bus == bus &&
+ PCI_DEVICE(slot->device) == dev)
+ return slot->slot;
+ }
+ return INT_MAX;
+}
+
+
+
+struct routing_table * pirq_alloc_read_table()
+{
+ struct routing_table *table = NULL;
+ uint16_t size = 0;
+ uint8_t checksum = 0;
+ int i;
+ void *mem;
+ off_t offset=0L;
+ int fd=open("/dev/mem", O_RDONLY);
+
+ if(fd==-1)
+ {
+ perror("open(/dev/mem)");
+ return NULL;
+ }
+
+ mem = mmap(0, 64*1024, PROT_READ, MAP_SHARED, fd, 0xF0000L);
+ if (!mem) {
+ perror("mmap(/dev/mem)");
+ goto out;
+ }
+
+ while( offset < 0xFFFF)
+ {
+ if(memcmp(mem+offset, "$PIR", 4)==0)
+ {
+ table = (struct routing_table *)(mem+offset);
+ size = table->size;
+ /* quick sanity checks */
+ /* Version must be 1.0 */
+ if (! (table->version >> 8)==1 &&
+ (table->version && 0xFF) == 0) break;
+
+ table = malloc(size);
+ if (!table) break;
+
+ memcpy(table, mem+offset, size);
+ for (i=0; i<size; i++)
+ checksum +=*(((uint8_t *)table)+i);
+ if (checksum) {
+ free (table);
+ table = NULL;
+ }
+ break;
+ }
+ offset += 16;
+ }
+ munmap(mem, 64*1024);
+out:
+ close(fd);
+ return table;
+}
+
+void pirq_free_table(struct routing_table *table)
+{
+ free(table);
+}
+
+
+#ifdef UNIT_TEST_PIRQ
+
+static void
+pirq_unparse_slot(struct slot_entry *slot)
+{
+ printf("Slot %d: PCI %x:%x. ",
+ slot->slot, slot->bus, PCI_DEVICE(slot->device));
+ printf("INTA link %x irq %x ", slot->inta_link, slot->inta_irq);
+ printf("B link %x irq %x ", slot->intb_link, slot->intb_irq);
+ printf("C link %x irq %x ", slot->intc_link, slot->intc_irq);
+ printf("D link %x irq %x ", slot->intd_link, slot->intd_irq);
+ printf("\n");
+}
+
+static void
+pirq_unparse_routing_table(struct routing_table *table)
+{
+ int i, num_slots;
+ struct slot_entry *slot;
+ char buf[5]; buf[4] = 0;
+ memcpy(buf, &table->signature, 4);
+
+ printf("PCI IRQ Routing Table\n");
+ printf("Signature: %s\n", buf);
+ printf("Version : %x\n", table->version);
+ printf("Size : %xh\n", table->size);
+ printf("Bus : %x\n", table->router_bus);
+ printf("DevFn : %x\n", table->router_devfn);
+ printf("Exclusive IRQs : %x\n", table->exclusive_irqs);
+ printf("Compatable Router: %x\n", table->compatable_router);
+
+ num_slots = (table->size - 32) / sizeof(*slot);
+ slot = &table->slot[0];
+ for (i=0; i<num_slots; i++) {
+ pirq_unparse_slot(&slot[i]);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ struct routing_table *table;
+ table = pirq_alloc_read_table();
+ if (!table)
+ return 1;
+ pirq_unparse_routing_table(table);
+ pirq_free_table(table);
+ return 0;
+}
+
+#endif
diff --git a/src/pirq.h b/src/pirq.h
new file mode 100644
index 0000000..293b81d
--- /dev/null
+++ b/src/pirq.h
@@ -0,0 +1,58 @@
+#ifndef PIRQ_H_INCLUDED
+#define PIRQ_H_INCLUDED
+
+/*
+ * PCI IRQ Routing Table dumper
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ *
+ * Based on the description of said table found at
+ * http://www.microsoft.com/hwdev/busbios/pciirq.htm
+ * Licensed under the GNU General Public license, version 2.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef unsigned char __u8;
+typedef unsigned short int __u16;
+typedef unsigned int __u32;
+
+
+struct slot_entry {
+ __u8 bus;
+ __u8 device;
+ __u8 inta_link;
+ __u16 inta_irq;
+ __u8 intb_link;
+ __u16 intb_irq;
+ __u8 intc_link;
+ __u16 intc_irq;
+ __u8 intd_link;
+ __u16 intd_irq;
+ __u8 slot;
+ __u8 reserved;
+} __attribute__((packed));
+
+struct routing_table {
+ __u32 signature;
+ __u16 version;
+ __u16 size;
+ __u8 router_bus;
+ __u8 router_devfn;
+ __u16 exclusive_irqs;
+ __u32 compatable_router;
+ __u32 miniport_data;
+ __u8 reserved[11];
+ __u8 checksum;
+ struct slot_entry slot[1];
+} __attribute__((packed));
+
+
+#define PCI_DEVICE(devfn) (((devfn) >> 3) & 0x1f)
+#define PCI_FUNC(devfn) ((devfn) & 0x07)
+extern struct routing_table * pirq_alloc_read_table(void);
+extern void pirq_free_table(struct routing_table *table);
+extern int pirq_pci_dev_to_slot(struct routing_table *table, int bus, int dev);
+
+#endif /* PIRQ_H_INCLUDED */
diff --git a/src/read-cis.c b/src/read-cis.c
new file mode 100644
index 0000000..9ee71e2
--- /dev/null
+++ b/src/read-cis.c
@@ -0,0 +1,275 @@
+/*
+ * read-cis.c
+ *
+ * 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 <syslog.h>
+#include <linux/limits.h>
+
+#include "cistpl.h"
+
+#define MAX_TUPLES 0x200
+
+#define PATH_TO_SOCKET "/sys/class/pcmcia_socket/"
+
+/* Bits in attr field */
+#define IS_ATTR 1
+#define IS_INDIRECT 8
+
+
+static unsigned int functions;
+static unsigned char cis_copy[MAX_TUPLES];
+static unsigned int cis_length = MAX_TUPLES;
+
+
+#define SPACE(f) (((tuple_flags *)(&(f)))->space)
+#define HAS_LINK(f) (((tuple_flags *)(&(f)))->has_link)
+#define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space)
+#define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn)
+
+
+static void read_cis(int attr, unsigned int addr, unsigned int len, void *ptr)
+{
+ if (cis_length > addr+len)
+ memcpy(ptr, cis_copy+addr, len);
+ else
+ memset(ptr, 0xff, len);
+ return;
+}
+
+int pcmcia_get_next_tuple(unsigned int function, tuple_t *tuple);
+
+int pcmcia_get_first_tuple(unsigned int function, tuple_t *tuple)
+{
+ tuple->TupleLink = tuple->Flags = 0;
+ {
+ /* Assume presence of a LONGLINK_C to address 0 */
+ tuple->CISOffset = tuple->LinkOffset = 0;
+ SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1;
+ }
+ if ((functions > 1) &&
+ !(tuple->Attributes & TUPLE_RETURN_COMMON)) {
+ unsigned char req = tuple->DesiredTuple;
+ tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
+ if (!pcmcia_get_next_tuple(function, tuple)) {
+ tuple->DesiredTuple = CISTPL_LINKTARGET;
+ if (pcmcia_get_next_tuple(function, tuple))
+ return -ENODEV;
+ } else
+ tuple->CISOffset = tuple->TupleLink = 0;
+ tuple->DesiredTuple = req;
+ }
+ return pcmcia_get_next_tuple(function, tuple);
+}
+
+
+static int follow_link(tuple_t *tuple)
+{
+ char link[5];
+ unsigned int ofs;
+
+ if (MFC_FN(tuple->Flags)) {
+ /* Get indirect link from the MFC tuple */
+ read_cis(LINK_SPACE(tuple->Flags),
+ tuple->LinkOffset, 5, link);
+ ofs = *(u_int *)(link+1);
+ SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
+ /* Move to the next indirect link */
+ tuple->LinkOffset += 5;
+ MFC_FN(tuple->Flags)--;
+ } else if (HAS_LINK(tuple->Flags)) {
+ ofs = tuple->LinkOffset;
+ SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags);
+ HAS_LINK(tuple->Flags) = 0;
+ } else {
+ return -1;
+ }
+ if (SPACE(tuple->Flags)) {
+ /* This is ugly, but a common CIS error is to code the long
+ link offset incorrectly, so we check the right spot... */
+ read_cis(SPACE(tuple->Flags), ofs, 5, link);
+ if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
+ (strncmp(link+2, "CIS", 3) == 0))
+ return ofs;
+ /* Then, we try the wrong spot... */
+ ofs = ofs >> 1;
+ }
+ read_cis(SPACE(tuple->Flags), ofs, 5, link);
+ if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
+ (strncmp(link+2, "CIS", 3) == 0))
+ return ofs;
+ return -1;
+}
+
+int pcmcia_get_next_tuple(unsigned int function, tuple_t *tuple)
+{
+ unsigned char link[2], tmp;
+ int ofs, i, attr;
+
+ link[1] = tuple->TupleLink;
+ ofs = tuple->CISOffset + tuple->TupleLink;
+ attr = SPACE(tuple->Flags);
+
+ for (i = 0; i < MAX_TUPLES; i++) {
+ if (link[1] == 0xff) {
+ link[0] = CISTPL_END;
+ } else {
+ read_cis(attr, ofs, 2, link);
+ if (link[0] == CISTPL_NULL) {
+ ofs++; continue;
+ }
+ }
+
+ /* End of chain? Follow long link if possible */
+ if (link[0] == CISTPL_END) {
+ if ((ofs = follow_link(tuple)) < 0)
+ return -ENODEV;
+ attr = SPACE(tuple->Flags);
+ read_cis(attr, ofs, 2, link);
+ }
+
+ /* Is this a link tuple? Make a note of it */
+ if ((link[0] == CISTPL_LONGLINK_A) ||
+ (link[0] == CISTPL_LONGLINK_C) ||
+ (link[0] == CISTPL_LONGLINK_MFC) ||
+ (link[0] == CISTPL_LINKTARGET) ||
+ (link[0] == CISTPL_INDIRECT) ||
+ (link[0] == CISTPL_NO_LINK)) {
+ switch (link[0]) {
+ case CISTPL_LONGLINK_A:
+ HAS_LINK(tuple->Flags) = 1;
+ LINK_SPACE(tuple->Flags) = attr | IS_ATTR;
+ read_cis(attr, ofs+2, 4, &tuple->LinkOffset);
+ break;
+ case CISTPL_LONGLINK_C:
+ HAS_LINK(tuple->Flags) = 1;
+ LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR;
+ read_cis(attr, ofs+2, 4, &tuple->LinkOffset);
+ break;
+ case CISTPL_INDIRECT:
+ HAS_LINK(tuple->Flags) = 1;
+ LINK_SPACE(tuple->Flags) = IS_ATTR | IS_INDIRECT;
+ tuple->LinkOffset = 0;
+ break;
+ case CISTPL_LONGLINK_MFC:
+ tuple->LinkOffset = ofs + 3;
+ LINK_SPACE(tuple->Flags) = attr;
+ if (function == BIND_FN_ALL) {
+ /* Follow all the MFC links */
+ read_cis(attr, ofs+2, 1, &tmp);
+ MFC_FN(tuple->Flags) = tmp;
+ } else {
+ /* Follow exactly one of the links */
+ MFC_FN(tuple->Flags) = 1;
+ tuple->LinkOffset += function * 5;
+ }
+ break;
+ case CISTPL_NO_LINK:
+ HAS_LINK(tuple->Flags) = 0;
+ break;
+ }
+ if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
+ (tuple->DesiredTuple == RETURN_FIRST_TUPLE))
+ break;
+ } else
+ if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
+ break;
+
+ if (link[0] == tuple->DesiredTuple)
+ break;
+ ofs += link[1] + 2;
+ }
+ if (i == MAX_TUPLES)
+ return -ENODEV;
+
+ tuple->TupleCode = link[0];
+ tuple->TupleLink = link[1];
+ tuple->CISOffset = ofs + 2;
+
+ return 0;
+}
+
+#define _MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+int pcmcia_get_tuple_data(tuple_t *tuple)
+{
+ unsigned int len;
+
+ if (tuple->TupleLink < tuple->TupleOffset)
+ return -ENODEV;
+ len = tuple->TupleLink - tuple->TupleOffset;
+ tuple->TupleDataLen = tuple->TupleLink;
+ if (len == 0)
+ return 0;
+
+ read_cis (SPACE(tuple->Flags),
+ tuple->CISOffset + tuple->TupleOffset,
+ _MIN(len, tuple->TupleDataMax),
+ tuple->TupleData);
+
+ return 0;
+}
+
+
+int read_out_cis (unsigned int socket_no, FILE *fd)
+{
+ char file[PATH_MAX];
+ int ret, i;
+ tuple_t tuple;
+ unsigned char buf[256];
+
+ snprintf(file, sizeof(file), PATH_TO_SOCKET "pcmcia_socket%d/cis",
+ socket_no);
+
+ 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);
+
+ if (cis_length < 4)
+ return -EINVAL;
+
+ functions = 1;
+
+ tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
+ tuple.Attributes = TUPLE_RETURN_COMMON;
+
+ ret = pcmcia_get_first_tuple(BIND_FN_ALL, &tuple);
+ if (ret)
+ functions = 1;
+
+ tuple.TupleData = buf;
+ tuple.TupleOffset = 0;
+ tuple.TupleDataMax = 255;
+ ret = pcmcia_get_tuple_data(&tuple);
+ if (ret)
+ return -EBADF;
+
+ functions = tuple.TupleData[0];
+
+ return 0;
+}
diff --git a/src/read_proc.c b/src/read_proc.c
new file mode 100644
index 0000000..aea203f
--- /dev/null
+++ b/src/read_proc.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ * Copied from from net-tools-1.60, also under the GNU GPL v2,
+ * and modified for use here.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "eths.h"
+
+#define _PATH_PROCNET_DEV "/proc/net/dev"
+
+static struct network_device *add_interface(struct libbiosdevname_state *state,
+ const char *name)
+{
+ struct network_device *i;
+ i = malloc(sizeof(*i));
+ if (!i)
+ return NULL;
+ memset(i, 0, sizeof(*i));
+ INIT_LIST_HEAD(&i->node);
+ snprintf(i->kernel_name, sizeof(i->kernel_name), name);
+ list_add_tail(&i->node, &state->network_devices);
+ return i;
+}
+
+
+static char *get_name(char **namep, char *p)
+{
+ int count = 0;
+ char *name;
+ while (isspace(*p))
+ p++;
+ name = *namep = p;
+ while (*p) {
+ if (isspace(*p))
+ break;
+ if (*p == ':') { /* could be an alias */
+ char *dot = p, *dotname = name;
+ *name++ = *p++;
+ count++;
+ while (isdigit(*p)){
+ *name++ = *p++;
+ count++;
+ if (count == (IFNAMSIZ-1))
+ break;
+ }
+ if (*p != ':') { /* it wasn't, backup */
+ p = dot;
+ name = dotname;
+ }
+ if (*p == '\0')
+ return NULL;
+ p++;
+ break;
+ }
+ *name++ = *p++;
+ count++;
+ if (count == (IFNAMSIZ-1))
+ break;
+ }
+ *name++ = '\0';
+ return p;
+}
+
+
+
+int get_interfaces(struct libbiosdevname_state *state)
+{
+ FILE *fh;
+ int err;
+ char *line = NULL;
+ size_t linelen = 0;
+
+ fh = fopen(_PATH_PROCNET_DEV, "r");
+ if (!fh) {
+ fprintf(stderr, "Error: cannot open %s (%s).\n",
+ _PATH_PROCNET_DEV, strerror(errno));
+ return 1;
+ }
+ if (getline(&line, &linelen, fh) == -1 /* eat line */
+ || getline(&line, &linelen, fh) == -1) {
+ err = -1;
+ goto out;
+ }
+
+ err = 0;
+ while (getline(&line, &linelen, fh) != -1) {
+ char *s, *name;
+ s = get_name(&name, line);
+ add_interface(state, name);
+ }
+ if (ferror(fh)) {
+ perror(_PATH_PROCNET_DEV);
+ err = -1;
+ }
+
+out:
+ free(line);
+ fclose(fh);
+ return err;
+}
diff --git a/src/state.h b/src/state.h
new file mode 100644
index 0000000..25bcc61
--- /dev/null
+++ b/src/state.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2006 Dell, Inc.
+ * by Matt Domsch <Matt_Domsch@dell.com>
+ * Licensed under the GNU General Public license, version 2.
+ */
+#ifndef LIBBIOSDEVICE_STATE_H_INCLUDED
+#define LIBBIOSDEVICE_STATE_H_INCLUDED
+
+#include "list.h"
+
+struct libbiosdevname_state {
+ struct list_head bios_devices;
+ struct list_head pci_devices;
+ struct list_head pcmcia_devices;
+ struct list_head network_devices;
+};
+
+#endif /* LIBBIOSDEVICESTATE_H_INCLUDED */