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 - 2011, 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 acpica_device_id **return_id)
  71{
  72        union acpi_operand_object *obj_desc;
  73        struct acpica_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 acpica_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 DEVICE_ID struct */
 105
 106        hid->string = ACPI_ADD_PTR(char, hid, sizeof(struct acpica_device_id));
 107
 108        /* Convert EISAID to a string or simply copy existing string */
 109
 110        if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
 111                acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value);
 112        } else {
 113                ACPI_STRCPY(hid->string, obj_desc->string.pointer);
 114        }
 115
 116        hid->length = length;
 117        *return_id = hid;
 118
 119cleanup:
 120
 121        /* On exit, we must delete the return object */
 122
 123        acpi_ut_remove_reference(obj_desc);
 124        return_ACPI_STATUS(status);
 125}
 126
 127/*******************************************************************************
 128 *
 129 * FUNCTION:    acpi_ut_execute_UID
 130 *
 131 * PARAMETERS:  device_node         - Node for the device
 132 *              return_id           - Where the string UID is returned
 133 *
 134 * RETURN:      Status
 135 *
 136 * DESCRIPTION: Executes the _UID control method that returns the unique
 137 *              ID of the device. The UID is either a 64-bit Integer (NOT an
 138 *              EISAID) or a string. Always returns a string. A 64-bit integer
 139 *              is converted to a decimal string.
 140 *
 141 *              NOTE: Internal function, no parameter validation
 142 *
 143 ******************************************************************************/
 144
 145acpi_status
 146acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
 147                    struct acpica_device_id **return_id)
 148{
 149        union acpi_operand_object *obj_desc;
 150        struct acpica_device_id *uid;
 151        u32 length;
 152        acpi_status status;
 153
 154        ACPI_FUNCTION_TRACE(ut_execute_UID);
 155
 156        status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID,
 157                                         ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
 158                                         &obj_desc);
 159        if (ACPI_FAILURE(status)) {
 160                return_ACPI_STATUS(status);
 161        }
 162
 163        /* Get the size of the String to be returned, includes null terminator */
 164
 165        if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
 166                length = ACPI_MAX64_DECIMAL_DIGITS + 1;
 167        } else {
 168                length = obj_desc->string.length + 1;
 169        }
 170
 171        /* Allocate a buffer for the UID */
 172
 173        uid =
 174            ACPI_ALLOCATE_ZEROED(sizeof(struct acpica_device_id) +
 175                                 (acpi_size) length);
 176        if (!uid) {
 177                status = AE_NO_MEMORY;
 178                goto cleanup;
 179        }
 180
 181        /* Area for the string starts after DEVICE_ID struct */
 182
 183        uid->string = ACPI_ADD_PTR(char, uid, sizeof(struct acpica_device_id));
 184
 185        /* Convert an Integer to string, or just copy an existing string */
 186
 187        if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
 188                acpi_ex_integer_to_string(uid->string, obj_desc->integer.value);
 189        } else {
 190                ACPI_STRCPY(uid->string, obj_desc->string.pointer);
 191        }
 192
 193        uid->length = length;
 194        *return_id = uid;
 195
 196cleanup:
 197
 198        /* On exit, we must delete the return object */
 199
 200        acpi_ut_remove_reference(obj_desc);
 201        return_ACPI_STATUS(status);
 202}
 203
 204/*******************************************************************************
 205 *
 206 * FUNCTION:    acpi_ut_execute_CID
 207 *
 208 * PARAMETERS:  device_node         - Node for the device
 209 *              return_cid_list     - Where the CID list is returned
 210 *
 211 * RETURN:      Status, list of CID strings
 212 *
 213 * DESCRIPTION: Executes the _CID control method that returns one or more
 214 *              compatible hardware IDs for the device.
 215 *
 216 *              NOTE: Internal function, no parameter validation
 217 *
 218 * A _CID method can return either a single compatible ID or a package of
 219 * compatible IDs. Each compatible ID can be one of the following:
 220 * 1) Integer (32 bit compressed EISA ID) or
 221 * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss")
 222 *
 223 * The Integer CIDs are converted to string format by this function.
 224 *
 225 ******************************************************************************/
 226
 227acpi_status
 228acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
 229                    struct acpica_device_id_list **return_cid_list)
 230{
 231        union acpi_operand_object **cid_objects;
 232        union acpi_operand_object *obj_desc;
 233        struct acpica_device_id_list *cid_list;
 234        char *next_id_string;
 235        u32 string_area_size;
 236        u32 length;
 237        u32 cid_list_size;
 238        acpi_status status;
 239        u32 count;
 240        u32 i;
 241
 242        ACPI_FUNCTION_TRACE(ut_execute_CID);
 243
 244        /* Evaluate the _CID method for this device */
 245
 246        status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID,
 247                                         ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING
 248                                         | ACPI_BTYPE_PACKAGE, &obj_desc);
 249        if (ACPI_FAILURE(status)) {
 250                return_ACPI_STATUS(status);
 251        }
 252
 253        /*
 254         * Get the count and size of the returned _CIDs. _CID can return either
 255         * a Package of Integers/Strings or a single Integer or String.
 256         * Note: This section also validates that all CID elements are of the
 257         * correct type (Integer or String).
 258         */
 259        if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
 260                count = obj_desc->package.count;
 261                cid_objects = obj_desc->package.elements;
 262        } else {                /* Single Integer or String CID */
 263
 264                count = 1;
 265                cid_objects = &obj_desc;
 266        }
 267
 268        string_area_size = 0;
 269        for (i = 0; i < count; i++) {
 270
 271                /* String lengths include null terminator */
 272
 273                switch (cid_objects[i]->common.type) {
 274                case ACPI_TYPE_INTEGER:
 275                        string_area_size += ACPI_EISAID_STRING_SIZE;
 276                        break;
 277
 278                case ACPI_TYPE_STRING:
 279                        string_area_size += cid_objects[i]->string.length + 1;
 280                        break;
 281
 282                default:
 283                        status = AE_TYPE;
 284                        goto cleanup;
 285                }
 286        }
 287
 288        /*
 289         * Now that we know the length of the CIDs, allocate return buffer:
 290         * 1) Size of the base structure +
 291         * 2) Size of the CID DEVICE_ID array +
 292         * 3) Size of the actual CID strings
 293         */
 294        cid_list_size = sizeof(struct acpica_device_id_list) +
 295            ((count - 1) * sizeof(struct acpica_device_id)) + string_area_size;
 296
 297        cid_list = ACPI_ALLOCATE_ZEROED(cid_list_size);
 298        if (!cid_list) {
 299                status = AE_NO_MEMORY;
 300                goto cleanup;
 301        }
 302
 303        /* Area for CID strings starts after the CID DEVICE_ID array */
 304
 305        next_id_string = ACPI_CAST_PTR(char, cid_list->ids) +
 306            ((acpi_size) count * sizeof(struct acpica_device_id));
 307
 308        /* Copy/convert the CIDs to the return buffer */
 309
 310        for (i = 0; i < count; i++) {
 311                if (cid_objects[i]->common.type == ACPI_TYPE_INTEGER) {
 312
 313                        /* Convert the Integer (EISAID) CID to a string */
 314
 315                        acpi_ex_eisa_id_to_string(next_id_string,
 316                                                  cid_objects[i]->integer.
 317                                                  value);
 318                        length = ACPI_EISAID_STRING_SIZE;
 319                } else {        /* ACPI_TYPE_STRING */
 320
 321                        /* Copy the String CID from the returned object */
 322
 323                        ACPI_STRCPY(next_id_string,
 324                                    cid_objects[i]->string.pointer);
 325                        length = cid_objects[i]->string.length + 1;
 326                }
 327
 328                cid_list->ids[i].string = next_id_string;
 329                cid_list->ids[i].length = length;
 330                next_id_string += length;
 331        }
 332
 333        /* Finish the CID list */
 334
 335        cid_list->count = count;
 336        cid_list->list_size = cid_list_size;
 337        *return_cid_list = cid_list;
 338
 339cleanup:
 340
 341        /* On exit, we must delete the _CID return object */
 342
 343        acpi_ut_remove_reference(obj_desc);
 344        return_ACPI_STATUS(status);
 345}
 346