~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/power/acpi/tools/acpidbg/acpidbg.c

Version: ~ [ linux-6.1-rc7 ] ~ [ linux-6.0.10 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.80 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.156 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.225 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.267 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.300 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.334 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.302 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 = -1;
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 }
439 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp