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