diff options
Diffstat (limited to 'drivers/acpi/debugfs.c')
| -rw-r--r-- | drivers/acpi/debugfs.c | 85 | 
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/acpi/debugfs.c b/drivers/acpi/debugfs.c new file mode 100644 index 00000000000..abfcf9f6e76 --- /dev/null +++ b/drivers/acpi/debugfs.c @@ -0,0 +1,85 @@ +/* + * debugfs.c - ACPI debugfs interface to userspace. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> +#include <acpi/acpi_drivers.h> + +#define _COMPONENT		ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME("debugfs"); + +/* /sys/kernel/debug/acpi/custom_method */ + +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; +		add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); +	} + +	return count; +} + +static const struct file_operations cm_fops = { +	.write = cm_write, +}; + +int __init 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; +}  |