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