1/*-
2 *   Copyright (C) 2011 by Maxim Ignatenko
3 *   gelraen.ua@gmail.com
4 *
5 *   All rights reserved.                                                  *
6 *                                                                         *
7 *   Redistribution and use in source and binary forms, with or without    *
8 *    modification, are permitted provided that the following conditions   *
9 *    are met:                                                             *
10 *     * Redistributions of source code must retain the above copyright    *
11 *       notice, this list of conditions and the following disclaimer.     *
12 *     * Redistributions in binary form must reproduce the above copyright *
13 *       notice, this list of conditions and the following disclaimer in   *
14 *       the documentation and/or other materials provided with the        *
15 *       distribution.                                                     *
16 *                                                                         *
17 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   *
18 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     *
19 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR *
20 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  *
21 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
22 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      *
23 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
24 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
25 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   *
26 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
27 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  *
28 *
29 */
30
31//#include "acpi_call_io.h"
32
33#include <fcntl.h>
34#include <sys/ioctl.h>
35#include <unistd.h>
36#include <sys/param.h>
37#include <stdlib.h>
38#include <stdio.h>
39#include <string.h>
40
41#include "acpi.h"
42
43
44struct acpi_call_descr
45{
46	char*		path;
47	ACPI_OBJECT_LIST	args;
48	ACPI_STATUS	retval;
49	ACPI_BUFFER	result;
50	ACPI_SIZE	reslen;
51};
52
53
54#define	MAX_ACPI_PATH	1024 // XXX
55#define MAX_ACPI_ARGS	7
56
57char dev_path[MAXPATHLEN] = "/dev/acpi/call";
58char method_path[MAX_ACPI_PATH] = "";
59size_t result_buf_size = 1024;
60char output_format = 'o';
61
62int verbose;
63
64ACPI_OBJECT args[MAX_ACPI_ARGS];
65struct acpi_call_descr params;
66
67void parse_opts(int, char *[]);
68void show_help(FILE*);
69int parse_buffer(ACPI_OBJECT*, char*);
70void print_params(struct acpi_call_descr*);
71void print_acpi_object(ACPI_OBJECT*);
72void print_acpi_buffer(ACPI_BUFFER*, char);
73
74int main(int argc, char * argv[])
75{
76	int fd;
77
78	bzero(&params, sizeof(params));
79	params.path = method_path;
80	params.args.Count = 0;
81	params.args.Pointer = args;
82
83	verbose = 0;
84
85	parse_opts(argc, argv);
86
87	params.result.Length = result_buf_size;
88	params.result.Pointer = malloc(result_buf_size);
89
90	if (params.result.Pointer == NULL)
91	{
92		perror("malloc");
93		return 1;
94	}
95
96	if (method_path[0] == 0)
97	{
98		fprintf(stderr, "Please specify path to method with -p flag\n");
99		return 1;
100	}
101
102	if (verbose)
103		print_params(&params);
104
105	fd = open(dev_path, O_RDWR);
106	if (fd < 0)
107	{
108		perror("open");
109		return 1;
110	}
111	if (ioctl(fd, 'ACCA', &params) == -1)
112	{
113		perror("ioctl");
114		return 1;
115	}
116
117	if (verbose)
118		printf("Status: %d\nResult: ", params.retval);
119	print_acpi_buffer(&params.result, output_format);
120	printf("\n");
121
122	return params.retval;
123}
124
125void parse_opts(int argc, char * argv[])
126{
127	char c;
128	int i;
129
130	while ((c = getopt(argc, argv, "hvd:p:i:s:b:o:")) != -1)
131	{
132		switch(c)
133		{
134		case 'h':
135			show_help(stdout);
136			exit(0);
137			break;
138		case 'v':
139			verbose = 1;
140			break;
141		case 'd':
142			strlcpy(dev_path, optarg, MAXPATHLEN);
143			break;
144		case 'p':
145			strlcpy(method_path, optarg, MAX_ACPI_PATH);
146			break;
147		case 'i':
148		case 's':
149		case 'b':
150			i = params.args.Count;
151			if (i >= MAX_ACPI_ARGS)
152			{
153				fprintf(stderr, "Maximum number of arguments exceeded\n");
154				exit(1);
155			}
156			switch (optopt)
157			{
158			case 'i':
159				args[i].Type = ACPI_TYPE_INTEGER;
160				args[i].Integer.Value = strtol(optarg, NULL, 10);
161				break;
162			case 's':
163				args[i].Type = ACPI_TYPE_STRING;
164				args[i].String.Length = strlen(optarg);
165				args[i].String.Pointer = optarg;
166				break;
167			case 'b':
168				if (parse_buffer(&args[i], optarg))
169				{
170					fprintf(stderr, "Unable to parse hexstring to buffer: %s\n", optarg);
171					exit(1);
172				}
173				break;
174			}
175			params.args.Count++;
176			break;
177		case 'o':
178			output_format = optarg[0];
179			switch (optarg[0])
180			{
181			case 'i':
182			case 's':
183			case 'b':
184			case 'o':
185				break;
186			default:
187				fprintf(stderr, "Incorrect output format: %c\n", optarg[0]);
188				show_help(stderr);
189				exit(1);
190			}
191			break;
192		default:
193			show_help(stderr);
194			exit(1);
195		}
196	}
197}
198
199void show_help(FILE* f)
200{
201	fprintf(f, "Options:\n");
202	fprintf(f, "  -h              - print this help\n");
203	fprintf(f, "  -v              - be verbose\n");
204	fprintf(f, "  -d filename     - specify path to ACPI control pseudo-device. Default: /dev/acpi/call\n");
205	fprintf(f, "  -p path         - full path to ACPI method\n");
206	fprintf(f, "  -i number       - add integer argument\n");
207	fprintf(f, "  -s string       - add string argument\n");
208	fprintf(f, "  -b hexstring    - add buffer argument\n");
209	fprintf(f, "  -o i|s|b|o      - print result as integer|string|hexstring|object\n");
210}
211
212int parse_buffer(ACPI_OBJECT *dst, char *src)
213{
214	char tmp[3] = {0};
215	size_t len = strlen(src)/2, i;
216
217	dst->Type = ACPI_TYPE_BUFFER;
218	dst->Buffer.Length = len;
219	if ((dst->Buffer.Pointer = (UINT8*)malloc(len)) == NULL)
220	{
221		fprintf(stderr, "parse_buffer: Failed to allocate %" B_PRIuSIZE " bytes\n", len);
222		exit(1);
223	}
224
225	for(i = 0; i < len; i++)
226	{
227		tmp[0] = src[i*2];
228		tmp[1] = src[i*2+1];
229		dst->Buffer.Pointer[i] = strtol(tmp, NULL, 16);
230	}
231
232	return 0;
233}
234
235void print_params(struct acpi_call_descr* p)
236{
237	printf("Path: %s\n", p->path);
238	printf("Number of arguments: %d\n", p->args.Count);
239	for(uint32 i = 0; i < p->args.Count; i++)
240	{
241		switch (p->args.Pointer[i].Type)
242		{
243		case ACPI_TYPE_INTEGER:
244			printf("Argument %d type: Integer\n", i+1);
245			break;
246		case ACPI_TYPE_STRING:
247			printf("Argument %d type: String\n", i+1);
248			break;
249		case ACPI_TYPE_BUFFER:
250			printf("Argument %d type: Buffer\n", i+1);
251			break;
252		}
253		printf("Argument %d value: ", i+1);
254		print_acpi_object(&(p->args.Pointer[i]));
255		printf("\n");
256	}
257}
258
259void print_acpi_object(ACPI_OBJECT* obj)
260{
261	switch (obj->Type)
262	{
263	case ACPI_TYPE_INTEGER:
264		printf("%" B_PRIu64, obj->Integer.Value);
265		break;
266	case ACPI_TYPE_STRING:
267		printf("%s", obj->String.Pointer);
268		break;
269	case ACPI_TYPE_BUFFER:
270		for(uint32 i = 0; i < obj->Buffer.Length; i++)
271		{
272			printf("%02X", obj->Buffer.Pointer[i]);
273		}
274		break;
275	default:
276		printf("Unknown object type '%d'", obj->Type);
277	}
278}
279
280void print_acpi_buffer(ACPI_BUFFER* buf, char format)
281{
282	switch (format)
283	{
284	case 'i':
285		printf("%" B_PRIu64, *((ACPI_INTEGER*)(buf->Pointer)));
286		break;
287	case 's':
288		printf("%s", (char*)buf->Pointer);
289		break;
290	case 'b':
291		for(uint32 i = 0; i < buf->Length; i++)
292		{
293			printf("%02X", ((UINT8*)(buf->Pointer))[i]);
294		}
295		break;
296	case 'o':
297		print_acpi_object((ACPI_OBJECT*)(buf->Pointer));
298		break;
299	}
300}
301