1 | /****************************************************************************** |
2 | * |
3 | * Module Name: evmisc - Miscellaneous event manager support functions |
4 | * |
5 | *****************************************************************************/ |
6 | |
7 | /* |
8 | * Copyright (C) 2000 - 2016, 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 | |
79 | switch (Node->Type) |
80 | { |
81 | case ACPI_TYPE_DEVICE: |
82 | case ACPI_TYPE_PROCESSOR: |
83 | case ACPI_TYPE_THERMAL: |
84 | /* |
85 | * These are the ONLY objects that can receive ACPI notifications |
86 | */ |
87 | return (TRUE); |
88 | |
89 | default: |
90 | |
91 | return (FALSE); |
92 | } |
93 | } |
94 | |
95 | |
96 | /******************************************************************************* |
97 | * |
98 | * FUNCTION: AcpiEvQueueNotifyRequest |
99 | * |
100 | * PARAMETERS: Node - NS node for the notified object |
101 | * NotifyValue - Value from the Notify() request |
102 | * |
103 | * RETURN: Status |
104 | * |
105 | * DESCRIPTION: Dispatch a device notification event to a previously |
106 | * installed handler. |
107 | * |
108 | ******************************************************************************/ |
109 | |
110 | ACPI_STATUS |
111 | AcpiEvQueueNotifyRequest ( |
112 | ACPI_NAMESPACE_NODE *Node, |
113 | UINT32 NotifyValue) |
114 | { |
115 | ACPI_OPERAND_OBJECT *ObjDesc; |
116 | ACPI_OPERAND_OBJECT *HandlerListHead = NULL; |
117 | ACPI_GENERIC_STATE *Info; |
118 | UINT8 HandlerListId = 0; |
119 | ACPI_STATUS Status = AE_OK; |
120 | |
121 | |
122 | ACPI_FUNCTION_NAME (EvQueueNotifyRequest); |
123 | |
124 | |
125 | /* Are Notifies allowed on this object? */ |
126 | |
127 | if (!AcpiEvIsNotifyObject (Node)) |
128 | { |
129 | return (AE_TYPE); |
130 | } |
131 | |
132 | /* Get the correct notify list type (System or Device) */ |
133 | |
134 | if (NotifyValue <= ACPI_MAX_SYS_NOTIFY) |
135 | { |
136 | HandlerListId = ACPI_SYSTEM_HANDLER_LIST; |
137 | } |
138 | else |
139 | { |
140 | HandlerListId = ACPI_DEVICE_HANDLER_LIST; |
141 | } |
142 | |
143 | /* Get the notify object attached to the namespace Node */ |
144 | |
145 | ObjDesc = AcpiNsGetAttachedObject (Node); |
146 | if (ObjDesc) |
147 | { |
148 | /* We have an attached object, Get the correct handler list */ |
149 | |
150 | HandlerListHead = ObjDesc->CommonNotify.NotifyList[HandlerListId]; |
151 | } |
152 | |
153 | /* |
154 | * If there is no notify handler (Global or Local) |
155 | * for this object, just ignore the notify |
156 | */ |
157 | if (!AcpiGbl_GlobalNotify[HandlerListId].Handler && !HandlerListHead) |
158 | { |
159 | ACPI_DEBUG_PRINT ((ACPI_DB_INFO, |
160 | "No notify handler for Notify, ignoring (%4.4s, %X) node %p\n" , |
161 | AcpiUtGetNodeName (Node), NotifyValue, Node)); |
162 | |
163 | return (AE_OK); |
164 | } |
165 | |
166 | /* Setup notify info and schedule the notify dispatcher */ |
167 | |
168 | Info = AcpiUtCreateGenericState (); |
169 | if (!Info) |
170 | { |
171 | return (AE_NO_MEMORY); |
172 | } |
173 | |
174 | Info->Common.DescriptorType = ACPI_DESC_TYPE_STATE_NOTIFY; |
175 | |
176 | Info->Notify.Node = Node; |
177 | Info->Notify.Value = (UINT16) NotifyValue; |
178 | Info->Notify.HandlerListId = HandlerListId; |
179 | Info->Notify.HandlerListHead = HandlerListHead; |
180 | Info->Notify.Global = &AcpiGbl_GlobalNotify[HandlerListId]; |
181 | |
182 | ACPI_DEBUG_PRINT ((ACPI_DB_INFO, |
183 | "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n" , |
184 | AcpiUtGetNodeName (Node), AcpiUtGetTypeName (Node->Type), |
185 | NotifyValue, AcpiUtGetNotifyName (NotifyValue, ACPI_TYPE_ANY), Node)); |
186 | |
187 | Status = AcpiOsExecute (OSL_NOTIFY_HANDLER, |
188 | AcpiEvNotifyDispatch, Info); |
189 | if (ACPI_FAILURE (Status)) |
190 | { |
191 | AcpiUtDeleteGenericState (Info); |
192 | } |
193 | |
194 | return (Status); |
195 | } |
196 | |
197 | |
198 | /******************************************************************************* |
199 | * |
200 | * FUNCTION: AcpiEvNotifyDispatch |
201 | * |
202 | * PARAMETERS: Context - To be passed to the notify handler |
203 | * |
204 | * RETURN: None. |
205 | * |
206 | * DESCRIPTION: Dispatch a device notification event to a previously |
207 | * installed handler. |
208 | * |
209 | ******************************************************************************/ |
210 | |
211 | static void ACPI_SYSTEM_XFACE |
212 | AcpiEvNotifyDispatch ( |
213 | void *Context) |
214 | { |
215 | ACPI_GENERIC_STATE *Info = (ACPI_GENERIC_STATE *) Context; |
216 | ACPI_OPERAND_OBJECT *HandlerObj; |
217 | |
218 | |
219 | ACPI_FUNCTION_ENTRY (); |
220 | |
221 | |
222 | /* Invoke a global notify handler if installed */ |
223 | |
224 | if (Info->Notify.Global->Handler) |
225 | { |
226 | Info->Notify.Global->Handler (Info->Notify.Node, |
227 | Info->Notify.Value, |
228 | Info->Notify.Global->Context); |
229 | } |
230 | |
231 | /* Now invoke the local notify handler(s) if any are installed */ |
232 | |
233 | HandlerObj = Info->Notify.HandlerListHead; |
234 | while (HandlerObj) |
235 | { |
236 | HandlerObj->Notify.Handler (Info->Notify.Node, |
237 | Info->Notify.Value, |
238 | HandlerObj->Notify.Context); |
239 | |
240 | HandlerObj = HandlerObj->Notify.Next[Info->Notify.HandlerListId]; |
241 | } |
242 | |
243 | /* All done with the info object */ |
244 | |
245 | AcpiUtDeleteGenericState (Info); |
246 | } |
247 | |
248 | |
249 | #if (!ACPI_REDUCED_HARDWARE) |
250 | /****************************************************************************** |
251 | * |
252 | * FUNCTION: AcpiEvTerminate |
253 | * |
254 | * PARAMETERS: none |
255 | * |
256 | * RETURN: none |
257 | * |
258 | * DESCRIPTION: Disable events and free memory allocated for table storage. |
259 | * |
260 | ******************************************************************************/ |
261 | |
262 | void |
263 | AcpiEvTerminate ( |
264 | void) |
265 | { |
266 | UINT32 i; |
267 | ACPI_STATUS Status; |
268 | |
269 | |
270 | ACPI_FUNCTION_TRACE (EvTerminate); |
271 | |
272 | |
273 | if (AcpiGbl_EventsInitialized) |
274 | { |
275 | /* |
276 | * Disable all event-related functionality. In all cases, on error, |
277 | * print a message but obviously we don't abort. |
278 | */ |
279 | |
280 | /* Disable all fixed events */ |
281 | |
282 | for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) |
283 | { |
284 | Status = AcpiDisableEvent (i, 0); |
285 | if (ACPI_FAILURE (Status)) |
286 | { |
287 | ACPI_ERROR ((AE_INFO, |
288 | "Could not disable fixed event %u" , (UINT32) i)); |
289 | } |
290 | } |
291 | |
292 | /* Disable all GPEs in all GPE blocks */ |
293 | |
294 | Status = AcpiEvWalkGpeList (AcpiHwDisableGpeBlock, NULL); |
295 | |
296 | Status = AcpiEvRemoveGlobalLockHandler (); |
297 | if (ACPI_FAILURE(Status)) |
298 | { |
299 | ACPI_ERROR ((AE_INFO, |
300 | "Could not remove Global Lock handler" )); |
301 | } |
302 | |
303 | AcpiGbl_EventsInitialized = FALSE; |
304 | } |
305 | |
306 | /* Remove SCI handlers */ |
307 | |
308 | Status = AcpiEvRemoveAllSciHandlers (); |
309 | if (ACPI_FAILURE(Status)) |
310 | { |
311 | ACPI_ERROR ((AE_INFO, |
312 | "Could not remove SCI handler" )); |
313 | } |
314 | |
315 | /* Deallocate all handler objects installed within GPE info structs */ |
316 | |
317 | Status = AcpiEvWalkGpeList (AcpiEvDeleteGpeHandlers, NULL); |
318 | |
319 | /* Return to original mode if necessary */ |
320 | |
321 | if (AcpiGbl_OriginalMode == ACPI_SYS_MODE_LEGACY) |
322 | { |
323 | Status = AcpiDisable (); |
324 | if (ACPI_FAILURE (Status)) |
325 | { |
326 | ACPI_WARNING ((AE_INFO, "AcpiDisable failed" )); |
327 | } |
328 | } |
329 | return_VOID; |
330 | } |
331 | |
332 | #endif /* !ACPI_REDUCED_HARDWARE */ |
333 | |