aboutsummaryrefslogtreecommitdiffstats
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/dmi-id.c222
-rw-r--r--drivers/firmware/dmi_scan.c73
4 files changed, 299 insertions, 6 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
84 Say Y or M here to enable the driver for use by Dell systems 84 Say Y or M here to enable the driver for use by Dell systems
85 management software such as Dell OpenManage. 85 management software such as Dell OpenManage.
86 86
87config DMIID
88 bool "Export DMI identification via sysfs to userspace"
89 depends on DMI
90 default y
91 help
92 Say Y here if you want to query SMBIOS/DMI system identification
93 information from userspace through /sys/class/dmi/id/ or if you want
94 DMI-based module auto-loading.
95
87endmenu 96endmenu
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
7obj-$(CONFIG_EFI_PCDP) += pcdp.o 7obj-$(CONFIG_EFI_PCDP) += pcdp.o
8obj-$(CONFIG_DELL_RBU) += dell_rbu.o 8obj-$(CONFIG_DELL_RBU) += dell_rbu.o
9obj-$(CONFIG_DCDBAS) += dcdbas.o 9obj-$(CONFIG_DCDBAS) += dcdbas.o
10obj-$(CONFIG_DMIID) += dmi-id.o
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 @@
1/*
2 * Export SMBIOS/DMI info via sysfs to userspace
3 *
4 * Copyright 2007, Lennart Poettering
5 *
6 * Licensed under GPLv2
7 */
8
9#include <linux/module.h>
10#include <linux/kernel.h>
11#include <linux/init.h>
12#include <linux/dmi.h>
13#include <linux/device.h>
14#include <linux/autoconf.h>
15
16#define DEFINE_DMI_ATTR(_name, _mode, _show) \
17static struct device_attribute sys_dmi_##_name##_attr = \
18 __ATTR(_name, _mode, _show, NULL);
19
20#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \
21static ssize_t sys_dmi_##_name##_show(struct device *dev, \
22 struct device_attribute *attr, \
23 char *page) \
24{ \
25 ssize_t len; \
26 len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \
27 page[len-1] = '\n'; \
28 return len; \
29} \
30DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show);
31
32DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor, 0444, DMI_BIOS_VENDOR);
33DEFINE_DMI_ATTR_WITH_SHOW(bios_version, 0444, DMI_BIOS_VERSION);
34DEFINE_DMI_ATTR_WITH_SHOW(bios_date, 0444, DMI_BIOS_DATE);
35DEFINE_DMI_ATTR_WITH_SHOW(sys_vendor, 0444, DMI_SYS_VENDOR);
36DEFINE_DMI_ATTR_WITH_SHOW(product_name, 0444, DMI_PRODUCT_NAME);
37DEFINE_DMI_ATTR_WITH_SHOW(product_version, 0444, DMI_PRODUCT_VERSION);
38DEFINE_DMI_ATTR_WITH_SHOW(product_serial, 0400, DMI_PRODUCT_SERIAL);
39DEFINE_DMI_ATTR_WITH_SHOW(product_uuid, 0400, DMI_PRODUCT_UUID);
40DEFINE_DMI_ATTR_WITH_SHOW(board_vendor, 0444, DMI_BOARD_VENDOR);
41DEFINE_DMI_ATTR_WITH_SHOW(board_name, 0444, DMI_BOARD_NAME);
42DEFINE_DMI_ATTR_WITH_SHOW(board_version, 0444, DMI_BOARD_VERSION);
43DEFINE_DMI_ATTR_WITH_SHOW(board_serial, 0400, DMI_BOARD_SERIAL);
44DEFINE_DMI_ATTR_WITH_SHOW(board_asset_tag, 0444, DMI_BOARD_ASSET_TAG);
45DEFINE_DMI_ATTR_WITH_SHOW(chassis_vendor, 0444, DMI_CHASSIS_VENDOR);
46DEFINE_DMI_ATTR_WITH_SHOW(chassis_type, 0444, DMI_CHASSIS_TYPE);
47DEFINE_DMI_ATTR_WITH_SHOW(chassis_version, 0444, DMI_CHASSIS_VERSION);
48DEFINE_DMI_ATTR_WITH_SHOW(chassis_serial, 0400, DMI_CHASSIS_SERIAL);
49DEFINE_DMI_ATTR_WITH_SHOW(chassis_asset_tag, 0444, DMI_CHASSIS_ASSET_TAG);
50
51static void ascii_filter(char *d, const char *s)
52{
53 /* Filter out characters we don't want to see in the modalias string */
54 for (; *s; s++)
55 if (*s > ' ' && *s < 127 && *s != ':')
56 *(d++) = *s;
57
58 *d = 0;
59}
60
61static ssize_t get_modalias(char *buffer, size_t buffer_size)
62{
63 static const struct mafield {
64 const char *prefix;
65 int field;
66 } fields[] = {
67 { "bvn", DMI_BIOS_VENDOR },
68 { "bvr", DMI_BIOS_VERSION },
69 { "bd", DMI_BIOS_DATE },
70 { "svn", DMI_SYS_VENDOR },
71 { "pn", DMI_PRODUCT_NAME },
72 { "pvr", DMI_PRODUCT_VERSION },
73 { "rvn", DMI_BOARD_VENDOR },
74 { "rn", DMI_BOARD_NAME },
75 { "rvr", DMI_BOARD_VERSION },
76 { "cvn", DMI_CHASSIS_VENDOR },
77 { "ct", DMI_CHASSIS_TYPE },
78 { "cvr", DMI_CHASSIS_VERSION },
79 { NULL, DMI_NONE }
80 };
81
82 ssize_t l, left;
83 char *p;
84 const struct mafield *f;
85
86 strcpy(buffer, "dmi");
87 p = buffer + 3; left = buffer_size - 4;
88
89 for (f = fields; f->prefix && left > 0; f++) {
90 const char *c;
91 char *t;
92
93 c = dmi_get_system_info(f->field);
94 if (!c)
95 continue;
96
97 t = kmalloc(strlen(c) + 1, GFP_KERNEL);
98 if (!t)
99 break;
100 ascii_filter(t, c);
101 l = scnprintf(p, left, ":%s%s", f->prefix, t);
102 kfree(t);
103
104 p += l;
105 left -= l;
106 }
107
108 p[0] = ':';
109 p[1] = 0;
110
111 return p - buffer + 1;
112}
113
114static ssize_t sys_dmi_modalias_show(struct device *dev,
115 struct device_attribute *attr, char *page)
116{
117 ssize_t r;
118 r = get_modalias(page, PAGE_SIZE-1);
119 page[r] = '\n';
120 page[r+1] = 0;
121 return r+1;
122}
123
124DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show);
125
126static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2];
127
128static struct attribute_group sys_dmi_attribute_group = {
129 .attrs = sys_dmi_attributes,
130};
131
132static struct attribute_group* sys_dmi_attribute_groups[] = {
133 &sys_dmi_attribute_group,
134 NULL
135};
136
137static int dmi_dev_uevent(struct device *dev, char **envp,
138 int num_envp, char *buffer, int buffer_size)
139{
140 strcpy(buffer, "MODALIAS=");
141 get_modalias(buffer+9, buffer_size-9);
142 envp[0] = buffer;
143 envp[1] = NULL;
144
145 return 0;
146}
147
148static struct class dmi_class = {
149 .name = "dmi",
150 .dev_release = (void(*)(struct device *)) kfree,
151 .dev_uevent = dmi_dev_uevent,
152};
153
154static struct device *dmi_dev;
155
156/* Initialization */
157
158#define ADD_DMI_ATTR(_name, _field) \
159 if (dmi_get_system_info(_field)) \
160 sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr;
161
162extern int dmi_available;
163
164static int __init dmi_id_init(void)
165{
166 int ret, i;
167
168 if (!dmi_available)
169 return -ENODEV;
170
171 /* Not necessarily all DMI fields are available on all
172 * systems, hence let's built an attribute table of just
173 * what's available */
174 i = 0;
175 ADD_DMI_ATTR(bios_vendor, DMI_BIOS_VENDOR);
176 ADD_DMI_ATTR(bios_version, DMI_BIOS_VERSION);
177 ADD_DMI_ATTR(bios_date, DMI_BIOS_DATE);
178 ADD_DMI_ATTR(sys_vendor, DMI_SYS_VENDOR);
179 ADD_DMI_ATTR(product_name, DMI_PRODUCT_NAME);
180 ADD_DMI_ATTR(product_version, DMI_PRODUCT_VERSION);
181 ADD_DMI_ATTR(product_serial, DMI_PRODUCT_SERIAL);
182 ADD_DMI_ATTR(product_uuid, DMI_PRODUCT_UUID);
183 ADD_DMI_ATTR(board_vendor, DMI_BOARD_VENDOR);
184 ADD_DMI_ATTR(board_name, DMI_BOARD_NAME);
185 ADD_DMI_ATTR(board_version, DMI_BOARD_VERSION);
186 ADD_DMI_ATTR(board_serial, DMI_BOARD_SERIAL);
187 ADD_DMI_ATTR(board_asset_tag, DMI_BOARD_ASSET_TAG);
188 ADD_DMI_ATTR(chassis_vendor, DMI_CHASSIS_VENDOR);
189 ADD_DMI_ATTR(chassis_type, DMI_CHASSIS_TYPE);
190 ADD_DMI_ATTR(chassis_version, DMI_CHASSIS_VERSION);
191 ADD_DMI_ATTR(chassis_serial, DMI_CHASSIS_SERIAL);
192 ADD_DMI_ATTR(chassis_asset_tag, DMI_CHASSIS_ASSET_TAG);
193 sys_dmi_attributes[i++] = &sys_dmi_modalias_attr.attr;
194
195 ret = class_register(&dmi_class);
196 if (ret)
197 return ret;
198
199 dmi_dev = kzalloc(sizeof(*dmi_dev), GFP_KERNEL);
200 if (!dmi_dev) {
201 ret = -ENOMEM;
202 goto fail_class_unregister;
203 }
204
205 dmi_dev->class = &dmi_class;
206 strcpy(dmi_dev->bus_id, "id");
207 dmi_dev->groups = sys_dmi_attribute_groups;
208
209 ret = device_register(dmi_dev);
210 if (ret)
211 goto fail_class_unregister;
212
213 return 0;
214
215fail_class_unregister:
216
217 class_unregister(&dmi_class);
218
219 return ret;
220}
221
222arch_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)
84 84
85static char *dmi_ident[DMI_STRING_MAX]; 85static char *dmi_ident[DMI_STRING_MAX];
86static LIST_HEAD(dmi_devices); 86static LIST_HEAD(dmi_devices);
87int dmi_available;
87 88
88/* 89/*
89 * Save a DMI string 90 * Save a DMI string
@@ -102,6 +103,51 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
102 dmi_ident[slot] = p; 103 dmi_ident[slot] = p;
103} 104}
104 105
106static void __init dmi_save_uuid(struct dmi_header *dm, int slot, int index)
107{
108 u8 *d = (u8*) dm + index;
109 char *s;
110 int is_ff = 1, is_00 = 1, i;
111
112 if (dmi_ident[slot])
113 return;
114
115 for (i = 0; i < 16 && (is_ff || is_00); i++) {
116 if(d[i] != 0x00) is_ff = 0;
117 if(d[i] != 0xFF) is_00 = 0;
118 }
119
120 if (is_ff || is_00)
121 return;
122
123 s = dmi_alloc(16*2+4+1);
124 if (!s)
125 return;
126
127 sprintf(s,
128 "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
129 d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
130 d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
131
132 dmi_ident[slot] = s;
133}
134
135static void __init dmi_save_type(struct dmi_header *dm, int slot, int index)
136{
137 u8 *d = (u8*) dm + index;
138 char *s;
139
140 if (dmi_ident[slot])
141 return;
142
143 s = dmi_alloc(4);
144 if (!s)
145 return;
146
147 sprintf(s, "%u", *d & 0x7F);
148 dmi_ident[slot] = s;
149}
150
105static void __init dmi_save_devices(struct dmi_header *dm) 151static void __init dmi_save_devices(struct dmi_header *dm)
106{ 152{
107 int i, count = (dm->length - sizeof(struct dmi_header)) / 2; 153 int i, count = (dm->length - sizeof(struct dmi_header)) / 2;
@@ -192,11 +238,21 @@ static void __init dmi_decode(struct dmi_header *dm)
192 dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); 238 dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
193 dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); 239 dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
194 dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7); 240 dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
241 dmi_save_uuid(dm, DMI_PRODUCT_UUID, 8);
195 break; 242 break;
196 case 2: /* Base Board Information */ 243 case 2: /* Base Board Information */
197 dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); 244 dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
198 dmi_save_ident(dm, DMI_BOARD_NAME, 5); 245 dmi_save_ident(dm, DMI_BOARD_NAME, 5);
199 dmi_save_ident(dm, DMI_BOARD_VERSION, 6); 246 dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
247 dmi_save_ident(dm, DMI_BOARD_SERIAL, 7);
248 dmi_save_ident(dm, DMI_BOARD_ASSET_TAG, 8);
249 break;
250 case 3: /* Chassis Information */
251 dmi_save_ident(dm, DMI_CHASSIS_VENDOR, 4);
252 dmi_save_type(dm, DMI_CHASSIS_TYPE, 5);
253 dmi_save_ident(dm, DMI_CHASSIS_VERSION, 6);
254 dmi_save_ident(dm, DMI_CHASSIS_SERIAL, 7);
255 dmi_save_ident(dm, DMI_CHASSIS_ASSET_TAG, 8);
200 break; 256 break;
201 case 10: /* Onboard Devices Information */ 257 case 10: /* Onboard Devices Information */
202 dmi_save_devices(dm); 258 dmi_save_devices(dm);
@@ -243,18 +299,20 @@ void __init dmi_scan_machine(void)
243 if (efi.smbios == EFI_INVALID_TABLE_ADDR) 299 if (efi.smbios == EFI_INVALID_TABLE_ADDR)
244 goto out; 300 goto out;
245 301
246 /* This is called as a core_initcall() because it isn't 302 /* This is called as a core_initcall() because it isn't
247 * needed during early boot. This also means we can 303 * needed during early boot. This also means we can
248 * iounmap the space when we're done with it. 304 * iounmap the space when we're done with it.
249 */ 305 */
250 p = dmi_ioremap(efi.smbios, 32); 306 p = dmi_ioremap(efi.smbios, 32);
251 if (p == NULL) 307 if (p == NULL)
252 goto out; 308 goto out;
253 309
254 rc = dmi_present(p + 0x10); /* offset of _DMI_ string */ 310 rc = dmi_present(p + 0x10); /* offset of _DMI_ string */
255 dmi_iounmap(p, 32); 311 dmi_iounmap(p, 32);
256 if (!rc) 312 if (!rc) {
313 dmi_available = 1;
257 return; 314 return;
315 }
258 } 316 }
259 else { 317 else {
260 /* 318 /*
@@ -268,8 +326,10 @@ void __init dmi_scan_machine(void)
268 326
269 for (q = p; q < p + 0x10000; q += 16) { 327 for (q = p; q < p + 0x10000; q += 16) {
270 rc = dmi_present(q); 328 rc = dmi_present(q);
271 if (!rc) 329 if (!rc) {
330 dmi_available = 1;
272 return; 331 return;
332 }
273 } 333 }
274 } 334 }
275 out: printk(KERN_INFO "DMI not present or invalid.\n"); 335 out: printk(KERN_INFO "DMI not present or invalid.\n");
@@ -404,3 +464,4 @@ int dmi_get_year(int field)
404 464
405 return year; 465 return year;
406} 466}
467