summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-12-31 21:26:26 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-12-31 21:26:26 -0500
commitb17629dbf72d0718e88190d7f0a1d54be044799c (patch)
tree90e1908b4c7eab87989b17341cdaa8d074e355b2
parent74bf8efb5fa6e958d2d7c7917b8bb672085ec0c6 (diff)
parent59adb3988ebeec012343317ac783d6a7935e0c83 (diff)
Merge branch 'acpi-debug' into acpica
-rw-r--r--drivers/acpi/Kconfig17
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/acpi_dbg.c804
-rw-r--r--drivers/acpi/acpica/acdebug.h36
-rw-r--r--drivers/acpi/acpica/acglobal.h5
-rw-r--r--drivers/acpi/acpica/acmacros.h11
-rw-r--r--drivers/acpi/acpica/dbdisply.c12
-rw-r--r--drivers/acpi/acpica/dbinput.c100
-rw-r--r--drivers/acpi/acpica/dbxface.c93
-rw-r--r--drivers/acpi/acpica/dscontrol.c10
-rw-r--r--drivers/acpi/acpica/dsutils.c16
-rw-r--r--drivers/acpi/acpica/dswexec.c16
-rw-r--r--drivers/acpi/acpica/utmutex.c17
-rw-r--r--drivers/acpi/bus.c1
-rw-r--r--drivers/acpi/osl.c250
-rw-r--r--include/acpi/acpiosxf.h18
-rw-r--r--include/acpi/acpixf.h34
-rw-r--r--include/acpi/platform/aclinux.h2
-rw-r--r--include/acpi/platform/aclinuxex.h9
-rw-r--r--include/linux/acpi.h71
-rw-r--r--tools/power/acpi/Makefile16
-rw-r--r--tools/power/acpi/tools/acpidbg/Makefile27
-rw-r--r--tools/power/acpi/tools/acpidbg/acpidbg.c438
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
60config ACPI_DEBUGGER 60config 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
69if ACPI_DEBUGGER
70
71config 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
78endif
79
69config ACPI_SLEEP 80config 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
79obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o 79obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
80obj-$(CONFIG_ACPI_BGRT) += bgrt.o 80obj-$(CONFIG_ACPI_BGRT) += bgrt.o
81obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o 81obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o
82obj-$(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
84processor-y := processor_driver.o 85processor-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
50struct 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
65static struct acpi_aml_io acpi_aml_io;
66static bool acpi_aml_initialized;
67static struct file *acpi_aml_active_reader;
68static struct dentry *acpi_aml_dentry;
69
70static inline bool __acpi_aml_running(void)
71{
72 return acpi_aml_io.thread ? true : false;
73}
74
75static 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
94static 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
105static 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
116static inline bool __acpi_aml_busy(void)
117{
118 if (acpi_aml_io.flags & ACPI_AML_BUSY)
119 return true;
120 return false;
121}
122
123static inline bool __acpi_aml_opened(void)
124{
125 if (acpi_aml_io.flags & ACPI_AML_OPEN)
126 return true;
127 return false;
128}
129
130static inline bool __acpi_aml_used(void)
131{
132 return acpi_aml_io.usages ? true : false;
133}
134
135static 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
145static 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
155static 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
169static 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
180static 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
191static 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
202static 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
213static 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;
227out:
228 mutex_unlock(&acpi_aml_io.lock);
229 return ret;
230}
231
232static 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;
246out:
247 mutex_unlock(&acpi_aml_io.lock);
248 return ret;
249}
250
251static 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
260static 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
282static 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 */
310static 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) {
320again:
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 */
350static 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) {
361again:
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
393static 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 */
428static 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
451static 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
467static int acpi_aml_notify_command_complete(void)
468{
469 return 0;
470}
471
472static 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++;
528err_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);
534err_exit:
535 return ret;
536}
537
538static 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
582static 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;
604out:
605 acpi_aml_unlock_fifo(ACPI_AML_OUT_USER, !IS_ERR_VALUE(ret));
606 return ret;
607}
608
609static 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) {
621again:
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
652static 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;
674out:
675 acpi_aml_unlock_fifo(ACPI_AML_IN_USER, !IS_ERR_VALUE(ret));
676 return n;
677}
678
679static 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) {
691again:
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
721static 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
734static 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
743static 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
751int __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
778err_fs:
779 if (ret) {
780 debugfs_remove(acpi_aml_dentry);
781 acpi_aml_dentry = NULL;
782 }
783err_exit:
784 return ret;
785}
786
787void __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
799module_init(acpi_aml_init);
800module_exit(acpi_aml_exit);
801
802MODULE_AUTHOR("Lv Zheng");
803MODULE_DESCRIPTION("ACPI debugger userspace IO driver");
804MODULE_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 */
83acpi_status 83ACPI_DBR_DEPENDENT_RETURN_OK(acpi_status
84acpi_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
183void acpi_db_decode_and_display_object(char *target, char *output_type); 189void acpi_db_decode_and_display_object(char *target, char *output_type);
184 190
185void 191ACPI_DBR_DEPENDENT_RETURN_VOID(void
186acpi_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
189acpi_status acpi_db_display_all_methods(char *display_count_arg); 199 acpi_status acpi_db_display_all_methods(char *display_count_arg);
190 200
191void acpi_db_display_arguments(void); 201void acpi_db_display_arguments(void);
192 202
@@ -198,9 +208,13 @@ void acpi_db_display_calling_tree(void);
198 208
199void acpi_db_display_object_type(char *object_arg); 209void acpi_db_display_object_type(char *object_arg);
200 210
201void 211ACPI_DBR_DEPENDENT_RETURN_VOID(void
202acpi_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
258void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context); 272void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context);
259 273
260acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op); 274acpi_status acpi_db_user_commands(void);
261 275
262char *acpi_db_get_next_token(char *string, 276char *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
328ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE); 328ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE);
329ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE);
330ACPI_INIT_GLOBAL(acpi_thread_id, acpi_gbl_db_thread_id, ACPI_INVALID_THREAD_ID); 329ACPI_INIT_GLOBAL(acpi_thread_id, acpi_gbl_db_thread_id, ACPI_INVALID_THREAD_ID);
331 330
332ACPI_GLOBAL(u8, acpi_gbl_db_opt_no_ini_methods); 331ACPI_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
348ACPI_GLOBAL(char, acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]);
349ACPI_GLOBAL(char, acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE]); 347ACPI_GLOBAL(char, acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE]);
350ACPI_GLOBAL(char, acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE]); 348ACPI_GLOBAL(char, acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE]);
351ACPI_GLOBAL(char, acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE]); 349ACPI_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);
360ACPI_GLOBAL(u32, acpi_gbl_num_nodes); 358ACPI_GLOBAL(u32, acpi_gbl_num_nodes);
361ACPI_GLOBAL(u32, acpi_gbl_num_objects); 359ACPI_GLOBAL(u32, acpi_gbl_num_objects);
362 360
363ACPI_GLOBAL(acpi_mutex, acpi_gbl_db_command_ready);
364ACPI_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
54static u32 acpi_db_match_command(char *user_command); 54static u32 acpi_db_match_command(char *user_command);
55 55
56static void acpi_db_single_thread(void);
57
58static void acpi_db_display_command_info(char *command, u8 display_all); 56static void acpi_db_display_command_info(char *command, u8 display_all);
59 57
60static void acpi_db_display_help(char *command); 58static void acpi_db_display_help(char *command);
@@ -1149,55 +1147,16 @@ acpi_db_command_dispatch(char *input_buffer,
1149 1147
1150void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context) 1148void 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
1186static 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
1209acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op) 1168acpi_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
112error_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
132void 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
52ACPI_MODULE_NAME("dscontrol") 53ACPI_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}
223EXPORT_SYMBOL(acpi_os_printf);
223 224
224void acpi_os_vprintf(const char *fmt, va_list args) 225void 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
1107static struct acpi_debugger acpi_debugger;
1108static bool acpi_debugger_initialized;
1109
1110int 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
1124err_lock:
1125 mutex_unlock(&acpi_debugger.lock);
1126 return ret;
1127}
1128EXPORT_SYMBOL(acpi_register_debugger);
1129
1130void 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}
1139EXPORT_SYMBOL(acpi_unregister_debugger);
1140
1141int 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);
1166err_lock:
1167 mutex_unlock(&acpi_debugger.lock);
1168 return ret;
1169}
1170
1171ssize_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);
1196err_lock:
1197 mutex_unlock(&acpi_debugger.lock);
1198 return ret;
1199}
1200
1201ssize_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);
1226err_lock:
1227 mutex_unlock(&acpi_debugger.lock);
1228 return ret;
1229}
1230
1231int 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);
1257err_lock:
1258 mutex_unlock(&acpi_debugger.lock);
1259 return ret;
1260}
1261
1262int 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);
1287err_lock:
1288 mutex_unlock(&acpi_debugger.lock);
1289 return ret;
1290}
1291
1292int __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 }
1383err_workqueue:
1384 if (ACPI_FAILURE(status))
1385 kfree(dpc);
1386out_thread:
1174 return status; 1387 return status;
1175} 1388}
1176EXPORT_SYMBOL(acpi_os_execute); 1389EXPORT_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}
1586EXPORT_SYMBOL(acpi_os_get_line);
1587
1588acpi_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
1598acpi_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
1366acpi_status acpi_os_signal(u32 function, void *info) 1608acpi_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
355acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read); 355acpi_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
359acpi_status acpi_os_initialize_command_signals(void);
360#endif
361
362#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals
363void acpi_os_terminate_command_signals(void);
364#endif
365
366#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
367acpi_status acpi_os_wait_command_ready(void);
368#endif
369
370#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete
371acpi_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);
264ACPI_INIT_GLOBAL(u32, acpi_dbg_layer, 0); 264ACPI_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
271ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE);
272ACPI_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 */
269ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT); 278ACPI_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
964void acpi_run_debugger(char *batch_buffer);
965
932void acpi_set_debugger_thread_id(acpi_thread_id thread_id); 966void 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
132static inline acpi_status acpi_os_initialize_command_signals(void)
133{
134 return AE_OK;
135}
136
137static 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);
119typedef int (*acpi_tbl_entry_handler)(struct acpi_subtable_header *header, 121typedef 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
126struct 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
134struct acpi_debugger {
135 const struct acpi_debugger_ops *ops;
136 struct module *owner;
137 struct mutex lock;
138};
139
140#ifdef CONFIG_ACPI_DEBUGGER
141int __init acpi_debugger_init(void);
142int acpi_register_debugger(struct module *owner,
143 const struct acpi_debugger_ops *ops);
144void acpi_unregister_debugger(const struct acpi_debugger_ops *ops);
145int acpi_debugger_create_thread(acpi_osd_exec_callback function, void *context);
146ssize_t acpi_debugger_write_log(const char *msg);
147ssize_t acpi_debugger_read_cmd(char *buffer, size_t buffer_length);
148int acpi_debugger_wait_command_ready(void);
149int acpi_debugger_notify_command_complete(void);
150#else
151static inline int acpi_debugger_init(void)
152{
153 return -ENODEV;
154}
155
156static inline int acpi_register_debugger(struct module *owner,
157 const struct acpi_debugger_ops *ops)
158{
159 return -ENODEV;
160}
161
162static inline void acpi_unregister_debugger(const struct acpi_debugger_ops *ops)
163{
164}
165
166static inline int acpi_debugger_create_thread(acpi_osd_exec_callback function,
167 void *context)
168{
169 return -ENODEV;
170}
171
172static inline int acpi_debugger_write_log(const char *msg)
173{
174 return -ENODEV;
175}
176
177static inline int acpi_debugger_read_cmd(char *buffer, u32 buffer_length)
178{
179 return -ENODEV;
180}
181
182static inline int acpi_debugger_wait_command_ready(void)
183{
184 return -ENODEV;
185}
186
187static 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
123void acpi_initrd_override(void *data, size_t size); 194void 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
11include ../../scripts/Makefile.include 11include ../../scripts/Makefile.include
12 12
13all: acpidump ec 13all: acpidbg acpidump ec
14clean: acpidump_clean ec_clean 14clean: acpidbg_clean acpidump_clean ec_clean
15install: acpidump_install ec_install 15install: acpidbg_install acpidump_install ec_install
16uninstall: acpidump_uninstall ec_uninstall 16uninstall: acpidbg_uninstall acpidump_uninstall ec_uninstall
17 17
18acpidump ec: FORCE 18acpidbg acpidump ec: FORCE
19 $(call descend,tools/$@,all) 19 $(call descend,tools/$@,all)
20acpidump_clean ec_clean: 20acpidbg_clean acpidump_clean ec_clean:
21 $(call descend,tools/$(@:_clean=),clean) 21 $(call descend,tools/$(@:_clean=),clean)
22acpidump_install ec_install: 22acpidbg_install acpidump_install ec_install:
23 $(call descend,tools/$(@:_install=),install) 23 $(call descend,tools/$(@:_install=),install)
24acpidump_uninstall ec_uninstall: 24acpidbg_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
11include ../../Makefile.config
12
13TOOL = acpidbg
14vpath %.c \
15 ../../../../../drivers/acpi/acpica\
16 ../../common\
17 ../../os_specific/service_layers\
18 .
19CFLAGS += -DACPI_APPLICATION -DACPI_SINGLE_THREAD -DACPI_DEBUGGER\
20 -I.\
21 -I../../../../../drivers/acpi/acpica\
22 -I../../../../../include
23LDFLAGS += -lpthread
24TOOL_OBJS = \
25 acpidbg.o
26
27include ../../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
70static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
71static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
72static struct circ_buf acpi_aml_cmd_crc = {
73 .buf = acpi_aml_cmd_buf,
74 .head = 0,
75 .tail = 0,
76};
77static struct circ_buf acpi_aml_log_crc = {
78 .buf = acpi_aml_log_buf,
79 .head = 0,
80 .tail = 0,
81};
82static const char *acpi_aml_file_path = ACPI_AML_FILE;
83static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
84static bool acpi_aml_exit;
85
86static bool acpi_aml_batch_drain;
87static unsigned long acpi_aml_batch_state;
88static char acpi_aml_batch_prompt;
89static char acpi_aml_batch_roll;
90static unsigned long acpi_aml_log_state;
91static char *acpi_aml_batch_cmd = NULL;
92static char *acpi_aml_batch_pos = NULL;
93
94static 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
112static 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
120static 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
135static 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
156static 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
220static 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
235static 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
252static 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
262static 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
333static 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 */
357static 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
366void 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
376int 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
432exit:
433 if (fd < 0)
434 close(fd);
435 if (acpi_aml_batch_cmd)
436 free(acpi_aml_batch_cmd);
437 return ret;
438}