]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - tools/power/acpi/tools/acpidbg/acpidbg.c
crypto: qat - change the adf_ctl_stop_devices to void
[mirror_ubuntu-artful-kernel.git] / tools / power / acpi / tools / acpidbg / acpidbg.c
1 /*
2 * ACPI AML interfacing userspace utility
3 *
4 * Copyright (C) 2015, Intel Corporation
5 * Authors: Lv Zheng <lv.zheng@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12 #include <acpi/acpi.h>
13
14 /* Headers not included by include/acpi/platform/aclinux.h */
15 #include <stdbool.h>
16 #include <fcntl.h>
17 #include <assert.h>
18 #include <linux/circ_buf.h>
19
20 #define ACPI_AML_FILE "/sys/kernel/debug/acpi/acpidbg"
21 #define ACPI_AML_SEC_TICK 1
22 #define ACPI_AML_USEC_PEEK 200
23 #define ACPI_AML_BUF_SIZE 4096
24
25 #define ACPI_AML_BATCH_WRITE_CMD 0x00 /* Write command to kernel */
26 #define ACPI_AML_BATCH_READ_LOG 0x01 /* Read log from kernel */
27 #define ACPI_AML_BATCH_WRITE_LOG 0x02 /* Write log to console */
28
29 #define ACPI_AML_LOG_START 0x00
30 #define ACPI_AML_PROMPT_START 0x01
31 #define ACPI_AML_PROMPT_STOP 0x02
32 #define ACPI_AML_LOG_STOP 0x03
33 #define ACPI_AML_PROMPT_ROLL 0x04
34
35 #define ACPI_AML_INTERACTIVE 0x00
36 #define ACPI_AML_BATCH 0x01
37
38 #define circ_count(circ) \
39 (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
40 #define circ_count_to_end(circ) \
41 (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
42 #define circ_space(circ) \
43 (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
44 #define circ_space_to_end(circ) \
45 (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
46
47 #define acpi_aml_cmd_count() circ_count(&acpi_aml_cmd_crc)
48 #define acpi_aml_log_count() circ_count(&acpi_aml_log_crc)
49 #define acpi_aml_cmd_space() circ_space(&acpi_aml_cmd_crc)
50 #define acpi_aml_log_space() circ_space(&acpi_aml_log_crc)
51
52 #define ACPI_AML_DO(_fd, _op, _buf, _ret) \
53 do { \
54 _ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc); \
55 if (_ret == 0) { \
56 fprintf(stderr, \
57 "%s %s pipe closed.\n", #_buf, #_op); \
58 return; \
59 } \
60 } while (0)
61 #define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret) \
62 do { \
63 _ret = acpi_aml_##_op##_batch_##_buf(_fd, \
64 &acpi_aml_##_buf##_crc); \
65 if (_ret == 0) \
66 return; \
67 } while (0)
68
69
70 static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
71 static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
72 static struct circ_buf acpi_aml_cmd_crc = {
73 .buf = acpi_aml_cmd_buf,
74 .head = 0,
75 .tail = 0,
76 };
77 static struct circ_buf acpi_aml_log_crc = {
78 .buf = acpi_aml_log_buf,
79 .head = 0,
80 .tail = 0,
81 };
82 static const char *acpi_aml_file_path = ACPI_AML_FILE;
83 static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
84 static bool acpi_aml_exit;
85
86 static bool acpi_aml_batch_drain;
87 static unsigned long acpi_aml_batch_state;
88 static char acpi_aml_batch_prompt;
89 static char acpi_aml_batch_roll;
90 static unsigned long acpi_aml_log_state;
91 static char *acpi_aml_batch_cmd = NULL;
92 static char *acpi_aml_batch_pos = NULL;
93
94 static int acpi_aml_set_fl(int fd, int flags)
95 {
96 int ret;
97
98 ret = fcntl(fd, F_GETFL, 0);
99 if (ret < 0) {
100 perror("fcntl(F_GETFL)");
101 return ret;
102 }
103 flags |= ret;
104 ret = fcntl(fd, F_SETFL, flags);
105 if (ret < 0) {
106 perror("fcntl(F_SETFL)");
107 return ret;
108 }
109 return ret;
110 }
111
112 static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set)
113 {
114 if (fd > maxfd)
115 maxfd = fd;
116 FD_SET(fd, set);
117 return maxfd;
118 }
119
120 static int acpi_aml_read(int fd, struct circ_buf *crc)
121 {
122 char *p;
123 int len;
124
125 p = &crc->buf[crc->head];
126 len = circ_space_to_end(crc);
127 len = read(fd, p, len);
128 if (len < 0)
129 perror("read");
130 else if (len > 0)
131 crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
132 return len;
133 }
134
135 static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc)
136 {
137 char *p;
138 int len;
139 int remained = strlen(acpi_aml_batch_pos);
140
141 p = &crc->buf[crc->head];
142 len = circ_space_to_end(crc);
143 if (len > remained) {
144 memcpy(p, acpi_aml_batch_pos, remained);
145 acpi_aml_batch_pos += remained;
146 len = remained;
147 } else {
148 memcpy(p, acpi_aml_batch_pos, len);
149 acpi_aml_batch_pos += len;
150 }
151 if (len > 0)
152 crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
153 return len;
154 }
155
156 static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc)
157 {
158 char *p;
159 int len;
160 int ret = 0;
161
162 p = &crc->buf[crc->head];
163 len = circ_space_to_end(crc);
164 while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) {
165 if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) {
166 *p = acpi_aml_batch_roll;
167 len = 1;
168 crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
169 ret += 1;
170 acpi_aml_log_state = ACPI_AML_LOG_START;
171 } else {
172 len = read(fd, p, 1);
173 if (len <= 0) {
174 if (len < 0)
175 perror("read");
176 ret = len;
177 break;
178 }
179 }
180 switch (acpi_aml_log_state) {
181 case ACPI_AML_LOG_START:
182 if (*p == '\n')
183 acpi_aml_log_state = ACPI_AML_PROMPT_START;
184 crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
185 ret += 1;
186 break;
187 case ACPI_AML_PROMPT_START:
188 if (*p == ACPI_DEBUGGER_COMMAND_PROMPT ||
189 *p == ACPI_DEBUGGER_EXECUTE_PROMPT) {
190 acpi_aml_batch_prompt = *p;
191 acpi_aml_log_state = ACPI_AML_PROMPT_STOP;
192 } else {
193 if (*p != '\n')
194 acpi_aml_log_state = ACPI_AML_LOG_START;
195 crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
196 ret += 1;
197 }
198 break;
199 case ACPI_AML_PROMPT_STOP:
200 if (*p == ' ') {
201 acpi_aml_log_state = ACPI_AML_LOG_STOP;
202 acpi_aml_exit = true;
203 } else {
204 /* Roll back */
205 acpi_aml_log_state = ACPI_AML_PROMPT_ROLL;
206 acpi_aml_batch_roll = *p;
207 *p = acpi_aml_batch_prompt;
208 crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
209 ret += 1;
210 }
211 break;
212 default:
213 assert(0);
214 break;
215 }
216 }
217 return ret;
218 }
219
220 static int acpi_aml_write(int fd, struct circ_buf *crc)
221 {
222 char *p;
223 int len;
224
225 p = &crc->buf[crc->tail];
226 len = circ_count_to_end(crc);
227 len = write(fd, p, len);
228 if (len < 0)
229 perror("write");
230 else if (len > 0)
231 crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
232 return len;
233 }
234
235 static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc)
236 {
237 char *p;
238 int len;
239
240 p = &crc->buf[crc->tail];
241 len = circ_count_to_end(crc);
242 if (!acpi_aml_batch_drain) {
243 len = write(fd, p, len);
244 if (len < 0)
245 perror("write");
246 }
247 if (len > 0)
248 crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
249 return len;
250 }
251
252 static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc)
253 {
254 int len;
255
256 len = acpi_aml_write(fd, crc);
257 if (circ_count_to_end(crc) == 0)
258 acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
259 return len;
260 }
261
262 static void acpi_aml_loop(int fd)
263 {
264 fd_set rfds;
265 fd_set wfds;
266 struct timeval tv;
267 int ret;
268 int maxfd = 0;
269
270 if (acpi_aml_mode == ACPI_AML_BATCH) {
271 acpi_aml_log_state = ACPI_AML_LOG_START;
272 acpi_aml_batch_pos = acpi_aml_batch_cmd;
273 if (acpi_aml_batch_drain)
274 acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
275 else
276 acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD;
277 }
278 acpi_aml_exit = false;
279 while (!acpi_aml_exit) {
280 tv.tv_sec = ACPI_AML_SEC_TICK;
281 tv.tv_usec = 0;
282 FD_ZERO(&rfds);
283 FD_ZERO(&wfds);
284
285 if (acpi_aml_cmd_space()) {
286 if (acpi_aml_mode == ACPI_AML_INTERACTIVE)
287 maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds);
288 else if (strlen(acpi_aml_batch_pos) &&
289 acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)
290 ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret);
291 }
292 if (acpi_aml_cmd_count() &&
293 (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
294 acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD))
295 maxfd = acpi_aml_set_fd(fd, maxfd, &wfds);
296 if (acpi_aml_log_space() &&
297 (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
298 acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG))
299 maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
300 if (acpi_aml_log_count())
301 maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds);
302
303 ret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
304 if (ret < 0) {
305 perror("select");
306 break;
307 }
308 if (ret > 0) {
309 if (FD_ISSET(STDIN_FILENO, &rfds))
310 ACPI_AML_DO(STDIN_FILENO, read, cmd, ret);
311 if (FD_ISSET(fd, &wfds)) {
312 if (acpi_aml_mode == ACPI_AML_BATCH)
313 ACPI_AML_BATCH_DO(fd, write, cmd, ret);
314 else
315 ACPI_AML_DO(fd, write, cmd, ret);
316 }
317 if (FD_ISSET(fd, &rfds)) {
318 if (acpi_aml_mode == ACPI_AML_BATCH)
319 ACPI_AML_BATCH_DO(fd, read, log, ret);
320 else
321 ACPI_AML_DO(fd, read, log, ret);
322 }
323 if (FD_ISSET(STDOUT_FILENO, &wfds)) {
324 if (acpi_aml_mode == ACPI_AML_BATCH)
325 ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret);
326 else
327 ACPI_AML_DO(STDOUT_FILENO, write, log, ret);
328 }
329 }
330 }
331 }
332
333 static bool acpi_aml_readable(int fd)
334 {
335 fd_set rfds;
336 struct timeval tv;
337 int ret;
338 int maxfd = 0;
339
340 tv.tv_sec = 0;
341 tv.tv_usec = ACPI_AML_USEC_PEEK;
342 FD_ZERO(&rfds);
343 maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
344 ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
345 if (ret < 0)
346 perror("select");
347 if (ret > 0 && FD_ISSET(fd, &rfds))
348 return true;
349 return false;
350 }
351
352 /*
353 * This is a userspace IO flush implementation, replying on the prompt
354 * characters and can be turned into a flush() call after kernel implements
355 * .flush() filesystem operation.
356 */
357 static void acpi_aml_flush(int fd)
358 {
359 while (acpi_aml_readable(fd)) {
360 acpi_aml_batch_drain = true;
361 acpi_aml_loop(fd);
362 acpi_aml_batch_drain = false;
363 }
364 }
365
366 void usage(FILE *file, char *progname)
367 {
368 fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname);
369 fprintf(file, "\nOptions:\n");
370 fprintf(file, " -b Specify command to be executed in batch mode\n");
371 fprintf(file, " -f Specify interface file other than");
372 fprintf(file, " /sys/kernel/debug/acpi/acpidbg\n");
373 fprintf(file, " -h Print this help message\n");
374 }
375
376 int main(int argc, char **argv)
377 {
378 int fd = 0;
379 int ch;
380 int len;
381 int ret = EXIT_SUCCESS;
382
383 while ((ch = getopt(argc, argv, "b:f:h")) != -1) {
384 switch (ch) {
385 case 'b':
386 if (acpi_aml_batch_cmd) {
387 fprintf(stderr, "Already specify %s\n",
388 acpi_aml_batch_cmd);
389 ret = EXIT_FAILURE;
390 goto exit;
391 }
392 len = strlen(optarg);
393 acpi_aml_batch_cmd = calloc(len + 2, 1);
394 if (!acpi_aml_batch_cmd) {
395 perror("calloc");
396 ret = EXIT_FAILURE;
397 goto exit;
398 }
399 memcpy(acpi_aml_batch_cmd, optarg, len);
400 acpi_aml_batch_cmd[len] = '\n';
401 acpi_aml_mode = ACPI_AML_BATCH;
402 break;
403 case 'f':
404 acpi_aml_file_path = optarg;
405 break;
406 case 'h':
407 usage(stdout, argv[0]);
408 goto exit;
409 break;
410 case '?':
411 default:
412 usage(stderr, argv[0]);
413 ret = EXIT_FAILURE;
414 goto exit;
415 break;
416 }
417 }
418
419 fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK);
420 if (fd < 0) {
421 perror("open");
422 ret = EXIT_FAILURE;
423 goto exit;
424 }
425 acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK);
426 acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK);
427
428 if (acpi_aml_mode == ACPI_AML_BATCH)
429 acpi_aml_flush(fd);
430 acpi_aml_loop(fd);
431
432 exit:
433 if (fd < 0)
434 close(fd);
435 if (acpi_aml_batch_cmd)
436 free(acpi_aml_batch_cmd);
437 return ret;
438 }