167754Smsmith/******************************************************************************
267754Smsmith *
367754Smsmith * Module Name: evxface - External interfaces for ACPI events
467754Smsmith *
567754Smsmith *****************************************************************************/
667754Smsmith
7217365Sjkim/*
8281075Sdim * Copyright (C) 2000 - 2015, 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
44281075Sdim#define EXPORT_ACPI_INTERFACES
4567754Smsmith
46193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
47193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
48193341Sjkim#include <contrib/dev/acpica/include/acnamesp.h>
49193341Sjkim#include <contrib/dev/acpica/include/acevents.h>
50193341Sjkim#include <contrib/dev/acpica/include/acinterp.h>
5167754Smsmith
5277424Smsmith#define _COMPONENT          ACPI_EVENTS
5391116Smsmith        ACPI_MODULE_NAME    ("evxface")
5467754Smsmith
55281075Sdim#if (!ACPI_REDUCED_HARDWARE)
5667754Smsmith
57281075Sdim/* Local prototypes */
58281075Sdim
59281075Sdimstatic ACPI_STATUS
60281075SdimAcpiEvInstallGpeHandler (
61281075Sdim    ACPI_HANDLE             GpeDevice,
62281075Sdim    UINT32                  GpeNumber,
63281075Sdim    UINT32                  Type,
64281075Sdim    BOOLEAN                 IsRawHandler,
65281075Sdim    ACPI_GPE_HANDLER        Address,
66281075Sdim    void                    *Context);
67281075Sdim
68281075Sdim#endif
69281075Sdim
70281075Sdim
7177424Smsmith/*******************************************************************************
7267754Smsmith *
7367754Smsmith * FUNCTION:    AcpiInstallNotifyHandler
7467754Smsmith *
7567754Smsmith * PARAMETERS:  Device          - The device for which notifies will be handled
7667754Smsmith *              HandlerType     - The type of handler:
77234623Sjkim *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
78234623Sjkim *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
79234623Sjkim *                                  ACPI_ALL_NOTIFY:    Both System and Device
8067754Smsmith *              Handler         - Address of the handler
8167754Smsmith *              Context         - Value passed to the handler on each GPE
8267754Smsmith *
8367754Smsmith * RETURN:      Status
8467754Smsmith *
85234623Sjkim * DESCRIPTION: Install a handler for notifications on an ACPI Device,
86234623Sjkim *              ThermalZone, or Processor object.
8767754Smsmith *
88234623Sjkim * NOTES:       The Root namespace object may have only one handler for each
89234623Sjkim *              type of notify (System/Device). Device/Thermal/Processor objects
90234623Sjkim *              may have one device notify handler, and multiple system notify
91234623Sjkim *              handlers.
92234623Sjkim *
9367754Smsmith ******************************************************************************/
9467754Smsmith
9567754SmsmithACPI_STATUS
9667754SmsmithAcpiInstallNotifyHandler (
9767754Smsmith    ACPI_HANDLE             Device,
9867754Smsmith    UINT32                  HandlerType,
9977424Smsmith    ACPI_NOTIFY_HANDLER     Handler,
10067754Smsmith    void                    *Context)
10167754Smsmith{
102234623Sjkim    ACPI_NAMESPACE_NODE     *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Device);
10367754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc;
104234623Sjkim    ACPI_OPERAND_OBJECT     *HandlerObj;
10591116Smsmith    ACPI_STATUS             Status;
106234623Sjkim    UINT32                  i;
10767754Smsmith
10867754Smsmith
109167802Sjkim    ACPI_FUNCTION_TRACE (AcpiInstallNotifyHandler);
11067754Smsmith
11167754Smsmith
11267754Smsmith    /* Parameter validation */
11367754Smsmith
114234623Sjkim    if ((!Device) || (!Handler) || (!HandlerType) ||
11567754Smsmith        (HandlerType > ACPI_MAX_NOTIFY_HANDLER_TYPE))
11667754Smsmith    {
11767754Smsmith        return_ACPI_STATUS (AE_BAD_PARAMETER);
11867754Smsmith    }
11967754Smsmith
12091116Smsmith    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
12191116Smsmith    if (ACPI_FAILURE (Status))
12291116Smsmith    {
12391116Smsmith        return_ACPI_STATUS (Status);
12491116Smsmith    }
12571867Smsmith
12667754Smsmith    /*
12771867Smsmith     * Root Object:
12871867Smsmith     * Registering a notify handler on the root object indicates that the
129193267Sjkim     * caller wishes to receive notifications for all objects. Note that
130234623Sjkim     * only one global handler can be registered per notify type.
131234623Sjkim     * Ensure that a handler is not already installed.
13267754Smsmith     */
13367754Smsmith    if (Device == ACPI_ROOT_OBJECT)
13467754Smsmith    {
135234623Sjkim        for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
13667754Smsmith        {
137234623Sjkim            if (HandlerType & (i+1))
138234623Sjkim            {
139234623Sjkim                if (AcpiGbl_GlobalNotify[i].Handler)
140234623Sjkim                {
141234623Sjkim                    Status = AE_ALREADY_EXISTS;
142234623Sjkim                    goto UnlockAndExit;
143234623Sjkim                }
14467754Smsmith
145234623Sjkim                AcpiGbl_GlobalNotify[i].Handler = Handler;
146234623Sjkim                AcpiGbl_GlobalNotify[i].Context = Context;
147234623Sjkim            }
14867754Smsmith        }
149129684Snjl
150234623Sjkim        goto UnlockAndExit; /* Global notify handler installed, all done */
15167754Smsmith    }
15267754Smsmith
15367754Smsmith    /*
15485756Smsmith     * All Other Objects:
155234623Sjkim     * Caller will only receive notifications specific to the target
156234623Sjkim     * object. Note that only certain object types are allowed to
157234623Sjkim     * receive notifications.
15867754Smsmith     */
159234623Sjkim
160234623Sjkim    /* Are Notifies allowed on this object? */
161234623Sjkim
162234623Sjkim    if (!AcpiEvIsNotifyObject (Node))
16385756Smsmith    {
164234623Sjkim        Status = AE_TYPE;
165234623Sjkim        goto UnlockAndExit;
166234623Sjkim    }
16799146Siwasaki
168234623Sjkim    /* Check for an existing internal object, might not exist */
169234623Sjkim
170234623Sjkim    ObjDesc = AcpiNsGetAttachedObject (Node);
171234623Sjkim    if (!ObjDesc)
172234623Sjkim    {
173234623Sjkim        /* Create a new object */
174234623Sjkim
175234623Sjkim        ObjDesc = AcpiUtCreateInternalObject (Node->Type);
176234623Sjkim        if (!ObjDesc)
17767754Smsmith        {
178234623Sjkim            Status = AE_NO_MEMORY;
17967754Smsmith            goto UnlockAndExit;
18067754Smsmith        }
18167754Smsmith
182234623Sjkim        /* Attach new object to the Node, remove local reference */
18367754Smsmith
184234623Sjkim        Status = AcpiNsAttachObject (Device, ObjDesc, Node->Type);
185234623Sjkim        AcpiUtRemoveReference (ObjDesc);
186234623Sjkim        if (ACPI_FAILURE (Status))
18767754Smsmith        {
188234623Sjkim            goto UnlockAndExit;
189234623Sjkim        }
190234623Sjkim    }
19171867Smsmith
192234623Sjkim    /* Ensure that the handler is not already installed in the lists */
193234623Sjkim
194234623Sjkim    for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
195234623Sjkim    {
196234623Sjkim        if (HandlerType & (i+1))
19771867Smsmith        {
198234623Sjkim            HandlerObj = ObjDesc->CommonNotify.NotifyList[i];
199234623Sjkim            while (HandlerObj)
20071867Smsmith            {
201234623Sjkim                if (HandlerObj->Notify.Handler == Handler)
202234623Sjkim                {
203234623Sjkim                    Status = AE_ALREADY_EXISTS;
204234623Sjkim                    goto UnlockAndExit;
205234623Sjkim                }
20667754Smsmith
207234623Sjkim                HandlerObj = HandlerObj->Notify.Next[i];
20871867Smsmith            }
20971867Smsmith        }
210234623Sjkim    }
21171867Smsmith
212234623Sjkim    /* Create and populate a new notify handler object */
21371867Smsmith
214234623Sjkim    HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_NOTIFY);
215234623Sjkim    if (!HandlerObj)
216234623Sjkim    {
217234623Sjkim        Status = AE_NO_MEMORY;
218234623Sjkim        goto UnlockAndExit;
219234623Sjkim    }
22067754Smsmith
221234623Sjkim    HandlerObj->Notify.Node = Node;
222234623Sjkim    HandlerObj->Notify.HandlerType = HandlerType;
223234623Sjkim    HandlerObj->Notify.Handler = Handler;
224234623Sjkim    HandlerObj->Notify.Context = Context;
22567754Smsmith
226234623Sjkim    /* Install the handler at the list head(s) */
227234623Sjkim
228234623Sjkim    for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
229234623Sjkim    {
230234623Sjkim        if (HandlerType & (i+1))
23171867Smsmith        {
232234623Sjkim            HandlerObj->Notify.Next[i] =
233234623Sjkim                ObjDesc->CommonNotify.NotifyList[i];
234129684Snjl
235234623Sjkim            ObjDesc->CommonNotify.NotifyList[i] = HandlerObj;
23671867Smsmith        }
237234623Sjkim    }
238129684Snjl
239234623Sjkim    /* Add an extra reference if handler was installed in both lists */
240129684Snjl
241234623Sjkim    if (HandlerType == ACPI_ALL_NOTIFY)
242234623Sjkim    {
243234623Sjkim        AcpiUtAddReference (HandlerObj);
24467754Smsmith    }
24567754Smsmith
24685756Smsmith
24767754SmsmithUnlockAndExit:
24891116Smsmith    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
24967754Smsmith    return_ACPI_STATUS (Status);
25067754Smsmith}
25167754Smsmith
252167802SjkimACPI_EXPORT_SYMBOL (AcpiInstallNotifyHandler)
25367754Smsmith
254167802Sjkim
25577424Smsmith/*******************************************************************************
25667754Smsmith *
25767754Smsmith * FUNCTION:    AcpiRemoveNotifyHandler
25867754Smsmith *
259234623Sjkim * PARAMETERS:  Device          - The device for which the handler is installed
26067754Smsmith *              HandlerType     - The type of handler:
261234623Sjkim *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
262234623Sjkim *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
263234623Sjkim *                                  ACPI_ALL_NOTIFY:    Both System and Device
26467754Smsmith *              Handler         - Address of the handler
265138287Smarks *
26667754Smsmith * RETURN:      Status
26767754Smsmith *
26867754Smsmith * DESCRIPTION: Remove a handler for notifies on an ACPI device
26967754Smsmith *
27067754Smsmith ******************************************************************************/
27167754Smsmith
27267754SmsmithACPI_STATUS
27367754SmsmithAcpiRemoveNotifyHandler (
27467754Smsmith    ACPI_HANDLE             Device,
27567754Smsmith    UINT32                  HandlerType,
27677424Smsmith    ACPI_NOTIFY_HANDLER     Handler)
27767754Smsmith{
278234623Sjkim    ACPI_NAMESPACE_NODE     *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Device);
27967754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc;
280234623Sjkim    ACPI_OPERAND_OBJECT     *HandlerObj;
281234623Sjkim    ACPI_OPERAND_OBJECT     *PreviousHandlerObj;
282281075Sdim    ACPI_STATUS             Status = AE_OK;
283234623Sjkim    UINT32                  i;
28467754Smsmith
28577424Smsmith
286167802Sjkim    ACPI_FUNCTION_TRACE (AcpiRemoveNotifyHandler);
28767754Smsmith
28877424Smsmith
28967754Smsmith    /* Parameter validation */
29067754Smsmith
291234623Sjkim    if ((!Device) || (!Handler) || (!HandlerType) ||
29267754Smsmith        (HandlerType > ACPI_MAX_NOTIFY_HANDLER_TYPE))
29367754Smsmith    {
29467754Smsmith        return_ACPI_STATUS (AE_BAD_PARAMETER);
29567754Smsmith    }
29667754Smsmith
297234623Sjkim    /* Root Object. Global handlers are removed here */
29867754Smsmith
29987031Smsmith    if (Device == ACPI_ROOT_OBJECT)
30085756Smsmith    {
301234623Sjkim        for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
30271867Smsmith        {
303234623Sjkim            if (HandlerType & (i+1))
304234623Sjkim            {
305281075Sdim                Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
306281075Sdim                if (ACPI_FAILURE (Status))
307281075Sdim                {
308281075Sdim                    return_ACPI_STATUS (Status);
309281075Sdim                }
310281075Sdim
311234623Sjkim                if (!AcpiGbl_GlobalNotify[i].Handler ||
312234623Sjkim                    (AcpiGbl_GlobalNotify[i].Handler != Handler))
313234623Sjkim                {
314234623Sjkim                    Status = AE_NOT_EXIST;
315234623Sjkim                    goto UnlockAndExit;
316234623Sjkim                }
31767754Smsmith
318234623Sjkim                ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
319234623Sjkim                    "Removing global notify handler\n"));
320234623Sjkim
321234623Sjkim                AcpiGbl_GlobalNotify[i].Handler = NULL;
322234623Sjkim                AcpiGbl_GlobalNotify[i].Context = NULL;
323281075Sdim
324281075Sdim                (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
325281075Sdim
326281075Sdim                /* Make sure all deferred notify tasks are completed */
327281075Sdim
328281075Sdim                AcpiOsWaitEventsComplete ();
329234623Sjkim            }
33071867Smsmith        }
331129684Snjl
332281075Sdim        return_ACPI_STATUS (AE_OK);
33367754Smsmith    }
33467754Smsmith
335234623Sjkim    /* All other objects: Are Notifies allowed on this object? */
336138287Smarks
337234623Sjkim    if (!AcpiEvIsNotifyObject (Node))
33885756Smsmith    {
339281075Sdim        return_ACPI_STATUS (AE_TYPE);
340234623Sjkim    }
34199146Siwasaki
342234623Sjkim    /* Must have an existing internal object */
34367754Smsmith
344234623Sjkim    ObjDesc = AcpiNsGetAttachedObject (Node);
345234623Sjkim    if (!ObjDesc)
346234623Sjkim    {
347281075Sdim        return_ACPI_STATUS (AE_NOT_EXIST);
348234623Sjkim    }
34967754Smsmith
350234623Sjkim    /* Internal object exists. Find the handler and remove it */
351234623Sjkim
352234623Sjkim    for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
353234623Sjkim    {
354234623Sjkim        if (HandlerType & (i+1))
35571867Smsmith        {
356281075Sdim            Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
357281075Sdim            if (ACPI_FAILURE (Status))
358281075Sdim            {
359281075Sdim                return_ACPI_STATUS (Status);
360281075Sdim            }
361281075Sdim
362234623Sjkim            HandlerObj = ObjDesc->CommonNotify.NotifyList[i];
363234623Sjkim            PreviousHandlerObj = NULL;
36467754Smsmith
365234623Sjkim            /* Attempt to find the handler in the handler list */
36671867Smsmith
367234623Sjkim            while (HandlerObj &&
368234623Sjkim                  (HandlerObj->Notify.Handler != Handler))
369129684Snjl            {
370234623Sjkim                PreviousHandlerObj = HandlerObj;
371234623Sjkim                HandlerObj = HandlerObj->Notify.Next[i];
372167802Sjkim            }
373167802Sjkim
374234623Sjkim            if (!HandlerObj)
375167802Sjkim            {
376234623Sjkim                Status = AE_NOT_EXIST;
377129684Snjl                goto UnlockAndExit;
378129684Snjl            }
379129684Snjl
380234623Sjkim            /* Remove the handler object from the list */
381129684Snjl
382234623Sjkim            if (PreviousHandlerObj) /* Handler is not at the list head */
383129684Snjl            {
384234623Sjkim                PreviousHandlerObj->Notify.Next[i] =
385234623Sjkim                    HandlerObj->Notify.Next[i];
386167802Sjkim            }
387234623Sjkim            else /* Handler is at the list head */
388167802Sjkim            {
389234623Sjkim                ObjDesc->CommonNotify.NotifyList[i] =
390234623Sjkim                    HandlerObj->Notify.Next[i];
391129684Snjl            }
39271867Smsmith
393281075Sdim            (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
394281075Sdim
395281075Sdim            /* Make sure all deferred notify tasks are completed */
396281075Sdim
397281075Sdim            AcpiOsWaitEventsComplete ();
398234623Sjkim            AcpiUtRemoveReference (HandlerObj);
39971867Smsmith        }
40067754Smsmith    }
40167754Smsmith
402281075Sdim    return_ACPI_STATUS (Status);
40367754Smsmith
404281075Sdim
40567754SmsmithUnlockAndExit:
40691116Smsmith    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
40767754Smsmith    return_ACPI_STATUS (Status);
40867754Smsmith}
40967754Smsmith
410167802SjkimACPI_EXPORT_SYMBOL (AcpiRemoveNotifyHandler)
41171867Smsmith
412167802Sjkim
41377424Smsmith/*******************************************************************************
41467754Smsmith *
415231844Sjkim * FUNCTION:    AcpiInstallExceptionHandler
416231844Sjkim *
417231844Sjkim * PARAMETERS:  Handler         - Pointer to the handler function for the
418231844Sjkim *                                event
419231844Sjkim *
420231844Sjkim * RETURN:      Status
421231844Sjkim *
422231844Sjkim * DESCRIPTION: Saves the pointer to the handler function
423231844Sjkim *
424231844Sjkim ******************************************************************************/
425231844Sjkim
426231844SjkimACPI_STATUS
427231844SjkimAcpiInstallExceptionHandler (
428231844Sjkim    ACPI_EXCEPTION_HANDLER  Handler)
429231844Sjkim{
430231844Sjkim    ACPI_STATUS             Status;
431231844Sjkim
432231844Sjkim
433231844Sjkim    ACPI_FUNCTION_TRACE (AcpiInstallExceptionHandler);
434231844Sjkim
435231844Sjkim
436231844Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
437231844Sjkim    if (ACPI_FAILURE (Status))
438231844Sjkim    {
439231844Sjkim        return_ACPI_STATUS (Status);
440231844Sjkim    }
441231844Sjkim
442231844Sjkim    /* Don't allow two handlers. */
443231844Sjkim
444231844Sjkim    if (AcpiGbl_ExceptionHandler)
445231844Sjkim    {
446231844Sjkim        Status = AE_ALREADY_EXISTS;
447231844Sjkim        goto Cleanup;
448231844Sjkim    }
449231844Sjkim
450231844Sjkim    /* Install the handler */
451231844Sjkim
452231844Sjkim    AcpiGbl_ExceptionHandler = Handler;
453231844Sjkim
454231844SjkimCleanup:
455231844Sjkim    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
456231844Sjkim    return_ACPI_STATUS (Status);
457231844Sjkim}
458231844Sjkim
459231844SjkimACPI_EXPORT_SYMBOL (AcpiInstallExceptionHandler)
460231844Sjkim
461231844Sjkim
462231844Sjkim#if (!ACPI_REDUCED_HARDWARE)
463231844Sjkim/*******************************************************************************
464231844Sjkim *
465254745Sjkim * FUNCTION:    AcpiInstallSciHandler
466254745Sjkim *
467254745Sjkim * PARAMETERS:  Address             - Address of the handler
468254745Sjkim *              Context             - Value passed to the handler on each SCI
469254745Sjkim *
470254745Sjkim * RETURN:      Status
471254745Sjkim *
472254745Sjkim * DESCRIPTION: Install a handler for a System Control Interrupt.
473254745Sjkim *
474254745Sjkim ******************************************************************************/
475254745Sjkim
476254745SjkimACPI_STATUS
477254745SjkimAcpiInstallSciHandler (
478254745Sjkim    ACPI_SCI_HANDLER        Address,
479254745Sjkim    void                    *Context)
480254745Sjkim{
481254745Sjkim    ACPI_SCI_HANDLER_INFO   *NewSciHandler;
482254745Sjkim    ACPI_SCI_HANDLER_INFO   *SciHandler;
483254745Sjkim    ACPI_CPU_FLAGS          Flags;
484254745Sjkim    ACPI_STATUS             Status;
485254745Sjkim
486254745Sjkim
487254745Sjkim    ACPI_FUNCTION_TRACE (AcpiInstallSciHandler);
488254745Sjkim
489254745Sjkim
490254745Sjkim    if (!Address)
491254745Sjkim    {
492254745Sjkim        return_ACPI_STATUS (AE_BAD_PARAMETER);
493254745Sjkim    }
494254745Sjkim
495254745Sjkim    /* Allocate and init a handler object */
496254745Sjkim
497254745Sjkim    NewSciHandler = ACPI_ALLOCATE (sizeof (ACPI_SCI_HANDLER_INFO));
498254745Sjkim    if (!NewSciHandler)
499254745Sjkim    {
500254745Sjkim        return_ACPI_STATUS (AE_NO_MEMORY);
501254745Sjkim    }
502254745Sjkim
503254745Sjkim    NewSciHandler->Address = Address;
504254745Sjkim    NewSciHandler->Context = Context;
505254745Sjkim
506254745Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
507254745Sjkim    if (ACPI_FAILURE (Status))
508254745Sjkim    {
509254745Sjkim        goto Exit;
510254745Sjkim    }
511254745Sjkim
512254745Sjkim    /* Lock list during installation */
513254745Sjkim
514254745Sjkim    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
515254745Sjkim    SciHandler = AcpiGbl_SciHandlerList;
516254745Sjkim
517254745Sjkim    /* Ensure handler does not already exist */
518254745Sjkim
519254745Sjkim    while (SciHandler)
520254745Sjkim    {
521254745Sjkim        if (Address == SciHandler->Address)
522254745Sjkim        {
523254745Sjkim            Status = AE_ALREADY_EXISTS;
524254745Sjkim            goto UnlockAndExit;
525254745Sjkim        }
526254745Sjkim
527254745Sjkim        SciHandler = SciHandler->Next;
528254745Sjkim    }
529254745Sjkim
530254745Sjkim    /* Install the new handler into the global list (at head) */
531254745Sjkim
532254745Sjkim    NewSciHandler->Next = AcpiGbl_SciHandlerList;
533254745Sjkim    AcpiGbl_SciHandlerList = NewSciHandler;
534254745Sjkim
535254745Sjkim
536254745SjkimUnlockAndExit:
537254745Sjkim
538254745Sjkim    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
539254745Sjkim    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
540254745Sjkim
541254745SjkimExit:
542254745Sjkim    if (ACPI_FAILURE (Status))
543254745Sjkim    {
544254745Sjkim        ACPI_FREE (NewSciHandler);
545254745Sjkim    }
546254745Sjkim    return_ACPI_STATUS (Status);
547254745Sjkim}
548254745Sjkim
549281075SdimACPI_EXPORT_SYMBOL (AcpiInstallSciHandler)
550254745Sjkim
551281075Sdim
552254745Sjkim/*******************************************************************************
553254745Sjkim *
554254745Sjkim * FUNCTION:    AcpiRemoveSciHandler
555254745Sjkim *
556254745Sjkim * PARAMETERS:  Address             - Address of the handler
557254745Sjkim *
558254745Sjkim * RETURN:      Status
559254745Sjkim *
560254745Sjkim * DESCRIPTION: Remove a handler for a System Control Interrupt.
561254745Sjkim *
562254745Sjkim ******************************************************************************/
563254745Sjkim
564254745SjkimACPI_STATUS
565254745SjkimAcpiRemoveSciHandler (
566254745Sjkim    ACPI_SCI_HANDLER        Address)
567254745Sjkim{
568254745Sjkim    ACPI_SCI_HANDLER_INFO   *PrevSciHandler;
569254745Sjkim    ACPI_SCI_HANDLER_INFO   *NextSciHandler;
570254745Sjkim    ACPI_CPU_FLAGS          Flags;
571254745Sjkim    ACPI_STATUS             Status;
572254745Sjkim
573254745Sjkim
574254745Sjkim    ACPI_FUNCTION_TRACE (AcpiRemoveSciHandler);
575254745Sjkim
576254745Sjkim
577254745Sjkim    if (!Address)
578254745Sjkim    {
579254745Sjkim        return_ACPI_STATUS (AE_BAD_PARAMETER);
580254745Sjkim    }
581254745Sjkim
582254745Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
583254745Sjkim    if (ACPI_FAILURE (Status))
584254745Sjkim    {
585254745Sjkim        return_ACPI_STATUS (Status);
586254745Sjkim    }
587254745Sjkim
588254745Sjkim    /* Remove the SCI handler with lock */
589254745Sjkim
590254745Sjkim    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
591254745Sjkim
592254745Sjkim    PrevSciHandler = NULL;
593254745Sjkim    NextSciHandler = AcpiGbl_SciHandlerList;
594254745Sjkim    while (NextSciHandler)
595254745Sjkim    {
596254745Sjkim        if (NextSciHandler->Address == Address)
597254745Sjkim        {
598254745Sjkim            /* Unlink and free the SCI handler info block */
599254745Sjkim
600254745Sjkim            if (PrevSciHandler)
601254745Sjkim            {
602254745Sjkim                PrevSciHandler->Next = NextSciHandler->Next;
603254745Sjkim            }
604254745Sjkim            else
605254745Sjkim            {
606254745Sjkim                AcpiGbl_SciHandlerList = NextSciHandler->Next;
607254745Sjkim            }
608254745Sjkim
609254745Sjkim            AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
610254745Sjkim            ACPI_FREE (NextSciHandler);
611254745Sjkim            goto UnlockAndExit;
612254745Sjkim        }
613254745Sjkim
614254745Sjkim        PrevSciHandler = NextSciHandler;
615254745Sjkim        NextSciHandler = NextSciHandler->Next;
616254745Sjkim    }
617254745Sjkim
618254745Sjkim    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
619254745Sjkim    Status = AE_NOT_EXIST;
620254745Sjkim
621254745Sjkim
622254745SjkimUnlockAndExit:
623254745Sjkim    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
624254745Sjkim    return_ACPI_STATUS (Status);
625254745Sjkim}
626254745Sjkim
627281075SdimACPI_EXPORT_SYMBOL (AcpiRemoveSciHandler)
628254745Sjkim
629281075Sdim
630254745Sjkim/*******************************************************************************
631254745Sjkim *
632231844Sjkim * FUNCTION:    AcpiInstallGlobalEventHandler
633231844Sjkim *
634231844Sjkim * PARAMETERS:  Handler         - Pointer to the global event handler function
635231844Sjkim *              Context         - Value passed to the handler on each event
636231844Sjkim *
637231844Sjkim * RETURN:      Status
638231844Sjkim *
639231844Sjkim * DESCRIPTION: Saves the pointer to the handler function. The global handler
640231844Sjkim *              is invoked upon each incoming GPE and Fixed Event. It is
641231844Sjkim *              invoked at interrupt level at the time of the event dispatch.
642231844Sjkim *              Can be used to update event counters, etc.
643231844Sjkim *
644231844Sjkim ******************************************************************************/
645231844Sjkim
646231844SjkimACPI_STATUS
647231844SjkimAcpiInstallGlobalEventHandler (
648231844Sjkim    ACPI_GBL_EVENT_HANDLER  Handler,
649231844Sjkim    void                    *Context)
650231844Sjkim{
651231844Sjkim    ACPI_STATUS             Status;
652231844Sjkim
653231844Sjkim
654231844Sjkim    ACPI_FUNCTION_TRACE (AcpiInstallGlobalEventHandler);
655231844Sjkim
656231844Sjkim
657231844Sjkim    /* Parameter validation */
658231844Sjkim
659231844Sjkim    if (!Handler)
660231844Sjkim    {
661231844Sjkim        return_ACPI_STATUS (AE_BAD_PARAMETER);
662231844Sjkim    }
663231844Sjkim
664231844Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
665231844Sjkim    if (ACPI_FAILURE (Status))
666231844Sjkim    {
667231844Sjkim        return_ACPI_STATUS (Status);
668231844Sjkim    }
669231844Sjkim
670231844Sjkim    /* Don't allow two handlers. */
671231844Sjkim
672231844Sjkim    if (AcpiGbl_GlobalEventHandler)
673231844Sjkim    {
674231844Sjkim        Status = AE_ALREADY_EXISTS;
675231844Sjkim        goto Cleanup;
676231844Sjkim    }
677231844Sjkim
678231844Sjkim    AcpiGbl_GlobalEventHandler = Handler;
679231844Sjkim    AcpiGbl_GlobalEventHandlerContext = Context;
680231844Sjkim
681231844Sjkim
682231844SjkimCleanup:
683231844Sjkim    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
684231844Sjkim    return_ACPI_STATUS (Status);
685231844Sjkim}
686231844Sjkim
687231844SjkimACPI_EXPORT_SYMBOL (AcpiInstallGlobalEventHandler)
688231844Sjkim
689231844Sjkim
690231844Sjkim/*******************************************************************************
691231844Sjkim *
692231844Sjkim * FUNCTION:    AcpiInstallFixedEventHandler
693231844Sjkim *
694231844Sjkim * PARAMETERS:  Event           - Event type to enable.
695231844Sjkim *              Handler         - Pointer to the handler function for the
696231844Sjkim *                                event
697231844Sjkim *              Context         - Value passed to the handler on each GPE
698231844Sjkim *
699231844Sjkim * RETURN:      Status
700231844Sjkim *
701231844Sjkim * DESCRIPTION: Saves the pointer to the handler function and then enables the
702231844Sjkim *              event.
703231844Sjkim *
704231844Sjkim ******************************************************************************/
705231844Sjkim
706231844SjkimACPI_STATUS
707231844SjkimAcpiInstallFixedEventHandler (
708231844Sjkim    UINT32                  Event,
709231844Sjkim    ACPI_EVENT_HANDLER      Handler,
710231844Sjkim    void                    *Context)
711231844Sjkim{
712231844Sjkim    ACPI_STATUS             Status;
713231844Sjkim
714231844Sjkim
715231844Sjkim    ACPI_FUNCTION_TRACE (AcpiInstallFixedEventHandler);
716231844Sjkim
717231844Sjkim
718231844Sjkim    /* Parameter validation */
719231844Sjkim
720231844Sjkim    if (Event > ACPI_EVENT_MAX)
721231844Sjkim    {
722231844Sjkim        return_ACPI_STATUS (AE_BAD_PARAMETER);
723231844Sjkim    }
724231844Sjkim
725231844Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
726231844Sjkim    if (ACPI_FAILURE (Status))
727231844Sjkim    {
728231844Sjkim        return_ACPI_STATUS (Status);
729231844Sjkim    }
730231844Sjkim
731246849Sjkim    /* Do not allow multiple handlers */
732231844Sjkim
733246849Sjkim    if (AcpiGbl_FixedEventHandlers[Event].Handler)
734231844Sjkim    {
735231844Sjkim        Status = AE_ALREADY_EXISTS;
736231844Sjkim        goto Cleanup;
737231844Sjkim    }
738231844Sjkim
739231844Sjkim    /* Install the handler before enabling the event */
740231844Sjkim
741231844Sjkim    AcpiGbl_FixedEventHandlers[Event].Handler = Handler;
742231844Sjkim    AcpiGbl_FixedEventHandlers[Event].Context = Context;
743231844Sjkim
744231844Sjkim    Status = AcpiEnableEvent (Event, 0);
745231844Sjkim    if (ACPI_FAILURE (Status))
746231844Sjkim    {
747246849Sjkim        ACPI_WARNING ((AE_INFO,
748246849Sjkim            "Could not enable fixed event - %s (%u)",
749246849Sjkim            AcpiUtGetEventName (Event), Event));
750231844Sjkim
751231844Sjkim        /* Remove the handler */
752231844Sjkim
753231844Sjkim        AcpiGbl_FixedEventHandlers[Event].Handler = NULL;
754231844Sjkim        AcpiGbl_FixedEventHandlers[Event].Context = NULL;
755231844Sjkim    }
756231844Sjkim    else
757231844Sjkim    {
758231844Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
759246849Sjkim            "Enabled fixed event %s (%X), Handler=%p\n",
760246849Sjkim            AcpiUtGetEventName (Event), Event, Handler));
761231844Sjkim    }
762231844Sjkim
763231844Sjkim
764231844SjkimCleanup:
765231844Sjkim    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
766231844Sjkim    return_ACPI_STATUS (Status);
767231844Sjkim}
768231844Sjkim
769231844SjkimACPI_EXPORT_SYMBOL (AcpiInstallFixedEventHandler)
770231844Sjkim
771231844Sjkim
772231844Sjkim/*******************************************************************************
773231844Sjkim *
774231844Sjkim * FUNCTION:    AcpiRemoveFixedEventHandler
775231844Sjkim *
776231844Sjkim * PARAMETERS:  Event           - Event type to disable.
777231844Sjkim *              Handler         - Address of the handler
778231844Sjkim *
779231844Sjkim * RETURN:      Status
780231844Sjkim *
781231844Sjkim * DESCRIPTION: Disables the event and unregisters the event handler.
782231844Sjkim *
783231844Sjkim ******************************************************************************/
784231844Sjkim
785231844SjkimACPI_STATUS
786231844SjkimAcpiRemoveFixedEventHandler (
787231844Sjkim    UINT32                  Event,
788231844Sjkim    ACPI_EVENT_HANDLER      Handler)
789231844Sjkim{
790231844Sjkim    ACPI_STATUS             Status = AE_OK;
791231844Sjkim
792231844Sjkim
793231844Sjkim    ACPI_FUNCTION_TRACE (AcpiRemoveFixedEventHandler);
794231844Sjkim
795231844Sjkim
796231844Sjkim    /* Parameter validation */
797231844Sjkim
798231844Sjkim    if (Event > ACPI_EVENT_MAX)
799231844Sjkim    {
800231844Sjkim        return_ACPI_STATUS (AE_BAD_PARAMETER);
801231844Sjkim    }
802231844Sjkim
803231844Sjkim    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
804231844Sjkim    if (ACPI_FAILURE (Status))
805231844Sjkim    {
806231844Sjkim        return_ACPI_STATUS (Status);
807231844Sjkim    }
808231844Sjkim
809231844Sjkim    /* Disable the event before removing the handler */
810231844Sjkim
811231844Sjkim    Status = AcpiDisableEvent (Event, 0);
812231844Sjkim
813231844Sjkim    /* Always Remove the handler */
814231844Sjkim
815231844Sjkim    AcpiGbl_FixedEventHandlers[Event].Handler = NULL;
816231844Sjkim    AcpiGbl_FixedEventHandlers[Event].Context = NULL;
817231844Sjkim
818231844Sjkim    if (ACPI_FAILURE (Status))
819231844Sjkim    {
820231844Sjkim        ACPI_WARNING ((AE_INFO,
821246849Sjkim            "Could not disable fixed event - %s (%u)",
822246849Sjkim            AcpiUtGetEventName (Event), Event));
823231844Sjkim    }
824231844Sjkim    else
825231844Sjkim    {
826246849Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
827246849Sjkim            "Disabled fixed event - %s (%X)\n",
828246849Sjkim            AcpiUtGetEventName (Event), Event));
829231844Sjkim    }
830231844Sjkim
831231844Sjkim    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
832231844Sjkim    return_ACPI_STATUS (Status);
833231844Sjkim}
834231844Sjkim
835231844SjkimACPI_EXPORT_SYMBOL (AcpiRemoveFixedEventHandler)
836231844Sjkim
837231844Sjkim
838231844Sjkim/*******************************************************************************
839231844Sjkim *
840281075Sdim * FUNCTION:    AcpiEvInstallGpeHandler
84167754Smsmith *
842151937Sjkim * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
843151937Sjkim *                                defined GPEs)
844151937Sjkim *              GpeNumber       - The GPE number within the GPE block
84567754Smsmith *              Type            - Whether this GPE should be treated as an
84667754Smsmith *                                edge- or level-triggered interrupt.
847281075Sdim *              IsRawHandler    - Whether this GPE should be handled using
848281075Sdim *                                the special GPE handler mode.
849129684Snjl *              Address         - Address of the handler
85067754Smsmith *              Context         - Value passed to the handler on each GPE
85167754Smsmith *
85267754Smsmith * RETURN:      Status
85367754Smsmith *
854281075Sdim * DESCRIPTION: Internal function to install a handler for a General Purpose
855281075Sdim *              Event.
85667754Smsmith *
85767754Smsmith ******************************************************************************/
85867754Smsmith
859281075Sdimstatic ACPI_STATUS
860281075SdimAcpiEvInstallGpeHandler (
861117521Snjl    ACPI_HANDLE             GpeDevice,
86267754Smsmith    UINT32                  GpeNumber,
86367754Smsmith    UINT32                  Type,
864281075Sdim    BOOLEAN                 IsRawHandler,
865216471Sjkim    ACPI_GPE_HANDLER        Address,
86667754Smsmith    void                    *Context)
86767754Smsmith{
868129684Snjl    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
869216471Sjkim    ACPI_GPE_HANDLER_INFO   *Handler;
87091116Smsmith    ACPI_STATUS             Status;
871167802Sjkim    ACPI_CPU_FLAGS          Flags;
87267754Smsmith
87377424Smsmith
874281075Sdim    ACPI_FUNCTION_TRACE (EvInstallGpeHandler);
87567754Smsmith
87677424Smsmith
87767754Smsmith    /* Parameter validation */
87867754Smsmith
879206117Sjkim    if ((!Address) || (Type & ~ACPI_GPE_XRUPT_TYPE_MASK))
88067754Smsmith    {
88167754Smsmith        return_ACPI_STATUS (AE_BAD_PARAMETER);
88267754Smsmith    }
88367754Smsmith
884117521Snjl    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
885117521Snjl    if (ACPI_FAILURE (Status))
886117521Snjl    {
887117521Snjl        return_ACPI_STATUS (Status);
888117521Snjl    }
889117521Snjl
890216471Sjkim    /* Allocate and init handler object (before lock) */
891216471Sjkim
892216471Sjkim    Handler = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_HANDLER_INFO));
893216471Sjkim    if (!Handler)
894216471Sjkim    {
895216471Sjkim        Status = AE_NO_MEMORY;
896216471Sjkim        goto UnlockAndExit;
897216471Sjkim    }
898216471Sjkim
899216471Sjkim    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
900216471Sjkim
90167754Smsmith    /* Ensure that we have a valid GPE number */
90267754Smsmith
903117521Snjl    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
904114237Snjl    if (!GpeEventInfo)
90567754Smsmith    {
906117521Snjl        Status = AE_BAD_PARAMETER;
907216471Sjkim        goto FreeAndExit;
90867754Smsmith    }
90967754Smsmith
91067754Smsmith    /* Make sure that there isn't a handler there already */
91167754Smsmith
912281075Sdim    if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) ==
913281075Sdim            ACPI_GPE_DISPATCH_HANDLER) ||
914281075Sdim        (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) ==
915281075Sdim            ACPI_GPE_DISPATCH_RAW_HANDLER))
91667754Smsmith    {
91787031Smsmith        Status = AE_ALREADY_EXISTS;
918216471Sjkim        goto FreeAndExit;
91967754Smsmith    }
92067754Smsmith
921216471Sjkim    Handler->Address = Address;
922216471Sjkim    Handler->Context = Context;
923216471Sjkim    Handler->MethodNode = GpeEventInfo->Dispatch.MethodNode;
924216471Sjkim    Handler->OriginalFlags = (UINT8) (GpeEventInfo->Flags &
925216471Sjkim        (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK));
92667754Smsmith
927216471Sjkim    /*
928216471Sjkim     * If the GPE is associated with a method, it may have been enabled
929216471Sjkim     * automatically during initialization, in which case it has to be
930216471Sjkim     * disabled now to avoid spurious execution of the handler.
931216471Sjkim     */
932281075Sdim    if (((ACPI_GPE_DISPATCH_TYPE (Handler->OriginalFlags) ==
933281075Sdim            ACPI_GPE_DISPATCH_METHOD) ||
934281075Sdim         (ACPI_GPE_DISPATCH_TYPE (Handler->OriginalFlags) ==
935281075Sdim            ACPI_GPE_DISPATCH_NOTIFY)) &&
936216471Sjkim        GpeEventInfo->RuntimeCount)
937129684Snjl    {
938216471Sjkim        Handler->OriginallyEnabled = TRUE;
939216471Sjkim        (void) AcpiEvRemoveGpeReference (GpeEventInfo);
940216471Sjkim
941216471Sjkim        /* Sanity check of original type against new type */
942216471Sjkim
943216471Sjkim        if (Type != (UINT32) (GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK))
944216471Sjkim        {
945216471Sjkim            ACPI_WARNING ((AE_INFO, "GPE type mismatch (level/edge)"));
946216471Sjkim        }
947129684Snjl    }
94867754Smsmith
949129684Snjl    /* Install the handler */
95085756Smsmith
951129684Snjl    GpeEventInfo->Dispatch.Handler = Handler;
95299679Siwasaki
953216471Sjkim    /* Setup up dispatch flags to indicate handler (vs. method/notify) */
954129684Snjl
955193267Sjkim    GpeEventInfo->Flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
956281075Sdim    GpeEventInfo->Flags |= (UINT8) (Type | (IsRawHandler ?
957281075Sdim        ACPI_GPE_DISPATCH_RAW_HANDLER : ACPI_GPE_DISPATCH_HANDLER));
958129684Snjl
959151937Sjkim    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
960129684Snjl
961129684Snjl
962117521SnjlUnlockAndExit:
96391116Smsmith    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
96467754Smsmith    return_ACPI_STATUS (Status);
965216471Sjkim
966216471SjkimFreeAndExit:
967216471Sjkim    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
968216471Sjkim    ACPI_FREE (Handler);
969216471Sjkim    goto UnlockAndExit;
97067754Smsmith}
97167754Smsmith
972281075Sdim
973281075Sdim/*******************************************************************************
974281075Sdim *
975281075Sdim * FUNCTION:    AcpiInstallGpeHandler
976281075Sdim *
977281075Sdim * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
978281075Sdim *                                defined GPEs)
979281075Sdim *              GpeNumber       - The GPE number within the GPE block
980281075Sdim *              Type            - Whether this GPE should be treated as an
981281075Sdim *                                edge- or level-triggered interrupt.
982281075Sdim *              Address         - Address of the handler
983281075Sdim *              Context         - Value passed to the handler on each GPE
984281075Sdim *
985281075Sdim * RETURN:      Status
986281075Sdim *
987281075Sdim * DESCRIPTION: Install a handler for a General Purpose Event.
988281075Sdim *
989281075Sdim ******************************************************************************/
990281075Sdim
991281075SdimACPI_STATUS
992281075SdimAcpiInstallGpeHandler (
993281075Sdim    ACPI_HANDLE             GpeDevice,
994281075Sdim    UINT32                  GpeNumber,
995281075Sdim    UINT32                  Type,
996281075Sdim    ACPI_GPE_HANDLER        Address,
997281075Sdim    void                    *Context)
998281075Sdim{
999281075Sdim    ACPI_STATUS             Status;
1000281075Sdim
1001281075Sdim
1002281075Sdim    ACPI_FUNCTION_TRACE (AcpiInstallGpeHandler);
1003281075Sdim
1004281075Sdim
1005281075Sdim    Status = AcpiEvInstallGpeHandler (GpeDevice, GpeNumber, Type, FALSE,
1006281075Sdim                Address, Context);
1007281075Sdim
1008281075Sdim    return_ACPI_STATUS (Status);
1009281075Sdim}
1010281075Sdim
1011167802SjkimACPI_EXPORT_SYMBOL (AcpiInstallGpeHandler)
101267754Smsmith
1013167802Sjkim
101477424Smsmith/*******************************************************************************
101567754Smsmith *
1016281075Sdim * FUNCTION:    AcpiInstallGpeRawHandler
1017281075Sdim *
1018281075Sdim * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
1019281075Sdim *                                defined GPEs)
1020281075Sdim *              GpeNumber       - The GPE number within the GPE block
1021281075Sdim *              Type            - Whether this GPE should be treated as an
1022281075Sdim *                                edge- or level-triggered interrupt.
1023281075Sdim *              Address         - Address of the handler
1024281075Sdim *              Context         - Value passed to the handler on each GPE
1025281075Sdim *
1026281075Sdim * RETURN:      Status
1027281075Sdim *
1028281075Sdim * DESCRIPTION: Install a handler for a General Purpose Event.
1029281075Sdim *
1030281075Sdim ******************************************************************************/
1031281075Sdim
1032281075SdimACPI_STATUS
1033281075SdimAcpiInstallGpeRawHandler (
1034281075Sdim    ACPI_HANDLE             GpeDevice,
1035281075Sdim    UINT32                  GpeNumber,
1036281075Sdim    UINT32                  Type,
1037281075Sdim    ACPI_GPE_HANDLER        Address,
1038281075Sdim    void                    *Context)
1039281075Sdim{
1040281075Sdim    ACPI_STATUS             Status;
1041281075Sdim
1042281075Sdim
1043281075Sdim    ACPI_FUNCTION_TRACE (AcpiInstallGpeRawHandler);
1044281075Sdim
1045281075Sdim
1046281075Sdim    Status = AcpiEvInstallGpeHandler (GpeDevice, GpeNumber, Type, TRUE,
1047281075Sdim                Address, Context);
1048281075Sdim
1049281075Sdim    return_ACPI_STATUS (Status);
1050281075Sdim}
1051281075Sdim
1052281075SdimACPI_EXPORT_SYMBOL (AcpiInstallGpeRawHandler)
1053281075Sdim
1054281075Sdim
1055281075Sdim/*******************************************************************************
1056281075Sdim *
105767754Smsmith * FUNCTION:    AcpiRemoveGpeHandler
105867754Smsmith *
1059151937Sjkim * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
1060151937Sjkim *                                defined GPEs)
1061151937Sjkim *              GpeNumber       - The event to remove a handler
1062129684Snjl *              Address         - Address of the handler
106367754Smsmith *
106467754Smsmith * RETURN:      Status
106567754Smsmith *
106667754Smsmith * DESCRIPTION: Remove a handler for a General Purpose AcpiEvent.
106767754Smsmith *
106867754Smsmith ******************************************************************************/
106967754Smsmith
107067754SmsmithACPI_STATUS
107167754SmsmithAcpiRemoveGpeHandler (
1072117521Snjl    ACPI_HANDLE             GpeDevice,
107367754Smsmith    UINT32                  GpeNumber,
1074216471Sjkim    ACPI_GPE_HANDLER        Address)
107567754Smsmith{
1076129684Snjl    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
1077216471Sjkim    ACPI_GPE_HANDLER_INFO   *Handler;
107891116Smsmith    ACPI_STATUS             Status;
1079167802Sjkim    ACPI_CPU_FLAGS          Flags;
108067754Smsmith
108167754Smsmith
1082167802Sjkim    ACPI_FUNCTION_TRACE (AcpiRemoveGpeHandler);
108367754Smsmith
108467754Smsmith
108567754Smsmith    /* Parameter validation */
108667754Smsmith
1087129684Snjl    if (!Address)
108867754Smsmith    {
108967754Smsmith        return_ACPI_STATUS (AE_BAD_PARAMETER);
109067754Smsmith    }
109167754Smsmith
1092117521Snjl    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
1093117521Snjl    if (ACPI_FAILURE (Status))
1094117521Snjl    {
1095117521Snjl        return_ACPI_STATUS (Status);
1096117521Snjl    }
1097117521Snjl
1098216471Sjkim    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
1099216471Sjkim
110067754Smsmith    /* Ensure that we have a valid GPE number */
110167754Smsmith
1102117521Snjl    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
1103114237Snjl    if (!GpeEventInfo)
110467754Smsmith    {
1105117521Snjl        Status = AE_BAD_PARAMETER;
1106117521Snjl        goto UnlockAndExit;
110767754Smsmith    }
110867754Smsmith
1109129684Snjl    /* Make sure that a handler is indeed installed */
111067754Smsmith
1111281075Sdim    if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) !=
1112281075Sdim            ACPI_GPE_DISPATCH_HANDLER) &&
1113281075Sdim        (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) !=
1114281075Sdim            ACPI_GPE_DISPATCH_RAW_HANDLER))
111599679Siwasaki    {
1116129684Snjl        Status = AE_NOT_EXIST;
1117117521Snjl        goto UnlockAndExit;
111899679Siwasaki    }
111967754Smsmith
112067754Smsmith    /* Make sure that the installed handler is the same */
112167754Smsmith
1122129684Snjl    if (GpeEventInfo->Dispatch.Handler->Address != Address)
112367754Smsmith    {
112467754Smsmith        Status = AE_BAD_PARAMETER;
1125117521Snjl        goto UnlockAndExit;
112667754Smsmith    }
112767754Smsmith
112867754Smsmith    /* Remove the handler */
112967754Smsmith
1130129684Snjl    Handler = GpeEventInfo->Dispatch.Handler;
1131281075Sdim    GpeEventInfo->Dispatch.Handler = NULL;
1132129684Snjl
1133129684Snjl    /* Restore Method node (if any), set dispatch flags */
1134129684Snjl
1135129684Snjl    GpeEventInfo->Dispatch.MethodNode = Handler->MethodNode;
1136216471Sjkim    GpeEventInfo->Flags &=
1137216471Sjkim        ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
1138216471Sjkim    GpeEventInfo->Flags |= Handler->OriginalFlags;
1139216471Sjkim
1140216471Sjkim    /*
1141216471Sjkim     * If the GPE was previously associated with a method and it was
1142216471Sjkim     * enabled, it should be enabled at this point to restore the
1143216471Sjkim     * post-initialization configuration.
1144216471Sjkim     */
1145281075Sdim    if (((ACPI_GPE_DISPATCH_TYPE (Handler->OriginalFlags) ==
1146281075Sdim            ACPI_GPE_DISPATCH_METHOD) ||
1147281075Sdim         (ACPI_GPE_DISPATCH_TYPE (Handler->OriginalFlags) ==
1148281075Sdim            ACPI_GPE_DISPATCH_NOTIFY)) &&
1149216471Sjkim        Handler->OriginallyEnabled)
1150129684Snjl    {
1151216471Sjkim        (void) AcpiEvAddGpeReference (GpeEventInfo);
1152129684Snjl    }
115367754Smsmith
1154281075Sdim    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
1155281075Sdim    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
1156281075Sdim
1157281075Sdim    /* Make sure all deferred GPE tasks are completed */
1158281075Sdim
1159281075Sdim    AcpiOsWaitEventsComplete ();
1160281075Sdim
1161129684Snjl    /* Now we can free the handler object */
116285756Smsmith
1163167802Sjkim    ACPI_FREE (Handler);
1164281075Sdim    return_ACPI_STATUS (Status);
1165129684Snjl
1166117521SnjlUnlockAndExit:
1167216471Sjkim    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
116891116Smsmith    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
116967754Smsmith    return_ACPI_STATUS (Status);
117067754Smsmith}
117167754Smsmith
1172167802SjkimACPI_EXPORT_SYMBOL (AcpiRemoveGpeHandler)
117367754Smsmith
1174167802Sjkim
117577424Smsmith/*******************************************************************************
117667754Smsmith *
117767754Smsmith * FUNCTION:    AcpiAcquireGlobalLock
117867754Smsmith *
117967754Smsmith * PARAMETERS:  Timeout         - How long the caller is willing to wait
1180151937Sjkim *              Handle          - Where the handle to the lock is returned
1181151937Sjkim *                                (if acquired)
118267754Smsmith *
118367754Smsmith * RETURN:      Status
118467754Smsmith *
118567754Smsmith * DESCRIPTION: Acquire the ACPI Global Lock
118667754Smsmith *
1187167802Sjkim * Note: Allows callers with the same thread ID to acquire the global lock
1188167802Sjkim * multiple times. In other words, externally, the behavior of the global lock
1189167802Sjkim * is identical to an AML mutex. On the first acquire, a new handle is
1190167802Sjkim * returned. On any subsequent calls to acquire by the same thread, the same
1191167802Sjkim * handle is returned.
1192167802Sjkim *
119367754Smsmith ******************************************************************************/
119485756Smsmith
119567754SmsmithACPI_STATUS
119667754SmsmithAcpiAcquireGlobalLock (
1197107325Siwasaki    UINT16                  Timeout,
119891116Smsmith    UINT32                  *Handle)
119967754Smsmith{
120067754Smsmith    ACPI_STATUS             Status;
120167754Smsmith
120267754Smsmith
120391116Smsmith    if (!Handle)
120491116Smsmith    {
120591116Smsmith        return (AE_BAD_PARAMETER);
120691116Smsmith    }
120791116Smsmith
1208167802Sjkim    /* Must lock interpreter to prevent race conditions */
120977424Smsmith
1210167802Sjkim    AcpiExEnterInterpreter ();
121167754Smsmith
1212167802Sjkim    Status = AcpiExAcquireMutexObject (Timeout,
1213167802Sjkim                AcpiGbl_GlobalLockMutex, AcpiOsGetThreadId ());
1214167802Sjkim
121591116Smsmith    if (ACPI_SUCCESS (Status))
121691116Smsmith    {
1217172314Sjkim        /* Return the global lock handle (updated in AcpiEvAcquireGlobalLock) */
1218167802Sjkim
121991116Smsmith        *Handle = AcpiGbl_GlobalLockHandle;
122091116Smsmith    }
122191116Smsmith
1222167802Sjkim    AcpiExExitInterpreter ();
122367754Smsmith    return (Status);
122467754Smsmith}
122567754Smsmith
1226167802SjkimACPI_EXPORT_SYMBOL (AcpiAcquireGlobalLock)
122767754Smsmith
1228167802Sjkim
122977424Smsmith/*******************************************************************************
123067754Smsmith *
123167754Smsmith * FUNCTION:    AcpiReleaseGlobalLock
123267754Smsmith *
123367754Smsmith * PARAMETERS:  Handle      - Returned from AcpiAcquireGlobalLock
123467754Smsmith *
123567754Smsmith * RETURN:      Status
123667754Smsmith *
1237151937Sjkim * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid.
123867754Smsmith *
123967754Smsmith ******************************************************************************/
124067754Smsmith
124167754SmsmithACPI_STATUS
124267754SmsmithAcpiReleaseGlobalLock (
124391116Smsmith    UINT32                  Handle)
124467754Smsmith{
124599679Siwasaki    ACPI_STATUS             Status;
124685756Smsmith
124799679Siwasaki
1248167802Sjkim    if (!Handle || (Handle != AcpiGbl_GlobalLockHandle))
124991116Smsmith    {
125091116Smsmith        return (AE_NOT_ACQUIRED);
125191116Smsmith    }
125291116Smsmith
1253167802Sjkim    Status = AcpiExReleaseMutexObject (AcpiGbl_GlobalLockMutex);
125499679Siwasaki    return (Status);
125567754Smsmith}
125667754Smsmith
1257167802SjkimACPI_EXPORT_SYMBOL (AcpiReleaseGlobalLock)
125867754Smsmith
1259231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */
1260