1 // SPDX-License-Identifier: GPL-2.0-only
3 * Export SMBIOS/DMI info via sysfs to userspace
5 * Copyright 2007, Lennart Poettering
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/init.h>
11 #include <linux/dmi.h>
12 #include <linux/device.h>
13 #include <linux/slab.h>
15 struct dmi_device_attribute
{
16 struct device_attribute dev_attr
;
19 #define to_dmi_dev_attr(_dev_attr) \
20 container_of(_dev_attr, struct dmi_device_attribute, dev_attr)
22 static ssize_t
sys_dmi_field_show(struct device
*dev
,
23 struct device_attribute
*attr
,
26 int field
= to_dmi_dev_attr(attr
)->field
;
28 len
= scnprintf(page
, PAGE_SIZE
, "%s\n", dmi_get_system_info(field
));
33 #define DMI_ATTR(_name, _mode, _show, _field) \
34 { .dev_attr = __ATTR(_name, _mode, _show, NULL), \
37 #define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \
38 static struct dmi_device_attribute sys_dmi_##_name##_attr = \
39 DMI_ATTR(_name, _mode, sys_dmi_field_show, _field);
41 DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor
, 0444, DMI_BIOS_VENDOR
);
42 DEFINE_DMI_ATTR_WITH_SHOW(bios_version
, 0444, DMI_BIOS_VERSION
);
43 DEFINE_DMI_ATTR_WITH_SHOW(bios_date
, 0444, DMI_BIOS_DATE
);
44 DEFINE_DMI_ATTR_WITH_SHOW(sys_vendor
, 0444, DMI_SYS_VENDOR
);
45 DEFINE_DMI_ATTR_WITH_SHOW(product_name
, 0444, DMI_PRODUCT_NAME
);
46 DEFINE_DMI_ATTR_WITH_SHOW(product_version
, 0444, DMI_PRODUCT_VERSION
);
47 DEFINE_DMI_ATTR_WITH_SHOW(product_serial
, 0400, DMI_PRODUCT_SERIAL
);
48 DEFINE_DMI_ATTR_WITH_SHOW(product_uuid
, 0400, DMI_PRODUCT_UUID
);
49 DEFINE_DMI_ATTR_WITH_SHOW(product_sku
, 0444, DMI_PRODUCT_SKU
);
50 DEFINE_DMI_ATTR_WITH_SHOW(product_family
, 0444, DMI_PRODUCT_FAMILY
);
51 DEFINE_DMI_ATTR_WITH_SHOW(board_vendor
, 0444, DMI_BOARD_VENDOR
);
52 DEFINE_DMI_ATTR_WITH_SHOW(board_name
, 0444, DMI_BOARD_NAME
);
53 DEFINE_DMI_ATTR_WITH_SHOW(board_version
, 0444, DMI_BOARD_VERSION
);
54 DEFINE_DMI_ATTR_WITH_SHOW(board_serial
, 0400, DMI_BOARD_SERIAL
);
55 DEFINE_DMI_ATTR_WITH_SHOW(board_asset_tag
, 0444, DMI_BOARD_ASSET_TAG
);
56 DEFINE_DMI_ATTR_WITH_SHOW(chassis_vendor
, 0444, DMI_CHASSIS_VENDOR
);
57 DEFINE_DMI_ATTR_WITH_SHOW(chassis_type
, 0444, DMI_CHASSIS_TYPE
);
58 DEFINE_DMI_ATTR_WITH_SHOW(chassis_version
, 0444, DMI_CHASSIS_VERSION
);
59 DEFINE_DMI_ATTR_WITH_SHOW(chassis_serial
, 0400, DMI_CHASSIS_SERIAL
);
60 DEFINE_DMI_ATTR_WITH_SHOW(chassis_asset_tag
, 0444, DMI_CHASSIS_ASSET_TAG
);
62 static void ascii_filter(char *d
, const char *s
)
64 /* Filter out characters we don't want to see in the modalias string */
66 if (*s
> ' ' && *s
< 127 && *s
!= ':')
72 static ssize_t
get_modalias(char *buffer
, size_t buffer_size
)
74 static const struct mafield
{
78 { "bvn", DMI_BIOS_VENDOR
},
79 { "bvr", DMI_BIOS_VERSION
},
80 { "bd", DMI_BIOS_DATE
},
81 { "svn", DMI_SYS_VENDOR
},
82 { "pn", DMI_PRODUCT_NAME
},
83 { "pvr", DMI_PRODUCT_VERSION
},
84 { "rvn", DMI_BOARD_VENDOR
},
85 { "rn", DMI_BOARD_NAME
},
86 { "rvr", DMI_BOARD_VERSION
},
87 { "cvn", DMI_CHASSIS_VENDOR
},
88 { "ct", DMI_CHASSIS_TYPE
},
89 { "cvr", DMI_CHASSIS_VERSION
},
95 const struct mafield
*f
;
97 strcpy(buffer
, "dmi");
98 p
= buffer
+ 3; left
= buffer_size
- 4;
100 for (f
= fields
; f
->prefix
&& left
> 0; f
++) {
104 c
= dmi_get_system_info(f
->field
);
108 t
= kmalloc(strlen(c
) + 1, GFP_KERNEL
);
112 l
= scnprintf(p
, left
, ":%s%s", f
->prefix
, t
);
122 return p
- buffer
+ 1;
125 static ssize_t
sys_dmi_modalias_show(struct device
*dev
,
126 struct device_attribute
*attr
, char *page
)
129 r
= get_modalias(page
, PAGE_SIZE
-1);
135 static struct device_attribute sys_dmi_modalias_attr
=
136 __ATTR(modalias
, 0444, sys_dmi_modalias_show
, NULL
);
138 static struct attribute
*sys_dmi_attributes
[DMI_STRING_MAX
+2];
140 static struct attribute_group sys_dmi_attribute_group
= {
141 .attrs
= sys_dmi_attributes
,
144 static const struct attribute_group
* sys_dmi_attribute_groups
[] = {
145 &sys_dmi_attribute_group
,
149 static int dmi_dev_uevent(struct device
*dev
, struct kobj_uevent_env
*env
)
153 if (add_uevent_var(env
, "MODALIAS="))
155 len
= get_modalias(&env
->buf
[env
->buflen
- 1],
156 sizeof(env
->buf
) - env
->buflen
);
157 if (len
>= (sizeof(env
->buf
) - env
->buflen
))
163 static struct class dmi_class
= {
165 .dev_release
= (void(*)(struct device
*)) kfree
,
166 .dev_uevent
= dmi_dev_uevent
,
169 static struct device
*dmi_dev
;
173 #define ADD_DMI_ATTR(_name, _field) \
174 if (dmi_get_system_info(_field)) \
175 sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr;
177 /* In a separate function to keep gcc 3.2 happy - do NOT merge this in
179 static void __init
dmi_id_init_attr_table(void)
183 /* Not necessarily all DMI fields are available on all
184 * systems, hence let's built an attribute table of just
185 * what's available */
187 ADD_DMI_ATTR(bios_vendor
, DMI_BIOS_VENDOR
);
188 ADD_DMI_ATTR(bios_version
, DMI_BIOS_VERSION
);
189 ADD_DMI_ATTR(bios_date
, DMI_BIOS_DATE
);
190 ADD_DMI_ATTR(sys_vendor
, DMI_SYS_VENDOR
);
191 ADD_DMI_ATTR(product_name
, DMI_PRODUCT_NAME
);
192 ADD_DMI_ATTR(product_version
, DMI_PRODUCT_VERSION
);
193 ADD_DMI_ATTR(product_serial
, DMI_PRODUCT_SERIAL
);
194 ADD_DMI_ATTR(product_uuid
, DMI_PRODUCT_UUID
);
195 ADD_DMI_ATTR(product_family
, DMI_PRODUCT_FAMILY
);
196 ADD_DMI_ATTR(product_sku
, DMI_PRODUCT_SKU
);
197 ADD_DMI_ATTR(board_vendor
, DMI_BOARD_VENDOR
);
198 ADD_DMI_ATTR(board_name
, DMI_BOARD_NAME
);
199 ADD_DMI_ATTR(board_version
, DMI_BOARD_VERSION
);
200 ADD_DMI_ATTR(board_serial
, DMI_BOARD_SERIAL
);
201 ADD_DMI_ATTR(board_asset_tag
, DMI_BOARD_ASSET_TAG
);
202 ADD_DMI_ATTR(chassis_vendor
, DMI_CHASSIS_VENDOR
);
203 ADD_DMI_ATTR(chassis_type
, DMI_CHASSIS_TYPE
);
204 ADD_DMI_ATTR(chassis_version
, DMI_CHASSIS_VERSION
);
205 ADD_DMI_ATTR(chassis_serial
, DMI_CHASSIS_SERIAL
);
206 ADD_DMI_ATTR(chassis_asset_tag
, DMI_CHASSIS_ASSET_TAG
);
207 sys_dmi_attributes
[i
++] = &sys_dmi_modalias_attr
.attr
;
210 static int __init
dmi_id_init(void)
217 dmi_id_init_attr_table();
219 ret
= class_register(&dmi_class
);
223 dmi_dev
= kzalloc(sizeof(*dmi_dev
), GFP_KERNEL
);
226 goto fail_class_unregister
;
229 dmi_dev
->class = &dmi_class
;
230 dev_set_name(dmi_dev
, "id");
231 dmi_dev
->groups
= sys_dmi_attribute_groups
;
233 ret
= device_register(dmi_dev
);
235 goto fail_put_dmi_dev
;
242 fail_class_unregister
:
243 class_unregister(&dmi_class
);
248 arch_initcall(dmi_id_init
);