aboutsummaryrefslogtreecommitdiff
path: root/drivers/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/Kconfig9
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/dcdbas.c10
-rw-r--r--drivers/firmware/dcdbas.h3
-rw-r--r--drivers/firmware/dell_rbu.c31
-rw-r--r--drivers/firmware/dmi-id.c222
-rw-r--r--drivers/firmware/dmi_scan.c73
-rw-r--r--drivers/firmware/edd.c2
-rw-r--r--drivers/firmware/efivars.c6
9 files changed, 328 insertions, 29 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 88f462122a30..05f02a326f1c 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -84,4 +84,13 @@ config DCDBAS
Say Y or M here to enable the driver for use by Dell systems
management software such as Dell OpenManage.
+config DMIID
+ bool "Export DMI identification via sysfs to userspace"
+ depends on DMI
+ default y
+ help
+ Say Y here if you want to query SMBIOS/DMI system identification
+ information from userspace through /sys/class/dmi/id/ or if you want
+ DMI-based module auto-loading.
+
endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 98e395f4bb29..8d4ebc805a50 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_EFI_VARS) += efivars.o
obj-$(CONFIG_EFI_PCDP) += pcdp.o
obj-$(CONFIG_DELL_RBU) += dell_rbu.o
obj-$(CONFIG_DCDBAS) += dcdbas.o
+obj-$(CONFIG_DMIID) += dmi-id.o
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index 1865b56fb141..18cdcb3ae1ca 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -149,8 +149,9 @@ static ssize_t smi_data_buf_size_store(struct device *dev,
return count;
}
-static ssize_t smi_data_read(struct kobject *kobj, char *buf, loff_t pos,
- size_t count)
+static ssize_t smi_data_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t count)
{
size_t max_read;
ssize_t ret;
@@ -170,8 +171,9 @@ out:
return ret;
}
-static ssize_t smi_data_write(struct kobject *kobj, char *buf, loff_t pos,
- size_t count)
+static ssize_t smi_data_write(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t count)
{
ssize_t ret;
diff --git a/drivers/firmware/dcdbas.h b/drivers/firmware/dcdbas.h
index 58a85182b3e8..dcdba0f1b32c 100644
--- a/drivers/firmware/dcdbas.h
+++ b/drivers/firmware/dcdbas.h
@@ -67,8 +67,7 @@
#define DCDBAS_BIN_ATTR_RW(_name) \
struct bin_attribute bin_attr_##_name = { \
.attr = { .name = __stringify(_name), \
- .mode = 0600, \
- .owner = THIS_MODULE }, \
+ .mode = 0600 }, \
.read = _name##_read, \
.write = _name##_write, \
}
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
index fc702e40bd43..477a3d0e3caf 100644
--- a/drivers/firmware/dell_rbu.c
+++ b/drivers/firmware/dell_rbu.c
@@ -543,8 +543,9 @@ static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count)
return ret_count;
}
-static ssize_t read_rbu_data(struct kobject *kobj, char *buffer,
- loff_t pos, size_t count)
+static ssize_t read_rbu_data(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
{
ssize_t ret_count = 0;
@@ -591,8 +592,9 @@ static void callbackfn_rbu(const struct firmware *fw, void *context)
spin_unlock(&rbu_data.lock);
}
-static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer,
- loff_t pos, size_t count)
+static ssize_t read_rbu_image_type(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
{
int size = 0;
if (!pos)
@@ -600,8 +602,9 @@ static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer,
return size;
}
-static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer,
- loff_t pos, size_t count)
+static ssize_t write_rbu_image_type(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
{
int rc = count;
int req_firm_rc = 0;
@@ -660,8 +663,9 @@ static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer,
return rc;
}
-static ssize_t read_rbu_packet_size(struct kobject *kobj, char *buffer,
- loff_t pos, size_t count)
+static ssize_t read_rbu_packet_size(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
{
int size = 0;
if (!pos) {
@@ -672,8 +676,9 @@ static ssize_t read_rbu_packet_size(struct kobject *kobj, char *buffer,
return size;
}
-static ssize_t write_rbu_packet_size(struct kobject *kobj, char *buffer,
- loff_t pos, size_t count)
+static ssize_t write_rbu_packet_size(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
{
unsigned long temp;
spin_lock(&rbu_data.lock);
@@ -687,18 +692,18 @@ static ssize_t write_rbu_packet_size(struct kobject *kobj, char *buffer,
}
static struct bin_attribute rbu_data_attr = {
- .attr = {.name = "data",.owner = THIS_MODULE,.mode = 0444},
+ .attr = {.name = "data", .mode = 0444},
.read = read_rbu_data,
};
static struct bin_attribute rbu_image_type_attr = {
- .attr = {.name = "image_type",.owner = THIS_MODULE,.mode = 0644},
+ .attr = {.name = "image_type", .mode = 0644},
.read = read_rbu_image_type,
.write = write_rbu_image_type,
};
static struct bin_attribute rbu_packet_size_attr = {
- .attr = {.name = "packet_size",.owner = THIS_MODULE,.mode = 0644},
+ .attr = {.name = "packet_size", .mode = 0644},
.read = read_rbu_packet_size,
.write = write_rbu_packet_size,
};
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
new file mode 100644
index 000000000000..59c3b5aa89f4
--- /dev/null
+++ b/drivers/firmware/dmi-id.c
@@ -0,0 +1,222 @@
+/*
+ * Export SMBIOS/DMI info via sysfs to userspace
+ *
+ * Copyright 2007, Lennart Poettering
+ *
+ * Licensed under GPLv2
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <linux/device.h>
+#include <linux/autoconf.h>
+
+#define DEFINE_DMI_ATTR(_name, _mode, _show) \
+static struct device_attribute sys_dmi_##_name##_attr = \
+ __ATTR(_name, _mode, _show, NULL);
+
+#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \
+static ssize_t sys_dmi_##_name##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *page) \
+{ \
+ ssize_t len; \
+ len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \
+ page[len-1] = '\n'; \
+ return len; \
+} \
+DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show);
+
+DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor, 0444, DMI_BIOS_VENDOR);
+DEFINE_DMI_ATTR_WITH_SHOW(bios_version, 0444, DMI_BIOS_VERSION);
+DEFINE_DMI_ATTR_WITH_SHOW(bios_date, 0444, DMI_BIOS_DATE);
+DEFINE_DMI_ATTR_WITH_SHOW(sys_vendor, 0444, DMI_SYS_VENDOR);
+DEFINE_DMI_ATTR_WITH_SHOW(product_name, 0444, DMI_PRODUCT_NAME);
+DEFINE_DMI_ATTR_WITH_SHOW(product_version, 0444, DMI_PRODUCT_VERSION);
+DEFINE_DMI_ATTR_WITH_SHOW(product_serial, 0400, DMI_PRODUCT_SERIAL);
+DEFINE_DMI_ATTR_WITH_SHOW(product_uuid, 0400, DMI_PRODUCT_UUID);
+DEFINE_DMI_ATTR_WITH_SHOW(board_vendor, 0444, DMI_BOARD_VENDOR);
+DEFINE_DMI_ATTR_WITH_SHOW(board_name, 0444, DMI_BOARD_NAME);
+DEFINE_DMI_ATTR_WITH_SHOW(board_version, 0444, DMI_BOARD_VERSION);
+DEFINE_DMI_ATTR_WITH_SHOW(board_serial, 0400, DMI_BOARD_SERIAL);
+DEFINE_DMI_ATTR_WITH_SHOW(board_asset_tag, 0444, DMI_BOARD_ASSET_TAG);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_vendor, 0444, DMI_CHASSIS_VENDOR);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_type, 0444, DMI_CHASSIS_TYPE);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_version, 0444, DMI_CHASSIS_VERSION);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_serial, 0400, DMI_CHASSIS_SERIAL);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_asset_tag, 0444, DMI_CHASSIS_ASSET_TAG);
+
+static void 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 ssize_t get_modalias(char *buffer, size_t buffer_size)
+{
+ static const struct mafield {
+ const char *prefix;
+ int field;
+ } 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 }
+ };
+
+ ssize_t l, left;
+ char *p;
+ const struct mafield *f;
+
+ strcpy(buffer, "dmi");
+ p = buffer + 3; left = buffer_size - 4;
+
+ for (f = fields; f->prefix && left > 0; f++) {
+ const char *c;
+ char *t;
+
+ c = dmi_get_system_info(f->field);
+ if (!c)
+ continue;
+
+ t = kmalloc(strlen(c) + 1, GFP_KERNEL);
+ if (!t)
+ break;
+ ascii_filter(t, c);
+ l = scnprintf(p, left, ":%s%s", f->prefix, t);
+ kfree(t);
+
+ p += l;
+ left -= l;
+ }
+
+ p[0] = ':';
+ p[1] = 0;
+
+ return p - buffer + 1;
+}
+
+static ssize_t sys_dmi_modalias_show(struct device *dev,
+ struct device_attribute *attr, char *page)
+{
+ ssize_t r;
+ r = get_modalias(page, PAGE_SIZE-1);
+ page[r] = '\n';
+ page[r+1] = 0;
+ return r+1;
+}
+
+DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show);
+
+static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2];
+
+static struct attribute_group sys_dmi_attribute_group = {
+ .attrs = sys_dmi_attributes,
+};
+
+static struct attribute_group* sys_dmi_attribute_groups[] = {
+ &sys_dmi_attribute_group,
+ NULL
+};
+
+static int dmi_dev_uevent(struct device *dev, char **envp,
+ int num_envp, char *buffer, int buffer_size)
+{
+ strcpy(buffer, "MODALIAS=");
+ get_modalias(buffer+9, buffer_size-9);
+ envp[0] = buffer;
+ envp[1] = NULL;
+
+ return 0;
+}
+
+static struct class dmi_class = {
+ .name = "dmi",
+ .dev_release = (void(*)(struct device *)) kfree,
+ .dev_uevent = dmi_dev_uevent,
+};
+
+static struct device *dmi_dev;
+
+/* Initialization */
+
+#define ADD_DMI_ATTR(_name, _field) \
+ if (dmi_get_system_info(_field)) \
+ sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr;
+
+extern int dmi_available;
+
+static int __init dmi_id_init(void)
+{
+ int ret, i;
+
+ if (!dmi_available)
+ return -ENODEV;
+
+ /* Not necessarily all DMI fields are available on all
+ * systems, hence let's built an attribute table of just
+ * what's available */
+ i = 0;
+ ADD_DMI_ATTR(bios_vendor, DMI_BIOS_VENDOR);
+ ADD_DMI_ATTR(bios_version, DMI_BIOS_VERSION);
+ ADD_DMI_ATTR(bios_date, DMI_BIOS_DATE);
+ ADD_DMI_ATTR(sys_vendor, DMI_SYS_VENDOR);
+ ADD_DMI_ATTR(product_name, DMI_PRODUCT_NAME);
+ ADD_DMI_ATTR(product_version, DMI_PRODUCT_VERSION);
+ ADD_DMI_ATTR(product_serial, DMI_PRODUCT_SERIAL);
+ ADD_DMI_ATTR(product_uuid, DMI_PRODUCT_UUID);
+ ADD_DMI_ATTR(board_vendor, DMI_BOARD_VENDOR);
+ ADD_DMI_ATTR(board_name, DMI_BOARD_NAME);
+ ADD_DMI_ATTR(board_version, DMI_BOARD_VERSION);
+ ADD_DMI_ATTR(board_serial, DMI_BOARD_SERIAL);
+ ADD_DMI_ATTR(board_asset_tag, DMI_BOARD_ASSET_TAG);
+ ADD_DMI_ATTR(chassis_vendor, DMI_CHASSIS_VENDOR);
+ ADD_DMI_ATTR(chassis_type, DMI_CHASSIS_TYPE);
+ ADD_DMI_ATTR(chassis_version, DMI_CHASSIS_VERSION);
+ ADD_DMI_ATTR(chassis_serial, DMI_CHASSIS_SERIAL);
+ ADD_DMI_ATTR(chassis_asset_tag, DMI_CHASSIS_ASSET_TAG);
+ sys_dmi_attributes[i++] = &sys_dmi_modalias_attr.attr;
+
+ ret = class_register(&dmi_class);
+ if (ret)
+ return ret;
+
+ dmi_dev = kzalloc(sizeof(*dmi_dev), GFP_KERNEL);
+ if (!dmi_dev) {
+ ret = -ENOMEM;
+ goto fail_class_unregister;
+ }
+
+ dmi_dev->class = &dmi_class;
+ strcpy(dmi_dev->bus_id, "id");
+ dmi_dev->groups = sys_dmi_attribute_groups;
+
+ ret = device_register(dmi_dev);
+ if (ret)
+ goto fail_class_unregister;
+
+ return 0;
+
+fail_class_unregister:
+
+ class_unregister(&dmi_class);
+
+ return ret;
+}
+
+arch_initcall(dmi_id_init);
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 37deee6c0c1c..f7318b3b51f2 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -84,6 +84,7 @@ static int __init dmi_checksum(u8 *buf)
static char *dmi_ident[DMI_STRING_MAX];
static LIST_HEAD(dmi_devices);
+int dmi_available;
/*
* Save a DMI string
@@ -102,6 +103,51 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
dmi_ident[slot] = p;
}
+static void __init dmi_save_uuid(struct dmi_header *dm, int slot, int index)
+{
+ u8 *d = (u8*) dm + index;
+ char *s;
+ int is_ff = 1, is_00 = 1, i;
+
+ if (dmi_ident[slot])
+ return;
+
+ for (i = 0; i < 16 && (is_ff || is_00); i++) {
+ if(d[i] != 0x00) is_ff = 0;
+ if(d[i] != 0xFF) is_00 = 0;
+ }
+
+ if (is_ff || is_00)
+ return;
+
+ s = dmi_alloc(16*2+4+1);
+ if (!s)
+ return;
+
+ sprintf(s,
+ "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
+ d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
+
+ dmi_ident[slot] = s;
+}
+
+static void __init dmi_save_type(struct dmi_header *dm, int slot, int index)
+{
+ u8 *d = (u8*) dm + index;
+ char *s;
+
+ if (dmi_ident[slot])
+ return;
+
+ s = dmi_alloc(4);
+ if (!s)
+ return;
+
+ sprintf(s, "%u", *d & 0x7F);
+ dmi_ident[slot] = s;
+}
+
static void __init dmi_save_devices(struct dmi_header *dm)
{
int i, count = (dm->length - sizeof(struct dmi_header)) / 2;
@@ -192,11 +238,21 @@ static void __init dmi_decode(struct dmi_header *dm)
dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
+ dmi_save_uuid(dm, DMI_PRODUCT_UUID, 8);
break;
case 2: /* Base Board Information */
dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
dmi_save_ident(dm, DMI_BOARD_NAME, 5);
dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
+ dmi_save_ident(dm, DMI_BOARD_SERIAL, 7);
+ dmi_save_ident(dm, DMI_BOARD_ASSET_TAG, 8);
+ break;
+ case 3: /* Chassis Information */
+ dmi_save_ident(dm, DMI_CHASSIS_VENDOR, 4);
+ dmi_save_type(dm, DMI_CHASSIS_TYPE, 5);
+ dmi_save_ident(dm, DMI_CHASSIS_VERSION, 6);
+ dmi_save_ident(dm, DMI_CHASSIS_SERIAL, 7);
+ dmi_save_ident(dm, DMI_CHASSIS_ASSET_TAG, 8);
break;
case 10: /* Onboard Devices Information */
dmi_save_devices(dm);
@@ -243,18 +299,20 @@ void __init dmi_scan_machine(void)
if (efi.smbios == EFI_INVALID_TABLE_ADDR)
goto out;
- /* This is called as a core_initcall() because it isn't
- * needed during early boot. This also means we can
- * iounmap the space when we're done with it.
- */
+ /* This is called as a core_initcall() because it isn't
+ * needed during early boot. This also means we can
+ * iounmap the space when we're done with it.
+ */
p = dmi_ioremap(efi.smbios, 32);
if (p == NULL)
goto out;
rc = dmi_present(p + 0x10); /* offset of _DMI_ string */
dmi_iounmap(p, 32);
- if (!rc)
+ if (!rc) {
+ dmi_available = 1;
return;
+ }
}
else {
/*
@@ -268,8 +326,10 @@ void __init dmi_scan_machine(void)
for (q = p; q < p + 0x10000; q += 16) {
rc = dmi_present(q);
- if (!rc)
+ if (!rc) {
+ dmi_available = 1;
return;
+ }
}
}
out: printk(KERN_INFO "DMI not present or invalid.\n");
@@ -404,3 +464,4 @@ int dmi_get_year(int field)
return year;
}
+
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index d8806e4f1829..15232271d848 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -74,7 +74,7 @@ static struct edd_device *edd_devices[EDD_MBR_SIG_MAX];
#define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \
struct edd_attribute edd_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.test = _test, \
};
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 1324984a4c35..bfd2d67df689 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -131,21 +131,21 @@ struct efivar_attribute {
#define EFI_ATTR(_name, _mode, _show, _store) \
struct subsys_attribute efi_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
+ .attr = {.name = __stringify(_name), .mode = _mode}, \
.show = _show, \
.store = _store, \
};
#define EFIVAR_ATTR(_name, _mode, _show, _store) \
struct efivar_attribute efivar_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
+ .attr = {.name = __stringify(_name), .mode = _mode}, \
.show = _show, \
.store = _store, \
};
#define VAR_SUBSYS_ATTR(_name, _mode, _show, _store) \
struct subsys_attribute var_subsys_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
+ .attr = {.name = __stringify(_name), .mode = _mode}, \
.show = _show, \
.store = _store, \
};