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