evxface.c revision 245582
167754Smsmith/******************************************************************************
267754Smsmith *
367754Smsmith * Module Name: evxface - External interfaces for ACPI events
467754Smsmith *
567754Smsmith *****************************************************************************/
667754Smsmith
7217365Sjkim/*
8245582Sjkim * Copyright (C) 2000 - 2013, Intel Corp.
970243Smsmith * All rights reserved.
1067754Smsmith *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
2567754Smsmith *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
2967754Smsmith *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
4367754Smsmith
4467754Smsmith
4567754Smsmith#define __EVXFACE_C__
4667754Smsmith
47193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
48193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
49193341Sjkim#include <contrib/dev/acpica/include/acnamesp.h>
50193341Sjkim#include <contrib/dev/acpica/include/acevents.h>
51193341Sjkim#include <contrib/dev/acpica/include/acinterp.h>
5267754Smsmith
5377424Smsmith#define _COMPONENT          ACPI_EVENTS
5491116Smsmith        ACPI_MODULE_NAME    ("evxface")
5567754Smsmith
5667754Smsmith
5777424Smsmith/*******************************************************************************
5867754Smsmith *
5967754Smsmith * FUNCTION:    AcpiInstallNotifyHandler
6067754Smsmith *
6167754Smsmith * PARAMETERS:  Device          - The device for which notifies will be handled
6267754Smsmith *              HandlerType     - The type of handler:
63234623Sjkim *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
64234623Sjkim *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
65234623Sjkim *                                  ACPI_ALL_NOTIFY:    Both System and Device
6667754Smsmith *              Handler         - Address of the handler
6767754Smsmith *              Context         - Value passed to the handler on each GPE
6867754Smsmith *
6967754Smsmith * RETURN:      Status
7067754Smsmith *
71234623Sjkim * DESCRIPTION: Install a handler for notifications on an ACPI Device,
72234623Sjkim *              ThermalZone, or Processor object.
7367754Smsmith *
74234623Sjkim * NOTES:       The Root namespace object may have only one handler for each
75234623Sjkim *              type of notify (System/Device). Device/Thermal/Processor objects
76234623Sjkim *              may have one device notify handler, and multiple system notify
77234623Sjkim *              handlers.
78234623Sjkim *
7967754Smsmith ******************************************************************************/
8067754Smsmith
8167754SmsmithACPI_STATUS
8267754SmsmithAcpiInstallNotifyHandler (
8367754Smsmith    ACPI_HANDLE             Device,
8467754Smsmith    UINT32                  HandlerType,
8577424Smsmith    ACPI_NOTIFY_HANDLER     Handler,
8667754Smsmith    void                    *Context)
8767754Smsmith{
88234623Sjkim    ACPI_NAMESPACE_NODE     *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Device);
8967754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc;
90234623Sjkim    ACPI_OPERAND_OBJECT     *HandlerObj;
9191116Smsmith    ACPI_STATUS             Status;
92234623Sjkim    UINT32                  i;
9367754Smsmith
9467754Smsmith
95167802Sjkim    ACPI_FUNCTION_TRACE (AcpiInstallNotifyHandler);
9667754Smsmith
9767754Smsmith
9867754Smsmith    /* Parameter validation */
9967754Smsmith
100234623Sjkim    if ((!Device) || (!Handler) || (!HandlerType) ||
10167754Smsmith        (HandlerType > ACPI_MAX_NOTIFY_HANDLER_TYPE))
10267754Smsmith    {
10367754Smsmith        return_ACPI_STATUS (AE_BAD_PARAMETER);
10467754Smsmith    }
10567754Smsmith
10691116Smsmith    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
10791116Smsmith    if (ACPI_FAILURE (Status))
10891116Smsmith    {
10991116Smsmith        return_ACPI_STATUS (Status);
11091116Smsmith    }
11171867Smsmith
11267754Smsmith    /*
11371867Smsmith     * Root Object:
11471867Smsmith     * Registering a notify handler on the root object indicates that the
115193267Sjkim     * caller wishes to receive notifications for all objects. Note that
116234623Sjkim     * only one global handler can be registered per notify type.
117234623Sjkim     * Ensure that a handler is not already installed.
11867754Smsmith     */
11967754Smsmith    if (Device == ACPI_ROOT_OBJECT)
12067754Smsmith    {
121234623Sjkim        for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
12267754Smsmith        {
123234623Sjkim            if (HandlerType & (i+1))
124234623Sjkim            {
125234623Sjkim                if (AcpiGbl_GlobalNotify[i].Handler)
126234623Sjkim                {
127234623Sjkim                    Status = AE_ALREADY_EXISTS;
128234623Sjkim                    goto UnlockAndExit;
129234623Sjkim                }
13067754Smsmith
131234623Sjkim                AcpiGbl_GlobalNotify[i].Handler = Handler;
132234623Sjkim                AcpiGbl_GlobalNotify[i].Context = Context;
133234623Sjkim            }
13467754Smsmith        }
135129684Snjl
136234623Sjkim        goto UnlockAndExit; /* Global notify handler installed, all done */
13767754Smsmith    }
13867754Smsmith
13967754Smsmith    /*
14085756Smsmith     * All Other Objects:
141234623Sjkim     * Caller will only receive notifications specific to the target
142234623Sjkim     * object. Note that only certain object types are allowed to
143234623Sjkim     * receive notifications.
14467754Smsmith     */
145234623Sjkim
146234623Sjkim    /* Are Notifies allowed on this object? */
147234623Sjkim
148234623Sjkim    if (!AcpiEvIsNotifyObject (Node))
14985756Smsmith    {
150234623Sjkim        Status = AE_TYPE;
151234623Sjkim        goto UnlockAndExit;
152234623Sjkim    }
15399146Siwasaki
154234623Sjkim    /* Check for an existing internal object, might not exist */
155234623Sjkim
156234623Sjkim    ObjDesc = AcpiNsGetAttachedObject (Node);
157234623Sjkim    if (!ObjDesc)
158234623Sjkim    {
159234623Sjkim        /* Create a new object */
160234623Sjkim
161234623Sjkim        ObjDesc = AcpiUtCreateInternalObject (Node->Type);
162234623Sjkim        if (!ObjDesc)
16367754Smsmith        {
164234623Sjkim            Status = AE_NO_MEMORY;
16567754Smsmith            goto UnlockAndExit;
16667754Smsmith        }
16767754Smsmith
168234623Sjkim        /* Attach new object to the Node, remove local reference */
16967754Smsmith
170234623Sjkim        Status = AcpiNsAttachObject (Device, ObjDesc, Node->Type);
171234623Sjkim        AcpiUtRemoveReference (ObjDesc);
172234623Sjkim        if (ACPI_FAILURE (Status))
17367754Smsmith        {
174234623Sjkim            goto UnlockAndExit;
175234623Sjkim        }
176234623Sjkim    }
17771867Smsmith
178234623Sjkim    /* Ensure that the handler is not already installed in the lists */
179234623Sjkim
180234623Sjkim    for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
181234623Sjkim    {
182234623Sjkim        if (HandlerType & (i+1))
18371867Smsmith        {
184234623Sjkim            HandlerObj = ObjDesc->CommonNotify.NotifyList[i];
185234623Sjkim            while (HandlerObj)
18671867Smsmith            {
187234623Sjkim                if (HandlerObj->Notify.Handler == Handler)
188234623Sjkim                {
189234623Sjkim                    Status = AE_ALREADY_EXISTS;
190234623Sjkim                    goto UnlockAndExit;
191234623Sjkim                }
19267754Smsmith
193234623Sjkim                HandlerObj = HandlerObj->Notify.Next[i];
19471867Smsmith            }
19571867Smsmith        }
196234623Sjkim    }
19771867Smsmith
198234623Sjkim    /* Create and populate a new notify handler object */
19971867Smsmith
200234623Sjkim    HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_NOTIFY);
201234623Sjkim    if (!HandlerObj)
202234623Sjkim    {
203234623Sjkim        Status = AE_NO_MEMORY;
204234623Sjkim        goto UnlockAndExit;
205234623Sjkim    }
20667754Smsmith
207234623Sjkim    HandlerObj->Notify.Node = Node;
208234623Sjkim    HandlerObj->Notify.HandlerType = HandlerType;
209234623Sjkim    HandlerObj->Notify.Handler = Handler;
210234623Sjkim    HandlerObj->Notify.Context = Context;
21167754Smsmith
212234623Sjkim    /* Install the handler at the list head(s) */
213234623Sjkim
214234623Sjkim    for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
215234623Sjkim    {
216234623Sjkim        if (HandlerType & (i+1))
21771867Smsmith        {
218234623Sjkim            HandlerObj->Notify.Next[i] =
219234623Sjkim                ObjDesc->CommonNotify.NotifyList[i];
220129684Snjl
221234623Sjkim            ObjDesc->CommonNotify.NotifyList[i] = HandlerObj;
22271867Smsmith        }
223234623Sjkim    }
224129684Snjl
225234623Sjkim    /* Add an extra reference if handler was installed in both lists */
226129684Snjl
227234623Sjkim    if (HandlerType == ACPI_ALL_NOTIFY)
228234623Sjkim    {
229234623Sjkim        AcpiUtAddReference (HandlerObj);
23067754Smsmith    }
23167754Smsmith
23285756Smsmith
23367754SmsmithUnlockAndExit:
23491116Smsmith    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
23567754Smsmith    return_ACPI_STATUS (Status);
23667754Smsmith}
23767754Smsmith
238167802SjkimACPI_EXPORT_SYMBOL (AcpiInstallNotifyHandler)
23967754Smsmith
240167802Sjkim
24177424Smsmith/*******************************************************************************
24267754Smsmith *
24367754Smsmith * FUNCTION:    AcpiRemoveNotifyHandler
24467754Smsmith *
245234623Sjkim * PARAMETERS:  Device          - The device for which the handler is installed
24667754Smsmith *              HandlerType     - The type of handler:
247234623Sjkim *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
248234623Sjkim *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
249234623Sjkim *                                  ACPI_ALL_NOTIFY:    Both System and Device
25067754Smsmith *              Handler         - Address of the handler
251138287Smarks *
25267754Smsmith * RETURN:      Status
25367754Smsmith *
25467754Smsmith * DESCRIPTION: Remove a handler for notifies on an ACPI device
25567754Smsmith *
25667754Smsmith ******************************************************************************/
25767754Smsmith
25867754SmsmithACPI_STATUS
25967754SmsmithAcpiRemoveNotifyHandler (
26067754Smsmith    ACPI_HANDLE             Device,
26167754Smsmith    UINT32                  HandlerType,
26277424Smsmith    ACPI_NOTIFY_HANDLER     Handler)
26367754Smsmith{
264234623Sjkim    ACPI_NAMESPACE_NODE     *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Device);
26567754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc;
266234623Sjkim    ACPI_OPERAND_OBJECT     *HandlerObj;
267234623Sjkim    ACPI_OPERAND_OBJECT     *PreviousHandlerObj;
26891116Smsmith    ACPI_STATUS             Status;
269234623Sjkim    UINT32                  i;
27067754Smsmith
27177424Smsmith
272167802Sjkim    ACPI_FUNCTION_TRACE (AcpiRemoveNotifyHandler);
27367754Smsmith
27477424Smsmith
27567754Smsmith    /* Parameter validation */
27667754Smsmith
277234623Sjkim    if ((!Device) || (!Handler) || (!HandlerType) ||
27867754Smsmith        (HandlerType > ACPI_MAX_NOTIFY_HANDLER_TYPE))
27967754Smsmith    {
28067754Smsmith        return_ACPI_STATUS (AE_BAD_PARAMETER);
28167754Smsmith    }
28267754Smsmith
283235945Sjkim    /* Make sure all deferred notify tasks are completed */
284234623Sjkim
285235945Sjkim    AcpiOsWaitEventsComplete ();
286234623Sjkim
28791116Smsmith    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
28891116Smsmith    if (ACPI_FAILURE (Status))
28991116Smsmith    {
29091116Smsmith        return_ACPI_STATUS (Status);
29191116Smsmith    }
29267754Smsmith
293234623Sjkim    /* Root Object. Global handlers are removed here */
29467754Smsmith
29587031Smsmith    if (Device == ACPI_ROOT_OBJECT)
29685756Smsmith    {
297234623Sjkim        for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
29871867Smsmith        {
299234623Sjkim            if (HandlerType & (i+1))
300234623Sjkim            {
301234623Sjkim                if (!AcpiGbl_GlobalNotify[i].Handler ||
302234623Sjkim                    (AcpiGbl_GlobalNotify[i].Handler != Handler))
303234623Sjkim                {
304234623Sjkim                    Status = AE_NOT_EXIST;
305234623Sjkim                    goto UnlockAndExit;
306234623Sjkim                }
30767754Smsmith
308234623Sjkim                ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
309234623Sjkim                    "Removing global notify handler\n"));
310234623Sjkim
311234623Sjkim                AcpiGbl_GlobalNotify[i].Handler = NULL;
312234623Sjkim                AcpiGbl_GlobalNotify[i].Context = NULL;
313234623Sjkim            }
31471867Smsmith        }
315129684Snjl
316234623Sjkim        goto UnlockAndExit;
31767754Smsmith    }
31867754Smsmith
319234623Sjkim    /* All other objects: Are Notifies allowed on this object? */
320138287Smarks
321234623Sjkim    if (!AcpiEvIsNotifyObject (Node))
32285756Smsmith    {
323234623Sjkim        Status = AE_TYPE;
324234623Sjkim        goto UnlockAndExit;
325234623Sjkim    }
32699146Siwasaki
327234623Sjkim    /* Must have an existing internal object */
32867754Smsmith
329234623Sjkim    ObjDesc = AcpiNsGetAttachedObject (Node);
330234623Sjkim    if (!ObjDesc)
331234623Sjkim    {
332234623Sjkim        Status = AE_NOT_EXIST;
333234623Sjkim        goto UnlockAndExit;
334234623Sjkim    }
33567754Smsmith
336234623Sjkim    /* Internal object exists. Find the handler and remove it */
337234623Sjkim
338234623Sjkim    for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
339234623Sjkim    {
340234623Sjkim        if (HandlerType & (i+1))
34171867Smsmith        {
342234623Sjkim            HandlerObj = ObjDesc->CommonNotify.NotifyList[i];
343234623Sjkim            PreviousHandlerObj = NULL;
34467754Smsmith
345234623Sjkim            /* Attempt to find the handler in the handler list */
34671867Smsmith
347234623Sjkim            while (HandlerObj &&
348234623Sjkim                  (HandlerObj->Notify.Handler != Handler))
349129684Snjl            {
350234623Sjkim                PreviousHandlerObj = HandlerObj;
351234623Sjkim                HandlerObj = HandlerObj->Notify.Next[i];
352167802Sjkim            }
353167802Sjkim
354234623Sjkim            if (!HandlerObj)
355167802Sjkim            {
356234623Sjkim                Status = AE_NOT_EXIST;
357129684Snjl                goto UnlockAndExit;
358129684Snjl            }
359129684Snjl
360234623Sjkim            /* Remove the handler object from the list */
361129684Snjl
362234623Sjkim            if (PreviousHandlerObj) /* Handler is not at the list head */
363129684Snjl            {
364234623Sjkim                PreviousHandlerObj->Notify.Next[i] =
365234623Sjkim                    HandlerObj->Notify.Next[i];
366167802Sjkim            }
367234623Sjkim            else /* Handler is at the list head */
368167802Sjkim            {
369234623Sjkim                ObjDesc->CommonNotify.NotifyList[i] =
370234623Sjkim                    HandlerObj->Notify.Next[i];
371129684Snjl            }
37271867Smsmith
373234623Sjkim            AcpiUtRemoveReference (HandlerObj);
37471867Smsmith        }
37567754Smsmith    }
37667754Smsmith
37767754Smsmith
37867754SmsmithUnlockAndExit:
37991116Smsmith    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
38067754Smsmith    return_ACPI_STATUS (Status);
38167754Smsmith}
38267754Smsmith
383167802SjkimACPI_EXPORT_SYMBOL (AcpiRemoveNotifyHandler)
38471867Smsmith
385167802Sjkim
38677424Smsmith/*******************************************************************************
38767754Smsmith *
388231844Sjkim * FUNCTION:    AcpiInstallExceptionHandler
389231844Sjkim *
390231844Sjkim * PARAMETERS:  Handler         - Pointer to the handler function for the
391231844Sjkim *                                event
392231844Sjkim *
393231844Sjkim * RETURN:      Status
394231844Sjkim *
395231844Sjkim * DESCRIPTION: Saves the pointer to the handler function
396231844Sjkim *
397231844Sjkim ******************************************************************************/
398231844Sjkim
399231844SjkimACPI_STATUS
400231844SjkimAcpiInstallExceptionHandler (
401231844Sjkim    ACPI_EXCEPTION_HANDLER  Handler)
402231844Sjkim{
403231844Sjkim    ACPI_STATUS             Status;
404231844Sjkim
405231844Sjkim
406231844Sjkim    ACPI_FUNCTION_TRACE (AcpiInstallExceptionHandler);
407231844Sjkim
408231844Sjkim
409231844Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
410231844Sjkim    if (ACPI_FAILURE (Status))
411231844Sjkim    {
412231844Sjkim        return_ACPI_STATUS (Status);
413231844Sjkim    }
414231844Sjkim
415231844Sjkim    /* Don't allow two handlers. */
416231844Sjkim
417231844Sjkim    if (AcpiGbl_ExceptionHandler)
418231844Sjkim    {
419231844Sjkim        Status = AE_ALREADY_EXISTS;
420231844Sjkim        goto Cleanup;
421231844Sjkim    }
422231844Sjkim
423231844Sjkim    /* Install the handler */
424231844Sjkim
425231844Sjkim    AcpiGbl_ExceptionHandler = Handler;
426231844Sjkim
427231844SjkimCleanup:
428231844Sjkim    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
429231844Sjkim    return_ACPI_STATUS (Status);
430231844Sjkim}
431231844Sjkim
432231844SjkimACPI_EXPORT_SYMBOL (AcpiInstallExceptionHandler)
433231844Sjkim
434231844Sjkim
435231844Sjkim#if (!ACPI_REDUCED_HARDWARE)
436231844Sjkim/*******************************************************************************
437231844Sjkim *
438231844Sjkim * FUNCTION:    AcpiInstallGlobalEventHandler
439231844Sjkim *
440231844Sjkim * PARAMETERS:  Handler         - Pointer to the global event handler function
441231844Sjkim *              Context         - Value passed to the handler on each event
442231844Sjkim *
443231844Sjkim * RETURN:      Status
444231844Sjkim *
445231844Sjkim * DESCRIPTION: Saves the pointer to the handler function. The global handler
446231844Sjkim *              is invoked upon each incoming GPE and Fixed Event. It is
447231844Sjkim *              invoked at interrupt level at the time of the event dispatch.
448231844Sjkim *              Can be used to update event counters, etc.
449231844Sjkim *
450231844Sjkim ******************************************************************************/
451231844Sjkim
452231844SjkimACPI_STATUS
453231844SjkimAcpiInstallGlobalEventHandler (
454231844Sjkim    ACPI_GBL_EVENT_HANDLER  Handler,
455231844Sjkim    void                    *Context)
456231844Sjkim{
457231844Sjkim    ACPI_STATUS             Status;
458231844Sjkim
459231844Sjkim
460231844Sjkim    ACPI_FUNCTION_TRACE (AcpiInstallGlobalEventHandler);
461231844Sjkim
462231844Sjkim
463231844Sjkim    /* Parameter validation */
464231844Sjkim
465231844Sjkim    if (!Handler)
466231844Sjkim    {
467231844Sjkim        return_ACPI_STATUS (AE_BAD_PARAMETER);
468231844Sjkim    }
469231844Sjkim
470231844Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
471231844Sjkim    if (ACPI_FAILURE (Status))
472231844Sjkim    {
473231844Sjkim        return_ACPI_STATUS (Status);
474231844Sjkim    }
475231844Sjkim
476231844Sjkim    /* Don't allow two handlers. */
477231844Sjkim
478231844Sjkim    if (AcpiGbl_GlobalEventHandler)
479231844Sjkim    {
480231844Sjkim        Status = AE_ALREADY_EXISTS;
481231844Sjkim        goto Cleanup;
482231844Sjkim    }
483231844Sjkim
484231844Sjkim    AcpiGbl_GlobalEventHandler = Handler;
485231844Sjkim    AcpiGbl_GlobalEventHandlerContext = Context;
486231844Sjkim
487231844Sjkim
488231844SjkimCleanup:
489231844Sjkim    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
490231844Sjkim    return_ACPI_STATUS (Status);
491231844Sjkim}
492231844Sjkim
493231844SjkimACPI_EXPORT_SYMBOL (AcpiInstallGlobalEventHandler)
494231844Sjkim
495231844Sjkim
496231844Sjkim/*******************************************************************************
497231844Sjkim *
498231844Sjkim * FUNCTION:    AcpiInstallFixedEventHandler
499231844Sjkim *
500231844Sjkim * PARAMETERS:  Event           - Event type to enable.
501231844Sjkim *              Handler         - Pointer to the handler function for the
502231844Sjkim *                                event
503231844Sjkim *              Context         - Value passed to the handler on each GPE
504231844Sjkim *
505231844Sjkim * RETURN:      Status
506231844Sjkim *
507231844Sjkim * DESCRIPTION: Saves the pointer to the handler function and then enables the
508231844Sjkim *              event.
509231844Sjkim *
510231844Sjkim ******************************************************************************/
511231844Sjkim
512231844SjkimACPI_STATUS
513231844SjkimAcpiInstallFixedEventHandler (
514231844Sjkim    UINT32                  Event,
515231844Sjkim    ACPI_EVENT_HANDLER      Handler,
516231844Sjkim    void                    *Context)
517231844Sjkim{
518231844Sjkim    ACPI_STATUS             Status;
519231844Sjkim
520231844Sjkim
521231844Sjkim    ACPI_FUNCTION_TRACE (AcpiInstallFixedEventHandler);
522231844Sjkim
523231844Sjkim
524231844Sjkim    /* Parameter validation */
525231844Sjkim
526231844Sjkim    if (Event > ACPI_EVENT_MAX)
527231844Sjkim    {
528231844Sjkim        return_ACPI_STATUS (AE_BAD_PARAMETER);
529231844Sjkim    }
530231844Sjkim
531231844Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
532231844Sjkim    if (ACPI_FAILURE (Status))
533231844Sjkim    {
534231844Sjkim        return_ACPI_STATUS (Status);
535231844Sjkim    }
536231844Sjkim
537231844Sjkim    /* Don't allow two handlers. */
538231844Sjkim
539231844Sjkim    if (NULL != AcpiGbl_FixedEventHandlers[Event].Handler)
540231844Sjkim    {
541231844Sjkim        Status = AE_ALREADY_EXISTS;
542231844Sjkim        goto Cleanup;
543231844Sjkim    }
544231844Sjkim
545231844Sjkim    /* Install the handler before enabling the event */
546231844Sjkim
547231844Sjkim    AcpiGbl_FixedEventHandlers[Event].Handler = Handler;
548231844Sjkim    AcpiGbl_FixedEventHandlers[Event].Context = Context;
549231844Sjkim
550231844Sjkim    Status = AcpiEnableEvent (Event, 0);
551231844Sjkim    if (ACPI_FAILURE (Status))
552231844Sjkim    {
553231844Sjkim        ACPI_WARNING ((AE_INFO, "Could not enable fixed event 0x%X", Event));
554231844Sjkim
555231844Sjkim        /* Remove the handler */
556231844Sjkim
557231844Sjkim        AcpiGbl_FixedEventHandlers[Event].Handler = NULL;
558231844Sjkim        AcpiGbl_FixedEventHandlers[Event].Context = NULL;
559231844Sjkim    }
560231844Sjkim    else
561231844Sjkim    {
562231844Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
563231844Sjkim            "Enabled fixed event %X, Handler=%p\n", Event, Handler));
564231844Sjkim    }
565231844Sjkim
566231844Sjkim
567231844SjkimCleanup:
568231844Sjkim    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
569231844Sjkim    return_ACPI_STATUS (Status);
570231844Sjkim}
571231844Sjkim
572231844SjkimACPI_EXPORT_SYMBOL (AcpiInstallFixedEventHandler)
573231844Sjkim
574231844Sjkim
575231844Sjkim/*******************************************************************************
576231844Sjkim *
577231844Sjkim * FUNCTION:    AcpiRemoveFixedEventHandler
578231844Sjkim *
579231844Sjkim * PARAMETERS:  Event           - Event type to disable.
580231844Sjkim *              Handler         - Address of the handler
581231844Sjkim *
582231844Sjkim * RETURN:      Status
583231844Sjkim *
584231844Sjkim * DESCRIPTION: Disables the event and unregisters the event handler.
585231844Sjkim *
586231844Sjkim ******************************************************************************/
587231844Sjkim
588231844SjkimACPI_STATUS
589231844SjkimAcpiRemoveFixedEventHandler (
590231844Sjkim    UINT32                  Event,
591231844Sjkim    ACPI_EVENT_HANDLER      Handler)
592231844Sjkim{
593231844Sjkim    ACPI_STATUS             Status = AE_OK;
594231844Sjkim
595231844Sjkim
596231844Sjkim    ACPI_FUNCTION_TRACE (AcpiRemoveFixedEventHandler);
597231844Sjkim
598231844Sjkim
599231844Sjkim    /* Parameter validation */
600231844Sjkim
601231844Sjkim    if (Event > ACPI_EVENT_MAX)
602231844Sjkim    {
603231844Sjkim        return_ACPI_STATUS (AE_BAD_PARAMETER);
604231844Sjkim    }
605231844Sjkim
606231844Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
607231844Sjkim    if (ACPI_FAILURE (Status))
608231844Sjkim    {
609231844Sjkim        return_ACPI_STATUS (Status);
610231844Sjkim    }
611231844Sjkim
612231844Sjkim    /* Disable the event before removing the handler */
613231844Sjkim
614231844Sjkim    Status = AcpiDisableEvent (Event, 0);
615231844Sjkim
616231844Sjkim    /* Always Remove the handler */
617231844Sjkim
618231844Sjkim    AcpiGbl_FixedEventHandlers[Event].Handler = NULL;
619231844Sjkim    AcpiGbl_FixedEventHandlers[Event].Context = NULL;
620231844Sjkim
621231844Sjkim    if (ACPI_FAILURE (Status))
622231844Sjkim    {
623231844Sjkim        ACPI_WARNING ((AE_INFO,
624231844Sjkim            "Could not write to fixed event enable register 0x%X", Event));
625231844Sjkim    }
626231844Sjkim    else
627231844Sjkim    {
628231844Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Disabled fixed event %X\n", Event));
629231844Sjkim    }
630231844Sjkim
631231844Sjkim    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
632231844Sjkim    return_ACPI_STATUS (Status);
633231844Sjkim}
634231844Sjkim
635231844SjkimACPI_EXPORT_SYMBOL (AcpiRemoveFixedEventHandler)
636231844Sjkim
637231844Sjkim
638231844Sjkim/*******************************************************************************
639231844Sjkim *
64067754Smsmith * FUNCTION:    AcpiInstallGpeHandler
64167754Smsmith *
642151937Sjkim * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
643151937Sjkim *                                defined GPEs)
644151937Sjkim *              GpeNumber       - The GPE number within the GPE block
64567754Smsmith *              Type            - Whether this GPE should be treated as an
64667754Smsmith *                                edge- or level-triggered interrupt.
647129684Snjl *              Address         - Address of the handler
64867754Smsmith *              Context         - Value passed to the handler on each GPE
64967754Smsmith *
65067754Smsmith * RETURN:      Status
65167754Smsmith *
65267754Smsmith * DESCRIPTION: Install a handler for a General Purpose Event.
65367754Smsmith *
65467754Smsmith ******************************************************************************/
65567754Smsmith
65667754SmsmithACPI_STATUS
65767754SmsmithAcpiInstallGpeHandler (
658117521Snjl    ACPI_HANDLE             GpeDevice,
65967754Smsmith    UINT32                  GpeNumber,
66067754Smsmith    UINT32                  Type,
661216471Sjkim    ACPI_GPE_HANDLER        Address,
66267754Smsmith    void                    *Context)
66367754Smsmith{
664129684Snjl    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
665216471Sjkim    ACPI_GPE_HANDLER_INFO   *Handler;
66691116Smsmith    ACPI_STATUS             Status;
667167802Sjkim    ACPI_CPU_FLAGS          Flags;
66867754Smsmith
66977424Smsmith
670167802Sjkim    ACPI_FUNCTION_TRACE (AcpiInstallGpeHandler);
67167754Smsmith
67277424Smsmith
67367754Smsmith    /* Parameter validation */
67467754Smsmith
675206117Sjkim    if ((!Address) || (Type & ~ACPI_GPE_XRUPT_TYPE_MASK))
67667754Smsmith    {
67767754Smsmith        return_ACPI_STATUS (AE_BAD_PARAMETER);
67867754Smsmith    }
67967754Smsmith
680117521Snjl    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
681117521Snjl    if (ACPI_FAILURE (Status))
682117521Snjl    {
683117521Snjl        return_ACPI_STATUS (Status);
684117521Snjl    }
685117521Snjl
686216471Sjkim    /* Allocate and init handler object (before lock) */
687216471Sjkim
688216471Sjkim    Handler = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_HANDLER_INFO));
689216471Sjkim    if (!Handler)
690216471Sjkim    {
691216471Sjkim        Status = AE_NO_MEMORY;
692216471Sjkim        goto UnlockAndExit;
693216471Sjkim    }
694216471Sjkim
695216471Sjkim    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
696216471Sjkim
69767754Smsmith    /* Ensure that we have a valid GPE number */
69867754Smsmith
699117521Snjl    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
700114237Snjl    if (!GpeEventInfo)
70167754Smsmith    {
702117521Snjl        Status = AE_BAD_PARAMETER;
703216471Sjkim        goto FreeAndExit;
70467754Smsmith    }
70567754Smsmith
70667754Smsmith    /* Make sure that there isn't a handler there already */
70767754Smsmith
708193267Sjkim    if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
709193267Sjkim            ACPI_GPE_DISPATCH_HANDLER)
71067754Smsmith    {
71187031Smsmith        Status = AE_ALREADY_EXISTS;
712216471Sjkim        goto FreeAndExit;
71367754Smsmith    }
71467754Smsmith
715216471Sjkim    Handler->Address = Address;
716216471Sjkim    Handler->Context = Context;
717216471Sjkim    Handler->MethodNode = GpeEventInfo->Dispatch.MethodNode;
718216471Sjkim    Handler->OriginalFlags = (UINT8) (GpeEventInfo->Flags &
719216471Sjkim        (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK));
72067754Smsmith
721216471Sjkim    /*
722216471Sjkim     * If the GPE is associated with a method, it may have been enabled
723216471Sjkim     * automatically during initialization, in which case it has to be
724216471Sjkim     * disabled now to avoid spurious execution of the handler.
725216471Sjkim     */
726216471Sjkim    if (((Handler->OriginalFlags & ACPI_GPE_DISPATCH_METHOD) ||
727216471Sjkim         (Handler->OriginalFlags & ACPI_GPE_DISPATCH_NOTIFY)) &&
728216471Sjkim        GpeEventInfo->RuntimeCount)
729129684Snjl    {
730216471Sjkim        Handler->OriginallyEnabled = TRUE;
731216471Sjkim        (void) AcpiEvRemoveGpeReference (GpeEventInfo);
732216471Sjkim
733216471Sjkim        /* Sanity check of original type against new type */
734216471Sjkim
735216471Sjkim        if (Type != (UINT32) (GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK))
736216471Sjkim        {
737216471Sjkim            ACPI_WARNING ((AE_INFO, "GPE type mismatch (level/edge)"));
738216471Sjkim        }
739129684Snjl    }
74067754Smsmith
741129684Snjl    /* Install the handler */
74285756Smsmith
743129684Snjl    GpeEventInfo->Dispatch.Handler = Handler;
74499679Siwasaki
745216471Sjkim    /* Setup up dispatch flags to indicate handler (vs. method/notify) */
746129684Snjl
747193267Sjkim    GpeEventInfo->Flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
748129684Snjl    GpeEventInfo->Flags |= (UINT8) (Type | ACPI_GPE_DISPATCH_HANDLER);
749129684Snjl
750151937Sjkim    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
751129684Snjl
752129684Snjl
753117521SnjlUnlockAndExit:
75491116Smsmith    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
75567754Smsmith    return_ACPI_STATUS (Status);
756216471Sjkim
757216471SjkimFreeAndExit:
758216471Sjkim    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
759216471Sjkim    ACPI_FREE (Handler);
760216471Sjkim    goto UnlockAndExit;
76167754Smsmith}
76267754Smsmith
763167802SjkimACPI_EXPORT_SYMBOL (AcpiInstallGpeHandler)
76467754Smsmith
765167802Sjkim
76677424Smsmith/*******************************************************************************
76767754Smsmith *
76867754Smsmith * FUNCTION:    AcpiRemoveGpeHandler
76967754Smsmith *
770151937Sjkim * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
771151937Sjkim *                                defined GPEs)
772151937Sjkim *              GpeNumber       - The event to remove a handler
773129684Snjl *              Address         - Address of the handler
77467754Smsmith *
77567754Smsmith * RETURN:      Status
77667754Smsmith *
77767754Smsmith * DESCRIPTION: Remove a handler for a General Purpose AcpiEvent.
77867754Smsmith *
77967754Smsmith ******************************************************************************/
78067754Smsmith
78167754SmsmithACPI_STATUS
78267754SmsmithAcpiRemoveGpeHandler (
783117521Snjl    ACPI_HANDLE             GpeDevice,
78467754Smsmith    UINT32                  GpeNumber,
785216471Sjkim    ACPI_GPE_HANDLER        Address)
78667754Smsmith{
787129684Snjl    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
788216471Sjkim    ACPI_GPE_HANDLER_INFO   *Handler;
78991116Smsmith    ACPI_STATUS             Status;
790167802Sjkim    ACPI_CPU_FLAGS          Flags;
79167754Smsmith
79267754Smsmith
793167802Sjkim    ACPI_FUNCTION_TRACE (AcpiRemoveGpeHandler);
79467754Smsmith
79567754Smsmith
79667754Smsmith    /* Parameter validation */
79767754Smsmith
798129684Snjl    if (!Address)
79967754Smsmith    {
80067754Smsmith        return_ACPI_STATUS (AE_BAD_PARAMETER);
80167754Smsmith    }
80267754Smsmith
803235945Sjkim    /* Make sure all deferred GPE tasks are completed */
804235945Sjkim
805235945Sjkim    AcpiOsWaitEventsComplete ();
806235945Sjkim
807117521Snjl    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
808117521Snjl    if (ACPI_FAILURE (Status))
809117521Snjl    {
810117521Snjl        return_ACPI_STATUS (Status);
811117521Snjl    }
812117521Snjl
813216471Sjkim    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
814216471Sjkim
81567754Smsmith    /* Ensure that we have a valid GPE number */
81667754Smsmith
817117521Snjl    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
818114237Snjl    if (!GpeEventInfo)
81967754Smsmith    {
820117521Snjl        Status = AE_BAD_PARAMETER;
821117521Snjl        goto UnlockAndExit;
82267754Smsmith    }
82367754Smsmith
824129684Snjl    /* Make sure that a handler is indeed installed */
82567754Smsmith
826193267Sjkim    if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) !=
827193267Sjkim            ACPI_GPE_DISPATCH_HANDLER)
82899679Siwasaki    {
829129684Snjl        Status = AE_NOT_EXIST;
830117521Snjl        goto UnlockAndExit;
83199679Siwasaki    }
83267754Smsmith
83367754Smsmith    /* Make sure that the installed handler is the same */
83467754Smsmith
835129684Snjl    if (GpeEventInfo->Dispatch.Handler->Address != Address)
83667754Smsmith    {
83767754Smsmith        Status = AE_BAD_PARAMETER;
838117521Snjl        goto UnlockAndExit;
83967754Smsmith    }
84067754Smsmith
84167754Smsmith    /* Remove the handler */
84267754Smsmith
843129684Snjl    Handler = GpeEventInfo->Dispatch.Handler;
844129684Snjl
845129684Snjl    /* Restore Method node (if any), set dispatch flags */
846129684Snjl
847129684Snjl    GpeEventInfo->Dispatch.MethodNode = Handler->MethodNode;
848216471Sjkim    GpeEventInfo->Flags &=
849216471Sjkim        ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
850216471Sjkim    GpeEventInfo->Flags |= Handler->OriginalFlags;
851216471Sjkim
852216471Sjkim    /*
853216471Sjkim     * If the GPE was previously associated with a method and it was
854216471Sjkim     * enabled, it should be enabled at this point to restore the
855216471Sjkim     * post-initialization configuration.
856216471Sjkim     */
857216471Sjkim    if ((Handler->OriginalFlags & ACPI_GPE_DISPATCH_METHOD) &&
858216471Sjkim        Handler->OriginallyEnabled)
859129684Snjl    {
860216471Sjkim        (void) AcpiEvAddGpeReference (GpeEventInfo);
861129684Snjl    }
86267754Smsmith
863129684Snjl    /* Now we can free the handler object */
86485756Smsmith
865167802Sjkim    ACPI_FREE (Handler);
866129684Snjl
867129684Snjl
868117521SnjlUnlockAndExit:
869216471Sjkim    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
87091116Smsmith    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
87167754Smsmith    return_ACPI_STATUS (Status);
87267754Smsmith}
87367754Smsmith
874167802SjkimACPI_EXPORT_SYMBOL (AcpiRemoveGpeHandler)
87567754Smsmith
876167802Sjkim
87777424Smsmith/*******************************************************************************
87867754Smsmith *
87967754Smsmith * FUNCTION:    AcpiAcquireGlobalLock
88067754Smsmith *
88167754Smsmith * PARAMETERS:  Timeout         - How long the caller is willing to wait
882151937Sjkim *              Handle          - Where the handle to the lock is returned
883151937Sjkim *                                (if acquired)
88467754Smsmith *
88567754Smsmith * RETURN:      Status
88667754Smsmith *
88767754Smsmith * DESCRIPTION: Acquire the ACPI Global Lock
88867754Smsmith *
889167802Sjkim * Note: Allows callers with the same thread ID to acquire the global lock
890167802Sjkim * multiple times. In other words, externally, the behavior of the global lock
891167802Sjkim * is identical to an AML mutex. On the first acquire, a new handle is
892167802Sjkim * returned. On any subsequent calls to acquire by the same thread, the same
893167802Sjkim * handle is returned.
894167802Sjkim *
89567754Smsmith ******************************************************************************/
89685756Smsmith
89767754SmsmithACPI_STATUS
89867754SmsmithAcpiAcquireGlobalLock (
899107325Siwasaki    UINT16                  Timeout,
90091116Smsmith    UINT32                  *Handle)
90167754Smsmith{
90267754Smsmith    ACPI_STATUS             Status;
90367754Smsmith
90467754Smsmith
90591116Smsmith    if (!Handle)
90691116Smsmith    {
90791116Smsmith        return (AE_BAD_PARAMETER);
90891116Smsmith    }
90991116Smsmith
910167802Sjkim    /* Must lock interpreter to prevent race conditions */
91177424Smsmith
912167802Sjkim    AcpiExEnterInterpreter ();
91367754Smsmith
914167802Sjkim    Status = AcpiExAcquireMutexObject (Timeout,
915167802Sjkim                AcpiGbl_GlobalLockMutex, AcpiOsGetThreadId ());
916167802Sjkim
91791116Smsmith    if (ACPI_SUCCESS (Status))
91891116Smsmith    {
919172314Sjkim        /* Return the global lock handle (updated in AcpiEvAcquireGlobalLock) */
920167802Sjkim
92191116Smsmith        *Handle = AcpiGbl_GlobalLockHandle;
92291116Smsmith    }
92391116Smsmith
924167802Sjkim    AcpiExExitInterpreter ();
92567754Smsmith    return (Status);
92667754Smsmith}
92767754Smsmith
928167802SjkimACPI_EXPORT_SYMBOL (AcpiAcquireGlobalLock)
92967754Smsmith
930167802Sjkim
93177424Smsmith/*******************************************************************************
93267754Smsmith *
93367754Smsmith * FUNCTION:    AcpiReleaseGlobalLock
93467754Smsmith *
93567754Smsmith * PARAMETERS:  Handle      - Returned from AcpiAcquireGlobalLock
93667754Smsmith *
93767754Smsmith * RETURN:      Status
93867754Smsmith *
939151937Sjkim * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid.
94067754Smsmith *
94167754Smsmith ******************************************************************************/
94267754Smsmith
94367754SmsmithACPI_STATUS
94467754SmsmithAcpiReleaseGlobalLock (
94591116Smsmith    UINT32                  Handle)
94667754Smsmith{
94799679Siwasaki    ACPI_STATUS             Status;
94885756Smsmith
94999679Siwasaki
950167802Sjkim    if (!Handle || (Handle != AcpiGbl_GlobalLockHandle))
95191116Smsmith    {
95291116Smsmith        return (AE_NOT_ACQUIRED);
95391116Smsmith    }
95491116Smsmith
955167802Sjkim    Status = AcpiExReleaseMutexObject (AcpiGbl_GlobalLockMutex);
95699679Siwasaki    return (Status);
95767754Smsmith}
95867754Smsmith
959167802SjkimACPI_EXPORT_SYMBOL (AcpiReleaseGlobalLock)
96067754Smsmith
961231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */
962