linux/drivers/acpi/acpica/utosi.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Module Name: utosi - Support for the _OSI predefined control method
   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
  47#define _COMPONENT          ACPI_UTILITIES
  48ACPI_MODULE_NAME("utosi")
  49
  50/*
  51 * Strings supported by the _OSI predefined control method (which is
  52 * implemented internally within this module.)
  53 *
  54 * March 2009: Removed "Linux" as this host no longer wants to respond true
  55 * for this string. Basically, the only safe OS strings are windows-related
  56 * and in many or most cases represent the only test path within the
  57 * BIOS-provided ASL code.
  58 *
  59 * The last element of each entry is used to track the newest version of
  60 * Windows that the BIOS has requested.
  61 */
  62static struct acpi_interface_info acpi_default_supported_interfaces[] = {
  63        /* Operating System Vendor Strings */
  64
  65        {"Windows 2000", NULL, 0, ACPI_OSI_WIN_2000},   /* Windows 2000 */
  66        {"Windows 2001", NULL, 0, ACPI_OSI_WIN_XP},     /* Windows XP */
  67        {"Windows 2001 SP1", NULL, 0, ACPI_OSI_WIN_XP_SP1},     /* Windows XP SP1 */
  68        {"Windows 2001.1", NULL, 0, ACPI_OSI_WINSRV_2003},      /* Windows Server 2003 */
  69        {"Windows 2001 SP2", NULL, 0, ACPI_OSI_WIN_XP_SP2},     /* Windows XP SP2 */
  70        {"Windows 2001.1 SP1", NULL, 0, ACPI_OSI_WINSRV_2003_SP1},      /* Windows Server 2003 SP1 - Added 03/2006 */
  71        {"Windows 2006", NULL, 0, ACPI_OSI_WIN_VISTA},  /* Windows vista - Added 03/2006 */
  72        {"Windows 2006.1", NULL, 0, ACPI_OSI_WINSRV_2008},      /* Windows Server 2008 - Added 09/2009 */
  73        {"Windows 2006 SP1", NULL, 0, ACPI_OSI_WIN_VISTA_SP1},  /* Windows Vista SP1 - Added 09/2009 */
  74        {"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2},  /* Windows Vista SP2 - Added 09/2010 */
  75        {"Windows 2009", NULL, 0, ACPI_OSI_WIN_7},      /* Windows 7 and Server 2008 R2 - Added 09/2009 */
  76        {"Windows 2012", NULL, 0, ACPI_OSI_WIN_8},      /* Windows 8 and Server 2012 - Added 08/2012 */
  77        {"Windows 2013", NULL, 0, ACPI_OSI_WIN_8},      /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */
  78        {"Windows 2015", NULL, 0, ACPI_OSI_WIN_10},     /* Windows 10 - Added 03/2015 */
  79
  80        /* Feature Group Strings */
  81
  82        {"Extended Address Space Descriptor", NULL, 0, 0}
  83
  84        /*
  85         * All "optional" feature group strings (features that are implemented
  86         * by the host) should be dynamically added by the host via
  87         * acpi_install_interface and should not be manually added here.
  88         *
  89         * Examples of optional feature group strings:
  90         *
  91         * "Module Device"
  92         * "Processor Device"
  93         * "3.0 Thermal Model"
  94         * "3.0 _SCP Extensions"
  95         * "Processor Aggregator Device"
  96         */
  97};
  98
  99/*******************************************************************************
 100 *
 101 * FUNCTION:    acpi_ut_initialize_interfaces
 102 *
 103 * PARAMETERS:  None
 104 *
 105 * RETURN:      Status
 106 *
 107 * DESCRIPTION: Initialize the global _OSI supported interfaces list
 108 *
 109 ******************************************************************************/
 110
 111acpi_status acpi_ut_initialize_interfaces(void)
 112{
 113        acpi_status status;
 114        u32 i;
 115
 116        status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
 117        if (ACPI_FAILURE(status)) {
 118                return (status);
 119        }
 120
 121        acpi_gbl_supported_interfaces = acpi_default_supported_interfaces;
 122
 123        /* Link the static list of supported interfaces */
 124
 125        for (i = 0;
 126             i < (ACPI_ARRAY_LENGTH(acpi_default_supported_interfaces) - 1);
 127             i++) {
 128                acpi_default_supported_interfaces[i].next =
 129                    &acpi_default_supported_interfaces[(acpi_size) i + 1];
 130        }
 131
 132        acpi_os_release_mutex(acpi_gbl_osi_mutex);
 133        return (AE_OK);
 134}
 135
 136/*******************************************************************************
 137 *
 138 * FUNCTION:    acpi_ut_interface_terminate
 139 *
 140 * PARAMETERS:  None
 141 *
 142 * RETURN:      Status
 143 *
 144 * DESCRIPTION: Delete all interfaces in the global list. Sets
 145 *              acpi_gbl_supported_interfaces to NULL.
 146 *
 147 ******************************************************************************/
 148
 149acpi_status acpi_ut_interface_terminate(void)
 150{
 151        acpi_status status;
 152        struct acpi_interface_info *next_interface;
 153
 154        status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
 155        if (ACPI_FAILURE(status)) {
 156                return (status);
 157        }
 158
 159        next_interface = acpi_gbl_supported_interfaces;
 160        while (next_interface) {
 161                acpi_gbl_supported_interfaces = next_interface->next;
 162
 163                /* Only interfaces added at runtime can be freed */
 164
 165                if (next_interface->flags & ACPI_OSI_DYNAMIC) {
 166                        ACPI_FREE(next_interface->name);
 167                        ACPI_FREE(next_interface);
 168                }
 169
 170                next_interface = acpi_gbl_supported_interfaces;
 171        }
 172
 173        acpi_os_release_mutex(acpi_gbl_osi_mutex);
 174        return (AE_OK);
 175}
 176
 177/*******************************************************************************
 178 *
 179 * FUNCTION:    acpi_ut_install_interface
 180 *
 181 * PARAMETERS:  interface_name      - The interface to install
 182 *
 183 * RETURN:      Status
 184 *
 185 * DESCRIPTION: Install the interface into the global interface list.
 186 *              Caller MUST hold acpi_gbl_osi_mutex
 187 *
 188 ******************************************************************************/
 189
 190acpi_status acpi_ut_install_interface(acpi_string interface_name)
 191{
 192        struct acpi_interface_info *interface_info;
 193
 194        /* Allocate info block and space for the name string */
 195
 196        interface_info =
 197            ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_interface_info));
 198        if (!interface_info) {
 199                return (AE_NO_MEMORY);
 200        }
 201
 202        interface_info->name = ACPI_ALLOCATE_ZEROED(strlen(interface_name) + 1);
 203        if (!interface_info->name) {
 204                ACPI_FREE(interface_info);
 205                return (AE_NO_MEMORY);
 206        }
 207
 208        /* Initialize new info and insert at the head of the global list */
 209
 210        strcpy(interface_info->name, interface_name);
 211        interface_info->flags = ACPI_OSI_DYNAMIC;
 212        interface_info->next = acpi_gbl_supported_interfaces;
 213
 214        acpi_gbl_supported_interfaces = interface_info;
 215        return (AE_OK);
 216}
 217
 218/*******************************************************************************
 219 *
 220 * FUNCTION:    acpi_ut_remove_interface
 221 *
 222 * PARAMETERS:  interface_name      - The interface to remove
 223 *
 224 * RETURN:      Status
 225 *
 226 * DESCRIPTION: Remove the interface from the global interface list.
 227 *              Caller MUST hold acpi_gbl_osi_mutex
 228 *
 229 ******************************************************************************/
 230
 231acpi_status acpi_ut_remove_interface(acpi_string interface_name)
 232{
 233        struct acpi_interface_info *previous_interface;
 234        struct acpi_interface_info *next_interface;
 235
 236        previous_interface = next_interface = acpi_gbl_supported_interfaces;
 237        while (next_interface) {
 238                if (!strcmp(interface_name, next_interface->name)) {
 239
 240                        /* Found: name is in either the static list or was added at runtime */
 241
 242                        if (next_interface->flags & ACPI_OSI_DYNAMIC) {
 243
 244                                /* Interface was added dynamically, remove and free it */
 245
 246                                if (previous_interface == next_interface) {
 247                                        acpi_gbl_supported_interfaces =
 248                                            next_interface->next;
 249                                } else {
 250                                        previous_interface->next =
 251                                            next_interface->next;
 252                                }
 253
 254                                ACPI_FREE(next_interface->name);
 255                                ACPI_FREE(next_interface);
 256                        } else {
 257                                /*
 258                                 * Interface is in static list. If marked invalid, then it
 259                                 * does not actually exist. Else, mark it invalid.
 260                                 */
 261                                if (next_interface->flags & ACPI_OSI_INVALID) {
 262                                        return (AE_NOT_EXIST);
 263                                }
 264
 265                                next_interface->flags |= ACPI_OSI_INVALID;
 266                        }
 267
 268                        return (AE_OK);
 269                }
 270
 271                previous_interface = next_interface;
 272                next_interface = next_interface->next;
 273        }
 274
 275        /* Interface was not found */
 276
 277        return (AE_NOT_EXIST);
 278}
 279
 280/*******************************************************************************
 281 *
 282 * FUNCTION:    acpi_ut_get_interface
 283 *
 284 * PARAMETERS:  interface_name      - The interface to find
 285 *
 286 * RETURN:      struct acpi_interface_info if found. NULL if not found.
 287 *
 288 * DESCRIPTION: Search for the specified interface name in the global list.
 289 *              Caller MUST hold acpi_gbl_osi_mutex
 290 *
 291 ******************************************************************************/
 292
 293struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name)
 294{
 295        struct acpi_interface_info *next_interface;
 296
 297        next_interface = acpi_gbl_supported_interfaces;
 298        while (next_interface) {
 299                if (!strcmp(interface_name, next_interface->name)) {
 300                        return (next_interface);
 301                }
 302
 303                next_interface = next_interface->next;
 304        }
 305
 306        return (NULL);
 307}
 308
 309/*******************************************************************************
 310 *
 311 * FUNCTION:    acpi_ut_osi_implementation
 312 *
 313 * PARAMETERS:  walk_state          - Current walk state
 314 *
 315 * RETURN:      Status
 316 *
 317 * DESCRIPTION: Implementation of the _OSI predefined control method. When
 318 *              an invocation of _OSI is encountered in the system AML,
 319 *              control is transferred to this function.
 320 *
 321 ******************************************************************************/
 322
 323acpi_status acpi_ut_osi_implementation(struct acpi_walk_state * walk_state)
 324{
 325        union acpi_operand_object *string_desc;
 326        union acpi_operand_object *return_desc;
 327        struct acpi_interface_info *interface_info;
 328        acpi_interface_handler interface_handler;
 329        acpi_status status;
 330        u32 return_value;
 331
 332        ACPI_FUNCTION_TRACE(ut_osi_implementation);
 333
 334        /* Validate the string input argument (from the AML caller) */
 335
 336        string_desc = walk_state->arguments[0].object;
 337        if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) {
 338                return_ACPI_STATUS(AE_TYPE);
 339        }
 340
 341        /* Create a return object */
 342
 343        return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
 344        if (!return_desc) {
 345                return_ACPI_STATUS(AE_NO_MEMORY);
 346        }
 347
 348        /* Default return value is 0, NOT SUPPORTED */
 349
 350        return_value = 0;
 351        status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
 352        if (ACPI_FAILURE(status)) {
 353                acpi_ut_remove_reference(return_desc);
 354                return_ACPI_STATUS(status);
 355        }
 356
 357        /* Lookup the interface in the global _OSI list */
 358
 359        interface_info = acpi_ut_get_interface(string_desc->string.pointer);
 360        if (interface_info && !(interface_info->flags & ACPI_OSI_INVALID)) {
 361                /*
 362                 * The interface is supported.
 363                 * Update the osi_data if necessary. We keep track of the latest
 364                 * version of Windows that has been requested by the BIOS.
 365                 */
 366                if (interface_info->value > acpi_gbl_osi_data) {
 367                        acpi_gbl_osi_data = interface_info->value;
 368                }
 369
 370                return_value = ACPI_UINT32_MAX;
 371        }
 372
 373        acpi_os_release_mutex(acpi_gbl_osi_mutex);
 374
 375        /*
 376         * Invoke an optional _OSI interface handler. The host OS may wish
 377         * to do some interface-specific handling. For example, warn about
 378         * certain interfaces or override the true/false support value.
 379         */
 380        interface_handler = acpi_gbl_interface_handler;
 381        if (interface_handler) {
 382                return_value =
 383                    interface_handler(string_desc->string.pointer,
 384                                      return_value);
 385        }
 386
 387        ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,
 388                              "ACPI: BIOS _OSI(\"%s\") is %ssupported\n",
 389                              string_desc->string.pointer,
 390                              return_value == 0 ? "not " : ""));
 391
 392        /* Complete the return object */
 393
 394        return_desc->integer.value = return_value;
 395        walk_state->return_desc = return_desc;
 396        return_ACPI_STATUS(AE_OK);
 397}
 398