root/drivers/firmware/dmi-sysfs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dmi_entry_free
  2. to_entry
  3. to_attr
  4. dmi_sysfs_attr_show
  5. find_dmi_entry_helper
  6. find_dmi_entry
  7. dmi_entry_length
  8. dmi_entry_attr_show_helper
  9. dmi_entry_attr_show
  10. read_sel_8bit_indexed_io
  11. read_sel_2x8bit_indexed_io
  12. read_sel_16bit_indexed_io
  13. dmi_sel_raw_read_io
  14. dmi_sel_raw_read_phys32
  15. dmi_sel_raw_read_helper
  16. dmi_sel_raw_read
  17. dmi_system_event_log
  18. dmi_sysfs_entry_length
  19. dmi_sysfs_entry_handle
  20. dmi_sysfs_entry_type
  21. dmi_sysfs_entry_instance
  22. dmi_sysfs_entry_position
  23. dmi_entry_raw_read_helper
  24. dmi_entry_raw_read
  25. dmi_sysfs_entry_release
  26. dmi_sysfs_register_handle
  27. cleanup_entry_list
  28. dmi_sysfs_init
  29. dmi_sysfs_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * dmi-sysfs.c
   4  *
   5  * This module exports the DMI tables read-only to userspace through the
   6  * sysfs file system.
   7  *
   8  * Data is currently found below
   9  *    /sys/firmware/dmi/...
  10  *
  11  * DMI attributes are presented in attribute files with names
  12  * formatted using %d-%d, so that the first integer indicates the
  13  * structure type (0-255), and the second field is the instance of that
  14  * entry.
  15  *
  16  * Copyright 2011 Google, Inc.
  17  */
  18 
  19 #include <linux/kernel.h>
  20 #include <linux/init.h>
  21 #include <linux/module.h>
  22 #include <linux/types.h>
  23 #include <linux/kobject.h>
  24 #include <linux/dmi.h>
  25 #include <linux/capability.h>
  26 #include <linux/slab.h>
  27 #include <linux/list.h>
  28 #include <linux/io.h>
  29 #include <asm/dmi.h>
  30 
  31 #define MAX_ENTRY_TYPE 255 /* Most of these aren't used, but we consider
  32                               the top entry type is only 8 bits */
  33 
  34 struct dmi_sysfs_entry {
  35         struct dmi_header dh;
  36         struct kobject kobj;
  37         int instance;
  38         int position;
  39         struct list_head list;
  40         struct kobject *child;
  41 };
  42 
  43 /*
  44  * Global list of dmi_sysfs_entry.  Even though this should only be
  45  * manipulated at setup and teardown, the lazy nature of the kobject
  46  * system means we get lazy removes.
  47  */
  48 static LIST_HEAD(entry_list);
  49 static DEFINE_SPINLOCK(entry_list_lock);
  50 
  51 /* dmi_sysfs_attribute - Top level attribute. used by all entries. */
  52 struct dmi_sysfs_attribute {
  53         struct attribute attr;
  54         ssize_t (*show)(struct dmi_sysfs_entry *entry, char *buf);
  55 };
  56 
  57 #define DMI_SYSFS_ATTR(_entry, _name) \
  58 struct dmi_sysfs_attribute dmi_sysfs_attr_##_entry##_##_name = { \
  59         .attr = {.name = __stringify(_name), .mode = 0400}, \
  60         .show = dmi_sysfs_##_entry##_##_name, \
  61 }
  62 
  63 /*
  64  * dmi_sysfs_mapped_attribute - Attribute where we require the entry be
  65  * mapped in.  Use in conjunction with dmi_sysfs_specialize_attr_ops.
  66  */
  67 struct dmi_sysfs_mapped_attribute {
  68         struct attribute attr;
  69         ssize_t (*show)(struct dmi_sysfs_entry *entry,
  70                         const struct dmi_header *dh,
  71                         char *buf);
  72 };
  73 
  74 #define DMI_SYSFS_MAPPED_ATTR(_entry, _name) \
  75 struct dmi_sysfs_mapped_attribute dmi_sysfs_attr_##_entry##_##_name = { \
  76         .attr = {.name = __stringify(_name), .mode = 0400}, \
  77         .show = dmi_sysfs_##_entry##_##_name, \
  78 }
  79 
  80 /*************************************************
  81  * Generic DMI entry support.
  82  *************************************************/
  83 static void dmi_entry_free(struct kobject *kobj)
  84 {
  85         kfree(kobj);
  86 }
  87 
  88 static struct dmi_sysfs_entry *to_entry(struct kobject *kobj)
  89 {
  90         return container_of(kobj, struct dmi_sysfs_entry, kobj);
  91 }
  92 
  93 static struct dmi_sysfs_attribute *to_attr(struct attribute *attr)
  94 {
  95         return container_of(attr, struct dmi_sysfs_attribute, attr);
  96 }
  97 
  98 static ssize_t dmi_sysfs_attr_show(struct kobject *kobj,
  99                                    struct attribute *_attr, char *buf)
 100 {
 101         struct dmi_sysfs_entry *entry = to_entry(kobj);
 102         struct dmi_sysfs_attribute *attr = to_attr(_attr);
 103 
 104         /* DMI stuff is only ever admin visible */
 105         if (!capable(CAP_SYS_ADMIN))
 106                 return -EACCES;
 107 
 108         return attr->show(entry, buf);
 109 }
 110 
 111 static const struct sysfs_ops dmi_sysfs_attr_ops = {
 112         .show = dmi_sysfs_attr_show,
 113 };
 114 
 115 typedef ssize_t (*dmi_callback)(struct dmi_sysfs_entry *,
 116                                 const struct dmi_header *dh, void *);
 117 
 118 struct find_dmi_data {
 119         struct dmi_sysfs_entry  *entry;
 120         dmi_callback            callback;
 121         void                    *private;
 122         int                     instance_countdown;
 123         ssize_t                 ret;
 124 };
 125 
 126 static void find_dmi_entry_helper(const struct dmi_header *dh,
 127                                   void *_data)
 128 {
 129         struct find_dmi_data *data = _data;
 130         struct dmi_sysfs_entry *entry = data->entry;
 131 
 132         /* Is this the entry we want? */
 133         if (dh->type != entry->dh.type)
 134                 return;
 135 
 136         if (data->instance_countdown != 0) {
 137                 /* try the next instance? */
 138                 data->instance_countdown--;
 139                 return;
 140         }
 141 
 142         /*
 143          * Don't ever revisit the instance.  Short circuit later
 144          * instances by letting the instance_countdown run negative
 145          */
 146         data->instance_countdown--;
 147 
 148         /* Found the entry */
 149         data->ret = data->callback(entry, dh, data->private);
 150 }
 151 
 152 /* State for passing the read parameters through dmi_find_entry() */
 153 struct dmi_read_state {
 154         char *buf;
 155         loff_t pos;
 156         size_t count;
 157 };
 158 
 159 static ssize_t find_dmi_entry(struct dmi_sysfs_entry *entry,
 160                               dmi_callback callback, void *private)
 161 {
 162         struct find_dmi_data data = {
 163                 .entry = entry,
 164                 .callback = callback,
 165                 .private = private,
 166                 .instance_countdown = entry->instance,
 167                 .ret = -EIO,  /* To signal the entry disappeared */
 168         };
 169         int ret;
 170 
 171         ret = dmi_walk(find_dmi_entry_helper, &data);
 172         /* This shouldn't happen, but just in case. */
 173         if (ret)
 174                 return -EINVAL;
 175         return data.ret;
 176 }
 177 
 178 /*
 179  * Calculate and return the byte length of the dmi entry identified by
 180  * dh.  This includes both the formatted portion as well as the
 181  * unformatted string space, including the two trailing nul characters.
 182  */
 183 static size_t dmi_entry_length(const struct dmi_header *dh)
 184 {
 185         const char *p = (const char *)dh;
 186 
 187         p += dh->length;
 188 
 189         while (p[0] || p[1])
 190                 p++;
 191 
 192         return 2 + p - (const char *)dh;
 193 }
 194 
 195 /*************************************************
 196  * Support bits for specialized DMI entry support
 197  *************************************************/
 198 struct dmi_entry_attr_show_data {
 199         struct attribute *attr;
 200         char *buf;
 201 };
 202 
 203 static ssize_t dmi_entry_attr_show_helper(struct dmi_sysfs_entry *entry,
 204                                           const struct dmi_header *dh,
 205                                           void *_data)
 206 {
 207         struct dmi_entry_attr_show_data *data = _data;
 208         struct dmi_sysfs_mapped_attribute *attr;
 209 
 210         attr = container_of(data->attr,
 211                             struct dmi_sysfs_mapped_attribute, attr);
 212         return attr->show(entry, dh, data->buf);
 213 }
 214 
 215 static ssize_t dmi_entry_attr_show(struct kobject *kobj,
 216                                    struct attribute *attr,
 217                                    char *buf)
 218 {
 219         struct dmi_entry_attr_show_data data = {
 220                 .attr = attr,
 221                 .buf  = buf,
 222         };
 223         /* Find the entry according to our parent and call the
 224          * normalized show method hanging off of the attribute */
 225         return find_dmi_entry(to_entry(kobj->parent),
 226                               dmi_entry_attr_show_helper, &data);
 227 }
 228 
 229 static const struct sysfs_ops dmi_sysfs_specialize_attr_ops = {
 230         .show = dmi_entry_attr_show,
 231 };
 232 
 233 /*************************************************
 234  * Specialized DMI entry support.
 235  *************************************************/
 236 
 237 /*** Type 15 - System Event Table ***/
 238 
 239 #define DMI_SEL_ACCESS_METHOD_IO8       0x00
 240 #define DMI_SEL_ACCESS_METHOD_IO2x8     0x01
 241 #define DMI_SEL_ACCESS_METHOD_IO16      0x02
 242 #define DMI_SEL_ACCESS_METHOD_PHYS32    0x03
 243 #define DMI_SEL_ACCESS_METHOD_GPNV      0x04
 244 
 245 struct dmi_system_event_log {
 246         struct dmi_header header;
 247         u16     area_length;
 248         u16     header_start_offset;
 249         u16     data_start_offset;
 250         u8      access_method;
 251         u8      status;
 252         u32     change_token;
 253         union {
 254                 struct {
 255                         u16 index_addr;
 256                         u16 data_addr;
 257                 } io;
 258                 u32     phys_addr32;
 259                 u16     gpnv_handle;
 260                 u32     access_method_address;
 261         };
 262         u8      header_format;
 263         u8      type_descriptors_supported_count;
 264         u8      per_log_type_descriptor_length;
 265         u8      supported_log_type_descriptos[0];
 266 } __packed;
 267 
 268 #define DMI_SYSFS_SEL_FIELD(_field) \
 269 static ssize_t dmi_sysfs_sel_##_field(struct dmi_sysfs_entry *entry, \
 270                                       const struct dmi_header *dh, \
 271                                       char *buf) \
 272 { \
 273         struct dmi_system_event_log sel; \
 274         if (sizeof(sel) > dmi_entry_length(dh)) \
 275                 return -EIO; \
 276         memcpy(&sel, dh, sizeof(sel)); \
 277         return sprintf(buf, "%u\n", sel._field); \
 278 } \
 279 static DMI_SYSFS_MAPPED_ATTR(sel, _field)
 280 
 281 DMI_SYSFS_SEL_FIELD(area_length);
 282 DMI_SYSFS_SEL_FIELD(header_start_offset);
 283 DMI_SYSFS_SEL_FIELD(data_start_offset);
 284 DMI_SYSFS_SEL_FIELD(access_method);
 285 DMI_SYSFS_SEL_FIELD(status);
 286 DMI_SYSFS_SEL_FIELD(change_token);
 287 DMI_SYSFS_SEL_FIELD(access_method_address);
 288 DMI_SYSFS_SEL_FIELD(header_format);
 289 DMI_SYSFS_SEL_FIELD(type_descriptors_supported_count);
 290 DMI_SYSFS_SEL_FIELD(per_log_type_descriptor_length);
 291 
 292 static struct attribute *dmi_sysfs_sel_attrs[] = {
 293         &dmi_sysfs_attr_sel_area_length.attr,
 294         &dmi_sysfs_attr_sel_header_start_offset.attr,
 295         &dmi_sysfs_attr_sel_data_start_offset.attr,
 296         &dmi_sysfs_attr_sel_access_method.attr,
 297         &dmi_sysfs_attr_sel_status.attr,
 298         &dmi_sysfs_attr_sel_change_token.attr,
 299         &dmi_sysfs_attr_sel_access_method_address.attr,
 300         &dmi_sysfs_attr_sel_header_format.attr,
 301         &dmi_sysfs_attr_sel_type_descriptors_supported_count.attr,
 302         &dmi_sysfs_attr_sel_per_log_type_descriptor_length.attr,
 303         NULL,
 304 };
 305 
 306 
 307 static struct kobj_type dmi_system_event_log_ktype = {
 308         .release = dmi_entry_free,
 309         .sysfs_ops = &dmi_sysfs_specialize_attr_ops,
 310         .default_attrs = dmi_sysfs_sel_attrs,
 311 };
 312 
 313 typedef u8 (*sel_io_reader)(const struct dmi_system_event_log *sel,
 314                             loff_t offset);
 315 
 316 static DEFINE_MUTEX(io_port_lock);
 317 
 318 static u8 read_sel_8bit_indexed_io(const struct dmi_system_event_log *sel,
 319                                    loff_t offset)
 320 {
 321         u8 ret;
 322 
 323         mutex_lock(&io_port_lock);
 324         outb((u8)offset, sel->io.index_addr);
 325         ret = inb(sel->io.data_addr);
 326         mutex_unlock(&io_port_lock);
 327         return ret;
 328 }
 329 
 330 static u8 read_sel_2x8bit_indexed_io(const struct dmi_system_event_log *sel,
 331                                      loff_t offset)
 332 {
 333         u8 ret;
 334 
 335         mutex_lock(&io_port_lock);
 336         outb((u8)offset, sel->io.index_addr);
 337         outb((u8)(offset >> 8), sel->io.index_addr + 1);
 338         ret = inb(sel->io.data_addr);
 339         mutex_unlock(&io_port_lock);
 340         return ret;
 341 }
 342 
 343 static u8 read_sel_16bit_indexed_io(const struct dmi_system_event_log *sel,
 344                                     loff_t offset)
 345 {
 346         u8 ret;
 347 
 348         mutex_lock(&io_port_lock);
 349         outw((u16)offset, sel->io.index_addr);
 350         ret = inb(sel->io.data_addr);
 351         mutex_unlock(&io_port_lock);
 352         return ret;
 353 }
 354 
 355 static sel_io_reader sel_io_readers[] = {
 356         [DMI_SEL_ACCESS_METHOD_IO8]     = read_sel_8bit_indexed_io,
 357         [DMI_SEL_ACCESS_METHOD_IO2x8]   = read_sel_2x8bit_indexed_io,
 358         [DMI_SEL_ACCESS_METHOD_IO16]    = read_sel_16bit_indexed_io,
 359 };
 360 
 361 static ssize_t dmi_sel_raw_read_io(struct dmi_sysfs_entry *entry,
 362                                    const struct dmi_system_event_log *sel,
 363                                    char *buf, loff_t pos, size_t count)
 364 {
 365         ssize_t wrote = 0;
 366 
 367         sel_io_reader io_reader = sel_io_readers[sel->access_method];
 368 
 369         while (count && pos < sel->area_length) {
 370                 count--;
 371                 *(buf++) = io_reader(sel, pos++);
 372                 wrote++;
 373         }
 374 
 375         return wrote;
 376 }
 377 
 378 static ssize_t dmi_sel_raw_read_phys32(struct dmi_sysfs_entry *entry,
 379                                        const struct dmi_system_event_log *sel,
 380                                        char *buf, loff_t pos, size_t count)
 381 {
 382         u8 __iomem *mapped;
 383         ssize_t wrote = 0;
 384 
 385         mapped = dmi_remap(sel->access_method_address, sel->area_length);
 386         if (!mapped)
 387                 return -EIO;
 388 
 389         while (count && pos < sel->area_length) {
 390                 count--;
 391                 *(buf++) = readb(mapped + pos++);
 392                 wrote++;
 393         }
 394 
 395         dmi_unmap(mapped);
 396         return wrote;
 397 }
 398 
 399 static ssize_t dmi_sel_raw_read_helper(struct dmi_sysfs_entry *entry,
 400                                        const struct dmi_header *dh,
 401                                        void *_state)
 402 {
 403         struct dmi_read_state *state = _state;
 404         struct dmi_system_event_log sel;
 405 
 406         if (sizeof(sel) > dmi_entry_length(dh))
 407                 return -EIO;
 408 
 409         memcpy(&sel, dh, sizeof(sel));
 410 
 411         switch (sel.access_method) {
 412         case DMI_SEL_ACCESS_METHOD_IO8:
 413         case DMI_SEL_ACCESS_METHOD_IO2x8:
 414         case DMI_SEL_ACCESS_METHOD_IO16:
 415                 return dmi_sel_raw_read_io(entry, &sel, state->buf,
 416                                            state->pos, state->count);
 417         case DMI_SEL_ACCESS_METHOD_PHYS32:
 418                 return dmi_sel_raw_read_phys32(entry, &sel, state->buf,
 419                                                state->pos, state->count);
 420         case DMI_SEL_ACCESS_METHOD_GPNV:
 421                 pr_info("dmi-sysfs: GPNV support missing.\n");
 422                 return -EIO;
 423         default:
 424                 pr_info("dmi-sysfs: Unknown access method %02x\n",
 425                         sel.access_method);
 426                 return -EIO;
 427         }
 428 }
 429 
 430 static ssize_t dmi_sel_raw_read(struct file *filp, struct kobject *kobj,
 431                                 struct bin_attribute *bin_attr,
 432                                 char *buf, loff_t pos, size_t count)
 433 {
 434         struct dmi_sysfs_entry *entry = to_entry(kobj->parent);
 435         struct dmi_read_state state = {
 436                 .buf = buf,
 437                 .pos = pos,
 438                 .count = count,
 439         };
 440 
 441         return find_dmi_entry(entry, dmi_sel_raw_read_helper, &state);
 442 }
 443 
 444 static struct bin_attribute dmi_sel_raw_attr = {
 445         .attr = {.name = "raw_event_log", .mode = 0400},
 446         .read = dmi_sel_raw_read,
 447 };
 448 
 449 static int dmi_system_event_log(struct dmi_sysfs_entry *entry)
 450 {
 451         int ret;
 452 
 453         entry->child = kzalloc(sizeof(*entry->child), GFP_KERNEL);
 454         if (!entry->child)
 455                 return -ENOMEM;
 456         ret = kobject_init_and_add(entry->child,
 457                                    &dmi_system_event_log_ktype,
 458                                    &entry->kobj,
 459                                    "system_event_log");
 460         if (ret)
 461                 goto out_free;
 462 
 463         ret = sysfs_create_bin_file(entry->child, &dmi_sel_raw_attr);
 464         if (ret)
 465                 goto out_del;
 466 
 467         return 0;
 468 
 469 out_del:
 470         kobject_del(entry->child);
 471 out_free:
 472         kfree(entry->child);
 473         return ret;
 474 }
 475 
 476 /*************************************************
 477  * Generic DMI entry support.
 478  *************************************************/
 479 
 480 static ssize_t dmi_sysfs_entry_length(struct dmi_sysfs_entry *entry, char *buf)
 481 {
 482         return sprintf(buf, "%d\n", entry->dh.length);
 483 }
 484 
 485 static ssize_t dmi_sysfs_entry_handle(struct dmi_sysfs_entry *entry, char *buf)
 486 {
 487         return sprintf(buf, "%d\n", entry->dh.handle);
 488 }
 489 
 490 static ssize_t dmi_sysfs_entry_type(struct dmi_sysfs_entry *entry, char *buf)
 491 {
 492         return sprintf(buf, "%d\n", entry->dh.type);
 493 }
 494 
 495 static ssize_t dmi_sysfs_entry_instance(struct dmi_sysfs_entry *entry,
 496                                         char *buf)
 497 {
 498         return sprintf(buf, "%d\n", entry->instance);
 499 }
 500 
 501 static ssize_t dmi_sysfs_entry_position(struct dmi_sysfs_entry *entry,
 502                                         char *buf)
 503 {
 504         return sprintf(buf, "%d\n", entry->position);
 505 }
 506 
 507 static DMI_SYSFS_ATTR(entry, length);
 508 static DMI_SYSFS_ATTR(entry, handle);
 509 static DMI_SYSFS_ATTR(entry, type);
 510 static DMI_SYSFS_ATTR(entry, instance);
 511 static DMI_SYSFS_ATTR(entry, position);
 512 
 513 static struct attribute *dmi_sysfs_entry_attrs[] = {
 514         &dmi_sysfs_attr_entry_length.attr,
 515         &dmi_sysfs_attr_entry_handle.attr,
 516         &dmi_sysfs_attr_entry_type.attr,
 517         &dmi_sysfs_attr_entry_instance.attr,
 518         &dmi_sysfs_attr_entry_position.attr,
 519         NULL,
 520 };
 521 
 522 static ssize_t dmi_entry_raw_read_helper(struct dmi_sysfs_entry *entry,
 523                                          const struct dmi_header *dh,
 524                                          void *_state)
 525 {
 526         struct dmi_read_state *state = _state;
 527         size_t entry_length;
 528 
 529         entry_length = dmi_entry_length(dh);
 530 
 531         return memory_read_from_buffer(state->buf, state->count,
 532                                        &state->pos, dh, entry_length);
 533 }
 534 
 535 static ssize_t dmi_entry_raw_read(struct file *filp,
 536                                   struct kobject *kobj,
 537                                   struct bin_attribute *bin_attr,
 538                                   char *buf, loff_t pos, size_t count)
 539 {
 540         struct dmi_sysfs_entry *entry = to_entry(kobj);
 541         struct dmi_read_state state = {
 542                 .buf = buf,
 543                 .pos = pos,
 544                 .count = count,
 545         };
 546 
 547         return find_dmi_entry(entry, dmi_entry_raw_read_helper, &state);
 548 }
 549 
 550 static const struct bin_attribute dmi_entry_raw_attr = {
 551         .attr = {.name = "raw", .mode = 0400},
 552         .read = dmi_entry_raw_read,
 553 };
 554 
 555 static void dmi_sysfs_entry_release(struct kobject *kobj)
 556 {
 557         struct dmi_sysfs_entry *entry = to_entry(kobj);
 558 
 559         spin_lock(&entry_list_lock);
 560         list_del(&entry->list);
 561         spin_unlock(&entry_list_lock);
 562         kfree(entry);
 563 }
 564 
 565 static struct kobj_type dmi_sysfs_entry_ktype = {
 566         .release = dmi_sysfs_entry_release,
 567         .sysfs_ops = &dmi_sysfs_attr_ops,
 568         .default_attrs = dmi_sysfs_entry_attrs,
 569 };
 570 
 571 static struct kset *dmi_kset;
 572 
 573 /* Global count of all instances seen.  Only for setup */
 574 static int __initdata instance_counts[MAX_ENTRY_TYPE + 1];
 575 
 576 /* Global positional count of all entries seen.  Only for setup */
 577 static int __initdata position_count;
 578 
 579 static void __init dmi_sysfs_register_handle(const struct dmi_header *dh,
 580                                              void *_ret)
 581 {
 582         struct dmi_sysfs_entry *entry;
 583         int *ret = _ret;
 584 
 585         /* If a previous entry saw an error, short circuit */
 586         if (*ret)
 587                 return;
 588 
 589         /* Allocate and register a new entry into the entries set */
 590         entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 591         if (!entry) {
 592                 *ret = -ENOMEM;
 593                 return;
 594         }
 595 
 596         /* Set the key */
 597         memcpy(&entry->dh, dh, sizeof(*dh));
 598         entry->instance = instance_counts[dh->type]++;
 599         entry->position = position_count++;
 600 
 601         entry->kobj.kset = dmi_kset;
 602         *ret = kobject_init_and_add(&entry->kobj, &dmi_sysfs_entry_ktype, NULL,
 603                                     "%d-%d", dh->type, entry->instance);
 604 
 605         if (*ret) {
 606                 kfree(entry);
 607                 return;
 608         }
 609 
 610         /* Thread on the global list for cleanup */
 611         spin_lock(&entry_list_lock);
 612         list_add_tail(&entry->list, &entry_list);
 613         spin_unlock(&entry_list_lock);
 614 
 615         /* Handle specializations by type */
 616         switch (dh->type) {
 617         case DMI_ENTRY_SYSTEM_EVENT_LOG:
 618                 *ret = dmi_system_event_log(entry);
 619                 break;
 620         default:
 621                 /* No specialization */
 622                 break;
 623         }
 624         if (*ret)
 625                 goto out_err;
 626 
 627         /* Create the raw binary file to access the entry */
 628         *ret = sysfs_create_bin_file(&entry->kobj, &dmi_entry_raw_attr);
 629         if (*ret)
 630                 goto out_err;
 631 
 632         return;
 633 out_err:
 634         kobject_put(entry->child);
 635         kobject_put(&entry->kobj);
 636         return;
 637 }
 638 
 639 static void cleanup_entry_list(void)
 640 {
 641         struct dmi_sysfs_entry *entry, *next;
 642 
 643         /* No locks, we are on our way out */
 644         list_for_each_entry_safe(entry, next, &entry_list, list) {
 645                 kobject_put(entry->child);
 646                 kobject_put(&entry->kobj);
 647         }
 648 }
 649 
 650 static int __init dmi_sysfs_init(void)
 651 {
 652         int error;
 653         int val;
 654 
 655         if (!dmi_kobj) {
 656                 pr_debug("dmi-sysfs: dmi entry is absent.\n");
 657                 error = -ENODATA;
 658                 goto err;
 659         }
 660 
 661         dmi_kset = kset_create_and_add("entries", NULL, dmi_kobj);
 662         if (!dmi_kset) {
 663                 error = -ENOMEM;
 664                 goto err;
 665         }
 666 
 667         val = 0;
 668         error = dmi_walk(dmi_sysfs_register_handle, &val);
 669         if (error)
 670                 goto err;
 671         if (val) {
 672                 error = val;
 673                 goto err;
 674         }
 675 
 676         pr_debug("dmi-sysfs: loaded.\n");
 677 
 678         return 0;
 679 err:
 680         cleanup_entry_list();
 681         kset_unregister(dmi_kset);
 682         return error;
 683 }
 684 
 685 /* clean up everything. */
 686 static void __exit dmi_sysfs_exit(void)
 687 {
 688         pr_debug("dmi-sysfs: unloading.\n");
 689         cleanup_entry_list();
 690         kset_unregister(dmi_kset);
 691 }
 692 
 693 module_init(dmi_sysfs_init);
 694 module_exit(dmi_sysfs_exit);
 695 
 696 MODULE_AUTHOR("Mike Waychison <mikew@google.com>");
 697 MODULE_DESCRIPTION("DMI sysfs support");
 698 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */