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 <linux/dynamic_debug.h>
  34
  35#include "internal.h"
  36
  37#define _COMPONENT              ACPI_BUS_COMPONENT
  38ACPI_MODULE_NAME("utils");
  39
  40/* --------------------------------------------------------------------------
  41                            Object Evaluation Helpers
  42   -------------------------------------------------------------------------- */
  43static void
  44acpi_util_eval_error(acpi_handle h, acpi_string p, acpi_status s)
  45{
  46#ifdef ACPI_DEBUG_OUTPUT
  47        char prefix[80] = {'\0'};
  48        struct acpi_buffer buffer = {sizeof(prefix), prefix};
  49        acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);
  50        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",
  51                (char *) prefix, p, acpi_format_exception(s)));
  52#else
  53        return;
  54#endif
  55}
  56
  57acpi_status
  58acpi_extract_package(union acpi_object *package,
  59                     struct acpi_buffer *format, struct acpi_buffer *buffer)
  60{
  61        u32 size_required = 0;
  62        u32 tail_offset = 0;
  63        char *format_string = NULL;
  64        u32 format_count = 0;
  65        u32 i = 0;
  66        u8 *head = NULL;
  67        u8 *tail = NULL;
  68
  69
  70        if (!package || (package->type != ACPI_TYPE_PACKAGE)
  71            || (package->package.count < 1)) {
  72                printk(KERN_WARNING PREFIX "Invalid package argument\n");
  73                return AE_BAD_PARAMETER;
  74        }
  75
  76        if (!format || !format->pointer || (format->length < 1)) {
  77                printk(KERN_WARNING PREFIX "Invalid format argument\n");
  78                return AE_BAD_PARAMETER;
  79        }
  80
  81        if (!buffer) {
  82                printk(KERN_WARNING PREFIX "Invalid buffer argument\n");
  83                return AE_BAD_PARAMETER;
  84        }
  85
  86        format_count = (format->length / sizeof(char)) - 1;
  87        if (format_count > package->package.count) {
  88                printk(KERN_WARNING PREFIX "Format specifies more objects [%d]"
  89                              " than exist in package [%d].\n",
  90                              format_count, package->package.count);
  91                return AE_BAD_DATA;
  92        }
  93
  94        format_string = format->pointer;
  95
  96        /*
  97         * Calculate size_required.
  98         */
  99        for (i = 0; i < format_count; i++) {
 100
 101                union acpi_object *element = &(package->package.elements[i]);
 102
 103                switch (element->type) {
 104
 105                case ACPI_TYPE_INTEGER:
 106                        switch (format_string[i]) {
 107                        case 'N':
 108                                size_required += sizeof(u64);
 109                                tail_offset += sizeof(u64);
 110                                break;
 111                        case 'S':
 112                                size_required +=
 113                                    sizeof(char *) + sizeof(u64) +
 114                                    sizeof(char);
 115                                tail_offset += sizeof(char *);
 116                                break;
 117                        default:
 118                                printk(KERN_WARNING PREFIX "Invalid package element"
 119                                              " [%d]: got number, expecting"
 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                                              " expecting [%c]\n",
 147                                              i, format_string[i]);
 148                                return AE_BAD_DATA;
 149                                break;
 150                        }
 151                        break;
 152                case ACPI_TYPE_LOCAL_REFERENCE:
 153                        switch (format_string[i]) {
 154                        case 'R':
 155                                size_required += sizeof(void *);
 156                                tail_offset += sizeof(void *);
 157                                break;
 158                        default:
 159                                printk(KERN_WARNING PREFIX "Invalid package element"
 160                                              " [%d] got reference,"
 161                                              " expecting [%c]\n",
 162                                              i, format_string[i]);
 163                                return AE_BAD_DATA;
 164                                break;
 165                        }
 166                        break;
 167
 168                case ACPI_TYPE_PACKAGE:
 169                default:
 170                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 171                                          "Found unsupported element at index=%d\n",
 172                                          i));
 173                        /* TBD: handle nested packages... */
 174                        return AE_SUPPORT;
 175                        break;
 176                }
 177        }
 178
 179        /*
 180         * Validate output buffer.
 181         */
 182        if (buffer->length == ACPI_ALLOCATE_BUFFER) {
 183                buffer->pointer = ACPI_ALLOCATE_ZEROED(size_required);
 184                if (!buffer->pointer)
 185                        return AE_NO_MEMORY;
 186                buffer->length = size_required;
 187        } else {
 188                if (buffer->length < size_required) {
 189                        buffer->length = size_required;
 190                        return AE_BUFFER_OVERFLOW;
 191                } else if (buffer->length != size_required ||
 192                           !buffer->pointer) {
 193                        return AE_BAD_PARAMETER;
 194                }
 195        }
 196
 197        head = buffer->pointer;
 198        tail = buffer->pointer + tail_offset;
 199
 200        /*
 201         * Extract package data.
 202         */
 203        for (i = 0; i < format_count; i++) {
 204
 205                u8 **pointer = NULL;
 206                union acpi_object *element = &(package->package.elements[i]);
 207
 208                if (!element) {
 209                        return AE_BAD_DATA;
 210                }
 211
 212                switch (element->type) {
 213
 214                case ACPI_TYPE_INTEGER:
 215                        switch (format_string[i]) {
 216                        case 'N':
 217                                *((u64 *) head) =
 218                                    element->integer.value;
 219                                head += sizeof(u64);
 220                                break;
 221                        case 'S':
 222                                pointer = (u8 **) head;
 223                                *pointer = tail;
 224                                *((u64 *) tail) =
 225                                    element->integer.value;
 226                                head += sizeof(u64 *);
 227                                tail += sizeof(u64);
 228                                /* NULL terminate string */
 229                                *tail = (char)0;
 230                                tail += sizeof(char);
 231                                break;
 232                        default:
 233                                /* Should never get here */
 234                                break;
 235                        }
 236                        break;
 237
 238                case ACPI_TYPE_STRING:
 239                case ACPI_TYPE_BUFFER:
 240                        switch (format_string[i]) {
 241                        case 'S':
 242                                pointer = (u8 **) head;
 243                                *pointer = tail;
 244                                memcpy(tail, element->string.pointer,
 245                                       element->string.length);
 246                                head += sizeof(char *);
 247                                tail += element->string.length * sizeof(char);
 248                                /* NULL terminate string */
 249                                *tail = (char)0;
 250                                tail += sizeof(char);
 251                                break;
 252                        case 'B':
 253                                pointer = (u8 **) head;
 254                                *pointer = tail;
 255                                memcpy(tail, element->buffer.pointer,
 256                                       element->buffer.length);
 257                                head += sizeof(u8 *);
 258                                tail += element->buffer.length * sizeof(u8);
 259                                break;
 260                        default:
 261                                /* Should never get here */
 262                                break;
 263                        }
 264                        break;
 265                case ACPI_TYPE_LOCAL_REFERENCE:
 266                        switch (format_string[i]) {
 267                        case 'R':
 268                                *(void **)head =
 269                                    (void *)element->reference.handle;
 270                                head += sizeof(void *);
 271                                break;
 272                        default:
 273                                /* Should never get here */
 274                                break;
 275                        }
 276                        break;
 277                case ACPI_TYPE_PACKAGE:
 278                        /* TBD: handle nested packages... */
 279                default:
 280                        /* Should never get here */
 281                        break;
 282                }
 283        }
 284
 285        return AE_OK;
 286}
 287
 288EXPORT_SYMBOL(acpi_extract_package);
 289
 290acpi_status
 291acpi_evaluate_integer(acpi_handle handle,
 292                      acpi_string pathname,
 293                      struct acpi_object_list *arguments, unsigned long long *data)
 294{
 295        acpi_status status = AE_OK;
 296        union acpi_object element;
 297        struct acpi_buffer buffer = { 0, NULL };
 298
 299        if (!data)
 300                return AE_BAD_PARAMETER;
 301
 302        buffer.length = sizeof(union acpi_object);
 303        buffer.pointer = &element;
 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        if (element.type != ACPI_TYPE_INTEGER) {
 311                acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
 312                return AE_BAD_DATA;
 313        }
 314
 315        *data = element.integer.value;
 316
 317        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data));
 318
 319        return AE_OK;
 320}
 321
 322EXPORT_SYMBOL(acpi_evaluate_integer);
 323
 324acpi_status
 325acpi_evaluate_reference(acpi_handle handle,
 326                        acpi_string pathname,
 327                        struct acpi_object_list *arguments,
 328                        struct acpi_handle_list *list)
 329{
 330        acpi_status status = AE_OK;
 331        union acpi_object *package = NULL;
 332        union acpi_object *element = NULL;
 333        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 334        u32 i = 0;
 335
 336
 337        if (!list) {
 338                return AE_BAD_PARAMETER;
 339        }
 340
 341        /* Evaluate object. */
 342
 343        status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
 344        if (ACPI_FAILURE(status))
 345                goto end;
 346
 347        package = buffer.pointer;
 348
 349        if ((buffer.length == 0) || !package) {
 350                printk(KERN_ERR PREFIX "No return object (len %X ptr %p)\n",
 351                            (unsigned)buffer.length, package);
 352                status = AE_BAD_DATA;
 353                acpi_util_eval_error(handle, pathname, status);
 354                goto end;
 355        }
 356        if (package->type != ACPI_TYPE_PACKAGE) {
 357                printk(KERN_ERR PREFIX "Expecting a [Package], found type %X\n",
 358                            package->type);
 359                status = AE_BAD_DATA;
 360                acpi_util_eval_error(handle, pathname, status);
 361                goto end;
 362        }
 363        if (!package->package.count) {
 364                printk(KERN_ERR PREFIX "[Package] has zero elements (%p)\n",
 365                            package);
 366                status = AE_BAD_DATA;
 367                acpi_util_eval_error(handle, pathname, status);
 368                goto end;
 369        }
 370
 371        if (package->package.count > ACPI_MAX_HANDLES) {
 372                return AE_NO_MEMORY;
 373        }
 374        list->count = package->package.count;
 375
 376        /* Extract package data. */
 377
 378        for (i = 0; i < list->count; i++) {
 379
 380                element = &(package->package.elements[i]);
 381
 382                if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
 383                        status = AE_BAD_DATA;
 384                        printk(KERN_ERR PREFIX
 385                                    "Expecting a [Reference] package element, found type %X\n",
 386                                    element->type);
 387                        acpi_util_eval_error(handle, pathname, status);
 388                        break;
 389                }
 390
 391                if (!element->reference.handle) {
 392                        printk(KERN_WARNING PREFIX "Invalid reference in"
 393                               " package %s\n", pathname);
 394                        status = AE_NULL_ENTRY;
 395                        break;
 396                }
 397                /* Get the  acpi_handle. */
 398
 399                list->handles[i] = element->reference.handle;
 400                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found reference [%p]\n",
 401                                  list->handles[i]));
 402        }
 403
 404      end:
 405        if (ACPI_FAILURE(status)) {
 406                list->count = 0;
 407                //kfree(list->handles);
 408        }
 409
 410        kfree(buffer.pointer);
 411
 412        return status;
 413}
 414
 415EXPORT_SYMBOL(acpi_evaluate_reference);
 416
 417acpi_status
 418acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld)
 419{
 420        acpi_status status;
 421        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 422        union acpi_object *output;
 423
 424        status = acpi_evaluate_object(handle, "_PLD", NULL, &buffer);
 425
 426        if (ACPI_FAILURE(status))
 427                return status;
 428
 429        output = buffer.pointer;
 430
 431        if (!output || output->type != ACPI_TYPE_PACKAGE
 432            || !output->package.count
 433            || output->package.elements[0].type != ACPI_TYPE_BUFFER
 434            || output->package.elements[0].buffer.length < ACPI_PLD_REV1_BUFFER_SIZE) {
 435                status = AE_TYPE;
 436                goto out;
 437        }
 438
 439        status = acpi_decode_pld_buffer(
 440                        output->package.elements[0].buffer.pointer,
 441                        output->package.elements[0].buffer.length,
 442                        pld);
 443
 444out:
 445        kfree(buffer.pointer);
 446        return status;
 447}
 448EXPORT_SYMBOL(acpi_get_physical_device_location);
 449
 450/**
 451 * acpi_evaluate_ost: Evaluate _OST for hotplug operations
 452 * @handle: ACPI device handle
 453 * @source_event: source event code
 454 * @status_code: status code
 455 * @status_buf: optional detailed information (NULL if none)
 456 *
 457 * Evaluate _OST for hotplug operations. All ACPI hotplug handlers
 458 * must call this function when evaluating _OST for hotplug operations.
 459 * When the platform does not support _OST, this function has no effect.
 460 */
 461acpi_status
 462acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code,
 463                  struct acpi_buffer *status_buf)
 464{
 465        union acpi_object params[3] = {
 466                {.type = ACPI_TYPE_INTEGER,},
 467                {.type = ACPI_TYPE_INTEGER,},
 468                {.type = ACPI_TYPE_BUFFER,}
 469        };
 470        struct acpi_object_list arg_list = {3, params};
 471
 472        params[0].integer.value = source_event;
 473        params[1].integer.value = status_code;
 474        if (status_buf != NULL) {
 475                params[2].buffer.pointer = status_buf->pointer;
 476                params[2].buffer.length = status_buf->length;
 477        } else {
 478                params[2].buffer.pointer = NULL;
 479                params[2].buffer.length = 0;
 480        }
 481
 482        return acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
 483}
 484EXPORT_SYMBOL(acpi_evaluate_ost);
 485
 486/**
 487 * acpi_handle_path: Return the object path of handle
 488 *
 489 * Caller must free the returned buffer
 490 */
 491static char *acpi_handle_path(acpi_handle handle)
 492{
 493        struct acpi_buffer buffer = {
 494                .length = ACPI_ALLOCATE_BUFFER,
 495                .pointer = NULL
 496        };
 497
 498        if (in_interrupt() ||
 499            acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK)
 500                return NULL;
 501        return buffer.pointer;
 502}
 503
 504/**
 505 * acpi_handle_printk: Print message with ACPI prefix and object path
 506 *
 507 * This function is called through acpi_handle_<level> macros and prints
 508 * a message with ACPI prefix and object path.  This function acquires
 509 * the global namespace mutex to obtain an object path.  In interrupt
 510 * context, it shows the object path as <n/a>.
 511 */
 512void
 513acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...)
 514{
 515        struct va_format vaf;
 516        va_list args;
 517        const char *path;
 518
 519        va_start(args, fmt);
 520        vaf.fmt = fmt;
 521        vaf.va = &args;
 522
 523        path = acpi_handle_path(handle);
 524        printk("%sACPI: %s: %pV", level, path ? path : "<n/a>" , &vaf);
 525
 526        va_end(args);
 527        kfree(path);
 528}
 529EXPORT_SYMBOL(acpi_handle_printk);
 530
 531#if defined(CONFIG_DYNAMIC_DEBUG)
 532/**
 533 * __acpi_handle_debug: pr_debug with ACPI prefix and object path
 534 *
 535 * This function is called through acpi_handle_debug macro and debug
 536 * prints a message with ACPI prefix and object path. This function
 537 * acquires the global namespace mutex to obtain an object path.  In
 538 * interrupt context, it shows the object path as <n/a>.
 539 */
 540void
 541__acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle,
 542                    const char *fmt, ...)
 543{
 544        struct va_format vaf;
 545        va_list args;
 546        const char *path;
 547
 548        va_start(args, fmt);
 549        vaf.fmt = fmt;
 550        vaf.va = &args;
 551
 552        path = acpi_handle_path(handle);
 553        __dynamic_pr_debug(descriptor, "ACPI: %s: %pV", path ? path : "<n/a>", &vaf);
 554
 555        va_end(args);
 556        kfree(path);
 557}
 558EXPORT_SYMBOL(__acpi_handle_debug);
 559#endif
 560
 561/**
 562 * acpi_has_method: Check whether @handle has a method named @name
 563 * @handle: ACPI device handle
 564 * @name: name of object or method
 565 *
 566 * Check whether @handle has a method named @name.
 567 */
 568bool acpi_has_method(acpi_handle handle, char *name)
 569{
 570        acpi_handle tmp;
 571
 572        return ACPI_SUCCESS(acpi_get_handle(handle, name, &tmp));
 573}
 574EXPORT_SYMBOL(acpi_has_method);
 575
 576acpi_status acpi_execute_simple_method(acpi_handle handle, char *method,
 577                                       u64 arg)
 578{
 579        union acpi_object obj = { .type = ACPI_TYPE_INTEGER };
 580        struct acpi_object_list arg_list = { .count = 1, .pointer = &obj, };
 581
 582        obj.integer.value = arg;
 583
 584        return acpi_evaluate_object(handle, method, &arg_list, NULL);
 585}
 586EXPORT_SYMBOL(acpi_execute_simple_method);
 587
 588/**
 589 * acpi_evaluate_ej0: Evaluate _EJ0 method for hotplug operations
 590 * @handle: ACPI device handle
 591 *
 592 * Evaluate device's _EJ0 method for hotplug operations.
 593 */
 594acpi_status acpi_evaluate_ej0(acpi_handle handle)
 595{
 596        acpi_status status;
 597
 598        status = acpi_execute_simple_method(handle, "_EJ0", 1);
 599        if (status == AE_NOT_FOUND)
 600                acpi_handle_warn(handle, "No _EJ0 support for device\n");
 601        else if (ACPI_FAILURE(status))
 602                acpi_handle_warn(handle, "Eject failed (0x%x)\n", status);
 603
 604        return status;
 605}
 606
 607/**
 608 * acpi_evaluate_lck: Evaluate _LCK method to lock/unlock device
 609 * @handle: ACPI device handle
 610 * @lock: lock device if non-zero, otherwise unlock device
 611 *
 612 * Evaluate device's _LCK method if present to lock/unlock device
 613 */
 614acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)
 615{
 616        acpi_status status;
 617
 618        status = acpi_execute_simple_method(handle, "_LCK", !!lock);
 619        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
 620                if (lock)
 621                        acpi_handle_warn(handle,
 622                                "Locking device failed (0x%x)\n", status);
 623                else
 624                        acpi_handle_warn(handle,
 625                                "Unlocking device failed (0x%x)\n", status);
 626        }
 627
 628        return status;
 629}
 630
 631/**
 632 * acpi_evaluate_dsm - evaluate device's _DSM method
 633 * @handle: ACPI device handle
 634 * @uuid: UUID of requested functions, should be 16 bytes
 635 * @rev: revision number of requested function
 636 * @func: requested function number
 637 * @argv4: the function specific parameter
 638 *
 639 * Evaluate device's _DSM method with specified UUID, revision id and
 640 * function number. Caller needs to free the returned object.
 641 *
 642 * Though ACPI defines the fourth parameter for _DSM should be a package,
 643 * some old BIOSes do expect a buffer or an integer etc.
 644 */
 645union acpi_object *
 646acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, int rev, int func,
 647                  union acpi_object *argv4)
 648{
 649        acpi_status ret;
 650        struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
 651        union acpi_object params[4];
 652        struct acpi_object_list input = {
 653                .count = 4,
 654                .pointer = params,
 655        };
 656
 657        params[0].type = ACPI_TYPE_BUFFER;
 658        params[0].buffer.length = 16;
 659        params[0].buffer.pointer = (char *)uuid;
 660        params[1].type = ACPI_TYPE_INTEGER;
 661        params[1].integer.value = rev;
 662        params[2].type = ACPI_TYPE_INTEGER;
 663        params[2].integer.value = func;
 664        if (argv4) {
 665                params[3] = *argv4;
 666        } else {
 667                params[3].type = ACPI_TYPE_PACKAGE;
 668                params[3].package.count = 0;
 669                params[3].package.elements = NULL;
 670        }
 671
 672        ret = acpi_evaluate_object(handle, "_DSM", &input, &buf);
 673        if (ACPI_SUCCESS(ret))
 674                return (union acpi_object *)buf.pointer;
 675
 676        if (ret != AE_NOT_FOUND)
 677                acpi_handle_warn(handle,
 678                                "failed to evaluate _DSM (0x%x)\n", ret);
 679
 680        return NULL;
 681}
 682EXPORT_SYMBOL(acpi_evaluate_dsm);
 683
 684/**
 685 * acpi_check_dsm - check if _DSM method supports requested functions.
 686 * @handle: ACPI device handle
 687 * @uuid: UUID of requested functions, should be 16 bytes at least
 688 * @rev: revision number of requested functions
 689 * @funcs: bitmap of requested functions
 690 *
 691 * Evaluate device's _DSM method to check whether it supports requested
 692 * functions. Currently only support 64 functions at maximum, should be
 693 * enough for now.
 694 */
 695bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs)
 696{
 697        int i;
 698        u64 mask = 0;
 699        union acpi_object *obj;
 700
 701        if (funcs == 0)
 702                return false;
 703
 704        obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL);
 705        if (!obj)
 706                return false;
 707
 708        /* For compatibility, old BIOSes may return an integer */
 709        if (obj->type == ACPI_TYPE_INTEGER)
 710                mask = obj->integer.value;
 711        else if (obj->type == ACPI_TYPE_BUFFER)
 712                for (i = 0; i < obj->buffer.length && i < 8; i++)
 713                        mask |= (((u8)obj->buffer.pointer[i]) << (i * 8));
 714        ACPI_FREE(obj);
 715
 716        /*
 717         * Bit 0 indicates whether there's support for any functions other than
 718         * function 0 for the specified UUID and revision.
 719         */
 720        if ((mask & 0x1) && (mask & funcs) == funcs)
 721                return true;
 722
 723        return false;
 724}
 725EXPORT_SYMBOL(acpi_check_dsm);
 726