xref: /freebsd/sys/contrib/dev/acpica/components/events/evxface.c (revision 273c26a3c3bea87a241d6879abd4f991db180bf0)
1 /******************************************************************************
2  *
3  * Module Name: evxface - External interfaces for ACPI events
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 #define EXPORT_ACPI_INTERFACES
45 
46 #include <contrib/dev/acpica/include/acpi.h>
47 #include <contrib/dev/acpica/include/accommon.h>
48 #include <contrib/dev/acpica/include/acnamesp.h>
49 #include <contrib/dev/acpica/include/acevents.h>
50 #include <contrib/dev/acpica/include/acinterp.h>
51 
52 #define _COMPONENT          ACPI_EVENTS
53         ACPI_MODULE_NAME    ("evxface")
54 
55 #if (!ACPI_REDUCED_HARDWARE)
56 
57 /* Local prototypes */
58 
59 static ACPI_STATUS
60 AcpiEvInstallGpeHandler (
61     ACPI_HANDLE             GpeDevice,
62     UINT32                  GpeNumber,
63     UINT32                  Type,
64     BOOLEAN                 IsRawHandler,
65     ACPI_GPE_HANDLER        Address,
66     void                    *Context);
67 
68 #endif
69 
70 
71 /*******************************************************************************
72  *
73  * FUNCTION:    AcpiInstallNotifyHandler
74  *
75  * PARAMETERS:  Device          - The device for which notifies will be handled
76  *              HandlerType     - The type of handler:
77  *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
78  *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
79  *                                  ACPI_ALL_NOTIFY:    Both System and Device
80  *              Handler         - Address of the handler
81  *              Context         - Value passed to the handler on each GPE
82  *
83  * RETURN:      Status
84  *
85  * DESCRIPTION: Install a handler for notifications on an ACPI Device,
86  *              ThermalZone, or Processor object.
87  *
88  * NOTES:       The Root namespace object may have only one handler for each
89  *              type of notify (System/Device). Device/Thermal/Processor objects
90  *              may have one device notify handler, and multiple system notify
91  *              handlers.
92  *
93  ******************************************************************************/
94 
95 ACPI_STATUS
96 AcpiInstallNotifyHandler (
97     ACPI_HANDLE             Device,
98     UINT32                  HandlerType,
99     ACPI_NOTIFY_HANDLER     Handler,
100     void                    *Context)
101 {
102     ACPI_NAMESPACE_NODE     *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Device);
103     ACPI_OPERAND_OBJECT     *ObjDesc;
104     ACPI_OPERAND_OBJECT     *HandlerObj;
105     ACPI_STATUS             Status;
106     UINT32                  i;
107 
108 
109     ACPI_FUNCTION_TRACE (AcpiInstallNotifyHandler);
110 
111 
112     /* Parameter validation */
113 
114     if ((!Device) || (!Handler) || (!HandlerType) ||
115         (HandlerType > ACPI_MAX_NOTIFY_HANDLER_TYPE))
116     {
117         return_ACPI_STATUS (AE_BAD_PARAMETER);
118     }
119 
120     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
121     if (ACPI_FAILURE (Status))
122     {
123         return_ACPI_STATUS (Status);
124     }
125 
126     /*
127      * Root Object:
128      * Registering a notify handler on the root object indicates that the
129      * caller wishes to receive notifications for all objects. Note that
130      * only one global handler can be registered per notify type.
131      * Ensure that a handler is not already installed.
132      */
133     if (Device == ACPI_ROOT_OBJECT)
134     {
135         for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
136         {
137             if (HandlerType & (i+1))
138             {
139                 if (AcpiGbl_GlobalNotify[i].Handler)
140                 {
141                     Status = AE_ALREADY_EXISTS;
142                     goto UnlockAndExit;
143                 }
144 
145                 AcpiGbl_GlobalNotify[i].Handler = Handler;
146                 AcpiGbl_GlobalNotify[i].Context = Context;
147             }
148         }
149 
150         goto UnlockAndExit; /* Global notify handler installed, all done */
151     }
152 
153     /*
154      * All Other Objects:
155      * Caller will only receive notifications specific to the target
156      * object. Note that only certain object types are allowed to
157      * receive notifications.
158      */
159 
160     /* Are Notifies allowed on this object? */
161 
162     if (!AcpiEvIsNotifyObject (Node))
163     {
164         Status = AE_TYPE;
165         goto UnlockAndExit;
166     }
167 
168     /* Check for an existing internal object, might not exist */
169 
170     ObjDesc = AcpiNsGetAttachedObject (Node);
171     if (!ObjDesc)
172     {
173         /* Create a new object */
174 
175         ObjDesc = AcpiUtCreateInternalObject (Node->Type);
176         if (!ObjDesc)
177         {
178             Status = AE_NO_MEMORY;
179             goto UnlockAndExit;
180         }
181 
182         /* Attach new object to the Node, remove local reference */
183 
184         Status = AcpiNsAttachObject (Device, ObjDesc, Node->Type);
185         AcpiUtRemoveReference (ObjDesc);
186         if (ACPI_FAILURE (Status))
187         {
188             goto UnlockAndExit;
189         }
190     }
191 
192     /* Ensure that the handler is not already installed in the lists */
193 
194     for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
195     {
196         if (HandlerType & (i+1))
197         {
198             HandlerObj = ObjDesc->CommonNotify.NotifyList[i];
199             while (HandlerObj)
200             {
201                 if (HandlerObj->Notify.Handler == Handler)
202                 {
203                     Status = AE_ALREADY_EXISTS;
204                     goto UnlockAndExit;
205                 }
206 
207                 HandlerObj = HandlerObj->Notify.Next[i];
208             }
209         }
210     }
211 
212     /* Create and populate a new notify handler object */
213 
214     HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_NOTIFY);
215     if (!HandlerObj)
216     {
217         Status = AE_NO_MEMORY;
218         goto UnlockAndExit;
219     }
220 
221     HandlerObj->Notify.Node = Node;
222     HandlerObj->Notify.HandlerType = HandlerType;
223     HandlerObj->Notify.Handler = Handler;
224     HandlerObj->Notify.Context = Context;
225 
226     /* Install the handler at the list head(s) */
227 
228     for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
229     {
230         if (HandlerType & (i+1))
231         {
232             HandlerObj->Notify.Next[i] =
233                 ObjDesc->CommonNotify.NotifyList[i];
234 
235             ObjDesc->CommonNotify.NotifyList[i] = HandlerObj;
236         }
237     }
238 
239     /* Add an extra reference if handler was installed in both lists */
240 
241     if (HandlerType == ACPI_ALL_NOTIFY)
242     {
243         AcpiUtAddReference (HandlerObj);
244     }
245 
246 
247 UnlockAndExit:
248     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
249     return_ACPI_STATUS (Status);
250 }
251 
252 ACPI_EXPORT_SYMBOL (AcpiInstallNotifyHandler)
253 
254 
255 /*******************************************************************************
256  *
257  * FUNCTION:    AcpiRemoveNotifyHandler
258  *
259  * PARAMETERS:  Device          - The device for which the handler is installed
260  *              HandlerType     - The type of handler:
261  *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
262  *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
263  *                                  ACPI_ALL_NOTIFY:    Both System and Device
264  *              Handler         - Address of the handler
265  *
266  * RETURN:      Status
267  *
268  * DESCRIPTION: Remove a handler for notifies on an ACPI device
269  *
270  ******************************************************************************/
271 
272 ACPI_STATUS
273 AcpiRemoveNotifyHandler (
274     ACPI_HANDLE             Device,
275     UINT32                  HandlerType,
276     ACPI_NOTIFY_HANDLER     Handler)
277 {
278     ACPI_NAMESPACE_NODE     *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Device);
279     ACPI_OPERAND_OBJECT     *ObjDesc;
280     ACPI_OPERAND_OBJECT     *HandlerObj;
281     ACPI_OPERAND_OBJECT     *PreviousHandlerObj;
282     ACPI_STATUS             Status = AE_OK;
283     UINT32                  i;
284 
285 
286     ACPI_FUNCTION_TRACE (AcpiRemoveNotifyHandler);
287 
288 
289     /* Parameter validation */
290 
291     if ((!Device) || (!Handler) || (!HandlerType) ||
292         (HandlerType > ACPI_MAX_NOTIFY_HANDLER_TYPE))
293     {
294         return_ACPI_STATUS (AE_BAD_PARAMETER);
295     }
296 
297     /* Root Object. Global handlers are removed here */
298 
299     if (Device == ACPI_ROOT_OBJECT)
300     {
301         for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
302         {
303             if (HandlerType & (i+1))
304             {
305                 Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
306                 if (ACPI_FAILURE (Status))
307                 {
308                     return_ACPI_STATUS (Status);
309                 }
310 
311                 if (!AcpiGbl_GlobalNotify[i].Handler ||
312                     (AcpiGbl_GlobalNotify[i].Handler != Handler))
313                 {
314                     Status = AE_NOT_EXIST;
315                     goto UnlockAndExit;
316                 }
317 
318                 ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
319                     "Removing global notify handler\n"));
320 
321                 AcpiGbl_GlobalNotify[i].Handler = NULL;
322                 AcpiGbl_GlobalNotify[i].Context = NULL;
323 
324                 (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
325 
326                 /* Make sure all deferred notify tasks are completed */
327 
328                 AcpiOsWaitEventsComplete ();
329             }
330         }
331 
332         return_ACPI_STATUS (AE_OK);
333     }
334 
335     /* All other objects: Are Notifies allowed on this object? */
336 
337     if (!AcpiEvIsNotifyObject (Node))
338     {
339         return_ACPI_STATUS (AE_TYPE);
340     }
341 
342     /* Must have an existing internal object */
343 
344     ObjDesc = AcpiNsGetAttachedObject (Node);
345     if (!ObjDesc)
346     {
347         return_ACPI_STATUS (AE_NOT_EXIST);
348     }
349 
350     /* Internal object exists. Find the handler and remove it */
351 
352     for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
353     {
354         if (HandlerType & (i+1))
355         {
356             Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
357             if (ACPI_FAILURE (Status))
358             {
359                 return_ACPI_STATUS (Status);
360             }
361 
362             HandlerObj = ObjDesc->CommonNotify.NotifyList[i];
363             PreviousHandlerObj = NULL;
364 
365             /* Attempt to find the handler in the handler list */
366 
367             while (HandlerObj &&
368                   (HandlerObj->Notify.Handler != Handler))
369             {
370                 PreviousHandlerObj = HandlerObj;
371                 HandlerObj = HandlerObj->Notify.Next[i];
372             }
373 
374             if (!HandlerObj)
375             {
376                 Status = AE_NOT_EXIST;
377                 goto UnlockAndExit;
378             }
379 
380             /* Remove the handler object from the list */
381 
382             if (PreviousHandlerObj) /* Handler is not at the list head */
383             {
384                 PreviousHandlerObj->Notify.Next[i] =
385                     HandlerObj->Notify.Next[i];
386             }
387             else /* Handler is at the list head */
388             {
389                 ObjDesc->CommonNotify.NotifyList[i] =
390                     HandlerObj->Notify.Next[i];
391             }
392 
393             (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
394 
395             /* Make sure all deferred notify tasks are completed */
396 
397             AcpiOsWaitEventsComplete ();
398             AcpiUtRemoveReference (HandlerObj);
399         }
400     }
401 
402     return_ACPI_STATUS (Status);
403 
404 
405 UnlockAndExit:
406     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
407     return_ACPI_STATUS (Status);
408 }
409 
410 ACPI_EXPORT_SYMBOL (AcpiRemoveNotifyHandler)
411 
412 
413 /*******************************************************************************
414  *
415  * FUNCTION:    AcpiInstallExceptionHandler
416  *
417  * PARAMETERS:  Handler         - Pointer to the handler function for the
418  *                                event
419  *
420  * RETURN:      Status
421  *
422  * DESCRIPTION: Saves the pointer to the handler function
423  *
424  ******************************************************************************/
425 
426 ACPI_STATUS
427 AcpiInstallExceptionHandler (
428     ACPI_EXCEPTION_HANDLER  Handler)
429 {
430     ACPI_STATUS             Status;
431 
432 
433     ACPI_FUNCTION_TRACE (AcpiInstallExceptionHandler);
434 
435 
436     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
437     if (ACPI_FAILURE (Status))
438     {
439         return_ACPI_STATUS (Status);
440     }
441 
442     /* Don't allow two handlers. */
443 
444     if (AcpiGbl_ExceptionHandler)
445     {
446         Status = AE_ALREADY_EXISTS;
447         goto Cleanup;
448     }
449 
450     /* Install the handler */
451 
452     AcpiGbl_ExceptionHandler = Handler;
453 
454 Cleanup:
455     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
456     return_ACPI_STATUS (Status);
457 }
458 
459 ACPI_EXPORT_SYMBOL (AcpiInstallExceptionHandler)
460 
461 
462 #if (!ACPI_REDUCED_HARDWARE)
463 /*******************************************************************************
464  *
465  * FUNCTION:    AcpiInstallSciHandler
466  *
467  * PARAMETERS:  Address             - Address of the handler
468  *              Context             - Value passed to the handler on each SCI
469  *
470  * RETURN:      Status
471  *
472  * DESCRIPTION: Install a handler for a System Control Interrupt.
473  *
474  ******************************************************************************/
475 
476 ACPI_STATUS
477 AcpiInstallSciHandler (
478     ACPI_SCI_HANDLER        Address,
479     void                    *Context)
480 {
481     ACPI_SCI_HANDLER_INFO   *NewSciHandler;
482     ACPI_SCI_HANDLER_INFO   *SciHandler;
483     ACPI_CPU_FLAGS          Flags;
484     ACPI_STATUS             Status;
485 
486 
487     ACPI_FUNCTION_TRACE (AcpiInstallSciHandler);
488 
489 
490     if (!Address)
491     {
492         return_ACPI_STATUS (AE_BAD_PARAMETER);
493     }
494 
495     /* Allocate and init a handler object */
496 
497     NewSciHandler = ACPI_ALLOCATE (sizeof (ACPI_SCI_HANDLER_INFO));
498     if (!NewSciHandler)
499     {
500         return_ACPI_STATUS (AE_NO_MEMORY);
501     }
502 
503     NewSciHandler->Address = Address;
504     NewSciHandler->Context = Context;
505 
506     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
507     if (ACPI_FAILURE (Status))
508     {
509         goto Exit;
510     }
511 
512     /* Lock list during installation */
513 
514     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
515     SciHandler = AcpiGbl_SciHandlerList;
516 
517     /* Ensure handler does not already exist */
518 
519     while (SciHandler)
520     {
521         if (Address == SciHandler->Address)
522         {
523             Status = AE_ALREADY_EXISTS;
524             goto UnlockAndExit;
525         }
526 
527         SciHandler = SciHandler->Next;
528     }
529 
530     /* Install the new handler into the global list (at head) */
531 
532     NewSciHandler->Next = AcpiGbl_SciHandlerList;
533     AcpiGbl_SciHandlerList = NewSciHandler;
534 
535 
536 UnlockAndExit:
537 
538     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
539     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
540 
541 Exit:
542     if (ACPI_FAILURE (Status))
543     {
544         ACPI_FREE (NewSciHandler);
545     }
546     return_ACPI_STATUS (Status);
547 }
548 
549 ACPI_EXPORT_SYMBOL (AcpiInstallSciHandler)
550 
551 
552 /*******************************************************************************
553  *
554  * FUNCTION:    AcpiRemoveSciHandler
555  *
556  * PARAMETERS:  Address             - Address of the handler
557  *
558  * RETURN:      Status
559  *
560  * DESCRIPTION: Remove a handler for a System Control Interrupt.
561  *
562  ******************************************************************************/
563 
564 ACPI_STATUS
565 AcpiRemoveSciHandler (
566     ACPI_SCI_HANDLER        Address)
567 {
568     ACPI_SCI_HANDLER_INFO   *PrevSciHandler;
569     ACPI_SCI_HANDLER_INFO   *NextSciHandler;
570     ACPI_CPU_FLAGS          Flags;
571     ACPI_STATUS             Status;
572 
573 
574     ACPI_FUNCTION_TRACE (AcpiRemoveSciHandler);
575 
576 
577     if (!Address)
578     {
579         return_ACPI_STATUS (AE_BAD_PARAMETER);
580     }
581 
582     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
583     if (ACPI_FAILURE (Status))
584     {
585         return_ACPI_STATUS (Status);
586     }
587 
588     /* Remove the SCI handler with lock */
589 
590     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
591 
592     PrevSciHandler = NULL;
593     NextSciHandler = AcpiGbl_SciHandlerList;
594     while (NextSciHandler)
595     {
596         if (NextSciHandler->Address == Address)
597         {
598             /* Unlink and free the SCI handler info block */
599 
600             if (PrevSciHandler)
601             {
602                 PrevSciHandler->Next = NextSciHandler->Next;
603             }
604             else
605             {
606                 AcpiGbl_SciHandlerList = NextSciHandler->Next;
607             }
608 
609             AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
610             ACPI_FREE (NextSciHandler);
611             goto UnlockAndExit;
612         }
613 
614         PrevSciHandler = NextSciHandler;
615         NextSciHandler = NextSciHandler->Next;
616     }
617 
618     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
619     Status = AE_NOT_EXIST;
620 
621 
622 UnlockAndExit:
623     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
624     return_ACPI_STATUS (Status);
625 }
626 
627 ACPI_EXPORT_SYMBOL (AcpiRemoveSciHandler)
628 
629 
630 /*******************************************************************************
631  *
632  * FUNCTION:    AcpiInstallGlobalEventHandler
633  *
634  * PARAMETERS:  Handler         - Pointer to the global event handler function
635  *              Context         - Value passed to the handler on each event
636  *
637  * RETURN:      Status
638  *
639  * DESCRIPTION: Saves the pointer to the handler function. The global handler
640  *              is invoked upon each incoming GPE and Fixed Event. It is
641  *              invoked at interrupt level at the time of the event dispatch.
642  *              Can be used to update event counters, etc.
643  *
644  ******************************************************************************/
645 
646 ACPI_STATUS
647 AcpiInstallGlobalEventHandler (
648     ACPI_GBL_EVENT_HANDLER  Handler,
649     void                    *Context)
650 {
651     ACPI_STATUS             Status;
652 
653 
654     ACPI_FUNCTION_TRACE (AcpiInstallGlobalEventHandler);
655 
656 
657     /* Parameter validation */
658 
659     if (!Handler)
660     {
661         return_ACPI_STATUS (AE_BAD_PARAMETER);
662     }
663 
664     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
665     if (ACPI_FAILURE (Status))
666     {
667         return_ACPI_STATUS (Status);
668     }
669 
670     /* Don't allow two handlers. */
671 
672     if (AcpiGbl_GlobalEventHandler)
673     {
674         Status = AE_ALREADY_EXISTS;
675         goto Cleanup;
676     }
677 
678     AcpiGbl_GlobalEventHandler = Handler;
679     AcpiGbl_GlobalEventHandlerContext = Context;
680 
681 
682 Cleanup:
683     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
684     return_ACPI_STATUS (Status);
685 }
686 
687 ACPI_EXPORT_SYMBOL (AcpiInstallGlobalEventHandler)
688 
689 
690 /*******************************************************************************
691  *
692  * FUNCTION:    AcpiInstallFixedEventHandler
693  *
694  * PARAMETERS:  Event           - Event type to enable.
695  *              Handler         - Pointer to the handler function for the
696  *                                event
697  *              Context         - Value passed to the handler on each GPE
698  *
699  * RETURN:      Status
700  *
701  * DESCRIPTION: Saves the pointer to the handler function and then enables the
702  *              event.
703  *
704  ******************************************************************************/
705 
706 ACPI_STATUS
707 AcpiInstallFixedEventHandler (
708     UINT32                  Event,
709     ACPI_EVENT_HANDLER      Handler,
710     void                    *Context)
711 {
712     ACPI_STATUS             Status;
713 
714 
715     ACPI_FUNCTION_TRACE (AcpiInstallFixedEventHandler);
716 
717 
718     /* Parameter validation */
719 
720     if (Event > ACPI_EVENT_MAX)
721     {
722         return_ACPI_STATUS (AE_BAD_PARAMETER);
723     }
724 
725     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
726     if (ACPI_FAILURE (Status))
727     {
728         return_ACPI_STATUS (Status);
729     }
730 
731     /* Do not allow multiple handlers */
732 
733     if (AcpiGbl_FixedEventHandlers[Event].Handler)
734     {
735         Status = AE_ALREADY_EXISTS;
736         goto Cleanup;
737     }
738 
739     /* Install the handler before enabling the event */
740 
741     AcpiGbl_FixedEventHandlers[Event].Handler = Handler;
742     AcpiGbl_FixedEventHandlers[Event].Context = Context;
743 
744     Status = AcpiEnableEvent (Event, 0);
745     if (ACPI_FAILURE (Status))
746     {
747         ACPI_WARNING ((AE_INFO,
748             "Could not enable fixed event - %s (%u)",
749             AcpiUtGetEventName (Event), Event));
750 
751         /* Remove the handler */
752 
753         AcpiGbl_FixedEventHandlers[Event].Handler = NULL;
754         AcpiGbl_FixedEventHandlers[Event].Context = NULL;
755     }
756     else
757     {
758         ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
759             "Enabled fixed event %s (%X), Handler=%p\n",
760             AcpiUtGetEventName (Event), Event, Handler));
761     }
762 
763 
764 Cleanup:
765     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
766     return_ACPI_STATUS (Status);
767 }
768 
769 ACPI_EXPORT_SYMBOL (AcpiInstallFixedEventHandler)
770 
771 
772 /*******************************************************************************
773  *
774  * FUNCTION:    AcpiRemoveFixedEventHandler
775  *
776  * PARAMETERS:  Event           - Event type to disable.
777  *              Handler         - Address of the handler
778  *
779  * RETURN:      Status
780  *
781  * DESCRIPTION: Disables the event and unregisters the event handler.
782  *
783  ******************************************************************************/
784 
785 ACPI_STATUS
786 AcpiRemoveFixedEventHandler (
787     UINT32                  Event,
788     ACPI_EVENT_HANDLER      Handler)
789 {
790     ACPI_STATUS             Status = AE_OK;
791 
792 
793     ACPI_FUNCTION_TRACE (AcpiRemoveFixedEventHandler);
794 
795 
796     /* Parameter validation */
797 
798     if (Event > ACPI_EVENT_MAX)
799     {
800         return_ACPI_STATUS (AE_BAD_PARAMETER);
801     }
802 
803     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
804     if (ACPI_FAILURE (Status))
805     {
806         return_ACPI_STATUS (Status);
807     }
808 
809     /* Disable the event before removing the handler */
810 
811     Status = AcpiDisableEvent (Event, 0);
812 
813     /* Always Remove the handler */
814 
815     AcpiGbl_FixedEventHandlers[Event].Handler = NULL;
816     AcpiGbl_FixedEventHandlers[Event].Context = NULL;
817 
818     if (ACPI_FAILURE (Status))
819     {
820         ACPI_WARNING ((AE_INFO,
821             "Could not disable fixed event - %s (%u)",
822             AcpiUtGetEventName (Event), Event));
823     }
824     else
825     {
826         ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
827             "Disabled fixed event - %s (%X)\n",
828             AcpiUtGetEventName (Event), Event));
829     }
830 
831     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
832     return_ACPI_STATUS (Status);
833 }
834 
835 ACPI_EXPORT_SYMBOL (AcpiRemoveFixedEventHandler)
836 
837 
838 /*******************************************************************************
839  *
840  * FUNCTION:    AcpiEvInstallGpeHandler
841  *
842  * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
843  *                                defined GPEs)
844  *              GpeNumber       - The GPE number within the GPE block
845  *              Type            - Whether this GPE should be treated as an
846  *                                edge- or level-triggered interrupt.
847  *              IsRawHandler    - Whether this GPE should be handled using
848  *                                the special GPE handler mode.
849  *              Address         - Address of the handler
850  *              Context         - Value passed to the handler on each GPE
851  *
852  * RETURN:      Status
853  *
854  * DESCRIPTION: Internal function to install a handler for a General Purpose
855  *              Event.
856  *
857  ******************************************************************************/
858 
859 static ACPI_STATUS
860 AcpiEvInstallGpeHandler (
861     ACPI_HANDLE             GpeDevice,
862     UINT32                  GpeNumber,
863     UINT32                  Type,
864     BOOLEAN                 IsRawHandler,
865     ACPI_GPE_HANDLER        Address,
866     void                    *Context)
867 {
868     ACPI_GPE_EVENT_INFO     *GpeEventInfo;
869     ACPI_GPE_HANDLER_INFO   *Handler;
870     ACPI_STATUS             Status;
871     ACPI_CPU_FLAGS          Flags;
872 
873 
874     ACPI_FUNCTION_TRACE (EvInstallGpeHandler);
875 
876 
877     /* Parameter validation */
878 
879     if ((!Address) || (Type & ~ACPI_GPE_XRUPT_TYPE_MASK))
880     {
881         return_ACPI_STATUS (AE_BAD_PARAMETER);
882     }
883 
884     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
885     if (ACPI_FAILURE (Status))
886     {
887         return_ACPI_STATUS (Status);
888     }
889 
890     /* Allocate and init handler object (before lock) */
891 
892     Handler = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_HANDLER_INFO));
893     if (!Handler)
894     {
895         Status = AE_NO_MEMORY;
896         goto UnlockAndExit;
897     }
898 
899     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
900 
901     /* Ensure that we have a valid GPE number */
902 
903     GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
904     if (!GpeEventInfo)
905     {
906         Status = AE_BAD_PARAMETER;
907         goto FreeAndExit;
908     }
909 
910     /* Make sure that there isn't a handler there already */
911 
912     if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) ==
913             ACPI_GPE_DISPATCH_HANDLER) ||
914         (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) ==
915             ACPI_GPE_DISPATCH_RAW_HANDLER))
916     {
917         Status = AE_ALREADY_EXISTS;
918         goto FreeAndExit;
919     }
920 
921     Handler->Address = Address;
922     Handler->Context = Context;
923     Handler->MethodNode = GpeEventInfo->Dispatch.MethodNode;
924     Handler->OriginalFlags = (UINT8) (GpeEventInfo->Flags &
925         (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK));
926 
927     /*
928      * If the GPE is associated with a method, it may have been enabled
929      * automatically during initialization, in which case it has to be
930      * disabled now to avoid spurious execution of the handler.
931      */
932     if (((ACPI_GPE_DISPATCH_TYPE (Handler->OriginalFlags) ==
933             ACPI_GPE_DISPATCH_METHOD) ||
934          (ACPI_GPE_DISPATCH_TYPE (Handler->OriginalFlags) ==
935             ACPI_GPE_DISPATCH_NOTIFY)) &&
936         GpeEventInfo->RuntimeCount)
937     {
938         Handler->OriginallyEnabled = TRUE;
939         (void) AcpiEvRemoveGpeReference (GpeEventInfo);
940 
941         /* Sanity check of original type against new type */
942 
943         if (Type != (UINT32) (GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK))
944         {
945             ACPI_WARNING ((AE_INFO, "GPE type mismatch (level/edge)"));
946         }
947     }
948 
949     /* Install the handler */
950 
951     GpeEventInfo->Dispatch.Handler = Handler;
952 
953     /* Setup up dispatch flags to indicate handler (vs. method/notify) */
954 
955     GpeEventInfo->Flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
956     GpeEventInfo->Flags |= (UINT8) (Type | (IsRawHandler ?
957         ACPI_GPE_DISPATCH_RAW_HANDLER : ACPI_GPE_DISPATCH_HANDLER));
958 
959     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
960 
961 
962 UnlockAndExit:
963     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
964     return_ACPI_STATUS (Status);
965 
966 FreeAndExit:
967     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
968     ACPI_FREE (Handler);
969     goto UnlockAndExit;
970 }
971 
972 
973 /*******************************************************************************
974  *
975  * FUNCTION:    AcpiInstallGpeHandler
976  *
977  * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
978  *                                defined GPEs)
979  *              GpeNumber       - The GPE number within the GPE block
980  *              Type            - Whether this GPE should be treated as an
981  *                                edge- or level-triggered interrupt.
982  *              Address         - Address of the handler
983  *              Context         - Value passed to the handler on each GPE
984  *
985  * RETURN:      Status
986  *
987  * DESCRIPTION: Install a handler for a General Purpose Event.
988  *
989  ******************************************************************************/
990 
991 ACPI_STATUS
992 AcpiInstallGpeHandler (
993     ACPI_HANDLE             GpeDevice,
994     UINT32                  GpeNumber,
995     UINT32                  Type,
996     ACPI_GPE_HANDLER        Address,
997     void                    *Context)
998 {
999     ACPI_STATUS             Status;
1000 
1001 
1002     ACPI_FUNCTION_TRACE (AcpiInstallGpeHandler);
1003 
1004 
1005     Status = AcpiEvInstallGpeHandler (GpeDevice, GpeNumber, Type,
1006         FALSE, Address, Context);
1007 
1008     return_ACPI_STATUS (Status);
1009 }
1010 
1011 ACPI_EXPORT_SYMBOL (AcpiInstallGpeHandler)
1012 
1013 
1014 /*******************************************************************************
1015  *
1016  * FUNCTION:    AcpiInstallGpeRawHandler
1017  *
1018  * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
1019  *                                defined GPEs)
1020  *              GpeNumber       - The GPE number within the GPE block
1021  *              Type            - Whether this GPE should be treated as an
1022  *                                edge- or level-triggered interrupt.
1023  *              Address         - Address of the handler
1024  *              Context         - Value passed to the handler on each GPE
1025  *
1026  * RETURN:      Status
1027  *
1028  * DESCRIPTION: Install a handler for a General Purpose Event.
1029  *
1030  ******************************************************************************/
1031 
1032 ACPI_STATUS
1033 AcpiInstallGpeRawHandler (
1034     ACPI_HANDLE             GpeDevice,
1035     UINT32                  GpeNumber,
1036     UINT32                  Type,
1037     ACPI_GPE_HANDLER        Address,
1038     void                    *Context)
1039 {
1040     ACPI_STATUS             Status;
1041 
1042 
1043     ACPI_FUNCTION_TRACE (AcpiInstallGpeRawHandler);
1044 
1045 
1046     Status = AcpiEvInstallGpeHandler (GpeDevice, GpeNumber, Type,
1047         TRUE, Address, Context);
1048 
1049     return_ACPI_STATUS (Status);
1050 }
1051 
1052 ACPI_EXPORT_SYMBOL (AcpiInstallGpeRawHandler)
1053 
1054 
1055 /*******************************************************************************
1056  *
1057  * FUNCTION:    AcpiRemoveGpeHandler
1058  *
1059  * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
1060  *                                defined GPEs)
1061  *              GpeNumber       - The event to remove a handler
1062  *              Address         - Address of the handler
1063  *
1064  * RETURN:      Status
1065  *
1066  * DESCRIPTION: Remove a handler for a General Purpose AcpiEvent.
1067  *
1068  ******************************************************************************/
1069 
1070 ACPI_STATUS
1071 AcpiRemoveGpeHandler (
1072     ACPI_HANDLE             GpeDevice,
1073     UINT32                  GpeNumber,
1074     ACPI_GPE_HANDLER        Address)
1075 {
1076     ACPI_GPE_EVENT_INFO     *GpeEventInfo;
1077     ACPI_GPE_HANDLER_INFO   *Handler;
1078     ACPI_STATUS             Status;
1079     ACPI_CPU_FLAGS          Flags;
1080 
1081 
1082     ACPI_FUNCTION_TRACE (AcpiRemoveGpeHandler);
1083 
1084 
1085     /* Parameter validation */
1086 
1087     if (!Address)
1088     {
1089         return_ACPI_STATUS (AE_BAD_PARAMETER);
1090     }
1091 
1092     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
1093     if (ACPI_FAILURE (Status))
1094     {
1095         return_ACPI_STATUS (Status);
1096     }
1097 
1098     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
1099 
1100     /* Ensure that we have a valid GPE number */
1101 
1102     GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
1103     if (!GpeEventInfo)
1104     {
1105         Status = AE_BAD_PARAMETER;
1106         goto UnlockAndExit;
1107     }
1108 
1109     /* Make sure that a handler is indeed installed */
1110 
1111     if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) !=
1112             ACPI_GPE_DISPATCH_HANDLER) &&
1113         (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) !=
1114             ACPI_GPE_DISPATCH_RAW_HANDLER))
1115     {
1116         Status = AE_NOT_EXIST;
1117         goto UnlockAndExit;
1118     }
1119 
1120     /* Make sure that the installed handler is the same */
1121 
1122     if (GpeEventInfo->Dispatch.Handler->Address != Address)
1123     {
1124         Status = AE_BAD_PARAMETER;
1125         goto UnlockAndExit;
1126     }
1127 
1128     /* Remove the handler */
1129 
1130     Handler = GpeEventInfo->Dispatch.Handler;
1131     GpeEventInfo->Dispatch.Handler = NULL;
1132 
1133     /* Restore Method node (if any), set dispatch flags */
1134 
1135     GpeEventInfo->Dispatch.MethodNode = Handler->MethodNode;
1136     GpeEventInfo->Flags &=
1137         ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
1138     GpeEventInfo->Flags |= Handler->OriginalFlags;
1139 
1140     /*
1141      * If the GPE was previously associated with a method and it was
1142      * enabled, it should be enabled at this point to restore the
1143      * post-initialization configuration.
1144      */
1145     if (((ACPI_GPE_DISPATCH_TYPE (Handler->OriginalFlags) ==
1146             ACPI_GPE_DISPATCH_METHOD) ||
1147          (ACPI_GPE_DISPATCH_TYPE (Handler->OriginalFlags) ==
1148             ACPI_GPE_DISPATCH_NOTIFY)) &&
1149         Handler->OriginallyEnabled)
1150     {
1151         (void) AcpiEvAddGpeReference (GpeEventInfo);
1152     }
1153 
1154     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
1155     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
1156 
1157     /* Make sure all deferred GPE tasks are completed */
1158 
1159     AcpiOsWaitEventsComplete ();
1160 
1161     /* Now we can free the handler object */
1162 
1163     ACPI_FREE (Handler);
1164     return_ACPI_STATUS (Status);
1165 
1166 UnlockAndExit:
1167     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
1168     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
1169     return_ACPI_STATUS (Status);
1170 }
1171 
1172 ACPI_EXPORT_SYMBOL (AcpiRemoveGpeHandler)
1173 
1174 
1175 /*******************************************************************************
1176  *
1177  * FUNCTION:    AcpiAcquireGlobalLock
1178  *
1179  * PARAMETERS:  Timeout         - How long the caller is willing to wait
1180  *              Handle          - Where the handle to the lock is returned
1181  *                                (if acquired)
1182  *
1183  * RETURN:      Status
1184  *
1185  * DESCRIPTION: Acquire the ACPI Global Lock
1186  *
1187  * Note: Allows callers with the same thread ID to acquire the global lock
1188  * multiple times. In other words, externally, the behavior of the global lock
1189  * is identical to an AML mutex. On the first acquire, a new handle is
1190  * returned. On any subsequent calls to acquire by the same thread, the same
1191  * handle is returned.
1192  *
1193  ******************************************************************************/
1194 
1195 ACPI_STATUS
1196 AcpiAcquireGlobalLock (
1197     UINT16                  Timeout,
1198     UINT32                  *Handle)
1199 {
1200     ACPI_STATUS             Status;
1201 
1202 
1203     if (!Handle)
1204     {
1205         return (AE_BAD_PARAMETER);
1206     }
1207 
1208     /* Must lock interpreter to prevent race conditions */
1209 
1210     AcpiExEnterInterpreter ();
1211 
1212     Status = AcpiExAcquireMutexObject (Timeout,
1213         AcpiGbl_GlobalLockMutex, AcpiOsGetThreadId ());
1214 
1215     if (ACPI_SUCCESS (Status))
1216     {
1217         /* Return the global lock handle (updated in AcpiEvAcquireGlobalLock) */
1218 
1219         *Handle = AcpiGbl_GlobalLockHandle;
1220     }
1221 
1222     AcpiExExitInterpreter ();
1223     return (Status);
1224 }
1225 
1226 ACPI_EXPORT_SYMBOL (AcpiAcquireGlobalLock)
1227 
1228 
1229 /*******************************************************************************
1230  *
1231  * FUNCTION:    AcpiReleaseGlobalLock
1232  *
1233  * PARAMETERS:  Handle      - Returned from AcpiAcquireGlobalLock
1234  *
1235  * RETURN:      Status
1236  *
1237  * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid.
1238  *
1239  ******************************************************************************/
1240 
1241 ACPI_STATUS
1242 AcpiReleaseGlobalLock (
1243     UINT32                  Handle)
1244 {
1245     ACPI_STATUS             Status;
1246 
1247 
1248     if (!Handle || (Handle != AcpiGbl_GlobalLockHandle))
1249     {
1250         return (AE_NOT_ACQUIRED);
1251     }
1252 
1253     Status = AcpiExReleaseMutexObject (AcpiGbl_GlobalLockMutex);
1254     return (Status);
1255 }
1256 
1257 ACPI_EXPORT_SYMBOL (AcpiReleaseGlobalLock)
1258 
1259 #endif /* !ACPI_REDUCED_HARDWARE */
1260