1526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger/* 25baa1be1cf4d118002503198bd3843e105868f65Zhang Rui * custom_method.c - debugfs interface for customizing ACPI control method 3526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger */ 4526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 5526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger#include <linux/init.h> 6526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger#include <linux/module.h> 7526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger#include <linux/kernel.h> 8526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger#include <linux/uaccess.h> 9526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger#include <linux/debugfs.h> 108b48463f89429af408ff695244dc627e1acff4f7Lv Zheng#include <linux/acpi.h> 11526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 12526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger#include "internal.h" 13526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 14526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger#define _COMPONENT ACPI_SYSTEM_COMPONENT 15526b4af47f44148c9d665e57723ed9f86634c6e3Thomas RenningerACPI_MODULE_NAME("custom_method"); 16526b4af47f44148c9d665e57723ed9f86634c6e3Thomas RenningerMODULE_LICENSE("GPL"); 17526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 18526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renningerstatic struct dentry *cm_dentry; 19526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 20526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger/* /sys/kernel/debug/acpi/custom_method */ 21526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 22526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renningerstatic ssize_t cm_write(struct file *file, const char __user * user_buf, 23526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger size_t count, loff_t *ppos) 24526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger{ 25526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger static char *buf; 26526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger static u32 max_size; 27526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger static u32 uncopied_bytes; 28526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 29526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger struct acpi_table_header table; 30526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger acpi_status status; 31526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 32526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger if (!(*ppos)) { 33526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger /* parse the table header to get the table length */ 34526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger if (count <= sizeof(struct acpi_table_header)) 35526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger return -EINVAL; 36526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger if (copy_from_user(&table, user_buf, 37526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger sizeof(struct acpi_table_header))) 38526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger return -EFAULT; 39526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger uncopied_bytes = max_size = table.length; 40526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger buf = kzalloc(max_size, GFP_KERNEL); 41526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger if (!buf) 42526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger return -ENOMEM; 43526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger } 44526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 45526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger if (buf == NULL) 46526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger return -EINVAL; 47526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 48526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger if ((*ppos > max_size) || 49526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger (*ppos + count > max_size) || 50526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger (*ppos + count < count) || 51526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger (count > uncopied_bytes)) 52526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger return -EINVAL; 53526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 54526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger if (copy_from_user(buf + (*ppos), user_buf, count)) { 55526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger kfree(buf); 56526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger buf = NULL; 57526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger return -EFAULT; 58526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger } 59526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 60526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger uncopied_bytes -= count; 61526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger *ppos += count; 62526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 63526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger if (!uncopied_bytes) { 64526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger status = acpi_install_method(buf); 65526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger kfree(buf); 66526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger buf = NULL; 67526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger if (ACPI_FAILURE(status)) 68526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger return -EINVAL; 69373d4d099761cb1f637bed488ab3871945882273Rusty Russell add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE); 70526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger } 71526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 72526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger return count; 73526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger} 74526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 75526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renningerstatic const struct file_operations cm_fops = { 76526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger .write = cm_write, 77526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger .llseek = default_llseek, 78526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger}; 79526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 80526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renningerstatic int __init acpi_custom_method_init(void) 81526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger{ 82526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger if (acpi_debugfs_dir == NULL) 83526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger return -ENOENT; 84526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 85526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger cm_dentry = debugfs_create_file("custom_method", S_IWUSR, 86526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger acpi_debugfs_dir, NULL, &cm_fops); 87526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger if (cm_dentry == NULL) 88526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger return -ENODEV; 89526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 90526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger return 0; 91526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger} 92526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 93526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renningerstatic void __exit acpi_custom_method_exit(void) 94526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger{ 95526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger if (cm_dentry) 96526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger debugfs_remove(cm_dentry); 97526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger } 98526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renninger 99526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renningermodule_init(acpi_custom_method_init); 100526b4af47f44148c9d665e57723ed9f86634c6e3Thomas Renningermodule_exit(acpi_custom_method_exit); 101