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 <acpi/acpi_bus.h>
  32#include <acpi/acpi_drivers.h>
  33
  34#include "internal.h"
  35
  36#define _COMPONENT              ACPI_BUS_COMPONENT
  37ACPI_MODULE_NAME("utils");
  38
  39/* --------------------------------------------------------------------------
  40                            Object Evaluation Helpers
  41   -------------------------------------------------------------------------- */
  42static void
  43acpi_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
  56acpi_status
  57acpi_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
 257EXPORT_SYMBOL(acpi_extract_package);
 258
 259acpi_status
 260acpi_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
 291EXPORT_SYMBOL(acpi_evaluate_integer);
 292
 293acpi_status
 294acpi_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
 384EXPORT_SYMBOL(acpi_evaluate_reference);
 385
 386acpi_status
 387acpi_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);
 410out:
 411        kfree(buffer.pointer);
 412        return status;
 413}
 414EXPORT_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 */
 427acpi_status
 428acpi_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}
 456EXPORT_SYMBOL(acpi_evaluate_hotplug_ost);
 457
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.