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