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

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

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

~ [ 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