LCOV - code coverage report
Current view: top level - drivers/firmware - dmi-id.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 84 91 92.3 %
Date: 2022-03-28 13:20:08 Functions: 6 6 100.0 %
Branches: 37 66 56.1 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Export SMBIOS/DMI info via sysfs to userspace
       4                 :            :  *
       5                 :            :  * Copyright 2007, Lennart Poettering
       6                 :            :  */
       7                 :            : 
       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>
      14                 :            : 
      15                 :            : struct dmi_device_attribute{
      16                 :            :         struct device_attribute dev_attr;
      17                 :            :         int field;
      18                 :            : };
      19                 :            : #define to_dmi_dev_attr(_dev_attr) \
      20                 :            :         container_of(_dev_attr, struct dmi_device_attribute, dev_attr)
      21                 :            : 
      22                 :         60 : static ssize_t sys_dmi_field_show(struct device *dev,
      23                 :            :                                   struct device_attribute *attr,
      24                 :            :                                   char *page)
      25                 :            : {
      26                 :         60 :         int field = to_dmi_dev_attr(attr)->field;
      27                 :         60 :         ssize_t len;
      28                 :         60 :         len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(field));
      29                 :         60 :         page[len-1] = '\n';
      30                 :         60 :         return len;
      31                 :            : }
      32                 :            : 
      33                 :            : #define DMI_ATTR(_name, _mode, _show, _field)                   \
      34                 :            :         { .dev_attr = __ATTR(_name, _mode, _show, NULL),        \
      35                 :            :           .field = _field }
      36                 :            : 
      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);
      40                 :            : 
      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);
      61                 :            : 
      62                 :            : static void ascii_filter(char *d, const char *s)
      63                 :            : {
      64                 :            :         /* Filter out characters we don't want to see in the modalias string */
      65         [ +  + ]:      46530 :         for (; *s; s++)
      66         [ +  + ]:      43560 :                 if (*s > ' ' && *s < 127 && *s != ':')
      67                 :      41910 :                         *(d++) = *s;
      68                 :            : 
      69                 :       2970 :         *d = 0;
      70                 :            : }
      71                 :            : 
      72                 :        330 : static ssize_t get_modalias(char *buffer, size_t buffer_size)
      73                 :            : {
      74                 :        330 :         static const struct mafield {
      75                 :            :                 const char *prefix;
      76                 :            :                 int field;
      77                 :            :         } fields[] = {
      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 },
      90                 :            :                 { NULL,  DMI_NONE }
      91                 :            :         };
      92                 :            : 
      93                 :        330 :         ssize_t l, left;
      94                 :        330 :         char *p;
      95                 :        330 :         const struct mafield *f;
      96                 :            : 
      97                 :        330 :         strcpy(buffer, "dmi");
      98                 :        330 :         p = buffer + 3; left = buffer_size - 4;
      99                 :            : 
     100   [ +  +  +  - ]:       4290 :         for (f = fields; f->prefix && left > 0; f++) {
     101                 :       3960 :                 const char *c;
     102                 :       3960 :                 char *t;
     103                 :            : 
     104                 :       3960 :                 c = dmi_get_system_info(f->field);
     105         [ +  + ]:       3960 :                 if (!c)
     106                 :        990 :                         continue;
     107                 :            : 
     108         [ -  + ]:       2970 :                 t = kmalloc(strlen(c) + 1, GFP_KERNEL);
     109         [ +  - ]:       2970 :                 if (!t)
     110                 :            :                         break;
     111                 :            :                 ascii_filter(t, c);
     112                 :       2970 :                 l = scnprintf(p, left, ":%s%s", f->prefix, t);
     113                 :       2970 :                 kfree(t);
     114                 :            : 
     115                 :       2970 :                 p += l;
     116                 :       2970 :                 left -= l;
     117                 :            :         }
     118                 :            : 
     119                 :        330 :         p[0] = ':';
     120                 :        330 :         p[1] = 0;
     121                 :            : 
     122                 :        330 :         return p - buffer + 1;
     123                 :            : }
     124                 :            : 
     125                 :        210 : static ssize_t sys_dmi_modalias_show(struct device *dev,
     126                 :            :                                      struct device_attribute *attr, char *page)
     127                 :            : {
     128                 :        210 :         ssize_t r;
     129                 :        210 :         r = get_modalias(page, PAGE_SIZE-1);
     130                 :        210 :         page[r] = '\n';
     131                 :        210 :         page[r+1] = 0;
     132                 :        210 :         return r+1;
     133                 :            : }
     134                 :            : 
     135                 :            : static struct device_attribute sys_dmi_modalias_attr =
     136                 :            :         __ATTR(modalias, 0444, sys_dmi_modalias_show, NULL);
     137                 :            : 
     138                 :            : static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2];
     139                 :            : 
     140                 :            : static struct attribute_group sys_dmi_attribute_group = {
     141                 :            :         .attrs = sys_dmi_attributes,
     142                 :            : };
     143                 :            : 
     144                 :            : static const struct attribute_group* sys_dmi_attribute_groups[] = {
     145                 :            :         &sys_dmi_attribute_group,
     146                 :            :         NULL
     147                 :            : };
     148                 :            : 
     149                 :        120 : static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
     150                 :            : {
     151                 :        120 :         ssize_t len;
     152                 :            : 
     153         [ +  - ]:        120 :         if (add_uevent_var(env, "MODALIAS="))
     154                 :            :                 return -ENOMEM;
     155                 :        120 :         len = get_modalias(&env->buf[env->buflen - 1],
     156                 :        120 :                            sizeof(env->buf) - env->buflen);
     157         [ +  - ]:        120 :         if (len >= (sizeof(env->buf) - env->buflen))
     158                 :            :                 return -ENOMEM;
     159                 :        120 :         env->buflen += len;
     160                 :        120 :         return 0;
     161                 :            : }
     162                 :            : 
     163                 :            : static struct class dmi_class = {
     164                 :            :         .name = "dmi",
     165                 :            :         .dev_release = (void(*)(struct device *)) kfree,
     166                 :            :         .dev_uevent = dmi_dev_uevent,
     167                 :            : };
     168                 :            : 
     169                 :            : static struct device *dmi_dev;
     170                 :            : 
     171                 :            : /* Initialization */
     172                 :            : 
     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;
     176                 :            : 
     177                 :            : /* In a separate function to keep gcc 3.2 happy - do NOT merge this in
     178                 :            :    dmi_id_init! */
     179                 :         30 : static void __init dmi_id_init_attr_table(void)
     180                 :            : {
     181                 :         30 :         int i;
     182                 :            : 
     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 */
     186                 :         30 :         i = 0;
     187         [ +  - ]:         30 :         ADD_DMI_ATTR(bios_vendor,       DMI_BIOS_VENDOR);
     188         [ +  - ]:         30 :         ADD_DMI_ATTR(bios_version,      DMI_BIOS_VERSION);
     189         [ +  - ]:         30 :         ADD_DMI_ATTR(bios_date,         DMI_BIOS_DATE);
     190         [ +  - ]:         30 :         ADD_DMI_ATTR(sys_vendor,        DMI_SYS_VENDOR);
     191         [ +  - ]:         30 :         ADD_DMI_ATTR(product_name,      DMI_PRODUCT_NAME);
     192         [ +  - ]:         30 :         ADD_DMI_ATTR(product_version,   DMI_PRODUCT_VERSION);
     193         [ +  - ]:         30 :         ADD_DMI_ATTR(product_serial,    DMI_PRODUCT_SERIAL);
     194         [ -  + ]:         30 :         ADD_DMI_ATTR(product_uuid,      DMI_PRODUCT_UUID);
     195         [ +  - ]:         30 :         ADD_DMI_ATTR(product_family,    DMI_PRODUCT_FAMILY);
     196         [ +  - ]:         30 :         ADD_DMI_ATTR(product_sku,       DMI_PRODUCT_SKU);
     197         [ -  + ]:         30 :         ADD_DMI_ATTR(board_vendor,      DMI_BOARD_VENDOR);
     198         [ -  + ]:         30 :         ADD_DMI_ATTR(board_name,        DMI_BOARD_NAME);
     199         [ -  + ]:         30 :         ADD_DMI_ATTR(board_version,     DMI_BOARD_VERSION);
     200         [ -  + ]:         30 :         ADD_DMI_ATTR(board_serial,      DMI_BOARD_SERIAL);
     201         [ -  + ]:         30 :         ADD_DMI_ATTR(board_asset_tag,   DMI_BOARD_ASSET_TAG);
     202         [ +  - ]:         30 :         ADD_DMI_ATTR(chassis_vendor,    DMI_CHASSIS_VENDOR);
     203         [ +  - ]:         30 :         ADD_DMI_ATTR(chassis_type,      DMI_CHASSIS_TYPE);
     204         [ +  - ]:         30 :         ADD_DMI_ATTR(chassis_version,   DMI_CHASSIS_VERSION);
     205         [ +  - ]:         30 :         ADD_DMI_ATTR(chassis_serial,    DMI_CHASSIS_SERIAL);
     206         [ +  - ]:         30 :         ADD_DMI_ATTR(chassis_asset_tag, DMI_CHASSIS_ASSET_TAG);
     207                 :         30 :         sys_dmi_attributes[i++] = &sys_dmi_modalias_attr.attr;
     208                 :         30 : }
     209                 :            : 
     210                 :         30 : static int __init dmi_id_init(void)
     211                 :            : {
     212                 :         30 :         int ret;
     213                 :            : 
     214         [ +  - ]:         30 :         if (!dmi_available)
     215                 :            :                 return -ENODEV;
     216                 :            : 
     217                 :         30 :         dmi_id_init_attr_table();
     218                 :            : 
     219                 :         30 :         ret = class_register(&dmi_class);
     220         [ +  - ]:         30 :         if (ret)
     221                 :            :                 return ret;
     222                 :            : 
     223                 :         30 :         dmi_dev = kzalloc(sizeof(*dmi_dev), GFP_KERNEL);
     224         [ -  + ]:         30 :         if (!dmi_dev) {
     225                 :          0 :                 ret = -ENOMEM;
     226                 :          0 :                 goto fail_class_unregister;
     227                 :            :         }
     228                 :            : 
     229                 :         30 :         dmi_dev->class = &dmi_class;
     230                 :         30 :         dev_set_name(dmi_dev, "id");
     231                 :         30 :         dmi_dev->groups = sys_dmi_attribute_groups;
     232                 :            : 
     233                 :         30 :         ret = device_register(dmi_dev);
     234         [ -  + ]:         30 :         if (ret)
     235                 :          0 :                 goto fail_put_dmi_dev;
     236                 :            : 
     237                 :            :         return 0;
     238                 :            : 
     239                 :            : fail_put_dmi_dev:
     240                 :          0 :         put_device(dmi_dev);
     241                 :            : 
     242                 :          0 : fail_class_unregister:
     243                 :          0 :         class_unregister(&dmi_class);
     244                 :            : 
     245                 :          0 :         return ret;
     246                 :            : }
     247                 :            : 
     248                 :            : arch_initcall(dmi_id_init);

Generated by: LCOV version 1.14