2 * ACPI AML interfacing userspace utility
4 * Copyright (C) 2015, Intel Corporation
5 * Authors: Lv Zheng <lv.zheng@intel.com>
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.
12 #include <acpi/acpi.h>
14 /* Headers not included by include/acpi/platform/aclinux.h */
18 #include <linux/circ_buf.h>
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
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 */
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
35 #define ACPI_AML_INTERACTIVE 0x00
36 #define ACPI_AML_BATCH 0x01
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))
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)
52 #define ACPI_AML_DO(_fd, _op, _buf, _ret) \
54 _ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc); \
57 "%s %s pipe closed.\n", #_buf, #_op); \
61 #define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret) \
63 _ret = acpi_aml_##_op##_batch_##_buf(_fd, \
64 &acpi_aml_##_buf##_crc); \
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
,
77 static struct circ_buf acpi_aml_log_crc
= {
78 .buf
= acpi_aml_log_buf
,
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
;
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
;
94 static int acpi_aml_set_fl(int fd
, int flags
)
98 ret
= fcntl(fd
, F_GETFL
, 0);
100 perror("fcntl(F_GETFL)");
104 ret
= fcntl(fd
, F_SETFL
, flags
);
106 perror("fcntl(F_SETFL)");
112 static int acpi_aml_set_fd(int fd
, int maxfd
, fd_set
*set
)
120 static int acpi_aml_read(int fd
, struct circ_buf
*crc
)
125 p
= &crc
->buf
[crc
->head
];
126 len
= circ_space_to_end(crc
);
127 len
= read(fd
, p
, len
);
131 crc
->head
= (crc
->head
+ len
) & (ACPI_AML_BUF_SIZE
- 1);
135 static int acpi_aml_read_batch_cmd(int unused
, struct circ_buf
*crc
)
139 int remained
= strlen(acpi_aml_batch_pos
);
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
;
148 memcpy(p
, acpi_aml_batch_pos
, len
);
149 acpi_aml_batch_pos
+= len
;
152 crc
->head
= (crc
->head
+ len
) & (ACPI_AML_BUF_SIZE
- 1);
156 static int acpi_aml_read_batch_log(int fd
, struct circ_buf
*crc
)
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
;
168 crc
->head
= (crc
->head
+ 1) & (ACPI_AML_BUF_SIZE
- 1);
170 acpi_aml_log_state
= ACPI_AML_LOG_START
;
172 len
= read(fd
, p
, 1);
180 switch (acpi_aml_log_state
) {
181 case ACPI_AML_LOG_START
:
183 acpi_aml_log_state
= ACPI_AML_PROMPT_START
;
184 crc
->head
= (crc
->head
+ 1) & (ACPI_AML_BUF_SIZE
- 1);
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
;
194 acpi_aml_log_state
= ACPI_AML_LOG_START
;
195 crc
->head
= (crc
->head
+ 1) & (ACPI_AML_BUF_SIZE
- 1);
199 case ACPI_AML_PROMPT_STOP
:
201 acpi_aml_log_state
= ACPI_AML_LOG_STOP
;
202 acpi_aml_exit
= true;
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);
220 static int acpi_aml_write(int fd
, struct circ_buf
*crc
)
225 p
= &crc
->buf
[crc
->tail
];
226 len
= circ_count_to_end(crc
);
227 len
= write(fd
, p
, len
);
231 crc
->tail
= (crc
->tail
+ len
) & (ACPI_AML_BUF_SIZE
- 1);
235 static int acpi_aml_write_batch_log(int fd
, struct circ_buf
*crc
)
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
);
248 crc
->tail
= (crc
->tail
+ len
) & (ACPI_AML_BUF_SIZE
- 1);
252 static int acpi_aml_write_batch_cmd(int fd
, struct circ_buf
*crc
)
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
;
262 static void acpi_aml_loop(int fd
)
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
;
276 acpi_aml_batch_state
= ACPI_AML_BATCH_WRITE_CMD
;
278 acpi_aml_exit
= false;
279 while (!acpi_aml_exit
) {
280 tv
.tv_sec
= ACPI_AML_SEC_TICK
;
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
);
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
);
303 ret
= select(maxfd
+1, &rfds
, &wfds
, NULL
, &tv
);
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
);
315 ACPI_AML_DO(fd
, write
, cmd
, ret
);
317 if (FD_ISSET(fd
, &rfds
)) {
318 if (acpi_aml_mode
== ACPI_AML_BATCH
)
319 ACPI_AML_BATCH_DO(fd
, read
, log
, ret
);
321 ACPI_AML_DO(fd
, read
, log
, ret
);
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
);
327 ACPI_AML_DO(STDOUT_FILENO
, write
, log
, ret
);
333 static bool acpi_aml_readable(int fd
)
341 tv
.tv_usec
= ACPI_AML_USEC_PEEK
;
343 maxfd
= acpi_aml_set_fd(fd
, maxfd
, &rfds
);
344 ret
= select(maxfd
+1, &rfds
, NULL
, NULL
, &tv
);
347 if (ret
> 0 && FD_ISSET(fd
, &rfds
))
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.
357 static void acpi_aml_flush(int fd
)
359 while (acpi_aml_readable(fd
)) {
360 acpi_aml_batch_drain
= true;
362 acpi_aml_batch_drain
= false;
366 void usage(FILE *file
, char *progname
)
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");
376 int main(int argc
, char **argv
)
381 int ret
= EXIT_SUCCESS
;
383 while ((ch
= getopt(argc
, argv
, "b:f:h")) != -1) {
386 if (acpi_aml_batch_cmd
) {
387 fprintf(stderr
, "Already specify %s\n",
392 len
= strlen(optarg
);
393 acpi_aml_batch_cmd
= calloc(len
+ 2, 1);
394 if (!acpi_aml_batch_cmd
) {
399 memcpy(acpi_aml_batch_cmd
, optarg
, len
);
400 acpi_aml_batch_cmd
[len
] = '\n';
401 acpi_aml_mode
= ACPI_AML_BATCH
;
404 acpi_aml_file_path
= optarg
;
407 usage(stdout
, argv
[0]);
412 usage(stderr
, argv
[0]);
419 fd
= open(acpi_aml_file_path
, O_RDWR
| O_NONBLOCK
);
425 acpi_aml_set_fl(STDIN_FILENO
, O_NONBLOCK
);
426 acpi_aml_set_fl(STDOUT_FILENO
, O_NONBLOCK
);
428 if (acpi_aml_mode
== ACPI_AML_BATCH
)
435 if (acpi_aml_batch_cmd
)
436 free(acpi_aml_batch_cmd
);