aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2008-09-16 16:23:28 -0700
committerDavid Woodhouse <David.Woodhouse@intel.com>2008-10-13 16:05:06 +0100
commitd945b697d0eea5a811ec299c5f1a25889bb0242b (patch)
treee9f902122c05a174eac04464b145bd7a69f261dc
parent9d5a9e74655b9d04d0ec9c8e47801163b7b74211 (diff)
Automatic MODULE_ALIAS() for DMI match tables.
This makes modpost handle MODULE_DEVICE_TABLE(dmi, xxxx). I had to change the string pointers in the match table to char arrays, and picked a size of 79 bytes almost at random -- do we need to make it bigger than that? I was a bit concerned about the 'bloat' this introduces into the match tables, but they should all be __initdata so it shouldn't matter too much. (Actually, modpost does go through the relocations and look at most of them; it wouldn't be impossible to make it handle string pointers -- but doesn't seem to be worth the effort, since they're __initdata). Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--include/linux/dmi.h41
-rw-r--r--include/linux/mod_devicetable.h47
-rw-r--r--scripts/mod/file2alias.c57
3 files changed, 106 insertions, 39 deletions
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index 2a063b64133..e5084eb5943 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -2,29 +2,9 @@
#define __DMI_H__
#include <linux/list.h>
+#include <linux/mod_devicetable.h>
-enum dmi_field {
- DMI_NONE,
- DMI_BIOS_VENDOR,
- DMI_BIOS_VERSION,
- DMI_BIOS_DATE,
- DMI_SYS_VENDOR,
- DMI_PRODUCT_NAME,
- DMI_PRODUCT_VERSION,
- DMI_PRODUCT_SERIAL,
- DMI_PRODUCT_UUID,
- DMI_BOARD_VENDOR,
- DMI_BOARD_NAME,
- DMI_BOARD_VERSION,
- DMI_BOARD_SERIAL,
- DMI_BOARD_ASSET_TAG,
- DMI_CHASSIS_VENDOR,
- DMI_CHASSIS_TYPE,
- DMI_CHASSIS_VERSION,
- DMI_CHASSIS_SERIAL,
- DMI_CHASSIS_ASSET_TAG,
- DMI_STRING_MAX,
-};
+/* enum dmi_field is in mod_devicetable.h */
enum dmi_device_type {
DMI_DEV_TYPE_ANY = 0,
@@ -48,23 +28,6 @@ struct dmi_header {
u16 handle;
};
-/*
- * DMI callbacks for problem boards
- */
-struct dmi_strmatch {
- u8 slot;
- char *substr;
-};
-
-struct dmi_system_id {
- int (*callback)(const struct dmi_system_id *);
- const char *ident;
- struct dmi_strmatch matches[4];
- void *driver_data;
-};
-
-#define DMI_MATCH(a, b) { a, b }
-
struct dmi_device {
struct list_head list;
int type;
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index c4db5827963..3481a7d5bc0 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -388,5 +388,52 @@ struct i2c_device_id {
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
+/* dmi */
+enum dmi_field {
+ DMI_NONE,
+ DMI_BIOS_VENDOR,
+ DMI_BIOS_VERSION,
+ DMI_BIOS_DATE,
+ DMI_SYS_VENDOR,
+ DMI_PRODUCT_NAME,
+ DMI_PRODUCT_VERSION,
+ DMI_PRODUCT_SERIAL,
+ DMI_PRODUCT_UUID,
+ DMI_BOARD_VENDOR,
+ DMI_BOARD_NAME,
+ DMI_BOARD_VERSION,
+ DMI_BOARD_SERIAL,
+ DMI_BOARD_ASSET_TAG,
+ DMI_CHASSIS_VENDOR,
+ DMI_CHASSIS_TYPE,
+ DMI_CHASSIS_VERSION,
+ DMI_CHASSIS_SERIAL,
+ DMI_CHASSIS_ASSET_TAG,
+ DMI_STRING_MAX,
+};
+
+struct dmi_strmatch {
+ unsigned char slot;
+ char substr[79];
+};
+
+#ifndef __KERNEL__
+struct dmi_system_id {
+ kernel_ulong_t callback;
+ kernel_ulong_t ident;
+ struct dmi_strmatch matches[4];
+ kernel_ulong_t driver_data
+ __attribute__((aligned(sizeof(kernel_ulong_t))));
+};
+#else
+struct dmi_system_id {
+ int (*callback)(const struct dmi_system_id *);
+ const char *ident;
+ struct dmi_strmatch matches[4];
+ void *driver_data;
+};
+#endif
+
+#define DMI_MATCH(a, b) { a, b }
#endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 4c9890ec252..473f94e56ea 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -629,6 +629,59 @@ static int do_i2c_entry(const char *filename, struct i2c_device_id *id,
return 1;
}
+static const struct dmifield {
+ const char *prefix;
+ int field;
+} dmi_fields[] = {
+ { "bvn", DMI_BIOS_VENDOR },
+ { "bvr", DMI_BIOS_VERSION },
+ { "bd", DMI_BIOS_DATE },
+ { "svn", DMI_SYS_VENDOR },
+ { "pn", DMI_PRODUCT_NAME },
+ { "pvr", DMI_PRODUCT_VERSION },
+ { "rvn", DMI_BOARD_VENDOR },
+ { "rn", DMI_BOARD_NAME },
+ { "rvr", DMI_BOARD_VERSION },
+ { "cvn", DMI_CHASSIS_VENDOR },
+ { "ct", DMI_CHASSIS_TYPE },
+ { "cvr", DMI_CHASSIS_VERSION },
+ { NULL, DMI_NONE }
+};
+
+static void dmi_ascii_filter(char *d, const char *s)
+{
+ /* Filter out characters we don't want to see in the modalias string */
+ for (; *s; s++)
+ if (*s > ' ' && *s < 127 && *s != ':')
+ *(d++) = *s;
+
+ *d = 0;
+}
+
+
+static int do_dmi_entry(const char *filename, struct dmi_system_id *id,
+ char *alias)
+{
+ int i, j;
+
+ sprintf(alias, "dmi*");
+
+ for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) {
+ for (j = 0; j < 4; j++) {
+ if (id->matches[j].slot &&
+ id->matches[j].slot == dmi_fields[i].field) {
+ sprintf(alias + strlen(alias), ":%s*",
+ dmi_fields[i].prefix);
+ dmi_ascii_filter(alias + strlen(alias),
+ id->matches[j].substr);
+ strcat(alias, "*");
+ }
+ }
+ }
+
+ strcat(alias, ":");
+ return 1;
+}
/* Ignore any prefix, eg. some architectures prepend _ */
static inline int sym_is(const char *symbol, const char *name)
{
@@ -760,6 +813,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
do_table(symval, sym->st_size,
sizeof(struct i2c_device_id), "i2c",
do_i2c_entry, mod);
+ else if (sym_is(symname, "__mod_dmi_device_table"))
+ do_table(symval, sym->st_size,
+ sizeof(struct dmi_system_id), "dmi",
+ do_dmi_entry, mod);
free(zeros);
}