Commit 0e5064f8 authored by Rusty Russell's avatar Rusty Russell Committed by Kai Germaschewski

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
parent 0571739c
/*
* 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 */
......@@ -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)
......
......@@ -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;
......
#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)
......
......@@ -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
......
......@@ -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
......
/* 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;
}
/* 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment