summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2003-02-14 08:35:21 -0600
committerKai Germaschewski <kai@tp1.ruhr-uni-bochum.de>2003-02-14 08:35:21 -0600
commit0e5064f80d41d75abbb10e040bbd7c600e08299c (patch)
tree6eb8bdc574cf01754670b2f34396b1a152092b1c
parent0571739cd43b80de3bfa08f55fbcf410878cbe75 (diff)
kbuild: Module alias and device table support
Introduces "MODULE_ALIAS" which modules can use to embed their own aliases for modprobe to use. Also adds a "finishing" step to modules to supplement their aliases based on MODULE_TABLE declarations, eg. 'usb:v0506p4601dl*dh*dc*dsc*dp*ic*isc*ip*' for drivers/usb/net/pegasus.o
-rw-r--r--include/linux/mod_devicetable.h118
-rw-r--r--include/linux/module.h12
-rw-r--r--include/linux/pci.h11
-rw-r--r--include/linux/usb.h94
-rw-r--r--scripts/Makefile3
-rw-r--r--scripts/Makefile.modver19
-rw-r--r--scripts/file2alias.c259
-rw-r--r--scripts/file2alias_inc.c79
8 files changed, 485 insertions, 110 deletions
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
new file mode 100644
index 000000000000..f285481d5c79
--- /dev/null
+++ b/include/linux/mod_devicetable.h
@@ -0,0 +1,118 @@
+/*
+ * Device tables which are exported to userspace via
+ * scripts/table2alias.c. You must keep that file in sync with this
+ * header.
+ */
+
+#ifndef LINUX_MOD_DEVICETABLE_H
+#define LINUX_MOD_DEVICETABLE_H
+
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+typedef unsigned long kernel_ulong_t;
+#endif
+
+#define PCI_ANY_ID (~0)
+
+struct pci_device_id {
+ unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */
+ unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
+ unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */
+ kernel_ulong_t driver_data; /* Data private to the driver */
+};
+
+/*
+ * Device table entry for "new style" table-driven USB drivers.
+ * User mode code can read these tables to choose which modules to load.
+ * Declare the table as a MODULE_DEVICE_TABLE.
+ *
+ * A probe() parameter will point to a matching entry from this table.
+ * Use the driver_info field for each match to hold information tied
+ * to that match: device quirks, etc.
+ *
+ * Terminate the driver's table with an all-zeroes entry.
+ * Use the flag values to control which fields are compared.
+ */
+
+/**
+ * struct usb_device_id - identifies USB devices for probing and hotplugging
+ * @match_flags: Bit mask controlling of the other fields are used to match
+ * against new devices. Any field except for driver_info may be used,
+ * although some only make sense in conjunction with other fields.
+ * This is usually set by a USB_DEVICE_*() macro, which sets all
+ * other fields in this structure except for driver_info.
+ * @idVendor: USB vendor ID for a device; numbers are assigned
+ * by the USB forum to its members.
+ * @idProduct: Vendor-assigned product ID.
+ * @bcdDevice_lo: Low end of range of vendor-assigned product version numbers.
+ * This is also used to identify individual product versions, for
+ * a range consisting of a single device.
+ * @bcdDevice_hi: High end of version number range. The range of product
+ * versions is inclusive.
+ * @bDeviceClass: Class of device; numbers are assigned
+ * by the USB forum. Products may choose to implement classes,
+ * or be vendor-specific. Device classes specify behavior of all
+ * the interfaces on a devices.
+ * @bDeviceSubClass: Subclass of device; associated with bDeviceClass.
+ * @bDeviceProtocol: Protocol of device; associated with bDeviceClass.
+ * @bInterfaceClass: Class of interface; numbers are assigned
+ * by the USB forum. Products may choose to implement classes,
+ * or be vendor-specific. Interface classes specify behavior only
+ * of a given interface; other interfaces may support other classes.
+ * @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
+ * @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
+ * @driver_info: Holds information used by the driver. Usually it holds
+ * a pointer to a descriptor understood by the driver, or perhaps
+ * device flags.
+ *
+ * In most cases, drivers will create a table of device IDs by using
+ * USB_DEVICE(), or similar macros designed for that purpose.
+ * They will then export it to userspace using MODULE_DEVICE_TABLE(),
+ * and provide it to the USB core through their usb_driver structure.
+ *
+ * See the usb_match_id() function for information about how matches are
+ * performed. Briefly, you will normally use one of several macros to help
+ * construct these entries. Each entry you provide will either identify
+ * one or more specific products, or will identify a class of products
+ * which have agreed to behave the same. You should put the more specific
+ * matches towards the beginning of your table, so that driver_info can
+ * record quirks of specific products.
+ */
+struct usb_device_id {
+ /* which fields to match against? */
+ __u16 match_flags;
+
+ /* Used for product specific matches; range is inclusive */
+ __u16 idVendor;
+ __u16 idProduct;
+ __u16 bcdDevice_lo;
+ __u16 bcdDevice_hi;
+
+ /* Used for device class matches */
+ __u8 bDeviceClass;
+ __u8 bDeviceSubClass;
+ __u8 bDeviceProtocol;
+
+ /* Used for interface class matches */
+ __u8 bInterfaceClass;
+ __u8 bInterfaceSubClass;
+ __u8 bInterfaceProtocol;
+
+ /* not matched against */
+ kernel_ulong_t driver_info;
+};
+
+/* Some useful macros to use to create struct usb_device_id */
+#define USB_DEVICE_ID_MATCH_VENDOR 0x0001
+#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002
+#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004
+#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008
+#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
+#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020
+#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040
+#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
+#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
+#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
+
+#endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/module.h b/include/linux/module.h
index 53b4d2ea5987..d10249bfb667 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -57,13 +57,14 @@ search_extable(const struct exception_table_entry *first,
unsigned long value);
#ifdef MODULE
+#define ___module_cat(a,b) a ## b
+#define __module_cat(a,b) ___module_cat(a,b)
+/* For userspace: you can also call me... */
+#define MODULE_ALIAS(alias) \
+ static const char __module_cat(__alias_,__LINE__)[] \
+ __attribute__((section(".modinfo"),unused)) = "alias=" alias
-/* For replacement modutils, use an alias not a pointer. */
#define MODULE_GENERIC_TABLE(gtype,name) \
-static const unsigned long __module_##gtype##_size \
- __attribute__ ((unused)) = sizeof(struct gtype##_id); \
-static const struct gtype##_id * __module_##gtype##_table \
- __attribute__ ((unused)) = name; \
extern const struct gtype##_id __mod_##gtype##_table \
__attribute__ ((unused, alias(__stringify(name))))
@@ -103,6 +104,7 @@ extern const struct gtype##_id __mod_##gtype##_table \
#else /* !MODULE */
+#define MODULE_ALIAS(alias)
#define MODULE_GENERIC_TABLE(gtype,name)
#define THIS_MODULE ((struct module *)0)
#define MOD_INC_USE_COUNT do { } while (0)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7b42110379ac..e63da00d4cf6 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -17,6 +17,8 @@
#ifndef LINUX_PCI_H
#define LINUX_PCI_H
+#include <linux/mod_devicetable.h>
+
/*
* Under PCI, each device has 256 bytes of configuration address space,
* of which the first 64 bytes are standardized as follows:
@@ -359,8 +361,6 @@ enum pci_mmap_state {
#define DEVICE_COUNT_DMA 2
#define DEVICE_COUNT_RESOURCE 12
-#define PCI_ANY_ID (~0)
-
/*
* The pci_dev structure is used to describe PCI devices.
*/
@@ -491,13 +491,6 @@ struct pbus_set_ranges_data
unsigned long prefetch_start, prefetch_end;
};
-struct pci_device_id {
- unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */
- unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
- unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */
- unsigned long driver_data; /* Data private to the driver */
-};
-
struct pci_driver {
struct list_head node;
char *name;
diff --git a/include/linux/usb.h b/include/linux/usb.h
index cb5c0db14aa1..b0873cc6d8e1 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1,6 +1,7 @@
#ifndef __LINUX_USB_H
#define __LINUX_USB_H
+#include <linux/mod_devicetable.h>
#include <linux/usb_ch9.h>
#define USB_MAJOR 180
@@ -314,99 +315,6 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size)
/*-------------------------------------------------------------------------*/
-/*
- * Device table entry for "new style" table-driven USB drivers.
- * User mode code can read these tables to choose which modules to load.
- * Declare the table as a MODULE_DEVICE_TABLE.
- *
- * A probe() parameter will point to a matching entry from this table.
- * Use the driver_info field for each match to hold information tied
- * to that match: device quirks, etc.
- *
- * Terminate the driver's table with an all-zeroes entry.
- * Use the flag values to control which fields are compared.
- */
-
-/**
- * struct usb_device_id - identifies USB devices for probing and hotplugging
- * @match_flags: Bit mask controlling of the other fields are used to match
- * against new devices. Any field except for driver_info may be used,
- * although some only make sense in conjunction with other fields.
- * This is usually set by a USB_DEVICE_*() macro, which sets all
- * other fields in this structure except for driver_info.
- * @idVendor: USB vendor ID for a device; numbers are assigned
- * by the USB forum to its members.
- * @idProduct: Vendor-assigned product ID.
- * @bcdDevice_lo: Low end of range of vendor-assigned product version numbers.
- * This is also used to identify individual product versions, for
- * a range consisting of a single device.
- * @bcdDevice_hi: High end of version number range. The range of product
- * versions is inclusive.
- * @bDeviceClass: Class of device; numbers are assigned
- * by the USB forum. Products may choose to implement classes,
- * or be vendor-specific. Device classes specify behavior of all
- * the interfaces on a devices.
- * @bDeviceSubClass: Subclass of device; associated with bDeviceClass.
- * @bDeviceProtocol: Protocol of device; associated with bDeviceClass.
- * @bInterfaceClass: Class of interface; numbers are assigned
- * by the USB forum. Products may choose to implement classes,
- * or be vendor-specific. Interface classes specify behavior only
- * of a given interface; other interfaces may support other classes.
- * @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
- * @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
- * @driver_info: Holds information used by the driver. Usually it holds
- * a pointer to a descriptor understood by the driver, or perhaps
- * device flags.
- *
- * In most cases, drivers will create a table of device IDs by using
- * USB_DEVICE(), or similar macros designed for that purpose.
- * They will then export it to userspace using MODULE_DEVICE_TABLE(),
- * and provide it to the USB core through their usb_driver structure.
- *
- * See the usb_match_id() function for information about how matches are
- * performed. Briefly, you will normally use one of several macros to help
- * construct these entries. Each entry you provide will either identify
- * one or more specific products, or will identify a class of products
- * which have agreed to behave the same. You should put the more specific
- * matches towards the beginning of your table, so that driver_info can
- * record quirks of specific products.
- */
-struct usb_device_id {
- /* which fields to match against? */
- __u16 match_flags;
-
- /* Used for product specific matches; range is inclusive */
- __u16 idVendor;
- __u16 idProduct;
- __u16 bcdDevice_lo;
- __u16 bcdDevice_hi;
-
- /* Used for device class matches */
- __u8 bDeviceClass;
- __u8 bDeviceSubClass;
- __u8 bDeviceProtocol;
-
- /* Used for interface class matches */
- __u8 bInterfaceClass;
- __u8 bInterfaceSubClass;
- __u8 bInterfaceProtocol;
-
- /* not matched against */
- unsigned long driver_info;
-};
-
-/* Some useful macros to use to create struct usb_device_id */
-#define USB_DEVICE_ID_MATCH_VENDOR 0x0001
-#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002
-#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004
-#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008
-#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
-#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020
-#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040
-#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
-#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
-#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
-
#define USB_DEVICE_ID_MATCH_DEVICE (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
#define USB_DEVICE_ID_MATCH_DEV_RANGE (USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI)
#define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE)
diff --git a/scripts/Makefile b/scripts/Makefile
index 3927e5eab97f..cf5a1862ea1d 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -8,7 +8,8 @@
# docproc: Preprocess .tmpl file in order to generate .sgml documentation
# conmakehash: Create arrays for initializing the kernel console tables
-host-progs := fixdep split-include conmakehash docproc kallsyms modpost
+host-progs := fixdep split-include conmakehash docproc kallsyms modpost \
+ file2alias
build-targets := $(host-progs)
# Let clean descend into subdirs
diff --git a/scripts/Makefile.modver b/scripts/Makefile.modver
index 252dc42f7203..6d1a3cb32232 100644
--- a/scripts/Makefile.modver
+++ b/scripts/Makefile.modver
@@ -27,7 +27,7 @@ quiet_cmd_ld_ko_o = LD [M] $@
cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \
$(filter-out FORCE,$^)
-$(modules): %.ko :%.o %.ver.o FORCE
+$(modules): %.ko :%.o %.ver.o $(if CONFIG_HOTPLUG,%.aliases.o) FORCE
$(call if_changed,ld_ko_o)
targets += $(modules)
@@ -35,7 +35,7 @@ targets += $(modules)
# Compile version info for unresolved symbols
quiet_cmd_cc_o_c = CC $@
- cmd_cc_o_c = $(CC) $(CFLAGS) -c -o $@ $<
+ cmd_cc_o_c = $(CC) $(CFLAGS) $(CFLAGS_MODULE) -c -o $@ $<
# We have a fake dependency on compile.h to make sure that we
# notice if the compiler version changes under us.
@@ -45,6 +45,21 @@ $(modules:.ko=.ver.o): %.ver.o: %.ver.c include/linux/compile.h FORCE
targets += $(modules:.ko=.ver.o)
+$(modules:.ko=.aliases.o): %.aliases.o: %.aliases.c FORCE
+ $(call if_changed,cc_o_c)
+
+targets += $(modules:.ko=.aliases.o)
+
+# Generate aliases
+
+quiet_cmd_file2alias = ALIAS $@
+ cmd_file2alias = scripts/file2alias $< > $@
+
+$(modules:.ko=.aliases.c): %.aliases.c: %.o FORCE
+ $(call if_changed,file2alias)
+
+targets += $(modules:.ko=.aliases.c)
+
# All the .ver.c files are generated using the helper "modpost"
.PHONY: __modpost
diff --git a/scripts/file2alias.c b/scripts/file2alias.c
new file mode 100644
index 000000000000..525a766bab3e
--- /dev/null
+++ b/scripts/file2alias.c
@@ -0,0 +1,259 @@
+/* Simple code to turn various tables in an ELF file into alias definitions.
+ This deals with kernel datastructures where they should be
+ dealt with: in the kernel source.
+ (C) 2002 Rusty Russell IBM Corporation.
+*/
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <elf.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* 32 bits: if it turns out to be 64, we add explicitly (see EXTRA_SIZE). */
+typedef int kernel_ulong_t;
+#include "../include/linux/types.h"
+#include "../include/linux/mod_devicetable.h"
+
+static int switch_endian;
+
+static void __endian(const void *src, void *dest, unsigned int size)
+{
+ unsigned int i;
+ for (i = 0; i < size; i++)
+ ((unsigned char*)dest)[i] = ((unsigned char*)src)[size - i-1];
+}
+
+#define TO_NATIVE(x) \
+({ \
+ typeof(x) __x; \
+ if (switch_endian) __endian(&(x), &(__x), sizeof(__x)); \
+ else __x = x; \
+ __x; \
+})
+
+#define ADD(str, sep, cond, field) \
+do { \
+ strcat(str, sep); \
+ if (cond) \
+ sprintf(str + strlen(str), \
+ sizeof(field) == 1 ? "%02X" : \
+ sizeof(field) == 2 ? "%04X" : \
+ sizeof(field) == 4 ? "%08X" : "", \
+ field); \
+ else \
+ sprintf(str + strlen(str), "*"); \
+} while(0)
+
+/* Looks like "usb:vNpNdlNdhNdcNdscNdpNicNiscNipN" */
+static int do_usb_entry(const char *filename,
+ struct usb_device_id *id, char *alias)
+{
+ id->match_flags = TO_NATIVE(id->match_flags);
+ id->idVendor = TO_NATIVE(id->idVendor);
+ id->idProduct = TO_NATIVE(id->idProduct);
+ id->bcdDevice_lo = TO_NATIVE(id->bcdDevice_lo);
+ id->bcdDevice_hi = TO_NATIVE(id->bcdDevice_hi);
+
+ strcpy(alias, "usb:");
+ ADD(alias, "v", id->match_flags&USB_DEVICE_ID_MATCH_VENDOR,
+ id->idVendor);
+ ADD(alias, "p", id->match_flags&USB_DEVICE_ID_MATCH_PRODUCT,
+ id->idProduct);
+ ADD(alias, "dl", id->match_flags&USB_DEVICE_ID_MATCH_DEV_LO,
+ id->bcdDevice_lo);
+ ADD(alias, "dh", id->match_flags&USB_DEVICE_ID_MATCH_DEV_HI,
+ id->bcdDevice_hi);
+ ADD(alias, "dc", id->match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS,
+ id->bDeviceClass);
+ ADD(alias, "dsc",
+ id->match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS,
+ id->bDeviceSubClass);
+ ADD(alias, "dp",
+ id->match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL,
+ id->bDeviceProtocol);
+ ADD(alias, "ic",
+ id->match_flags&USB_DEVICE_ID_MATCH_INT_CLASS,
+ id->bInterfaceClass);
+ ADD(alias, "isc",
+ id->match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+ id->bInterfaceSubClass);
+ ADD(alias, "ip",
+ id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL,
+ id->bInterfaceProtocol);
+ return 1;
+}
+
+/* Looks like: pci:vNdNsvNsdNcN. */
+static int do_pci_entry(const char *filename,
+ struct pci_device_id *id, char *alias)
+{
+ id->vendor = TO_NATIVE(id->vendor);
+ id->device = TO_NATIVE(id->device);
+ id->subvendor = TO_NATIVE(id->subvendor);
+ id->subdevice = TO_NATIVE(id->subdevice);
+ id->class = TO_NATIVE(id->class);
+ id->class_mask = TO_NATIVE(id->class_mask);
+
+ strcpy(alias, "pci:");
+ ADD(alias, "v", id->vendor != PCI_ANY_ID, id->vendor);
+ ADD(alias, "d", id->device != PCI_ANY_ID, id->device);
+ ADD(alias, "sv", id->subvendor != PCI_ANY_ID, id->subvendor);
+ ADD(alias, "sd", id->subdevice != PCI_ANY_ID, id->subdevice);
+ if (id->class_mask != 0 && id->class_mask != ~0) {
+ fprintf(stderr,
+ "file2alias: Can't handle class_mask in %s:%04X\n",
+ filename, id->class_mask);
+ return 0;
+ }
+ ADD(alias, "c", id->class_mask == ~0, id->class);
+ return 1;
+}
+
+/* Ignore any prefix, eg. v850 prepends _ */
+static inline int sym_is(const char *symbol, const char *name)
+{
+ const char *match;
+
+ match = strstr(symbol, name);
+ if (!match)
+ return 0;
+ return match[strlen(symbol)] == '\0';
+}
+
+/* Returns 1 if we output anything. */
+static int do_table(void *symval, unsigned long size,
+ unsigned long id_size,
+ void *function,
+ const char *filename, int *first)
+{
+ unsigned int i;
+ char alias[500];
+ int (*do_entry)(const char *, void *entry, char *alias) = function;
+ int wrote = 0;
+
+ if (size % id_size || size < id_size) {
+ fprintf(stderr, "WARNING: %s ids %lu bad size (each on %lu)\n",
+ filename, size, id_size);
+ return 0;
+ }
+ /* Leave last one: it's the terminator. */
+ size -= id_size;
+
+ for (i = 0; i < size; i += id_size) {
+ if (do_entry(filename, symval+i, alias)) {
+ /* Always end in a wildcard, for future extension */
+ if (alias[strlen(alias)-1] != '*')
+ strcat(alias, "*");
+ if (*first) {
+ printf("#include <linux/module.h>\n\n");
+ *first = 0;
+ }
+ printf("MODULE_ALIAS(\"%s\");\n", alias);
+ wrote = 1;
+ }
+ }
+ return wrote;
+}
+
+/* This is the best way of doing this without making a complete mess
+ of the code. */
+#undef analyse_file
+#undef Elf_Ehdr
+#undef Elf_Shdr
+#undef Elf_Sym
+#undef EXTRA_SIZE
+#define analyse_file analyze_file32
+#define Elf_Ehdr Elf32_Ehdr
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define EXTRA_SIZE 0
+#include "file2alias_inc.c"
+#undef analyse_file
+#undef Elf_Ehdr
+#undef Elf_Shdr
+#undef Elf_Sym
+#undef EXTRA_SIZE
+#define analyse_file analyze_file64
+#define Elf_Ehdr Elf64_Ehdr
+#define Elf_Shdr Elf64_Shdr
+#define Elf_Sym Elf64_Sym
+#define EXTRA_SIZE 4
+#include "file2alias_inc.c"
+
+static void *grab_file(const char *filename, unsigned long *size)
+{
+ struct stat st;
+ void *map;
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+ if (fstat(fd, &st) != 0) {
+ close(fd);
+ return NULL;
+ }
+ *size = st.st_size;
+ map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (mmap == MAP_FAILED) {
+ close(fd);
+ return NULL;
+ }
+ close(fd);
+ return map;
+}
+
+/* Look through files for __mod_*_device_table: emit alias definitions
+ for compiling in. */
+int main(int argc, char *argv[])
+{
+ void *file;
+ unsigned long size;
+ int endian;
+ union { short s; char c[2]; } endian_test;
+
+ endian_test.s = 1;
+ if (endian_test.c[1] == 1) endian = ELFDATA2MSB;
+ else if (endian_test.c[0] == 1) endian = ELFDATA2LSB;
+ else
+ abort();
+
+ for (; argv[1]; argv++) {
+ file = grab_file(argv[1], &size);
+ if (!file) {
+ fprintf(stderr, "file2alias: opening %s: %s\n",
+ argv[1], strerror(errno));
+ continue;
+ }
+
+ if (size < SELFMAG || memcmp(file, ELFMAG, SELFMAG) != 0)
+ goto bad_elf;
+
+ if (((unsigned char *)file)[EI_DATA] != endian)
+ switch_endian = 1;
+
+ switch (((unsigned char *)file)[EI_CLASS]) {
+ case ELFCLASS32:
+ analyze_file32(file, size, argv[1]);
+ break;
+ case ELFCLASS64:
+ analyze_file64(file, size, argv[1]);
+ break;
+ default:
+ goto bad_elf;
+ }
+ munmap(file, size);
+ continue;
+
+ bad_elf:
+ fprintf(stderr, "file2alias: %s is not elf\n", argv[1]);
+ return 1;
+ }
+ return 0;
+}
diff --git a/scripts/file2alias_inc.c b/scripts/file2alias_inc.c
new file mode 100644
index 000000000000..3fcf52e0e3d4
--- /dev/null
+++ b/scripts/file2alias_inc.c
@@ -0,0 +1,79 @@
+/* This contains the cookie-cutter code for ELF handling (32 v 64).
+ Return true if anything output. */
+static void analyse_file(Elf_Ehdr *hdr,
+ unsigned int size,
+ const char *filename)
+{
+ unsigned int i, num_syms = 0;
+ Elf_Shdr *sechdrs;
+ Elf_Sym *syms = NULL;
+ char *secstrings, *strtab = NULL;
+ int first = 1;
+
+ if (size < sizeof(*hdr))
+ goto truncated;
+
+ sechdrs = (void *)hdr + TO_NATIVE(hdr->e_shoff);
+ if (switch_endian) {
+ hdr->e_shoff = TO_NATIVE(hdr->e_shoff);
+ hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
+ hdr->e_shnum = TO_NATIVE(hdr->e_shnum);
+ for (i = 0; i < hdr->e_shnum; i++) {
+ sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type);
+ sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
+ sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
+ sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
+ }
+ }
+
+ /* Find symbol table. */
+ secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+ for (i = 1; i < hdr->e_shnum; i++) {
+ if (sechdrs[i].sh_offset > size)
+ goto truncated;
+ if (sechdrs[i].sh_type == SHT_SYMTAB) {
+ syms = (void *)hdr + sechdrs[i].sh_offset;
+ num_syms = sechdrs[i].sh_size / sizeof(syms[0]);
+ } else if (sechdrs[i].sh_type == SHT_STRTAB)
+ strtab = (void *)hdr + sechdrs[i].sh_offset;
+ }
+
+ if (!strtab || !syms) {
+ fprintf(stderr, "table2alias: %s no symtab?\n", filename);
+ return;
+ }
+
+ for (i = 0; i < num_syms; i++) {
+ const char *symname;
+ void *symval;
+
+ if (switch_endian) {
+ syms[i].st_shndx = TO_NATIVE(syms[i].st_shndx);
+ syms[i].st_name = TO_NATIVE(syms[i].st_name);
+ syms[i].st_value = TO_NATIVE(syms[i].st_value);
+ syms[i].st_size = TO_NATIVE(syms[i].st_size);
+ }
+
+ if (!syms[i].st_shndx || syms[i].st_shndx >= hdr->e_shnum)
+ continue;
+
+ symname = strtab + syms[i].st_name;
+ symval = (void *)hdr
+ + sechdrs[syms[i].st_shndx].sh_offset
+ + syms[i].st_value;
+ if (sym_is(symname, "__mod_pci_device_table"))
+ do_table(symval, syms[i].st_size,
+ sizeof(struct pci_device_id) + EXTRA_SIZE * 1,
+ do_pci_entry, filename, &first);
+ else if (sym_is(symname, "__mod_usb_device_table"))
+ do_table(symval, syms[i].st_size,
+ sizeof(struct usb_device_id) + EXTRA_SIZE * 1,
+ do_usb_entry, filename, &first);
+ }
+ return;
+
+ truncated:
+ fprintf(stderr, "table2alias: %s is truncated.\n", filename);
+ return;
+}