linux/drivers/acpi/acpica/evmisc.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Module Name: evmisc - Miscellaneous event manager support functions
   4 *
   5 *****************************************************************************/
   6
   7/*
   8 * Copyright (C) 2000 - 2015, 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 "acevents.h"
  47#include "acnamesp.h"
  48
  49#define _COMPONENT          ACPI_EVENTS
  50ACPI_MODULE_NAME("evmisc")
  51
  52/* Local prototypes */
  53static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
  54
  55/*******************************************************************************
  56 *
  57 * FUNCTION:    acpi_ev_is_notify_object
  58 *
  59 * PARAMETERS:  node            - Node to check
  60 *
  61 * RETURN:      TRUE if notifies allowed on this object
  62 *
  63 * DESCRIPTION: Check type of node for a object that supports notifies.
  64 *
  65 *              TBD: This could be replaced by a flag bit in the node.
  66 *
  67 ******************************************************************************/
  68
  69u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node)
  70{
  71        switch (node->type) {
  72        case ACPI_TYPE_DEVICE:
  73        case ACPI_TYPE_PROCESSOR:
  74        case ACPI_TYPE_THERMAL:
  75                /*
  76                 * These are the ONLY objects that can receive ACPI notifications
  77                 */
  78                return (TRUE);
  79
  80        default:
  81
  82                return (FALSE);
  83        }
  84}
  85
  86/*******************************************************************************
  87 *
  88 * FUNCTION:    acpi_ev_queue_notify_request
  89 *
  90 * PARAMETERS:  node            - NS node for the notified object
  91 *              notify_value    - Value from the Notify() request
  92 *
  93 * RETURN:      Status
  94 *
  95 * DESCRIPTION: Dispatch a device notification event to a previously
  96 *              installed handler.
  97 *
  98 ******************************************************************************/
  99
 100acpi_status
 101acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
 102                             u32 notify_value)
 103{
 104        union acpi_operand_object *obj_desc;
 105        union acpi_operand_object *handler_list_head = NULL;
 106        union acpi_generic_state *info;
 107        u8 handler_list_id = 0;
 108        acpi_status status = AE_OK;
 109
 110        ACPI_FUNCTION_NAME(ev_queue_notify_request);
 111
 112        /* Are Notifies allowed on this object? */
 113
 114        if (!acpi_ev_is_notify_object(node)) {
 115                return (AE_TYPE);
 116        }
 117
 118        /* Get the correct notify list type (System or Device) */
 119
 120        if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
 121                handler_list_id = ACPI_SYSTEM_HANDLER_LIST;
 122        } else {
 123                handler_list_id = ACPI_DEVICE_HANDLER_LIST;
 124        }
 125
 126        /* Get the notify object attached to the namespace Node */
 127
 128        obj_desc = acpi_ns_get_attached_object(node);
 129        if (obj_desc) {
 130
 131                /* We have an attached object, Get the correct handler list */
 132
 133                handler_list_head =
 134                    obj_desc->common_notify.notify_list[handler_list_id];
 135        }
 136
 137        /*
 138         * If there is no notify handler (Global or Local)
 139         * for this object, just ignore the notify
 140         */
 141        if (!acpi_gbl_global_notify[handler_list_id].handler
 142            && !handler_list_head) {
 143                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 144                                  "No notify handler for Notify, ignoring (%4.4s, %X) node %p\n",
 145                                  acpi_ut_get_node_name(node), notify_value,
 146                                  node));
 147
 148                return (AE_OK);
 149        }
 150
 151        /* Setup notify info and schedule the notify dispatcher */
 152
 153        info = acpi_ut_create_generic_state();
 154        if (!info) {
 155                return (AE_NO_MEMORY);
 156        }
 157
 158        info->common.descriptor_type = ACPI_DESC_TYPE_STATE_NOTIFY;
 159
 160        info->notify.node = node;
 161        info->notify.value = (u16)notify_value;
 162        info->notify.handler_list_id = handler_list_id;
 163        info->notify.handler_list_head = handler_list_head;
 164        info->notify.global = &acpi_gbl_global_notify[handler_list_id];
 165
 166        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 167                          "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
 168                          acpi_ut_get_node_name(node),
 169                          acpi_ut_get_type_name(node->type), notify_value,
 170                          acpi_ut_get_notify_name(notify_value, ACPI_TYPE_ANY),
 171                          node));
 172
 173        status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
 174                                 info);
 175        if (ACPI_FAILURE(status)) {
 176                acpi_ut_delete_generic_state(info);
 177        }
 178
 179        return (status);
 180}
 181
 182/*******************************************************************************
 183 *
 184 * FUNCTION:    acpi_ev_notify_dispatch
 185 *
 186 * PARAMETERS:  context         - To be passed to the notify handler
 187 *
 188 * RETURN:      None.
 189 *
 190 * DESCRIPTION: Dispatch a device notification event to a previously
 191 *              installed handler.
 192 *
 193 ******************************************************************************/
 194
 195static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
 196{
 197        union acpi_generic_state *info = (union acpi_generic_state *)context;
 198        union acpi_operand_object *handler_obj;
 199
 200        ACPI_FUNCTION_ENTRY();
 201
 202        /* Invoke a global notify handler if installed */
 203
 204        if (info->notify.global->handler) {
 205                info->notify.global->handler(info->notify.node,
 206                                             info->notify.value,
 207                                             info->notify.global->context);
 208        }
 209
 210        /* Now invoke the local notify handler(s) if any are installed */
 211
 212        handler_obj = info->notify.handler_list_head;
 213        while (handler_obj) {
 214                handler_obj->notify.handler(info->notify.node,
 215                                            info->notify.value,
 216                                            handler_obj->notify.context);
 217
 218                handler_obj =
 219                    handler_obj->notify.next[info->notify.handler_list_id];
 220        }
 221
 222        /* All done with the info object */
 223
 224        acpi_ut_delete_generic_state(info);
 225}
 226
 227#if (!ACPI_REDUCED_HARDWARE)
 228/******************************************************************************
 229 *
 230 * FUNCTION:    acpi_ev_terminate
 231 *
 232 * PARAMETERS:  none
 233 *
 234 * RETURN:      none
 235 *
 236 * DESCRIPTION: Disable events and free memory allocated for table storage.
 237 *
 238 ******************************************************************************/
 239
 240void acpi_ev_terminate(void)
 241{
 242        u32 i;
 243        acpi_status status;
 244
 245        ACPI_FUNCTION_TRACE(ev_terminate);
 246
 247        if (acpi_gbl_events_initialized) {
 248                /*
 249                 * Disable all event-related functionality. In all cases, on error,
 250                 * print a message but obviously we don't abort.
 251                 */
 252
 253                /* Disable all fixed events */
 254
 255                for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
 256                        status = acpi_disable_event(i, 0);
 257                        if (ACPI_FAILURE(status)) {
 258                                ACPI_ERROR((AE_INFO,
 259                                            "Could not disable fixed event %u",
 260                                            (u32) i));
 261                        }
 262                }
 263
 264                /* Disable all GPEs in all GPE blocks */
 265
 266                status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL);
 267
 268                status = acpi_ev_remove_global_lock_handler();
 269                if (ACPI_FAILURE(status)) {
 270                        ACPI_ERROR((AE_INFO,
 271                                    "Could not remove Global Lock handler"));
 272                }
 273
 274                acpi_gbl_events_initialized = FALSE;
 275        }
 276
 277        /* Remove SCI handlers */
 278
 279        status = acpi_ev_remove_all_sci_handlers();
 280        if (ACPI_FAILURE(status)) {
 281                ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
 282        }
 283
 284        /* Deallocate all handler objects installed within GPE info structs */
 285
 286        status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers, NULL);
 287
 288        /* Return to original mode if necessary */
 289
 290        if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) {
 291                status = acpi_disable();
 292                if (ACPI_FAILURE(status)) {
 293                        ACPI_WARNING((AE_INFO, "AcpiDisable failed"));
 294                }
 295        }
 296        return_VOID;
 297}
 298
 299#endif                          /* !ACPI_REDUCED_HARDWARE */
 300