evxface.c revision 234623
124149Sguido/******************************************************************************
274531Sru *
324149Sguido * Module Name: evxface - External interfaces for ACPI events
424149Sguido *
574815Sru *****************************************************************************/
6208074Suqs
724149Sguido/*
824149Sguido * Copyright (C) 2000 - 2012, Intel Corp.
924149Sguido * All rights reserved.
1024149Sguido *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions, and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    substantially similar to the "NO WARRANTY" disclaimer below
19 *    ("Disclaimer") and any redistribution must be conditioned upon
20 *    including a substantially similar Disclaimer requirement for further
21 *    binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 *    of any contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44
45#define __EVXFACE_C__
46
47#include <contrib/dev/acpica/include/acpi.h>
48#include <contrib/dev/acpica/include/accommon.h>
49#include <contrib/dev/acpica/include/acnamesp.h>
50#include <contrib/dev/acpica/include/acevents.h>
51#include <contrib/dev/acpica/include/acinterp.h>
52
53#define _COMPONENT          ACPI_EVENTS
54        ACPI_MODULE_NAME    ("evxface")
55
56
57/*******************************************************************************
58 *
59 * FUNCTION:    AcpiInstallNotifyHandler
60 *
61 * PARAMETERS:  Device          - The device for which notifies will be handled
62 *              HandlerType     - The type of handler:
63 *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
64 *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
65 *                                  ACPI_ALL_NOTIFY:    Both System and Device
66 *              Handler         - Address of the handler
67 *              Context         - Value passed to the handler on each GPE
68 *
69 * RETURN:      Status
70 *
71 * DESCRIPTION: Install a handler for notifications on an ACPI Device,
72 *              ThermalZone, or Processor object.
73 *
74 * NOTES:       The Root namespace object may have only one handler for each
75 *              type of notify (System/Device). Device/Thermal/Processor objects
76 *              may have one device notify handler, and multiple system notify
77 *              handlers.
78 *
79 ******************************************************************************/
80
81ACPI_STATUS
82AcpiInstallNotifyHandler (
83    ACPI_HANDLE             Device,
84    UINT32                  HandlerType,
85    ACPI_NOTIFY_HANDLER     Handler,
86    void                    *Context)
87{
88    ACPI_NAMESPACE_NODE     *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Device);
89    ACPI_OPERAND_OBJECT     *ObjDesc;
90    ACPI_OPERAND_OBJECT     *HandlerObj;
91    ACPI_STATUS             Status;
92    UINT32                  i;
93
94
95    ACPI_FUNCTION_TRACE (AcpiInstallNotifyHandler);
96
97
98    /* Parameter validation */
99
100    if ((!Device) || (!Handler) || (!HandlerType) ||
101        (HandlerType > ACPI_MAX_NOTIFY_HANDLER_TYPE))
102    {
103        return_ACPI_STATUS (AE_BAD_PARAMETER);
104    }
105
106    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
107    if (ACPI_FAILURE (Status))
108    {
109        return_ACPI_STATUS (Status);
110    }
111
112    /*
113     * Root Object:
114     * Registering a notify handler on the root object indicates that the
115     * caller wishes to receive notifications for all objects. Note that
116     * only one global handler can be registered per notify type.
117     * Ensure that a handler is not already installed.
118     */
119    if (Device == ACPI_ROOT_OBJECT)
120    {
121        for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
122        {
123            if (HandlerType & (i+1))
124            {
125                if (AcpiGbl_GlobalNotify[i].Handler)
126                {
127                    Status = AE_ALREADY_EXISTS;
128                    goto UnlockAndExit;
129                }
130
131                AcpiGbl_GlobalNotify[i].Handler = Handler;
132                AcpiGbl_GlobalNotify[i].Context = Context;
133            }
134        }
135
136        goto UnlockAndExit; /* Global notify handler installed, all done */
137    }
138
139    /*
140     * All Other Objects:
141     * Caller will only receive notifications specific to the target
142     * object. Note that only certain object types are allowed to
143     * receive notifications.
144     */
145
146    /* Are Notifies allowed on this object? */
147
148    if (!AcpiEvIsNotifyObject (Node))
149    {
150        Status = AE_TYPE;
151        goto UnlockAndExit;
152    }
153
154    /* Check for an existing internal object, might not exist */
155
156    ObjDesc = AcpiNsGetAttachedObject (Node);
157    if (!ObjDesc)
158    {
159        /* Create a new object */
160
161        ObjDesc = AcpiUtCreateInternalObject (Node->Type);
162        if (!ObjDesc)
163        {
164            Status = AE_NO_MEMORY;
165            goto UnlockAndExit;
166        }
167
168        /* Attach new object to the Node, remove local reference */
169
170        Status = AcpiNsAttachObject (Device, ObjDesc, Node->Type);
171        AcpiUtRemoveReference (ObjDesc);
172        if (ACPI_FAILURE (Status))
173        {
174            goto UnlockAndExit;
175        }
176    }
177
178    /* Ensure that the handler is not already installed in the lists */
179
180    for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
181    {
182        if (HandlerType & (i+1))
183        {
184            HandlerObj = ObjDesc->CommonNotify.NotifyList[i];
185            while (HandlerObj)
186            {
187                if (HandlerObj->Notify.Handler == Handler)
188                {
189                    Status = AE_ALREADY_EXISTS;
190                    goto UnlockAndExit;
191                }
192
193                HandlerObj = HandlerObj->Notify.Next[i];
194            }
195        }
196    }
197
198    /* Create and populate a new notify handler object */
199
200    HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_NOTIFY);
201    if (!HandlerObj)
202    {
203        Status = AE_NO_MEMORY;
204        goto UnlockAndExit;
205    }
206
207    HandlerObj->Notify.Node = Node;
208    HandlerObj->Notify.HandlerType = HandlerType;
209    HandlerObj->Notify.Handler = Handler;
210    HandlerObj->Notify.Context = Context;
211
212    /* Install the handler at the list head(s) */
213
214    for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
215    {
216        if (HandlerType & (i+1))
217        {
218            HandlerObj->Notify.Next[i] =
219                ObjDesc->CommonNotify.NotifyList[i];
220
221            ObjDesc->CommonNotify.NotifyList[i] = HandlerObj;
222        }
223    }
224
225    /* Add an extra reference if handler was installed in both lists */
226
227    if (HandlerType == ACPI_ALL_NOTIFY)
228    {
229        AcpiUtAddReference (HandlerObj);
230    }
231
232
233UnlockAndExit:
234    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
235    return_ACPI_STATUS (Status);
236}
237
238ACPI_EXPORT_SYMBOL (AcpiInstallNotifyHandler)
239
240
241/*******************************************************************************
242 *
243 * FUNCTION:    AcpiRemoveNotifyHandler
244 *
245 * PARAMETERS:  Device          - The device for which the handler is installed
246 *              HandlerType     - The type of handler:
247 *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
248 *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
249 *                                  ACPI_ALL_NOTIFY:    Both System and Device
250 *              Handler         - Address of the handler
251 *
252 * RETURN:      Status
253 *
254 * DESCRIPTION: Remove a handler for notifies on an ACPI device
255 *
256 ******************************************************************************/
257
258ACPI_STATUS
259AcpiRemoveNotifyHandler (
260    ACPI_HANDLE             Device,
261    UINT32                  HandlerType,
262    ACPI_NOTIFY_HANDLER     Handler)
263{
264    ACPI_NAMESPACE_NODE     *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Device);
265    ACPI_OPERAND_OBJECT     *ObjDesc;
266    ACPI_OPERAND_OBJECT     *HandlerObj;
267    ACPI_OPERAND_OBJECT     *PreviousHandlerObj;
268    ACPI_STATUS             Status;
269    UINT32                  i;
270
271
272    ACPI_FUNCTION_TRACE (AcpiRemoveNotifyHandler);
273
274
275    /* Parameter validation */
276
277    if ((!Device) || (!Handler) || (!HandlerType) ||
278        (HandlerType > ACPI_MAX_NOTIFY_HANDLER_TYPE))
279    {
280        return_ACPI_STATUS (AE_BAD_PARAMETER);
281    }
282
283#ifdef _UNDER_DEVELOPMENT
284    /* Make sure all deferred tasks are completed */
285
286    AcpiOsWaitEventsComplete (NULL);
287#endif
288
289    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
290    if (ACPI_FAILURE (Status))
291    {
292        return_ACPI_STATUS (Status);
293    }
294
295    /* Root Object. Global handlers are removed here */
296
297    if (Device == ACPI_ROOT_OBJECT)
298    {
299        for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
300        {
301            if (HandlerType & (i+1))
302            {
303                if (!AcpiGbl_GlobalNotify[i].Handler ||
304                    (AcpiGbl_GlobalNotify[i].Handler != Handler))
305                {
306                    Status = AE_NOT_EXIST;
307                    goto UnlockAndExit;
308                }
309
310                ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
311                    "Removing global notify handler\n"));
312
313                AcpiGbl_GlobalNotify[i].Handler = NULL;
314                AcpiGbl_GlobalNotify[i].Context = NULL;
315            }
316        }
317
318        goto UnlockAndExit;
319    }
320
321    /* All other objects: Are Notifies allowed on this object? */
322
323    if (!AcpiEvIsNotifyObject (Node))
324    {
325        Status = AE_TYPE;
326        goto UnlockAndExit;
327    }
328
329    /* Must have an existing internal object */
330
331    ObjDesc = AcpiNsGetAttachedObject (Node);
332    if (!ObjDesc)
333    {
334        Status = AE_NOT_EXIST;
335        goto UnlockAndExit;
336    }
337
338    /* Internal object exists. Find the handler and remove it */
339
340    for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
341    {
342        if (HandlerType & (i+1))
343        {
344            HandlerObj = ObjDesc->CommonNotify.NotifyList[i];
345            PreviousHandlerObj = NULL;
346
347            /* Attempt to find the handler in the handler list */
348
349            while (HandlerObj &&
350                  (HandlerObj->Notify.Handler != Handler))
351            {
352                PreviousHandlerObj = HandlerObj;
353                HandlerObj = HandlerObj->Notify.Next[i];
354            }
355
356            if (!HandlerObj)
357            {
358                Status = AE_NOT_EXIST;
359                goto UnlockAndExit;
360            }
361
362            /* Remove the handler object from the list */
363
364            if (PreviousHandlerObj) /* Handler is not at the list head */
365            {
366                PreviousHandlerObj->Notify.Next[i] =
367                    HandlerObj->Notify.Next[i];
368            }
369            else /* Handler is at the list head */
370            {
371                ObjDesc->CommonNotify.NotifyList[i] =
372                    HandlerObj->Notify.Next[i];
373            }
374
375            AcpiUtRemoveReference (HandlerObj);
376        }
377    }
378
379
380UnlockAndExit:
381    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
382    return_ACPI_STATUS (Status);
383}
384
385ACPI_EXPORT_SYMBOL (AcpiRemoveNotifyHandler)
386
387
388/*******************************************************************************
389 *
390 * FUNCTION:    AcpiInstallExceptionHandler
391 *
392 * PARAMETERS:  Handler         - Pointer to the handler function for the
393 *                                event
394 *
395 * RETURN:      Status
396 *
397 * DESCRIPTION: Saves the pointer to the handler function
398 *
399 ******************************************************************************/
400
401ACPI_STATUS
402AcpiInstallExceptionHandler (
403    ACPI_EXCEPTION_HANDLER  Handler)
404{
405    ACPI_STATUS             Status;
406
407
408    ACPI_FUNCTION_TRACE (AcpiInstallExceptionHandler);
409
410
411    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
412    if (ACPI_FAILURE (Status))
413    {
414        return_ACPI_STATUS (Status);
415    }
416
417    /* Don't allow two handlers. */
418
419    if (AcpiGbl_ExceptionHandler)
420    {
421        Status = AE_ALREADY_EXISTS;
422        goto Cleanup;
423    }
424
425    /* Install the handler */
426
427    AcpiGbl_ExceptionHandler = Handler;
428
429Cleanup:
430    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
431    return_ACPI_STATUS (Status);
432}
433
434ACPI_EXPORT_SYMBOL (AcpiInstallExceptionHandler)
435
436
437#if (!ACPI_REDUCED_HARDWARE)
438/*******************************************************************************
439 *
440 * FUNCTION:    AcpiInstallGlobalEventHandler
441 *
442 * PARAMETERS:  Handler         - Pointer to the global event handler function
443 *              Context         - Value passed to the handler on each event
444 *
445 * RETURN:      Status
446 *
447 * DESCRIPTION: Saves the pointer to the handler function. The global handler
448 *              is invoked upon each incoming GPE and Fixed Event. It is
449 *              invoked at interrupt level at the time of the event dispatch.
450 *              Can be used to update event counters, etc.
451 *
452 ******************************************************************************/
453
454ACPI_STATUS
455AcpiInstallGlobalEventHandler (
456    ACPI_GBL_EVENT_HANDLER  Handler,
457    void                    *Context)
458{
459    ACPI_STATUS             Status;
460
461
462    ACPI_FUNCTION_TRACE (AcpiInstallGlobalEventHandler);
463
464
465    /* Parameter validation */
466
467    if (!Handler)
468    {
469        return_ACPI_STATUS (AE_BAD_PARAMETER);
470    }
471
472    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
473    if (ACPI_FAILURE (Status))
474    {
475        return_ACPI_STATUS (Status);
476    }
477
478    /* Don't allow two handlers. */
479
480    if (AcpiGbl_GlobalEventHandler)
481    {
482        Status = AE_ALREADY_EXISTS;
483        goto Cleanup;
484    }
485
486    AcpiGbl_GlobalEventHandler = Handler;
487    AcpiGbl_GlobalEventHandlerContext = Context;
488
489
490Cleanup:
491    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
492    return_ACPI_STATUS (Status);
493}
494
495ACPI_EXPORT_SYMBOL (AcpiInstallGlobalEventHandler)
496
497
498/*******************************************************************************
499 *
500 * FUNCTION:    AcpiInstallFixedEventHandler
501 *
502 * PARAMETERS:  Event           - Event type to enable.
503 *              Handler         - Pointer to the handler function for the
504 *                                event
505 *              Context         - Value passed to the handler on each GPE
506 *
507 * RETURN:      Status
508 *
509 * DESCRIPTION: Saves the pointer to the handler function and then enables the
510 *              event.
511 *
512 ******************************************************************************/
513
514ACPI_STATUS
515AcpiInstallFixedEventHandler (
516    UINT32                  Event,
517    ACPI_EVENT_HANDLER      Handler,
518    void                    *Context)
519{
520    ACPI_STATUS             Status;
521
522
523    ACPI_FUNCTION_TRACE (AcpiInstallFixedEventHandler);
524
525
526    /* Parameter validation */
527
528    if (Event > ACPI_EVENT_MAX)
529    {
530        return_ACPI_STATUS (AE_BAD_PARAMETER);
531    }
532
533    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
534    if (ACPI_FAILURE (Status))
535    {
536        return_ACPI_STATUS (Status);
537    }
538
539    /* Don't allow two handlers. */
540
541    if (NULL != AcpiGbl_FixedEventHandlers[Event].Handler)
542    {
543        Status = AE_ALREADY_EXISTS;
544        goto Cleanup;
545    }
546
547    /* Install the handler before enabling the event */
548
549    AcpiGbl_FixedEventHandlers[Event].Handler = Handler;
550    AcpiGbl_FixedEventHandlers[Event].Context = Context;
551
552    Status = AcpiEnableEvent (Event, 0);
553    if (ACPI_FAILURE (Status))
554    {
555        ACPI_WARNING ((AE_INFO, "Could not enable fixed event 0x%X", Event));
556
557        /* Remove the handler */
558
559        AcpiGbl_FixedEventHandlers[Event].Handler = NULL;
560        AcpiGbl_FixedEventHandlers[Event].Context = NULL;
561    }
562    else
563    {
564        ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
565            "Enabled fixed event %X, Handler=%p\n", Event, Handler));
566    }
567
568
569Cleanup:
570    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
571    return_ACPI_STATUS (Status);
572}
573
574ACPI_EXPORT_SYMBOL (AcpiInstallFixedEventHandler)
575
576
577/*******************************************************************************
578 *
579 * FUNCTION:    AcpiRemoveFixedEventHandler
580 *
581 * PARAMETERS:  Event           - Event type to disable.
582 *              Handler         - Address of the handler
583 *
584 * RETURN:      Status
585 *
586 * DESCRIPTION: Disables the event and unregisters the event handler.
587 *
588 ******************************************************************************/
589
590ACPI_STATUS
591AcpiRemoveFixedEventHandler (
592    UINT32                  Event,
593    ACPI_EVENT_HANDLER      Handler)
594{
595    ACPI_STATUS             Status = AE_OK;
596
597
598    ACPI_FUNCTION_TRACE (AcpiRemoveFixedEventHandler);
599
600
601    /* Parameter validation */
602
603    if (Event > ACPI_EVENT_MAX)
604    {
605        return_ACPI_STATUS (AE_BAD_PARAMETER);
606    }
607
608    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
609    if (ACPI_FAILURE (Status))
610    {
611        return_ACPI_STATUS (Status);
612    }
613
614    /* Disable the event before removing the handler */
615
616    Status = AcpiDisableEvent (Event, 0);
617
618    /* Always Remove the handler */
619
620    AcpiGbl_FixedEventHandlers[Event].Handler = NULL;
621    AcpiGbl_FixedEventHandlers[Event].Context = NULL;
622
623    if (ACPI_FAILURE (Status))
624    {
625        ACPI_WARNING ((AE_INFO,
626            "Could not write to fixed event enable register 0x%X", Event));
627    }
628    else
629    {
630        ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Disabled fixed event %X\n", Event));
631    }
632
633    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
634    return_ACPI_STATUS (Status);
635}
636
637ACPI_EXPORT_SYMBOL (AcpiRemoveFixedEventHandler)
638
639
640/*******************************************************************************
641 *
642 * FUNCTION:    AcpiInstallGpeHandler
643 *
644 * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
645 *                                defined GPEs)
646 *              GpeNumber       - The GPE number within the GPE block
647 *              Type            - Whether this GPE should be treated as an
648 *                                edge- or level-triggered interrupt.
649 *              Address         - Address of the handler
650 *              Context         - Value passed to the handler on each GPE
651 *
652 * RETURN:      Status
653 *
654 * DESCRIPTION: Install a handler for a General Purpose Event.
655 *
656 ******************************************************************************/
657
658ACPI_STATUS
659AcpiInstallGpeHandler (
660    ACPI_HANDLE             GpeDevice,
661    UINT32                  GpeNumber,
662    UINT32                  Type,
663    ACPI_GPE_HANDLER        Address,
664    void                    *Context)
665{
666    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
667    ACPI_GPE_HANDLER_INFO   *Handler;
668    ACPI_STATUS             Status;
669    ACPI_CPU_FLAGS          Flags;
670
671
672    ACPI_FUNCTION_TRACE (AcpiInstallGpeHandler);
673
674
675    /* Parameter validation */
676
677    if ((!Address) || (Type & ~ACPI_GPE_XRUPT_TYPE_MASK))
678    {
679        return_ACPI_STATUS (AE_BAD_PARAMETER);
680    }
681
682    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
683    if (ACPI_FAILURE (Status))
684    {
685        return_ACPI_STATUS (Status);
686    }
687
688    /* Allocate and init handler object (before lock) */
689
690    Handler = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_HANDLER_INFO));
691    if (!Handler)
692    {
693        Status = AE_NO_MEMORY;
694        goto UnlockAndExit;
695    }
696
697    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
698
699    /* Ensure that we have a valid GPE number */
700
701    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
702    if (!GpeEventInfo)
703    {
704        Status = AE_BAD_PARAMETER;
705        goto FreeAndExit;
706    }
707
708    /* Make sure that there isn't a handler there already */
709
710    if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
711            ACPI_GPE_DISPATCH_HANDLER)
712    {
713        Status = AE_ALREADY_EXISTS;
714        goto FreeAndExit;
715    }
716
717    Handler->Address = Address;
718    Handler->Context = Context;
719    Handler->MethodNode = GpeEventInfo->Dispatch.MethodNode;
720    Handler->OriginalFlags = (UINT8) (GpeEventInfo->Flags &
721        (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK));
722
723    /*
724     * If the GPE is associated with a method, it may have been enabled
725     * automatically during initialization, in which case it has to be
726     * disabled now to avoid spurious execution of the handler.
727     */
728    if (((Handler->OriginalFlags & ACPI_GPE_DISPATCH_METHOD) ||
729         (Handler->OriginalFlags & ACPI_GPE_DISPATCH_NOTIFY)) &&
730        GpeEventInfo->RuntimeCount)
731    {
732        Handler->OriginallyEnabled = TRUE;
733        (void) AcpiEvRemoveGpeReference (GpeEventInfo);
734
735        /* Sanity check of original type against new type */
736
737        if (Type != (UINT32) (GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK))
738        {
739            ACPI_WARNING ((AE_INFO, "GPE type mismatch (level/edge)"));
740        }
741    }
742
743    /* Install the handler */
744
745    GpeEventInfo->Dispatch.Handler = Handler;
746
747    /* Setup up dispatch flags to indicate handler (vs. method/notify) */
748
749    GpeEventInfo->Flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
750    GpeEventInfo->Flags |= (UINT8) (Type | ACPI_GPE_DISPATCH_HANDLER);
751
752    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
753
754
755UnlockAndExit:
756    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
757    return_ACPI_STATUS (Status);
758
759FreeAndExit:
760    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
761    ACPI_FREE (Handler);
762    goto UnlockAndExit;
763}
764
765ACPI_EXPORT_SYMBOL (AcpiInstallGpeHandler)
766
767
768/*******************************************************************************
769 *
770 * FUNCTION:    AcpiRemoveGpeHandler
771 *
772 * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
773 *                                defined GPEs)
774 *              GpeNumber       - The event to remove a handler
775 *              Address         - Address of the handler
776 *
777 * RETURN:      Status
778 *
779 * DESCRIPTION: Remove a handler for a General Purpose AcpiEvent.
780 *
781 ******************************************************************************/
782
783ACPI_STATUS
784AcpiRemoveGpeHandler (
785    ACPI_HANDLE             GpeDevice,
786    UINT32                  GpeNumber,
787    ACPI_GPE_HANDLER        Address)
788{
789    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
790    ACPI_GPE_HANDLER_INFO   *Handler;
791    ACPI_STATUS             Status;
792    ACPI_CPU_FLAGS          Flags;
793
794
795    ACPI_FUNCTION_TRACE (AcpiRemoveGpeHandler);
796
797
798    /* Parameter validation */
799
800    if (!Address)
801    {
802        return_ACPI_STATUS (AE_BAD_PARAMETER);
803    }
804
805    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
806    if (ACPI_FAILURE (Status))
807    {
808        return_ACPI_STATUS (Status);
809    }
810
811    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
812
813    /* Ensure that we have a valid GPE number */
814
815    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
816    if (!GpeEventInfo)
817    {
818        Status = AE_BAD_PARAMETER;
819        goto UnlockAndExit;
820    }
821
822    /* Make sure that a handler is indeed installed */
823
824    if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) !=
825            ACPI_GPE_DISPATCH_HANDLER)
826    {
827        Status = AE_NOT_EXIST;
828        goto UnlockAndExit;
829    }
830
831    /* Make sure that the installed handler is the same */
832
833    if (GpeEventInfo->Dispatch.Handler->Address != Address)
834    {
835        Status = AE_BAD_PARAMETER;
836        goto UnlockAndExit;
837    }
838
839    /* Remove the handler */
840
841    Handler = GpeEventInfo->Dispatch.Handler;
842
843    /* Restore Method node (if any), set dispatch flags */
844
845    GpeEventInfo->Dispatch.MethodNode = Handler->MethodNode;
846    GpeEventInfo->Flags &=
847        ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
848    GpeEventInfo->Flags |= Handler->OriginalFlags;
849
850    /*
851     * If the GPE was previously associated with a method and it was
852     * enabled, it should be enabled at this point to restore the
853     * post-initialization configuration.
854     */
855    if ((Handler->OriginalFlags & ACPI_GPE_DISPATCH_METHOD) &&
856        Handler->OriginallyEnabled)
857    {
858        (void) AcpiEvAddGpeReference (GpeEventInfo);
859    }
860
861    /* Now we can free the handler object */
862
863    ACPI_FREE (Handler);
864
865
866UnlockAndExit:
867    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
868    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
869    return_ACPI_STATUS (Status);
870}
871
872ACPI_EXPORT_SYMBOL (AcpiRemoveGpeHandler)
873
874
875/*******************************************************************************
876 *
877 * FUNCTION:    AcpiAcquireGlobalLock
878 *
879 * PARAMETERS:  Timeout         - How long the caller is willing to wait
880 *              Handle          - Where the handle to the lock is returned
881 *                                (if acquired)
882 *
883 * RETURN:      Status
884 *
885 * DESCRIPTION: Acquire the ACPI Global Lock
886 *
887 * Note: Allows callers with the same thread ID to acquire the global lock
888 * multiple times. In other words, externally, the behavior of the global lock
889 * is identical to an AML mutex. On the first acquire, a new handle is
890 * returned. On any subsequent calls to acquire by the same thread, the same
891 * handle is returned.
892 *
893 ******************************************************************************/
894
895ACPI_STATUS
896AcpiAcquireGlobalLock (
897    UINT16                  Timeout,
898    UINT32                  *Handle)
899{
900    ACPI_STATUS             Status;
901
902
903    if (!Handle)
904    {
905        return (AE_BAD_PARAMETER);
906    }
907
908    /* Must lock interpreter to prevent race conditions */
909
910    AcpiExEnterInterpreter ();
911
912    Status = AcpiExAcquireMutexObject (Timeout,
913                AcpiGbl_GlobalLockMutex, AcpiOsGetThreadId ());
914
915    if (ACPI_SUCCESS (Status))
916    {
917        /* Return the global lock handle (updated in AcpiEvAcquireGlobalLock) */
918
919        *Handle = AcpiGbl_GlobalLockHandle;
920    }
921
922    AcpiExExitInterpreter ();
923    return (Status);
924}
925
926ACPI_EXPORT_SYMBOL (AcpiAcquireGlobalLock)
927
928
929/*******************************************************************************
930 *
931 * FUNCTION:    AcpiReleaseGlobalLock
932 *
933 * PARAMETERS:  Handle      - Returned from AcpiAcquireGlobalLock
934 *
935 * RETURN:      Status
936 *
937 * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid.
938 *
939 ******************************************************************************/
940
941ACPI_STATUS
942AcpiReleaseGlobalLock (
943    UINT32                  Handle)
944{
945    ACPI_STATUS             Status;
946
947
948    if (!Handle || (Handle != AcpiGbl_GlobalLockHandle))
949    {
950        return (AE_NOT_ACQUIRED);
951    }
952
953    Status = AcpiExReleaseMutexObject (AcpiGbl_GlobalLockMutex);
954    return (Status);
955}
956
957ACPI_EXPORT_SYMBOL (AcpiReleaseGlobalLock)
958
959#endif /* !ACPI_REDUCED_HARDWARE */
960