system.c 7.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
/*
 *  acpi_system.c - ACPI System Driver ($Revision: 63 $)
 *
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or (at
 *  your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */

#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/init.h>
#include <asm/uaccess.h>

#include <acpi/acpi_drivers.h>

#define _COMPONENT		ACPI_SYSTEM_COMPONENT
34
ACPI_MODULE_NAME("system");
Z
Zhang Rui 已提交
35 36 37 38 39
#ifdef MODULE_PARAM_PREFIX
#undef MODULE_PARAM_PREFIX
#endif
#define MODULE_PARAM_PREFIX "acpi."

L
Linus Torvalds 已提交
40 41 42
#define ACPI_SYSTEM_CLASS		"system"
#define ACPI_SYSTEM_DEVICE_NAME		"System"

Z
Zhang Rui 已提交
43 44 45
/*
 * Make ACPICA version work as module param
 */
46 47
static int param_get_acpica_version(char *buffer, struct kernel_param *kp)
{
Z
Zhang Rui 已提交
48 49 50 51 52 53 54 55 56
	int result;

	result = sprintf(buffer, "%x", ACPI_CA_VERSION);

	return result;
}

module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);

57 58 59 60
/* --------------------------------------------------------------------------
                              FS Interface (/sys)
   -------------------------------------------------------------------------- */
static LIST_HEAD(acpi_table_attr_list);
61
static struct kobject *tables_kobj;
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137

struct acpi_table_attr {
	struct bin_attribute attr;
	char name[8];
	int instance;
	struct list_head node;
};

static ssize_t acpi_table_show(struct kobject *kobj,
			       struct bin_attribute *bin_attr, char *buf,
			       loff_t offset, size_t count)
{
	struct acpi_table_attr *table_attr =
	    container_of(bin_attr, struct acpi_table_attr, attr);
	struct acpi_table_header *table_header = NULL;
	acpi_status status;
	ssize_t ret_count = count;

	status =
	    acpi_get_table(table_attr->name, table_attr->instance,
			   &table_header);
	if (ACPI_FAILURE(status))
		return -ENODEV;

	if (offset >= table_header->length) {
		ret_count = 0;
		goto end;
	}

	if (offset + ret_count > table_header->length)
		ret_count = table_header->length - offset;

	memcpy(buf, ((char *)table_header) + offset, ret_count);

      end:
	return ret_count;
}

static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
				 struct acpi_table_header *table_header)
{
	struct acpi_table_header *header = NULL;
	struct acpi_table_attr *attr = NULL;

	memcpy(table_attr->name, table_header->signature, ACPI_NAME_SIZE);

	list_for_each_entry(attr, &acpi_table_attr_list, node) {
		if (!memcmp(table_header->signature, attr->name,
			    ACPI_NAME_SIZE))
			if (table_attr->instance < attr->instance)
				table_attr->instance = attr->instance;
	}
	table_attr->instance++;

	if (table_attr->instance > 1 || (table_attr->instance == 1 &&
					 !acpi_get_table(table_header->
							 signature, 2,
							 &header)))
		sprintf(table_attr->name + 4, "%d", table_attr->instance);

	table_attr->attr.size = 0;
	table_attr->attr.read = acpi_table_show;
	table_attr->attr.attr.name = table_attr->name;
	table_attr->attr.attr.mode = 0444;
	table_attr->attr.attr.owner = THIS_MODULE;

	return;
}

static int acpi_system_sysfs_init(void)
{
	struct acpi_table_attr *table_attr;
	struct acpi_table_header *table_header = NULL;
	int table_index = 0;
	int result;

138 139 140
	tables_kobj = kobject_create_and_add("tables", acpi_kobj);
	if (!tables_kobj)
		return -ENOMEM;
141 142 143 144 145 146 147 148 149 150 151 152 153

	do {
		result = acpi_get_table_by_index(table_index, &table_header);
		if (!result) {
			table_index++;
			table_attr = NULL;
			table_attr =
			    kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL);
			if (!table_attr)
				return -ENOMEM;

			acpi_table_attr_init(table_attr, table_header);
			result =
154
			    sysfs_create_bin_file(tables_kobj,
155 156 157 158 159 160 161 162 163
						  &table_attr->attr);
			if (result) {
				kfree(table_attr);
				return result;
			} else
				list_add_tail(&table_attr->node,
					      &acpi_table_attr_list);
		}
	} while (!result);
164
	kobject_uevent(tables_kobj, KOBJ_ADD);
165 166 167 168

	return 0;
}

L
Linus Torvalds 已提交
169 170 171
/* --------------------------------------------------------------------------
                              FS Interface (/proc)
   -------------------------------------------------------------------------- */
Z
Zhang Rui 已提交
172
#ifdef CONFIG_ACPI_PROCFS
173 174 175 176
#define ACPI_SYSTEM_FILE_INFO		"info"
#define ACPI_SYSTEM_FILE_EVENT		"event"
#define ACPI_SYSTEM_FILE_DSDT		"dsdt"
#define ACPI_SYSTEM_FILE_FADT		"fadt"
L
Linus Torvalds 已提交
177

L
Len Brown 已提交
178
static int acpi_system_read_info(struct seq_file *seq, void *offset)
L
Linus Torvalds 已提交
179 180 181
{

	seq_printf(seq, "version:                 %x\n", ACPI_CA_VERSION);
182
	return 0;
L
Linus Torvalds 已提交
183 184 185 186 187 188 189
}

static int acpi_system_info_open_fs(struct inode *inode, struct file *file)
{
	return single_open(file, acpi_system_read_info, PDE(inode)->data);
}

190
static const struct file_operations acpi_system_info_ops = {
L
Len Brown 已提交
191 192 193 194
	.open = acpi_system_info_open_fs,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
L
Linus Torvalds 已提交
195 196
};

L
Len Brown 已提交
197 198
static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
				     loff_t *);
L
Linus Torvalds 已提交
199

200
static const struct file_operations acpi_system_dsdt_ops = {
L
Len Brown 已提交
201
	.read = acpi_system_read_dsdt,
L
Linus Torvalds 已提交
202 203 204
};

static ssize_t
L
Len Brown 已提交
205 206
acpi_system_read_dsdt(struct file *file,
		      char __user * buffer, size_t count, loff_t * ppos)
L
Linus Torvalds 已提交
207
{
L
Len Brown 已提交
208
	acpi_status status = AE_OK;
209
	struct acpi_table_header *dsdt = NULL;
L
Len Brown 已提交
210
	ssize_t res;
L
Linus Torvalds 已提交
211

212
	status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt);
L
Linus Torvalds 已提交
213
	if (ACPI_FAILURE(status))
214
		return -ENODEV;
L
Linus Torvalds 已提交
215

216
	res = simple_read_from_buffer(buffer, count, ppos, dsdt, dsdt->length);
L
Linus Torvalds 已提交
217

218
	return res;
L
Linus Torvalds 已提交
219 220
}

L
Len Brown 已提交
221 222
static ssize_t acpi_system_read_fadt(struct file *, char __user *, size_t,
				     loff_t *);
L
Linus Torvalds 已提交
223

224
static const struct file_operations acpi_system_fadt_ops = {
L
Len Brown 已提交
225
	.read = acpi_system_read_fadt,
L
Linus Torvalds 已提交
226 227 228
};

static ssize_t
L
Len Brown 已提交
229 230
acpi_system_read_fadt(struct file *file,
		      char __user * buffer, size_t count, loff_t * ppos)
L
Linus Torvalds 已提交
231
{
L
Len Brown 已提交
232
	acpi_status status = AE_OK;
233
	struct acpi_table_header *fadt = NULL;
L
Len Brown 已提交
234
	ssize_t res;
L
Linus Torvalds 已提交
235

236
	status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt);
L
Linus Torvalds 已提交
237
	if (ACPI_FAILURE(status))
238
		return -ENODEV;
L
Linus Torvalds 已提交
239

240
	res = simple_read_from_buffer(buffer, count, ppos, fadt, fadt->length);
L
Linus Torvalds 已提交
241

242
	return res;
L
Linus Torvalds 已提交
243 244
}

245
static int acpi_system_procfs_init(void)
L
Linus Torvalds 已提交
246
{
L
Len Brown 已提交
247
	struct proc_dir_entry *entry;
L
Linus Torvalds 已提交
248
	int error = 0;
L
Len Brown 已提交
249
	char *name;
L
Linus Torvalds 已提交
250 251 252

	/* 'info' [R] */
	name = ACPI_SYSTEM_FILE_INFO;
L
Len Brown 已提交
253
	entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
L
Linus Torvalds 已提交
254 255 256 257 258 259 260 261 262 263 264
	if (!entry)
		goto Error;
	else {
		entry->proc_fops = &acpi_system_info_ops;
	}

	/* 'dsdt' [R] */
	name = ACPI_SYSTEM_FILE_DSDT;
	entry = create_proc_entry(name, S_IRUSR, acpi_root_dir);
	if (entry)
		entry->proc_fops = &acpi_system_dsdt_ops;
L
Len Brown 已提交
265
	else
L
Linus Torvalds 已提交
266 267 268 269 270 271 272 273 274 275
		goto Error;

	/* 'fadt' [R] */
	name = ACPI_SYSTEM_FILE_FADT;
	entry = create_proc_entry(name, S_IRUSR, acpi_root_dir);
	if (entry)
		entry->proc_fops = &acpi_system_fadt_ops;
	else
		goto Error;

L
Len Brown 已提交
276
      Done:
277
	return error;
L
Linus Torvalds 已提交
278

L
Len Brown 已提交
279
      Error:
L
Linus Torvalds 已提交
280 281 282 283 284 285 286
	remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
	remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
	remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);

	error = -EFAULT;
	goto Done;
}
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
#else
static int acpi_system_procfs_init(void)
{
	return 0;
}
#endif

static int __init acpi_system_init(void)
{
	int result = 0;

	if (acpi_disabled)
		return 0;

	result = acpi_system_procfs_init();
	if (result)
		return result;

	result = acpi_system_sysfs_init();

	return result;
}
L
Linus Torvalds 已提交
309 310

subsys_initcall(acpi_system_init);