kernel - Handle spinlock indefinite wait edge case
[dragonfly.git] / usr.sbin / acpi / acpicall / acpicall.c
blob9581a9d26810d8f01ae0335dbf142b9b6918e478
1 /*-
2 * Copyright (C) 2011 by Maxim Ignatenko
3 * gelraen.ua@gmail.com
4 * Copyright (C) 2015 Sascha Wildner
5 * swildner@dragonflybsd.org
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. *
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>
42 #include <contrib/dev/acpica/source/include/acpi.h>
43 #include <dev/acpica/acpiio_mcall.h>
45 #define MAX_ACPI_PATH 4096
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;
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);
61 int
62 main(int argc, char *argv[])
64 char c;
65 int i, fd, status;
66 uuid_t uuid;
68 bzero(&params, sizeof(params));
69 params.path = method_path;
70 params.args.Count = 0;
71 params.args.Pointer = args;
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);
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);
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);
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);
118 uuid_enc_le(args[i].Buffer.Pointer, &uuid);
119 break;
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;
141 break;
142 case 'v':
143 verbose = 1;
144 break;
145 default:
146 usage();
147 break;
150 argc -= optind;
151 argv += optind;
153 if (argc != 1)
154 usage();
155 strlcpy(method_path, argv[0], MAX_ACPI_PATH);
157 params.result.Length = result_buf_size;
158 params.result.Pointer = malloc(result_buf_size);
160 if (params.result.Pointer == NULL) {
161 perror("malloc");
162 return 1;
165 if (method_path[0] == 0) {
166 fprintf(stderr,
167 "please specify path to method with -p flag\n");
168 return 1;
171 if (verbose)
172 print_params(&params);
174 fd = open(dev_path, O_RDWR);
175 if (fd < 0) {
176 perror("open");
177 return 1;
179 if (ioctl(fd, ACPIIO_DO_MCALL, &params) == -1) {
180 perror("ioctl");
181 return 1;
184 if (verbose)
185 printf("status: %d\nresult: ", params.retval);
186 print_acpi_buffer(&params.result, output_format);
187 printf("\n");
189 return params.retval;
192 static void
193 usage(void)
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);
202 static int
203 parse_buffer(ACPI_OBJECT *dst, char *src)
205 char tmp[3] = { 0 };
206 size_t len = strlen(src) / 2, i;
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 %zd bytes\n", __func__, len);
213 exit(1);
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);
222 return 0;
225 static void
226 print_params(struct acpi_mcall_ioctl_arg *p)
228 int i;
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;
245 printf("argument %d value: ", i + 1);
246 print_acpi_object(&(p->args.Pointer[i]));
247 printf("\n");
251 static void
252 print_acpi_object(ACPI_OBJECT *obj)
254 int i;
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;
273 static void
274 print_acpi_buffer(ACPI_BUFFER *buf, char format)
276 int i;
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;