0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/kernel.h>
0010 #include <linux/init.h>
0011 #include <linux/dmi.h>
0012 #include <linux/device.h>
0013 #include <linux/slab.h>
0014
0015 struct dmi_device_attribute{
0016 struct device_attribute dev_attr;
0017 int field;
0018 };
0019 #define to_dmi_dev_attr(_dev_attr) \
0020 container_of(_dev_attr, struct dmi_device_attribute, dev_attr)
0021
0022 static ssize_t sys_dmi_field_show(struct device *dev,
0023 struct device_attribute *attr,
0024 char *page)
0025 {
0026 int field = to_dmi_dev_attr(attr)->field;
0027 ssize_t len;
0028 len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(field));
0029 page[len-1] = '\n';
0030 return len;
0031 }
0032
0033 #define DMI_ATTR(_name, _mode, _show, _field) \
0034 { .dev_attr = __ATTR(_name, _mode, _show, NULL), \
0035 .field = _field }
0036
0037 #define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \
0038 static struct dmi_device_attribute sys_dmi_##_name##_attr = \
0039 DMI_ATTR(_name, _mode, sys_dmi_field_show, _field);
0040
0041 DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor, 0444, DMI_BIOS_VENDOR);
0042 DEFINE_DMI_ATTR_WITH_SHOW(bios_version, 0444, DMI_BIOS_VERSION);
0043 DEFINE_DMI_ATTR_WITH_SHOW(bios_date, 0444, DMI_BIOS_DATE);
0044 DEFINE_DMI_ATTR_WITH_SHOW(sys_vendor, 0444, DMI_SYS_VENDOR);
0045 DEFINE_DMI_ATTR_WITH_SHOW(bios_release, 0444, DMI_BIOS_RELEASE);
0046 DEFINE_DMI_ATTR_WITH_SHOW(ec_firmware_release, 0444, DMI_EC_FIRMWARE_RELEASE);
0047 DEFINE_DMI_ATTR_WITH_SHOW(product_name, 0444, DMI_PRODUCT_NAME);
0048 DEFINE_DMI_ATTR_WITH_SHOW(product_version, 0444, DMI_PRODUCT_VERSION);
0049 DEFINE_DMI_ATTR_WITH_SHOW(product_serial, 0400, DMI_PRODUCT_SERIAL);
0050 DEFINE_DMI_ATTR_WITH_SHOW(product_uuid, 0400, DMI_PRODUCT_UUID);
0051 DEFINE_DMI_ATTR_WITH_SHOW(product_sku, 0444, DMI_PRODUCT_SKU);
0052 DEFINE_DMI_ATTR_WITH_SHOW(product_family, 0444, DMI_PRODUCT_FAMILY);
0053 DEFINE_DMI_ATTR_WITH_SHOW(board_vendor, 0444, DMI_BOARD_VENDOR);
0054 DEFINE_DMI_ATTR_WITH_SHOW(board_name, 0444, DMI_BOARD_NAME);
0055 DEFINE_DMI_ATTR_WITH_SHOW(board_version, 0444, DMI_BOARD_VERSION);
0056 DEFINE_DMI_ATTR_WITH_SHOW(board_serial, 0400, DMI_BOARD_SERIAL);
0057 DEFINE_DMI_ATTR_WITH_SHOW(board_asset_tag, 0444, DMI_BOARD_ASSET_TAG);
0058 DEFINE_DMI_ATTR_WITH_SHOW(chassis_vendor, 0444, DMI_CHASSIS_VENDOR);
0059 DEFINE_DMI_ATTR_WITH_SHOW(chassis_type, 0444, DMI_CHASSIS_TYPE);
0060 DEFINE_DMI_ATTR_WITH_SHOW(chassis_version, 0444, DMI_CHASSIS_VERSION);
0061 DEFINE_DMI_ATTR_WITH_SHOW(chassis_serial, 0400, DMI_CHASSIS_SERIAL);
0062 DEFINE_DMI_ATTR_WITH_SHOW(chassis_asset_tag, 0444, DMI_CHASSIS_ASSET_TAG);
0063
0064 static void ascii_filter(char *d, const char *s)
0065 {
0066
0067 for (; *s; s++)
0068 if (*s > ' ' && *s < 127 && *s != ':')
0069 *(d++) = *s;
0070
0071 *d = 0;
0072 }
0073
0074 static ssize_t get_modalias(char *buffer, size_t buffer_size)
0075 {
0076
0077
0078
0079
0080 static const struct mafield {
0081 const char *prefix;
0082 int field;
0083 } fields[] = {
0084 { "bvn", DMI_BIOS_VENDOR },
0085 { "bvr", DMI_BIOS_VERSION },
0086 { "bd", DMI_BIOS_DATE },
0087 { "br", DMI_BIOS_RELEASE },
0088 { "efr", DMI_EC_FIRMWARE_RELEASE },
0089 { "svn", DMI_SYS_VENDOR },
0090 { "pn", DMI_PRODUCT_NAME },
0091 { "pvr", DMI_PRODUCT_VERSION },
0092 { "rvn", DMI_BOARD_VENDOR },
0093 { "rn", DMI_BOARD_NAME },
0094 { "rvr", DMI_BOARD_VERSION },
0095 { "cvn", DMI_CHASSIS_VENDOR },
0096 { "ct", DMI_CHASSIS_TYPE },
0097 { "cvr", DMI_CHASSIS_VERSION },
0098 { "sku", DMI_PRODUCT_SKU },
0099 { NULL, DMI_NONE }
0100 };
0101
0102 ssize_t l, left;
0103 char *p;
0104 const struct mafield *f;
0105
0106 strcpy(buffer, "dmi");
0107 p = buffer + 3; left = buffer_size - 4;
0108
0109 for (f = fields; f->prefix && left > 0; f++) {
0110 const char *c;
0111 char *t;
0112
0113 c = dmi_get_system_info(f->field);
0114 if (!c)
0115 continue;
0116
0117 t = kmalloc(strlen(c) + 1, GFP_KERNEL);
0118 if (!t)
0119 break;
0120 ascii_filter(t, c);
0121 l = scnprintf(p, left, ":%s%s", f->prefix, t);
0122 kfree(t);
0123
0124 p += l;
0125 left -= l;
0126 }
0127
0128 p[0] = ':';
0129 p[1] = 0;
0130
0131 return p - buffer + 1;
0132 }
0133
0134 static ssize_t sys_dmi_modalias_show(struct device *dev,
0135 struct device_attribute *attr, char *page)
0136 {
0137 ssize_t r;
0138 r = get_modalias(page, PAGE_SIZE-1);
0139 page[r] = '\n';
0140 page[r+1] = 0;
0141 return r+1;
0142 }
0143
0144 static struct device_attribute sys_dmi_modalias_attr =
0145 __ATTR(modalias, 0444, sys_dmi_modalias_show, NULL);
0146
0147 static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2];
0148
0149 static struct attribute_group sys_dmi_attribute_group = {
0150 .attrs = sys_dmi_attributes,
0151 };
0152
0153 static const struct attribute_group* sys_dmi_attribute_groups[] = {
0154 &sys_dmi_attribute_group,
0155 NULL
0156 };
0157
0158 static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
0159 {
0160 ssize_t len;
0161
0162 if (add_uevent_var(env, "MODALIAS="))
0163 return -ENOMEM;
0164 len = get_modalias(&env->buf[env->buflen - 1],
0165 sizeof(env->buf) - env->buflen);
0166 if (len >= (sizeof(env->buf) - env->buflen))
0167 return -ENOMEM;
0168 env->buflen += len;
0169 return 0;
0170 }
0171
0172 static struct class dmi_class = {
0173 .name = "dmi",
0174 .dev_release = (void(*)(struct device *)) kfree,
0175 .dev_uevent = dmi_dev_uevent,
0176 };
0177
0178 static struct device *dmi_dev;
0179
0180
0181
0182 #define ADD_DMI_ATTR(_name, _field) \
0183 if (dmi_get_system_info(_field)) \
0184 sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr;
0185
0186
0187
0188 static void __init dmi_id_init_attr_table(void)
0189 {
0190 int i;
0191
0192
0193
0194
0195 i = 0;
0196 ADD_DMI_ATTR(bios_vendor, DMI_BIOS_VENDOR);
0197 ADD_DMI_ATTR(bios_version, DMI_BIOS_VERSION);
0198 ADD_DMI_ATTR(bios_date, DMI_BIOS_DATE);
0199 ADD_DMI_ATTR(bios_release, DMI_BIOS_RELEASE);
0200 ADD_DMI_ATTR(ec_firmware_release, DMI_EC_FIRMWARE_RELEASE);
0201 ADD_DMI_ATTR(sys_vendor, DMI_SYS_VENDOR);
0202 ADD_DMI_ATTR(product_name, DMI_PRODUCT_NAME);
0203 ADD_DMI_ATTR(product_version, DMI_PRODUCT_VERSION);
0204 ADD_DMI_ATTR(product_serial, DMI_PRODUCT_SERIAL);
0205 ADD_DMI_ATTR(product_uuid, DMI_PRODUCT_UUID);
0206 ADD_DMI_ATTR(product_family, DMI_PRODUCT_FAMILY);
0207 ADD_DMI_ATTR(product_sku, DMI_PRODUCT_SKU);
0208 ADD_DMI_ATTR(board_vendor, DMI_BOARD_VENDOR);
0209 ADD_DMI_ATTR(board_name, DMI_BOARD_NAME);
0210 ADD_DMI_ATTR(board_version, DMI_BOARD_VERSION);
0211 ADD_DMI_ATTR(board_serial, DMI_BOARD_SERIAL);
0212 ADD_DMI_ATTR(board_asset_tag, DMI_BOARD_ASSET_TAG);
0213 ADD_DMI_ATTR(chassis_vendor, DMI_CHASSIS_VENDOR);
0214 ADD_DMI_ATTR(chassis_type, DMI_CHASSIS_TYPE);
0215 ADD_DMI_ATTR(chassis_version, DMI_CHASSIS_VERSION);
0216 ADD_DMI_ATTR(chassis_serial, DMI_CHASSIS_SERIAL);
0217 ADD_DMI_ATTR(chassis_asset_tag, DMI_CHASSIS_ASSET_TAG);
0218 sys_dmi_attributes[i++] = &sys_dmi_modalias_attr.attr;
0219 }
0220
0221 static int __init dmi_id_init(void)
0222 {
0223 int ret;
0224
0225 if (!dmi_available)
0226 return -ENODEV;
0227
0228 dmi_id_init_attr_table();
0229
0230 ret = class_register(&dmi_class);
0231 if (ret)
0232 return ret;
0233
0234 dmi_dev = kzalloc(sizeof(*dmi_dev), GFP_KERNEL);
0235 if (!dmi_dev) {
0236 ret = -ENOMEM;
0237 goto fail_class_unregister;
0238 }
0239
0240 dmi_dev->class = &dmi_class;
0241 dev_set_name(dmi_dev, "id");
0242 dmi_dev->groups = sys_dmi_attribute_groups;
0243
0244 ret = device_register(dmi_dev);
0245 if (ret)
0246 goto fail_put_dmi_dev;
0247
0248 return 0;
0249
0250 fail_put_dmi_dev:
0251 put_device(dmi_dev);
0252
0253 fail_class_unregister:
0254 class_unregister(&dmi_class);
0255
0256 return ret;
0257 }
0258
0259 arch_initcall(dmi_id_init);