1/******************************************************************************
2 *
3 * Module Name: evxfgpe - External Interfaces for General Purpose Events (GPEs)
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2011, 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 __EVXFGPE_C__
46
47#include <contrib/dev/acpica/include/acpi.h>
48#include <contrib/dev/acpica/include/accommon.h>
49#include <contrib/dev/acpica/include/acevents.h>
50#include <contrib/dev/acpica/include/acnamesp.h>
51
52#define _COMPONENT          ACPI_EVENTS
53        ACPI_MODULE_NAME    ("evxfgpe")
54
55
56/*******************************************************************************
57 *
58 * FUNCTION:    AcpiUpdateAllGpes
59 *
60 * PARAMETERS:  None
61 *
62 * RETURN:      Status
63 *
64 * DESCRIPTION: Complete GPE initialization and enable all GPEs that have
65 *              associated _Lxx or _Exx methods and are not pointed to by any
66 *              device _PRW methods (this indicates that these GPEs are
67 *              generally intended for system or device wakeup. Such GPEs
68 *              have to be enabled directly when the devices whose _PRW
69 *              methods point to them are set up for wakeup signaling.)
70 *
71 * NOTE: Should be called after any GPEs are added to the system. Primarily,
72 * after the system _PRW methods have been run, but also after a GPE Block
73 * Device has been added or if any new GPE methods have been added via a
74 * dynamic table load.
75 *
76 ******************************************************************************/
77
78ACPI_STATUS
79AcpiUpdateAllGpes (
80    void)
81{
82    ACPI_STATUS             Status;
83
84
85    ACPI_FUNCTION_TRACE (AcpiUpdateGpes);
86
87
88    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
89    if (ACPI_FAILURE (Status))
90    {
91        return_ACPI_STATUS (Status);
92    }
93
94    if (AcpiGbl_AllGpesInitialized)
95    {
96        goto UnlockAndExit;
97    }
98
99    Status = AcpiEvWalkGpeList (AcpiEvInitializeGpeBlock, NULL);
100    if (ACPI_SUCCESS (Status))
101    {
102        AcpiGbl_AllGpesInitialized = TRUE;
103    }
104
105UnlockAndExit:
106    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
107    return_ACPI_STATUS (Status);
108}
109
110ACPI_EXPORT_SYMBOL (AcpiUpdateAllGpes)
111
112
113/*******************************************************************************
114 *
115 * FUNCTION:    AcpiEnableGpe
116 *
117 * PARAMETERS:  GpeDevice           - Parent GPE Device. NULL for GPE0/GPE1
118 *              GpeNumber           - GPE level within the GPE block
119 *
120 * RETURN:      Status
121 *
122 * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
123 *              hardware-enabled.
124 *
125 ******************************************************************************/
126
127ACPI_STATUS
128AcpiEnableGpe (
129    ACPI_HANDLE             GpeDevice,
130    UINT32                  GpeNumber)
131{
132    ACPI_STATUS             Status = AE_BAD_PARAMETER;
133    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
134    ACPI_CPU_FLAGS          Flags;
135
136
137    ACPI_FUNCTION_TRACE (AcpiEnableGpe);
138
139
140    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
141
142    /* Ensure that we have a valid GPE number */
143
144    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
145    if (GpeEventInfo)
146    {
147        Status = AcpiEvAddGpeReference (GpeEventInfo);
148    }
149
150    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
151    return_ACPI_STATUS (Status);
152}
153
154ACPI_EXPORT_SYMBOL (AcpiEnableGpe)
155
156
157/*******************************************************************************
158 *
159 * FUNCTION:    AcpiDisableGpe
160 *
161 * PARAMETERS:  GpeDevice           - Parent GPE Device. NULL for GPE0/GPE1
162 *              GpeNumber           - GPE level within the GPE block
163 *
164 * RETURN:      Status
165 *
166 * DESCRIPTION: Remove a reference to a GPE. When the last reference is
167 *              removed, only then is the GPE disabled (for runtime GPEs), or
168 *              the GPE mask bit disabled (for wake GPEs)
169 *
170 ******************************************************************************/
171
172ACPI_STATUS
173AcpiDisableGpe (
174    ACPI_HANDLE             GpeDevice,
175    UINT32                  GpeNumber)
176{
177    ACPI_STATUS             Status = AE_BAD_PARAMETER;
178    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
179    ACPI_CPU_FLAGS          Flags;
180
181
182    ACPI_FUNCTION_TRACE (AcpiDisableGpe);
183
184
185    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
186
187    /* Ensure that we have a valid GPE number */
188
189    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
190    if (GpeEventInfo)
191    {
192        Status = AcpiEvRemoveGpeReference (GpeEventInfo);
193    }
194
195    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
196    return_ACPI_STATUS (Status);
197}
198
199ACPI_EXPORT_SYMBOL (AcpiDisableGpe)
200
201
202/*******************************************************************************
203 *
204 * FUNCTION:    AcpiSetGpe
205 *
206 * PARAMETERS:  GpeDevice           - Parent GPE Device. NULL for GPE0/GPE1
207 *              GpeNumber           - GPE level within the GPE block
208 *              Action              - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE
209 *
210 * RETURN:      Status
211 *
212 * DESCRIPTION: Enable or disable an individual GPE. This function bypasses
213 *              the reference count mechanism used in the AcpiEnableGpe and
214 *              AcpiDisableGpe interfaces -- and should be used with care.
215 *
216 * Note: Typically used to disable a runtime GPE for short period of time,
217 * then re-enable it, without disturbing the existing reference counts. This
218 * is useful, for example, in the Embedded Controller (EC) driver.
219 *
220 ******************************************************************************/
221
222ACPI_STATUS
223AcpiSetGpe (
224    ACPI_HANDLE             GpeDevice,
225    UINT32                  GpeNumber,
226    UINT8                   Action)
227{
228    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
229    ACPI_STATUS             Status;
230    ACPI_CPU_FLAGS          Flags;
231
232
233    ACPI_FUNCTION_TRACE (AcpiSetGpe);
234
235
236    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
237
238    /* Ensure that we have a valid GPE number */
239
240    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
241    if (!GpeEventInfo)
242    {
243        Status = AE_BAD_PARAMETER;
244        goto UnlockAndExit;
245    }
246
247    /* Perform the action */
248
249    switch (Action)
250    {
251    case ACPI_GPE_ENABLE:
252        Status = AcpiEvEnableGpe (GpeEventInfo);
253        break;
254
255    case ACPI_GPE_DISABLE:
256        Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE);
257        break;
258
259    default:
260        Status = AE_BAD_PARAMETER;
261        break;
262    }
263
264UnlockAndExit:
265    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
266    return_ACPI_STATUS (Status);
267}
268
269ACPI_EXPORT_SYMBOL (AcpiSetGpe)
270
271
272/*******************************************************************************
273 *
274 * FUNCTION:    AcpiSetupGpeForWake
275 *
276 * PARAMETERS:  WakeDevice          - Device associated with the GPE (via _PRW)
277 *              GpeDevice           - Parent GPE Device. NULL for GPE0/GPE1
278 *              GpeNumber           - GPE level within the GPE block
279 *
280 * RETURN:      Status
281 *
282 * DESCRIPTION: Mark a GPE as having the ability to wake the system. This
283 *              interface is intended to be used as the host executes the
284 *              _PRW methods (Power Resources for Wake) in the system tables.
285 *              Each _PRW appears under a Device Object (The WakeDevice), and
286 *              contains the info for the wake GPE associated with the
287 *              WakeDevice.
288 *
289 ******************************************************************************/
290
291ACPI_STATUS
292AcpiSetupGpeForWake (
293    ACPI_HANDLE             WakeDevice,
294    ACPI_HANDLE             GpeDevice,
295    UINT32                  GpeNumber)
296{
297    ACPI_STATUS             Status = AE_BAD_PARAMETER;
298    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
299    ACPI_NAMESPACE_NODE     *DeviceNode;
300    ACPI_CPU_FLAGS          Flags;
301
302
303    ACPI_FUNCTION_TRACE (AcpiSetupGpeForWake);
304
305
306    /* Parameter Validation */
307
308    if (!WakeDevice)
309    {
310        /*
311         * By forcing WakeDevice to be valid, we automatically enable the
312         * implicit notify feature on all hosts.
313         */
314        return_ACPI_STATUS (AE_BAD_PARAMETER);
315    }
316
317    /* Handle root object case */
318
319    if (WakeDevice == ACPI_ROOT_OBJECT)
320    {
321        DeviceNode = AcpiGbl_RootNode;
322    }
323    else
324    {
325        DeviceNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, WakeDevice);
326    }
327
328    /* Validate WakeDevice is of type Device */
329
330    if (DeviceNode->Type != ACPI_TYPE_DEVICE)
331    {
332        return_ACPI_STATUS (AE_BAD_PARAMETER);
333    }
334
335    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
336
337    /* Ensure that we have a valid GPE number */
338
339    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
340    if (GpeEventInfo)
341    {
342        /*
343         * If there is no method or handler for this GPE, then the
344         * WakeDevice will be notified whenever this GPE fires (aka
345         * "implicit notify") Note: The GPE is assumed to be
346         * level-triggered (for windows compatibility).
347         */
348        if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
349                ACPI_GPE_DISPATCH_NONE)
350        {
351            GpeEventInfo->Flags =
352                (ACPI_GPE_DISPATCH_NOTIFY | ACPI_GPE_LEVEL_TRIGGERED);
353            GpeEventInfo->Dispatch.DeviceNode = DeviceNode;
354        }
355
356        GpeEventInfo->Flags |= ACPI_GPE_CAN_WAKE;
357        Status = AE_OK;
358    }
359
360    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
361    return_ACPI_STATUS (Status);
362}
363
364ACPI_EXPORT_SYMBOL (AcpiSetupGpeForWake)
365
366
367/*******************************************************************************
368 *
369 * FUNCTION:    AcpiSetGpeWakeMask
370 *
371 * PARAMETERS:  GpeDevice           - Parent GPE Device. NULL for GPE0/GPE1
372 *              GpeNumber           - GPE level within the GPE block
373 *              Action              - Enable or Disable
374 *
375 * RETURN:      Status
376 *
377 * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit. The GPE must
378 *              already be marked as a WAKE GPE.
379 *
380 ******************************************************************************/
381
382ACPI_STATUS
383AcpiSetGpeWakeMask (
384    ACPI_HANDLE             GpeDevice,
385    UINT32                  GpeNumber,
386    UINT8                   Action)
387{
388    ACPI_STATUS             Status = AE_OK;
389    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
390    ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
391    ACPI_CPU_FLAGS          Flags;
392    UINT32                  RegisterBit;
393
394
395    ACPI_FUNCTION_TRACE (AcpiSetGpeWakeMask);
396
397
398    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
399
400    /*
401     * Ensure that we have a valid GPE number and that this GPE is in
402     * fact a wake GPE
403     */
404    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
405    if (!GpeEventInfo)
406    {
407        Status = AE_BAD_PARAMETER;
408        goto UnlockAndExit;
409    }
410
411    if (!(GpeEventInfo->Flags & ACPI_GPE_CAN_WAKE))
412    {
413        Status = AE_TYPE;
414        goto UnlockAndExit;
415    }
416
417    GpeRegisterInfo = GpeEventInfo->RegisterInfo;
418    if (!GpeRegisterInfo)
419    {
420        Status = AE_NOT_EXIST;
421        goto UnlockAndExit;
422    }
423
424    RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo, GpeRegisterInfo);
425
426    /* Perform the action */
427
428    switch (Action)
429    {
430    case ACPI_GPE_ENABLE:
431        ACPI_SET_BIT (GpeRegisterInfo->EnableForWake, (UINT8) RegisterBit);
432        break;
433
434    case ACPI_GPE_DISABLE:
435        ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForWake, (UINT8) RegisterBit);
436        break;
437
438    default:
439        ACPI_ERROR ((AE_INFO, "%u, Invalid action", Action));
440        Status = AE_BAD_PARAMETER;
441        break;
442    }
443
444UnlockAndExit:
445    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
446    return_ACPI_STATUS (Status);
447}
448
449ACPI_EXPORT_SYMBOL (AcpiSetGpeWakeMask)
450
451
452/*******************************************************************************
453 *
454 * FUNCTION:    AcpiClearGpe
455 *
456 * PARAMETERS:  GpeDevice           - Parent GPE Device. NULL for GPE0/GPE1
457 *              GpeNumber           - GPE level within the GPE block
458 *
459 * RETURN:      Status
460 *
461 * DESCRIPTION: Clear an ACPI event (general purpose)
462 *
463 ******************************************************************************/
464
465ACPI_STATUS
466AcpiClearGpe (
467    ACPI_HANDLE             GpeDevice,
468    UINT32                  GpeNumber)
469{
470    ACPI_STATUS             Status = AE_OK;
471    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
472    ACPI_CPU_FLAGS          Flags;
473
474
475    ACPI_FUNCTION_TRACE (AcpiClearGpe);
476
477
478    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
479
480    /* Ensure that we have a valid GPE number */
481
482    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
483    if (!GpeEventInfo)
484    {
485        Status = AE_BAD_PARAMETER;
486        goto UnlockAndExit;
487    }
488
489    Status = AcpiHwClearGpe (GpeEventInfo);
490
491UnlockAndExit:
492    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
493    return_ACPI_STATUS (Status);
494}
495
496ACPI_EXPORT_SYMBOL (AcpiClearGpe)
497
498
499/*******************************************************************************
500 *
501 * FUNCTION:    AcpiGetGpeStatus
502 *
503 * PARAMETERS:  GpeDevice           - Parent GPE Device. NULL for GPE0/GPE1
504 *              GpeNumber           - GPE level within the GPE block
505 *              EventStatus         - Where the current status of the event
506 *                                    will be returned
507 *
508 * RETURN:      Status
509 *
510 * DESCRIPTION: Get the current status of a GPE (signalled/not_signalled)
511 *
512 ******************************************************************************/
513
514ACPI_STATUS
515AcpiGetGpeStatus (
516    ACPI_HANDLE             GpeDevice,
517    UINT32                  GpeNumber,
518    ACPI_EVENT_STATUS       *EventStatus)
519{
520    ACPI_STATUS             Status = AE_OK;
521    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
522    ACPI_CPU_FLAGS          Flags;
523
524
525    ACPI_FUNCTION_TRACE (AcpiGetGpeStatus);
526
527
528    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
529
530    /* Ensure that we have a valid GPE number */
531
532    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
533    if (!GpeEventInfo)
534    {
535        Status = AE_BAD_PARAMETER;
536        goto UnlockAndExit;
537    }
538
539    /* Obtain status on the requested GPE number */
540
541    Status = AcpiHwGetGpeStatus (GpeEventInfo, EventStatus);
542
543UnlockAndExit:
544    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
545    return_ACPI_STATUS (Status);
546}
547
548ACPI_EXPORT_SYMBOL (AcpiGetGpeStatus)
549
550
551/*******************************************************************************
552 *
553 * FUNCTION:    AcpiFinishGpe
554 *
555 * PARAMETERS:  GpeDevice           - Namespace node for the GPE Block
556 *                                    (NULL for FADT defined GPEs)
557 *              GpeNumber           - GPE level within the GPE block
558 *
559 * RETURN:      Status
560 *
561 * DESCRIPTION: Clear and conditionally reenable a GPE. This completes the GPE
562 *              processing. Intended for use by asynchronous host-installed
563 *              GPE handlers. The GPE is only reenabled if the EnableForRun bit
564 *              is set in the GPE info.
565 *
566 ******************************************************************************/
567
568ACPI_STATUS
569AcpiFinishGpe (
570    ACPI_HANDLE             GpeDevice,
571    UINT32                  GpeNumber)
572{
573    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
574    ACPI_STATUS             Status;
575    ACPI_CPU_FLAGS          Flags;
576
577
578    ACPI_FUNCTION_TRACE (AcpiFinishGpe);
579
580
581    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
582
583    /* Ensure that we have a valid GPE number */
584
585    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
586    if (!GpeEventInfo)
587    {
588        Status = AE_BAD_PARAMETER;
589        goto UnlockAndExit;
590    }
591
592    Status = AcpiEvFinishGpe (GpeEventInfo);
593
594UnlockAndExit:
595    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
596    return_ACPI_STATUS (Status);
597}
598
599ACPI_EXPORT_SYMBOL (AcpiFinishGpe)
600
601
602/******************************************************************************
603 *
604 * FUNCTION:    AcpiDisableAllGpes
605 *
606 * PARAMETERS:  None
607 *
608 * RETURN:      Status
609 *
610 * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
611 *
612 ******************************************************************************/
613
614ACPI_STATUS
615AcpiDisableAllGpes (
616    void)
617{
618    ACPI_STATUS             Status;
619
620
621    ACPI_FUNCTION_TRACE (AcpiDisableAllGpes);
622
623
624    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
625    if (ACPI_FAILURE (Status))
626    {
627        return_ACPI_STATUS (Status);
628    }
629
630    Status = AcpiHwDisableAllGpes ();
631    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
632
633    return_ACPI_STATUS (Status);
634}
635
636ACPI_EXPORT_SYMBOL (AcpiDisableAllGpes)
637
638
639/******************************************************************************
640 *
641 * FUNCTION:    AcpiEnableAllRuntimeGpes
642 *
643 * PARAMETERS:  None
644 *
645 * RETURN:      Status
646 *
647 * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
648 *
649 ******************************************************************************/
650
651ACPI_STATUS
652AcpiEnableAllRuntimeGpes (
653    void)
654{
655    ACPI_STATUS             Status;
656
657
658    ACPI_FUNCTION_TRACE (AcpiEnableAllRuntimeGpes);
659
660
661    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
662    if (ACPI_FAILURE (Status))
663    {
664        return_ACPI_STATUS (Status);
665    }
666
667    Status = AcpiHwEnableAllRuntimeGpes ();
668    (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
669
670    return_ACPI_STATUS (Status);
671}
672
673ACPI_EXPORT_SYMBOL (AcpiEnableAllRuntimeGpes)
674
675
676/*******************************************************************************
677 *
678 * FUNCTION:    AcpiInstallGpeBlock
679 *
680 * PARAMETERS:  GpeDevice           - Handle to the parent GPE Block Device
681 *              GpeBlockAddress     - Address and SpaceID
682 *              RegisterCount       - Number of GPE register pairs in the block
683 *              InterruptNumber     - H/W interrupt for the block
684 *
685 * RETURN:      Status
686 *
687 * DESCRIPTION: Create and Install a block of GPE registers. The GPEs are not
688 *              enabled here.
689 *
690 ******************************************************************************/
691
692ACPI_STATUS
693AcpiInstallGpeBlock (
694    ACPI_HANDLE             GpeDevice,
695    ACPI_GENERIC_ADDRESS    *GpeBlockAddress,
696    UINT32                  RegisterCount,
697    UINT32                  InterruptNumber)
698{
699    ACPI_STATUS             Status;
700    ACPI_OPERAND_OBJECT     *ObjDesc;
701    ACPI_NAMESPACE_NODE     *Node;
702    ACPI_GPE_BLOCK_INFO     *GpeBlock;
703
704
705    ACPI_FUNCTION_TRACE (AcpiInstallGpeBlock);
706
707
708    if ((!GpeDevice)       ||
709        (!GpeBlockAddress) ||
710        (!RegisterCount))
711    {
712        return_ACPI_STATUS (AE_BAD_PARAMETER);
713    }
714
715    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
716    if (ACPI_FAILURE (Status))
717    {
718        return (Status);
719    }
720
721    Node = AcpiNsValidateHandle (GpeDevice);
722    if (!Node)
723    {
724        Status = AE_BAD_PARAMETER;
725        goto UnlockAndExit;
726    }
727
728    /*
729     * For user-installed GPE Block Devices, the GpeBlockBaseNumber
730     * is always zero
731     */
732    Status = AcpiEvCreateGpeBlock (Node, GpeBlockAddress, RegisterCount,
733                0, InterruptNumber, &GpeBlock);
734    if (ACPI_FAILURE (Status))
735    {
736        goto UnlockAndExit;
737    }
738
739    /* Install block in the DeviceObject attached to the node */
740
741    ObjDesc = AcpiNsGetAttachedObject (Node);
742    if (!ObjDesc)
743    {
744        /*
745         * No object, create a new one (Device nodes do not always have
746         * an attached object)
747         */
748        ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_DEVICE);
749        if (!ObjDesc)
750        {
751            Status = AE_NO_MEMORY;
752            goto UnlockAndExit;
753        }
754
755        Status = AcpiNsAttachObject (Node, ObjDesc, ACPI_TYPE_DEVICE);
756
757        /* Remove local reference to the object */
758
759        AcpiUtRemoveReference (ObjDesc);
760        if (ACPI_FAILURE (Status))
761        {
762            goto UnlockAndExit;
763        }
764    }
765
766    /* Now install the GPE block in the DeviceObject */
767
768    ObjDesc->Device.GpeBlock = GpeBlock;
769
770
771UnlockAndExit:
772    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
773    return_ACPI_STATUS (Status);
774}
775
776ACPI_EXPORT_SYMBOL (AcpiInstallGpeBlock)
777
778
779/*******************************************************************************
780 *
781 * FUNCTION:    AcpiRemoveGpeBlock
782 *
783 * PARAMETERS:  GpeDevice           - Handle to the parent GPE Block Device
784 *
785 * RETURN:      Status
786 *
787 * DESCRIPTION: Remove a previously installed block of GPE registers
788 *
789 ******************************************************************************/
790
791ACPI_STATUS
792AcpiRemoveGpeBlock (
793    ACPI_HANDLE             GpeDevice)
794{
795    ACPI_OPERAND_OBJECT     *ObjDesc;
796    ACPI_STATUS             Status;
797    ACPI_NAMESPACE_NODE     *Node;
798
799
800    ACPI_FUNCTION_TRACE (AcpiRemoveGpeBlock);
801
802
803    if (!GpeDevice)
804    {
805        return_ACPI_STATUS (AE_BAD_PARAMETER);
806    }
807
808    Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
809    if (ACPI_FAILURE (Status))
810    {
811        return (Status);
812    }
813
814    Node = AcpiNsValidateHandle (GpeDevice);
815    if (!Node)
816    {
817        Status = AE_BAD_PARAMETER;
818        goto UnlockAndExit;
819    }
820
821    /* Get the DeviceObject attached to the node */
822
823    ObjDesc = AcpiNsGetAttachedObject (Node);
824    if (!ObjDesc ||
825        !ObjDesc->Device.GpeBlock)
826    {
827        return_ACPI_STATUS (AE_NULL_OBJECT);
828    }
829
830    /* Delete the GPE block (but not the DeviceObject) */
831
832    Status = AcpiEvDeleteGpeBlock (ObjDesc->Device.GpeBlock);
833    if (ACPI_SUCCESS (Status))
834    {
835        ObjDesc->Device.GpeBlock = NULL;
836    }
837
838UnlockAndExit:
839    (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
840    return_ACPI_STATUS (Status);
841}
842
843ACPI_EXPORT_SYMBOL (AcpiRemoveGpeBlock)
844
845
846/*******************************************************************************
847 *
848 * FUNCTION:    AcpiGetGpeDevice
849 *
850 * PARAMETERS:  Index               - System GPE index (0-CurrentGpeCount)
851 *              GpeDevice           - Where the parent GPE Device is returned
852 *
853 * RETURN:      Status
854 *
855 * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL
856 *              gpe device indicates that the gpe number is contained in one of
857 *              the FADT-defined gpe blocks. Otherwise, the GPE block device.
858 *
859 ******************************************************************************/
860
861ACPI_STATUS
862AcpiGetGpeDevice (
863    UINT32                  Index,
864    ACPI_HANDLE             *GpeDevice)
865{
866    ACPI_GPE_DEVICE_INFO    Info;
867    ACPI_STATUS             Status;
868
869
870    ACPI_FUNCTION_TRACE (AcpiGetGpeDevice);
871
872
873    if (!GpeDevice)
874    {
875        return_ACPI_STATUS (AE_BAD_PARAMETER);
876    }
877
878    if (Index >= AcpiCurrentGpeCount)
879    {
880        return_ACPI_STATUS (AE_NOT_EXIST);
881    }
882
883    /* Setup and walk the GPE list */
884
885    Info.Index = Index;
886    Info.Status = AE_NOT_EXIST;
887    Info.GpeDevice = NULL;
888    Info.NextBlockBaseIndex = 0;
889
890    Status = AcpiEvWalkGpeList (AcpiEvGetGpeDevice, &Info);
891    if (ACPI_FAILURE (Status))
892    {
893        return_ACPI_STATUS (Status);
894    }
895
896    *GpeDevice = ACPI_CAST_PTR (ACPI_HANDLE, Info.GpeDevice);
897    return_ACPI_STATUS (Info.Status);
898}
899
900ACPI_EXPORT_SYMBOL (AcpiGetGpeDevice)
901