From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932254AbcHOJYu (ORCPT ); Mon, 15 Aug 2016 05:24:50 -0400 Received: from esa1.dell-outbound.iphmx.com ([68.232.153.90]:56742 "EHLO esa1.dell-outbound.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752073AbcHOJXf (ORCPT ); Mon, 15 Aug 2016 05:23:35 -0400 DomainKey-Signature: s=smtpout; d=dell.com; c=simple; q=dns; h=Received:Received:X-LoopCount0:X-IronPort-AV:From:To:Cc: Subject:Date:Message-Id:X-Mailer; b=JE0U6fEHgGpEIn2o0V1/CoyQZmEsaWHrr8S1YlMtOTRnEqM4n5+MGJo6 iIBcoB3RRSv1cSI6cghumBrgTZqLy+BnO8z6sCH5Y+DF7fJJQpnVf/lFg b/V+cu1IhPpXvbXEhFx8kDBon+nLSJ3cMe4crr9yrPiPIq/4wUgPtf2Hv 4=; X-LoopCount0: from 10.106.62.76 X-IronPort-AV: E=Sophos;i="5.28,524,1464670800"; d="scan'208";a="832802206" From: Allen Hung To: Jean Delvare , Greg Kroah-Hartman , Russell King , Gabriel Somlo , Bjorn Andersson , Jens Wiklander , Andy Gross , Arnd Bergmann , Sudeep Holla , Eric Anholt , linux-kernel@vger.kernel.org, Mario Limonciello Cc: Allen Hung Subject: [PATCH v3 2/2] dmi-id: add dmi/id/oem group for exporting oem strings to sysfs Date: Mon, 15 Aug 2016 17:22:05 +0800 Message-Id: <1471252925-8082-1-git-send-email-allen_hung@dell.com> X-Mailer: git-send-email 1.9.1 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- drivers/firmware/Kconfig | 9 ++++ drivers/firmware/dmi-id.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 6664f11..885a6c9 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -119,6 +119,15 @@ config DMIID information from userspace through /sys/class/dmi/id/ or if you want DMI-based module auto-loading. +config DMIID_OEM_STRINGS + bool "Export OEM strings in SMBIOS/DMI via sysfs to userspace" + depends on DMIID + default n + help + Say Y here if you want to query OEM strings (as part of the information + contained in SMBIOS/DMI system identification) from userspace through + /sys/class/dmi/id/oem/. + config DMI_SYSFS tristate "DMI table support in sysfs" depends on SYSFS && DMI diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index 44c0139..4467044 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -58,6 +58,46 @@ 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); +#ifdef CONFIG_DMIID_OEM_STRINGS +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; +} +#endif + static void ascii_filter(char *d, const char *s) { /* Filter out characters we don't want to see in the modalias string */ @@ -204,6 +244,72 @@ static void __init dmi_id_init_attr_table(void) sys_dmi_attributes[i++] = &sys_dmi_modalias_attr.attr; } +#ifdef CONFIG_DMIID_OEM_STRINGS +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; + oa->dev_attr.attr.mode = 0400; + 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; +} +#endif + static int __init dmi_id_init(void) { int ret; @@ -231,8 +337,18 @@ static int __init dmi_id_init(void) if (ret) goto fail_put_dmi_dev; +#ifdef CONFIG_DMIID_OEM_STRINGS + ret = dmi_id_init_oem_attr_group(); + if (ret) + goto fail_dev_unregister; +#endif return 0; +#ifdef CONFIG_DMIID_OEM_STRINGS +fail_dev_unregister: + device_unregister(dmi_dev); +#endif + fail_put_dmi_dev: put_device(dmi_dev); -- 2.7.4