xref: /dragonfly/usr.sbin/acpi/acpicall/acpicall.c (revision 66b13f02)
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 
41 #include <contrib/dev/acpica/source/include/acpi.h>
42 #include <dev/acpica/acpiio_mcall.h>
43 
44 #define	MAX_ACPI_PATH	4096
45 
46 static char	dev_path[MAXPATHLEN] = "/dev/acpi";
47 static char	method_path[MAX_ACPI_PATH] = "";
48 static size_t	result_buf_size = 1024;
49 static char	output_format = 'o';
50 static int	verbose;
51 static ACPI_OBJECT args[ACPI_METHOD_NUM_ARGS];
52 static struct acpi_mcall_ioctl_arg params;
53 
54 static void	usage(void);
55 static int	parse_buffer(ACPI_OBJECT *, char *);
56 static void	print_params(struct acpi_mcall_ioctl_arg *);
57 static void	print_acpi_object(ACPI_OBJECT *);
58 static void	print_acpi_buffer(ACPI_BUFFER *, char);
59 
60 int
61 main(int argc, char *argv[])
62 {
63 	char c;
64 	int i, fd;
65 
66 	bzero(&params, sizeof(params));
67 	params.path = method_path;
68 	params.args.Count = 0;
69 	params.args.Pointer = args;
70 
71 	while ((c = getopt(argc, argv, "vb:d:i:o:s:")) != -1) {
72 		switch (c) {
73 		case 'b':
74 		case 'i':
75 		case 's':
76 			i = params.args.Count;
77 			if (i >= ACPI_METHOD_NUM_ARGS) {
78 				fprintf(stderr,
79 				    "maximum number of %d args exceeded\n",
80 				    ACPI_METHOD_NUM_ARGS);
81 				exit(1);
82 			}
83 			switch (optopt) {
84 			case 'b':
85 				if (parse_buffer(&args[i], optarg) != 0) {
86 					fprintf(stderr,
87 					    "unable to parse hexstring: %s\n",
88 					    optarg);
89 					exit(1);
90 				}
91 				break;
92 			case 'i':
93 				args[i].Type = ACPI_TYPE_INTEGER;
94 				args[i].Integer.Value =
95 				    strtol(optarg, NULL, 10);
96 				break;
97 			case 's':
98 				args[i].Type = ACPI_TYPE_STRING;
99 				args[i].String.Length = strlen(optarg);
100 				args[i].String.Pointer = optarg;
101 				break;
102 			}
103 			params.args.Count++;
104 			break;
105 		case 'd':
106 			strlcpy(dev_path, optarg, MAXPATHLEN);
107 			break;
108 		case 'o':
109 			switch (optarg[0]) {
110 			case 'b':
111 			case 'i':
112 			case 'o':
113 			case 's':
114 				output_format = optarg[0];
115 				break;
116 			default:
117 				fprintf(stderr,
118 				    "incorrect output format: %c\n",
119 				    optarg[0]);
120 				usage();
121 				break;
122 			}
123 			break;
124 		case 'v':
125 			verbose = 1;
126 			break;
127 		default:
128 			usage();
129 			break;
130 		}
131 	}
132 	argc -= optind;
133 	argv += optind;
134 
135 	if (argc != 1)
136 		usage();
137 	strlcpy(method_path, argv[0], MAX_ACPI_PATH);
138 
139 	params.result.Length = result_buf_size;
140 	params.result.Pointer = malloc(result_buf_size);
141 
142 	if (params.result.Pointer == NULL) {
143 		perror("malloc");
144 		return 1;
145 	}
146 
147 	if (method_path[0] == 0) {
148 		fprintf(stderr,
149 		    "please specify path to method with -p flag\n");
150 		return 1;
151 	}
152 
153 	if (verbose)
154 		print_params(&params);
155 
156 	fd = open(dev_path, O_RDWR);
157 	if (fd < 0) {
158 		perror("open");
159 		return 1;
160 	}
161 	if (ioctl(fd, ACPIIO_DO_MCALL, &params) == -1) {
162 		perror("ioctl");
163 		return 1;
164 	}
165 
166 	if (verbose)
167 		printf("status: %d\nresult: ", params.retval);
168 	print_acpi_buffer(&params.result, output_format);
169 	printf("\n");
170 
171 	return params.retval;
172 }
173 
174 static void
175 usage(void)
176 {
177 	fprintf(stderr,
178 	    "usage: acpicall [-v] [-b hexstring] [-d file] [-i number] "
179 	    "[-o i | s | b | o]\n");
180 	fprintf(stderr, "                [-s string] path\n");
181 	exit(1);
182 }
183 
184 static int
185 parse_buffer(ACPI_OBJECT *dst, char *src)
186 {
187 	char tmp[3] = { 0 };
188 	size_t len = strlen(src) / 2, i;
189 
190 	dst->Type = ACPI_TYPE_BUFFER;
191 	dst->Buffer.Length = len;
192 	if ((dst->Buffer.Pointer = malloc(len)) == NULL) {
193 		fprintf(stderr,
194 		    "%s: failed to allocate %zd bytes\n", __func__, len);
195 		exit(1);
196 	}
197 
198 	for (i = 0; i < len; i++) {
199 		tmp[0] = src[i * 2];
200 		tmp[1] = src[i * 2 + 1];
201 		dst->Buffer.Pointer[i] = strtol(tmp, NULL, 16);
202 	}
203 
204 	return 0;
205 }
206 
207 static void
208 print_params(struct acpi_mcall_ioctl_arg *p)
209 {
210 	int i;
211 
212 	printf("path: %s\n", p->path);
213 	printf("number of arguments: %d\n", p->args.Count);
214 	for (i = 0; i < (int)p->args.Count; i++) {
215 		printf("argument %d type: ", i + 1);
216 		switch (p->args.Pointer[i].Type) {
217 		case ACPI_TYPE_INTEGER:
218 			printf("integer\n");
219 			break;
220 		case ACPI_TYPE_STRING:
221 			printf("string\n");
222 			break;
223 		case ACPI_TYPE_BUFFER:
224 			printf("buffer\n");
225 			break;
226 		}
227 		printf("argument %d value: ", i + 1);
228 		print_acpi_object(&(p->args.Pointer[i]));
229 		printf("\n");
230 	}
231 }
232 
233 static void
234 print_acpi_object(ACPI_OBJECT *obj)
235 {
236 	int i;
237 
238 	switch (obj->Type) {
239 	case ACPI_TYPE_INTEGER:
240 		printf("%ju", (uintmax_t)obj->Integer.Value);
241 		break;
242 	case ACPI_TYPE_STRING:
243 		printf("%s", obj->String.Pointer);
244 		break;
245 	case ACPI_TYPE_BUFFER:
246 		for (i = 0; i < (int)obj->Buffer.Length; i++)
247 			printf("%02x", obj->Buffer.Pointer[i]);
248 		break;
249 	default:
250 		printf("unknown object type '%d'", obj->Type);
251 		break;
252 	}
253 }
254 
255 static void
256 print_acpi_buffer(ACPI_BUFFER *buf, char format)
257 {
258 	int i;
259 
260 	switch (format) {
261 	case 'i':
262 		printf("%ju", (uintmax_t)*((UINT64 *)buf->Pointer));
263 		break;
264 	case 's':
265 		printf("%s", (char *)buf->Pointer);
266 		break;
267 	case 'b':
268 		for (i = 0; i < (int)buf->Length; i++)
269 			printf("%02x", ((UINT8 *)(buf->Pointer))[i]);
270 		break;
271 	case 'o':
272 		print_acpi_object((ACPI_OBJECT *)buf->Pointer);
273 		break;
274 	}
275 }
276