1 /* 2 * acpi_utils.c - ACPI Utility Functions ($Revision: 10 $) 3 * 4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 6 * 7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or (at 12 * your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, write to the Free Software Foundation, Inc., 21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 22 * 23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 24 */ 25 26 #include <linux/kernel.h> 27 #include <linux/module.h> 28 #include <linux/slab.h> 29 #include <linux/init.h> 30 #include <linux/types.h> 31 #include <acpi/acpi_bus.h> 32 #include <acpi/acpi_drivers.h> 33 34 #include "internal.h" 35 36 #define _COMPONENT ACPI_BUS_COMPONENT 37 ACPI_MODULE_NAME("utils"); 38 39 /* -------------------------------------------------------------------------- 40 Object Evaluation Helpers 41 -------------------------------------------------------------------------- */ 42 static void 43 acpi_util_eval_error(acpi_handle h, acpi_string p, acpi_status s) 44 { 45 #ifdef ACPI_DEBUG_OUTPUT 46 char prefix[80] = {'\0'}; 47 struct acpi_buffer buffer = {sizeof(prefix), prefix}; 48 acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer); 49 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n", 50 (char *) prefix, p, acpi_format_exception(s))); 51 #else 52 return; 53 #endif 54 } 55 56 acpi_status 57 acpi_extract_package(union acpi_object *package, 58 struct acpi_buffer *format, struct acpi_buffer *buffer) 59 { 60 u32 size_required = 0; 61 u32 tail_offset = 0; 62 char *format_string = NULL; 63 u32 format_count = 0; 64 u32 i = 0; 65 u8 *head = NULL; 66 u8 *tail = NULL; 67 68 69 if (!package || (package->type != ACPI_TYPE_PACKAGE) 70 || (package->package.count < 1)) { 71 printk(KERN_WARNING PREFIX "Invalid package argument\n"); 72 return AE_BAD_PARAMETER; 73 } 74 75 if (!format || !format->pointer || (format->length < 1)) { 76 printk(KERN_WARNING PREFIX "Invalid format argument\n"); 77 return AE_BAD_PARAMETER; 78 } 79 80 if (!buffer) { 81 printk(KERN_WARNING PREFIX "Invalid buffer argument\n"); 82 return AE_BAD_PARAMETER; 83 } 84 85 format_count = (format->length / sizeof(char)) - 1; 86 if (format_count > package->package.count) { 87 printk(KERN_WARNING PREFIX "Format specifies more objects [%d]" 88 " than exist in package [%d].\n", 89 format_count, package->package.count); 90 return AE_BAD_DATA; 91 } 92 93 format_string = format->pointer; 94 95 /* 96 * Calculate size_required. 97 */ 98 for (i = 0; i < format_count; i++) { 99 100 union acpi_object *element = &(package->package.elements[i]); 101 102 if (!element) { 103 return AE_BAD_DATA; 104 } 105 106 switch (element->type) { 107 108 case ACPI_TYPE_INTEGER: 109 switch (format_string[i]) { 110 case 'N': 111 size_required += sizeof(u64); 112 tail_offset += sizeof(u64); 113 break; 114 case 'S': 115 size_required += 116 sizeof(char *) + sizeof(u64) + 117 sizeof(char); 118 tail_offset += sizeof(char *); 119 break; 120 default: 121 printk(KERN_WARNING PREFIX "Invalid package element" 122 " [%d]: got number, expecing" 123 " [%c]\n", 124 i, format_string[i]); 125 return AE_BAD_DATA; 126 break; 127 } 128 break; 129 130 case ACPI_TYPE_STRING: 131 case ACPI_TYPE_BUFFER: 132 switch (format_string[i]) { 133 case 'S': 134 size_required += 135 sizeof(char *) + 136 (element->string.length * sizeof(char)) + 137 sizeof(char); 138 tail_offset += sizeof(char *); 139 break; 140 case 'B': 141 size_required += 142 sizeof(u8 *) + 143 (element->buffer.length * sizeof(u8)); 144 tail_offset += sizeof(u8 *); 145 break; 146 default: 147 printk(KERN_WARNING PREFIX "Invalid package element" 148 " [%d] got string/buffer," 149 " expecing [%c]\n", 150 i, format_string[i]); 151 return AE_BAD_DATA; 152 break; 153 } 154 break; 155 156 case ACPI_TYPE_PACKAGE: 157 default: 158 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 159 "Found unsupported element at index=%d\n", 160 i)); 161 /* TBD: handle nested packages... */ 162 return AE_SUPPORT; 163 break; 164 } 165 } 166 167 /* 168 * Validate output buffer. 169 */ 170 if (buffer->length < size_required) { 171 buffer->length = size_required; 172 return AE_BUFFER_OVERFLOW; 173 } else if (buffer->length != size_required || !buffer->pointer) { 174 return AE_BAD_PARAMETER; 175 } 176 177 head = buffer->pointer; 178 tail = buffer->pointer + tail_offset; 179 180 /* 181 * Extract package data. 182 */ 183 for (i = 0; i < format_count; i++) { 184 185 u8 **pointer = NULL; 186 union acpi_object *element = &(package->package.elements[i]); 187 188 if (!element) { 189 return AE_BAD_DATA; 190 } 191 192 switch (element->type) { 193 194 case ACPI_TYPE_INTEGER: 195 switch (format_string[i]) { 196 case 'N': 197 *((u64 *) head) = 198 element->integer.value; 199 head += sizeof(u64); 200 break; 201 case 'S': 202 pointer = (u8 **) head; 203 *pointer = tail; 204 *((u64 *) tail) = 205 element->integer.value; 206 head += sizeof(u64 *); 207 tail += sizeof(u64); 208 /* NULL terminate string */ 209 *tail = (char)0; 210 tail += sizeof(char); 211 break; 212 default: 213 /* Should never get here */ 214 break; 215 } 216 break; 217 218 case ACPI_TYPE_STRING: 219 case ACPI_TYPE_BUFFER: 220 switch (format_string[i]) { 221 case 'S': 222 pointer = (u8 **) head; 223 *pointer = tail; 224 memcpy(tail, element->string.pointer, 225 element->string.length); 226 head += sizeof(char *); 227 tail += element->string.length * sizeof(char); 228 /* NULL terminate string */ 229 *tail = (char)0; 230 tail += sizeof(char); 231 break; 232 case 'B': 233 pointer = (u8 **) head; 234 *pointer = tail; 235 memcpy(tail, element->buffer.pointer, 236 element->buffer.length); 237 head += sizeof(u8 *); 238 tail += element->buffer.length * sizeof(u8); 239 break; 240 default: 241 /* Should never get here */ 242 break; 243 } 244 break; 245 246 case ACPI_TYPE_PACKAGE: 247 /* TBD: handle nested packages... */ 248 default: 249 /* Should never get here */ 250 break; 251 } 252 } 253 254 return AE_OK; 255 } 256 257 EXPORT_SYMBOL(acpi_extract_package); 258 259 acpi_status 260 acpi_evaluate_integer(acpi_handle handle, 261 acpi_string pathname, 262 struct acpi_object_list *arguments, unsigned long long *data) 263 { 264 acpi_status status = AE_OK; 265 union acpi_object element; 266 struct acpi_buffer buffer = { 0, NULL }; 267 268 if (!data) 269 return AE_BAD_PARAMETER; 270 271 buffer.length = sizeof(union acpi_object); 272 buffer.pointer = &element; 273 status = acpi_evaluate_object(handle, pathname, arguments, &buffer); 274 if (ACPI_FAILURE(status)) { 275 acpi_util_eval_error(handle, pathname, status); 276 return status; 277 } 278 279 if (element.type != ACPI_TYPE_INTEGER) { 280 acpi_util_eval_error(handle, pathname, AE_BAD_DATA); 281 return AE_BAD_DATA; 282 } 283 284 *data = element.integer.value; 285 286 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data)); 287 288 return AE_OK; 289 } 290 291 EXPORT_SYMBOL(acpi_evaluate_integer); 292 293 acpi_status 294 acpi_evaluate_reference(acpi_handle handle, 295 acpi_string pathname, 296 struct acpi_object_list *arguments, 297 struct acpi_handle_list *list) 298 { 299 acpi_status status = AE_OK; 300 union acpi_object *package = NULL; 301 union acpi_object *element = NULL; 302 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 303 u32 i = 0; 304 305 306 if (!list) { 307 return AE_BAD_PARAMETER; 308 } 309 310 /* Evaluate object. */ 311 312 status = acpi_evaluate_object(handle, pathname, arguments, &buffer); 313 if (ACPI_FAILURE(status)) 314 goto end; 315 316 package = buffer.pointer; 317 318 if ((buffer.length == 0) || !package) { 319 printk(KERN_ERR PREFIX "No return object (len %X ptr %p)\n", 320 (unsigned)buffer.length, package); 321 status = AE_BAD_DATA; 322 acpi_util_eval_error(handle, pathname, status); 323 goto end; 324 } 325 if (package->type != ACPI_TYPE_PACKAGE) { 326 printk(KERN_ERR PREFIX "Expecting a [Package], found type %X\n", 327 package->type); 328 status = AE_BAD_DATA; 329 acpi_util_eval_error(handle, pathname, status); 330 goto end; 331 } 332 if (!package->package.count) { 333 printk(KERN_ERR PREFIX "[Package] has zero elements (%p)\n", 334 package); 335 status = AE_BAD_DATA; 336 acpi_util_eval_error(handle, pathname, status); 337 goto end; 338 } 339 340 if (package->package.count > ACPI_MAX_HANDLES) { 341 return AE_NO_MEMORY; 342 } 343 list->count = package->package.count; 344 345 /* Extract package data. */ 346 347 for (i = 0; i < list->count; i++) { 348 349 element = &(package->package.elements[i]); 350 351 if (element->type != ACPI_TYPE_LOCAL_REFERENCE) { 352 status = AE_BAD_DATA; 353 printk(KERN_ERR PREFIX 354 "Expecting a [Reference] package element, found type %X\n", 355 element->type); 356 acpi_util_eval_error(handle, pathname, status); 357 break; 358 } 359 360 if (!element->reference.handle) { 361 printk(KERN_WARNING PREFIX "Invalid reference in" 362 " package %s\n", pathname); 363 status = AE_NULL_ENTRY; 364 break; 365 } 366 /* Get the acpi_handle. */ 367 368 list->handles[i] = element->reference.handle; 369 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found reference [%p]\n", 370 list->handles[i])); 371 } 372 373 end: 374 if (ACPI_FAILURE(status)) { 375 list->count = 0; 376 //kfree(list->handles); 377 } 378 379 kfree(buffer.pointer); 380 381 return status; 382 } 383 384 EXPORT_SYMBOL(acpi_evaluate_reference); 385 386 acpi_status 387 acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld *pld) 388 { 389 acpi_status status; 390 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 391 union acpi_object *output; 392 393 status = acpi_evaluate_object(handle, "_PLD", NULL, &buffer); 394 395 if (ACPI_FAILURE(status)) 396 return status; 397 398 output = buffer.pointer; 399 400 if (!output || output->type != ACPI_TYPE_PACKAGE 401 || !output->package.count 402 || output->package.elements[0].type != ACPI_TYPE_BUFFER 403 || output->package.elements[0].buffer.length > sizeof(*pld)) { 404 status = AE_TYPE; 405 goto out; 406 } 407 408 memcpy(pld, output->package.elements[0].buffer.pointer, 409 output->package.elements[0].buffer.length); 410 out: 411 kfree(buffer.pointer); 412 return status; 413 } 414 EXPORT_SYMBOL(acpi_get_physical_device_location); 415 416 /** 417 * acpi_evaluate_hotplug_ost: Evaluate _OST for hotplug operations 418 * @handle: ACPI device handle 419 * @source_event: source event code 420 * @status_code: status code 421 * @status_buf: optional detailed information (NULL if none) 422 * 423 * Evaluate _OST for hotplug operations. All ACPI hotplug handlers 424 * must call this function when evaluating _OST for hotplug operations. 425 * When the platform does not support _OST, this function has no effect. 426 */ 427 acpi_status 428 acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event, 429 u32 status_code, struct acpi_buffer *status_buf) 430 { 431 #ifdef ACPI_HOTPLUG_OST 432 union acpi_object params[3] = { 433 {.type = ACPI_TYPE_INTEGER,}, 434 {.type = ACPI_TYPE_INTEGER,}, 435 {.type = ACPI_TYPE_BUFFER,} 436 }; 437 struct acpi_object_list arg_list = {3, params}; 438 acpi_status status; 439 440 params[0].integer.value = source_event; 441 params[1].integer.value = status_code; 442 if (status_buf != NULL) { 443 params[2].buffer.pointer = status_buf->pointer; 444 params[2].buffer.length = status_buf->length; 445 } else { 446 params[2].buffer.pointer = NULL; 447 params[2].buffer.length = 0; 448 } 449 450 status = acpi_evaluate_object(handle, "_OST", &arg_list, NULL); 451 return status; 452 #else 453 return AE_OK; 454 #endif 455 } 456 EXPORT_SYMBOL(acpi_evaluate_hotplug_ost); 457