Blame view

drivers/firmware/dmi-id.c 6.62 KB
4f5c791a8   Lennart Poettering   DMI-based module ...
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * 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>
5a0e3ad6a   Tejun Heo   include cleanup: ...
14
  #include <linux/slab.h>
4f5c791a8   Lennart Poettering   DMI-based module ...
15

637447566   Jean Delvare   dmi-id: Use dynam...
16
17
18
19
20
21
  struct dmi_device_attribute{
  	struct device_attribute dev_attr;
  	int field;
  };
  #define to_dmi_dev_attr(_dev_attr) \
  	container_of(_dev_attr, struct dmi_device_attribute, dev_attr)
637447566   Jean Delvare   dmi-id: Use dynam...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
  static ssize_t sys_dmi_field_show(struct device *dev,
  				  struct device_attribute *attr,
  				  char *page)
  {
  	int field = to_dmi_dev_attr(attr)->field;
  	ssize_t len;
  	len = scnprintf(page, PAGE_SIZE, "%s
  ", dmi_get_system_info(field));
  	page[len-1] = '
  ';
  	return len;
  }
  
  #define DMI_ATTR(_name, _mode, _show, _field)			\
  	{ .dev_attr = __ATTR(_name, _mode, _show, NULL),	\
  	  .field = _field }
  
  #define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field)		\
  static struct dmi_device_attribute sys_dmi_##_name##_attr =	\
  	DMI_ATTR(_name, _mode, sys_dmi_field_show, _field);
4f5c791a8   Lennart Poettering   DMI-based module ...
42
43
44
45
46
47
48
49
50
  
  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);
e0733e975   Jean Delvare   firmware: dmi: Fi...
51
  DEFINE_DMI_ATTR_WITH_SHOW(product_family,	0444, DMI_PRODUCT_FAMILY);
4f5c791a8   Lennart Poettering   DMI-based module ...
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  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] = '
  ';
  	page[r+1] = 0;
  	return r+1;
  }
34b51f39e   Jean Delvare   dmi-id: Possible ...
136
137
  static struct device_attribute sys_dmi_modalias_attr =
  	__ATTR(modalias, 0444, sys_dmi_modalias_show, NULL);
4f5c791a8   Lennart Poettering   DMI-based module ...
138
139
140
141
142
143
  
  static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2];
  
  static struct attribute_group sys_dmi_attribute_group = {
  	.attrs = sys_dmi_attributes,
  };
a4dbd6740   David Brownell   driver model: con...
144
  static const struct attribute_group* sys_dmi_attribute_groups[] = {
4f5c791a8   Lennart Poettering   DMI-based module ...
145
146
147
  	&sys_dmi_attribute_group,
  	NULL
  };
7eff2e7a8   Kay Sievers   Driver core: chan...
148
  static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
4f5c791a8   Lennart Poettering   DMI-based module ...
149
  {
7eff2e7a8   Kay Sievers   Driver core: chan...
150
151
152
153
154
155
156
157
158
  	ssize_t len;
  
  	if (add_uevent_var(env, "MODALIAS="))
  		return -ENOMEM;
  	len = get_modalias(&env->buf[env->buflen - 1],
  			   sizeof(env->buf) - env->buflen);
  	if (len >= (sizeof(env->buf) - env->buflen))
  		return -ENOMEM;
  	env->buflen += len;
4f5c791a8   Lennart Poettering   DMI-based module ...
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  	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)) \
637447566   Jean Delvare   dmi-id: Use dynam...
174
  		sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr;
4f5c791a8   Lennart Poettering   DMI-based module ...
175

ce8c628ab   Jean Delvare   dmi-id: fix for _...
176
177
178
  /* In a separate function to keep gcc 3.2 happy - do NOT merge this in
     dmi_id_init! */
  static void __init dmi_id_init_attr_table(void)
4f5c791a8   Lennart Poettering   DMI-based module ...
179
  {
ce8c628ab   Jean Delvare   dmi-id: fix for _...
180
  	int i;
4f5c791a8   Lennart Poettering   DMI-based module ...
181
182
183
184
185
186
187
188
189
190
191
192
193
  
  	/* 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);
e0733e975   Jean Delvare   firmware: dmi: Fi...
194
  	ADD_DMI_ATTR(product_family,    DMI_PRODUCT_FAMILY);
4f5c791a8   Lennart Poettering   DMI-based module ...
195
196
197
198
199
200
201
202
203
204
205
  	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;
ce8c628ab   Jean Delvare   dmi-id: fix for _...
206
207
208
209
210
211
212
213
214
215
  }
  
  static int __init dmi_id_init(void)
  {
  	int ret;
  
  	if (!dmi_available)
  		return -ENODEV;
  
  	dmi_id_init_attr_table();
4f5c791a8   Lennart Poettering   DMI-based module ...
216
217
218
219
220
221
222
223
224
225
226
227
  
  	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;
6ff4dd36d   Kay Sievers   dmi: struct devic...
228
  	dev_set_name(dmi_dev, "id");
4f5c791a8   Lennart Poettering   DMI-based module ...
229
230
231
232
  	dmi_dev->groups = sys_dmi_attribute_groups;
  
  	ret = device_register(dmi_dev);
  	if (ret)
9b41b92bb   Allen Hung   dmi-id: don't fre...
233
  		goto fail_put_dmi_dev;
4f5c791a8   Lennart Poettering   DMI-based module ...
234
235
  
  	return 0;
9b41b92bb   Allen Hung   dmi-id: don't fre...
236
237
  fail_put_dmi_dev:
  	put_device(dmi_dev);
4f5c791a8   Lennart Poettering   DMI-based module ...
238

9b41b92bb   Allen Hung   dmi-id: don't fre...
239
  fail_class_unregister:
4f5c791a8   Lennart Poettering   DMI-based module ...
240
241
242
243
244
245
  	class_unregister(&dmi_class);
  
  	return ret;
  }
  
  arch_initcall(dmi_id_init);