* Copyright (C) 2011 by Maxim Ignatenko
* gelraen.ua@gmail.com
*
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* * Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* * Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in *
* the documentation and/or other materials provided with the *
* distribution. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR *
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*
*/
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/param.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "acpi.h"
struct acpi_call_descr
{
char* path;
ACPI_OBJECT_LIST args;
ACPI_STATUS retval;
ACPI_BUFFER result;
ACPI_SIZE reslen;
};
#define MAX_ACPI_PATH 1024 // XXX
#define MAX_ACPI_ARGS 7
char dev_path[MAXPATHLEN] = "/dev/acpi/call";
char method_path[MAX_ACPI_PATH] = "";
size_t result_buf_size = 1024;
char output_format = 'o';
int verbose;
ACPI_OBJECT args[MAX_ACPI_ARGS];
struct acpi_call_descr params;
void parse_opts(int, char *[]);
void show_help(FILE*);
int parse_buffer(ACPI_OBJECT*, char*);
void print_params(struct acpi_call_descr*);
void print_acpi_object(ACPI_OBJECT*);
void print_acpi_buffer(ACPI_BUFFER*, char);
int main(int argc, char * argv[])
{
int fd;
bzero(¶ms, sizeof(params));
params.path = method_path;
params.args.Count = 0;
params.args.Pointer = args;
verbose = 0;
parse_opts(argc, argv);
params.result.Length = result_buf_size;
params.result.Pointer = malloc(result_buf_size);
if (params.result.Pointer == NULL)
{
perror("malloc");
return 1;
}
if (method_path[0] == 0)
{
fprintf(stderr, "Please specify path to method with -p flag\n");
return 1;
}
if (verbose)
print_params(¶ms);
fd = open(dev_path, O_RDWR);
if (fd < 0)
{
perror("open");
return 1;
}
if (ioctl(fd, 'ACCA', ¶ms) == -1)
{
perror("ioctl");
return 1;
}
if (verbose)
printf("Status: %d\nResult: ", params.retval);
print_acpi_buffer(¶ms.result, output_format);
printf("\n");
return params.retval;
}
void parse_opts(int argc, char * argv[])
{
char c;
int i;
while ((c = getopt(argc, argv, "hvd:p:i:s:b:o:")) != -1)
{
switch(c)
{
case 'h':
show_help(stdout);
exit(0);
break;
case 'v':
verbose = 1;
break;
case 'd':
strlcpy(dev_path, optarg, MAXPATHLEN);
break;
case 'p':
strlcpy(method_path, optarg, MAX_ACPI_PATH);
break;
case 'i':
case 's':
case 'b':
i = params.args.Count;
if (i >= MAX_ACPI_ARGS)
{
fprintf(stderr, "Maximum number of arguments exceeded\n");
exit(1);
}
switch (optopt)
{
case 'i':
args[i].Type = ACPI_TYPE_INTEGER;
args[i].Integer.Value = strtol(optarg, NULL, 10);
break;
case 's':
args[i].Type = ACPI_TYPE_STRING;
args[i].String.Length = strlen(optarg);
args[i].String.Pointer = optarg;
break;
case 'b':
if (parse_buffer(&args[i], optarg))
{
fprintf(stderr, "Unable to parse hexstring to buffer: %s\n", optarg);
exit(1);
}
break;
}
params.args.Count++;
break;
case 'o':
output_format = optarg[0];
switch (optarg[0])
{
case 'i':
case 's':
case 'b':
case 'o':
break;
default:
fprintf(stderr, "Incorrect output format: %c\n", optarg[0]);
show_help(stderr);
exit(1);
}
break;
default:
show_help(stderr);
exit(1);
}
}
}
void show_help(FILE* f)
{
fprintf(f, "Options:\n");
fprintf(f, " -h - print this help\n");
fprintf(f, " -v - be verbose\n");
fprintf(f, " -d filename - specify path to ACPI control pseudo-device. Default: /dev/acpi/call\n");
fprintf(f, " -p path - full path to ACPI method\n");
fprintf(f, " -i number - add integer argument\n");
fprintf(f, " -s string - add string argument\n");
fprintf(f, " -b hexstring - add buffer argument\n");
fprintf(f, " -o i|s|b|o - print result as integer|string|hexstring|object\n");
}
int parse_buffer(ACPI_OBJECT *dst, char *src)
{
char tmp[3] = {0};
size_t len = strlen(src)/2, i;
dst->Type = ACPI_TYPE_BUFFER;
dst->Buffer.Length = len;
if ((dst->Buffer.Pointer = (UINT8*)malloc(len)) == NULL)
{
fprintf(stderr, "parse_buffer: Failed to allocate %" B_PRIuSIZE " bytes\n", len);
exit(1);
}
for(i = 0; i < len; i++)
{
tmp[0] = src[i*2];
tmp[1] = src[i*2+1];
dst->Buffer.Pointer[i] = strtol(tmp, NULL, 16);
}
return 0;
}
void print_params(struct acpi_call_descr* p)
{
printf("Path: %s\n", p->path);
printf("Number of arguments: %d\n", p->args.Count);
for(uint32 i = 0; i < p->args.Count; i++)
{
switch (p->args.Pointer[i].Type)
{
case ACPI_TYPE_INTEGER:
printf("Argument %d type: Integer\n", i+1);
break;
case ACPI_TYPE_STRING:
printf("Argument %d type: String\n", i+1);
break;
case ACPI_TYPE_BUFFER:
printf("Argument %d type: Buffer\n", i+1);
break;
}
printf("Argument %d value: ", i+1);
print_acpi_object(&(p->args.Pointer[i]));
printf("\n");
}
}
void print_acpi_object(ACPI_OBJECT* obj)
{
switch (obj->Type)
{
case ACPI_TYPE_INTEGER:
printf("%" B_PRIu64, obj->Integer.Value);
break;
case ACPI_TYPE_STRING:
printf("%s", obj->String.Pointer);
break;
case ACPI_TYPE_BUFFER:
for(uint32 i = 0; i < obj->Buffer.Length; i++)
{
printf("%02X", obj->Buffer.Pointer[i]);
}
break;
default:
printf("Unknown object type '%d'", obj->Type);
}
}
void print_acpi_buffer(ACPI_BUFFER* buf, char format)
{
switch (format)
{
case 'i':
printf("%" B_PRIu64, *((ACPI_INTEGER*)(buf->Pointer)));
break;
case 's':
printf("%s", (char*)buf->Pointer);
break;
case 'b':
for(uint32 i = 0; i < buf->Length; i++)
{
printf("%02X", ((UINT8*)(buf->Pointer))[i]);
}
break;
case 'o':
print_acpi_object((ACPI_OBJECT*)(buf->Pointer));
break;
}
}