diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-12-31 21:26:26 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-12-31 21:26:26 -0500 |
commit | b17629dbf72d0718e88190d7f0a1d54be044799c (patch) | |
tree | 90e1908b4c7eab87989b17341cdaa8d074e355b2 | |
parent | 74bf8efb5fa6e958d2d7c7917b8bb672085ec0c6 (diff) | |
parent | 59adb3988ebeec012343317ac783d6a7935e0c83 (diff) |
Merge branch 'acpi-debug' into acpica
-rw-r--r-- | drivers/acpi/Kconfig | 17 | ||||
-rw-r--r-- | drivers/acpi/Makefile | 1 | ||||
-rw-r--r-- | drivers/acpi/acpi_dbg.c | 804 | ||||
-rw-r--r-- | drivers/acpi/acpica/acdebug.h | 36 | ||||
-rw-r--r-- | drivers/acpi/acpica/acglobal.h | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/acmacros.h | 11 | ||||
-rw-r--r-- | drivers/acpi/acpica/dbdisply.c | 12 | ||||
-rw-r--r-- | drivers/acpi/acpica/dbinput.c | 100 | ||||
-rw-r--r-- | drivers/acpi/acpica/dbxface.c | 93 | ||||
-rw-r--r-- | drivers/acpi/acpica/dscontrol.c | 10 | ||||
-rw-r--r-- | drivers/acpi/acpica/dsutils.c | 16 | ||||
-rw-r--r-- | drivers/acpi/acpica/dswexec.c | 16 | ||||
-rw-r--r-- | drivers/acpi/acpica/utmutex.c | 17 | ||||
-rw-r--r-- | drivers/acpi/bus.c | 1 | ||||
-rw-r--r-- | drivers/acpi/osl.c | 250 | ||||
-rw-r--r-- | include/acpi/acpiosxf.h | 18 | ||||
-rw-r--r-- | include/acpi/acpixf.h | 34 | ||||
-rw-r--r-- | include/acpi/platform/aclinux.h | 2 | ||||
-rw-r--r-- | include/acpi/platform/aclinuxex.h | 9 | ||||
-rw-r--r-- | include/linux/acpi.h | 71 | ||||
-rw-r--r-- | tools/power/acpi/Makefile | 16 | ||||
-rw-r--r-- | tools/power/acpi/tools/acpidbg/Makefile | 27 | ||||
-rw-r--r-- | tools/power/acpi/tools/acpidbg/acpidbg.c | 438 |
23 files changed, 1793 insertions, 211 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 5eef4cb4f70e..82b96ee8624c 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -58,14 +58,25 @@ config ACPI_CCA_REQUIRED | |||
58 | bool | 58 | bool |
59 | 59 | ||
60 | config ACPI_DEBUGGER | 60 | config ACPI_DEBUGGER |
61 | bool "AML debugger interface (EXPERIMENTAL)" | 61 | bool "AML debugger interface" |
62 | select ACPI_DEBUG | 62 | select ACPI_DEBUG |
63 | help | 63 | help |
64 | Enable in-kernel debugging of AML facilities: statistics, internal | 64 | Enable in-kernel debugging of AML facilities: statistics, |
65 | object dump, single step control method execution. | 65 | internal object dump, single step control method execution. |
66 | This is still under development, currently enabling this only | 66 | This is still under development, currently enabling this only |
67 | results in the compilation of the ACPICA debugger files. | 67 | results in the compilation of the ACPICA debugger files. |
68 | 68 | ||
69 | if ACPI_DEBUGGER | ||
70 | |||
71 | config ACPI_DEBUGGER_USER | ||
72 | tristate "Userspace debugger accessiblity" | ||
73 | depends on DEBUG_FS | ||
74 | help | ||
75 | Export /sys/kernel/debug/acpi/acpidbg for userspace utilities | ||
76 | to access the debugger functionalities. | ||
77 | |||
78 | endif | ||
79 | |||
69 | config ACPI_SLEEP | 80 | config ACPI_SLEEP |
70 | bool | 81 | bool |
71 | depends on SUSPEND || HIBERNATION | 82 | depends on SUSPEND || HIBERNATION |
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 675eaf337178..c6f236f1b510 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile | |||
@@ -79,6 +79,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o | |||
79 | obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o | 79 | obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o |
80 | obj-$(CONFIG_ACPI_BGRT) += bgrt.o | 80 | obj-$(CONFIG_ACPI_BGRT) += bgrt.o |
81 | obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o | 81 | obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o |
82 | obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o | ||
82 | 83 | ||
83 | # processor has its own "processor." module_param namespace | 84 | # processor has its own "processor." module_param namespace |
84 | processor-y := processor_driver.o | 85 | processor-y := processor_driver.o |
diff --git a/drivers/acpi/acpi_dbg.c b/drivers/acpi/acpi_dbg.c new file mode 100644 index 000000000000..15e4604efba7 --- /dev/null +++ b/drivers/acpi/acpi_dbg.c | |||
@@ -0,0 +1,804 @@ | |||
1 | /* | ||
2 | * ACPI AML interfacing support | ||
3 | * | ||
4 | * Copyright (C) 2015, Intel Corporation | ||
5 | * Authors: Lv Zheng <lv.zheng@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | /* #define DEBUG */ | ||
13 | #define pr_fmt(fmt) "ACPI : AML: " fmt | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/wait.h> | ||
18 | #include <linux/poll.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/kthread.h> | ||
21 | #include <linux/proc_fs.h> | ||
22 | #include <linux/debugfs.h> | ||
23 | #include <linux/circ_buf.h> | ||
24 | #include <linux/acpi.h> | ||
25 | #include "internal.h" | ||
26 | |||
27 | #define ACPI_AML_BUF_ALIGN (sizeof (acpi_size)) | ||
28 | #define ACPI_AML_BUF_SIZE PAGE_SIZE | ||
29 | |||
30 | #define circ_count(circ) \ | ||
31 | (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) | ||
32 | #define circ_count_to_end(circ) \ | ||
33 | (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) | ||
34 | #define circ_space(circ) \ | ||
35 | (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) | ||
36 | #define circ_space_to_end(circ) \ | ||
37 | (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) | ||
38 | |||
39 | #define ACPI_AML_OPENED 0x0001 | ||
40 | #define ACPI_AML_CLOSED 0x0002 | ||
41 | #define ACPI_AML_IN_USER 0x0004 /* user space is writing cmd */ | ||
42 | #define ACPI_AML_IN_KERN 0x0008 /* kernel space is reading cmd */ | ||
43 | #define ACPI_AML_OUT_USER 0x0010 /* user space is reading log */ | ||
44 | #define ACPI_AML_OUT_KERN 0x0020 /* kernel space is writing log */ | ||
45 | #define ACPI_AML_USER (ACPI_AML_IN_USER | ACPI_AML_OUT_USER) | ||
46 | #define ACPI_AML_KERN (ACPI_AML_IN_KERN | ACPI_AML_OUT_KERN) | ||
47 | #define ACPI_AML_BUSY (ACPI_AML_USER | ACPI_AML_KERN) | ||
48 | #define ACPI_AML_OPEN (ACPI_AML_OPENED | ACPI_AML_CLOSED) | ||
49 | |||
50 | struct acpi_aml_io { | ||
51 | wait_queue_head_t wait; | ||
52 | unsigned long flags; | ||
53 | unsigned long users; | ||
54 | struct mutex lock; | ||
55 | struct task_struct *thread; | ||
56 | char out_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN); | ||
57 | struct circ_buf out_crc; | ||
58 | char in_buf[ACPI_AML_BUF_SIZE] __aligned(ACPI_AML_BUF_ALIGN); | ||
59 | struct circ_buf in_crc; | ||
60 | acpi_osd_exec_callback function; | ||
61 | void *context; | ||
62 | unsigned long usages; | ||
63 | }; | ||
64 | |||
65 | static struct acpi_aml_io acpi_aml_io; | ||
66 | static bool acpi_aml_initialized; | ||
67 | static struct file *acpi_aml_active_reader; | ||
68 | static struct dentry *acpi_aml_dentry; | ||
69 | |||
70 | static inline bool __acpi_aml_running(void) | ||
71 | { | ||
72 | return acpi_aml_io.thread ? true : false; | ||
73 | } | ||
74 | |||
75 | static inline bool __acpi_aml_access_ok(unsigned long flag) | ||
76 | { | ||
77 | /* | ||
78 | * The debugger interface is in opened state (OPENED && !CLOSED), | ||
79 | * then it is allowed to access the debugger buffers from either | ||
80 | * user space or the kernel space. | ||
81 | * In addition, for the kernel space, only the debugger thread | ||
82 | * (thread ID matched) is allowed to access. | ||
83 | */ | ||
84 | if (!(acpi_aml_io.flags & ACPI_AML_OPENED) || | ||
85 | (acpi_aml_io.flags & ACPI_AML_CLOSED) || | ||
86 | !__acpi_aml_running()) | ||
87 | return false; | ||
88 | if ((flag & ACPI_AML_KERN) && | ||
89 | current != acpi_aml_io.thread) | ||
90 | return false; | ||
91 | return true; | ||
92 | } | ||
93 | |||
94 | static inline bool __acpi_aml_readable(struct circ_buf *circ, unsigned long flag) | ||
95 | { | ||
96 | /* | ||
97 | * Another read is not in progress and there is data in buffer | ||
98 | * available for read. | ||
99 | */ | ||
100 | if (!(acpi_aml_io.flags & flag) && circ_count(circ)) | ||
101 | return true; | ||
102 | return false; | ||
103 | } | ||
104 | |||
105 | static inline bool __acpi_aml_writable(struct circ_buf *circ, unsigned long flag) | ||
106 | { | ||
107 | /* | ||
108 | * Another write is not in progress and there is buffer space | ||
109 | * available for write. | ||
110 | */ | ||
111 | if (!(acpi_aml_io.flags & flag) && circ_space(circ)) | ||
112 | return true; | ||
113 | return false; | ||
114 | } | ||
115 | |||
116 | static inline bool __acpi_aml_busy(void) | ||
117 | { | ||
118 | if (acpi_aml_io.flags & ACPI_AML_BUSY) | ||
119 | return true; | ||
120 | return false; | ||
121 | } | ||
122 | |||
123 | static inline bool __acpi_aml_opened(void) | ||
124 | { | ||
125 | if (acpi_aml_io.flags & ACPI_AML_OPEN) | ||
126 | return true; | ||
127 | return false; | ||
128 | } | ||
129 | |||
130 | static inline bool __acpi_aml_used(void) | ||
131 | { | ||
132 | return acpi_aml_io.usages ? true : false; | ||
133 | } | ||
134 | |||
135 | static inline bool acpi_aml_running(void) | ||
136 | { | ||
137 | bool ret; | ||
138 | |||
139 | mutex_lock(&acpi_aml_io.lock); | ||
140 | ret = __acpi_aml_running(); | ||
141 | mutex_unlock(&acpi_aml_io.lock); | ||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | static bool acpi_aml_busy(void) | ||
146 | { | ||
147 | bool ret; | ||
148 | |||
149 | mutex_lock(&acpi_aml_io.lock); | ||
150 | ret = __acpi_aml_busy(); | ||
151 | mutex_unlock(&acpi_aml_io.lock); | ||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | static bool acpi_aml_used(void) | ||
156 | { | ||
157 | bool ret; | ||
158 | |||
159 | /* | ||
160 | * The usage count is prepared to avoid race conditions between the | ||
161 | * starts and the stops of the debugger thread. | ||
162 | */ | ||
163 | mutex_lock(&acpi_aml_io.lock); | ||
164 | ret = __acpi_aml_used(); | ||
165 | mutex_unlock(&acpi_aml_io.lock); | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | static bool acpi_aml_kern_readable(void) | ||
170 | { | ||
171 | bool ret; | ||
172 | |||
173 | mutex_lock(&acpi_aml_io.lock); | ||
174 | ret = !__acpi_aml_access_ok(ACPI_AML_IN_KERN) || | ||
175 | __acpi_aml_readable(&acpi_aml_io.in_crc, ACPI_AML_IN_KERN); | ||
176 | mutex_unlock(&acpi_aml_io.lock); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | static bool acpi_aml_kern_writable(void) | ||
181 | { | ||
182 | bool ret; | ||
183 | |||
184 | mutex_lock(&acpi_aml_io.lock); | ||
185 | ret = !__acpi_aml_access_ok(ACPI_AML_OUT_KERN) || | ||
186 | __acpi_aml_writable(&acpi_aml_io.out_crc, ACPI_AML_OUT_KERN); | ||
187 | mutex_unlock(&acpi_aml_io.lock); | ||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | static bool acpi_aml_user_readable(void) | ||
192 | { | ||
193 | bool ret; | ||
194 | |||
195 | mutex_lock(&acpi_aml_io.lock); | ||
196 | ret = !__acpi_aml_access_ok(ACPI_AML_OUT_USER) || | ||
197 | __acpi_aml_readable(&acpi_aml_io.out_crc, ACPI_AML_OUT_USER); | ||
198 | mutex_unlock(&acpi_aml_io.lock); | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static bool acpi_aml_user_writable(void) | ||
203 | { | ||
204 | bool ret; | ||
205 | |||
206 | mutex_lock(&acpi_aml_io.lock); | ||
207 | ret = !__acpi_aml_access_ok(ACPI_AML_IN_USER) || | ||
208 | __acpi_aml_writable(&acpi_aml_io.in_crc, ACPI_AML_IN_USER); | ||
209 | mutex_unlock(&acpi_aml_io.lock); | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | static int acpi_aml_lock_write(struct circ_buf *circ, unsigned long flag) | ||
214 | { | ||
215 | int ret = 0; | ||
216 | |||
217 | mutex_lock(&acpi_aml_io.lock); | ||
218 | if (!__acpi_aml_access_ok(flag)) { | ||
219 | ret = -EFAULT; | ||
220 | goto out; | ||
221 | } | ||
222 | if (!__acpi_aml_writable(circ, flag)) { | ||
223 | ret = -EAGAIN; | ||
224 | goto out; | ||
225 | } | ||
226 | acpi_aml_io.flags |= flag; | ||
227 | out: | ||
228 | mutex_unlock(&acpi_aml_io.lock); | ||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | static int acpi_aml_lock_read(struct circ_buf *circ, unsigned long flag) | ||
233 | { | ||
234 | int ret = 0; | ||
235 | |||
236 | mutex_lock(&acpi_aml_io.lock); | ||
237 | if (!__acpi_aml_access_ok(flag)) { | ||
238 | ret = -EFAULT; | ||
239 | goto out; | ||
240 | } | ||
241 | if (!__acpi_aml_readable(circ, flag)) { | ||
242 | ret = -EAGAIN; | ||
243 | goto out; | ||
244 | } | ||
245 | acpi_aml_io.flags |= flag; | ||
246 | out: | ||
247 | mutex_unlock(&acpi_aml_io.lock); | ||
248 | return ret; | ||
249 | } | ||
250 | |||
251 | static void acpi_aml_unlock_fifo(unsigned long flag, bool wakeup) | ||
252 | { | ||
253 | mutex_lock(&acpi_aml_io.lock); | ||
254 | acpi_aml_io.flags &= ~flag; | ||
255 | if (wakeup) | ||
256 | wake_up_interruptible(&acpi_aml_io.wait); | ||
257 | mutex_unlock(&acpi_aml_io.lock); | ||
258 | } | ||
259 | |||
260 | static int acpi_aml_write_kern(const char *buf, int len) | ||
261 | { | ||
262 | int ret; | ||
263 | struct circ_buf *crc = &acpi_aml_io.out_crc; | ||
264 | int n; | ||
265 | char *p; | ||
266 | |||
267 | ret = acpi_aml_lock_write(crc, ACPI_AML_OUT_KERN); | ||
268 | if (IS_ERR_VALUE(ret)) | ||
269 | return ret; | ||
270 | /* sync tail before inserting logs */ | ||
271 | smp_mb(); | ||
272 | p = &crc->buf[crc->head]; | ||
273 | n = min(len, circ_space_to_end(crc)); | ||
274 | memcpy(p, buf, n); | ||
275 | /* sync head after inserting logs */ | ||
276 | smp_wmb(); | ||
277 | crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); | ||
278 | acpi_aml_unlock_fifo(ACPI_AML_OUT_KERN, true); | ||
279 | return n; | ||
280 | } | ||
281 | |||
282 | static int acpi_aml_readb_kern(void) | ||
283 | { | ||
284 | int ret; | ||
285 | struct circ_buf *crc = &acpi_aml_io.in_crc; | ||
286 | char *p; | ||
287 | |||
288 | ret = acpi_aml_lock_read(crc, ACPI_AML_IN_KERN); | ||
289 | if (IS_ERR_VALUE(ret)) | ||
290 | return ret; | ||
291 | /* sync head before removing cmds */ | ||
292 | smp_rmb(); | ||
293 | p = &crc->buf[crc->tail]; | ||
294 | ret = (int)*p; | ||
295 | /* sync tail before inserting cmds */ | ||
296 | smp_mb(); | ||
297 | crc->tail = (crc->tail + 1) & (ACPI_AML_BUF_SIZE - 1); | ||
298 | acpi_aml_unlock_fifo(ACPI_AML_IN_KERN, true); | ||
299 | return ret; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * acpi_aml_write_log() - Capture debugger output | ||
304 | * @msg: the debugger output | ||
305 | * | ||
306 | * This function should be used to implement acpi_os_printf() to filter out | ||
307 | * the debugger output and store the output into the debugger interface | ||
308 | * buffer. Return the size of stored logs or errno. | ||
309 | */ | ||
310 | static ssize_t acpi_aml_write_log(const char *msg) | ||
311 | { | ||
312 | int ret = 0; | ||
313 | int count = 0, size = 0; | ||
314 | |||
315 | if (!acpi_aml_initialized) | ||
316 | return -ENODEV; | ||
317 | if (msg) | ||
318 | count = strlen(msg); | ||
319 | while (count > 0) { | ||
320 | again: | ||
321 | ret = acpi_aml_write_kern(msg + size, count); | ||
322 | if (ret == -EAGAIN) { | ||
323 | ret = wait_event_interruptible(acpi_aml_io.wait, | ||
324 | acpi_aml_kern_writable()); | ||
325 | /* | ||
326 | * We need to retry when the condition | ||
327 | * becomes true. | ||
328 | */ | ||
329 | if (ret == 0) | ||
330 | goto again; | ||
331 | break; | ||
332 | } | ||
333 | if (IS_ERR_VALUE(ret)) | ||
334 | break; | ||
335 | size += ret; | ||
336 | count -= ret; | ||
337 | } | ||
338 | return size > 0 ? size : ret; | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * acpi_aml_read_cmd() - Capture debugger input | ||
343 | * @msg: the debugger input | ||
344 | * @size: the size of the debugger input | ||
345 | * | ||
346 | * This function should be used to implement acpi_os_get_line() to capture | ||
347 | * the debugger input commands and store the input commands into the | ||
348 | * debugger interface buffer. Return the size of stored commands or errno. | ||
349 | */ | ||
350 | static ssize_t acpi_aml_read_cmd(char *msg, size_t count) | ||
351 | { | ||
352 | int ret = 0; | ||
353 | int size = 0; | ||
354 | |||
355 | /* | ||
356 | * This is ensured by the running fact of the debugger thread | ||
357 | * unless a bug is introduced. | ||
358 | */ | ||
359 | BUG_ON(!acpi_aml_initialized); | ||
360 | while (count > 0) { | ||
361 | again: | ||
362 | /* | ||
363 | * Check each input byte to find the end of the command. | ||
364 | */ | ||
365 | ret = acpi_aml_readb_kern(); | ||
366 | if (ret == -EAGAIN) { | ||
367 | ret = wait_event_interruptible(acpi_aml_io.wait, | ||
368 | acpi_aml_kern_readable()); | ||
369 | /* | ||
370 | * We need to retry when the condition becomes | ||
371 | * true. | ||
372 | */ | ||
373 | if (ret == 0) | ||
374 | goto again; | ||
375 | } | ||
376 | if (IS_ERR_VALUE(ret)) | ||
377 | break; | ||
378 | *(msg + size) = (char)ret; | ||
379 | size++; | ||
380 | count--; | ||
381 | if (ret == '\n') { | ||
382 | /* | ||
383 | * acpi_os_get_line() requires a zero terminated command | ||
384 | * string. | ||
385 | */ | ||
386 | *(msg + size - 1) = '\0'; | ||
387 | break; | ||
388 | } | ||
389 | } | ||
390 | return size > 0 ? size : ret; | ||
391 | } | ||
392 | |||
393 | static int acpi_aml_thread(void *unsed) | ||
394 | { | ||
395 | acpi_osd_exec_callback function = NULL; | ||
396 | void *context; | ||
397 | |||
398 | mutex_lock(&acpi_aml_io.lock); | ||
399 | if (acpi_aml_io.function) { | ||
400 | acpi_aml_io.usages++; | ||
401 | function = acpi_aml_io.function; | ||
402 | context = acpi_aml_io.context; | ||
403 | } | ||
404 | mutex_unlock(&acpi_aml_io.lock); | ||
405 | |||
406 | if (function) | ||
407 | function(context); | ||
408 | |||
409 | mutex_lock(&acpi_aml_io.lock); | ||
410 | acpi_aml_io.usages--; | ||
411 | if (!__acpi_aml_used()) { | ||
412 | acpi_aml_io.thread = NULL; | ||
413 | wake_up(&acpi_aml_io.wait); | ||
414 | } | ||
415 | mutex_unlock(&acpi_aml_io.lock); | ||
416 | |||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * acpi_aml_create_thread() - Create AML debugger thread | ||
422 | * @function: the debugger thread callback | ||
423 | * @context: the context to be passed to the debugger thread | ||
424 | * | ||
425 | * This function should be used to implement acpi_os_execute() which is | ||
426 | * used by the ACPICA debugger to create the debugger thread. | ||
427 | */ | ||
428 | static int acpi_aml_create_thread(acpi_osd_exec_callback function, void *context) | ||
429 | { | ||
430 | struct task_struct *t; | ||
431 | |||
432 | mutex_lock(&acpi_aml_io.lock); | ||
433 | acpi_aml_io.function = function; | ||
434 | acpi_aml_io.context = context; | ||
435 | mutex_unlock(&acpi_aml_io.lock); | ||
436 | |||
437 | t = kthread_create(acpi_aml_thread, NULL, "aml"); | ||
438 | if (IS_ERR(t)) { | ||
439 | pr_err("Failed to create AML debugger thread.\n"); | ||
440 | return PTR_ERR(t); | ||
441 | } | ||
442 | |||
443 | mutex_lock(&acpi_aml_io.lock); | ||
444 | acpi_aml_io.thread = t; | ||
445 | acpi_set_debugger_thread_id((acpi_thread_id)(unsigned long)t); | ||
446 | wake_up_process(t); | ||
447 | mutex_unlock(&acpi_aml_io.lock); | ||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | static int acpi_aml_wait_command_ready(bool single_step, | ||
452 | char *buffer, size_t length) | ||
453 | { | ||
454 | acpi_status status; | ||
455 | |||
456 | if (single_step) | ||
457 | acpi_os_printf("\n%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); | ||
458 | else | ||
459 | acpi_os_printf("\n%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); | ||
460 | |||
461 | status = acpi_os_get_line(buffer, length, NULL); | ||
462 | if (ACPI_FAILURE(status)) | ||
463 | return -EINVAL; | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | static int acpi_aml_notify_command_complete(void) | ||
468 | { | ||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static int acpi_aml_open(struct inode *inode, struct file *file) | ||
473 | { | ||
474 | int ret = 0; | ||
475 | acpi_status status; | ||
476 | |||
477 | mutex_lock(&acpi_aml_io.lock); | ||
478 | /* | ||
479 | * The debugger interface is being closed, no new user is allowed | ||
480 | * during this period. | ||
481 | */ | ||
482 | if (acpi_aml_io.flags & ACPI_AML_CLOSED) { | ||
483 | ret = -EBUSY; | ||
484 | goto err_lock; | ||
485 | } | ||
486 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) { | ||
487 | /* | ||
488 | * Only one reader is allowed to initiate the debugger | ||
489 | * thread. | ||
490 | */ | ||
491 | if (acpi_aml_active_reader) { | ||
492 | ret = -EBUSY; | ||
493 | goto err_lock; | ||
494 | } else { | ||
495 | pr_debug("Opening debugger reader.\n"); | ||
496 | acpi_aml_active_reader = file; | ||
497 | } | ||
498 | } else { | ||
499 | /* | ||
500 | * No writer is allowed unless the debugger thread is | ||
501 | * ready. | ||
502 | */ | ||
503 | if (!(acpi_aml_io.flags & ACPI_AML_OPENED)) { | ||
504 | ret = -ENODEV; | ||
505 | goto err_lock; | ||
506 | } | ||
507 | } | ||
508 | if (acpi_aml_active_reader == file) { | ||
509 | pr_debug("Opening debugger interface.\n"); | ||
510 | mutex_unlock(&acpi_aml_io.lock); | ||
511 | |||
512 | pr_debug("Initializing debugger thread.\n"); | ||
513 | status = acpi_initialize_debugger(); | ||
514 | if (ACPI_FAILURE(status)) { | ||
515 | pr_err("Failed to initialize debugger.\n"); | ||
516 | ret = -EINVAL; | ||
517 | goto err_exit; | ||
518 | } | ||
519 | pr_debug("Debugger thread initialized.\n"); | ||
520 | |||
521 | mutex_lock(&acpi_aml_io.lock); | ||
522 | acpi_aml_io.flags |= ACPI_AML_OPENED; | ||
523 | acpi_aml_io.out_crc.head = acpi_aml_io.out_crc.tail = 0; | ||
524 | acpi_aml_io.in_crc.head = acpi_aml_io.in_crc.tail = 0; | ||
525 | pr_debug("Debugger interface opened.\n"); | ||
526 | } | ||
527 | acpi_aml_io.users++; | ||
528 | err_lock: | ||
529 | if (IS_ERR_VALUE(ret)) { | ||
530 | if (acpi_aml_active_reader == file) | ||
531 | acpi_aml_active_reader = NULL; | ||
532 | } | ||
533 | mutex_unlock(&acpi_aml_io.lock); | ||
534 | err_exit: | ||
535 | return ret; | ||
536 | } | ||
537 | |||
538 | static int acpi_aml_release(struct inode *inode, struct file *file) | ||
539 | { | ||
540 | mutex_lock(&acpi_aml_io.lock); | ||
541 | acpi_aml_io.users--; | ||
542 | if (file == acpi_aml_active_reader) { | ||
543 | pr_debug("Closing debugger reader.\n"); | ||
544 | acpi_aml_active_reader = NULL; | ||
545 | |||
546 | pr_debug("Closing debugger interface.\n"); | ||
547 | acpi_aml_io.flags |= ACPI_AML_CLOSED; | ||
548 | |||
549 | /* | ||
550 | * Wake up all user space/kernel space blocked | ||
551 | * readers/writers. | ||
552 | */ | ||
553 | wake_up_interruptible(&acpi_aml_io.wait); | ||
554 | mutex_unlock(&acpi_aml_io.lock); | ||
555 | /* | ||
556 | * Wait all user space/kernel space readers/writers to | ||
557 | * stop so that ACPICA command loop of the debugger thread | ||
558 | * should fail all its command line reads after this point. | ||
559 | */ | ||
560 | wait_event(acpi_aml_io.wait, !acpi_aml_busy()); | ||
561 | |||
562 | /* | ||
563 | * Then we try to terminate the debugger thread if it is | ||
564 | * not terminated. | ||
565 | */ | ||
566 | pr_debug("Terminating debugger thread.\n"); | ||
567 | acpi_terminate_debugger(); | ||
568 | wait_event(acpi_aml_io.wait, !acpi_aml_used()); | ||
569 | pr_debug("Debugger thread terminated.\n"); | ||
570 | |||
571 | mutex_lock(&acpi_aml_io.lock); | ||
572 | acpi_aml_io.flags &= ~ACPI_AML_OPENED; | ||
573 | } | ||
574 | if (acpi_aml_io.users == 0) { | ||
575 | pr_debug("Debugger interface closed.\n"); | ||
576 | acpi_aml_io.flags &= ~ACPI_AML_CLOSED; | ||
577 | } | ||
578 | mutex_unlock(&acpi_aml_io.lock); | ||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | static int acpi_aml_read_user(char __user *buf, int len) | ||
583 | { | ||
584 | int ret; | ||
585 | struct circ_buf *crc = &acpi_aml_io.out_crc; | ||
586 | int n; | ||
587 | char *p; | ||
588 | |||
589 | ret = acpi_aml_lock_read(crc, ACPI_AML_OUT_USER); | ||
590 | if (IS_ERR_VALUE(ret)) | ||
591 | return ret; | ||
592 | /* sync head before removing logs */ | ||
593 | smp_rmb(); | ||
594 | p = &crc->buf[crc->tail]; | ||
595 | n = min(len, circ_count_to_end(crc)); | ||
596 | if (copy_to_user(buf, p, n)) { | ||
597 | ret = -EFAULT; | ||
598 | goto out; | ||
599 | } | ||
600 | /* sync tail after removing logs */ | ||
601 | smp_mb(); | ||
602 | crc->tail = (crc->tail + n) & (ACPI_AML_BUF_SIZE - 1); | ||
603 | ret = n; | ||
604 | out: | ||
605 | acpi_aml_unlock_fifo(ACPI_AML_OUT_USER, !IS_ERR_VALUE(ret)); | ||
606 | return ret; | ||
607 | } | ||
608 | |||
609 | static ssize_t acpi_aml_read(struct file *file, char __user *buf, | ||
610 | size_t count, loff_t *ppos) | ||
611 | { | ||
612 | int ret = 0; | ||
613 | int size = 0; | ||
614 | |||
615 | if (!count) | ||
616 | return 0; | ||
617 | if (!access_ok(VERIFY_WRITE, buf, count)) | ||
618 | return -EFAULT; | ||
619 | |||
620 | while (count > 0) { | ||
621 | again: | ||
622 | ret = acpi_aml_read_user(buf + size, count); | ||
623 | if (ret == -EAGAIN) { | ||
624 | if (file->f_flags & O_NONBLOCK) | ||
625 | break; | ||
626 | else { | ||
627 | ret = wait_event_interruptible(acpi_aml_io.wait, | ||
628 | acpi_aml_user_readable()); | ||
629 | /* | ||
630 | * We need to retry when the condition | ||
631 | * becomes true. | ||
632 | */ | ||
633 | if (ret == 0) | ||
634 | goto again; | ||
635 | } | ||
636 | } | ||
637 | if (IS_ERR_VALUE(ret)) { | ||
638 | if (!acpi_aml_running()) | ||
639 | ret = 0; | ||
640 | break; | ||
641 | } | ||
642 | if (ret) { | ||
643 | size += ret; | ||
644 | count -= ret; | ||
645 | *ppos += ret; | ||
646 | break; | ||
647 | } | ||
648 | } | ||
649 | return size > 0 ? size : ret; | ||
650 | } | ||
651 | |||
652 | static int acpi_aml_write_user(const char __user *buf, int len) | ||
653 | { | ||
654 | int ret; | ||
655 | struct circ_buf *crc = &acpi_aml_io.in_crc; | ||
656 | int n; | ||
657 | char *p; | ||
658 | |||
659 | ret = acpi_aml_lock_write(crc, ACPI_AML_IN_USER); | ||
660 | if (IS_ERR_VALUE(ret)) | ||
661 | return ret; | ||
662 | /* sync tail before inserting cmds */ | ||
663 | smp_mb(); | ||
664 | p = &crc->buf[crc->head]; | ||
665 | n = min(len, circ_space_to_end(crc)); | ||
666 | if (copy_from_user(p, buf, n)) { | ||
667 | ret = -EFAULT; | ||
668 | goto out; | ||
669 | } | ||
670 | /* sync head after inserting cmds */ | ||
671 | smp_wmb(); | ||
672 | crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); | ||
673 | ret = n; | ||
674 | out: | ||
675 | acpi_aml_unlock_fifo(ACPI_AML_IN_USER, !IS_ERR_VALUE(ret)); | ||
676 | return n; | ||
677 | } | ||
678 | |||
679 | static ssize_t acpi_aml_write(struct file *file, const char __user *buf, | ||
680 | size_t count, loff_t *ppos) | ||
681 | { | ||
682 | int ret = 0; | ||
683 | int size = 0; | ||
684 | |||
685 | if (!count) | ||
686 | return 0; | ||
687 | if (!access_ok(VERIFY_READ, buf, count)) | ||
688 | return -EFAULT; | ||
689 | |||
690 | while (count > 0) { | ||
691 | again: | ||
692 | ret = acpi_aml_write_user(buf + size, count); | ||
693 | if (ret == -EAGAIN) { | ||
694 | if (file->f_flags & O_NONBLOCK) | ||
695 | break; | ||
696 | else { | ||
697 | ret = wait_event_interruptible(acpi_aml_io.wait, | ||
698 | acpi_aml_user_writable()); | ||
699 | /* | ||
700 | * We need to retry when the condition | ||
701 | * becomes true. | ||
702 | */ | ||
703 | if (ret == 0) | ||
704 | goto again; | ||
705 | } | ||
706 | } | ||
707 | if (IS_ERR_VALUE(ret)) { | ||
708 | if (!acpi_aml_running()) | ||
709 | ret = 0; | ||
710 | break; | ||
711 | } | ||
712 | if (ret) { | ||
713 | size += ret; | ||
714 | count -= ret; | ||
715 | *ppos += ret; | ||
716 | } | ||
717 | } | ||
718 | return size > 0 ? size : ret; | ||
719 | } | ||
720 | |||
721 | static unsigned int acpi_aml_poll(struct file *file, poll_table *wait) | ||
722 | { | ||
723 | int masks = 0; | ||
724 | |||
725 | poll_wait(file, &acpi_aml_io.wait, wait); | ||
726 | if (acpi_aml_user_readable()) | ||
727 | masks |= POLLIN | POLLRDNORM; | ||
728 | if (acpi_aml_user_writable()) | ||
729 | masks |= POLLOUT | POLLWRNORM; | ||
730 | |||
731 | return masks; | ||
732 | } | ||
733 | |||
734 | static const struct file_operations acpi_aml_operations = { | ||
735 | .read = acpi_aml_read, | ||
736 | .write = acpi_aml_write, | ||
737 | .poll = acpi_aml_poll, | ||
738 | .open = acpi_aml_open, | ||
739 | .release = acpi_aml_release, | ||
740 | .llseek = generic_file_llseek, | ||
741 | }; | ||
742 | |||
743 | static const struct acpi_debugger_ops acpi_aml_debugger = { | ||
744 | .create_thread = acpi_aml_create_thread, | ||
745 | .read_cmd = acpi_aml_read_cmd, | ||
746 | .write_log = acpi_aml_write_log, | ||
747 | .wait_command_ready = acpi_aml_wait_command_ready, | ||
748 | .notify_command_complete = acpi_aml_notify_command_complete, | ||
749 | }; | ||
750 | |||
751 | int __init acpi_aml_init(void) | ||
752 | { | ||
753 | int ret = 0; | ||
754 | |||
755 | if (!acpi_debugfs_dir) { | ||
756 | ret = -ENOENT; | ||
757 | goto err_exit; | ||
758 | } | ||
759 | |||
760 | /* Initialize AML IO interface */ | ||
761 | mutex_init(&acpi_aml_io.lock); | ||
762 | init_waitqueue_head(&acpi_aml_io.wait); | ||
763 | acpi_aml_io.out_crc.buf = acpi_aml_io.out_buf; | ||
764 | acpi_aml_io.in_crc.buf = acpi_aml_io.in_buf; | ||
765 | acpi_aml_dentry = debugfs_create_file("acpidbg", | ||
766 | S_IFREG | S_IRUGO | S_IWUSR, | ||
767 | acpi_debugfs_dir, NULL, | ||
768 | &acpi_aml_operations); | ||
769 | if (acpi_aml_dentry == NULL) { | ||
770 | ret = -ENODEV; | ||
771 | goto err_exit; | ||
772 | } | ||
773 | ret = acpi_register_debugger(THIS_MODULE, &acpi_aml_debugger); | ||
774 | if (ret) | ||
775 | goto err_fs; | ||
776 | acpi_aml_initialized = true; | ||
777 | |||
778 | err_fs: | ||
779 | if (ret) { | ||
780 | debugfs_remove(acpi_aml_dentry); | ||
781 | acpi_aml_dentry = NULL; | ||
782 | } | ||
783 | err_exit: | ||
784 | return ret; | ||
785 | } | ||
786 | |||
787 | void __exit acpi_aml_exit(void) | ||
788 | { | ||
789 | if (acpi_aml_initialized) { | ||
790 | acpi_unregister_debugger(&acpi_aml_debugger); | ||
791 | if (acpi_aml_dentry) { | ||
792 | debugfs_remove(acpi_aml_dentry); | ||
793 | acpi_aml_dentry = NULL; | ||
794 | } | ||
795 | acpi_aml_initialized = false; | ||
796 | } | ||
797 | } | ||
798 | |||
799 | module_init(acpi_aml_init); | ||
800 | module_exit(acpi_aml_exit); | ||
801 | |||
802 | MODULE_AUTHOR("Lv Zheng"); | ||
803 | MODULE_DESCRIPTION("ACPI debugger userspace IO driver"); | ||
804 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index c928ba494c40..dcaa15d5fe27 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h | |||
@@ -80,9 +80,15 @@ struct acpi_db_execute_walk { | |||
80 | /* | 80 | /* |
81 | * dbxface - external debugger interfaces | 81 | * dbxface - external debugger interfaces |
82 | */ | 82 | */ |
83 | acpi_status | 83 | ACPI_DBR_DEPENDENT_RETURN_OK(acpi_status |
84 | acpi_db_single_step(struct acpi_walk_state *walk_state, | 84 | acpi_db_single_step(struct acpi_walk_state |
85 | union acpi_parse_object *op, u32 op_type); | 85 | *walk_state, |
86 | union acpi_parse_object *op, | ||
87 | u32 op_type)) | ||
88 | ACPI_DBR_DEPENDENT_RETURN_VOID(void | ||
89 | acpi_db_signal_break_point(struct | ||
90 | acpi_walk_state | ||
91 | *walk_state)) | ||
86 | 92 | ||
87 | /* | 93 | /* |
88 | * dbcmds - debug commands and output routines | 94 | * dbcmds - debug commands and output routines |
@@ -182,11 +188,15 @@ void acpi_db_display_method_info(union acpi_parse_object *op); | |||
182 | 188 | ||
183 | void acpi_db_decode_and_display_object(char *target, char *output_type); | 189 | void acpi_db_decode_and_display_object(char *target, char *output_type); |
184 | 190 | ||
185 | void | 191 | ACPI_DBR_DEPENDENT_RETURN_VOID(void |
186 | acpi_db_display_result_object(union acpi_operand_object *obj_desc, | 192 | acpi_db_display_result_object(union |
187 | struct acpi_walk_state *walk_state); | 193 | acpi_operand_object |
194 | *obj_desc, | ||
195 | struct | ||
196 | acpi_walk_state | ||
197 | *walk_state)) | ||
188 | 198 | ||
189 | acpi_status acpi_db_display_all_methods(char *display_count_arg); | 199 | acpi_status acpi_db_display_all_methods(char *display_count_arg); |
190 | 200 | ||
191 | void acpi_db_display_arguments(void); | 201 | void acpi_db_display_arguments(void); |
192 | 202 | ||
@@ -198,9 +208,13 @@ void acpi_db_display_calling_tree(void); | |||
198 | 208 | ||
199 | void acpi_db_display_object_type(char *object_arg); | 209 | void acpi_db_display_object_type(char *object_arg); |
200 | 210 | ||
201 | void | 211 | ACPI_DBR_DEPENDENT_RETURN_VOID(void |
202 | acpi_db_display_argument_object(union acpi_operand_object *obj_desc, | 212 | acpi_db_display_argument_object(union |
203 | struct acpi_walk_state *walk_state); | 213 | acpi_operand_object |
214 | *obj_desc, | ||
215 | struct | ||
216 | acpi_walk_state | ||
217 | *walk_state)) | ||
204 | 218 | ||
205 | /* | 219 | /* |
206 | * dbexec - debugger control method execution | 220 | * dbexec - debugger control method execution |
@@ -257,7 +271,7 @@ acpi_db_command_dispatch(char *input_buffer, | |||
257 | 271 | ||
258 | void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context); | 272 | void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context); |
259 | 273 | ||
260 | acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op); | 274 | acpi_status acpi_db_user_commands(void); |
261 | 275 | ||
262 | char *acpi_db_get_next_token(char *string, | 276 | char *acpi_db_get_next_token(char *string, |
263 | char **next, acpi_object_type * return_type); | 277 | char **next, acpi_object_type * return_type); |
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index faa97604d878..3977134f2619 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h | |||
@@ -326,7 +326,6 @@ ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list); | |||
326 | #ifdef ACPI_DEBUGGER | 326 | #ifdef ACPI_DEBUGGER |
327 | 327 | ||
328 | ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE); | 328 | ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE); |
329 | ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE); | ||
330 | ACPI_INIT_GLOBAL(acpi_thread_id, acpi_gbl_db_thread_id, ACPI_INVALID_THREAD_ID); | 329 | ACPI_INIT_GLOBAL(acpi_thread_id, acpi_gbl_db_thread_id, ACPI_INVALID_THREAD_ID); |
331 | 330 | ||
332 | ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_ini_methods); | 331 | ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_ini_methods); |
@@ -345,7 +344,6 @@ ACPI_GLOBAL(acpi_object_type, acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS]); | |||
345 | 344 | ||
346 | /* These buffers should all be the same size */ | 345 | /* These buffers should all be the same size */ |
347 | 346 | ||
348 | ACPI_GLOBAL(char, acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]); | ||
349 | ACPI_GLOBAL(char, acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE]); | 347 | ACPI_GLOBAL(char, acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE]); |
350 | ACPI_GLOBAL(char, acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE]); | 348 | ACPI_GLOBAL(char, acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE]); |
351 | ACPI_GLOBAL(char, acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE]); | 349 | ACPI_GLOBAL(char, acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE]); |
@@ -360,9 +358,6 @@ ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc); | |||
360 | ACPI_GLOBAL(u32, acpi_gbl_num_nodes); | 358 | ACPI_GLOBAL(u32, acpi_gbl_num_nodes); |
361 | ACPI_GLOBAL(u32, acpi_gbl_num_objects); | 359 | ACPI_GLOBAL(u32, acpi_gbl_num_objects); |
362 | 360 | ||
363 | ACPI_GLOBAL(acpi_mutex, acpi_gbl_db_command_ready); | ||
364 | ACPI_GLOBAL(acpi_mutex, acpi_gbl_db_command_complete); | ||
365 | |||
366 | #endif /* ACPI_DEBUGGER */ | 361 | #endif /* ACPI_DEBUGGER */ |
367 | 362 | ||
368 | /***************************************************************************** | 363 | /***************************************************************************** |
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index e85366ceb15a..bad5bca03acc 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h | |||
@@ -401,17 +401,6 @@ | |||
401 | #endif | 401 | #endif |
402 | 402 | ||
403 | /* | 403 | /* |
404 | * Some code only gets executed when the debugger is built in. | ||
405 | * Note that this is entirely independent of whether the | ||
406 | * DEBUG_PRINT stuff (set by ACPI_DEBUG_OUTPUT) is on, or not. | ||
407 | */ | ||
408 | #ifdef ACPI_DEBUGGER | ||
409 | #define ACPI_DEBUGGER_EXEC(a) a | ||
410 | #else | ||
411 | #define ACPI_DEBUGGER_EXEC(a) | ||
412 | #endif | ||
413 | |||
414 | /* | ||
415 | * Macros used for ACPICA utilities only | 404 | * Macros used for ACPICA utilities only |
416 | */ | 405 | */ |
417 | 406 | ||
diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c index 672977ec7c7d..c42ce8aa9dfe 100644 --- a/drivers/acpi/acpica/dbdisply.c +++ b/drivers/acpi/acpica/dbdisply.c | |||
@@ -679,6 +679,12 @@ acpi_db_display_result_object(union acpi_operand_object *obj_desc, | |||
679 | struct acpi_walk_state *walk_state) | 679 | struct acpi_walk_state *walk_state) |
680 | { | 680 | { |
681 | 681 | ||
682 | #ifndef ACPI_APPLICATION | ||
683 | if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) { | ||
684 | return; | ||
685 | } | ||
686 | #endif | ||
687 | |||
682 | /* Only display if single stepping */ | 688 | /* Only display if single stepping */ |
683 | 689 | ||
684 | if (!acpi_gbl_cm_single_step) { | 690 | if (!acpi_gbl_cm_single_step) { |
@@ -708,6 +714,12 @@ acpi_db_display_argument_object(union acpi_operand_object *obj_desc, | |||
708 | struct acpi_walk_state *walk_state) | 714 | struct acpi_walk_state *walk_state) |
709 | { | 715 | { |
710 | 716 | ||
717 | #ifndef ACPI_APPLICATION | ||
718 | if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) { | ||
719 | return; | ||
720 | } | ||
721 | #endif | ||
722 | |||
711 | if (!acpi_gbl_cm_single_step) { | 723 | if (!acpi_gbl_cm_single_step) { |
712 | return; | 724 | return; |
713 | } | 725 | } |
diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c index 0480254437f1..2bf8e6b90d5b 100644 --- a/drivers/acpi/acpica/dbinput.c +++ b/drivers/acpi/acpica/dbinput.c | |||
@@ -53,8 +53,6 @@ static u32 acpi_db_get_line(char *input_buffer); | |||
53 | 53 | ||
54 | static u32 acpi_db_match_command(char *user_command); | 54 | static u32 acpi_db_match_command(char *user_command); |
55 | 55 | ||
56 | static void acpi_db_single_thread(void); | ||
57 | |||
58 | static void acpi_db_display_command_info(char *command, u8 display_all); | 56 | static void acpi_db_display_command_info(char *command, u8 display_all); |
59 | 57 | ||
60 | static void acpi_db_display_help(char *command); | 58 | static void acpi_db_display_help(char *command); |
@@ -1149,55 +1147,16 @@ acpi_db_command_dispatch(char *input_buffer, | |||
1149 | 1147 | ||
1150 | void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context) | 1148 | void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context) |
1151 | { | 1149 | { |
1152 | acpi_status status = AE_OK; | ||
1153 | acpi_status Mstatus; | ||
1154 | |||
1155 | while (status != AE_CTRL_TERMINATE && !acpi_gbl_db_terminate_loop) { | ||
1156 | acpi_gbl_method_executing = FALSE; | ||
1157 | acpi_gbl_step_to_next_call = FALSE; | ||
1158 | |||
1159 | Mstatus = acpi_os_acquire_mutex(acpi_gbl_db_command_ready, | ||
1160 | ACPI_WAIT_FOREVER); | ||
1161 | if (ACPI_FAILURE(Mstatus)) { | ||
1162 | return; | ||
1163 | } | ||
1164 | |||
1165 | status = | ||
1166 | acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL, NULL); | ||
1167 | 1150 | ||
1168 | acpi_os_release_mutex(acpi_gbl_db_command_complete); | 1151 | (void)acpi_db_user_commands(); |
1169 | } | ||
1170 | acpi_gbl_db_threads_terminated = TRUE; | 1152 | acpi_gbl_db_threads_terminated = TRUE; |
1171 | } | 1153 | } |
1172 | 1154 | ||
1173 | /******************************************************************************* | 1155 | /******************************************************************************* |
1174 | * | 1156 | * |
1175 | * FUNCTION: acpi_db_single_thread | ||
1176 | * | ||
1177 | * PARAMETERS: None | ||
1178 | * | ||
1179 | * RETURN: None | ||
1180 | * | ||
1181 | * DESCRIPTION: Debugger execute thread. Waits for a command line, then | ||
1182 | * simply dispatches it. | ||
1183 | * | ||
1184 | ******************************************************************************/ | ||
1185 | |||
1186 | static void acpi_db_single_thread(void) | ||
1187 | { | ||
1188 | |||
1189 | acpi_gbl_method_executing = FALSE; | ||
1190 | acpi_gbl_step_to_next_call = FALSE; | ||
1191 | |||
1192 | (void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL, NULL); | ||
1193 | } | ||
1194 | |||
1195 | /******************************************************************************* | ||
1196 | * | ||
1197 | * FUNCTION: acpi_db_user_commands | 1157 | * FUNCTION: acpi_db_user_commands |
1198 | * | 1158 | * |
1199 | * PARAMETERS: prompt - User prompt (depends on mode) | 1159 | * PARAMETERS: None |
1200 | * op - Current executing parse op | ||
1201 | * | 1160 | * |
1202 | * RETURN: None | 1161 | * RETURN: None |
1203 | * | 1162 | * |
@@ -1206,7 +1165,7 @@ static void acpi_db_single_thread(void) | |||
1206 | * | 1165 | * |
1207 | ******************************************************************************/ | 1166 | ******************************************************************************/ |
1208 | 1167 | ||
1209 | acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op) | 1168 | acpi_status acpi_db_user_commands(void) |
1210 | { | 1169 | { |
1211 | acpi_status status = AE_OK; | 1170 | acpi_status status = AE_OK; |
1212 | 1171 | ||
@@ -1216,52 +1175,31 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op) | |||
1216 | 1175 | ||
1217 | while (!acpi_gbl_db_terminate_loop) { | 1176 | while (!acpi_gbl_db_terminate_loop) { |
1218 | 1177 | ||
1219 | /* Force output to console until a command is entered */ | 1178 | /* Wait the readiness of the command */ |
1220 | |||
1221 | acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); | ||
1222 | |||
1223 | /* Different prompt if method is executing */ | ||
1224 | |||
1225 | if (!acpi_gbl_method_executing) { | ||
1226 | acpi_os_printf("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); | ||
1227 | } else { | ||
1228 | acpi_os_printf("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); | ||
1229 | } | ||
1230 | |||
1231 | /* Get the user input line */ | ||
1232 | 1179 | ||
1233 | status = acpi_os_get_line(acpi_gbl_db_line_buf, | 1180 | status = acpi_os_wait_command_ready(); |
1234 | ACPI_DB_LINE_BUFFER_SIZE, NULL); | ||
1235 | if (ACPI_FAILURE(status)) { | 1181 | if (ACPI_FAILURE(status)) { |
1236 | ACPI_EXCEPTION((AE_INFO, status, | 1182 | break; |
1237 | "While parsing command line")); | ||
1238 | return (status); | ||
1239 | } | 1183 | } |
1240 | 1184 | ||
1241 | /* Check for single or multithreaded debug */ | 1185 | /* Just call to the command line interpreter */ |
1242 | 1186 | ||
1243 | if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) { | 1187 | acpi_gbl_method_executing = FALSE; |
1244 | /* | 1188 | acpi_gbl_step_to_next_call = FALSE; |
1245 | * Signal the debug thread that we have a command to execute, | ||
1246 | * and wait for the command to complete. | ||
1247 | */ | ||
1248 | acpi_os_release_mutex(acpi_gbl_db_command_ready); | ||
1249 | if (ACPI_FAILURE(status)) { | ||
1250 | return (status); | ||
1251 | } | ||
1252 | 1189 | ||
1253 | status = | 1190 | (void)acpi_db_command_dispatch(acpi_gbl_db_line_buf, NULL, |
1254 | acpi_os_acquire_mutex(acpi_gbl_db_command_complete, | 1191 | NULL); |
1255 | ACPI_WAIT_FOREVER); | 1192 | |
1256 | if (ACPI_FAILURE(status)) { | 1193 | /* Notify the completion of the command */ |
1257 | return (status); | ||
1258 | } | ||
1259 | } else { | ||
1260 | /* Just call to the command line interpreter */ | ||
1261 | 1194 | ||
1262 | acpi_db_single_thread(); | 1195 | status = acpi_os_notify_command_complete(); |
1196 | if (ACPI_FAILURE(status)) { | ||
1197 | break; | ||
1263 | } | 1198 | } |
1264 | } | 1199 | } |
1265 | 1200 | ||
1201 | if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) { | ||
1202 | ACPI_EXCEPTION((AE_INFO, status, "While parsing command line")); | ||
1203 | } | ||
1266 | return (status); | 1204 | return (status); |
1267 | } | 1205 | } |
diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c index 342298a6e10f..d7ff58e8c233 100644 --- a/drivers/acpi/acpica/dbxface.c +++ b/drivers/acpi/acpica/dbxface.c | |||
@@ -85,46 +85,21 @@ acpi_db_start_command(struct acpi_walk_state *walk_state, | |||
85 | 85 | ||
86 | acpi_gbl_method_executing = TRUE; | 86 | acpi_gbl_method_executing = TRUE; |
87 | status = AE_CTRL_TRUE; | 87 | status = AE_CTRL_TRUE; |
88 | while (status == AE_CTRL_TRUE) { | ||
89 | if (acpi_gbl_debugger_configuration == DEBUGGER_MULTI_THREADED) { | ||
90 | |||
91 | /* Handshake with the front-end that gets user command lines */ | ||
92 | |||
93 | acpi_os_release_mutex(acpi_gbl_db_command_complete); | ||
94 | |||
95 | status = | ||
96 | acpi_os_acquire_mutex(acpi_gbl_db_command_ready, | ||
97 | ACPI_WAIT_FOREVER); | ||
98 | if (ACPI_FAILURE(status)) { | ||
99 | return (status); | ||
100 | } | ||
101 | } else { | ||
102 | /* Single threaded, we must get a command line ourselves */ | ||
103 | |||
104 | /* Force output to console until a command is entered */ | ||
105 | 88 | ||
106 | acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); | 89 | while (status == AE_CTRL_TRUE) { |
107 | 90 | ||
108 | /* Different prompt if method is executing */ | 91 | /* Notify the completion of the command */ |
109 | 92 | ||
110 | if (!acpi_gbl_method_executing) { | 93 | status = acpi_os_notify_command_complete(); |
111 | acpi_os_printf("%1c ", | 94 | if (ACPI_FAILURE(status)) { |
112 | ACPI_DEBUGGER_COMMAND_PROMPT); | 95 | goto error_exit; |
113 | } else { | 96 | } |
114 | acpi_os_printf("%1c ", | ||
115 | ACPI_DEBUGGER_EXECUTE_PROMPT); | ||
116 | } | ||
117 | 97 | ||
118 | /* Get the user input line */ | 98 | /* Wait the readiness of the command */ |
119 | 99 | ||
120 | status = acpi_os_get_line(acpi_gbl_db_line_buf, | 100 | status = acpi_os_wait_command_ready(); |
121 | ACPI_DB_LINE_BUFFER_SIZE, | 101 | if (ACPI_FAILURE(status)) { |
122 | NULL); | 102 | goto error_exit; |
123 | if (ACPI_FAILURE(status)) { | ||
124 | ACPI_EXCEPTION((AE_INFO, status, | ||
125 | "While parsing command line")); | ||
126 | return (status); | ||
127 | } | ||
128 | } | 103 | } |
129 | 104 | ||
130 | status = | 105 | status = |
@@ -134,11 +109,46 @@ acpi_db_start_command(struct acpi_walk_state *walk_state, | |||
134 | 109 | ||
135 | /* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */ | 110 | /* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */ |
136 | 111 | ||
112 | error_exit: | ||
113 | if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) { | ||
114 | ACPI_EXCEPTION((AE_INFO, status, | ||
115 | "While parsing/handling command line")); | ||
116 | } | ||
137 | return (status); | 117 | return (status); |
138 | } | 118 | } |
139 | 119 | ||
140 | /******************************************************************************* | 120 | /******************************************************************************* |
141 | * | 121 | * |
122 | * FUNCTION: acpi_db_signal_break_point | ||
123 | * | ||
124 | * PARAMETERS: walk_state - Current walk | ||
125 | * | ||
126 | * RETURN: Status | ||
127 | * | ||
128 | * DESCRIPTION: Called for AML_BREAK_POINT_OP | ||
129 | * | ||
130 | ******************************************************************************/ | ||
131 | |||
132 | void acpi_db_signal_break_point(struct acpi_walk_state *walk_state) | ||
133 | { | ||
134 | |||
135 | #ifndef ACPI_APPLICATION | ||
136 | if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) { | ||
137 | return; | ||
138 | } | ||
139 | #endif | ||
140 | |||
141 | /* | ||
142 | * Set the single-step flag. This will cause the debugger (if present) | ||
143 | * to break to the console within the AML debugger at the start of the | ||
144 | * next AML instruction. | ||
145 | */ | ||
146 | acpi_gbl_cm_single_step = TRUE; | ||
147 | acpi_os_printf("**break** Executed AML BreakPoint opcode\n"); | ||
148 | } | ||
149 | |||
150 | /******************************************************************************* | ||
151 | * | ||
142 | * FUNCTION: acpi_db_single_step | 152 | * FUNCTION: acpi_db_single_step |
143 | * | 153 | * |
144 | * PARAMETERS: walk_state - Current walk | 154 | * PARAMETERS: walk_state - Current walk |
@@ -420,15 +430,7 @@ acpi_status acpi_initialize_debugger(void) | |||
420 | 430 | ||
421 | /* These were created with one unit, grab it */ | 431 | /* These were created with one unit, grab it */ |
422 | 432 | ||
423 | status = acpi_os_acquire_mutex(acpi_gbl_db_command_complete, | 433 | status = acpi_os_initialize_command_signals(); |
424 | ACPI_WAIT_FOREVER); | ||
425 | if (ACPI_FAILURE(status)) { | ||
426 | acpi_os_printf("Could not get debugger mutex\n"); | ||
427 | return_ACPI_STATUS(status); | ||
428 | } | ||
429 | |||
430 | status = acpi_os_acquire_mutex(acpi_gbl_db_command_ready, | ||
431 | ACPI_WAIT_FOREVER); | ||
432 | if (ACPI_FAILURE(status)) { | 434 | if (ACPI_FAILURE(status)) { |
433 | acpi_os_printf("Could not get debugger mutex\n"); | 435 | acpi_os_printf("Could not get debugger mutex\n"); |
434 | return_ACPI_STATUS(status); | 436 | return_ACPI_STATUS(status); |
@@ -473,13 +475,14 @@ void acpi_terminate_debugger(void) | |||
473 | acpi_gbl_db_terminate_loop = TRUE; | 475 | acpi_gbl_db_terminate_loop = TRUE; |
474 | 476 | ||
475 | if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) { | 477 | if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) { |
476 | acpi_os_release_mutex(acpi_gbl_db_command_ready); | ||
477 | 478 | ||
478 | /* Wait the AML Debugger threads */ | 479 | /* Wait the AML Debugger threads */ |
479 | 480 | ||
480 | while (!acpi_gbl_db_threads_terminated) { | 481 | while (!acpi_gbl_db_threads_terminated) { |
481 | acpi_os_sleep(100); | 482 | acpi_os_sleep(100); |
482 | } | 483 | } |
484 | |||
485 | acpi_os_terminate_command_signals(); | ||
483 | } | 486 | } |
484 | 487 | ||
485 | if (acpi_gbl_db_buffer) { | 488 | if (acpi_gbl_db_buffer) { |
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index 435fc16e2f83..06a6f7f3af52 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include "amlcode.h" | 47 | #include "amlcode.h" |
48 | #include "acdispat.h" | 48 | #include "acdispat.h" |
49 | #include "acinterp.h" | 49 | #include "acinterp.h" |
50 | #include "acdebug.h" | ||
50 | 51 | ||
51 | #define _COMPONENT ACPI_DISPATCHER | 52 | #define _COMPONENT ACPI_DISPATCHER |
52 | ACPI_MODULE_NAME("dscontrol") | 53 | ACPI_MODULE_NAME("dscontrol") |
@@ -348,14 +349,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, | |||
348 | 349 | ||
349 | case AML_BREAK_POINT_OP: | 350 | case AML_BREAK_POINT_OP: |
350 | 351 | ||
351 | /* | 352 | acpi_db_signal_break_point(walk_state); |
352 | * Set the single-step flag. This will cause the debugger (if present) | ||
353 | * to break to the console within the AML debugger at the start of the | ||
354 | * next AML instruction. | ||
355 | */ | ||
356 | ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE); | ||
357 | ACPI_DEBUGGER_EXEC(acpi_os_printf | ||
358 | ("**break** Executed AML BreakPoint opcode\n")); | ||
359 | 353 | ||
360 | /* Call to the OSL in case OS wants a piece of the action */ | 354 | /* Call to the OSL in case OS wants a piece of the action */ |
361 | 355 | ||
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index ebc577baeaf9..e4293a8794ea 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c | |||
@@ -605,8 +605,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, | |||
605 | if (ACPI_FAILURE(status)) { | 605 | if (ACPI_FAILURE(status)) { |
606 | return_ACPI_STATUS(status); | 606 | return_ACPI_STATUS(status); |
607 | } | 607 | } |
608 | ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object | 608 | |
609 | (obj_desc, walk_state)); | 609 | acpi_db_display_argument_object(obj_desc, walk_state); |
610 | } else { | 610 | } else { |
611 | /* Check for null name case */ | 611 | /* Check for null name case */ |
612 | 612 | ||
@@ -638,10 +638,11 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, | |||
638 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, | 638 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
639 | "Argument previously created, already stacked\n")); | 639 | "Argument previously created, already stacked\n")); |
640 | 640 | ||
641 | ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object | 641 | acpi_db_display_argument_object(walk_state-> |
642 | (walk_state-> | 642 | operands[walk_state-> |
643 | operands[walk_state->num_operands - | 643 | num_operands - |
644 | 1], walk_state)); | 644 | 1], |
645 | walk_state); | ||
645 | 646 | ||
646 | /* | 647 | /* |
647 | * Use value that was already previously returned | 648 | * Use value that was already previously returned |
@@ -685,8 +686,7 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, | |||
685 | return_ACPI_STATUS(status); | 686 | return_ACPI_STATUS(status); |
686 | } | 687 | } |
687 | 688 | ||
688 | ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object | 689 | acpi_db_display_argument_object(obj_desc, walk_state); |
689 | (obj_desc, walk_state)); | ||
690 | } | 690 | } |
691 | 691 | ||
692 | return_ACPI_STATUS(AE_OK); | 692 | return_ACPI_STATUS(AE_OK); |
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index df54d46225cd..9cc5761ef483 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c | |||
@@ -178,8 +178,7 @@ cleanup: | |||
178 | 178 | ||
179 | /* Break to debugger to display result */ | 179 | /* Break to debugger to display result */ |
180 | 180 | ||
181 | ACPI_DEBUGGER_EXEC(acpi_db_display_result_object | 181 | acpi_db_display_result_object(local_obj_desc, walk_state); |
182 | (local_obj_desc, walk_state)); | ||
183 | 182 | ||
184 | /* | 183 | /* |
185 | * Delete the predicate result object (we know that | 184 | * Delete the predicate result object (we know that |
@@ -386,11 +385,10 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) | |||
386 | 385 | ||
387 | /* Call debugger for single step support (DEBUG build only) */ | 386 | /* Call debugger for single step support (DEBUG build only) */ |
388 | 387 | ||
389 | ACPI_DEBUGGER_EXEC(status = | 388 | status = acpi_db_single_step(walk_state, op, op_class); |
390 | acpi_db_single_step(walk_state, op, op_class)); | 389 | if (ACPI_FAILURE(status)) { |
391 | ACPI_DEBUGGER_EXEC(if (ACPI_FAILURE(status)) { | 390 | return_ACPI_STATUS(status); |
392 | return_ACPI_STATUS(status);} | 391 | } |
393 | ) ; | ||
394 | 392 | ||
395 | /* Decode the Opcode Class */ | 393 | /* Decode the Opcode Class */ |
396 | 394 | ||
@@ -728,8 +726,8 @@ cleanup: | |||
728 | 726 | ||
729 | /* Break to debugger to display result */ | 727 | /* Break to debugger to display result */ |
730 | 728 | ||
731 | ACPI_DEBUGGER_EXEC(acpi_db_display_result_object | 729 | acpi_db_display_result_object(walk_state->result_obj, |
732 | (walk_state->result_obj, walk_state)); | 730 | walk_state); |
733 | 731 | ||
734 | /* | 732 | /* |
735 | * Delete the result op if and only if: | 733 | * Delete the result op if and only if: |
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index ce406e39b669..ea0c207ff572 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c | |||
@@ -111,17 +111,6 @@ acpi_status acpi_ut_mutex_initialize(void) | |||
111 | if (ACPI_FAILURE(status)) { | 111 | if (ACPI_FAILURE(status)) { |
112 | return_ACPI_STATUS(status); | 112 | return_ACPI_STATUS(status); |
113 | } | 113 | } |
114 | #ifdef ACPI_DEBUGGER | ||
115 | |||
116 | /* Debugger Support */ | ||
117 | |||
118 | status = acpi_os_create_mutex(&acpi_gbl_db_command_ready); | ||
119 | if (ACPI_FAILURE(status)) { | ||
120 | return_ACPI_STATUS(status); | ||
121 | } | ||
122 | |||
123 | status = acpi_os_create_mutex(&acpi_gbl_db_command_complete); | ||
124 | #endif | ||
125 | 114 | ||
126 | return_ACPI_STATUS(status); | 115 | return_ACPI_STATUS(status); |
127 | } | 116 | } |
@@ -162,12 +151,6 @@ void acpi_ut_mutex_terminate(void) | |||
162 | /* Delete the reader/writer lock */ | 151 | /* Delete the reader/writer lock */ |
163 | 152 | ||
164 | acpi_ut_delete_rw_lock(&acpi_gbl_namespace_rw_lock); | 153 | acpi_ut_delete_rw_lock(&acpi_gbl_namespace_rw_lock); |
165 | |||
166 | #ifdef ACPI_DEBUGGER | ||
167 | acpi_os_delete_mutex(acpi_gbl_db_command_ready); | ||
168 | acpi_os_delete_mutex(acpi_gbl_db_command_complete); | ||
169 | #endif | ||
170 | |||
171 | return_VOID; | 154 | return_VOID; |
172 | } | 155 | } |
173 | 156 | ||
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a212cefae524..1a40111e1c86 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -1094,6 +1094,7 @@ static int __init acpi_init(void) | |||
1094 | acpi_debugfs_init(); | 1094 | acpi_debugfs_init(); |
1095 | acpi_sleep_proc_init(); | 1095 | acpi_sleep_proc_init(); |
1096 | acpi_wakeup_device_init(); | 1096 | acpi_wakeup_device_init(); |
1097 | acpi_debugger_init(); | ||
1097 | return 0; | 1098 | return 0; |
1098 | } | 1099 | } |
1099 | 1100 | ||
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 32d684af0ec7..bb66093b7799 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -220,6 +220,7 @@ void acpi_os_printf(const char *fmt, ...) | |||
220 | acpi_os_vprintf(fmt, args); | 220 | acpi_os_vprintf(fmt, args); |
221 | va_end(args); | 221 | va_end(args); |
222 | } | 222 | } |
223 | EXPORT_SYMBOL(acpi_os_printf); | ||
223 | 224 | ||
224 | void acpi_os_vprintf(const char *fmt, va_list args) | 225 | void acpi_os_vprintf(const char *fmt, va_list args) |
225 | { | 226 | { |
@@ -234,7 +235,8 @@ void acpi_os_vprintf(const char *fmt, va_list args) | |||
234 | printk(KERN_CONT "%s", buffer); | 235 | printk(KERN_CONT "%s", buffer); |
235 | } | 236 | } |
236 | #else | 237 | #else |
237 | printk(KERN_CONT "%s", buffer); | 238 | if (acpi_debugger_write_log(buffer) < 0) |
239 | printk(KERN_CONT "%s", buffer); | ||
238 | #endif | 240 | #endif |
239 | } | 241 | } |
240 | 242 | ||
@@ -1101,6 +1103,200 @@ static void acpi_os_execute_deferred(struct work_struct *work) | |||
1101 | kfree(dpc); | 1103 | kfree(dpc); |
1102 | } | 1104 | } |
1103 | 1105 | ||
1106 | #ifdef CONFIG_ACPI_DEBUGGER | ||
1107 | static struct acpi_debugger acpi_debugger; | ||
1108 | static bool acpi_debugger_initialized; | ||
1109 | |||
1110 | int acpi_register_debugger(struct module *owner, | ||
1111 | const struct acpi_debugger_ops *ops) | ||
1112 | { | ||
1113 | int ret = 0; | ||
1114 | |||
1115 | mutex_lock(&acpi_debugger.lock); | ||
1116 | if (acpi_debugger.ops) { | ||
1117 | ret = -EBUSY; | ||
1118 | goto err_lock; | ||
1119 | } | ||
1120 | |||
1121 | acpi_debugger.owner = owner; | ||
1122 | acpi_debugger.ops = ops; | ||
1123 | |||
1124 | err_lock: | ||
1125 | mutex_unlock(&acpi_debugger.lock); | ||
1126 | return ret; | ||
1127 | } | ||
1128 | EXPORT_SYMBOL(acpi_register_debugger); | ||
1129 | |||
1130 | void acpi_unregister_debugger(const struct acpi_debugger_ops *ops) | ||
1131 | { | ||
1132 | mutex_lock(&acpi_debugger.lock); | ||
1133 | if (ops == acpi_debugger.ops) { | ||
1134 | acpi_debugger.ops = NULL; | ||
1135 | acpi_debugger.owner = NULL; | ||
1136 | } | ||
1137 | mutex_unlock(&acpi_debugger.lock); | ||
1138 | } | ||
1139 | EXPORT_SYMBOL(acpi_unregister_debugger); | ||
1140 | |||
1141 | int acpi_debugger_create_thread(acpi_osd_exec_callback function, void *context) | ||
1142 | { | ||
1143 | int ret; | ||
1144 | int (*func)(acpi_osd_exec_callback, void *); | ||
1145 | struct module *owner; | ||
1146 | |||
1147 | if (!acpi_debugger_initialized) | ||
1148 | return -ENODEV; | ||
1149 | mutex_lock(&acpi_debugger.lock); | ||
1150 | if (!acpi_debugger.ops) { | ||
1151 | ret = -ENODEV; | ||
1152 | goto err_lock; | ||
1153 | } | ||
1154 | if (!try_module_get(acpi_debugger.owner)) { | ||
1155 | ret = -ENODEV; | ||
1156 | goto err_lock; | ||
1157 | } | ||
1158 | func = acpi_debugger.ops->create_thread; | ||
1159 | owner = acpi_debugger.owner; | ||
1160 | mutex_unlock(&acpi_debugger.lock); | ||
1161 | |||
1162 | ret = func(function, context); | ||
1163 | |||
1164 | mutex_lock(&acpi_debugger.lock); | ||
1165 | module_put(owner); | ||
1166 | err_lock: | ||
1167 | mutex_unlock(&acpi_debugger.lock); | ||
1168 | return ret; | ||
1169 | } | ||
1170 | |||
1171 | ssize_t acpi_debugger_write_log(const char *msg) | ||
1172 | { | ||
1173 | ssize_t ret; | ||
1174 | ssize_t (*func)(const char *); | ||
1175 | struct module *owner; | ||
1176 | |||
1177 | if (!acpi_debugger_initialized) | ||
1178 | return -ENODEV; | ||
1179 | mutex_lock(&acpi_debugger.lock); | ||
1180 | if (!acpi_debugger.ops) { | ||
1181 | ret = -ENODEV; | ||
1182 | goto err_lock; | ||
1183 | } | ||
1184 | if (!try_module_get(acpi_debugger.owner)) { | ||
1185 | ret = -ENODEV; | ||
1186 | goto err_lock; | ||
1187 | } | ||
1188 | func = acpi_debugger.ops->write_log; | ||
1189 | owner = acpi_debugger.owner; | ||
1190 | mutex_unlock(&acpi_debugger.lock); | ||
1191 | |||
1192 | ret = func(msg); | ||
1193 | |||
1194 | mutex_lock(&acpi_debugger.lock); | ||
1195 | module_put(owner); | ||
1196 | err_lock: | ||
1197 | mutex_unlock(&acpi_debugger.lock); | ||
1198 | return ret; | ||
1199 | } | ||
1200 | |||
1201 | ssize_t acpi_debugger_read_cmd(char *buffer, size_t buffer_length) | ||
1202 | { | ||
1203 | ssize_t ret; | ||
1204 | ssize_t (*func)(char *, size_t); | ||
1205 | struct module *owner; | ||
1206 | |||
1207 | if (!acpi_debugger_initialized) | ||
1208 | return -ENODEV; | ||
1209 | mutex_lock(&acpi_debugger.lock); | ||
1210 | if (!acpi_debugger.ops) { | ||
1211 | ret = -ENODEV; | ||
1212 | goto err_lock; | ||
1213 | } | ||
1214 | if (!try_module_get(acpi_debugger.owner)) { | ||
1215 | ret = -ENODEV; | ||
1216 | goto err_lock; | ||
1217 | } | ||
1218 | func = acpi_debugger.ops->read_cmd; | ||
1219 | owner = acpi_debugger.owner; | ||
1220 | mutex_unlock(&acpi_debugger.lock); | ||
1221 | |||
1222 | ret = func(buffer, buffer_length); | ||
1223 | |||
1224 | mutex_lock(&acpi_debugger.lock); | ||
1225 | module_put(owner); | ||
1226 | err_lock: | ||
1227 | mutex_unlock(&acpi_debugger.lock); | ||
1228 | return ret; | ||
1229 | } | ||
1230 | |||
1231 | int acpi_debugger_wait_command_ready(void) | ||
1232 | { | ||
1233 | int ret; | ||
1234 | int (*func)(bool, char *, size_t); | ||
1235 | struct module *owner; | ||
1236 | |||
1237 | if (!acpi_debugger_initialized) | ||
1238 | return -ENODEV; | ||
1239 | mutex_lock(&acpi_debugger.lock); | ||
1240 | if (!acpi_debugger.ops) { | ||
1241 | ret = -ENODEV; | ||
1242 | goto err_lock; | ||
1243 | } | ||
1244 | if (!try_module_get(acpi_debugger.owner)) { | ||
1245 | ret = -ENODEV; | ||
1246 | goto err_lock; | ||
1247 | } | ||
1248 | func = acpi_debugger.ops->wait_command_ready; | ||
1249 | owner = acpi_debugger.owner; | ||
1250 | mutex_unlock(&acpi_debugger.lock); | ||
1251 | |||
1252 | ret = func(acpi_gbl_method_executing, | ||
1253 | acpi_gbl_db_line_buf, ACPI_DB_LINE_BUFFER_SIZE); | ||
1254 | |||
1255 | mutex_lock(&acpi_debugger.lock); | ||
1256 | module_put(owner); | ||
1257 | err_lock: | ||
1258 | mutex_unlock(&acpi_debugger.lock); | ||
1259 | return ret; | ||
1260 | } | ||
1261 | |||
1262 | int acpi_debugger_notify_command_complete(void) | ||
1263 | { | ||
1264 | int ret; | ||
1265 | int (*func)(void); | ||
1266 | struct module *owner; | ||
1267 | |||
1268 | if (!acpi_debugger_initialized) | ||
1269 | return -ENODEV; | ||
1270 | mutex_lock(&acpi_debugger.lock); | ||
1271 | if (!acpi_debugger.ops) { | ||
1272 | ret = -ENODEV; | ||
1273 | goto err_lock; | ||
1274 | } | ||
1275 | if (!try_module_get(acpi_debugger.owner)) { | ||
1276 | ret = -ENODEV; | ||
1277 | goto err_lock; | ||
1278 | } | ||
1279 | func = acpi_debugger.ops->notify_command_complete; | ||
1280 | owner = acpi_debugger.owner; | ||
1281 | mutex_unlock(&acpi_debugger.lock); | ||
1282 | |||
1283 | ret = func(); | ||
1284 | |||
1285 | mutex_lock(&acpi_debugger.lock); | ||
1286 | module_put(owner); | ||
1287 | err_lock: | ||
1288 | mutex_unlock(&acpi_debugger.lock); | ||
1289 | return ret; | ||
1290 | } | ||
1291 | |||
1292 | int __init acpi_debugger_init(void) | ||
1293 | { | ||
1294 | mutex_init(&acpi_debugger.lock); | ||
1295 | acpi_debugger_initialized = true; | ||
1296 | return 0; | ||
1297 | } | ||
1298 | #endif | ||
1299 | |||
1104 | /******************************************************************************* | 1300 | /******************************************************************************* |
1105 | * | 1301 | * |
1106 | * FUNCTION: acpi_os_execute | 1302 | * FUNCTION: acpi_os_execute |
@@ -1127,6 +1323,15 @@ acpi_status acpi_os_execute(acpi_execute_type type, | |||
1127 | "Scheduling function [%p(%p)] for deferred execution.\n", | 1323 | "Scheduling function [%p(%p)] for deferred execution.\n", |
1128 | function, context)); | 1324 | function, context)); |
1129 | 1325 | ||
1326 | if (type == OSL_DEBUGGER_MAIN_THREAD) { | ||
1327 | ret = acpi_debugger_create_thread(function, context); | ||
1328 | if (ret) { | ||
1329 | pr_err("Call to kthread_create() failed.\n"); | ||
1330 | status = AE_ERROR; | ||
1331 | } | ||
1332 | goto out_thread; | ||
1333 | } | ||
1334 | |||
1130 | /* | 1335 | /* |
1131 | * Allocate/initialize DPC structure. Note that this memory will be | 1336 | * Allocate/initialize DPC structure. Note that this memory will be |
1132 | * freed by the callee. The kernel handles the work_struct list in a | 1337 | * freed by the callee. The kernel handles the work_struct list in a |
@@ -1151,11 +1356,17 @@ acpi_status acpi_os_execute(acpi_execute_type type, | |||
1151 | if (type == OSL_NOTIFY_HANDLER) { | 1356 | if (type == OSL_NOTIFY_HANDLER) { |
1152 | queue = kacpi_notify_wq; | 1357 | queue = kacpi_notify_wq; |
1153 | INIT_WORK(&dpc->work, acpi_os_execute_deferred); | 1358 | INIT_WORK(&dpc->work, acpi_os_execute_deferred); |
1154 | } else { | 1359 | } else if (type == OSL_GPE_HANDLER) { |
1155 | queue = kacpid_wq; | 1360 | queue = kacpid_wq; |
1156 | INIT_WORK(&dpc->work, acpi_os_execute_deferred); | 1361 | INIT_WORK(&dpc->work, acpi_os_execute_deferred); |
1362 | } else { | ||
1363 | pr_err("Unsupported os_execute type %d.\n", type); | ||
1364 | status = AE_ERROR; | ||
1157 | } | 1365 | } |
1158 | 1366 | ||
1367 | if (ACPI_FAILURE(status)) | ||
1368 | goto err_workqueue; | ||
1369 | |||
1159 | /* | 1370 | /* |
1160 | * On some machines, a software-initiated SMI causes corruption unless | 1371 | * On some machines, a software-initiated SMI causes corruption unless |
1161 | * the SMI runs on CPU 0. An SMI can be initiated by any AML, but | 1372 | * the SMI runs on CPU 0. An SMI can be initiated by any AML, but |
@@ -1164,13 +1375,15 @@ acpi_status acpi_os_execute(acpi_execute_type type, | |||
1164 | * queueing on CPU 0. | 1375 | * queueing on CPU 0. |
1165 | */ | 1376 | */ |
1166 | ret = queue_work_on(0, queue, &dpc->work); | 1377 | ret = queue_work_on(0, queue, &dpc->work); |
1167 | |||
1168 | if (!ret) { | 1378 | if (!ret) { |
1169 | printk(KERN_ERR PREFIX | 1379 | printk(KERN_ERR PREFIX |
1170 | "Call to queue_work() failed.\n"); | 1380 | "Call to queue_work() failed.\n"); |
1171 | status = AE_ERROR; | 1381 | status = AE_ERROR; |
1172 | kfree(dpc); | ||
1173 | } | 1382 | } |
1383 | err_workqueue: | ||
1384 | if (ACPI_FAILURE(status)) | ||
1385 | kfree(dpc); | ||
1386 | out_thread: | ||
1174 | return status; | 1387 | return status; |
1175 | } | 1388 | } |
1176 | EXPORT_SYMBOL(acpi_os_execute); | 1389 | EXPORT_SYMBOL(acpi_os_execute); |
@@ -1358,10 +1571,39 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read) | |||
1358 | chars = strlen(buffer) - 1; | 1571 | chars = strlen(buffer) - 1; |
1359 | buffer[chars] = '\0'; | 1572 | buffer[chars] = '\0'; |
1360 | } | 1573 | } |
1574 | #else | ||
1575 | int ret; | ||
1576 | |||
1577 | ret = acpi_debugger_read_cmd(buffer, buffer_length); | ||
1578 | if (ret < 0) | ||
1579 | return AE_ERROR; | ||
1580 | if (bytes_read) | ||
1581 | *bytes_read = ret; | ||
1361 | #endif | 1582 | #endif |
1362 | 1583 | ||
1363 | return AE_OK; | 1584 | return AE_OK; |
1364 | } | 1585 | } |
1586 | EXPORT_SYMBOL(acpi_os_get_line); | ||
1587 | |||
1588 | acpi_status acpi_os_wait_command_ready(void) | ||
1589 | { | ||
1590 | int ret; | ||
1591 | |||
1592 | ret = acpi_debugger_wait_command_ready(); | ||
1593 | if (ret < 0) | ||
1594 | return AE_ERROR; | ||
1595 | return AE_OK; | ||
1596 | } | ||
1597 | |||
1598 | acpi_status acpi_os_notify_command_complete(void) | ||
1599 | { | ||
1600 | int ret; | ||
1601 | |||
1602 | ret = acpi_debugger_notify_command_complete(); | ||
1603 | if (ret < 0) | ||
1604 | return AE_ERROR; | ||
1605 | return AE_OK; | ||
1606 | } | ||
1365 | 1607 | ||
1366 | acpi_status acpi_os_signal(u32 function, void *info) | 1608 | acpi_status acpi_os_signal(u32 function, void *info) |
1367 | { | 1609 | { |
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index fbc2baf2b9dc..0d824a28522d 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h | |||
@@ -349,12 +349,28 @@ void acpi_os_redirect_output(void *destination); | |||
349 | #endif | 349 | #endif |
350 | 350 | ||
351 | /* | 351 | /* |
352 | * Debug input | 352 | * Debug IO |
353 | */ | 353 | */ |
354 | #ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_line | 354 | #ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_line |
355 | acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read); | 355 | acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read); |
356 | #endif | 356 | #endif |
357 | 357 | ||
358 | #ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals | ||
359 | acpi_status acpi_os_initialize_command_signals(void); | ||
360 | #endif | ||
361 | |||
362 | #ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals | ||
363 | void acpi_os_terminate_command_signals(void); | ||
364 | #endif | ||
365 | |||
366 | #ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready | ||
367 | acpi_status acpi_os_wait_command_ready(void); | ||
368 | #endif | ||
369 | |||
370 | #ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete | ||
371 | acpi_status acpi_os_notify_command_complete(void); | ||
372 | #endif | ||
373 | |||
358 | /* | 374 | /* |
359 | * Obtain ACPI table(s) | 375 | * Obtain ACPI table(s) |
360 | */ | 376 | */ |
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 3aaaa8630735..5dfab9c2142e 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h | |||
@@ -264,6 +264,15 @@ ACPI_INIT_GLOBAL(u32, acpi_dbg_level, ACPI_DEBUG_DEFAULT); | |||
264 | ACPI_INIT_GLOBAL(u32, acpi_dbg_layer, 0); | 264 | ACPI_INIT_GLOBAL(u32, acpi_dbg_layer, 0); |
265 | 265 | ||
266 | /* | 266 | /* |
267 | * Debugger command handshake globals. Host OSes need to access these | ||
268 | * variables to implement their own command handshake mechanism. | ||
269 | */ | ||
270 | #ifdef ACPI_DEBUGGER | ||
271 | ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE); | ||
272 | ACPI_GLOBAL(char, acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]); | ||
273 | #endif | ||
274 | |||
275 | /* | ||
267 | * Other miscellaneous globals | 276 | * Other miscellaneous globals |
268 | */ | 277 | */ |
269 | ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT); | 278 | ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT); |
@@ -366,6 +375,29 @@ ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running); | |||
366 | 375 | ||
367 | #endif /* ACPI_APPLICATION */ | 376 | #endif /* ACPI_APPLICATION */ |
368 | 377 | ||
378 | /* | ||
379 | * Debugger prototypes | ||
380 | * | ||
381 | * All interfaces used by debugger will be configured | ||
382 | * out of the ACPICA build unless the ACPI_DEBUGGER | ||
383 | * flag is defined. | ||
384 | */ | ||
385 | #ifdef ACPI_DEBUGGER | ||
386 | #define ACPI_DBR_DEPENDENT_RETURN_OK(prototype) \ | ||
387 | ACPI_EXTERNAL_RETURN_OK(prototype) | ||
388 | |||
389 | #define ACPI_DBR_DEPENDENT_RETURN_VOID(prototype) \ | ||
390 | ACPI_EXTERNAL_RETURN_VOID(prototype) | ||
391 | |||
392 | #else | ||
393 | #define ACPI_DBR_DEPENDENT_RETURN_OK(prototype) \ | ||
394 | static ACPI_INLINE prototype {return(AE_OK);} | ||
395 | |||
396 | #define ACPI_DBR_DEPENDENT_RETURN_VOID(prototype) \ | ||
397 | static ACPI_INLINE prototype {return;} | ||
398 | |||
399 | #endif /* ACPI_DEBUGGER */ | ||
400 | |||
369 | /***************************************************************************** | 401 | /***************************************************************************** |
370 | * | 402 | * |
371 | * ACPICA public interface prototypes | 403 | * ACPICA public interface prototypes |
@@ -929,6 +961,8 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status | |||
929 | void **data, | 961 | void **data, |
930 | void (*callback)(void *))) | 962 | void (*callback)(void *))) |
931 | 963 | ||
964 | void acpi_run_debugger(char *batch_buffer); | ||
965 | |||
932 | void acpi_set_debugger_thread_id(acpi_thread_id thread_id); | 966 | void acpi_set_debugger_thread_id(acpi_thread_id thread_id); |
933 | 967 | ||
934 | #endif /* __ACXFACE_H__ */ | 968 | #endif /* __ACXFACE_H__ */ |
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 323e5daece54..e21857d2ec05 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h | |||
@@ -150,6 +150,8 @@ | |||
150 | */ | 150 | */ |
151 | #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_readable | 151 | #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_readable |
152 | #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_writable | 152 | #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_writable |
153 | #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals | ||
154 | #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals | ||
153 | 155 | ||
154 | /* | 156 | /* |
155 | * OSL interfaces used by utilities | 157 | * OSL interfaces used by utilities |
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h index fd6d70fe1219..ceea026b2c0b 100644 --- a/include/acpi/platform/aclinuxex.h +++ b/include/acpi/platform/aclinuxex.h | |||
@@ -129,6 +129,15 @@ static inline u8 acpi_os_readable(void *pointer, acpi_size length) | |||
129 | return TRUE; | 129 | return TRUE; |
130 | } | 130 | } |
131 | 131 | ||
132 | static inline acpi_status acpi_os_initialize_command_signals(void) | ||
133 | { | ||
134 | return AE_OK; | ||
135 | } | ||
136 | |||
137 | static inline void acpi_os_terminate_command_signals(void) | ||
138 | { | ||
139 | } | ||
140 | |||
132 | /* | 141 | /* |
133 | * OSL interfaces added by Linux | 142 | * OSL interfaces added by Linux |
134 | */ | 143 | */ |
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 1991aea2ec4c..a03a05474527 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
@@ -37,6 +37,8 @@ | |||
37 | #include <linux/list.h> | 37 | #include <linux/list.h> |
38 | #include <linux/mod_devicetable.h> | 38 | #include <linux/mod_devicetable.h> |
39 | #include <linux/dynamic_debug.h> | 39 | #include <linux/dynamic_debug.h> |
40 | #include <linux/module.h> | ||
41 | #include <linux/mutex.h> | ||
40 | 42 | ||
41 | #include <acpi/acpi_bus.h> | 43 | #include <acpi/acpi_bus.h> |
42 | #include <acpi/acpi_drivers.h> | 44 | #include <acpi/acpi_drivers.h> |
@@ -119,6 +121,75 @@ typedef int (*acpi_tbl_table_handler)(struct acpi_table_header *table); | |||
119 | typedef int (*acpi_tbl_entry_handler)(struct acpi_subtable_header *header, | 121 | typedef int (*acpi_tbl_entry_handler)(struct acpi_subtable_header *header, |
120 | const unsigned long end); | 122 | const unsigned long end); |
121 | 123 | ||
124 | /* Debugger support */ | ||
125 | |||
126 | struct acpi_debugger_ops { | ||
127 | int (*create_thread)(acpi_osd_exec_callback function, void *context); | ||
128 | ssize_t (*write_log)(const char *msg); | ||
129 | ssize_t (*read_cmd)(char *buffer, size_t length); | ||
130 | int (*wait_command_ready)(bool single_step, char *buffer, size_t length); | ||
131 | int (*notify_command_complete)(void); | ||
132 | }; | ||
133 | |||
134 | struct acpi_debugger { | ||
135 | const struct acpi_debugger_ops *ops; | ||
136 | struct module *owner; | ||
137 | struct mutex lock; | ||
138 | }; | ||
139 | |||
140 | #ifdef CONFIG_ACPI_DEBUGGER | ||
141 | int __init acpi_debugger_init(void); | ||
142 | int acpi_register_debugger(struct module *owner, | ||
143 | const struct acpi_debugger_ops *ops); | ||
144 | void acpi_unregister_debugger(const struct acpi_debugger_ops *ops); | ||
145 | int acpi_debugger_create_thread(acpi_osd_exec_callback function, void *context); | ||
146 | ssize_t acpi_debugger_write_log(const char *msg); | ||
147 | ssize_t acpi_debugger_read_cmd(char *buffer, size_t buffer_length); | ||
148 | int acpi_debugger_wait_command_ready(void); | ||
149 | int acpi_debugger_notify_command_complete(void); | ||
150 | #else | ||
151 | static inline int acpi_debugger_init(void) | ||
152 | { | ||
153 | return -ENODEV; | ||
154 | } | ||
155 | |||
156 | static inline int acpi_register_debugger(struct module *owner, | ||
157 | const struct acpi_debugger_ops *ops) | ||
158 | { | ||
159 | return -ENODEV; | ||
160 | } | ||
161 | |||
162 | static inline void acpi_unregister_debugger(const struct acpi_debugger_ops *ops) | ||
163 | { | ||
164 | } | ||
165 | |||
166 | static inline int acpi_debugger_create_thread(acpi_osd_exec_callback function, | ||
167 | void *context) | ||
168 | { | ||
169 | return -ENODEV; | ||
170 | } | ||
171 | |||
172 | static inline int acpi_debugger_write_log(const char *msg) | ||
173 | { | ||
174 | return -ENODEV; | ||
175 | } | ||
176 | |||
177 | static inline int acpi_debugger_read_cmd(char *buffer, u32 buffer_length) | ||
178 | { | ||
179 | return -ENODEV; | ||
180 | } | ||
181 | |||
182 | static inline int acpi_debugger_wait_command_ready(void) | ||
183 | { | ||
184 | return -ENODEV; | ||
185 | } | ||
186 | |||
187 | static inline int acpi_debugger_notify_command_complete(void) | ||
188 | { | ||
189 | return -ENODEV; | ||
190 | } | ||
191 | #endif | ||
192 | |||
122 | #ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE | 193 | #ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE |
123 | void acpi_initrd_override(void *data, size_t size); | 194 | void acpi_initrd_override(void *data, size_t size); |
124 | #else | 195 | #else |
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile index e882c8320135..a8bf9081512b 100644 --- a/tools/power/acpi/Makefile +++ b/tools/power/acpi/Makefile | |||
@@ -10,18 +10,18 @@ | |||
10 | 10 | ||
11 | include ../../scripts/Makefile.include | 11 | include ../../scripts/Makefile.include |
12 | 12 | ||
13 | all: acpidump ec | 13 | all: acpidbg acpidump ec |
14 | clean: acpidump_clean ec_clean | 14 | clean: acpidbg_clean acpidump_clean ec_clean |
15 | install: acpidump_install ec_install | 15 | install: acpidbg_install acpidump_install ec_install |
16 | uninstall: acpidump_uninstall ec_uninstall | 16 | uninstall: acpidbg_uninstall acpidump_uninstall ec_uninstall |
17 | 17 | ||
18 | acpidump ec: FORCE | 18 | acpidbg acpidump ec: FORCE |
19 | $(call descend,tools/$@,all) | 19 | $(call descend,tools/$@,all) |
20 | acpidump_clean ec_clean: | 20 | acpidbg_clean acpidump_clean ec_clean: |
21 | $(call descend,tools/$(@:_clean=),clean) | 21 | $(call descend,tools/$(@:_clean=),clean) |
22 | acpidump_install ec_install: | 22 | acpidbg_install acpidump_install ec_install: |
23 | $(call descend,tools/$(@:_install=),install) | 23 | $(call descend,tools/$(@:_install=),install) |
24 | acpidump_uninstall ec_uninstall: | 24 | acpidbg_uninstall acpidump_uninstall ec_uninstall: |
25 | $(call descend,tools/$(@:_uninstall=),uninstall) | 25 | $(call descend,tools/$(@:_uninstall=),uninstall) |
26 | 26 | ||
27 | .PHONY: FORCE | 27 | .PHONY: FORCE |
diff --git a/tools/power/acpi/tools/acpidbg/Makefile b/tools/power/acpi/tools/acpidbg/Makefile new file mode 100644 index 000000000000..352df4b41ae9 --- /dev/null +++ b/tools/power/acpi/tools/acpidbg/Makefile | |||
@@ -0,0 +1,27 @@ | |||
1 | # tools/power/acpi/tools/acpidbg/Makefile - ACPI tool Makefile | ||
2 | # | ||
3 | # Copyright (c) 2015, Intel Corporation | ||
4 | # Author: Lv Zheng <lv.zheng@intel.com> | ||
5 | # | ||
6 | # This program is free software; you can redistribute it and/or | ||
7 | # modify it under the terms of the GNU General Public License | ||
8 | # as published by the Free Software Foundation; version 2 | ||
9 | # of the License. | ||
10 | |||
11 | include ../../Makefile.config | ||
12 | |||
13 | TOOL = acpidbg | ||
14 | vpath %.c \ | ||
15 | ../../../../../drivers/acpi/acpica\ | ||
16 | ../../common\ | ||
17 | ../../os_specific/service_layers\ | ||
18 | . | ||
19 | CFLAGS += -DACPI_APPLICATION -DACPI_SINGLE_THREAD -DACPI_DEBUGGER\ | ||
20 | -I.\ | ||
21 | -I../../../../../drivers/acpi/acpica\ | ||
22 | -I../../../../../include | ||
23 | LDFLAGS += -lpthread | ||
24 | TOOL_OBJS = \ | ||
25 | acpidbg.o | ||
26 | |||
27 | include ../../Makefile.rules | ||
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c new file mode 100644 index 000000000000..d070fccdba6d --- /dev/null +++ b/tools/power/acpi/tools/acpidbg/acpidbg.c | |||
@@ -0,0 +1,438 @@ | |||
1 | /* | ||
2 | * ACPI AML interfacing userspace utility | ||
3 | * | ||
4 | * Copyright (C) 2015, Intel Corporation | ||
5 | * Authors: Lv Zheng <lv.zheng@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <acpi/acpi.h> | ||
13 | |||
14 | /* Headers not included by include/acpi/platform/aclinux.h */ | ||
15 | #include <stdbool.h> | ||
16 | #include <fcntl.h> | ||
17 | #include <assert.h> | ||
18 | #include <linux/circ_buf.h> | ||
19 | |||
20 | #define ACPI_AML_FILE "/sys/kernel/debug/acpi/acpidbg" | ||
21 | #define ACPI_AML_SEC_TICK 1 | ||
22 | #define ACPI_AML_USEC_PEEK 200 | ||
23 | #define ACPI_AML_BUF_SIZE 4096 | ||
24 | |||
25 | #define ACPI_AML_BATCH_WRITE_CMD 0x00 /* Write command to kernel */ | ||
26 | #define ACPI_AML_BATCH_READ_LOG 0x01 /* Read log from kernel */ | ||
27 | #define ACPI_AML_BATCH_WRITE_LOG 0x02 /* Write log to console */ | ||
28 | |||
29 | #define ACPI_AML_LOG_START 0x00 | ||
30 | #define ACPI_AML_PROMPT_START 0x01 | ||
31 | #define ACPI_AML_PROMPT_STOP 0x02 | ||
32 | #define ACPI_AML_LOG_STOP 0x03 | ||
33 | #define ACPI_AML_PROMPT_ROLL 0x04 | ||
34 | |||
35 | #define ACPI_AML_INTERACTIVE 0x00 | ||
36 | #define ACPI_AML_BATCH 0x01 | ||
37 | |||
38 | #define circ_count(circ) \ | ||
39 | (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) | ||
40 | #define circ_count_to_end(circ) \ | ||
41 | (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) | ||
42 | #define circ_space(circ) \ | ||
43 | (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) | ||
44 | #define circ_space_to_end(circ) \ | ||
45 | (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE)) | ||
46 | |||
47 | #define acpi_aml_cmd_count() circ_count(&acpi_aml_cmd_crc) | ||
48 | #define acpi_aml_log_count() circ_count(&acpi_aml_log_crc) | ||
49 | #define acpi_aml_cmd_space() circ_space(&acpi_aml_cmd_crc) | ||
50 | #define acpi_aml_log_space() circ_space(&acpi_aml_log_crc) | ||
51 | |||
52 | #define ACPI_AML_DO(_fd, _op, _buf, _ret) \ | ||
53 | do { \ | ||
54 | _ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc); \ | ||
55 | if (_ret == 0) { \ | ||
56 | fprintf(stderr, \ | ||
57 | "%s %s pipe closed.\n", #_buf, #_op); \ | ||
58 | return; \ | ||
59 | } \ | ||
60 | } while (0) | ||
61 | #define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret) \ | ||
62 | do { \ | ||
63 | _ret = acpi_aml_##_op##_batch_##_buf(_fd, \ | ||
64 | &acpi_aml_##_buf##_crc); \ | ||
65 | if (_ret == 0) \ | ||
66 | return; \ | ||
67 | } while (0) | ||
68 | |||
69 | |||
70 | static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE]; | ||
71 | static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE]; | ||
72 | static struct circ_buf acpi_aml_cmd_crc = { | ||
73 | .buf = acpi_aml_cmd_buf, | ||
74 | .head = 0, | ||
75 | .tail = 0, | ||
76 | }; | ||
77 | static struct circ_buf acpi_aml_log_crc = { | ||
78 | .buf = acpi_aml_log_buf, | ||
79 | .head = 0, | ||
80 | .tail = 0, | ||
81 | }; | ||
82 | static const char *acpi_aml_file_path = ACPI_AML_FILE; | ||
83 | static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE; | ||
84 | static bool acpi_aml_exit; | ||
85 | |||
86 | static bool acpi_aml_batch_drain; | ||
87 | static unsigned long acpi_aml_batch_state; | ||
88 | static char acpi_aml_batch_prompt; | ||
89 | static char acpi_aml_batch_roll; | ||
90 | static unsigned long acpi_aml_log_state; | ||
91 | static char *acpi_aml_batch_cmd = NULL; | ||
92 | static char *acpi_aml_batch_pos = NULL; | ||
93 | |||
94 | static int acpi_aml_set_fl(int fd, int flags) | ||
95 | { | ||
96 | int ret; | ||
97 | |||
98 | ret = fcntl(fd, F_GETFL, 0); | ||
99 | if (ret < 0) { | ||
100 | perror("fcntl(F_GETFL)"); | ||
101 | return ret; | ||
102 | } | ||
103 | flags |= ret; | ||
104 | ret = fcntl(fd, F_SETFL, flags); | ||
105 | if (ret < 0) { | ||
106 | perror("fcntl(F_SETFL)"); | ||
107 | return ret; | ||
108 | } | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set) | ||
113 | { | ||
114 | if (fd > maxfd) | ||
115 | maxfd = fd; | ||
116 | FD_SET(fd, set); | ||
117 | return maxfd; | ||
118 | } | ||
119 | |||
120 | static int acpi_aml_read(int fd, struct circ_buf *crc) | ||
121 | { | ||
122 | char *p; | ||
123 | int len; | ||
124 | |||
125 | p = &crc->buf[crc->head]; | ||
126 | len = circ_space_to_end(crc); | ||
127 | len = read(fd, p, len); | ||
128 | if (len < 0) | ||
129 | perror("read"); | ||
130 | else if (len > 0) | ||
131 | crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1); | ||
132 | return len; | ||
133 | } | ||
134 | |||
135 | static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc) | ||
136 | { | ||
137 | char *p; | ||
138 | int len; | ||
139 | int remained = strlen(acpi_aml_batch_pos); | ||
140 | |||
141 | p = &crc->buf[crc->head]; | ||
142 | len = circ_space_to_end(crc); | ||
143 | if (len > remained) { | ||
144 | memcpy(p, acpi_aml_batch_pos, remained); | ||
145 | acpi_aml_batch_pos += remained; | ||
146 | len = remained; | ||
147 | } else { | ||
148 | memcpy(p, acpi_aml_batch_pos, len); | ||
149 | acpi_aml_batch_pos += len; | ||
150 | } | ||
151 | if (len > 0) | ||
152 | crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1); | ||
153 | return len; | ||
154 | } | ||
155 | |||
156 | static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc) | ||
157 | { | ||
158 | char *p; | ||
159 | int len; | ||
160 | int ret = 0; | ||
161 | |||
162 | p = &crc->buf[crc->head]; | ||
163 | len = circ_space_to_end(crc); | ||
164 | while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) { | ||
165 | if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) { | ||
166 | *p = acpi_aml_batch_roll; | ||
167 | len = 1; | ||
168 | crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1); | ||
169 | ret += 1; | ||
170 | acpi_aml_log_state = ACPI_AML_LOG_START; | ||
171 | } else { | ||
172 | len = read(fd, p, 1); | ||
173 | if (len <= 0) { | ||
174 | if (len < 0) | ||
175 | perror("read"); | ||
176 | ret = len; | ||
177 | break; | ||
178 | } | ||
179 | } | ||
180 | switch (acpi_aml_log_state) { | ||
181 | case ACPI_AML_LOG_START: | ||
182 | if (*p == '\n') | ||
183 | acpi_aml_log_state = ACPI_AML_PROMPT_START; | ||
184 | crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1); | ||
185 | ret += 1; | ||
186 | break; | ||
187 | case ACPI_AML_PROMPT_START: | ||
188 | if (*p == ACPI_DEBUGGER_COMMAND_PROMPT || | ||
189 | *p == ACPI_DEBUGGER_EXECUTE_PROMPT) { | ||
190 | acpi_aml_batch_prompt = *p; | ||
191 | acpi_aml_log_state = ACPI_AML_PROMPT_STOP; | ||
192 | } else { | ||
193 | if (*p != '\n') | ||
194 | acpi_aml_log_state = ACPI_AML_LOG_START; | ||
195 | crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1); | ||
196 | ret += 1; | ||
197 | } | ||
198 | break; | ||
199 | case ACPI_AML_PROMPT_STOP: | ||
200 | if (*p == ' ') { | ||
201 | acpi_aml_log_state = ACPI_AML_LOG_STOP; | ||
202 | acpi_aml_exit = true; | ||
203 | } else { | ||
204 | /* Roll back */ | ||
205 | acpi_aml_log_state = ACPI_AML_PROMPT_ROLL; | ||
206 | acpi_aml_batch_roll = *p; | ||
207 | *p = acpi_aml_batch_prompt; | ||
208 | crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1); | ||
209 | ret += 1; | ||
210 | } | ||
211 | break; | ||
212 | default: | ||
213 | assert(0); | ||
214 | break; | ||
215 | } | ||
216 | } | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | static int acpi_aml_write(int fd, struct circ_buf *crc) | ||
221 | { | ||
222 | char *p; | ||
223 | int len; | ||
224 | |||
225 | p = &crc->buf[crc->tail]; | ||
226 | len = circ_count_to_end(crc); | ||
227 | len = write(fd, p, len); | ||
228 | if (len < 0) | ||
229 | perror("write"); | ||
230 | else if (len > 0) | ||
231 | crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1); | ||
232 | return len; | ||
233 | } | ||
234 | |||
235 | static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc) | ||
236 | { | ||
237 | char *p; | ||
238 | int len; | ||
239 | |||
240 | p = &crc->buf[crc->tail]; | ||
241 | len = circ_count_to_end(crc); | ||
242 | if (!acpi_aml_batch_drain) { | ||
243 | len = write(fd, p, len); | ||
244 | if (len < 0) | ||
245 | perror("write"); | ||
246 | } | ||
247 | if (len > 0) | ||
248 | crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1); | ||
249 | return len; | ||
250 | } | ||
251 | |||
252 | static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc) | ||
253 | { | ||
254 | int len; | ||
255 | |||
256 | len = acpi_aml_write(fd, crc); | ||
257 | if (circ_count_to_end(crc) == 0) | ||
258 | acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG; | ||
259 | return len; | ||
260 | } | ||
261 | |||
262 | static void acpi_aml_loop(int fd) | ||
263 | { | ||
264 | fd_set rfds; | ||
265 | fd_set wfds; | ||
266 | struct timeval tv; | ||
267 | int ret; | ||
268 | int maxfd = 0; | ||
269 | |||
270 | if (acpi_aml_mode == ACPI_AML_BATCH) { | ||
271 | acpi_aml_log_state = ACPI_AML_LOG_START; | ||
272 | acpi_aml_batch_pos = acpi_aml_batch_cmd; | ||
273 | if (acpi_aml_batch_drain) | ||
274 | acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG; | ||
275 | else | ||
276 | acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD; | ||
277 | } | ||
278 | acpi_aml_exit = false; | ||
279 | while (!acpi_aml_exit) { | ||
280 | tv.tv_sec = ACPI_AML_SEC_TICK; | ||
281 | tv.tv_usec = 0; | ||
282 | FD_ZERO(&rfds); | ||
283 | FD_ZERO(&wfds); | ||
284 | |||
285 | if (acpi_aml_cmd_space()) { | ||
286 | if (acpi_aml_mode == ACPI_AML_INTERACTIVE) | ||
287 | maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds); | ||
288 | else if (strlen(acpi_aml_batch_pos) && | ||
289 | acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD) | ||
290 | ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret); | ||
291 | } | ||
292 | if (acpi_aml_cmd_count() && | ||
293 | (acpi_aml_mode == ACPI_AML_INTERACTIVE || | ||
294 | acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)) | ||
295 | maxfd = acpi_aml_set_fd(fd, maxfd, &wfds); | ||
296 | if (acpi_aml_log_space() && | ||
297 | (acpi_aml_mode == ACPI_AML_INTERACTIVE || | ||
298 | acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG)) | ||
299 | maxfd = acpi_aml_set_fd(fd, maxfd, &rfds); | ||
300 | if (acpi_aml_log_count()) | ||
301 | maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds); | ||
302 | |||
303 | ret = select(maxfd+1, &rfds, &wfds, NULL, &tv); | ||
304 | if (ret < 0) { | ||
305 | perror("select"); | ||
306 | break; | ||
307 | } | ||
308 | if (ret > 0) { | ||
309 | if (FD_ISSET(STDIN_FILENO, &rfds)) | ||
310 | ACPI_AML_DO(STDIN_FILENO, read, cmd, ret); | ||
311 | if (FD_ISSET(fd, &wfds)) { | ||
312 | if (acpi_aml_mode == ACPI_AML_BATCH) | ||
313 | ACPI_AML_BATCH_DO(fd, write, cmd, ret); | ||
314 | else | ||
315 | ACPI_AML_DO(fd, write, cmd, ret); | ||
316 | } | ||
317 | if (FD_ISSET(fd, &rfds)) { | ||
318 | if (acpi_aml_mode == ACPI_AML_BATCH) | ||
319 | ACPI_AML_BATCH_DO(fd, read, log, ret); | ||
320 | else | ||
321 | ACPI_AML_DO(fd, read, log, ret); | ||
322 | } | ||
323 | if (FD_ISSET(STDOUT_FILENO, &wfds)) { | ||
324 | if (acpi_aml_mode == ACPI_AML_BATCH) | ||
325 | ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret); | ||
326 | else | ||
327 | ACPI_AML_DO(STDOUT_FILENO, write, log, ret); | ||
328 | } | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | |||
333 | static bool acpi_aml_readable(int fd) | ||
334 | { | ||
335 | fd_set rfds; | ||
336 | struct timeval tv; | ||
337 | int ret; | ||
338 | int maxfd = 0; | ||
339 | |||
340 | tv.tv_sec = 0; | ||
341 | tv.tv_usec = ACPI_AML_USEC_PEEK; | ||
342 | FD_ZERO(&rfds); | ||
343 | maxfd = acpi_aml_set_fd(fd, maxfd, &rfds); | ||
344 | ret = select(maxfd+1, &rfds, NULL, NULL, &tv); | ||
345 | if (ret < 0) | ||
346 | perror("select"); | ||
347 | if (ret > 0 && FD_ISSET(fd, &rfds)) | ||
348 | return true; | ||
349 | return false; | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * This is a userspace IO flush implementation, replying on the prompt | ||
354 | * characters and can be turned into a flush() call after kernel implements | ||
355 | * .flush() filesystem operation. | ||
356 | */ | ||
357 | static void acpi_aml_flush(int fd) | ||
358 | { | ||
359 | while (acpi_aml_readable(fd)) { | ||
360 | acpi_aml_batch_drain = true; | ||
361 | acpi_aml_loop(fd); | ||
362 | acpi_aml_batch_drain = false; | ||
363 | } | ||
364 | } | ||
365 | |||
366 | void usage(FILE *file, char *progname) | ||
367 | { | ||
368 | fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname); | ||
369 | fprintf(file, "\nOptions:\n"); | ||
370 | fprintf(file, " -b Specify command to be executed in batch mode\n"); | ||
371 | fprintf(file, " -f Specify interface file other than"); | ||
372 | fprintf(file, " /sys/kernel/debug/acpi/acpidbg\n"); | ||
373 | fprintf(file, " -h Print this help message\n"); | ||
374 | } | ||
375 | |||
376 | int main(int argc, char **argv) | ||
377 | { | ||
378 | int fd = 0; | ||
379 | int ch; | ||
380 | int len; | ||
381 | int ret = EXIT_SUCCESS; | ||
382 | |||
383 | while ((ch = getopt(argc, argv, "b:f:h")) != -1) { | ||
384 | switch (ch) { | ||
385 | case 'b': | ||
386 | if (acpi_aml_batch_cmd) { | ||
387 | fprintf(stderr, "Already specify %s\n", | ||
388 | acpi_aml_batch_cmd); | ||
389 | ret = EXIT_FAILURE; | ||
390 | goto exit; | ||
391 | } | ||
392 | len = strlen(optarg); | ||
393 | acpi_aml_batch_cmd = calloc(len + 2, 1); | ||
394 | if (!acpi_aml_batch_cmd) { | ||
395 | perror("calloc"); | ||
396 | ret = EXIT_FAILURE; | ||
397 | goto exit; | ||
398 | } | ||
399 | memcpy(acpi_aml_batch_cmd, optarg, len); | ||
400 | acpi_aml_batch_cmd[len] = '\n'; | ||
401 | acpi_aml_mode = ACPI_AML_BATCH; | ||
402 | break; | ||
403 | case 'f': | ||
404 | acpi_aml_file_path = optarg; | ||
405 | break; | ||
406 | case 'h': | ||
407 | usage(stdout, argv[0]); | ||
408 | goto exit; | ||
409 | break; | ||
410 | case '?': | ||
411 | default: | ||
412 | usage(stderr, argv[0]); | ||
413 | ret = EXIT_FAILURE; | ||
414 | goto exit; | ||
415 | break; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK); | ||
420 | if (fd < 0) { | ||
421 | perror("open"); | ||
422 | ret = EXIT_FAILURE; | ||
423 | goto exit; | ||
424 | } | ||
425 | acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK); | ||
426 | acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK); | ||
427 | |||
428 | if (acpi_aml_mode == ACPI_AML_BATCH) | ||
429 | acpi_aml_flush(fd); | ||
430 | acpi_aml_loop(fd); | ||
431 | |||
432 | exit: | ||
433 | if (fd < 0) | ||
434 | close(fd); | ||
435 | if (acpi_aml_batch_cmd) | ||
436 | free(acpi_aml_batch_cmd); | ||
437 | return ret; | ||
438 | } | ||