1 /******************************************************************************
   2  *
   3  * Module Name: evmisc - Miscellaneous event manager support functions
   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.h"
  45 #include "accommon.h"
  46 #include "acevents.h"
  47 #include "acnamesp.h"
  48 
  49 #define _COMPONENT          ACPI_EVENTS
  50         ACPI_MODULE_NAME    ("evmisc")
  51 
  52 
  53 /* Local prototypes */
  54 
  55 static void ACPI_SYSTEM_XFACE
  56 AcpiEvNotifyDispatch (
  57     void                    *Context);
  58 
  59 
  60 /*******************************************************************************
  61  *
  62  * FUNCTION:    AcpiEvIsNotifyObject
  63  *
  64  * PARAMETERS:  Node            - Node to check
  65  *
  66  * RETURN:      TRUE if notifies allowed on this object
  67  *
  68  * DESCRIPTION: Check type of node for a object that supports notifies.
  69  *
  70  *              TBD: This could be replaced by a flag bit in the node.
  71  *
  72  ******************************************************************************/
  73 
  74 BOOLEAN
  75 AcpiEvIsNotifyObject (
  76     ACPI_NAMESPACE_NODE     *Node)
  77 {
  78     switch (Node->Type)
  79     {
  80     case ACPI_TYPE_DEVICE:
  81     case ACPI_TYPE_PROCESSOR:
  82     case ACPI_TYPE_THERMAL:
  83         /*
  84          * These are the ONLY objects that can receive ACPI notifications
  85          */
  86         return (TRUE);
  87 
  88     default:
  89         return (FALSE);
  90     }
  91 }
  92 
  93 
  94 /*******************************************************************************
  95  *
  96  * FUNCTION:    AcpiEvQueueNotifyRequest
  97  *
  98  * PARAMETERS:  Node            - NS node for the notified object
  99  *              NotifyValue     - Value from the Notify() request
 100  *
 101  * RETURN:      Status
 102  *
 103  * DESCRIPTION: Dispatch a device notification event to a previously
 104  *              installed handler.
 105  *
 106  ******************************************************************************/
 107 
 108 ACPI_STATUS
 109 AcpiEvQueueNotifyRequest (
 110     ACPI_NAMESPACE_NODE     *Node,
 111     UINT32                  NotifyValue)
 112 {
 113     ACPI_OPERAND_OBJECT     *ObjDesc;
 114     ACPI_OPERAND_OBJECT     *HandlerObj = NULL;
 115     ACPI_GENERIC_STATE      *NotifyInfo;
 116     ACPI_STATUS             Status = AE_OK;
 117 
 118 
 119     ACPI_FUNCTION_NAME (EvQueueNotifyRequest);
 120 
 121 
 122     /*
 123      * For value 3 (Ejection Request), some device method may need to be run.
 124      * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need
 125      *   to be run.
 126      * For value 0x80 (Status Change) on the power button or sleep button,
 127      *   initiate soft-off or sleep operation?
 128      */
 129     ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
 130         "Dispatching Notify on [%4.4s] Node %p Value 0x%2.2X (%s)\n",
 131         AcpiUtGetNodeName (Node), Node, NotifyValue,
 132         AcpiUtGetNotifyName (NotifyValue)));
 133 
 134     /* Get the notify object attached to the NS Node */
 135 
 136     ObjDesc = AcpiNsGetAttachedObject (Node);
 137     if (ObjDesc)
 138     {
 139         /* We have the notify object, Get the right handler */
 140 
 141         switch (Node->Type)
 142         {
 143         /* Notify allowed only on these types */
 144 
 145         case ACPI_TYPE_DEVICE:
 146         case ACPI_TYPE_THERMAL:
 147         case ACPI_TYPE_PROCESSOR:
 148 
 149             if (NotifyValue <= ACPI_MAX_SYS_NOTIFY)
 150             {
 151                 HandlerObj = ObjDesc->CommonNotify.SystemNotify;
 152             }
 153             else
 154             {
 155                 HandlerObj = ObjDesc->CommonNotify.DeviceNotify;
 156             }
 157             break;
 158 
 159         default:
 160 
 161             /* All other types are not supported */
 162 
 163             return (AE_TYPE);
 164         }
 165     }
 166 
 167     /*
 168      * If there is any handler to run, schedule the dispatcher.
 169      * Check for:
 170      * 1) Global system notify handler
 171      * 2) Global device notify handler
 172      * 3) Per-device notify handler
 173      */
 174     if ((AcpiGbl_SystemNotify.Handler &&
 175             (NotifyValue <= ACPI_MAX_SYS_NOTIFY)) ||
 176         (AcpiGbl_DeviceNotify.Handler &&
 177             (NotifyValue > ACPI_MAX_SYS_NOTIFY))  ||
 178         HandlerObj)
 179     {
 180         NotifyInfo = AcpiUtCreateGenericState ();
 181         if (!NotifyInfo)
 182         {
 183             return (AE_NO_MEMORY);
 184         }
 185 
 186         if (!HandlerObj)
 187         {
 188             ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
 189                 "Executing system notify handler for Notify (%4.4s, %X) "
 190                 "node %p\n",
 191                 AcpiUtGetNodeName (Node), NotifyValue, Node));
 192         }
 193 
 194         NotifyInfo->Common.DescriptorType = ACPI_DESC_TYPE_STATE_NOTIFY;
 195         NotifyInfo->Notify.Node = Node;
 196         NotifyInfo->Notify.Value = (UINT16) NotifyValue;
 197         NotifyInfo->Notify.HandlerObj = HandlerObj;
 198 
 199         Status = AcpiOsExecute (
 200                     OSL_NOTIFY_HANDLER, AcpiEvNotifyDispatch, NotifyInfo);
 201         if (ACPI_FAILURE (Status))
 202         {
 203             AcpiUtDeleteGenericState (NotifyInfo);
 204         }
 205     }
 206     else
 207     {
 208         /* There is no notify handler (per-device or system) for this device */
 209 
 210         ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
 211             "No notify handler for Notify (%4.4s, %X) node %p\n",
 212             AcpiUtGetNodeName (Node), NotifyValue, Node));
 213     }
 214 
 215     return (Status);
 216 }
 217 
 218 
 219 /*******************************************************************************
 220  *
 221  * FUNCTION:    AcpiEvNotifyDispatch
 222  *
 223  * PARAMETERS:  Context         - To be passed to the notify handler
 224  *
 225  * RETURN:      None.
 226  *
 227  * DESCRIPTION: Dispatch a device notification event to a previously
 228  *              installed handler.
 229  *
 230  ******************************************************************************/
 231 
 232 static void ACPI_SYSTEM_XFACE
 233 AcpiEvNotifyDispatch (
 234     void                    *Context)
 235 {
 236     ACPI_GENERIC_STATE      *NotifyInfo = (ACPI_GENERIC_STATE *) Context;
 237     ACPI_NOTIFY_HANDLER     GlobalHandler = NULL;
 238     void                    *GlobalContext = NULL;
 239     ACPI_OPERAND_OBJECT     *HandlerObj;
 240 
 241 
 242     ACPI_FUNCTION_ENTRY ();
 243 
 244 
 245     /*
 246      * We will invoke a global notify handler if installed. This is done
 247      * _before_ we invoke the per-device handler attached to the device.
 248      */
 249     if (NotifyInfo->Notify.Value <= ACPI_MAX_SYS_NOTIFY)
 250     {
 251         /* Global system notification handler */
 252 
 253         if (AcpiGbl_SystemNotify.Handler)
 254         {
 255             GlobalHandler = AcpiGbl_SystemNotify.Handler;
 256             GlobalContext = AcpiGbl_SystemNotify.Context;
 257         }
 258     }
 259     else
 260     {
 261         /* Global driver notification handler */
 262 
 263         if (AcpiGbl_DeviceNotify.Handler)
 264         {
 265             GlobalHandler = AcpiGbl_DeviceNotify.Handler;
 266             GlobalContext = AcpiGbl_DeviceNotify.Context;
 267         }
 268     }
 269 
 270     /* Invoke the system handler first, if present */
 271 
 272     if (GlobalHandler)
 273     {
 274         GlobalHandler (NotifyInfo->Notify.Node, NotifyInfo->Notify.Value,
 275             GlobalContext);
 276     }
 277 
 278     /* Now invoke the per-device handler, if present */
 279 
 280     HandlerObj = NotifyInfo->Notify.HandlerObj;
 281     if (HandlerObj)
 282     {
 283         HandlerObj->Notify.Handler (NotifyInfo->Notify.Node,
 284             NotifyInfo->Notify.Value,
 285             HandlerObj->Notify.Context);
 286     }
 287 
 288     /* All done with the info object */
 289 
 290     AcpiUtDeleteGenericState (NotifyInfo);
 291 }
 292 
 293 
 294 /******************************************************************************
 295  *
 296  * FUNCTION:    AcpiEvTerminate
 297  *
 298  * PARAMETERS:  none
 299  *
 300  * RETURN:      none
 301  *
 302  * DESCRIPTION: Disable events and free memory allocated for table storage.
 303  *
 304  ******************************************************************************/
 305 
 306 void
 307 AcpiEvTerminate (
 308     void)
 309 {
 310     UINT32                  i;
 311     ACPI_STATUS             Status;
 312 
 313 
 314     ACPI_FUNCTION_TRACE (EvTerminate);
 315 
 316 
 317     if (AcpiGbl_EventsInitialized)
 318     {
 319         /*
 320          * Disable all event-related functionality. In all cases, on error,
 321          * print a message but obviously we don't abort.
 322          */
 323 
 324         /* Disable all fixed events */
 325 
 326         for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++)
 327         {
 328             Status = AcpiDisableEvent (i, 0);
 329             if (ACPI_FAILURE (Status))
 330             {
 331                 ACPI_ERROR ((AE_INFO,
 332                     "Could not disable fixed event %u", (UINT32) i));
 333             }
 334         }
 335 
 336         /* Disable all GPEs in all GPE blocks */
 337 
 338         Status = AcpiEvWalkGpeList (AcpiHwDisableGpeBlock, NULL);
 339 
 340         /* Remove SCI handler */
 341 
 342         Status = AcpiEvRemoveSciHandler ();
 343         if (ACPI_FAILURE(Status))
 344         {
 345             ACPI_ERROR ((AE_INFO,
 346                 "Could not remove SCI handler"));
 347         }
 348 
 349         Status = AcpiEvRemoveGlobalLockHandler ();
 350         if (ACPI_FAILURE(Status))
 351         {
 352             ACPI_ERROR ((AE_INFO,
 353                 "Could not remove Global Lock handler"));
 354         }
 355     }
 356 
 357     /* Deallocate all handler objects installed within GPE info structs */
 358 
 359     Status = AcpiEvWalkGpeList (AcpiEvDeleteGpeHandlers, NULL);
 360 
 361     /* Return to original mode if necessary */
 362 
 363     if (AcpiGbl_OriginalMode == ACPI_SYS_MODE_LEGACY)
 364     {
 365         Status = AcpiDisable ();
 366         if (ACPI_FAILURE (Status))
 367         {
 368             ACPI_WARNING ((AE_INFO, "AcpiDisable failed"));
 369         }
 370     }
 371     return_VOID;
 372 }