xref: /freebsd/sys/contrib/dev/acpica/components/events/evxface.c (revision 595e514d0df2bac5b813d35f83e32875dbf16a83)
1 /******************************************************************************
2  *
3  * Module Name: evxface - External interfaces for ACPI events
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2013, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 
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 
81 ACPI_STATUS
82 AcpiInstallNotifyHandler (
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 
233 UnlockAndExit:
234     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
235     return_ACPI_STATUS (Status);
236 }
237 
238 ACPI_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 
258 ACPI_STATUS
259 AcpiRemoveNotifyHandler (
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     /* Make sure all deferred notify tasks are completed */
284 
285     AcpiOsWaitEventsComplete ();
286 
287     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
288     if (ACPI_FAILURE (Status))
289     {
290         return_ACPI_STATUS (Status);
291     }
292 
293     /* Root Object. Global handlers are removed here */
294 
295     if (Device == ACPI_ROOT_OBJECT)
296     {
297         for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
298         {
299             if (HandlerType & (i+1))
300             {
301                 if (!AcpiGbl_GlobalNotify[i].Handler ||
302                     (AcpiGbl_GlobalNotify[i].Handler != Handler))
303                 {
304                     Status = AE_NOT_EXIST;
305                     goto UnlockAndExit;
306                 }
307 
308                 ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
309                     "Removing global notify handler\n"));
310 
311                 AcpiGbl_GlobalNotify[i].Handler = NULL;
312                 AcpiGbl_GlobalNotify[i].Context = NULL;
313             }
314         }
315 
316         goto UnlockAndExit;
317     }
318 
319     /* All other objects: Are Notifies allowed on this object? */
320 
321     if (!AcpiEvIsNotifyObject (Node))
322     {
323         Status = AE_TYPE;
324         goto UnlockAndExit;
325     }
326 
327     /* Must have an existing internal object */
328 
329     ObjDesc = AcpiNsGetAttachedObject (Node);
330     if (!ObjDesc)
331     {
332         Status = AE_NOT_EXIST;
333         goto UnlockAndExit;
334     }
335 
336     /* Internal object exists. Find the handler and remove it */
337 
338     for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
339     {
340         if (HandlerType & (i+1))
341         {
342             HandlerObj = ObjDesc->CommonNotify.NotifyList[i];
343             PreviousHandlerObj = NULL;
344 
345             /* Attempt to find the handler in the handler list */
346 
347             while (HandlerObj &&
348                   (HandlerObj->Notify.Handler != Handler))
349             {
350                 PreviousHandlerObj = HandlerObj;
351                 HandlerObj = HandlerObj->Notify.Next[i];
352             }
353 
354             if (!HandlerObj)
355             {
356                 Status = AE_NOT_EXIST;
357                 goto UnlockAndExit;
358             }
359 
360             /* Remove the handler object from the list */
361 
362             if (PreviousHandlerObj) /* Handler is not at the list head */
363             {
364                 PreviousHandlerObj->Notify.Next[i] =
365                     HandlerObj->Notify.Next[i];
366             }
367             else /* Handler is at the list head */
368             {
369                 ObjDesc->CommonNotify.NotifyList[i] =
370                     HandlerObj->Notify.Next[i];
371             }
372 
373             AcpiUtRemoveReference (HandlerObj);
374         }
375     }
376 
377 
378 UnlockAndExit:
379     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
380     return_ACPI_STATUS (Status);
381 }
382 
383 ACPI_EXPORT_SYMBOL (AcpiRemoveNotifyHandler)
384 
385 
386 /*******************************************************************************
387  *
388  * FUNCTION:    AcpiInstallExceptionHandler
389  *
390  * PARAMETERS:  Handler         - Pointer to the handler function for the
391  *                                event
392  *
393  * RETURN:      Status
394  *
395  * DESCRIPTION: Saves the pointer to the handler function
396  *
397  ******************************************************************************/
398 
399 ACPI_STATUS
400 AcpiInstallExceptionHandler (
401     ACPI_EXCEPTION_HANDLER  Handler)
402 {
403     ACPI_STATUS             Status;
404 
405 
406     ACPI_FUNCTION_TRACE (AcpiInstallExceptionHandler);
407 
408 
409     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
410     if (ACPI_FAILURE (Status))
411     {
412         return_ACPI_STATUS (Status);
413     }
414 
415     /* Don't allow two handlers. */
416 
417     if (AcpiGbl_ExceptionHandler)
418     {
419         Status = AE_ALREADY_EXISTS;
420         goto Cleanup;
421     }
422 
423     /* Install the handler */
424 
425     AcpiGbl_ExceptionHandler = Handler;
426 
427 Cleanup:
428     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
429     return_ACPI_STATUS (Status);
430 }
431 
432 ACPI_EXPORT_SYMBOL (AcpiInstallExceptionHandler)
433 
434 
435 #if (!ACPI_REDUCED_HARDWARE)
436 /*******************************************************************************
437  *
438  * FUNCTION:    AcpiInstallGlobalEventHandler
439  *
440  * PARAMETERS:  Handler         - Pointer to the global event handler function
441  *              Context         - Value passed to the handler on each event
442  *
443  * RETURN:      Status
444  *
445  * DESCRIPTION: Saves the pointer to the handler function. The global handler
446  *              is invoked upon each incoming GPE and Fixed Event. It is
447  *              invoked at interrupt level at the time of the event dispatch.
448  *              Can be used to update event counters, etc.
449  *
450  ******************************************************************************/
451 
452 ACPI_STATUS
453 AcpiInstallGlobalEventHandler (
454     ACPI_GBL_EVENT_HANDLER  Handler,
455     void                    *Context)
456 {
457     ACPI_STATUS             Status;
458 
459 
460     ACPI_FUNCTION_TRACE (AcpiInstallGlobalEventHandler);
461 
462 
463     /* Parameter validation */
464 
465     if (!Handler)
466     {
467         return_ACPI_STATUS (AE_BAD_PARAMETER);
468     }
469 
470     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
471     if (ACPI_FAILURE (Status))
472     {
473         return_ACPI_STATUS (Status);
474     }
475 
476     /* Don't allow two handlers. */
477 
478     if (AcpiGbl_GlobalEventHandler)
479     {
480         Status = AE_ALREADY_EXISTS;
481         goto Cleanup;
482     }
483 
484     AcpiGbl_GlobalEventHandler = Handler;
485     AcpiGbl_GlobalEventHandlerContext = Context;
486 
487 
488 Cleanup:
489     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
490     return_ACPI_STATUS (Status);
491 }
492 
493 ACPI_EXPORT_SYMBOL (AcpiInstallGlobalEventHandler)
494 
495 
496 /*******************************************************************************
497  *
498  * FUNCTION:    AcpiInstallFixedEventHandler
499  *
500  * PARAMETERS:  Event           - Event type to enable.
501  *              Handler         - Pointer to the handler function for the
502  *                                event
503  *              Context         - Value passed to the handler on each GPE
504  *
505  * RETURN:      Status
506  *
507  * DESCRIPTION: Saves the pointer to the handler function and then enables the
508  *              event.
509  *
510  ******************************************************************************/
511 
512 ACPI_STATUS
513 AcpiInstallFixedEventHandler (
514     UINT32                  Event,
515     ACPI_EVENT_HANDLER      Handler,
516     void                    *Context)
517 {
518     ACPI_STATUS             Status;
519 
520 
521     ACPI_FUNCTION_TRACE (AcpiInstallFixedEventHandler);
522 
523 
524     /* Parameter validation */
525 
526     if (Event > ACPI_EVENT_MAX)
527     {
528         return_ACPI_STATUS (AE_BAD_PARAMETER);
529     }
530 
531     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
532     if (ACPI_FAILURE (Status))
533     {
534         return_ACPI_STATUS (Status);
535     }
536 
537     /* Do not allow multiple handlers */
538 
539     if (AcpiGbl_FixedEventHandlers[Event].Handler)
540     {
541         Status = AE_ALREADY_EXISTS;
542         goto Cleanup;
543     }
544 
545     /* Install the handler before enabling the event */
546 
547     AcpiGbl_FixedEventHandlers[Event].Handler = Handler;
548     AcpiGbl_FixedEventHandlers[Event].Context = Context;
549 
550     Status = AcpiEnableEvent (Event, 0);
551     if (ACPI_FAILURE (Status))
552     {
553         ACPI_WARNING ((AE_INFO,
554             "Could not enable fixed event - %s (%u)",
555             AcpiUtGetEventName (Event), 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 %s (%X), Handler=%p\n",
566             AcpiUtGetEventName (Event), Event, Handler));
567     }
568 
569 
570 Cleanup:
571     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
572     return_ACPI_STATUS (Status);
573 }
574 
575 ACPI_EXPORT_SYMBOL (AcpiInstallFixedEventHandler)
576 
577 
578 /*******************************************************************************
579  *
580  * FUNCTION:    AcpiRemoveFixedEventHandler
581  *
582  * PARAMETERS:  Event           - Event type to disable.
583  *              Handler         - Address of the handler
584  *
585  * RETURN:      Status
586  *
587  * DESCRIPTION: Disables the event and unregisters the event handler.
588  *
589  ******************************************************************************/
590 
591 ACPI_STATUS
592 AcpiRemoveFixedEventHandler (
593     UINT32                  Event,
594     ACPI_EVENT_HANDLER      Handler)
595 {
596     ACPI_STATUS             Status = AE_OK;
597 
598 
599     ACPI_FUNCTION_TRACE (AcpiRemoveFixedEventHandler);
600 
601 
602     /* Parameter validation */
603 
604     if (Event > ACPI_EVENT_MAX)
605     {
606         return_ACPI_STATUS (AE_BAD_PARAMETER);
607     }
608 
609     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
610     if (ACPI_FAILURE (Status))
611     {
612         return_ACPI_STATUS (Status);
613     }
614 
615     /* Disable the event before removing the handler */
616 
617     Status = AcpiDisableEvent (Event, 0);
618 
619     /* Always Remove the handler */
620 
621     AcpiGbl_FixedEventHandlers[Event].Handler = NULL;
622     AcpiGbl_FixedEventHandlers[Event].Context = NULL;
623 
624     if (ACPI_FAILURE (Status))
625     {
626         ACPI_WARNING ((AE_INFO,
627             "Could not disable fixed event - %s (%u)",
628             AcpiUtGetEventName (Event), Event));
629     }
630     else
631     {
632         ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
633             "Disabled fixed event - %s (%X)\n",
634             AcpiUtGetEventName (Event), Event));
635     }
636 
637     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
638     return_ACPI_STATUS (Status);
639 }
640 
641 ACPI_EXPORT_SYMBOL (AcpiRemoveFixedEventHandler)
642 
643 
644 /*******************************************************************************
645  *
646  * FUNCTION:    AcpiInstallGpeHandler
647  *
648  * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
649  *                                defined GPEs)
650  *              GpeNumber       - The GPE number within the GPE block
651  *              Type            - Whether this GPE should be treated as an
652  *                                edge- or level-triggered interrupt.
653  *              Address         - Address of the handler
654  *              Context         - Value passed to the handler on each GPE
655  *
656  * RETURN:      Status
657  *
658  * DESCRIPTION: Install a handler for a General Purpose Event.
659  *
660  ******************************************************************************/
661 
662 ACPI_STATUS
663 AcpiInstallGpeHandler (
664     ACPI_HANDLE             GpeDevice,
665     UINT32                  GpeNumber,
666     UINT32                  Type,
667     ACPI_GPE_HANDLER        Address,
668     void                    *Context)
669 {
670     ACPI_GPE_EVENT_INFO     *GpeEventInfo;
671     ACPI_GPE_HANDLER_INFO   *Handler;
672     ACPI_STATUS             Status;
673     ACPI_CPU_FLAGS          Flags;
674 
675 
676     ACPI_FUNCTION_TRACE (AcpiInstallGpeHandler);
677 
678 
679     /* Parameter validation */
680 
681     if ((!Address) || (Type & ~ACPI_GPE_XRUPT_TYPE_MASK))
682     {
683         return_ACPI_STATUS (AE_BAD_PARAMETER);
684     }
685 
686     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
687     if (ACPI_FAILURE (Status))
688     {
689         return_ACPI_STATUS (Status);
690     }
691 
692     /* Allocate and init handler object (before lock) */
693 
694     Handler = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_HANDLER_INFO));
695     if (!Handler)
696     {
697         Status = AE_NO_MEMORY;
698         goto UnlockAndExit;
699     }
700 
701     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
702 
703     /* Ensure that we have a valid GPE number */
704 
705     GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
706     if (!GpeEventInfo)
707     {
708         Status = AE_BAD_PARAMETER;
709         goto FreeAndExit;
710     }
711 
712     /* Make sure that there isn't a handler there already */
713 
714     if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
715             ACPI_GPE_DISPATCH_HANDLER)
716     {
717         Status = AE_ALREADY_EXISTS;
718         goto FreeAndExit;
719     }
720 
721     Handler->Address = Address;
722     Handler->Context = Context;
723     Handler->MethodNode = GpeEventInfo->Dispatch.MethodNode;
724     Handler->OriginalFlags = (UINT8) (GpeEventInfo->Flags &
725         (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK));
726 
727     /*
728      * If the GPE is associated with a method, it may have been enabled
729      * automatically during initialization, in which case it has to be
730      * disabled now to avoid spurious execution of the handler.
731      */
732     if (((Handler->OriginalFlags & ACPI_GPE_DISPATCH_METHOD) ||
733          (Handler->OriginalFlags & ACPI_GPE_DISPATCH_NOTIFY)) &&
734         GpeEventInfo->RuntimeCount)
735     {
736         Handler->OriginallyEnabled = TRUE;
737         (void) AcpiEvRemoveGpeReference (GpeEventInfo);
738 
739         /* Sanity check of original type against new type */
740 
741         if (Type != (UINT32) (GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK))
742         {
743             ACPI_WARNING ((AE_INFO, "GPE type mismatch (level/edge)"));
744         }
745     }
746 
747     /* Install the handler */
748 
749     GpeEventInfo->Dispatch.Handler = Handler;
750 
751     /* Setup up dispatch flags to indicate handler (vs. method/notify) */
752 
753     GpeEventInfo->Flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
754     GpeEventInfo->Flags |= (UINT8) (Type | ACPI_GPE_DISPATCH_HANDLER);
755 
756     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
757 
758 
759 UnlockAndExit:
760     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
761     return_ACPI_STATUS (Status);
762 
763 FreeAndExit:
764     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
765     ACPI_FREE (Handler);
766     goto UnlockAndExit;
767 }
768 
769 ACPI_EXPORT_SYMBOL (AcpiInstallGpeHandler)
770 
771 
772 /*******************************************************************************
773  *
774  * FUNCTION:    AcpiRemoveGpeHandler
775  *
776  * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
777  *                                defined GPEs)
778  *              GpeNumber       - The event to remove a handler
779  *              Address         - Address of the handler
780  *
781  * RETURN:      Status
782  *
783  * DESCRIPTION: Remove a handler for a General Purpose AcpiEvent.
784  *
785  ******************************************************************************/
786 
787 ACPI_STATUS
788 AcpiRemoveGpeHandler (
789     ACPI_HANDLE             GpeDevice,
790     UINT32                  GpeNumber,
791     ACPI_GPE_HANDLER        Address)
792 {
793     ACPI_GPE_EVENT_INFO     *GpeEventInfo;
794     ACPI_GPE_HANDLER_INFO   *Handler;
795     ACPI_STATUS             Status;
796     ACPI_CPU_FLAGS          Flags;
797 
798 
799     ACPI_FUNCTION_TRACE (AcpiRemoveGpeHandler);
800 
801 
802     /* Parameter validation */
803 
804     if (!Address)
805     {
806         return_ACPI_STATUS (AE_BAD_PARAMETER);
807     }
808 
809     /* Make sure all deferred GPE tasks are completed */
810 
811     AcpiOsWaitEventsComplete ();
812 
813     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
814     if (ACPI_FAILURE (Status))
815     {
816         return_ACPI_STATUS (Status);
817     }
818 
819     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
820 
821     /* Ensure that we have a valid GPE number */
822 
823     GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
824     if (!GpeEventInfo)
825     {
826         Status = AE_BAD_PARAMETER;
827         goto UnlockAndExit;
828     }
829 
830     /* Make sure that a handler is indeed installed */
831 
832     if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) !=
833             ACPI_GPE_DISPATCH_HANDLER)
834     {
835         Status = AE_NOT_EXIST;
836         goto UnlockAndExit;
837     }
838 
839     /* Make sure that the installed handler is the same */
840 
841     if (GpeEventInfo->Dispatch.Handler->Address != Address)
842     {
843         Status = AE_BAD_PARAMETER;
844         goto UnlockAndExit;
845     }
846 
847     /* Remove the handler */
848 
849     Handler = GpeEventInfo->Dispatch.Handler;
850 
851     /* Restore Method node (if any), set dispatch flags */
852 
853     GpeEventInfo->Dispatch.MethodNode = Handler->MethodNode;
854     GpeEventInfo->Flags &=
855         ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
856     GpeEventInfo->Flags |= Handler->OriginalFlags;
857 
858     /*
859      * If the GPE was previously associated with a method and it was
860      * enabled, it should be enabled at this point to restore the
861      * post-initialization configuration.
862      */
863     if ((Handler->OriginalFlags & ACPI_GPE_DISPATCH_METHOD) &&
864         Handler->OriginallyEnabled)
865     {
866         (void) AcpiEvAddGpeReference (GpeEventInfo);
867     }
868 
869     /* Now we can free the handler object */
870 
871     ACPI_FREE (Handler);
872 
873 
874 UnlockAndExit:
875     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
876     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
877     return_ACPI_STATUS (Status);
878 }
879 
880 ACPI_EXPORT_SYMBOL (AcpiRemoveGpeHandler)
881 
882 
883 /*******************************************************************************
884  *
885  * FUNCTION:    AcpiAcquireGlobalLock
886  *
887  * PARAMETERS:  Timeout         - How long the caller is willing to wait
888  *              Handle          - Where the handle to the lock is returned
889  *                                (if acquired)
890  *
891  * RETURN:      Status
892  *
893  * DESCRIPTION: Acquire the ACPI Global Lock
894  *
895  * Note: Allows callers with the same thread ID to acquire the global lock
896  * multiple times. In other words, externally, the behavior of the global lock
897  * is identical to an AML mutex. On the first acquire, a new handle is
898  * returned. On any subsequent calls to acquire by the same thread, the same
899  * handle is returned.
900  *
901  ******************************************************************************/
902 
903 ACPI_STATUS
904 AcpiAcquireGlobalLock (
905     UINT16                  Timeout,
906     UINT32                  *Handle)
907 {
908     ACPI_STATUS             Status;
909 
910 
911     if (!Handle)
912     {
913         return (AE_BAD_PARAMETER);
914     }
915 
916     /* Must lock interpreter to prevent race conditions */
917 
918     AcpiExEnterInterpreter ();
919 
920     Status = AcpiExAcquireMutexObject (Timeout,
921                 AcpiGbl_GlobalLockMutex, AcpiOsGetThreadId ());
922 
923     if (ACPI_SUCCESS (Status))
924     {
925         /* Return the global lock handle (updated in AcpiEvAcquireGlobalLock) */
926 
927         *Handle = AcpiGbl_GlobalLockHandle;
928     }
929 
930     AcpiExExitInterpreter ();
931     return (Status);
932 }
933 
934 ACPI_EXPORT_SYMBOL (AcpiAcquireGlobalLock)
935 
936 
937 /*******************************************************************************
938  *
939  * FUNCTION:    AcpiReleaseGlobalLock
940  *
941  * PARAMETERS:  Handle      - Returned from AcpiAcquireGlobalLock
942  *
943  * RETURN:      Status
944  *
945  * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid.
946  *
947  ******************************************************************************/
948 
949 ACPI_STATUS
950 AcpiReleaseGlobalLock (
951     UINT32                  Handle)
952 {
953     ACPI_STATUS             Status;
954 
955 
956     if (!Handle || (Handle != AcpiGbl_GlobalLockHandle))
957     {
958         return (AE_NOT_ACQUIRED);
959     }
960 
961     Status = AcpiExReleaseMutexObject (AcpiGbl_GlobalLockMutex);
962     return (Status);
963 }
964 
965 ACPI_EXPORT_SYMBOL (AcpiReleaseGlobalLock)
966 
967 #endif /* !ACPI_REDUCED_HARDWARE */
968