linux/drivers/acpi/utils.c
<<
>>
Prefs
   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 <linux/hardirq.h>
  32#include <linux/acpi.h>
  33#include <acpi/acpi_bus.h>
  34#include <acpi/acpi_drivers.h>
  35
  36#include "internal.h"
  37
  38#define _COMPONENT              ACPI_BUS_COMPONENT
  39ACPI_MODULE_NAME("utils");
  40
  41/* --------------------------------------------------------------------------
  42                            Object Evaluation Helpers
  43   -------------------------------------------------------------------------- */
  44static void
  45acpi_util_eval_error(acpi_handle h, acpi_string p, acpi_status s)
  46{
  47#ifdef ACPI_DEBUG_OUTPUT
  48        char prefix[80] = {'\0'};
  49        struct acpi_buffer buffer = {sizeof(prefix), prefix};
  50        acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);
  51        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",
  52                (char *) prefix, p, acpi_format_exception(s)));
  53#else
  54        return;
  55#endif
  56}
  57
  58acpi_status
  59acpi_extract_package(union acpi_object *package,
  60                     struct acpi_buffer *format, struct acpi_buffer *buffer)
  61{
  62        u32 size_required = 0;
  63        u32 tail_offset = 0;
  64        char *format_string = NULL;
  65        u32 format_count = 0;
  66        u32 i = 0;
  67        u8 *head = NULL;
  68        u8 *tail = NULL;
  69
  70
  71        if (!package || (package->type != ACPI_TYPE_PACKAGE)
  72            || (package->package.count < 1)) {
  73                printk(KERN_WARNING PREFIX "Invalid package argument\n");
  74                return AE_BAD_PARAMETER;
  75        }
  76
  77        if (!format || !format->pointer || (format->length < 1)) {
  78                printk(KERN_WARNING PREFIX "Invalid format argument\n");
  79                return AE_BAD_PARAMETER;
  80        }
  81
  82        if (!buffer) {
  83                printk(KERN_WARNING PREFIX "Invalid buffer argument\n");
  84                return AE_BAD_PARAMETER;
  85        }
  86
  87        format_count = (format->length / sizeof(char)) - 1;
  88        if (format_count > package->package.count) {
  89                printk(KERN_WARNING PREFIX "Format specifies more objects [%d]"
  90                              " than exist in package [%d].\n",
  91                              format_count, package->package.count);
  92                return AE_BAD_DATA;
  93        }
  94
  95        format_string = format->pointer;
  96
  97        /*
  98         * Calculate size_required.
  99         */
 100        for (i = 0; i < format_count; i++) {
 101
 102                union acpi_object *element = &(package->package.elements[i]);
 103
 104                if (!element) {
 105                        return AE_BAD_DATA;
 106                }
 107
 108                switch (element->type) {
 109
 110                case ACPI_TYPE_INTEGER:
 111                        switch (format_string[i]) {
 112                        case 'N':
 113                                size_required += sizeof(u64);
 114                                tail_offset += sizeof(u64);
 115                                break;
 116                        case 'S':
 117                                size_required +=
 118                                    sizeof(char *) + sizeof(u64) +
 119                                    sizeof(char);
 120                                tail_offset += sizeof(char *);
 121                                break;
 122                        default:
 123                                printk(KERN_WARNING PREFIX "Invalid package element"
 124                                              " [%d]: got number, expecing"
 125                                              " [%c]\n",
 126                                              i, format_string[i]);
 127                                return AE_BAD_DATA;
 128                                break;
 129                        }
 130                        break;
 131
 132                case ACPI_TYPE_STRING:
 133                case ACPI_TYPE_BUFFER:
 134                        switch (format_string[i]) {
 135                        case 'S':
 136                                size_required +=
 137                                    sizeof(char *) +
 138                                    (element->string.length * sizeof(char)) +
 139                                    sizeof(char);
 140                                tail_offset += sizeof(char *);
 141                                break;
 142                        case 'B':
 143                                size_required +=
 144                                    sizeof(u8 *) +
 145                                    (element->buffer.length * sizeof(u8));
 146                                tail_offset += sizeof(u8 *);
 147                                break;
 148                        default:
 149                                printk(KERN_WARNING PREFIX "Invalid package element"
 150                                              " [%d] got string/buffer,"
 151                                              " expecing [%c]\n",
 152                                              i, format_string[i]);
 153                                return AE_BAD_DATA;
 154                                break;
 155                        }
 156                        break;
 157
 158                case ACPI_TYPE_PACKAGE:
 159                default:
 160                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 161                                          "Found unsupported element at index=%d\n",
 162                                          i));
 163                        /* TBD: handle nested packages... */
 164                        return AE_SUPPORT;
 165                        break;
 166                }
 167        }
 168
 169        /*
 170         * Validate output buffer.
 171         */
 172        if (buffer->length < size_required) {
 173                buffer->length = size_required;
 174                return AE_BUFFER_OVERFLOW;
 175        } else if (buffer->length != size_required || !buffer->pointer) {
 176                return AE_BAD_PARAMETER;
 177        }
 178
 179        head = buffer->pointer;
 180        tail = buffer->pointer + tail_offset;
 181
 182        /*
 183         * Extract package data.
 184         */
 185        for (i = 0; i < format_count; i++) {
 186
 187                u8 **pointer = NULL;
 188                union acpi_object *element = &(package->package.elements[i]);
 189
 190                if (!element) {
 191                        return AE_BAD_DATA;
 192                }
 193
 194                switch (element->type) {
 195
 196                case ACPI_TYPE_INTEGER:
 197                        switch (format_string[i]) {
 198                        case 'N':
 199                                *((u64 *) head) =
 200                                    element->integer.value;
 201                                head += sizeof(u64);
 202                                break;
 203                        case 'S':
 204                                pointer = (u8 **) head;
 205                                *pointer = tail;
 206                                *((u64 *) tail) =
 207                                    element->integer.value;
 208                                head += sizeof(u64 *);
 209                                tail += sizeof(u64);
 210                                /* NULL terminate string */
 211                                *tail = (char)0;
 212                                tail += sizeof(char);
 213                                break;
 214                        default:
 215                                /* Should never get here */
 216                                break;
 217                        }
 218                        break;
 219
 220                case ACPI_TYPE_STRING:
 221                case ACPI_TYPE_BUFFER:
 222                        switch (format_string[i]) {
 223                        case 'S':
 224                                pointer = (u8 **) head;
 225                                *pointer = tail;
 226                                memcpy(tail, element->string.pointer,
 227                                       element->string.length);
 228                                head += sizeof(char *);
 229                                tail += element->string.length * sizeof(char);
 230                                /* NULL terminate string */
 231                                *tail = (char)0;
 232                                tail += sizeof(char);
 233                                break;
 234                        case 'B':
 235                                pointer = (u8 **) head;
 236                                *pointer = tail;
 237                                memcpy(tail, element->buffer.pointer,
 238                                       element->buffer.length);
 239                                head += sizeof(u8 *);
 240                                tail += element->buffer.length * sizeof(u8);
 241                                break;
 242                        default:
 243                                /* Should never get here */
 244                                break;
 245                        }
 246                        break;
 247
 248                case ACPI_TYPE_PACKAGE:
 249                        /* TBD: handle nested packages... */
 250                default:
 251                        /* Should never get here */
 252                        break;
 253                }
 254        }
 255
 256        return AE_OK;
 257}
 258
 259EXPORT_SYMBOL(acpi_extract_package);
 260
 261acpi_status
 262acpi_evaluate_integer(acpi_handle handle,
 263                      acpi_string pathname,
 264                      struct acpi_object_list *arguments, unsigned long long *data)
 265{
 266        acpi_status status = AE_OK;
 267        union acpi_object element;
 268        struct acpi_buffer buffer = { 0, NULL };
 269
 270        if (!data)
 271                return AE_BAD_PARAMETER;
 272
 273        buffer.length = sizeof(union acpi_object);
 274        buffer.pointer = &element;
 275        status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
 276        if (ACPI_FAILURE(status)) {
 277                acpi_util_eval_error(handle, pathname, status);
 278                return status;
 279        }
 280
 281        if (element.type != ACPI_TYPE_INTEGER) {
 282                acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
 283                return AE_BAD_DATA;
 284        }
 285
 286        *data = element.integer.value;
 287
 288        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data));
 289
 290        return AE_OK;
 291}
 292
 293EXPORT_SYMBOL(acpi_evaluate_integer);
 294
 295acpi_status
 296acpi_evaluate_reference(acpi_handle handle,
 297                        acpi_string pathname,
 298                        struct acpi_object_list *arguments,
 299                        struct acpi_handle_list *list)
 300{
 301        acpi_status status = AE_OK;
 302        union acpi_object *package = NULL;
 303        union acpi_object *element = NULL;
 304        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 305        u32 i = 0;
 306
 307
 308        if (!list) {
 309                return AE_BAD_PARAMETER;
 310        }
 311
 312        /* Evaluate object. */
 313
 314        status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
 315        if (ACPI_FAILURE(status))
 316                goto end;
 317
 318        package = buffer.pointer;
 319
 320        if ((buffer.length == 0) || !package) {
 321                printk(KERN_ERR PREFIX "No return object (len %X ptr %p)\n",
 322                            (unsigned)buffer.length, package);
 323                status = AE_BAD_DATA;
 324                acpi_util_eval_error(handle, pathname, status);
 325                goto end;
 326        }
 327        if (package->type != ACPI_TYPE_PACKAGE) {
 328                printk(KERN_ERR PREFIX "Expecting a [Package], found type %X\n",
 329                            package->type);
 330                status = AE_BAD_DATA;
 331                acpi_util_eval_error(handle, pathname, status);
 332                goto end;
 333        }
 334        if (!package->package.count) {
 335                printk(KERN_ERR PREFIX "[Package] has zero elements (%p)\n",
 336                            package);
 337                status = AE_BAD_DATA;
 338                acpi_util_eval_error(handle, pathname, status);
 339                goto end;
 340        }
 341
 342        if (package->package.count > ACPI_MAX_HANDLES) {
 343                return AE_NO_MEMORY;
 344        }
 345        list->count = package->package.count;
 346
 347        /* Extract package data. */
 348
 349        for (i = 0; i < list->count; i++) {
 350
 351                element = &(package->package.elements[i]);
 352
 353                if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
 354                        status = AE_BAD_DATA;
 355                        printk(KERN_ERR PREFIX
 356                                    "Expecting a [Reference] package element, found type %X\n",
 357                                    element->type);
 358                        acpi_util_eval_error(handle, pathname, status);
 359                        break;
 360                }
 361
 362                if (!element->reference.handle) {
 363                        printk(KERN_WARNING PREFIX "Invalid reference in"
 364                               " package %s\n", pathname);
 365                        status = AE_NULL_ENTRY;
 366                        break;
 367                }
 368                /* Get the  acpi_handle. */
 369
 370                list->handles[i] = element->reference.handle;
 371                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found reference [%p]\n",
 372                                  list->handles[i]));
 373        }
 374
 375      end:
 376        if (ACPI_FAILURE(status)) {
 377                list->count = 0;
 378                //kfree(list->handles);
 379        }
 380
 381        kfree(buffer.pointer);
 382
 383        return status;
 384}
 385
 386EXPORT_SYMBOL(acpi_evaluate_reference);
 387
 388acpi_status
 389acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld)
 390{
 391        acpi_status status;
 392        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 393        union acpi_object *output;
 394
 395        status = acpi_evaluate_object(handle, "_PLD", NULL, &buffer);
 396
 397        if (ACPI_FAILURE(status))
 398                return status;
 399
 400        output = buffer.pointer;
 401
 402        if (!output || output->type != ACPI_TYPE_PACKAGE
 403            || !output->package.count
 404            || output->package.elements[0].type != ACPI_TYPE_BUFFER
 405            || output->package.elements[0].buffer.length < ACPI_PLD_REV1_BUFFER_SIZE) {
 406                status = AE_TYPE;
 407                goto out;
 408        }
 409
 410        status = acpi_decode_pld_buffer(
 411                        output->package.elements[0].buffer.pointer,
 412                        output->package.elements[0].buffer.length,
 413                        pld);
 414
 415out:
 416        kfree(buffer.pointer);
 417        return status;
 418}
 419EXPORT_SYMBOL(acpi_get_physical_device_location);
 420
 421/**
 422 * acpi_evaluate_hotplug_ost: Evaluate _OST for hotplug operations
 423 * @handle: ACPI device handle
 424 * @source_event: source event code
 425 * @status_code: status code
 426 * @status_buf: optional detailed information (NULL if none)
 427 *
 428 * Evaluate _OST for hotplug operations. All ACPI hotplug handlers
 429 * must call this function when evaluating _OST for hotplug operations.
 430 * When the platform does not support _OST, this function has no effect.
 431 */
 432acpi_status
 433acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
 434                u32 status_code, struct acpi_buffer *status_buf)
 435{
 436#ifdef ACPI_HOTPLUG_OST
 437        union acpi_object params[3] = {
 438                {.type = ACPI_TYPE_INTEGER,},
 439                {.type = ACPI_TYPE_INTEGER,},
 440                {.type = ACPI_TYPE_BUFFER,}
 441        };
 442        struct acpi_object_list arg_list = {3, params};
 443        acpi_status status;
 444
 445        params[0].integer.value = source_event;
 446        params[1].integer.value = status_code;
 447        if (status_buf != NULL) {
 448                params[2].buffer.pointer = status_buf->pointer;
 449                params[2].buffer.length = status_buf->length;
 450        } else {
 451                params[2].buffer.pointer = NULL;
 452                params[2].buffer.length = 0;
 453        }
 454
 455        status = acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
 456        return status;
 457#else
 458        return AE_OK;
 459#endif
 460}
 461EXPORT_SYMBOL(acpi_evaluate_hotplug_ost);
 462
 463/**
 464 * acpi_handle_printk: Print message with ACPI prefix and object path
 465 *
 466 * This function is called through acpi_handle_<level> macros and prints
 467 * a message with ACPI prefix and object path.  This function acquires
 468 * the global namespace mutex to obtain an object path.  In interrupt
 469 * context, it shows the object path as <n/a>.
 470 */
 471void
 472acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...)
 473{
 474        struct va_format vaf;
 475        va_list args;
 476        struct acpi_buffer buffer = {
 477                .length = ACPI_ALLOCATE_BUFFER,
 478                .pointer = NULL
 479        };
 480        const char *path;
 481
 482        va_start(args, fmt);
 483        vaf.fmt = fmt;
 484        vaf.va = &args;
 485
 486        if (in_interrupt() ||
 487            acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK)
 488                path = "<n/a>";
 489        else
 490                path = buffer.pointer;
 491
 492        printk("%sACPI: %s: %pV", level, path, &vaf);
 493
 494        va_end(args);
 495        kfree(buffer.pointer);
 496}
 497EXPORT_SYMBOL(acpi_handle_printk);
 498