root/tools/power/acpi/tools/acpidbg/acpidbg.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. acpi_aml_set_fl
  2. acpi_aml_set_fd
  3. acpi_aml_read
  4. acpi_aml_read_batch_cmd
  5. acpi_aml_read_batch_log
  6. acpi_aml_write
  7. acpi_aml_write_batch_log
  8. acpi_aml_write_batch_cmd
  9. acpi_aml_loop
  10. acpi_aml_readable
  11. acpi_aml_flush
  12. usage
  13. main

   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 }

/* [<][>][^][v][top][bottom][index][help] */