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