evxface.c revision 254745
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
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    /* 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
378UnlockAndExit:
379    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
380    return_ACPI_STATUS (Status);
381}
382
383ACPI_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
399ACPI_STATUS
400AcpiInstallExceptionHandler (
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
427Cleanup:
428    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
429    return_ACPI_STATUS (Status);
430}
431
432ACPI_EXPORT_SYMBOL (AcpiInstallExceptionHandler)
433
434
435#if (!ACPI_REDUCED_HARDWARE)
436/*******************************************************************************
437 *
438 * FUNCTION:    AcpiInstallSciHandler
439 *
440 * PARAMETERS:  Address             - Address of the handler
441 *              Context             - Value passed to the handler on each SCI
442 *
443 * RETURN:      Status
444 *
445 * DESCRIPTION: Install a handler for a System Control Interrupt.
446 *
447 ******************************************************************************/
448
449ACPI_STATUS
450AcpiInstallSciHandler (
451    ACPI_SCI_HANDLER        Address,
452    void                    *Context)
453{
454    ACPI_SCI_HANDLER_INFO   *NewSciHandler;
455    ACPI_SCI_HANDLER_INFO   *SciHandler;
456    ACPI_CPU_FLAGS          Flags;
457    ACPI_STATUS             Status;
458
459
460    ACPI_FUNCTION_TRACE (AcpiInstallSciHandler);
461
462
463    if (!Address)
464    {
465        return_ACPI_STATUS (AE_BAD_PARAMETER);
466    }
467
468    /* Allocate and init a handler object */
469
470    NewSciHandler = ACPI_ALLOCATE (sizeof (ACPI_SCI_HANDLER_INFO));
471    if (!NewSciHandler)
472    {
473        return_ACPI_STATUS (AE_NO_MEMORY);
474    }
475
476    NewSciHandler->Address = Address;
477    NewSciHandler->Context = Context;
478
479    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
480    if (ACPI_FAILURE (Status))
481    {
482        goto Exit;
483    }
484
485    /* Lock list during installation */
486
487    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
488    SciHandler = AcpiGbl_SciHandlerList;
489
490    /* Ensure handler does not already exist */
491
492    while (SciHandler)
493    {
494        if (Address == SciHandler->Address)
495        {
496            Status = AE_ALREADY_EXISTS;
497            goto UnlockAndExit;
498        }
499
500        SciHandler = SciHandler->Next;
501    }
502
503    /* Install the new handler into the global list (at head) */
504
505    NewSciHandler->Next = AcpiGbl_SciHandlerList;
506    AcpiGbl_SciHandlerList = NewSciHandler;
507
508
509UnlockAndExit:
510
511    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
512    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
513
514Exit:
515    if (ACPI_FAILURE (Status))
516    {
517        ACPI_FREE (NewSciHandler);
518    }
519    return_ACPI_STATUS (Status);
520}
521
522
523/*******************************************************************************
524 *
525 * FUNCTION:    AcpiRemoveSciHandler
526 *
527 * PARAMETERS:  Address             - Address of the handler
528 *
529 * RETURN:      Status
530 *
531 * DESCRIPTION: Remove a handler for a System Control Interrupt.
532 *
533 ******************************************************************************/
534
535ACPI_STATUS
536AcpiRemoveSciHandler (
537    ACPI_SCI_HANDLER        Address)
538{
539    ACPI_SCI_HANDLER_INFO   *PrevSciHandler;
540    ACPI_SCI_HANDLER_INFO   *NextSciHandler;
541    ACPI_CPU_FLAGS          Flags;
542    ACPI_STATUS             Status;
543
544
545    ACPI_FUNCTION_TRACE (AcpiRemoveSciHandler);
546
547
548    if (!Address)
549    {
550        return_ACPI_STATUS (AE_BAD_PARAMETER);
551    }
552
553    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
554    if (ACPI_FAILURE (Status))
555    {
556        return_ACPI_STATUS (Status);
557    }
558
559    /* Remove the SCI handler with lock */
560
561    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
562
563    PrevSciHandler = NULL;
564    NextSciHandler = AcpiGbl_SciHandlerList;
565    while (NextSciHandler)
566    {
567        if (NextSciHandler->Address == Address)
568        {
569            /* Unlink and free the SCI handler info block */
570
571            if (PrevSciHandler)
572            {
573                PrevSciHandler->Next = NextSciHandler->Next;
574            }
575            else
576            {
577                AcpiGbl_SciHandlerList = NextSciHandler->Next;
578            }
579
580            AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
581            ACPI_FREE (NextSciHandler);
582            goto UnlockAndExit;
583        }
584
585        PrevSciHandler = NextSciHandler;
586        NextSciHandler = NextSciHandler->Next;
587    }
588
589    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
590    Status = AE_NOT_EXIST;
591
592
593UnlockAndExit:
594    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
595    return_ACPI_STATUS (Status);
596}
597
598
599/*******************************************************************************
600 *
601 * FUNCTION:    AcpiInstallGlobalEventHandler
602 *
603 * PARAMETERS:  Handler         - Pointer to the global event handler function
604 *              Context         - Value passed to the handler on each event
605 *
606 * RETURN:      Status
607 *
608 * DESCRIPTION: Saves the pointer to the handler function. The global handler
609 *              is invoked upon each incoming GPE and Fixed Event. It is
610 *              invoked at interrupt level at the time of the event dispatch.
611 *              Can be used to update event counters, etc.
612 *
613 ******************************************************************************/
614
615ACPI_STATUS
616AcpiInstallGlobalEventHandler (
617    ACPI_GBL_EVENT_HANDLER  Handler,
618    void                    *Context)
619{
620    ACPI_STATUS             Status;
621
622
623    ACPI_FUNCTION_TRACE (AcpiInstallGlobalEventHandler);
624
625
626    /* Parameter validation */
627
628    if (!Handler)
629    {
630        return_ACPI_STATUS (AE_BAD_PARAMETER);
631    }
632
633    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
634    if (ACPI_FAILURE (Status))
635    {
636        return_ACPI_STATUS (Status);
637    }
638
639    /* Don't allow two handlers. */
640
641    if (AcpiGbl_GlobalEventHandler)
642    {
643        Status = AE_ALREADY_EXISTS;
644        goto Cleanup;
645    }
646
647    AcpiGbl_GlobalEventHandler = Handler;
648    AcpiGbl_GlobalEventHandlerContext = Context;
649
650
651Cleanup:
652    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
653    return_ACPI_STATUS (Status);
654}
655
656ACPI_EXPORT_SYMBOL (AcpiInstallGlobalEventHandler)
657
658
659/*******************************************************************************
660 *
661 * FUNCTION:    AcpiInstallFixedEventHandler
662 *
663 * PARAMETERS:  Event           - Event type to enable.
664 *              Handler         - Pointer to the handler function for the
665 *                                event
666 *              Context         - Value passed to the handler on each GPE
667 *
668 * RETURN:      Status
669 *
670 * DESCRIPTION: Saves the pointer to the handler function and then enables the
671 *              event.
672 *
673 ******************************************************************************/
674
675ACPI_STATUS
676AcpiInstallFixedEventHandler (
677    UINT32                  Event,
678    ACPI_EVENT_HANDLER      Handler,
679    void                    *Context)
680{
681    ACPI_STATUS             Status;
682
683
684    ACPI_FUNCTION_TRACE (AcpiInstallFixedEventHandler);
685
686
687    /* Parameter validation */
688
689    if (Event > ACPI_EVENT_MAX)
690    {
691        return_ACPI_STATUS (AE_BAD_PARAMETER);
692    }
693
694    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
695    if (ACPI_FAILURE (Status))
696    {
697        return_ACPI_STATUS (Status);
698    }
699
700    /* Do not allow multiple handlers */
701
702    if (AcpiGbl_FixedEventHandlers[Event].Handler)
703    {
704        Status = AE_ALREADY_EXISTS;
705        goto Cleanup;
706    }
707
708    /* Install the handler before enabling the event */
709
710    AcpiGbl_FixedEventHandlers[Event].Handler = Handler;
711    AcpiGbl_FixedEventHandlers[Event].Context = Context;
712
713    Status = AcpiEnableEvent (Event, 0);
714    if (ACPI_FAILURE (Status))
715    {
716        ACPI_WARNING ((AE_INFO,
717            "Could not enable fixed event - %s (%u)",
718            AcpiUtGetEventName (Event), Event));
719
720        /* Remove the handler */
721
722        AcpiGbl_FixedEventHandlers[Event].Handler = NULL;
723        AcpiGbl_FixedEventHandlers[Event].Context = NULL;
724    }
725    else
726    {
727        ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
728            "Enabled fixed event %s (%X), Handler=%p\n",
729            AcpiUtGetEventName (Event), Event, Handler));
730    }
731
732
733Cleanup:
734    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
735    return_ACPI_STATUS (Status);
736}
737
738ACPI_EXPORT_SYMBOL (AcpiInstallFixedEventHandler)
739
740
741/*******************************************************************************
742 *
743 * FUNCTION:    AcpiRemoveFixedEventHandler
744 *
745 * PARAMETERS:  Event           - Event type to disable.
746 *              Handler         - Address of the handler
747 *
748 * RETURN:      Status
749 *
750 * DESCRIPTION: Disables the event and unregisters the event handler.
751 *
752 ******************************************************************************/
753
754ACPI_STATUS
755AcpiRemoveFixedEventHandler (
756    UINT32                  Event,
757    ACPI_EVENT_HANDLER      Handler)
758{
759    ACPI_STATUS             Status = AE_OK;
760
761
762    ACPI_FUNCTION_TRACE (AcpiRemoveFixedEventHandler);
763
764
765    /* Parameter validation */
766
767    if (Event > ACPI_EVENT_MAX)
768    {
769        return_ACPI_STATUS (AE_BAD_PARAMETER);
770    }
771
772    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
773    if (ACPI_FAILURE (Status))
774    {
775        return_ACPI_STATUS (Status);
776    }
777
778    /* Disable the event before removing the handler */
779
780    Status = AcpiDisableEvent (Event, 0);
781
782    /* Always Remove the handler */
783
784    AcpiGbl_FixedEventHandlers[Event].Handler = NULL;
785    AcpiGbl_FixedEventHandlers[Event].Context = NULL;
786
787    if (ACPI_FAILURE (Status))
788    {
789        ACPI_WARNING ((AE_INFO,
790            "Could not disable fixed event - %s (%u)",
791            AcpiUtGetEventName (Event), Event));
792    }
793    else
794    {
795        ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
796            "Disabled fixed event - %s (%X)\n",
797            AcpiUtGetEventName (Event), Event));
798    }
799
800    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
801    return_ACPI_STATUS (Status);
802}
803
804ACPI_EXPORT_SYMBOL (AcpiRemoveFixedEventHandler)
805
806
807/*******************************************************************************
808 *
809 * FUNCTION:    AcpiInstallGpeHandler
810 *
811 * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
812 *                                defined GPEs)
813 *              GpeNumber       - The GPE number within the GPE block
814 *              Type            - Whether this GPE should be treated as an
815 *                                edge- or level-triggered interrupt.
816 *              Address         - Address of the handler
817 *              Context         - Value passed to the handler on each GPE
818 *
819 * RETURN:      Status
820 *
821 * DESCRIPTION: Install a handler for a General Purpose Event.
822 *
823 ******************************************************************************/
824
825ACPI_STATUS
826AcpiInstallGpeHandler (
827    ACPI_HANDLE             GpeDevice,
828    UINT32                  GpeNumber,
829    UINT32                  Type,
830    ACPI_GPE_HANDLER        Address,
831    void                    *Context)
832{
833    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
834    ACPI_GPE_HANDLER_INFO   *Handler;
835    ACPI_STATUS             Status;
836    ACPI_CPU_FLAGS          Flags;
837
838
839    ACPI_FUNCTION_TRACE (AcpiInstallGpeHandler);
840
841
842    /* Parameter validation */
843
844    if ((!Address) || (Type & ~ACPI_GPE_XRUPT_TYPE_MASK))
845    {
846        return_ACPI_STATUS (AE_BAD_PARAMETER);
847    }
848
849    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
850    if (ACPI_FAILURE (Status))
851    {
852        return_ACPI_STATUS (Status);
853    }
854
855    /* Allocate and init handler object (before lock) */
856
857    Handler = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_HANDLER_INFO));
858    if (!Handler)
859    {
860        Status = AE_NO_MEMORY;
861        goto UnlockAndExit;
862    }
863
864    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
865
866    /* Ensure that we have a valid GPE number */
867
868    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
869    if (!GpeEventInfo)
870    {
871        Status = AE_BAD_PARAMETER;
872        goto FreeAndExit;
873    }
874
875    /* Make sure that there isn't a handler there already */
876
877    if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
878            ACPI_GPE_DISPATCH_HANDLER)
879    {
880        Status = AE_ALREADY_EXISTS;
881        goto FreeAndExit;
882    }
883
884    Handler->Address = Address;
885    Handler->Context = Context;
886    Handler->MethodNode = GpeEventInfo->Dispatch.MethodNode;
887    Handler->OriginalFlags = (UINT8) (GpeEventInfo->Flags &
888        (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK));
889
890    /*
891     * If the GPE is associated with a method, it may have been enabled
892     * automatically during initialization, in which case it has to be
893     * disabled now to avoid spurious execution of the handler.
894     */
895    if (((Handler->OriginalFlags & ACPI_GPE_DISPATCH_METHOD) ||
896         (Handler->OriginalFlags & ACPI_GPE_DISPATCH_NOTIFY)) &&
897        GpeEventInfo->RuntimeCount)
898    {
899        Handler->OriginallyEnabled = TRUE;
900        (void) AcpiEvRemoveGpeReference (GpeEventInfo);
901
902        /* Sanity check of original type against new type */
903
904        if (Type != (UINT32) (GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK))
905        {
906            ACPI_WARNING ((AE_INFO, "GPE type mismatch (level/edge)"));
907        }
908    }
909
910    /* Install the handler */
911
912    GpeEventInfo->Dispatch.Handler = Handler;
913
914    /* Setup up dispatch flags to indicate handler (vs. method/notify) */
915
916    GpeEventInfo->Flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
917    GpeEventInfo->Flags |= (UINT8) (Type | ACPI_GPE_DISPATCH_HANDLER);
918
919    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
920
921
922UnlockAndExit:
923    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
924    return_ACPI_STATUS (Status);
925
926FreeAndExit:
927    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
928    ACPI_FREE (Handler);
929    goto UnlockAndExit;
930}
931
932ACPI_EXPORT_SYMBOL (AcpiInstallGpeHandler)
933
934
935/*******************************************************************************
936 *
937 * FUNCTION:    AcpiRemoveGpeHandler
938 *
939 * PARAMETERS:  GpeDevice       - Namespace node for the GPE (NULL for FADT
940 *                                defined GPEs)
941 *              GpeNumber       - The event to remove a handler
942 *              Address         - Address of the handler
943 *
944 * RETURN:      Status
945 *
946 * DESCRIPTION: Remove a handler for a General Purpose AcpiEvent.
947 *
948 ******************************************************************************/
949
950ACPI_STATUS
951AcpiRemoveGpeHandler (
952    ACPI_HANDLE             GpeDevice,
953    UINT32                  GpeNumber,
954    ACPI_GPE_HANDLER        Address)
955{
956    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
957    ACPI_GPE_HANDLER_INFO   *Handler;
958    ACPI_STATUS             Status;
959    ACPI_CPU_FLAGS          Flags;
960
961
962    ACPI_FUNCTION_TRACE (AcpiRemoveGpeHandler);
963
964
965    /* Parameter validation */
966
967    if (!Address)
968    {
969        return_ACPI_STATUS (AE_BAD_PARAMETER);
970    }
971
972    /* Make sure all deferred GPE tasks are completed */
973
974    AcpiOsWaitEventsComplete ();
975
976    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
977    if (ACPI_FAILURE (Status))
978    {
979        return_ACPI_STATUS (Status);
980    }
981
982    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
983
984    /* Ensure that we have a valid GPE number */
985
986    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
987    if (!GpeEventInfo)
988    {
989        Status = AE_BAD_PARAMETER;
990        goto UnlockAndExit;
991    }
992
993    /* Make sure that a handler is indeed installed */
994
995    if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) !=
996            ACPI_GPE_DISPATCH_HANDLER)
997    {
998        Status = AE_NOT_EXIST;
999        goto UnlockAndExit;
1000    }
1001
1002    /* Make sure that the installed handler is the same */
1003
1004    if (GpeEventInfo->Dispatch.Handler->Address != Address)
1005    {
1006        Status = AE_BAD_PARAMETER;
1007        goto UnlockAndExit;
1008    }
1009
1010    /* Remove the handler */
1011
1012    Handler = GpeEventInfo->Dispatch.Handler;
1013
1014    /* Restore Method node (if any), set dispatch flags */
1015
1016    GpeEventInfo->Dispatch.MethodNode = Handler->MethodNode;
1017    GpeEventInfo->Flags &=
1018        ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
1019    GpeEventInfo->Flags |= Handler->OriginalFlags;
1020
1021    /*
1022     * If the GPE was previously associated with a method and it was
1023     * enabled, it should be enabled at this point to restore the
1024     * post-initialization configuration.
1025     */
1026    if ((Handler->OriginalFlags & ACPI_GPE_DISPATCH_METHOD) &&
1027        Handler->OriginallyEnabled)
1028    {
1029        (void) AcpiEvAddGpeReference (GpeEventInfo);
1030    }
1031
1032    /* Now we can free the handler object */
1033
1034    ACPI_FREE (Handler);
1035
1036
1037UnlockAndExit:
1038    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
1039    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
1040    return_ACPI_STATUS (Status);
1041}
1042
1043ACPI_EXPORT_SYMBOL (AcpiRemoveGpeHandler)
1044
1045
1046/*******************************************************************************
1047 *
1048 * FUNCTION:    AcpiAcquireGlobalLock
1049 *
1050 * PARAMETERS:  Timeout         - How long the caller is willing to wait
1051 *              Handle          - Where the handle to the lock is returned
1052 *                                (if acquired)
1053 *
1054 * RETURN:      Status
1055 *
1056 * DESCRIPTION: Acquire the ACPI Global Lock
1057 *
1058 * Note: Allows callers with the same thread ID to acquire the global lock
1059 * multiple times. In other words, externally, the behavior of the global lock
1060 * is identical to an AML mutex. On the first acquire, a new handle is
1061 * returned. On any subsequent calls to acquire by the same thread, the same
1062 * handle is returned.
1063 *
1064 ******************************************************************************/
1065
1066ACPI_STATUS
1067AcpiAcquireGlobalLock (
1068    UINT16                  Timeout,
1069    UINT32                  *Handle)
1070{
1071    ACPI_STATUS             Status;
1072
1073
1074    if (!Handle)
1075    {
1076        return (AE_BAD_PARAMETER);
1077    }
1078
1079    /* Must lock interpreter to prevent race conditions */
1080
1081    AcpiExEnterInterpreter ();
1082
1083    Status = AcpiExAcquireMutexObject (Timeout,
1084                AcpiGbl_GlobalLockMutex, AcpiOsGetThreadId ());
1085
1086    if (ACPI_SUCCESS (Status))
1087    {
1088        /* Return the global lock handle (updated in AcpiEvAcquireGlobalLock) */
1089
1090        *Handle = AcpiGbl_GlobalLockHandle;
1091    }
1092
1093    AcpiExExitInterpreter ();
1094    return (Status);
1095}
1096
1097ACPI_EXPORT_SYMBOL (AcpiAcquireGlobalLock)
1098
1099
1100/*******************************************************************************
1101 *
1102 * FUNCTION:    AcpiReleaseGlobalLock
1103 *
1104 * PARAMETERS:  Handle      - Returned from AcpiAcquireGlobalLock
1105 *
1106 * RETURN:      Status
1107 *
1108 * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid.
1109 *
1110 ******************************************************************************/
1111
1112ACPI_STATUS
1113AcpiReleaseGlobalLock (
1114    UINT32                  Handle)
1115{
1116    ACPI_STATUS             Status;
1117
1118
1119    if (!Handle || (Handle != AcpiGbl_GlobalLockHandle))
1120    {
1121        return (AE_NOT_ACQUIRED);
1122    }
1123
1124    Status = AcpiExReleaseMutexObject (AcpiGbl_GlobalLockMutex);
1125    return (Status);
1126}
1127
1128ACPI_EXPORT_SYMBOL (AcpiReleaseGlobalLock)
1129
1130#endif /* !ACPI_REDUCED_HARDWARE */
1131