1948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison/* 2948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * dmi-sysfs.c 3948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * 4948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * This module exports the DMI tables read-only to userspace through the 5948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * sysfs file system. 6948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * 7948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * Data is currently found below 8948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * /sys/firmware/dmi/... 9948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * 10948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * DMI attributes are presented in attribute files with names 11948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * formatted using %d-%d, so that the first integer indicates the 12948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * structure type (0-255), and the second field is the instance of that 13948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * entry. 14948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * 15948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * Copyright 2011 Google, Inc. 16948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison */ 17948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 18948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison#include <linux/kernel.h> 19948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison#include <linux/init.h> 20948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison#include <linux/module.h> 21948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison#include <linux/types.h> 22948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison#include <linux/kobject.h> 23948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison#include <linux/dmi.h> 24948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison#include <linux/capability.h> 25948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison#include <linux/slab.h> 26948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison#include <linux/list.h> 27948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison#include <linux/io.h> 28948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 29948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison#define MAX_ENTRY_TYPE 255 /* Most of these aren't used, but we consider 30948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison the top entry type is only 8 bits */ 31948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 32948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstruct dmi_sysfs_entry { 33948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct dmi_header dh; 34948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct kobject kobj; 35948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison int instance; 36948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison int position; 37948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct list_head list; 38925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison struct kobject *child; 39948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison}; 40948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 41948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison/* 42948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * Global list of dmi_sysfs_entry. Even though this should only be 43948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * manipulated at setup and teardown, the lazy nature of the kobject 44948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * system means we get lazy removes. 45948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison */ 46948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic LIST_HEAD(entry_list); 47948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic DEFINE_SPINLOCK(entry_list_lock); 48948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 49948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison/* dmi_sysfs_attribute - Top level attribute. used by all entries. */ 50948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstruct dmi_sysfs_attribute { 51948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct attribute attr; 52948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison ssize_t (*show)(struct dmi_sysfs_entry *entry, char *buf); 53948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison}; 54948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 55948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison#define DMI_SYSFS_ATTR(_entry, _name) \ 56948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstruct dmi_sysfs_attribute dmi_sysfs_attr_##_entry##_##_name = { \ 57948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .attr = {.name = __stringify(_name), .mode = 0400}, \ 58948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .show = dmi_sysfs_##_entry##_##_name, \ 59948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 60948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 61948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison/* 62948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * dmi_sysfs_mapped_attribute - Attribute where we require the entry be 63948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * mapped in. Use in conjunction with dmi_sysfs_specialize_attr_ops. 64948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison */ 65948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstruct dmi_sysfs_mapped_attribute { 66948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct attribute attr; 67948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison ssize_t (*show)(struct dmi_sysfs_entry *entry, 68948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison const struct dmi_header *dh, 69948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison char *buf); 70948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison}; 71948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 72948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison#define DMI_SYSFS_MAPPED_ATTR(_entry, _name) \ 73948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstruct dmi_sysfs_mapped_attribute dmi_sysfs_attr_##_entry##_##_name = { \ 74948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .attr = {.name = __stringify(_name), .mode = 0400}, \ 75948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .show = dmi_sysfs_##_entry##_##_name, \ 76948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 77948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 78948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison/************************************************* 79948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * Generic DMI entry support. 80948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison *************************************************/ 81925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychisonstatic void dmi_entry_free(struct kobject *kobj) 82925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison{ 83925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison kfree(kobj); 84925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison} 85948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 86948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic struct dmi_sysfs_entry *to_entry(struct kobject *kobj) 87948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 88948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return container_of(kobj, struct dmi_sysfs_entry, kobj); 89948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 90948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 91948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic struct dmi_sysfs_attribute *to_attr(struct attribute *attr) 92948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 93948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return container_of(attr, struct dmi_sysfs_attribute, attr); 94948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 95948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 96948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic ssize_t dmi_sysfs_attr_show(struct kobject *kobj, 97948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct attribute *_attr, char *buf) 98948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 99948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct dmi_sysfs_entry *entry = to_entry(kobj); 100948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct dmi_sysfs_attribute *attr = to_attr(_attr); 101948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 102948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison /* DMI stuff is only ever admin visible */ 103948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison if (!capable(CAP_SYS_ADMIN)) 104948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return -EACCES; 105948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 106948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return attr->show(entry, buf); 107948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 108948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 109948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic const struct sysfs_ops dmi_sysfs_attr_ops = { 110948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .show = dmi_sysfs_attr_show, 111948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison}; 112948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 113948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisontypedef ssize_t (*dmi_callback)(struct dmi_sysfs_entry *, 114948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison const struct dmi_header *dh, void *); 115948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 116948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstruct find_dmi_data { 117948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct dmi_sysfs_entry *entry; 118948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison dmi_callback callback; 119948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison void *private; 120948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison int instance_countdown; 121948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison ssize_t ret; 122948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison}; 123948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 124948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic void find_dmi_entry_helper(const struct dmi_header *dh, 125948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison void *_data) 126948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 127948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct find_dmi_data *data = _data; 128948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct dmi_sysfs_entry *entry = data->entry; 129948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 130948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison /* Is this the entry we want? */ 131948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison if (dh->type != entry->dh.type) 132948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return; 133948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 134948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison if (data->instance_countdown != 0) { 135948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison /* try the next instance? */ 136948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison data->instance_countdown--; 137948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return; 138948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison } 139948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 140948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison /* 141948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * Don't ever revisit the instance. Short circuit later 142948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * instances by letting the instance_countdown run negative 143948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison */ 144948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison data->instance_countdown--; 145948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 146948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison /* Found the entry */ 147948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison data->ret = data->callback(entry, dh, data->private); 148948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 149948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 150948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison/* State for passing the read parameters through dmi_find_entry() */ 151948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstruct dmi_read_state { 152948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison char *buf; 153948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison loff_t pos; 154948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison size_t count; 155948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison}; 156948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 157948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic ssize_t find_dmi_entry(struct dmi_sysfs_entry *entry, 158948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison dmi_callback callback, void *private) 159948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 160948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct find_dmi_data data = { 161948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .entry = entry, 162948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .callback = callback, 163948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .private = private, 164948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .instance_countdown = entry->instance, 165948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .ret = -EIO, /* To signal the entry disappeared */ 166948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison }; 167948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison int ret; 168948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 169948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison ret = dmi_walk(find_dmi_entry_helper, &data); 170948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison /* This shouldn't happen, but just in case. */ 171948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison if (ret) 172948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return -EINVAL; 173948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return data.ret; 174948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 175948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 176948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison/* 177948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * Calculate and return the byte length of the dmi entry identified by 178948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * dh. This includes both the formatted portion as well as the 179948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * unformatted string space, including the two trailing nul characters. 180948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison */ 181948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic size_t dmi_entry_length(const struct dmi_header *dh) 182948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 183948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison const char *p = (const char *)dh; 184948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 185948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison p += dh->length; 186948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 187948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison while (p[0] || p[1]) 188948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison p++; 189948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 190948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return 2 + p - (const char *)dh; 191948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 192948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 193948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison/************************************************* 194925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison * Support bits for specialized DMI entry support 195925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison *************************************************/ 196925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychisonstruct dmi_entry_attr_show_data { 197925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison struct attribute *attr; 198925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison char *buf; 199925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison}; 200925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 201925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychisonstatic ssize_t dmi_entry_attr_show_helper(struct dmi_sysfs_entry *entry, 202925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison const struct dmi_header *dh, 203925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison void *_data) 204925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison{ 205925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison struct dmi_entry_attr_show_data *data = _data; 206925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison struct dmi_sysfs_mapped_attribute *attr; 207925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 208925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison attr = container_of(data->attr, 209925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison struct dmi_sysfs_mapped_attribute, attr); 210925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison return attr->show(entry, dh, data->buf); 211925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison} 212925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 213925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychisonstatic ssize_t dmi_entry_attr_show(struct kobject *kobj, 214925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison struct attribute *attr, 215925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison char *buf) 216925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison{ 217925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison struct dmi_entry_attr_show_data data = { 218925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison .attr = attr, 219925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison .buf = buf, 220925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison }; 221925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison /* Find the entry according to our parent and call the 222925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison * normalized show method hanging off of the attribute */ 223925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison return find_dmi_entry(to_entry(kobj->parent), 224925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison dmi_entry_attr_show_helper, &data); 225925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison} 226925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 227925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychisonstatic const struct sysfs_ops dmi_sysfs_specialize_attr_ops = { 228925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison .show = dmi_entry_attr_show, 229925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison}; 230925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 231925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison/************************************************* 232925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison * Specialized DMI entry support. 233925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison *************************************************/ 234925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 235925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison/*** Type 15 - System Event Table ***/ 236925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 237925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison#define DMI_SEL_ACCESS_METHOD_IO8 0x00 238925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison#define DMI_SEL_ACCESS_METHOD_IO2x8 0x01 239925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison#define DMI_SEL_ACCESS_METHOD_IO16 0x02 240925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison#define DMI_SEL_ACCESS_METHOD_PHYS32 0x03 241925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison#define DMI_SEL_ACCESS_METHOD_GPNV 0x04 242925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 243925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychisonstruct dmi_system_event_log { 244925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison struct dmi_header header; 245925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u16 area_length; 246925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u16 header_start_offset; 247925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u16 data_start_offset; 248925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u8 access_method; 249925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u8 status; 250925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u32 change_token; 251925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison union { 252925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison struct { 253925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u16 index_addr; 254925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u16 data_addr; 255925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison } io; 256925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u32 phys_addr32; 257925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u16 gpnv_handle; 258925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u32 access_method_address; 259925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison }; 260925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u8 header_format; 261925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u8 type_descriptors_supported_count; 262925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u8 per_log_type_descriptor_length; 263925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison u8 supported_log_type_descriptos[0]; 264925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison} __packed; 265925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 266925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison#define DMI_SYSFS_SEL_FIELD(_field) \ 267925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychisonstatic ssize_t dmi_sysfs_sel_##_field(struct dmi_sysfs_entry *entry, \ 268925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison const struct dmi_header *dh, \ 269925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison char *buf) \ 270925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison{ \ 27166245ad025e02fe9e727c03d43308bb24e346bb6Mike Waychison struct dmi_system_event_log sel; \ 27266245ad025e02fe9e727c03d43308bb24e346bb6Mike Waychison if (sizeof(sel) > dmi_entry_length(dh)) \ 273925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison return -EIO; \ 27466245ad025e02fe9e727c03d43308bb24e346bb6Mike Waychison memcpy(&sel, dh, sizeof(sel)); \ 27566245ad025e02fe9e727c03d43308bb24e346bb6Mike Waychison return sprintf(buf, "%u\n", sel._field); \ 276925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison} \ 277925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychisonstatic DMI_SYSFS_MAPPED_ATTR(sel, _field) 278925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 279925a1da7477fc4ba5849c6f0243934fa5072493cMike WaychisonDMI_SYSFS_SEL_FIELD(area_length); 280925a1da7477fc4ba5849c6f0243934fa5072493cMike WaychisonDMI_SYSFS_SEL_FIELD(header_start_offset); 281925a1da7477fc4ba5849c6f0243934fa5072493cMike WaychisonDMI_SYSFS_SEL_FIELD(data_start_offset); 282925a1da7477fc4ba5849c6f0243934fa5072493cMike WaychisonDMI_SYSFS_SEL_FIELD(access_method); 283925a1da7477fc4ba5849c6f0243934fa5072493cMike WaychisonDMI_SYSFS_SEL_FIELD(status); 284925a1da7477fc4ba5849c6f0243934fa5072493cMike WaychisonDMI_SYSFS_SEL_FIELD(change_token); 285925a1da7477fc4ba5849c6f0243934fa5072493cMike WaychisonDMI_SYSFS_SEL_FIELD(access_method_address); 286925a1da7477fc4ba5849c6f0243934fa5072493cMike WaychisonDMI_SYSFS_SEL_FIELD(header_format); 287925a1da7477fc4ba5849c6f0243934fa5072493cMike WaychisonDMI_SYSFS_SEL_FIELD(type_descriptors_supported_count); 288925a1da7477fc4ba5849c6f0243934fa5072493cMike WaychisonDMI_SYSFS_SEL_FIELD(per_log_type_descriptor_length); 289925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 290925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychisonstatic struct attribute *dmi_sysfs_sel_attrs[] = { 291925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison &dmi_sysfs_attr_sel_area_length.attr, 292925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison &dmi_sysfs_attr_sel_header_start_offset.attr, 293925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison &dmi_sysfs_attr_sel_data_start_offset.attr, 294925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison &dmi_sysfs_attr_sel_access_method.attr, 295925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison &dmi_sysfs_attr_sel_status.attr, 296925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison &dmi_sysfs_attr_sel_change_token.attr, 297925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison &dmi_sysfs_attr_sel_access_method_address.attr, 298925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison &dmi_sysfs_attr_sel_header_format.attr, 299925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison &dmi_sysfs_attr_sel_type_descriptors_supported_count.attr, 300925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison &dmi_sysfs_attr_sel_per_log_type_descriptor_length.attr, 301925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison NULL, 302925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison}; 303925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 304925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 305925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychisonstatic struct kobj_type dmi_system_event_log_ktype = { 306925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison .release = dmi_entry_free, 307925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison .sysfs_ops = &dmi_sysfs_specialize_attr_ops, 308925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison .default_attrs = dmi_sysfs_sel_attrs, 309925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison}; 310925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 311a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychisontypedef u8 (*sel_io_reader)(const struct dmi_system_event_log *sel, 312a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison loff_t offset); 313a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 314a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychisonstatic DEFINE_MUTEX(io_port_lock); 315a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 316a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychisonstatic u8 read_sel_8bit_indexed_io(const struct dmi_system_event_log *sel, 317a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison loff_t offset) 318a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison{ 319a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison u8 ret; 320a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 321a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison mutex_lock(&io_port_lock); 322a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison outb((u8)offset, sel->io.index_addr); 323a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison ret = inb(sel->io.data_addr); 324a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison mutex_unlock(&io_port_lock); 325a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison return ret; 326a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison} 327a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 328a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychisonstatic u8 read_sel_2x8bit_indexed_io(const struct dmi_system_event_log *sel, 329a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison loff_t offset) 330a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison{ 331a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison u8 ret; 332a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 333a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison mutex_lock(&io_port_lock); 334a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison outb((u8)offset, sel->io.index_addr); 335a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison outb((u8)(offset >> 8), sel->io.index_addr + 1); 336a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison ret = inb(sel->io.data_addr); 337a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison mutex_unlock(&io_port_lock); 338a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison return ret; 339a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison} 340a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 341a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychisonstatic u8 read_sel_16bit_indexed_io(const struct dmi_system_event_log *sel, 342a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison loff_t offset) 343a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison{ 344a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison u8 ret; 345a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 346a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison mutex_lock(&io_port_lock); 347a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison outw((u16)offset, sel->io.index_addr); 348a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison ret = inb(sel->io.data_addr); 349a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison mutex_unlock(&io_port_lock); 350a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison return ret; 351a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison} 352a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 353a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychisonstatic sel_io_reader sel_io_readers[] = { 354a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison [DMI_SEL_ACCESS_METHOD_IO8] = read_sel_8bit_indexed_io, 355a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison [DMI_SEL_ACCESS_METHOD_IO2x8] = read_sel_2x8bit_indexed_io, 356a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison [DMI_SEL_ACCESS_METHOD_IO16] = read_sel_16bit_indexed_io, 357a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison}; 358a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 359a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychisonstatic ssize_t dmi_sel_raw_read_io(struct dmi_sysfs_entry *entry, 360a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison const struct dmi_system_event_log *sel, 361a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison char *buf, loff_t pos, size_t count) 362a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison{ 363a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison ssize_t wrote = 0; 364a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 365a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison sel_io_reader io_reader = sel_io_readers[sel->access_method]; 366a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 367a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison while (count && pos < sel->area_length) { 368a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison count--; 369a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison *(buf++) = io_reader(sel, pos++); 370a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison wrote++; 371a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison } 372a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 373a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison return wrote; 374a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison} 375a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 376a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychisonstatic ssize_t dmi_sel_raw_read_phys32(struct dmi_sysfs_entry *entry, 377a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison const struct dmi_system_event_log *sel, 378a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison char *buf, loff_t pos, size_t count) 379a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison{ 380a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison u8 __iomem *mapped; 381a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison ssize_t wrote = 0; 382a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 383a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison mapped = ioremap(sel->access_method_address, sel->area_length); 384a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison if (!mapped) 385a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison return -EIO; 386a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 387a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison while (count && pos < sel->area_length) { 388a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison count--; 389a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison *(buf++) = readb(mapped + pos++); 390a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison wrote++; 391a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison } 392a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 393a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison iounmap(mapped); 394a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison return wrote; 395a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison} 396a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 397a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychisonstatic ssize_t dmi_sel_raw_read_helper(struct dmi_sysfs_entry *entry, 398a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison const struct dmi_header *dh, 399a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison void *_state) 400a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison{ 401a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison struct dmi_read_state *state = _state; 40266245ad025e02fe9e727c03d43308bb24e346bb6Mike Waychison struct dmi_system_event_log sel; 403a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 40466245ad025e02fe9e727c03d43308bb24e346bb6Mike Waychison if (sizeof(sel) > dmi_entry_length(dh)) 405a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison return -EIO; 406a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 40766245ad025e02fe9e727c03d43308bb24e346bb6Mike Waychison memcpy(&sel, dh, sizeof(sel)); 40866245ad025e02fe9e727c03d43308bb24e346bb6Mike Waychison 40966245ad025e02fe9e727c03d43308bb24e346bb6Mike Waychison switch (sel.access_method) { 410a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison case DMI_SEL_ACCESS_METHOD_IO8: 411a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison case DMI_SEL_ACCESS_METHOD_IO2x8: 412a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison case DMI_SEL_ACCESS_METHOD_IO16: 41366245ad025e02fe9e727c03d43308bb24e346bb6Mike Waychison return dmi_sel_raw_read_io(entry, &sel, state->buf, 414a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison state->pos, state->count); 415a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison case DMI_SEL_ACCESS_METHOD_PHYS32: 41666245ad025e02fe9e727c03d43308bb24e346bb6Mike Waychison return dmi_sel_raw_read_phys32(entry, &sel, state->buf, 417a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison state->pos, state->count); 418a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison case DMI_SEL_ACCESS_METHOD_GPNV: 419a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison pr_info("dmi-sysfs: GPNV support missing.\n"); 420a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison return -EIO; 421a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison default: 422a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison pr_info("dmi-sysfs: Unknown access method %02x\n", 42366245ad025e02fe9e727c03d43308bb24e346bb6Mike Waychison sel.access_method); 424a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison return -EIO; 425a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison } 426a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison} 427a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 428a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychisonstatic ssize_t dmi_sel_raw_read(struct file *filp, struct kobject *kobj, 429a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison struct bin_attribute *bin_attr, 430a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison char *buf, loff_t pos, size_t count) 431a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison{ 432a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison struct dmi_sysfs_entry *entry = to_entry(kobj->parent); 433a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison struct dmi_read_state state = { 434a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison .buf = buf, 435a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison .pos = pos, 436a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison .count = count, 437a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison }; 438a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 439a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison return find_dmi_entry(entry, dmi_sel_raw_read_helper, &state); 440a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison} 441a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 442a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychisonstatic struct bin_attribute dmi_sel_raw_attr = { 443a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison .attr = {.name = "raw_event_log", .mode = 0400}, 444a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison .read = dmi_sel_raw_read, 445a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison}; 446a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 447925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychisonstatic int dmi_system_event_log(struct dmi_sysfs_entry *entry) 448925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison{ 449925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison int ret; 450925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 451925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison entry->child = kzalloc(sizeof(*entry->child), GFP_KERNEL); 452925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison if (!entry->child) 453925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison return -ENOMEM; 454925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison ret = kobject_init_and_add(entry->child, 455925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison &dmi_system_event_log_ktype, 456925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison &entry->kobj, 457925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison "system_event_log"); 458925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison if (ret) 459925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison goto out_free; 460a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 461a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison ret = sysfs_create_bin_file(entry->child, &dmi_sel_raw_attr); 462a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison if (ret) 463a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison goto out_del; 464a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 465a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison return 0; 466a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison 467a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychisonout_del: 468a3857a5c9893aa69d44be6e881927b0950b1d931Mike Waychison kobject_del(entry->child); 469925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychisonout_free: 470925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison kfree(entry->child); 471925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison return ret; 472925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison} 473925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 474925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison/************************************************* 475948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison * Generic DMI entry support. 476948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison *************************************************/ 477948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 478948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic ssize_t dmi_sysfs_entry_length(struct dmi_sysfs_entry *entry, char *buf) 479948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 480948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return sprintf(buf, "%d\n", entry->dh.length); 481948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 482948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 483948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic ssize_t dmi_sysfs_entry_handle(struct dmi_sysfs_entry *entry, char *buf) 484948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 485948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return sprintf(buf, "%d\n", entry->dh.handle); 486948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 487948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 488948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic ssize_t dmi_sysfs_entry_type(struct dmi_sysfs_entry *entry, char *buf) 489948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 490948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return sprintf(buf, "%d\n", entry->dh.type); 491948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 492948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 493948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic ssize_t dmi_sysfs_entry_instance(struct dmi_sysfs_entry *entry, 494948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison char *buf) 495948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 496948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return sprintf(buf, "%d\n", entry->instance); 497948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 498948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 499948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic ssize_t dmi_sysfs_entry_position(struct dmi_sysfs_entry *entry, 500948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison char *buf) 501948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 502948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return sprintf(buf, "%d\n", entry->position); 503948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 504948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 505948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic DMI_SYSFS_ATTR(entry, length); 506948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic DMI_SYSFS_ATTR(entry, handle); 507948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic DMI_SYSFS_ATTR(entry, type); 508948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic DMI_SYSFS_ATTR(entry, instance); 509948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic DMI_SYSFS_ATTR(entry, position); 510948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 511948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic struct attribute *dmi_sysfs_entry_attrs[] = { 512948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison &dmi_sysfs_attr_entry_length.attr, 513948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison &dmi_sysfs_attr_entry_handle.attr, 514948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison &dmi_sysfs_attr_entry_type.attr, 515948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison &dmi_sysfs_attr_entry_instance.attr, 516948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison &dmi_sysfs_attr_entry_position.attr, 517948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison NULL, 518948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison}; 519948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 520948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic ssize_t dmi_entry_raw_read_helper(struct dmi_sysfs_entry *entry, 521948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison const struct dmi_header *dh, 522948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison void *_state) 523948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 524948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct dmi_read_state *state = _state; 525948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison size_t entry_length; 526948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 527948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison entry_length = dmi_entry_length(dh); 528948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 529948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return memory_read_from_buffer(state->buf, state->count, 530948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison &state->pos, dh, entry_length); 531948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 532948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 533948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic ssize_t dmi_entry_raw_read(struct file *filp, 534948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct kobject *kobj, 535948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct bin_attribute *bin_attr, 536948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison char *buf, loff_t pos, size_t count) 537948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 538948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct dmi_sysfs_entry *entry = to_entry(kobj); 539948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct dmi_read_state state = { 540948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .buf = buf, 541948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .pos = pos, 542948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .count = count, 543948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison }; 544948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 545948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return find_dmi_entry(entry, dmi_entry_raw_read_helper, &state); 546948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 547948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 548948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic const struct bin_attribute dmi_entry_raw_attr = { 549948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .attr = {.name = "raw", .mode = 0400}, 550948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .read = dmi_entry_raw_read, 551948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison}; 552948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 553948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic void dmi_sysfs_entry_release(struct kobject *kobj) 554948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 555948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct dmi_sysfs_entry *entry = to_entry(kobj); 556a61aca2854eaecf2d1bffbaf1fc368fb1a20c850Bjorn Helgaas 557948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison spin_lock(&entry_list_lock); 558948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison list_del(&entry->list); 559948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison spin_unlock(&entry_list_lock); 560948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison kfree(entry); 561948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 562948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 563948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic struct kobj_type dmi_sysfs_entry_ktype = { 564948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .release = dmi_sysfs_entry_release, 565948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .sysfs_ops = &dmi_sysfs_attr_ops, 566948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison .default_attrs = dmi_sysfs_entry_attrs, 567948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison}; 568948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 569948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic struct kobject *dmi_kobj; 570948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic struct kset *dmi_kset; 571948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 572948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison/* Global count of all instances seen. Only for setup */ 573948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic int __initdata instance_counts[MAX_ENTRY_TYPE + 1]; 574948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 575948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison/* Global positional count of all entries seen. Only for setup */ 576948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic int __initdata position_count; 577948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 578948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic void __init dmi_sysfs_register_handle(const struct dmi_header *dh, 579948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison void *_ret) 580948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 581948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct dmi_sysfs_entry *entry; 582948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison int *ret = _ret; 583948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 584948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison /* If a previous entry saw an error, short circuit */ 585948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison if (*ret) 586948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return; 587948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 588948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison /* Allocate and register a new entry into the entries set */ 589948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison entry = kzalloc(sizeof(*entry), GFP_KERNEL); 590948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison if (!entry) { 591948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison *ret = -ENOMEM; 592948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return; 593948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison } 594948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 595948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison /* Set the key */ 59666245ad025e02fe9e727c03d43308bb24e346bb6Mike Waychison memcpy(&entry->dh, dh, sizeof(*dh)); 597948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison entry->instance = instance_counts[dh->type]++; 598948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison entry->position = position_count++; 599948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 600948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison entry->kobj.kset = dmi_kset; 601948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison *ret = kobject_init_and_add(&entry->kobj, &dmi_sysfs_entry_ktype, NULL, 602948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison "%d-%d", dh->type, entry->instance); 603948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 604948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison if (*ret) { 605948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison kfree(entry); 606948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return; 607948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison } 608948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 609948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison /* Thread on the global list for cleanup */ 610948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison spin_lock(&entry_list_lock); 611948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison list_add_tail(&entry->list, &entry_list); 612948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison spin_unlock(&entry_list_lock); 613948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 614925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison /* Handle specializations by type */ 615925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison switch (dh->type) { 616925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison case DMI_ENTRY_SYSTEM_EVENT_LOG: 617925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison *ret = dmi_system_event_log(entry); 618925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison break; 619925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison default: 620925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison /* No specialization */ 621925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison break; 622925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison } 623925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison if (*ret) 624925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison goto out_err; 625925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison 626948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison /* Create the raw binary file to access the entry */ 627948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison *ret = sysfs_create_bin_file(&entry->kobj, &dmi_entry_raw_attr); 628948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison if (*ret) 629948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison goto out_err; 630948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 631948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return; 632948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonout_err: 633925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison kobject_put(entry->child); 634948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison kobject_put(&entry->kobj); 635948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return; 636948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 637948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 638948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic void cleanup_entry_list(void) 639948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 640948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison struct dmi_sysfs_entry *entry, *next; 641948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 642948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison /* No locks, we are on our way out */ 643948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison list_for_each_entry_safe(entry, next, &entry_list, list) { 644925a1da7477fc4ba5849c6f0243934fa5072493cMike Waychison kobject_put(entry->child); 645948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison kobject_put(&entry->kobj); 646948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison } 647948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 648948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 649948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic int __init dmi_sysfs_init(void) 650948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 651948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison int error = -ENOMEM; 652948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison int val; 653948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 654948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison /* Set up our directory */ 655948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison dmi_kobj = kobject_create_and_add("dmi", firmware_kobj); 656948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison if (!dmi_kobj) 657948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison goto err; 658948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 659948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison dmi_kset = kset_create_and_add("entries", NULL, dmi_kobj); 660948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison if (!dmi_kset) 661948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison goto err; 662948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 663948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison val = 0; 664948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison error = dmi_walk(dmi_sysfs_register_handle, &val); 665948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison if (error) 666948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison goto err; 667948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison if (val) { 668948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison error = val; 669948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison goto err; 670948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison } 671948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 672948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison pr_debug("dmi-sysfs: loaded.\n"); 673948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 674948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return 0; 675948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonerr: 676948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison cleanup_entry_list(); 677948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison kset_unregister(dmi_kset); 678948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison kobject_put(dmi_kobj); 679948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison return error; 680948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 681948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 682948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison/* clean up everything. */ 683948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonstatic void __exit dmi_sysfs_exit(void) 684948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison{ 685948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison pr_debug("dmi-sysfs: unloading.\n"); 686948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison cleanup_entry_list(); 687948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison kset_unregister(dmi_kset); 688d0f80f9aadf60adc4caafed0d2b01e79a315ff80Bjorn Helgaas kobject_del(dmi_kobj); 689948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison kobject_put(dmi_kobj); 690948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison} 691948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 692948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonmodule_init(dmi_sysfs_init); 693948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychisonmodule_exit(dmi_sysfs_exit); 694948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike Waychison 695948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike WaychisonMODULE_AUTHOR("Mike Waychison <mikew@google.com>"); 696948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike WaychisonMODULE_DESCRIPTION("DMI sysfs support"); 697948af1f0bbc8526448e8cbe3f8d3bf211bdf5181Mike WaychisonMODULE_LICENSE("GPL"); 698