public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Rusty Russell <rusty@rustcorp.com.au>
To: linux-kernel@vger.kernel.org
Cc: Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de>,
	greg@kroah.com, jgarzik@pobox.com
Subject: [PATCH] Module alias and device table support.
Date: Fri, 31 Jan 2003 11:09:38 +1100	[thread overview]
Message-ID: <20030131002043.947632C056@lists.samba.org> (raw)

This patch adds MODULE_ALIAS("foo") capability, and uses it to
automatically generate sensible aliases from device tables.  The
post-processing is a little rough, but works.

Name: Module alias and device table support
Author: Rusty Russell
Status: Tested on 2.5.59

D: Introduces "MODULE_ALIAS" which modules can use to embed their own
D: aliases for modprobe to use.  Also adds a "finishing" step to modules to
D: supplement their aliases based on MODULE_TABLE declarations, eg.
D: 'usb:v0506p4601dl*dh*dc*dsc*dp*ic*isc*ip*' for drivers/usb/net/pegasus.o

diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.59/include/linux/isapnp.h working-2.5.59-alias/include/linux/isapnp.h
--- linux-2.5.59/include/linux/isapnp.h	2003-01-14 10:13:08.000000000 +1100
+++ working-2.5.59-alias/include/linux/isapnp.h	2003-01-30 16:13:12.000000000 +1100
@@ -69,8 +69,9 @@
 
 /* export used IDs outside module */
 #define ISAPNP_CARD_TABLE(name) \
-		MODULE_GENERIC_TABLE(isapnp_card, name)
+		MODULE_TABLE(isapnp_card, name)
 
+/* If you change this, you must update scripts/table2alias.c. */
 struct isapnp_card_id {
 	unsigned long driver_data;	/* data private to the driver */
 	unsigned short card_vendor, card_device;
@@ -85,6 +86,7 @@ struct isapnp_card_id {
 #define ISAPNP_DEVICE_SINGLE_END \
 		.card_vendor = 0, .card_device = 0
 
+/* If you change this, you must update scripts/table2alias.c. */
 struct isapnp_device_id {
 	unsigned short card_vendor, card_device;
 	unsigned short vendor, function;
diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.59/include/linux/module.h working-2.5.59-alias/include/linux/module.h
--- linux-2.5.59/include/linux/module.h	2003-01-17 17:01:18.000000000 +1100
+++ working-2.5.59-alias/include/linux/module.h	2003-01-30 17:56:37.000000000 +1100
@@ -50,13 +50,14 @@ search_extable(const struct exception_ta
 	       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(".modalias"),unused)) = 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))))
 
@@ -96,6 +97,7 @@ extern const struct gtype##_id __mod_##g
 
 #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 -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.59/include/linux/pci.h working-2.5.59-alias/include/linux/pci.h
--- linux-2.5.59/include/linux/pci.h	2003-01-02 14:48:00.000000000 +1100
+++ working-2.5.59-alias/include/linux/pci.h	2003-01-30 16:13:12.000000000 +1100
@@ -491,6 +491,7 @@ struct pbus_set_ranges_data
 	unsigned long prefetch_start, prefetch_end;
 };
 
+/* If you change this, you must update scripts/table2alias.c. */
 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 */
diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.59/include/linux/usb.h working-2.5.59-alias/include/linux/usb.h
--- linux-2.5.59/include/linux/usb.h	2003-01-17 17:01:18.000000000 +1100
+++ working-2.5.59-alias/include/linux/usb.h	2003-01-30 16:13:12.000000000 +1100
@@ -371,6 +371,7 @@ static inline int usb_make_path (struct 
  * matches towards the beginning of your table, so that driver_info can
  * record quirks of specific products.
  */
+/* If you change this, you must update scripts/table2alias.c. */
 struct usb_device_id {
 	/* which fields to match against? */
 	__u16		match_flags;
diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.59/scripts/Makefile working-2.5.59-alias/scripts/Makefile
--- linux-2.5.59/scripts/Makefile	2003-01-02 12:45:31.000000000 +1100
+++ working-2.5.59-alias/scripts/Makefile	2003-01-30 16:13:12.000000000 +1100
@@ -8,7 +8,7 @@
 # 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
+host-progs    := fixdep split-include conmakehash docproc kallsyms table2alias
 build-targets := $(host-progs)
 
 # Let clean descend into subdirs
diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.59/scripts/Makefile.build working-2.5.59-alias/scripts/Makefile.build
--- linux-2.5.59/scripts/Makefile.build	2003-01-17 17:01:18.000000000 +1100
+++ working-2.5.59-alias/scripts/Makefile.build	2003-01-30 17:51:31.000000000 +1100
@@ -175,11 +175,16 @@ endif
 quiet_cmd_link_multi-y = LD      $@
 cmd_link_multi-y = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(addprefix $(obj)/,$($(subst $(obj)/,,$(@:.o=-objs))) $($(subst $(obj)/,,$(@:.o=-y)))),$^)
 
+ifdef CONFIG_HOTPLUG
+module_link_hotplug-multi = `$(CONFIG_SHELL) scripts/extract_aliases $@.aliases "$(modname_flags)" $(filter $(addprefix $(obj)/,$($(subst $(obj)/,,$(@:.ko=-objs))) $($(subst $(obj)/,,$(@:.ko=-y)))),$^)`
+module_link_hotplug-single = `$(CONFIG_SHELL) scripts/extract_aliases $@.aliases "$(modname_flags)" $<`
+endif
+
 quiet_cmd_link_multi-m = LD [M]  $@
-cmd_link_multi-m = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_MODULE) -o $@ $(filter $(addprefix $(obj)/,$($(subst $(obj)/,,$(@:.ko=-objs))) $($(subst $(obj)/,,$(@:.ko=-y)))),$^) init/vermagic.o
+cmd_link_multi-m = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_MODULE) -o $@ $(filter $(addprefix $(obj)/,$($(subst $(obj)/,,$(@:.ko=-objs))) $($(subst $(obj)/,,$(@:.ko=-y)))),$^) $(module_link_hotplug-multi) init/vermagic.o 
 
 quiet_cmd_link_single-m = LD [M]  $@
-cmd_link_single-m = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_MODULE) -o $@ $< init/vermagic.o
+cmd_link_single-m = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_MODULE) -o $@ $< init/vermagic.o $(module_link_hotplug-single)
 
 # Don't rebuilt vermagic.o unless we actually are in the init/ dir
 ifneq ($(obj),init)
diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.59/scripts/extract_aliases working-2.5.59-alias/scripts/extract_aliases
--- linux-2.5.59/scripts/extract_aliases	1970-01-01 10:00:00.000000000 +1000
+++ working-2.5.59-alias/scripts/extract_aliases	2003-01-30 18:06:59.000000000 +1100
@@ -0,0 +1,21 @@
+#! /bin/sh
+
+# Look for module tables, and if found, put them in the object file
+# and print its name.
+set -e
+
+OUTPUT="$1"
+MODNAME_FLAGS="$2"
+shift 2
+
+$NM --no-sort --print-size --radix=d --print-file-name "$@" | 
+    grep '__mod_[a-z_]*_table' | 
+    while IFS=": " read FILE OFFSET SIZE TYPE NAME; do
+	scripts/table2alias $NAME $FILE $OFFSET $SIZE
+    done > $OUTPUT.c
+
+if [ -s $OUTPUT.c ]; then
+    $CC $CFLAGS $NOSTDINC_FLAGS $EXTRA_CFLAGS $MODNAME_FLAGS -DMODULE -include include/linux/module.h -c -o $OUTPUT.o $OUTPUT.c
+    echo $OUTPUT.o
+fi
+rm $OUTPUT.c
diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.59/scripts/table2alias.c working-2.5.59-alias/scripts/table2alias.c
--- linux-2.5.59/scripts/table2alias.c	1970-01-01 10:00:00.000000000 +1000
+++ working-2.5.59-alias/scripts/table2alias.c	2003-01-30 17:49:45.000000000 +1100
@@ -0,0 +1,244 @@
+/* Simple code to turn various tables into module aliases.
+   This deals with kernel datastructures where they should be
+   dealt with: in the kernel source.
+   (C) 2002 Rusty Russell IBM Corporation.
+*/
+#include <stdint.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* We need __LITTLE_ENDIAN/__BIG_ENDIAN and BITS_PER_LONG */
+#define __KERNEL__
+#include "../include/asm/byteorder.h"
+#include "../include/asm/types.h"
+
+#if BITS_PER_LONG == 32
+typedef uint32_t kernel_long_t;
+#elif BITS_PER_LONG == 64
+typedef uint64_t kernel_long_t;
+#else
+#error Unknown BITS_PER_LONG
+#endif
+
+/* If we're cross-compiling, we could have any wierd endian
+   combination.  Keep it simple. */
+static kernel_long_t __to_native(unsigned char *ptr, unsigned int size)
+{
+        unsigned int i;
+        kernel_long_t ret = 0;
+
+#ifdef __LITTLE_ENDIAN
+        for (i = 0; i < size; i++)
+                ret += ((unsigned long long)ptr[size - 1 - i]) << (i * 8);
+#elif defined(__BIG_ENDIAN)
+        for (i = 0; i < size; i++)
+                ret += ((unsigned long long)ptr[i]) << (i * 8);
+#else
+#error Must be big or little endian.
+#endif
+	return ret;
+}
+
+#define TO_NATIVE(x) (x) = __to_native((void *)&(x), sizeof(x))
+
+#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
+
+struct usb_device_id {
+        /* which fields to match against? */
+        uint16_t        match_flags;
+
+        /* Used for product specific matches; range is inclusive */
+        uint16_t        idVendor;
+        uint16_t        idProduct;
+        uint16_t        bcdDevice_lo;
+        uint16_t        bcdDevice_hi;
+
+        /* Used for device class matches */
+        uint8_t         bDeviceClass;
+        uint8_t         bDeviceSubClass;
+        uint8_t         bDeviceProtocol;
+
+        /* Used for interface class matches */
+        uint8_t         bInterfaceClass;
+        uint8_t         bInterfaceSubClass;
+        uint8_t         bInterfaceProtocol;
+
+        /* not matched against */
+        kernel_long_t   driver_info;
+};
+
+#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 void do_usb_table(struct usb_device_id *ids, unsigned int size,
+			 const char *filename)
+{
+	unsigned int i;
+        char alias[200];
+
+	/* Should be exact multiple. */
+	if (size % sizeof(ids[0]))
+		fprintf(stderr, "WARNING: %s USB ids size has %u left\n",
+			filename, size % sizeof(ids[0]));
+	for (i = 0; i < size / sizeof(ids[0]); i++) {
+                TO_NATIVE(ids[i].match_flags);
+                TO_NATIVE(ids[i].idVendor);
+                TO_NATIVE(ids[i].idProduct);
+                TO_NATIVE(ids[i].bcdDevice_lo);
+                TO_NATIVE(ids[i].bcdDevice_hi);
+
+                strcpy(alias, "usb:");
+                ADD(alias, "v", ids[i].match_flags&USB_DEVICE_ID_MATCH_VENDOR,
+                    ids[i].idVendor);
+                ADD(alias, "p", ids[i].match_flags&USB_DEVICE_ID_MATCH_PRODUCT,
+                    ids[i].idProduct);
+                ADD(alias, "dl", ids[i].match_flags&USB_DEVICE_ID_MATCH_DEV_LO,
+                    ids[i].bcdDevice_lo);
+                ADD(alias, "dh", ids[i].match_flags&USB_DEVICE_ID_MATCH_DEV_HI,
+                    ids[i].bcdDevice_hi);
+                ADD(alias, "dc", ids[i].match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS,
+                    ids[i].bDeviceClass);
+                ADD(alias, "dsc",
+		    ids[i].match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS,
+                    ids[i].bDeviceSubClass);
+                ADD(alias, "dp",
+		    ids[i].match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL,
+                    ids[i].bDeviceProtocol);
+                ADD(alias, "ic",
+		    ids[i].match_flags&USB_DEVICE_ID_MATCH_INT_CLASS,
+                    ids[i].bInterfaceClass);
+                ADD(alias, "isc",
+		    ids[i].match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+                    ids[i].bInterfaceSubClass);
+                ADD(alias, "ip",
+		    ids[i].match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL,
+                    ids[i].bInterfaceProtocol);
+		/* Always end in a wildcard, for future extension */
+		if (alias[strlen(alias)-1] != '*')
+			strcat(alias, "*");
+                printf("MODULE_ALIAS(\"%s\");\n", alias);
+        }
+}
+
+#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_long_t driver_data;        /* Data private to the driver */
+};
+
+/* Looks like: pci:vNdNsvNsdNcN. */
+static void do_pci_table(struct pci_device_id *ids, unsigned int size,
+			 const char *filename)
+{
+	unsigned int i;
+        char alias[200];
+
+	/* Should be exact multiple. */
+	if (size % sizeof(ids[0]))
+		fprintf(stderr, "WARNING: %s PCI ids size has %u left\n",
+			filename, size % sizeof(ids[0]));
+	for (i = 0; i < size / sizeof(ids[0]); i++) {
+                TO_NATIVE(ids[i].vendor);
+                TO_NATIVE(ids[i].device);
+                TO_NATIVE(ids[i].subvendor);
+                TO_NATIVE(ids[i].subdevice);
+                TO_NATIVE(ids[i].class);
+                TO_NATIVE(ids[i].class_mask);
+
+                strcpy(alias, "pci:");
+                ADD(alias, "v", ids[i].vendor != PCI_ANY_ID, ids[i].vendor);
+                ADD(alias, "d", ids[i].device != PCI_ANY_ID, ids[i].device);
+                ADD(alias, "sv", ids[i].subvendor != PCI_ANY_ID, ids[i].subvendor);
+                ADD(alias, "sd", ids[i].subdevice != PCI_ANY_ID, ids[i].subdevice);
+                if (ids[i].class_mask != 0 && ids[i].class_mask != ~0) {
+                        fprintf(stderr,
+				"Can't handle strange class_mask in %s:%04X\n",
+				filename, ids[i].class_mask);
+                        exit(1);
+                }
+                ADD(alias, "c", ids[i].class != PCI_ANY_ID, ids[i].subvendor);
+		/* Always end in a wildcard, for future extension */
+		if (alias[strlen(alias)-1] != '*')
+			strcat(alias, "*");
+                printf("MODULE_ALIAS(\"%s\");\n", alias);
+        }
+}
+
+int main(int argc, char *argv[])
+{
+	int ret, fd;
+	unsigned int size, offset;
+	void *file;
+
+        if (argc != 5) {
+                fprintf(stderr,
+                        "Usage: table2alias <type> <file> <offset> <size>\n"
+                        "  Where type is __mod_{pci, usb}_device_table.\n");
+                exit(1);
+        }
+
+	/* Suck it in. */
+	offset = atoi(argv[3]);
+	size = atoi(argv[4]);
+	file = malloc(size);
+
+	fd = open(argv[2], O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "opening %s: %s\n", argv[2], strerror(errno));
+		exit(1);
+	}
+	if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
+		fprintf(stderr, "seeking to %u in %s: %s\n",
+			offset, argv[2], strerror(errno));
+		exit(1);
+	}
+
+	offset = 0;
+	while (offset < size) {
+		ret = read(fd, file+offset, size-offset);
+		if (ret < 0) {
+			fprintf(stderr, "reading from %s: %s\n",
+				argv[2], strerror(errno));
+			exit(1);
+		}
+		offset += ret;
+	} 
+
+        if (strcmp(argv[1], "__mod_usb_device_table") == 0)
+                do_usb_table(file, size, argv[2]);
+        else if (strcmp(argv[1], "__mod_pci_device_table") == 0)
+                do_pci_table(file, size, argv[2]);
+        else {
+                fprintf(stderr, "table2alias: unknown type %s\n", argv[1]);
+                exit(1);
+        }
+        exit(0);
+}

--
  Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

             reply	other threads:[~2003-01-31  0:11 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-01-31  0:09 Rusty Russell [this message]
2003-01-31  6:23 ` [PATCH] Module alias and device table support Kai Germaschewski
2003-01-31  9:41   ` Horst von Brand
2003-01-31 15:42     ` Ingo Oeser
2003-01-31 22:33   ` Roman Zippel
2003-02-01  0:48     ` Kai Germaschewski
2003-02-01  1:22       ` Roman Zippel
2003-02-01  2:59         ` Kai Germaschewski
2003-02-01 10:31           ` Roman Zippel
2003-02-01  3:49   ` Rusty Russell
2003-02-01  7:20     ` Kai Germaschewski
2003-02-01 23:02     ` Horst von Brand
2003-02-03  0:52       ` Rusty Russell
2003-02-03  2:49         ` John Levon
2003-02-03 10:34           ` Rusty Russell
2003-02-04  9:56             ` Horst von Brand
2003-02-05  0:00               ` Rusty Russell
2003-02-03  8:31         ` Horst von Brand
2003-02-03 10:52           ` Rusty Russell
2003-02-04  8:05             ` Horst von Brand
2003-02-04  8:51               ` Rusty Russell
2003-02-06 23:09                 ` [PATCH] Restore module support Roman Zippel
2003-02-06 23:25                   ` Greg KH
2003-02-07  0:01                     ` Roman Zippel
2003-02-07  4:06                       ` Greg KH
2003-02-07  9:39                         ` Roman Zippel
2003-02-07 18:01                         ` Roman Zippel
2003-02-07  0:10                     ` Russell King
2003-02-07  4:53                       ` Rusty Russell
2003-02-07 10:03                         ` Russell King
2003-02-07  6:12                       ` Kai Germaschewski
2003-02-07  9:46                         ` Roman Zippel
2003-02-04 14:49               ` [PATCH] Module alias and device table support Roman Zippel
2003-02-03 13:40           ` Roman Zippel
     [not found] <20030201073007$5418@gated-at.bofh.it>
     [not found] ` <20030201073007$3e7f@gated-at.bofh.it>
2003-02-01 10:36   ` Arnd Bergmann
  -- strict thread matches above, loose matches on Subject: below --
2003-02-04 17:25 Adam J. Richter
2003-02-04 17:45 Adam J. Richter
2003-02-05  0:17 ` Rusty Russell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20030131002043.947632C056@lists.samba.org \
    --to=rusty@rustcorp.com.au \
    --cc=greg@kroah.com \
    --cc=jgarzik@pobox.com \
    --cc=kai@tp1.ruhr-uni-bochum.de \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox