linux/drivers/acpi/acpica/utids.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Module Name: utids - support for device Ids - HID, UID, CID
   4 *
   5 *****************************************************************************/
   6
   7/*
   8 * Copyright (C) 2000 - 2013, Intel Corp.
   9 * All rights reserved.
  10 *
  11 * Redistribution and use in source and binary forms, with or without
  12 * modification, are permitted provided that the following conditions
  13 * are met:
  14 * 1. Redistributions of source code must retain the above copyright
  15 *    notice, this list of conditions, and the following disclaimer,
  16 *    without modification.
  17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  18 *    substantially similar to the "NO WARRANTY" disclaimer below
  19 *    ("Disclaimer") and any redistribution must be conditioned upon
  20 *    including a substantially similar Disclaimer requirement for further
  21 *    binary redistribution.
  22 * 3. Neither the names of the above-listed copyright holders nor the names
  23 *    of any contributors may be used to endorse or promote products derived
  24 *    from this software without specific prior written permission.
  25 *
  26 * Alternatively, this software may be distributed under the terms of the
  27 * GNU General Public License ("GPL") version 2 as published by the Free
  28 * Software Foundation.
  29 *
  30 * NO WARRANTY
  31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  41 * POSSIBILITY OF SUCH DAMAGES.
  42 */
  43
  44#include <acpi/acpi.h>
  45#include "accommon.h"
  46#include "acinterp.h"
  47
  48#define _COMPONENT          ACPI_UTILITIES
  49ACPI_MODULE_NAME("utids")
  50
  51/*******************************************************************************
  52 *
  53 * FUNCTION:    acpi_ut_execute_HID
  54 *
  55 * PARAMETERS:  device_node         - Node for the device
  56 *              return_id           - Where the string HID is returned
  57 *
  58 * RETURN:      Status
  59 *
  60 * DESCRIPTION: Executes the _HID control method that returns the hardware
  61 *              ID of the device. The HID is either an 32-bit encoded EISAID
  62 *              Integer or a String. A string is always returned. An EISAID
  63 *              is converted to a string.
  64 *
  65 *              NOTE: Internal function, no parameter validation
  66 *
  67 ******************************************************************************/
  68acpi_status
  69acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
  70                    struct acpi_pnp_device_id **return_id)
  71{
  72        union acpi_operand_object *obj_desc;
  73        struct acpi_pnp_device_id *hid;
  74        u32 length;
  75        acpi_status status;
  76
  77        ACPI_FUNCTION_TRACE(ut_execute_HID);
  78
  79        status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID,
  80                                         ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
  81                                         &obj_desc);
  82        if (ACPI_FAILURE(status)) {
  83                return_ACPI_STATUS(status);
  84        }
  85
  86        /* Get the size of the String to be returned, includes null terminator */
  87
  88        if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
  89                length = ACPI_EISAID_STRING_SIZE;
  90        } else {
  91                length = obj_desc->string.length + 1;
  92        }
  93
  94        /* Allocate a buffer for the HID */
  95
  96        hid =
  97            ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) +
  98                                 (acpi_size) length);
  99        if (!hid) {
 100                status = AE_NO_MEMORY;
 101                goto cleanup;
 102        }
 103
 104        /* Area for the string starts after PNP_DEVICE_ID struct */
 105
 106        hid->string =
 107            ACPI_ADD_PTR(char, hid, sizeof(struct acpi_pnp_device_id));
 108
 109        /* Convert EISAID to a string or simply copy existing string */
 110
 111        if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
 112                acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value);
 113        } else {
 114                ACPI_STRCPY(hid->string, obj_desc->string.pointer);
 115        }
 116
 117        hid->length = length;
 118        *return_id = hid;
 119
 120cleanup:
 121
 122        /* On exit, we must delete the return object */
 123
 124        acpi_ut_remove_reference(obj_desc);
 125        return_ACPI_STATUS(status);
 126}
 127
 128/*******************************************************************************
 129 *
 130 * FUNCTION:    acpi_ut_execute_SUB
 131 *
 132 * PARAMETERS:  device_node         - Node for the device
 133 *              return_id           - Where the _SUB is returned
 134 *
 135 * RETURN:      Status
 136 *
 137 * DESCRIPTION: Executes the _SUB control method that returns the subsystem
 138 *              ID of the device. The _SUB value is always a string containing
 139 *              either a valid PNP or ACPI ID.
 140 *
 141 *              NOTE: Internal function, no parameter validation
 142 *
 143 ******************************************************************************/
 144
 145acpi_status
 146acpi_ut_execute_SUB(struct acpi_namespace_node *device_node,
 147                    struct acpi_pnp_device_id **return_id)
 148{
 149        union acpi_operand_object *obj_desc;
 150        struct acpi_pnp_device_id *sub;
 151        u32 length;
 152        acpi_status status;
 153
 154        ACPI_FUNCTION_TRACE(ut_execute_SUB);
 155
 156        status = acpi_ut_evaluate_object(device_node, METHOD_NAME__SUB,
 157                                         ACPI_BTYPE_STRING, &obj_desc);
 158        if (ACPI_FAILURE(status)) {
 159                return_ACPI_STATUS(status);
 160        }
 161
 162        /* Get the size of the String to be returned, includes null terminator */
 163
 164        length = obj_desc->string.length + 1;
 165
 166        /* Allocate a buffer for the SUB */
 167
 168        sub =
 169            ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) +
 170                                 (acpi_size) length);
 171        if (!sub) {
 172                status = AE_NO_MEMORY;
 173                goto cleanup;
 174        }
 175
 176        /* Area for the string starts after PNP_DEVICE_ID struct */
 177
 178        sub->string =
 179            ACPI_ADD_PTR(char, sub, sizeof(struct acpi_pnp_device_id));
 180
 181        /* Simply copy existing string */
 182
 183        ACPI_STRCPY(sub->string, obj_desc->string.pointer);
 184        sub->length = length;
 185        *return_id = sub;
 186
 187      cleanup:
 188
 189        /* On exit, we must delete the return object */
 190
 191        acpi_ut_remove_reference(obj_desc);
 192        return_ACPI_STATUS(status);
 193}
 194
 195/*******************************************************************************
 196 *
 197 * FUNCTION:    acpi_ut_execute_UID
 198 *
 199 * PARAMETERS:  device_node         - Node for the device
 200 *              return_id           - Where the string UID is returned
 201 *
 202 * RETURN:      Status
 203 *
 204 * DESCRIPTION: Executes the _UID control method that returns the unique
 205 *              ID of the device. The UID is either a 64-bit Integer (NOT an
 206 *              EISAID) or a string. Always returns a string. A 64-bit integer
 207 *              is converted to a decimal string.
 208 *
 209 *              NOTE: Internal function, no parameter validation
 210 *
 211 ******************************************************************************/
 212
 213acpi_status
 214acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
 215                    struct acpi_pnp_device_id **return_id)
 216{
 217        union acpi_operand_object *obj_desc;
 218        struct acpi_pnp_device_id *uid;
 219        u32 length;
 220        acpi_status status;
 221
 222        ACPI_FUNCTION_TRACE(ut_execute_UID);
 223
 224        status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID,
 225                                         ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
 226                                         &obj_desc);
 227        if (ACPI_FAILURE(status)) {
 228                return_ACPI_STATUS(status);
 229        }
 230
 231        /* Get the size of the String to be returned, includes null terminator */
 232
 233        if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
 234                length = ACPI_MAX64_DECIMAL_DIGITS + 1;
 235        } else {
 236                length = obj_desc->string.length + 1;
 237        }
 238
 239        /* Allocate a buffer for the UID */
 240
 241        uid =
 242            ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) +
 243                                 (acpi_size) length);
 244        if (!uid) {
 245                status = AE_NO_MEMORY;
 246                goto cleanup;
 247        }
 248
 249        /* Area for the string starts after PNP_DEVICE_ID struct */
 250
 251        uid->string =
 252            ACPI_ADD_PTR(char, uid, sizeof(struct acpi_pnp_device_id));
 253
 254        /* Convert an Integer to string, or just copy an existing string */
 255
 256        if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
 257                acpi_ex_integer_to_string(uid->string, obj_desc->integer.value);
 258        } else {
 259                ACPI_STRCPY(uid->string, obj_desc->string.pointer);
 260        }
 261
 262        uid->length = length;
 263        *return_id = uid;
 264
 265cleanup:
 266
 267        /* On exit, we must delete the return object */
 268
 269        acpi_ut_remove_reference(obj_desc);
 270        return_ACPI_STATUS(status);
 271}
 272
 273/*******************************************************************************
 274 *
 275 * FUNCTION:    acpi_ut_execute_CID
 276 *
 277 * PARAMETERS:  device_node         - Node for the device
 278 *              return_cid_list     - Where the CID list is returned
 279 *
 280 * RETURN:      Status, list of CID strings
 281 *
 282 * DESCRIPTION: Executes the _CID control method that returns one or more
 283 *              compatible hardware IDs for the device.
 284 *
 285 *              NOTE: Internal function, no parameter validation
 286 *
 287 * A _CID method can return either a single compatible ID or a package of
 288 * compatible IDs. Each compatible ID can be one of the following:
 289 * 1) Integer (32 bit compressed EISA ID) or
 290 * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss")
 291 *
 292 * The Integer CIDs are converted to string format by this function.
 293 *
 294 ******************************************************************************/
 295
 296acpi_status
 297acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
 298                    struct acpi_pnp_device_id_list **return_cid_list)
 299{
 300        union acpi_operand_object **cid_objects;
 301        union acpi_operand_object *obj_desc;
 302        struct acpi_pnp_device_id_list *cid_list;
 303        char *next_id_string;
 304        u32 string_area_size;
 305        u32 length;
 306        u32 cid_list_size;
 307        acpi_status status;
 308        u32 count;
 309        u32 i;
 310
 311        ACPI_FUNCTION_TRACE(ut_execute_CID);
 312
 313        /* Evaluate the _CID method for this device */
 314
 315        status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID,
 316                                         ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING
 317                                         | ACPI_BTYPE_PACKAGE, &obj_desc);
 318        if (ACPI_FAILURE(status)) {
 319                return_ACPI_STATUS(status);
 320        }
 321
 322        /*
 323         * Get the count and size of the returned _CIDs. _CID can return either
 324         * a Package of Integers/Strings or a single Integer or String.
 325         * Note: This section also validates that all CID elements are of the
 326         * correct type (Integer or String).
 327         */
 328        if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
 329                count = obj_desc->package.count;
 330                cid_objects = obj_desc->package.elements;
 331        } else {                /* Single Integer or String CID */
 332
 333                count = 1;
 334                cid_objects = &obj_desc;
 335        }
 336
 337        string_area_size = 0;
 338        for (i = 0; i < count; i++) {
 339
 340                /* String lengths include null terminator */
 341
 342                switch (cid_objects[i]->common.type) {
 343                case ACPI_TYPE_INTEGER:
 344
 345                        string_area_size += ACPI_EISAID_STRING_SIZE;
 346                        break;
 347
 348                case ACPI_TYPE_STRING:
 349
 350                        string_area_size += cid_objects[i]->string.length + 1;
 351                        break;
 352
 353                default:
 354
 355                        status = AE_TYPE;
 356                        goto cleanup;
 357                }
 358        }
 359
 360        /*
 361         * Now that we know the length of the CIDs, allocate return buffer:
 362         * 1) Size of the base structure +
 363         * 2) Size of the CID PNP_DEVICE_ID array +
 364         * 3) Size of the actual CID strings
 365         */
 366        cid_list_size = sizeof(struct acpi_pnp_device_id_list) +
 367            ((count - 1) * sizeof(struct acpi_pnp_device_id)) +
 368            string_area_size;
 369
 370        cid_list = ACPI_ALLOCATE_ZEROED(cid_list_size);
 371        if (!cid_list) {
 372                status = AE_NO_MEMORY;
 373                goto cleanup;
 374        }
 375
 376        /* Area for CID strings starts after the CID PNP_DEVICE_ID array */
 377
 378        next_id_string = ACPI_CAST_PTR(char, cid_list->ids) +
 379            ((acpi_size) count * sizeof(struct acpi_pnp_device_id));
 380
 381        /* Copy/convert the CIDs to the return buffer */
 382
 383        for (i = 0; i < count; i++) {
 384                if (cid_objects[i]->common.type == ACPI_TYPE_INTEGER) {
 385
 386                        /* Convert the Integer (EISAID) CID to a string */
 387
 388                        acpi_ex_eisa_id_to_string(next_id_string,
 389                                                  cid_objects[i]->integer.
 390                                                  value);
 391                        length = ACPI_EISAID_STRING_SIZE;
 392                } else {        /* ACPI_TYPE_STRING */
 393
 394                        /* Copy the String CID from the returned object */
 395
 396                        ACPI_STRCPY(next_id_string,
 397                                    cid_objects[i]->string.pointer);
 398                        length = cid_objects[i]->string.length + 1;
 399                }
 400
 401                cid_list->ids[i].string = next_id_string;
 402                cid_list->ids[i].length = length;
 403                next_id_string += length;
 404        }
 405
 406        /* Finish the CID list */
 407
 408        cid_list->count = count;
 409        cid_list->list_size = cid_list_size;
 410        *return_cid_list = cid_list;
 411
 412cleanup:
 413
 414        /* On exit, we must delete the _CID return object */
 415
 416        acpi_ut_remove_reference(obj_desc);
 417        return_ACPI_STATUS(status);
 418}
 419