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(¶ms, 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(¶ms); 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, ¶ms) == -1) { 162 perror("ioctl"); 163 return 1; 164 } 165 166 if (verbose) 167 printf("status: %d\nresult: ", params.retval); 168 print_acpi_buffer(¶ms.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