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(¶ms, 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(¶ms); 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, ¶ms) == -1) { 180 perror("ioctl"); 181 return 1; 182 } 183 184 if (verbose) 185 printf("status: %d\nresult: ", params.retval); 186 print_acpi_buffer(¶ms.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