Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  acpidbg.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * ACPI AML interfacing userspace utility
 *
 * Copyright (C) 2015, Intel Corporation
 * Authors: Lv Zheng <lv.zheng@intel.com>
 */


#include <acpi/acpi.h>

/* Headers not included by include/acpi/platform/aclinux.h */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
#include <stdbool.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/select.h>
#include "../../../../../include/linux/circ_buf.h"

#define ACPI_AML_FILE  "/sys/kernel/debug/acpi/acpidbg"
#define ACPI_AML_SEC_TICK 1
#define ACPI_AML_USEC_PEEK 200
#define ACPI_AML_BUF_SIZE 4096

#define ACPI_AML_BATCH_WRITE_CMD 0x00 /* Write command to kernel */
#define ACPI_AML_BATCH_READ_LOG  0x01 /* Read log from kernel */
#define ACPI_AML_BATCH_WRITE_LOG 0x02 /* Write log to console */

#define ACPI_AML_LOG_START  0x00
#define ACPI_AML_PROMPT_START  0x01
#define ACPI_AML_PROMPT_STOP  0x02
#define ACPI_AML_LOG_STOP  0x03
#define ACPI_AML_PROMPT_ROLL  0x04

#define ACPI_AML_INTERACTIVE 0x00
#define ACPI_AML_BATCH  0x01

#define circ_count(circ) \
 (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
#define circ_count_to_end(circ) \
 (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
#define circ_space(circ) \
 (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
#define circ_space_to_end(circ) \
 (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))

#define acpi_aml_cmd_count() circ_count(&acpi_aml_cmd_crc)
#define acpi_aml_log_count() circ_count(&acpi_aml_log_crc)
#define acpi_aml_cmd_space() circ_space(&acpi_aml_cmd_crc)
#define acpi_aml_log_space() circ_space(&acpi_aml_log_crc)

#define ACPI_AML_DO(_fd, _op, _buf, _ret)    \
 do {        \
  _ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc); \
  if (_ret == 0) {     \
   fprintf(stderr,     \
    "%s %s pipe closed.\n"#_buf, #_op); \
   return;      \
  }       \
 } while (0)
#define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret)    \
 do {        \
  _ret = acpi_aml_##_op##_batch_##_buf(_fd,  \
    &acpi_aml_##_buf##_crc);   \
  if (_ret == 0)      \
   return;      \
 } while (0)


static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
static struct circ_buf acpi_aml_cmd_crc = {
 .buf = acpi_aml_cmd_buf,
 .head = 0,
 .tail = 0,
};
static struct circ_buf acpi_aml_log_crc = {
 .buf = acpi_aml_log_buf,
 .head = 0,
 .tail = 0,
};
static const char *acpi_aml_file_path = ACPI_AML_FILE;
static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
static bool acpi_aml_exit;

static bool acpi_aml_batch_drain;
static unsigned long acpi_aml_batch_state;
static char acpi_aml_batch_prompt;
static char acpi_aml_batch_roll;
static unsigned long acpi_aml_log_state;
static char *acpi_aml_batch_cmd = NULL;
static char *acpi_aml_batch_pos = NULL;

static int acpi_aml_set_fl(int fd, int flags)
{
 int ret;

 ret = fcntl(fd, F_GETFL, 0);
 if (ret < 0) {
  perror("fcntl(F_GETFL)");
  return ret;
 }
 flags |= ret;
 ret = fcntl(fd, F_SETFL, flags);
 if (ret < 0) {
  perror("fcntl(F_SETFL)");
  return ret;
 }
 return ret;
}

static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set)
{
 if (fd > maxfd)
  maxfd = fd;
 FD_SET(fd, set);
 return maxfd;
}

static int acpi_aml_read(int fd, struct circ_buf *crc)
{
 char *p;
 int len;

 p = &crc->buf[crc->head];
 len = circ_space_to_end(crc);
 len = read(fd, p, len);
 if (len < 0)
  perror("read");
 else if (len > 0)
  crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
 return len;
}

static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc)
{
 char *p;
 int len;
 int remained = strlen(acpi_aml_batch_pos);

 p = &crc->buf[crc->head];
 len = circ_space_to_end(crc);
 if (len > remained) {
  memcpy(p, acpi_aml_batch_pos, remained);
  acpi_aml_batch_pos += remained;
  len = remained;
 } else {
  memcpy(p, acpi_aml_batch_pos, len);
  acpi_aml_batch_pos += len;
 }
 if (len > 0)
  crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
 return len;
}

static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc)
{
 char *p;
 int len;
 int ret = 0;

 p = &crc->buf[crc->head];
 len = circ_space_to_end(crc);
 while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) {
  if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) {
   *p = acpi_aml_batch_roll;
   len = 1;
   crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
   ret += 1;
   acpi_aml_log_state = ACPI_AML_LOG_START;
  } else {
   len = read(fd, p, 1);
   if (len <= 0) {
    if (len < 0)
     perror("read");
    ret = len;
    break;
   }
  }
  switch (acpi_aml_log_state) {
  case ACPI_AML_LOG_START:
   if (*p == '\n')
    acpi_aml_log_state = ACPI_AML_PROMPT_START;
   crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
   ret += 1;
   break;
  case ACPI_AML_PROMPT_START:
   if (*p == ACPI_DEBUGGER_COMMAND_PROMPT ||
       *p == ACPI_DEBUGGER_EXECUTE_PROMPT) {
    acpi_aml_batch_prompt = *p;
    acpi_aml_log_state = ACPI_AML_PROMPT_STOP;
   } else {
    if (*p != '\n')
     acpi_aml_log_state = ACPI_AML_LOG_START;
    crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
    ret += 1;
   }
   break;
  case ACPI_AML_PROMPT_STOP:
   if (*p == ' ') {
    acpi_aml_log_state = ACPI_AML_LOG_STOP;
    acpi_aml_exit = true;
   } else {
    /* Roll back */
    acpi_aml_log_state = ACPI_AML_PROMPT_ROLL;
    acpi_aml_batch_roll = *p;
    *p = acpi_aml_batch_prompt;
    crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
    ret += 1;
   }
   break;
  default:
   assert(0);
   break;
  }
 }
 return ret;
}

static int acpi_aml_write(int fd, struct circ_buf *crc)
{
 char *p;
 int len;

 p = &crc->buf[crc->tail];
 len = circ_count_to_end(crc);
 len = write(fd, p, len);
 if (len < 0)
  perror("write");
 else if (len > 0)
  crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
 return len;
}

static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc)
{
 char *p;
 int len;

 p = &crc->buf[crc->tail];
 len = circ_count_to_end(crc);
 if (!acpi_aml_batch_drain) {
  len = write(fd, p, len);
  if (len < 0)
   perror("write");
 }
 if (len > 0)
  crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
 return len;
}

static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc)
{
 int len;

 len = acpi_aml_write(fd, crc);
 if (circ_count_to_end(crc) == 0)
  acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
 return len;
}

static void acpi_aml_loop(int fd)
{
 fd_set rfds;
 fd_set wfds;
 struct timeval tv;
 int ret;
 int maxfd = 0;

 if (acpi_aml_mode == ACPI_AML_BATCH) {
  acpi_aml_log_state = ACPI_AML_LOG_START;
  acpi_aml_batch_pos = acpi_aml_batch_cmd;
  if (acpi_aml_batch_drain)
   acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
  else
   acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD;
 }
 acpi_aml_exit = false;
 while (!acpi_aml_exit) {
  tv.tv_sec = ACPI_AML_SEC_TICK;
  tv.tv_usec = 0;
  FD_ZERO(&rfds);
  FD_ZERO(&wfds);

  if (acpi_aml_cmd_space()) {
   if (acpi_aml_mode == ACPI_AML_INTERACTIVE)
    maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds);
   else if (strlen(acpi_aml_batch_pos) &&
     acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)
    ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret);
  }
  if (acpi_aml_cmd_count() &&
      (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
       acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD))
   maxfd = acpi_aml_set_fd(fd, maxfd, &wfds);
  if (acpi_aml_log_space() &&
      (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
       acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG))
   maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
  if (acpi_aml_log_count())
   maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds);

  ret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
  if (ret < 0) {
   perror("select");
   break;
  }
  if (ret > 0) {
   if (FD_ISSET(STDIN_FILENO, &rfds))
    ACPI_AML_DO(STDIN_FILENO, read, cmd, ret);
   if (FD_ISSET(fd, &wfds)) {
    if (acpi_aml_mode == ACPI_AML_BATCH)
     ACPI_AML_BATCH_DO(fd, write, cmd, ret);
    else
     ACPI_AML_DO(fd, write, cmd, ret);
   }
   if (FD_ISSET(fd, &rfds)) {
    if (acpi_aml_mode == ACPI_AML_BATCH)
     ACPI_AML_BATCH_DO(fd, read, log, ret);
    else
     ACPI_AML_DO(fd, read, log, ret);
   }
   if (FD_ISSET(STDOUT_FILENO, &wfds)) {
    if (acpi_aml_mode == ACPI_AML_BATCH)
     ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret);
    else
     ACPI_AML_DO(STDOUT_FILENO, write, log, ret);
   }
  }
 }
}

static bool acpi_aml_readable(int fd)
{
 fd_set rfds;
 struct timeval tv;
 int ret;
 int maxfd = 0;

 tv.tv_sec = 0;
 tv.tv_usec = ACPI_AML_USEC_PEEK;
 FD_ZERO(&rfds);
 maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
 ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
 if (ret < 0)
  perror("select");
 if (ret > 0 && FD_ISSET(fd, &rfds))
  return true;
 return false;
}

/*
 * This is a userspace IO flush implementation, replying on the prompt
 * characters and can be turned into a flush() call after kernel implements
 * .flush() filesystem operation.
 */

static void acpi_aml_flush(int fd)
{
 while (acpi_aml_readable(fd)) {
  acpi_aml_batch_drain = true;
  acpi_aml_loop(fd);
  acpi_aml_batch_drain = false;
 }
}

void usage(FILE *file, char *progname)
{
 fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname);
 fprintf(file, "\nOptions:\n");
 fprintf(file, " -b Specify command to be executed in batch mode\n");
 fprintf(file, " -f Specify interface file other than");
 fprintf(file, " /sys/kernel/debug/acpi/acpidbg\n");
 fprintf(file, " -h Print this help message\n");
}

int main(int argc, char **argv)
{
 int fd = -1;
 int ch;
 int len;
 int ret = EXIT_SUCCESS;

 while ((ch = getopt(argc, argv, "b:f:h")) != -1) {
  switch (ch) {
  case 'b':
   if (acpi_aml_batch_cmd) {
    fprintf(stderr, "Already specify %s\n",
     acpi_aml_batch_cmd);
    ret = EXIT_FAILURE;
    goto exit;
   }
   len = strlen(optarg);
   acpi_aml_batch_cmd = calloc(len + 2, 1);
   if (!acpi_aml_batch_cmd) {
    perror("calloc");
    ret = EXIT_FAILURE;
    goto exit;
   }
   memcpy(acpi_aml_batch_cmd, optarg, len);
   acpi_aml_batch_cmd[len] = '\n';
   acpi_aml_mode = ACPI_AML_BATCH;
   break;
  case 'f':
   acpi_aml_file_path = optarg;
   break;
  case 'h':
   usage(stdout, argv[0]);
   goto exit;
   break;
  case '?':
  default:
   usage(stderr, argv[0]);
   ret = EXIT_FAILURE;
   goto exit;
   break;
  }
 }

 fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK);
 if (fd < 0) {
  perror("open");
  ret = EXIT_FAILURE;
  goto exit;
 }
 acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK);
 acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK);

 if (acpi_aml_mode == ACPI_AML_BATCH)
  acpi_aml_flush(fd);
 acpi_aml_loop(fd);

exit:
 if (fd >= 0)
  close(fd);
 if (acpi_aml_batch_cmd)
  free(acpi_aml_batch_cmd);
 return ret;
}

Messung V0.5
C=97 H=89 G=93

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge