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 */
23 #include <sys/select.h>
24 #include "../../../../../include/linux/circ_buf.h"
26 #define ACPI_AML_FILE "/sys/kernel/debug/acpi/acpidbg"
27 #define ACPI_AML_SEC_TICK 1
28 #define ACPI_AML_USEC_PEEK 200
29 #define ACPI_AML_BUF_SIZE 4096
31 #define ACPI_AML_BATCH_WRITE_CMD 0x00 /* Write command to kernel */
32 #define ACPI_AML_BATCH_READ_LOG 0x01 /* Read log from kernel */
33 #define ACPI_AML_BATCH_WRITE_LOG 0x02 /* Write log to console */
35 #define ACPI_AML_LOG_START 0x00
36 #define ACPI_AML_PROMPT_START 0x01
37 #define ACPI_AML_PROMPT_STOP 0x02
38 #define ACPI_AML_LOG_STOP 0x03
39 #define ACPI_AML_PROMPT_ROLL 0x04
41 #define ACPI_AML_INTERACTIVE 0x00
42 #define ACPI_AML_BATCH 0x01
44 #define circ_count(circ) \
45 (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
46 #define circ_count_to_end(circ) \
47 (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
48 #define circ_space(circ) \
49 (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
50 #define circ_space_to_end(circ) \
51 (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
53 #define acpi_aml_cmd_count() circ_count(&acpi_aml_cmd_crc)
54 #define acpi_aml_log_count() circ_count(&acpi_aml_log_crc)
55 #define acpi_aml_cmd_space() circ_space(&acpi_aml_cmd_crc)
56 #define acpi_aml_log_space() circ_space(&acpi_aml_log_crc)
58 #define ACPI_AML_DO(_fd, _op, _buf, _ret) \
60 _ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc); \
63 "%s %s pipe closed.\n", #_buf, #_op); \
67 #define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret) \
69 _ret = acpi_aml_##_op##_batch_##_buf(_fd, \
70 &acpi_aml_##_buf##_crc); \
76 static char acpi_aml_cmd_buf
[ACPI_AML_BUF_SIZE
];
77 static char acpi_aml_log_buf
[ACPI_AML_BUF_SIZE
];
78 static struct circ_buf acpi_aml_cmd_crc
= {
79 .buf
= acpi_aml_cmd_buf
,
83 static struct circ_buf acpi_aml_log_crc
= {
84 .buf
= acpi_aml_log_buf
,
88 static const char *acpi_aml_file_path
= ACPI_AML_FILE
;
89 static unsigned long acpi_aml_mode
= ACPI_AML_INTERACTIVE
;
90 static bool acpi_aml_exit
;
92 static bool acpi_aml_batch_drain
;
93 static unsigned long acpi_aml_batch_state
;
94 static char acpi_aml_batch_prompt
;
95 static char acpi_aml_batch_roll
;
96 static unsigned long acpi_aml_log_state
;
97 static char *acpi_aml_batch_cmd
= NULL
;
98 static char *acpi_aml_batch_pos
= NULL
;
100 static int acpi_aml_set_fl(int fd
, int flags
)
104 ret
= fcntl(fd
, F_GETFL
, 0);
106 perror("fcntl(F_GETFL)");
110 ret
= fcntl(fd
, F_SETFL
, flags
);
112 perror("fcntl(F_SETFL)");
118 static int acpi_aml_set_fd(int fd
, int maxfd
, fd_set
*set
)
126 static int acpi_aml_read(int fd
, struct circ_buf
*crc
)
131 p
= &crc
->buf
[crc
->head
];
132 len
= circ_space_to_end(crc
);
133 len
= read(fd
, p
, len
);
137 crc
->head
= (crc
->head
+ len
) & (ACPI_AML_BUF_SIZE
- 1);
141 static int acpi_aml_read_batch_cmd(int unused
, struct circ_buf
*crc
)
145 int remained
= strlen(acpi_aml_batch_pos
);
147 p
= &crc
->buf
[crc
->head
];
148 len
= circ_space_to_end(crc
);
149 if (len
> remained
) {
150 memcpy(p
, acpi_aml_batch_pos
, remained
);
151 acpi_aml_batch_pos
+= remained
;
154 memcpy(p
, acpi_aml_batch_pos
, len
);
155 acpi_aml_batch_pos
+= len
;
158 crc
->head
= (crc
->head
+ len
) & (ACPI_AML_BUF_SIZE
- 1);
162 static int acpi_aml_read_batch_log(int fd
, struct circ_buf
*crc
)
168 p
= &crc
->buf
[crc
->head
];
169 len
= circ_space_to_end(crc
);
170 while (ret
< len
&& acpi_aml_log_state
!= ACPI_AML_LOG_STOP
) {
171 if (acpi_aml_log_state
== ACPI_AML_PROMPT_ROLL
) {
172 *p
= acpi_aml_batch_roll
;
174 crc
->head
= (crc
->head
+ 1) & (ACPI_AML_BUF_SIZE
- 1);
176 acpi_aml_log_state
= ACPI_AML_LOG_START
;
178 len
= read(fd
, p
, 1);
186 switch (acpi_aml_log_state
) {
187 case ACPI_AML_LOG_START
:
189 acpi_aml_log_state
= ACPI_AML_PROMPT_START
;
190 crc
->head
= (crc
->head
+ 1) & (ACPI_AML_BUF_SIZE
- 1);
193 case ACPI_AML_PROMPT_START
:
194 if (*p
== ACPI_DEBUGGER_COMMAND_PROMPT
||
195 *p
== ACPI_DEBUGGER_EXECUTE_PROMPT
) {
196 acpi_aml_batch_prompt
= *p
;
197 acpi_aml_log_state
= ACPI_AML_PROMPT_STOP
;
200 acpi_aml_log_state
= ACPI_AML_LOG_START
;
201 crc
->head
= (crc
->head
+ 1) & (ACPI_AML_BUF_SIZE
- 1);
205 case ACPI_AML_PROMPT_STOP
:
207 acpi_aml_log_state
= ACPI_AML_LOG_STOP
;
208 acpi_aml_exit
= true;
211 acpi_aml_log_state
= ACPI_AML_PROMPT_ROLL
;
212 acpi_aml_batch_roll
= *p
;
213 *p
= acpi_aml_batch_prompt
;
214 crc
->head
= (crc
->head
+ 1) & (ACPI_AML_BUF_SIZE
- 1);
226 static int acpi_aml_write(int fd
, struct circ_buf
*crc
)
231 p
= &crc
->buf
[crc
->tail
];
232 len
= circ_count_to_end(crc
);
233 len
= write(fd
, p
, len
);
237 crc
->tail
= (crc
->tail
+ len
) & (ACPI_AML_BUF_SIZE
- 1);
241 static int acpi_aml_write_batch_log(int fd
, struct circ_buf
*crc
)
246 p
= &crc
->buf
[crc
->tail
];
247 len
= circ_count_to_end(crc
);
248 if (!acpi_aml_batch_drain
) {
249 len
= write(fd
, p
, len
);
254 crc
->tail
= (crc
->tail
+ len
) & (ACPI_AML_BUF_SIZE
- 1);
258 static int acpi_aml_write_batch_cmd(int fd
, struct circ_buf
*crc
)
262 len
= acpi_aml_write(fd
, crc
);
263 if (circ_count_to_end(crc
) == 0)
264 acpi_aml_batch_state
= ACPI_AML_BATCH_READ_LOG
;
268 static void acpi_aml_loop(int fd
)
276 if (acpi_aml_mode
== ACPI_AML_BATCH
) {
277 acpi_aml_log_state
= ACPI_AML_LOG_START
;
278 acpi_aml_batch_pos
= acpi_aml_batch_cmd
;
279 if (acpi_aml_batch_drain
)
280 acpi_aml_batch_state
= ACPI_AML_BATCH_READ_LOG
;
282 acpi_aml_batch_state
= ACPI_AML_BATCH_WRITE_CMD
;
284 acpi_aml_exit
= false;
285 while (!acpi_aml_exit
) {
286 tv
.tv_sec
= ACPI_AML_SEC_TICK
;
291 if (acpi_aml_cmd_space()) {
292 if (acpi_aml_mode
== ACPI_AML_INTERACTIVE
)
293 maxfd
= acpi_aml_set_fd(STDIN_FILENO
, maxfd
, &rfds
);
294 else if (strlen(acpi_aml_batch_pos
) &&
295 acpi_aml_batch_state
== ACPI_AML_BATCH_WRITE_CMD
)
296 ACPI_AML_BATCH_DO(STDIN_FILENO
, read
, cmd
, ret
);
298 if (acpi_aml_cmd_count() &&
299 (acpi_aml_mode
== ACPI_AML_INTERACTIVE
||
300 acpi_aml_batch_state
== ACPI_AML_BATCH_WRITE_CMD
))
301 maxfd
= acpi_aml_set_fd(fd
, maxfd
, &wfds
);
302 if (acpi_aml_log_space() &&
303 (acpi_aml_mode
== ACPI_AML_INTERACTIVE
||
304 acpi_aml_batch_state
== ACPI_AML_BATCH_READ_LOG
))
305 maxfd
= acpi_aml_set_fd(fd
, maxfd
, &rfds
);
306 if (acpi_aml_log_count())
307 maxfd
= acpi_aml_set_fd(STDOUT_FILENO
, maxfd
, &wfds
);
309 ret
= select(maxfd
+1, &rfds
, &wfds
, NULL
, &tv
);
315 if (FD_ISSET(STDIN_FILENO
, &rfds
))
316 ACPI_AML_DO(STDIN_FILENO
, read
, cmd
, ret
);
317 if (FD_ISSET(fd
, &wfds
)) {
318 if (acpi_aml_mode
== ACPI_AML_BATCH
)
319 ACPI_AML_BATCH_DO(fd
, write
, cmd
, ret
);
321 ACPI_AML_DO(fd
, write
, cmd
, ret
);
323 if (FD_ISSET(fd
, &rfds
)) {
324 if (acpi_aml_mode
== ACPI_AML_BATCH
)
325 ACPI_AML_BATCH_DO(fd
, read
, log
, ret
);
327 ACPI_AML_DO(fd
, read
, log
, ret
);
329 if (FD_ISSET(STDOUT_FILENO
, &wfds
)) {
330 if (acpi_aml_mode
== ACPI_AML_BATCH
)
331 ACPI_AML_BATCH_DO(STDOUT_FILENO
, write
, log
, ret
);
333 ACPI_AML_DO(STDOUT_FILENO
, write
, log
, ret
);
339 static bool acpi_aml_readable(int fd
)
347 tv
.tv_usec
= ACPI_AML_USEC_PEEK
;
349 maxfd
= acpi_aml_set_fd(fd
, maxfd
, &rfds
);
350 ret
= select(maxfd
+1, &rfds
, NULL
, NULL
, &tv
);
353 if (ret
> 0 && FD_ISSET(fd
, &rfds
))
359 * This is a userspace IO flush implementation, replying on the prompt
360 * characters and can be turned into a flush() call after kernel implements
361 * .flush() filesystem operation.
363 static void acpi_aml_flush(int fd
)
365 while (acpi_aml_readable(fd
)) {
366 acpi_aml_batch_drain
= true;
368 acpi_aml_batch_drain
= false;
372 void usage(FILE *file
, char *progname
)
374 fprintf(file
, "usage: %s [-b cmd] [-f file] [-h]\n", progname
);
375 fprintf(file
, "\nOptions:\n");
376 fprintf(file
, " -b Specify command to be executed in batch mode\n");
377 fprintf(file
, " -f Specify interface file other than");
378 fprintf(file
, " /sys/kernel/debug/acpi/acpidbg\n");
379 fprintf(file
, " -h Print this help message\n");
382 int main(int argc
, char **argv
)
387 int ret
= EXIT_SUCCESS
;
389 while ((ch
= getopt(argc
, argv
, "b:f:h")) != -1) {
392 if (acpi_aml_batch_cmd
) {
393 fprintf(stderr
, "Already specify %s\n",
398 len
= strlen(optarg
);
399 acpi_aml_batch_cmd
= calloc(len
+ 2, 1);
400 if (!acpi_aml_batch_cmd
) {
405 memcpy(acpi_aml_batch_cmd
, optarg
, len
);
406 acpi_aml_batch_cmd
[len
] = '\n';
407 acpi_aml_mode
= ACPI_AML_BATCH
;
410 acpi_aml_file_path
= optarg
;
413 usage(stdout
, argv
[0]);
418 usage(stderr
, argv
[0]);
425 fd
= open(acpi_aml_file_path
, O_RDWR
| O_NONBLOCK
);
431 acpi_aml_set_fl(STDIN_FILENO
, O_NONBLOCK
);
432 acpi_aml_set_fl(STDOUT_FILENO
, O_NONBLOCK
);
434 if (acpi_aml_mode
== ACPI_AML_BATCH
)
441 if (acpi_aml_batch_cmd
)
442 free(acpi_aml_batch_cmd
);