xref: /haiku/src/bin/acpi_call/acpi_call.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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 
44 struct 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 
57 char dev_path[MAXPATHLEN] = "/dev/acpi/call";
58 char method_path[MAX_ACPI_PATH] = "";
59 size_t result_buf_size = 1024;
60 char output_format = 'o';
61 
62 int verbose;
63 
64 ACPI_OBJECT args[MAX_ACPI_ARGS];
65 struct acpi_call_descr params;
66 
67 void parse_opts(int, char *[]);
68 void show_help(FILE*);
69 int parse_buffer(ACPI_OBJECT*, char*);
70 void print_params(struct acpi_call_descr*);
71 void print_acpi_object(ACPI_OBJECT*);
72 void print_acpi_buffer(ACPI_BUFFER*, char);
73 
74 int 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 
125 void 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 
199 void 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 
212 int 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 
235 void 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 
259 void 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 
280 void 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