The oem strings in DMI system identification information of the BIOS have been parsed and stored as dmi devices in dmi_scan.c but they are not exported to userspace via sysfs.
The patch intends to export oem strings to sysfs device /sys/class/dmi/id. As the number of oem strings are dynamic, a group "oem" is added to the device and the strings will be added to the group as string1, string2, ..., and stringN. Signed-off-by: Allen Hung <allen_h...@dell.com> --- drivers/firmware/dmi-id.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index 44c0139..f284a07 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -58,6 +58,107 @@ 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 struct attribute *dmi_oem_attrs[] = { + NULL, +}; + +static const char oem_group[] = "oem"; + +static struct attribute_group dmi_oem_attr_group = { + .attrs = dmi_oem_attrs, + .name = oem_group, +}; + +static LIST_HEAD(dmi_oem_attrs_list); + +struct dmi_oem_attribute { + struct device_attribute dev_attr; + const char *oem_string; + char buf[32]; + bool is_added:1; + struct list_head list; +}; + +#define to_dmi_oem_attr(_dev_attr) \ + container_of(_dev_attr, struct dmi_oem_attribute, dev_attr) + +static ssize_t sys_dmi_oem_show(struct device *dev, + struct device_attribute *attr, + char *page) +{ + struct dmi_oem_attribute *oa = to_dmi_oem_attr(attr); + ssize_t len; + + strlcpy(page, oa->oem_string, PAGE_SIZE-1); + len = strlen(page); + page[len++] = '\n'; + page[len] = 0; + return len; +} + +static int __init dmi_id_init_oem_attr_group(void) +{ + int i, ret; + const struct dmi_device *dev; + struct dmi_oem_attribute *oa, *tmp; + struct device_attribute dev_attr_tmpl = + __ATTR(, 0444, sys_dmi_oem_show, NULL); + + ret = sysfs_create_group(&dmi_dev->kobj, &dmi_oem_attr_group); + if (ret) + return ret; + + /* All devices with type=DMI_DEV_TYPE_OEM_STRING will be found in + * the reverse order of what they were parsed in dmi_scan.c. However, + * we do want to expose the OEM strings to sysfs in the same order as + * what they were originally parsed. A linked list with 2-pass method + * is used here to reverse the reserved order. + * + * Pass 1: find out all "OEM string" devices and add each "oem string" + * to a linked list. + */ + dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, NULL); + while (dev) { + oa = kzalloc(sizeof(*oa), GFP_KERNEL); + if (!oa) { + ret = -ENOMEM; + goto failed; + } + oa->dev_attr = dev_attr_tmpl; + oa->oem_string = dev->name; + list_add(&oa->list, &dmi_oem_attrs_list); + dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev); + } + + /* Pass 2: traverse the list and add each string as a file to "oem" + * group + */ + i = 0; + list_for_each_entry(oa, &dmi_oem_attrs_list, list) { + snprintf(oa->buf, sizeof(oa->buf), "string%d", ++i); + oa->dev_attr.attr.name = oa->buf; + ret = sysfs_add_file_to_group( + &dmi_dev->kobj, &oa->dev_attr.attr, oem_group); + if (ret) + goto failed; + oa->is_added = 1; + } + + return 0; + +failed: + list_for_each_entry_safe(oa, tmp, &dmi_oem_attrs_list, list) { + if (oa->is_added) + sysfs_remove_file_from_group( + &dmi_dev->kobj, &oa->dev_attr.attr, oem_group); + list_del(&oa->list); + kfree(oa); + } + sysfs_remove_group(&dmi_dev->kobj, &dmi_oem_attr_group); + + return ret; +} + static void ascii_filter(char *d, const char *s) { /* Filter out characters we don't want to see in the modalias string */ @@ -231,8 +332,15 @@ static int __init dmi_id_init(void) if (ret) goto fail_put_dmi_dev; + ret = dmi_id_init_oem_attr_group(); + if (ret) + goto fail_dev_unregister; + return 0; +fail_dev_unregister: + device_unregister(dmi_dev); + fail_put_dmi_dev: put_device(dmi_dev); -- 2.7.4