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/init.h>
  29#include <linux/types.h>
  30#include <acpi/acpi_bus.h>
  31#include <acpi/acpi_drivers.h>
  32
  33#include "internal.h"
  34
  35#define _COMPONENT              ACPI_BUS_COMPONENT
  36ACPI_MODULE_NAME("utils");
  37
  38/* --------------------------------------------------------------------------
  39                            Object Evaluation Helpers
  40   -------------------------------------------------------------------------- */
  41static void
  42acpi_util_eval_error(acpi_handle h, acpi_string p, acpi_status s)
  43{
  44#ifdef ACPI_DEBUG_OUTPUT
  45        char prefix[80] = {'\0'};
  46        struct acpi_buffer buffer = {sizeof(prefix), prefix};
  47        acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);
  48        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",
  49                (char *) prefix, p, acpi_format_exception(s)));
  50#else
  51        return;
  52#endif
  53}
  54
  55acpi_status
  56acpi_extract_package(union acpi_object *package,
  57                     struct acpi_buffer *format, struct acpi_buffer *buffer)
  58{
  59        u32 size_required = 0;
  60        u32 tail_offset = 0;
  61        char *format_string = NULL;
  62        u32 format_count = 0;
  63        u32 i = 0;
  64        u8 *head = NULL;
  65        u8 *tail = NULL;
  66
  67
  68        if (!package || (package->type != ACPI_TYPE_PACKAGE)
  69            || (package->package.count < 1)) {
  70                printk(KERN_WARNING PREFIX "Invalid package argument\n");
  71                return AE_BAD_PARAMETER;
  72        }
  73
  74        if (!format || !format->pointer || (format->length < 1)) {
  75                printk(KERN_WARNING PREFIX "Invalid format argument\n");
  76                return AE_BAD_PARAMETER;
  77        }
  78
  79        if (!buffer) {
  80                printk(KERN_WARNING PREFIX "Invalid buffer argument\n");
  81                return AE_BAD_PARAMETER;
  82        }
  83
  84        format_count = (format->length / sizeof(char)) - 1;
  85        if (format_count > package->package.count) {
  86                printk(KERN_WARNING PREFIX "Format specifies more objects [%d]"
  87                              " than exist in package [%d].\n",
  88                              format_count, package->package.count);
  89                return AE_BAD_DATA;
  90        }
  91
  92        format_string = format->pointer;
  93
  94        /*
  95         * Calculate size_required.
  96         */
  97        for (i = 0; i < format_count; i++) {
  98
  99                union acpi_object *element = &(package->package.elements[i]);
 100
 101                if (!element) {
 102                        return AE_BAD_DATA;
 103                }
 104
 105                switch (element->type) {
 106
 107                case ACPI_TYPE_INTEGER:
 108                        switch (format_string[i]) {
 109                        case 'N':
 110                                size_required += sizeof(acpi_integer);
 111                                tail_offset += sizeof(acpi_integer);
 112                                break;
 113                        case 'S':
 114                                size_required +=
 115                                    sizeof(char *) + sizeof(acpi_integer) +
 116                                    sizeof(char);
 117                                tail_offset += sizeof(char *);
 118                                break;
 119                        default:
 120                                printk(KERN_WARNING PREFIX "Invalid package element"
 121                                              " [%d]: got number, expecing"
 122                                              " [%c]\n",
 123                                              i, format_string[i]);
 124                                return AE_BAD_DATA;
 125                                break;
 126                        }
 127                        break;
 128
 129                case ACPI_TYPE_STRING:
 130                case ACPI_TYPE_BUFFER:
 131                        switch (format_string[i]) {
 132                        case 'S':
 133                                size_required +=
 134                                    sizeof(char *) +
 135                                    (element->string.length * sizeof(char)) +
 136                                    sizeof(char);
 137                                tail_offset += sizeof(char *);
 138                                break;
 139                        case 'B':
 140                                size_required +=
 141                                    sizeof(u8 *) +
 142                                    (element->buffer.length * sizeof(u8));
 143                                tail_offset += sizeof(u8 *);
 144                                break;
 145                        default:
 146                                printk(KERN_WARNING PREFIX "Invalid package element"
 147                                              " [%d] got string/buffer,"
 148                                              " expecing [%c]\n",
 149                                              i, format_string[i]);
 150                                return AE_BAD_DATA;
 151                                break;
 152                        }
 153                        break;
 154
 155                case ACPI_TYPE_PACKAGE:
 156                default:
 157                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 158                                          "Found unsupported element at index=%d\n",
 159                                          i));
 160                        /* TBD: handle nested packages... */
 161                        return AE_SUPPORT;
 162                        break;
 163                }
 164        }
 165
 166        /*
 167         * Validate output buffer.
 168         */
 169        if (buffer->length < size_required) {
 170                buffer->length = size_required;
 171                return AE_BUFFER_OVERFLOW;
 172        } else if (buffer->length != size_required || !buffer->pointer) {
 173                return AE_BAD_PARAMETER;
 174        }
 175
 176        head = buffer->pointer;
 177        tail = buffer->pointer + tail_offset;
 178
 179        /*
 180         * Extract package data.
 181         */
 182        for (i = 0; i < format_count; i++) {
 183
 184                u8 **pointer = NULL;
 185                union acpi_object *element = &(package->package.elements[i]);
 186
 187                if (!element) {
 188                        return AE_BAD_DATA;
 189                }
 190
 191                switch (element->type) {
 192
 193                case ACPI_TYPE_INTEGER:
 194                        switch (format_string[i]) {
 195                        case 'N':
 196                                *((acpi_integer *) head) =
 197                                    element->integer.value;
 198                                head += sizeof(acpi_integer);
 199                                break;
 200                        case 'S':
 201                                pointer = (u8 **) head;
 202                                *pointer = tail;
 203                                *((acpi_integer *) tail) =
 204                                    element->integer.value;
 205                                head += sizeof(acpi_integer *);
 206                                tail += sizeof(acpi_integer);
 207                                /* NULL terminate string */
 208                                *tail = (char)0;
 209                                tail += sizeof(char);
 210                                break;
 211                        default:
 212                                /* Should never get here */
 213                                break;
 214                        }
 215                        break;
 216
 217                case ACPI_TYPE_STRING:
 218                case ACPI_TYPE_BUFFER:
 219                        switch (format_string[i]) {
 220                        case 'S':
 221                                pointer = (u8 **) head;
 222                                *pointer = tail;
 223                                memcpy(tail, element->string.pointer,
 224                                       element->string.length);
 225                                head += sizeof(char *);
 226                                tail += element->string.length * sizeof(char);
 227                                /* NULL terminate string */
 228                                *tail = (char)0;
 229                                tail += sizeof(char);
 230                                break;
 231                        case 'B':
 232                                pointer = (u8 **) head;
 233                                *pointer = tail;
 234                                memcpy(tail, element->buffer.pointer,
 235                                       element->buffer.length);
 236                                head += sizeof(u8 *);
 237                                tail += element->buffer.length * sizeof(u8);
 238                                break;
 239                        default:
 240                                /* Should never get here */
 241                                break;
 242                        }
 243                        break;
 244
 245                case ACPI_TYPE_PACKAGE:
 246                        /* TBD: handle nested packages... */
 247                default:
 248                        /* Should never get here */
 249                        break;
 250                }
 251        }
 252
 253        return AE_OK;
 254}
 255
 256EXPORT_SYMBOL(acpi_extract_package);
 257
 258acpi_status
 259acpi_evaluate_integer(acpi_handle handle,
 260                      acpi_string pathname,
 261                      struct acpi_object_list *arguments, unsigned long long *data)
 262{
 263        acpi_status status = AE_OK;
 264        union acpi_object element;
 265        struct acpi_buffer buffer = { 0, NULL };
 266
 267        if (!data)
 268                return AE_BAD_PARAMETER;
 269
 270        buffer.length = sizeof(union acpi_object);
 271        buffer.pointer = &element;
 272        status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
 273        if (ACPI_FAILURE(status)) {
 274                acpi_util_eval_error(handle, pathname, status);
 275                return status;
 276        }
 277
 278        if (element.type != ACPI_TYPE_INTEGER) {
 279                acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
 280                return AE_BAD_DATA;
 281        }
 282
 283        *data = element.integer.value;
 284
 285        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data));
 286
 287        return AE_OK;
 288}
 289
 290EXPORT_SYMBOL(acpi_evaluate_integer);
 291
 292#if 0
 293acpi_status
 294acpi_evaluate_string(acpi_handle handle,
 295                     acpi_string pathname,
 296                     acpi_object_list * arguments, acpi_string * data)
 297{
 298        acpi_status status = AE_OK;
 299        acpi_object *element = NULL;
 300        acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 301
 302
 303        if (!data)
 304                return AE_BAD_PARAMETER;
 305
 306        status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
 307        if (ACPI_FAILURE(status)) {
 308                acpi_util_eval_error(handle, pathname, status);
 309                return status;
 310        }
 311
 312        element = (acpi_object *) buffer.pointer;
 313
 314        if ((element->type != ACPI_TYPE_STRING)
 315            || (element->type != ACPI_TYPE_BUFFER)
 316            || !element->string.length) {
 317                acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
 318                return AE_BAD_DATA;
 319        }
 320
 321        *data = kzalloc(element->string.length + 1, GFP_KERNEL);
 322        if (!data) {
 323                printk(KERN_ERR PREFIX "Memory allocation\n");
 324                return -ENOMEM;
 325        }
 326
 327        memcpy(*data, element->string.pointer, element->string.length);
 328
 329        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%s]\n", *data));
 330
 331        kfree(buffer.pointer);
 332
 333        return AE_OK;
 334}
 335#endif
 336
 337acpi_status
 338acpi_evaluate_reference(acpi_handle handle,
 339                        acpi_string pathname,
 340                        struct acpi_object_list *arguments,
 341                        struct acpi_handle_list *list)
 342{
 343        acpi_status status = AE_OK;
 344        union acpi_object *package = NULL;
 345        union acpi_object *element = NULL;
 346        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 347        u32 i = 0;
 348
 349
 350        if (!list) {
 351                return AE_BAD_PARAMETER;
 352        }
 353
 354        /* Evaluate object. */
 355
 356        status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
 357        if (ACPI_FAILURE(status))
 358                goto end;
 359
 360        package = buffer.pointer;
 361
 362        if ((buffer.length == 0) || !package) {
 363                printk(KERN_ERR PREFIX "No return object (len %X ptr %p)\n",
 364                            (unsigned)buffer.length, package);
 365                status = AE_BAD_DATA;
 366                acpi_util_eval_error(handle, pathname, status);
 367                goto end;
 368        }
 369        if (package->type != ACPI_TYPE_PACKAGE) {
 370                printk(KERN_ERR PREFIX "Expecting a [Package], found type %X\n",
 371                            package->type);
 372                status = AE_BAD_DATA;
 373                acpi_util_eval_error(handle, pathname, status);
 374                goto end;
 375        }
 376        if (!package->package.count) {
 377                printk(KERN_ERR PREFIX "[Package] has zero elements (%p)\n",
 378                            package);
 379                status = AE_BAD_DATA;
 380                acpi_util_eval_error(handle, pathname, status);
 381                goto end;
 382        }
 383
 384        if (package->package.count > ACPI_MAX_HANDLES) {
 385                return AE_NO_MEMORY;
 386        }
 387        list->count = package->package.count;
 388
 389        /* Extract package data. */
 390
 391        for (i = 0; i < list->count; i++) {
 392
 393                element = &(package->package.elements[i]);
 394
 395                if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
 396                        status = AE_BAD_DATA;
 397                        printk(KERN_ERR PREFIX
 398                                    "Expecting a [Reference] package element, found type %X\n",
 399                                    element->type);
 400                        acpi_util_eval_error(handle, pathname, status);
 401                        break;
 402                }
 403
 404                if (!element->reference.handle) {
 405                        printk(KERN_WARNING PREFIX "Invalid reference in"
 406                               " package %s\n", pathname);
 407                        status = AE_NULL_ENTRY;
 408                        break;
 409                }
 410                /* Get the  acpi_handle. */
 411
 412                list->handles[i] = element->reference.handle;
 413                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found reference [%p]\n",
 414                                  list->handles[i]));
 415        }
 416
 417      end:
 418        if (ACPI_FAILURE(status)) {
 419                list->count = 0;
 420                //kfree(list->handles);
 421        }
 422
 423        kfree(buffer.pointer);
 424
 425        return status;
 426}
 427
 428EXPORT_SYMBOL(acpi_evaluate_reference);
 429