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