aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/acpi/method-customizing.txt66
-rw-r--r--drivers/acpi/debug.c83
2 files changed, 148 insertions, 1 deletions
diff --git a/Documentation/acpi/method-customizing.txt b/Documentation/acpi/method-customizing.txt
new file mode 100644
index 000000000000..e628cd23ca80
--- /dev/null
+++ b/Documentation/acpi/method-customizing.txt
@@ -0,0 +1,66 @@
1Linux ACPI Custom Control Method How To
2=======================================
3
4Written by Zhang Rui <rui.zhang@intel.com>
5
6
7Linux supports customizing ACPI control methods at runtime.
8
9Users can use this to
101. override an existing method which may not work correctly,
11 or just for debugging purposes.
122. insert a completely new method in order to create a missing
13 method such as _OFF, _ON, _STA, _INI, etc.
14For these cases, it is far simpler to dynamically install a single
15control method rather than override the entire DSDT, because kernel
16rebuild/reboot is not needed and test result can be got in minutes.
17
18Note: Only ACPI METHOD can be overridden, any other object types like
19 "Device", "OperationRegion", are not recognized.
20Note: The same ACPI control method can be overridden for many times,
21 and it's always the latest one that used by Linux/kernel.
22
231. override an existing method
24 a) get the ACPI table via ACPI sysfs I/F. e.g. to get the DSDT,
25 just run "cat /sys/firmware/acpi/tables/DSDT > /tmp/dsdt.dat"
26 b) disassemble the table by running "iasl -d dsdt.dat".
27 c) rewrite the ASL code of the method and save it in a new file,
28 d) package the new file (psr.asl) to an ACPI table format.
29 Here is an example of a customized \_SB._AC._PSR method,
30
31 DefinitionBlock ("", "SSDT", 1, "", "", 0x20080715)
32 {
33 External (ACON)
34
35 Method (\_SB_.AC._PSR, 0, NotSerialized)
36 {
37 Store ("In AC _PSR", Debug)
38 Return (ACON)
39 }
40 }
41 Note that the full pathname of the method in ACPI namespace
42 should be used.
43 And remember to use "External" to declare external objects.
44 e) assemble the file to generate the AML code of the method.
45 e.g. "iasl psr.asl" (psr.aml is generated as a result)
46 f) mount debugfs by "mount -t debugfs none /sys/kernel/debug"
47 g) override the old method via the debugfs by running
48 "cat /tmp/psr.aml > /sys/kernel/debug/acpi/custom_method"
49
502. insert a new method
51 This is easier than overriding an existing method.
52 We just need to create the ASL code of the method we want to
53 insert and then follow the step c) ~ g) in section 1.
54
553. undo your changes
56 The "undo" operation is not supported for a new inserted method
57 right now, i.e. we can not remove a method currently.
58 For an overrided method, in order to undo your changes, please
59 save a copy of the method original ASL code in step c) section 1,
60 and redo step c) ~ g) to override the method with the original one.
61
62
63Note: We can use a kernel with multiple custom ACPI method running,
64 But each individual write to debugfs can implement a SINGLE
65 method override. i.e. if we want to insert/override multiple
66 ACPI methods, we need to redo step c) ~ g) for multiple times.
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 @@
8#include <linux/module.h> 8#include <linux/module.h>
9#include <linux/kernel.h> 9#include <linux/kernel.h>
10#include <linux/moduleparam.h> 10#include <linux/moduleparam.h>
11#include <linux/debugfs.h>
11#include <asm/uaccess.h> 12#include <asm/uaccess.h>
12#include <acpi/acpi_drivers.h> 13#include <acpi/acpi_drivers.h>
13 14
@@ -196,6 +197,79 @@ module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
196 NULL, 0644); 197 NULL, 0644);
197 198
198/* -------------------------------------------------------------------------- 199/* --------------------------------------------------------------------------
200 DebugFS Interface
201 -------------------------------------------------------------------------- */
202
203static ssize_t cm_write(struct file *file, const char __user *user_buf,
204 size_t count, loff_t *ppos)
205{
206 static char *buf;
207 static int uncopied_bytes;
208 struct acpi_table_header table;
209 acpi_status status;
210
211 if (!(*ppos)) {
212 /* parse the table header to get the table length */
213 if (count <= sizeof(struct acpi_table_header))
214 return -EINVAL;
215 if (copy_from_user(&table, user_buf,
216 sizeof(struct acpi_table_header)))
217 return -EFAULT;
218 uncopied_bytes = table.length;
219 buf = kzalloc(uncopied_bytes, GFP_KERNEL);
220 if (!buf)
221 return -ENOMEM;
222 }
223
224 if (uncopied_bytes < count) {
225 kfree(buf);
226 return -EINVAL;
227 }
228
229 if (copy_from_user(buf + (*ppos), user_buf, count)) {
230 kfree(buf);
231 return -EFAULT;
232 }
233
234 uncopied_bytes -= count;
235 *ppos += count;
236
237 if (!uncopied_bytes) {
238 status = acpi_install_method(buf);
239 kfree(buf);
240 if (ACPI_FAILURE(status))
241 return -EINVAL;
242 }
243
244 return count;
245}
246
247static const struct file_operations cm_fops = {
248 .write = cm_write,
249};
250
251static int acpi_debugfs_init(void)
252{
253 struct dentry *acpi_dir, *cm_dentry;
254
255 acpi_dir = debugfs_create_dir("acpi", NULL);
256 if (!acpi_dir)
257 goto err;
258
259 cm_dentry = debugfs_create_file("custom_method", S_IWUGO,
260 acpi_dir, NULL, &cm_fops);
261 if (!cm_dentry)
262 goto err;
263
264 return 0;
265
266err:
267 if (acpi_dir)
268 debugfs_remove(acpi_dir);
269 return -EINVAL;
270}
271
272/* --------------------------------------------------------------------------
199 FS Interface (/proc) 273 FS Interface (/proc)
200 -------------------------------------------------------------------------- */ 274 -------------------------------------------------------------------------- */
201#ifdef CONFIG_ACPI_PROCFS 275#ifdef CONFIG_ACPI_PROCFS
@@ -286,7 +360,7 @@ static const struct file_operations acpi_system_debug_proc_fops = {
286}; 360};
287#endif 361#endif
288 362
289int __init acpi_debug_init(void) 363int __init acpi_procfs_init(void)
290{ 364{
291#ifdef CONFIG_ACPI_PROCFS 365#ifdef CONFIG_ACPI_PROCFS
292 struct proc_dir_entry *entry; 366 struct proc_dir_entry *entry;
@@ -321,3 +395,10 @@ int __init acpi_debug_init(void)
321 return 0; 395 return 0;
322#endif 396#endif
323} 397}
398
399int __init acpi_debug_init(void)
400{
401 acpi_debugfs_init();
402 acpi_procfs_init();
403 return 0;
404}