From a1a541d86f50a9957beeedb122a035870d602647 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 2 Dec 2009 13:31:00 +0800 Subject: ACPI: support customizing ACPI control methods at runtime Introduce a new debugfs I/F (/sys/kernel/debug/acpi/custom_method) for ACPI, which can be used to customize the ACPI control methods at runtime. We can use this to debug the AML code level bugs instead of overriding the whole DSDT table, without rebuilding/rebooting kernel any more. Detailed description about how to use this debugfs I/F is stated in Documentation/acpi/method-customizing.txt Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/debug.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c index 8a690c3b8e23..0bedd1554f2f 100644 --- a/drivers/acpi/debug.c +++ b/drivers/acpi/debug.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -195,6 +196,79 @@ static int param_get_trace_state(char *buffer, struct kernel_param *kp) module_param_call(trace_state, param_set_trace_state, param_get_trace_state, NULL, 0644); +/* -------------------------------------------------------------------------- + DebugFS Interface + -------------------------------------------------------------------------- */ + +static ssize_t cm_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + static char *buf; + static int uncopied_bytes; + struct acpi_table_header table; + acpi_status status; + + if (!(*ppos)) { + /* parse the table header to get the table length */ + if (count <= sizeof(struct acpi_table_header)) + return -EINVAL; + if (copy_from_user(&table, user_buf, + sizeof(struct acpi_table_header))) + return -EFAULT; + uncopied_bytes = table.length; + buf = kzalloc(uncopied_bytes, GFP_KERNEL); + if (!buf) + return -ENOMEM; + } + + if (uncopied_bytes < count) { + kfree(buf); + return -EINVAL; + } + + if (copy_from_user(buf + (*ppos), user_buf, count)) { + kfree(buf); + return -EFAULT; + } + + uncopied_bytes -= count; + *ppos += count; + + if (!uncopied_bytes) { + status = acpi_install_method(buf); + kfree(buf); + if (ACPI_FAILURE(status)) + return -EINVAL; + } + + return count; +} + +static const struct file_operations cm_fops = { + .write = cm_write, +}; + +static int acpi_debugfs_init(void) +{ + struct dentry *acpi_dir, *cm_dentry; + + acpi_dir = debugfs_create_dir("acpi", NULL); + if (!acpi_dir) + goto err; + + cm_dentry = debugfs_create_file("custom_method", S_IWUGO, + acpi_dir, NULL, &cm_fops); + if (!cm_dentry) + goto err; + + return 0; + +err: + if (acpi_dir) + debugfs_remove(acpi_dir); + return -EINVAL; +} + /* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ @@ -286,7 +360,7 @@ static const struct file_operations acpi_system_debug_proc_fops = { }; #endif -int __init acpi_debug_init(void) +int __init acpi_procfs_init(void) { #ifdef CONFIG_ACPI_PROCFS struct proc_dir_entry *entry; @@ -321,3 +395,10 @@ int __init acpi_debug_init(void) return 0; #endif } + +int __init acpi_debug_init(void) +{ + acpi_debugfs_init(); + acpi_procfs_init(); + return 0; +} -- cgit v1.2.1