Blame view

drivers/acpi/custom_method.c 2.06 KB
526b4af47   Thomas Renninger   ACPI: Split out c...
1
  /*
5baa1be1c   Zhang Rui   ACPI: fix obsolet...
2
   * custom_method.c - debugfs interface for customizing ACPI control method
526b4af47   Thomas Renninger   ACPI: Split out c...
3
4
5
6
7
8
9
   */
  
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/uaccess.h>
  #include <linux/debugfs.h>
8b48463f8   Lv Zheng   ACPI: Clean up in...
10
  #include <linux/acpi.h>
526b4af47   Thomas Renninger   ACPI: Split out c...
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  
  #include "internal.h"
  
  #define _COMPONENT		ACPI_SYSTEM_COMPONENT
  ACPI_MODULE_NAME("custom_method");
  MODULE_LICENSE("GPL");
  
  static struct dentry *cm_dentry;
  
  /* /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 u32 max_size;
  	static u32 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 = max_size = table.length;
  		buf = kzalloc(max_size, GFP_KERNEL);
  		if (!buf)
  			return -ENOMEM;
  	}
  
  	if (buf == NULL)
  		return -EINVAL;
  
  	if ((*ppos > max_size) ||
  	    (*ppos + count > max_size) ||
  	    (*ppos + count < count) ||
  	    (count > uncopied_bytes))
  		return -EINVAL;
  
  	if (copy_from_user(buf + (*ppos), user_buf, count)) {
  		kfree(buf);
  		buf = NULL;
  		return -EFAULT;
  	}
  
  	uncopied_bytes -= count;
  	*ppos += count;
  
  	if (!uncopied_bytes) {
  		status = acpi_install_method(buf);
  		kfree(buf);
  		buf = NULL;
  		if (ACPI_FAILURE(status))
  			return -EINVAL;
373d4d099   Rusty Russell   taint: add explic...
69
  		add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
526b4af47   Thomas Renninger   ACPI: Split out c...
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
  	}
  
  	return count;
  }
  
  static const struct file_operations cm_fops = {
  	.write = cm_write,
  	.llseek = default_llseek,
  };
  
  static int __init acpi_custom_method_init(void)
  {
  	if (acpi_debugfs_dir == NULL)
  		return -ENOENT;
  
  	cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
  					acpi_debugfs_dir, NULL, &cm_fops);
  	if (cm_dentry == NULL)
  		return -ENODEV;
  
  	return 0;
  }
  
  static void __exit acpi_custom_method_exit(void)
  {
  	if (cm_dentry)
  		debugfs_remove(cm_dentry);
   }
  
  module_init(acpi_custom_method_init);
  module_exit(acpi_custom_method_exit);