1 | /****************************************************************************** |
2 | * |
3 | * Module Name: evxfgpe - External Interfaces for General Purpose Events (GPEs) |
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 "acpi.h" |
47 | #include "accommon.h" |
48 | #include "acevents.h" |
49 | #include "acnamesp.h" |
50 | |
51 | #define _COMPONENT ACPI_EVENTS |
52 | ACPI_MODULE_NAME ("evxfgpe" ) |
53 | |
54 | |
55 | #if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
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 | |
78 | ACPI_STATUS |
79 | AcpiUpdateAllGpes ( |
80 | void) |
81 | { |
82 | ACPI_STATUS Status; |
83 | |
84 | |
85 | ACPI_FUNCTION_TRACE (AcpiUpdateAllGpes); |
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 | |
105 | UnlockAndExit: |
106 | (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); |
107 | return_ACPI_STATUS (Status); |
108 | } |
109 | |
110 | ACPI_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 | |
127 | ACPI_STATUS |
128 | AcpiEnableGpe ( |
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 | /* |
143 | * Ensure that we have a valid GPE number and that there is some way |
144 | * of handling the GPE (handler or a GPE method). In other words, we |
145 | * won't allow a valid GPE to be enabled if there is no way to handle it. |
146 | */ |
147 | GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); |
148 | if (GpeEventInfo) |
149 | { |
150 | if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) != |
151 | ACPI_GPE_DISPATCH_NONE) |
152 | { |
153 | Status = AcpiEvAddGpeReference (GpeEventInfo); |
154 | } |
155 | else |
156 | { |
157 | Status = AE_NO_HANDLER; |
158 | } |
159 | } |
160 | |
161 | AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); |
162 | return_ACPI_STATUS (Status); |
163 | } |
164 | |
165 | ACPI_EXPORT_SYMBOL (AcpiEnableGpe) |
166 | |
167 | |
168 | /******************************************************************************* |
169 | * |
170 | * FUNCTION: AcpiDisableGpe |
171 | * |
172 | * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 |
173 | * GpeNumber - GPE level within the GPE block |
174 | * |
175 | * RETURN: Status |
176 | * |
177 | * DESCRIPTION: Remove a reference to a GPE. When the last reference is |
178 | * removed, only then is the GPE disabled (for runtime GPEs), or |
179 | * the GPE mask bit disabled (for wake GPEs) |
180 | * |
181 | ******************************************************************************/ |
182 | |
183 | ACPI_STATUS |
184 | AcpiDisableGpe ( |
185 | ACPI_HANDLE GpeDevice, |
186 | UINT32 GpeNumber) |
187 | { |
188 | ACPI_STATUS Status = AE_BAD_PARAMETER; |
189 | ACPI_GPE_EVENT_INFO *GpeEventInfo; |
190 | ACPI_CPU_FLAGS Flags; |
191 | |
192 | |
193 | ACPI_FUNCTION_TRACE (AcpiDisableGpe); |
194 | |
195 | |
196 | Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); |
197 | |
198 | /* Ensure that we have a valid GPE number */ |
199 | |
200 | GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); |
201 | if (GpeEventInfo) |
202 | { |
203 | Status = AcpiEvRemoveGpeReference (GpeEventInfo); |
204 | } |
205 | |
206 | AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); |
207 | return_ACPI_STATUS (Status); |
208 | } |
209 | |
210 | ACPI_EXPORT_SYMBOL (AcpiDisableGpe) |
211 | |
212 | |
213 | /******************************************************************************* |
214 | * |
215 | * FUNCTION: AcpiSetGpe |
216 | * |
217 | * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 |
218 | * GpeNumber - GPE level within the GPE block |
219 | * Action - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE |
220 | * |
221 | * RETURN: Status |
222 | * |
223 | * DESCRIPTION: Enable or disable an individual GPE. This function bypasses |
224 | * the reference count mechanism used in the AcpiEnableGpe(), |
225 | * AcpiDisableGpe() interfaces. |
226 | * This API is typically used by the GPE raw handler mode driver |
227 | * to switch between the polling mode and the interrupt mode after |
228 | * the driver has enabled the GPE. |
229 | * The APIs should be invoked in this order: |
230 | * AcpiEnableGpe() <- Ensure the reference count > 0 |
231 | * AcpiSetGpe(ACPI_GPE_DISABLE) <- Enter polling mode |
232 | * AcpiSetGpe(ACPI_GPE_ENABLE) <- Leave polling mode |
233 | * AcpiDisableGpe() <- Decrease the reference count |
234 | * |
235 | * Note: If a GPE is shared by 2 silicon components, then both the drivers |
236 | * should support GPE polling mode or disabling the GPE for long period |
237 | * for one driver may break the other. So use it with care since all |
238 | * firmware _Lxx/_Exx handlers currently rely on the GPE interrupt mode. |
239 | * |
240 | ******************************************************************************/ |
241 | |
242 | ACPI_STATUS |
243 | AcpiSetGpe ( |
244 | ACPI_HANDLE GpeDevice, |
245 | UINT32 GpeNumber, |
246 | UINT8 Action) |
247 | { |
248 | ACPI_GPE_EVENT_INFO *GpeEventInfo; |
249 | ACPI_STATUS Status; |
250 | ACPI_CPU_FLAGS Flags; |
251 | |
252 | |
253 | ACPI_FUNCTION_TRACE (AcpiSetGpe); |
254 | |
255 | |
256 | Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); |
257 | |
258 | /* Ensure that we have a valid GPE number */ |
259 | |
260 | GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); |
261 | if (!GpeEventInfo) |
262 | { |
263 | Status = AE_BAD_PARAMETER; |
264 | goto UnlockAndExit; |
265 | } |
266 | |
267 | /* Perform the action */ |
268 | |
269 | switch (Action) |
270 | { |
271 | case ACPI_GPE_ENABLE: |
272 | |
273 | Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE); |
274 | GpeEventInfo->DisableForDispatch = FALSE; |
275 | break; |
276 | |
277 | case ACPI_GPE_DISABLE: |
278 | |
279 | Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); |
280 | GpeEventInfo->DisableForDispatch = TRUE; |
281 | break; |
282 | |
283 | default: |
284 | |
285 | Status = AE_BAD_PARAMETER; |
286 | break; |
287 | } |
288 | |
289 | UnlockAndExit: |
290 | AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); |
291 | return_ACPI_STATUS (Status); |
292 | } |
293 | |
294 | ACPI_EXPORT_SYMBOL (AcpiSetGpe) |
295 | |
296 | |
297 | /******************************************************************************* |
298 | * |
299 | * FUNCTION: AcpiMaskGpe |
300 | * |
301 | * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 |
302 | * GpeNumber - GPE level within the GPE block |
303 | * IsMasked - Whether the GPE is masked or not |
304 | * |
305 | * RETURN: Status |
306 | * |
307 | * DESCRIPTION: Unconditionally mask/unmask the an individual GPE, ex., to |
308 | * prevent a GPE flooding. |
309 | * |
310 | ******************************************************************************/ |
311 | |
312 | ACPI_STATUS |
313 | AcpiMaskGpe ( |
314 | ACPI_HANDLE GpeDevice, |
315 | UINT32 GpeNumber, |
316 | BOOLEAN IsMasked) |
317 | { |
318 | ACPI_GPE_EVENT_INFO *GpeEventInfo; |
319 | ACPI_STATUS Status; |
320 | ACPI_CPU_FLAGS Flags; |
321 | |
322 | |
323 | ACPI_FUNCTION_TRACE (AcpiMaskGpe); |
324 | |
325 | |
326 | Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); |
327 | |
328 | /* Ensure that we have a valid GPE number */ |
329 | |
330 | GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); |
331 | if (!GpeEventInfo) |
332 | { |
333 | Status = AE_BAD_PARAMETER; |
334 | goto UnlockAndExit; |
335 | } |
336 | |
337 | Status = AcpiEvMaskGpe (GpeEventInfo, IsMasked); |
338 | |
339 | UnlockAndExit: |
340 | AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); |
341 | return_ACPI_STATUS (Status); |
342 | } |
343 | |
344 | ACPI_EXPORT_SYMBOL (AcpiMaskGpe) |
345 | |
346 | |
347 | /******************************************************************************* |
348 | * |
349 | * FUNCTION: AcpiMarkGpeForWake |
350 | * |
351 | * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 |
352 | * GpeNumber - GPE level within the GPE block |
353 | * |
354 | * RETURN: Status |
355 | * |
356 | * DESCRIPTION: Mark a GPE as having the ability to wake the system. Simply |
357 | * sets the ACPI_GPE_CAN_WAKE flag. |
358 | * |
359 | * Some potential callers of AcpiSetupGpeForWake may know in advance that |
360 | * there won't be any notify handlers installed for device wake notifications |
361 | * from the given GPE (one example is a button GPE in Linux). For these cases, |
362 | * AcpiMarkGpeForWake should be used instead of AcpiSetupGpeForWake. |
363 | * This will set the ACPI_GPE_CAN_WAKE flag for the GPE without trying to |
364 | * setup implicit wake notification for it (since there's no handler method). |
365 | * |
366 | ******************************************************************************/ |
367 | |
368 | ACPI_STATUS |
369 | AcpiMarkGpeForWake ( |
370 | ACPI_HANDLE GpeDevice, |
371 | UINT32 GpeNumber) |
372 | { |
373 | ACPI_GPE_EVENT_INFO *GpeEventInfo; |
374 | ACPI_STATUS Status = AE_BAD_PARAMETER; |
375 | ACPI_CPU_FLAGS Flags; |
376 | |
377 | |
378 | ACPI_FUNCTION_TRACE (AcpiMarkGpeForWake); |
379 | |
380 | |
381 | Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); |
382 | |
383 | /* Ensure that we have a valid GPE number */ |
384 | |
385 | GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); |
386 | if (GpeEventInfo) |
387 | { |
388 | /* Mark the GPE as a possible wake event */ |
389 | |
390 | GpeEventInfo->Flags |= ACPI_GPE_CAN_WAKE; |
391 | Status = AE_OK; |
392 | } |
393 | |
394 | AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); |
395 | return_ACPI_STATUS (Status); |
396 | } |
397 | |
398 | ACPI_EXPORT_SYMBOL (AcpiMarkGpeForWake) |
399 | |
400 | |
401 | /******************************************************************************* |
402 | * |
403 | * FUNCTION: AcpiSetupGpeForWake |
404 | * |
405 | * PARAMETERS: WakeDevice - Device associated with the GPE (via _PRW) |
406 | * GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 |
407 | * GpeNumber - GPE level within the GPE block |
408 | * |
409 | * RETURN: Status |
410 | * |
411 | * DESCRIPTION: Mark a GPE as having the ability to wake the system. This |
412 | * interface is intended to be used as the host executes the |
413 | * _PRW methods (Power Resources for Wake) in the system tables. |
414 | * Each _PRW appears under a Device Object (The WakeDevice), and |
415 | * contains the info for the wake GPE associated with the |
416 | * WakeDevice. |
417 | * |
418 | ******************************************************************************/ |
419 | |
420 | ACPI_STATUS |
421 | AcpiSetupGpeForWake ( |
422 | ACPI_HANDLE WakeDevice, |
423 | ACPI_HANDLE GpeDevice, |
424 | UINT32 GpeNumber) |
425 | { |
426 | ACPI_STATUS Status; |
427 | ACPI_GPE_EVENT_INFO *GpeEventInfo; |
428 | ACPI_NAMESPACE_NODE *DeviceNode; |
429 | ACPI_GPE_NOTIFY_INFO *Notify; |
430 | ACPI_GPE_NOTIFY_INFO *NewNotify; |
431 | ACPI_CPU_FLAGS Flags; |
432 | |
433 | |
434 | ACPI_FUNCTION_TRACE (AcpiSetupGpeForWake); |
435 | |
436 | |
437 | /* Parameter Validation */ |
438 | |
439 | if (!WakeDevice) |
440 | { |
441 | /* |
442 | * By forcing WakeDevice to be valid, we automatically enable the |
443 | * implicit notify feature on all hosts. |
444 | */ |
445 | return_ACPI_STATUS (AE_BAD_PARAMETER); |
446 | } |
447 | |
448 | /* Handle root object case */ |
449 | |
450 | if (WakeDevice == ACPI_ROOT_OBJECT) |
451 | { |
452 | DeviceNode = AcpiGbl_RootNode; |
453 | } |
454 | else |
455 | { |
456 | DeviceNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, WakeDevice); |
457 | } |
458 | |
459 | /* Validate WakeDevice is of type Device */ |
460 | |
461 | if (DeviceNode->Type != ACPI_TYPE_DEVICE) |
462 | { |
463 | return_ACPI_STATUS (AE_BAD_PARAMETER); |
464 | } |
465 | |
466 | /* |
467 | * Allocate a new notify object up front, in case it is needed. |
468 | * Memory allocation while holding a spinlock is a big no-no |
469 | * on some hosts. |
470 | */ |
471 | NewNotify = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_NOTIFY_INFO)); |
472 | if (!NewNotify) |
473 | { |
474 | return_ACPI_STATUS (AE_NO_MEMORY); |
475 | } |
476 | |
477 | Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); |
478 | |
479 | /* Ensure that we have a valid GPE number */ |
480 | |
481 | GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); |
482 | if (!GpeEventInfo) |
483 | { |
484 | Status = AE_BAD_PARAMETER; |
485 | goto UnlockAndExit; |
486 | } |
487 | |
488 | /* |
489 | * If there is no method or handler for this GPE, then the |
490 | * WakeDevice will be notified whenever this GPE fires. This is |
491 | * known as an "implicit notify". Note: The GPE is assumed to be |
492 | * level-triggered (for windows compatibility). |
493 | */ |
494 | if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == |
495 | ACPI_GPE_DISPATCH_NONE) |
496 | { |
497 | /* |
498 | * This is the first device for implicit notify on this GPE. |
499 | * Just set the flags here, and enter the NOTIFY block below. |
500 | */ |
501 | GpeEventInfo->Flags = |
502 | (ACPI_GPE_DISPATCH_NOTIFY | ACPI_GPE_LEVEL_TRIGGERED); |
503 | } |
504 | |
505 | /* |
506 | * If we already have an implicit notify on this GPE, add |
507 | * this device to the notify list. |
508 | */ |
509 | if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == |
510 | ACPI_GPE_DISPATCH_NOTIFY) |
511 | { |
512 | /* Ensure that the device is not already in the list */ |
513 | |
514 | Notify = GpeEventInfo->Dispatch.NotifyList; |
515 | while (Notify) |
516 | { |
517 | if (Notify->DeviceNode == DeviceNode) |
518 | { |
519 | Status = AE_ALREADY_EXISTS; |
520 | goto UnlockAndExit; |
521 | } |
522 | Notify = Notify->Next; |
523 | } |
524 | |
525 | /* Add this device to the notify list for this GPE */ |
526 | |
527 | NewNotify->DeviceNode = DeviceNode; |
528 | NewNotify->Next = GpeEventInfo->Dispatch.NotifyList; |
529 | GpeEventInfo->Dispatch.NotifyList = NewNotify; |
530 | NewNotify = NULL; |
531 | } |
532 | |
533 | /* Mark the GPE as a possible wake event */ |
534 | |
535 | GpeEventInfo->Flags |= ACPI_GPE_CAN_WAKE; |
536 | Status = AE_OK; |
537 | |
538 | |
539 | UnlockAndExit: |
540 | AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); |
541 | |
542 | /* Delete the notify object if it was not used above */ |
543 | |
544 | if (NewNotify) |
545 | { |
546 | ACPI_FREE (NewNotify); |
547 | } |
548 | return_ACPI_STATUS (Status); |
549 | } |
550 | |
551 | ACPI_EXPORT_SYMBOL (AcpiSetupGpeForWake) |
552 | |
553 | |
554 | /******************************************************************************* |
555 | * |
556 | * FUNCTION: AcpiSetGpeWakeMask |
557 | * |
558 | * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 |
559 | * GpeNumber - GPE level within the GPE block |
560 | * Action - Enable or Disable |
561 | * |
562 | * RETURN: Status |
563 | * |
564 | * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit. The GPE must |
565 | * already be marked as a WAKE GPE. |
566 | * |
567 | ******************************************************************************/ |
568 | |
569 | ACPI_STATUS |
570 | AcpiSetGpeWakeMask ( |
571 | ACPI_HANDLE GpeDevice, |
572 | UINT32 GpeNumber, |
573 | UINT8 Action) |
574 | { |
575 | ACPI_STATUS Status = AE_OK; |
576 | ACPI_GPE_EVENT_INFO *GpeEventInfo; |
577 | ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; |
578 | ACPI_CPU_FLAGS Flags; |
579 | UINT32 RegisterBit; |
580 | |
581 | |
582 | ACPI_FUNCTION_TRACE (AcpiSetGpeWakeMask); |
583 | |
584 | |
585 | Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); |
586 | |
587 | /* |
588 | * Ensure that we have a valid GPE number and that this GPE is in |
589 | * fact a wake GPE |
590 | */ |
591 | GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); |
592 | if (!GpeEventInfo) |
593 | { |
594 | Status = AE_BAD_PARAMETER; |
595 | goto UnlockAndExit; |
596 | } |
597 | |
598 | if (!(GpeEventInfo->Flags & ACPI_GPE_CAN_WAKE)) |
599 | { |
600 | Status = AE_TYPE; |
601 | goto UnlockAndExit; |
602 | } |
603 | |
604 | GpeRegisterInfo = GpeEventInfo->RegisterInfo; |
605 | if (!GpeRegisterInfo) |
606 | { |
607 | Status = AE_NOT_EXIST; |
608 | goto UnlockAndExit; |
609 | } |
610 | |
611 | RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo); |
612 | |
613 | /* Perform the action */ |
614 | |
615 | switch (Action) |
616 | { |
617 | case ACPI_GPE_ENABLE: |
618 | |
619 | ACPI_SET_BIT (GpeRegisterInfo->EnableForWake, (UINT8) RegisterBit); |
620 | break; |
621 | |
622 | case ACPI_GPE_DISABLE: |
623 | |
624 | ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForWake, (UINT8) RegisterBit); |
625 | break; |
626 | |
627 | default: |
628 | |
629 | ACPI_ERROR ((AE_INFO, "%u, Invalid action" , Action)); |
630 | Status = AE_BAD_PARAMETER; |
631 | break; |
632 | } |
633 | |
634 | UnlockAndExit: |
635 | AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); |
636 | return_ACPI_STATUS (Status); |
637 | } |
638 | |
639 | ACPI_EXPORT_SYMBOL (AcpiSetGpeWakeMask) |
640 | |
641 | |
642 | /******************************************************************************* |
643 | * |
644 | * FUNCTION: AcpiClearGpe |
645 | * |
646 | * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 |
647 | * GpeNumber - GPE level within the GPE block |
648 | * |
649 | * RETURN: Status |
650 | * |
651 | * DESCRIPTION: Clear an ACPI event (general purpose) |
652 | * |
653 | ******************************************************************************/ |
654 | |
655 | ACPI_STATUS |
656 | AcpiClearGpe ( |
657 | ACPI_HANDLE GpeDevice, |
658 | UINT32 GpeNumber) |
659 | { |
660 | ACPI_STATUS Status = AE_OK; |
661 | ACPI_GPE_EVENT_INFO *GpeEventInfo; |
662 | ACPI_CPU_FLAGS Flags; |
663 | |
664 | |
665 | ACPI_FUNCTION_TRACE (AcpiClearGpe); |
666 | |
667 | |
668 | Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); |
669 | |
670 | /* Ensure that we have a valid GPE number */ |
671 | |
672 | GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); |
673 | if (!GpeEventInfo) |
674 | { |
675 | Status = AE_BAD_PARAMETER; |
676 | goto UnlockAndExit; |
677 | } |
678 | |
679 | Status = AcpiHwClearGpe (GpeEventInfo); |
680 | |
681 | UnlockAndExit: |
682 | AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); |
683 | return_ACPI_STATUS (Status); |
684 | } |
685 | |
686 | ACPI_EXPORT_SYMBOL (AcpiClearGpe) |
687 | |
688 | |
689 | /******************************************************************************* |
690 | * |
691 | * FUNCTION: AcpiGetGpeStatus |
692 | * |
693 | * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 |
694 | * GpeNumber - GPE level within the GPE block |
695 | * EventStatus - Where the current status of the event |
696 | * will be returned |
697 | * |
698 | * RETURN: Status |
699 | * |
700 | * DESCRIPTION: Get the current status of a GPE (signalled/not_signalled) |
701 | * |
702 | ******************************************************************************/ |
703 | |
704 | ACPI_STATUS |
705 | AcpiGetGpeStatus ( |
706 | ACPI_HANDLE GpeDevice, |
707 | UINT32 GpeNumber, |
708 | ACPI_EVENT_STATUS *EventStatus) |
709 | { |
710 | ACPI_STATUS Status = AE_OK; |
711 | ACPI_GPE_EVENT_INFO *GpeEventInfo; |
712 | ACPI_CPU_FLAGS Flags; |
713 | |
714 | |
715 | ACPI_FUNCTION_TRACE (AcpiGetGpeStatus); |
716 | |
717 | |
718 | Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); |
719 | |
720 | /* Ensure that we have a valid GPE number */ |
721 | |
722 | GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); |
723 | if (!GpeEventInfo) |
724 | { |
725 | Status = AE_BAD_PARAMETER; |
726 | goto UnlockAndExit; |
727 | } |
728 | |
729 | /* Obtain status on the requested GPE number */ |
730 | |
731 | Status = AcpiHwGetGpeStatus (GpeEventInfo, EventStatus); |
732 | |
733 | UnlockAndExit: |
734 | AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); |
735 | return_ACPI_STATUS (Status); |
736 | } |
737 | |
738 | ACPI_EXPORT_SYMBOL (AcpiGetGpeStatus) |
739 | |
740 | |
741 | /******************************************************************************* |
742 | * |
743 | * FUNCTION: AcpiFinishGpe |
744 | * |
745 | * PARAMETERS: GpeDevice - Namespace node for the GPE Block |
746 | * (NULL for FADT defined GPEs) |
747 | * GpeNumber - GPE level within the GPE block |
748 | * |
749 | * RETURN: Status |
750 | * |
751 | * DESCRIPTION: Clear and conditionally reenable a GPE. This completes the GPE |
752 | * processing. Intended for use by asynchronous host-installed |
753 | * GPE handlers. The GPE is only reenabled if the EnableForRun bit |
754 | * is set in the GPE info. |
755 | * |
756 | ******************************************************************************/ |
757 | |
758 | ACPI_STATUS |
759 | AcpiFinishGpe ( |
760 | ACPI_HANDLE GpeDevice, |
761 | UINT32 GpeNumber) |
762 | { |
763 | ACPI_GPE_EVENT_INFO *GpeEventInfo; |
764 | ACPI_STATUS Status; |
765 | ACPI_CPU_FLAGS Flags; |
766 | |
767 | |
768 | ACPI_FUNCTION_TRACE (AcpiFinishGpe); |
769 | |
770 | |
771 | Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); |
772 | |
773 | /* Ensure that we have a valid GPE number */ |
774 | |
775 | GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); |
776 | if (!GpeEventInfo) |
777 | { |
778 | Status = AE_BAD_PARAMETER; |
779 | goto UnlockAndExit; |
780 | } |
781 | |
782 | Status = AcpiEvFinishGpe (GpeEventInfo); |
783 | |
784 | UnlockAndExit: |
785 | AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); |
786 | return_ACPI_STATUS (Status); |
787 | } |
788 | |
789 | ACPI_EXPORT_SYMBOL (AcpiFinishGpe) |
790 | |
791 | |
792 | /****************************************************************************** |
793 | * |
794 | * FUNCTION: AcpiDisableAllGpes |
795 | * |
796 | * PARAMETERS: None |
797 | * |
798 | * RETURN: Status |
799 | * |
800 | * DESCRIPTION: Disable and clear all GPEs in all GPE blocks |
801 | * |
802 | ******************************************************************************/ |
803 | |
804 | ACPI_STATUS |
805 | AcpiDisableAllGpes ( |
806 | void) |
807 | { |
808 | ACPI_STATUS Status; |
809 | |
810 | |
811 | ACPI_FUNCTION_TRACE (AcpiDisableAllGpes); |
812 | |
813 | |
814 | Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); |
815 | if (ACPI_FAILURE (Status)) |
816 | { |
817 | return_ACPI_STATUS (Status); |
818 | } |
819 | |
820 | Status = AcpiHwDisableAllGpes (); |
821 | (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); |
822 | |
823 | return_ACPI_STATUS (Status); |
824 | } |
825 | |
826 | ACPI_EXPORT_SYMBOL (AcpiDisableAllGpes) |
827 | |
828 | |
829 | /****************************************************************************** |
830 | * |
831 | * FUNCTION: AcpiEnableAllRuntimeGpes |
832 | * |
833 | * PARAMETERS: None |
834 | * |
835 | * RETURN: Status |
836 | * |
837 | * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks |
838 | * |
839 | ******************************************************************************/ |
840 | |
841 | ACPI_STATUS |
842 | AcpiEnableAllRuntimeGpes ( |
843 | void) |
844 | { |
845 | ACPI_STATUS Status; |
846 | |
847 | |
848 | ACPI_FUNCTION_TRACE (AcpiEnableAllRuntimeGpes); |
849 | |
850 | |
851 | Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); |
852 | if (ACPI_FAILURE (Status)) |
853 | { |
854 | return_ACPI_STATUS (Status); |
855 | } |
856 | |
857 | Status = AcpiHwEnableAllRuntimeGpes (); |
858 | (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); |
859 | |
860 | return_ACPI_STATUS (Status); |
861 | } |
862 | |
863 | ACPI_EXPORT_SYMBOL (AcpiEnableAllRuntimeGpes) |
864 | |
865 | |
866 | /****************************************************************************** |
867 | * |
868 | * FUNCTION: AcpiEnableAllWakeupGpes |
869 | * |
870 | * PARAMETERS: None |
871 | * |
872 | * RETURN: Status |
873 | * |
874 | * DESCRIPTION: Enable all "wakeup" GPEs and disable all of the other GPEs, in |
875 | * all GPE blocks. |
876 | * |
877 | ******************************************************************************/ |
878 | |
879 | ACPI_STATUS |
880 | AcpiEnableAllWakeupGpes ( |
881 | void) |
882 | { |
883 | ACPI_STATUS Status; |
884 | |
885 | |
886 | ACPI_FUNCTION_TRACE (AcpiEnableAllWakeupGpes); |
887 | |
888 | |
889 | Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); |
890 | if (ACPI_FAILURE (Status)) |
891 | { |
892 | return_ACPI_STATUS (Status); |
893 | } |
894 | |
895 | Status = AcpiHwEnableAllWakeupGpes (); |
896 | (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); |
897 | |
898 | return_ACPI_STATUS (Status); |
899 | } |
900 | |
901 | ACPI_EXPORT_SYMBOL (AcpiEnableAllWakeupGpes) |
902 | |
903 | |
904 | /******************************************************************************* |
905 | * |
906 | * FUNCTION: AcpiInstallGpeBlock |
907 | * |
908 | * PARAMETERS: GpeDevice - Handle to the parent GPE Block Device |
909 | * GpeBlockAddress - Address and SpaceID |
910 | * RegisterCount - Number of GPE register pairs in the block |
911 | * InterruptNumber - H/W interrupt for the block |
912 | * |
913 | * RETURN: Status |
914 | * |
915 | * DESCRIPTION: Create and Install a block of GPE registers. The GPEs are not |
916 | * enabled here. |
917 | * |
918 | ******************************************************************************/ |
919 | |
920 | ACPI_STATUS |
921 | AcpiInstallGpeBlock ( |
922 | ACPI_HANDLE GpeDevice, |
923 | ACPI_GENERIC_ADDRESS *GpeBlockAddress, |
924 | UINT32 RegisterCount, |
925 | UINT32 InterruptNumber) |
926 | { |
927 | ACPI_STATUS Status; |
928 | ACPI_OPERAND_OBJECT *ObjDesc; |
929 | ACPI_NAMESPACE_NODE *Node; |
930 | ACPI_GPE_BLOCK_INFO *GpeBlock; |
931 | |
932 | |
933 | ACPI_FUNCTION_TRACE (AcpiInstallGpeBlock); |
934 | |
935 | |
936 | if ((!GpeDevice) || |
937 | (!GpeBlockAddress) || |
938 | (!RegisterCount)) |
939 | { |
940 | return_ACPI_STATUS (AE_BAD_PARAMETER); |
941 | } |
942 | |
943 | Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); |
944 | if (ACPI_FAILURE (Status)) |
945 | { |
946 | return_ACPI_STATUS (Status); |
947 | } |
948 | |
949 | Node = AcpiNsValidateHandle (GpeDevice); |
950 | if (!Node) |
951 | { |
952 | Status = AE_BAD_PARAMETER; |
953 | goto UnlockAndExit; |
954 | } |
955 | |
956 | /* Validate the parent device */ |
957 | |
958 | if (Node->Type != ACPI_TYPE_DEVICE) |
959 | { |
960 | Status = AE_TYPE; |
961 | goto UnlockAndExit; |
962 | } |
963 | |
964 | if (Node->Object) |
965 | { |
966 | Status = AE_ALREADY_EXISTS; |
967 | goto UnlockAndExit; |
968 | } |
969 | |
970 | /* |
971 | * For user-installed GPE Block Devices, the GpeBlockBaseNumber |
972 | * is always zero |
973 | */ |
974 | Status = AcpiEvCreateGpeBlock (Node, GpeBlockAddress->Address, |
975 | GpeBlockAddress->SpaceId, RegisterCount, |
976 | 0, InterruptNumber, &GpeBlock); |
977 | if (ACPI_FAILURE (Status)) |
978 | { |
979 | goto UnlockAndExit; |
980 | } |
981 | |
982 | /* Install block in the DeviceObject attached to the node */ |
983 | |
984 | ObjDesc = AcpiNsGetAttachedObject (Node); |
985 | if (!ObjDesc) |
986 | { |
987 | /* |
988 | * No object, create a new one (Device nodes do not always have |
989 | * an attached object) |
990 | */ |
991 | ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_DEVICE); |
992 | if (!ObjDesc) |
993 | { |
994 | Status = AE_NO_MEMORY; |
995 | goto UnlockAndExit; |
996 | } |
997 | |
998 | Status = AcpiNsAttachObject (Node, ObjDesc, ACPI_TYPE_DEVICE); |
999 | |
1000 | /* Remove local reference to the object */ |
1001 | |
1002 | AcpiUtRemoveReference (ObjDesc); |
1003 | if (ACPI_FAILURE (Status)) |
1004 | { |
1005 | goto UnlockAndExit; |
1006 | } |
1007 | } |
1008 | |
1009 | /* Now install the GPE block in the DeviceObject */ |
1010 | |
1011 | ObjDesc->Device.GpeBlock = GpeBlock; |
1012 | |
1013 | |
1014 | UnlockAndExit: |
1015 | (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); |
1016 | return_ACPI_STATUS (Status); |
1017 | } |
1018 | |
1019 | ACPI_EXPORT_SYMBOL (AcpiInstallGpeBlock) |
1020 | |
1021 | |
1022 | /******************************************************************************* |
1023 | * |
1024 | * FUNCTION: AcpiRemoveGpeBlock |
1025 | * |
1026 | * PARAMETERS: GpeDevice - Handle to the parent GPE Block Device |
1027 | * |
1028 | * RETURN: Status |
1029 | * |
1030 | * DESCRIPTION: Remove a previously installed block of GPE registers |
1031 | * |
1032 | ******************************************************************************/ |
1033 | |
1034 | ACPI_STATUS |
1035 | AcpiRemoveGpeBlock ( |
1036 | ACPI_HANDLE GpeDevice) |
1037 | { |
1038 | ACPI_OPERAND_OBJECT *ObjDesc; |
1039 | ACPI_STATUS Status; |
1040 | ACPI_NAMESPACE_NODE *Node; |
1041 | |
1042 | |
1043 | ACPI_FUNCTION_TRACE (AcpiRemoveGpeBlock); |
1044 | |
1045 | |
1046 | if (!GpeDevice) |
1047 | { |
1048 | return_ACPI_STATUS (AE_BAD_PARAMETER); |
1049 | } |
1050 | |
1051 | Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); |
1052 | if (ACPI_FAILURE (Status)) |
1053 | { |
1054 | return_ACPI_STATUS (Status); |
1055 | } |
1056 | |
1057 | Node = AcpiNsValidateHandle (GpeDevice); |
1058 | if (!Node) |
1059 | { |
1060 | Status = AE_BAD_PARAMETER; |
1061 | goto UnlockAndExit; |
1062 | } |
1063 | |
1064 | /* Validate the parent device */ |
1065 | |
1066 | if (Node->Type != ACPI_TYPE_DEVICE) |
1067 | { |
1068 | Status = AE_TYPE; |
1069 | goto UnlockAndExit; |
1070 | } |
1071 | |
1072 | /* Get the DeviceObject attached to the node */ |
1073 | |
1074 | ObjDesc = AcpiNsGetAttachedObject (Node); |
1075 | if (!ObjDesc || |
1076 | !ObjDesc->Device.GpeBlock) |
1077 | { |
1078 | return_ACPI_STATUS (AE_NULL_OBJECT); |
1079 | } |
1080 | |
1081 | /* Delete the GPE block (but not the DeviceObject) */ |
1082 | |
1083 | Status = AcpiEvDeleteGpeBlock (ObjDesc->Device.GpeBlock); |
1084 | if (ACPI_SUCCESS (Status)) |
1085 | { |
1086 | ObjDesc->Device.GpeBlock = NULL; |
1087 | } |
1088 | |
1089 | UnlockAndExit: |
1090 | (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); |
1091 | return_ACPI_STATUS (Status); |
1092 | } |
1093 | |
1094 | ACPI_EXPORT_SYMBOL (AcpiRemoveGpeBlock) |
1095 | |
1096 | |
1097 | /******************************************************************************* |
1098 | * |
1099 | * FUNCTION: AcpiGetGpeDevice |
1100 | * |
1101 | * PARAMETERS: Index - System GPE index (0-CurrentGpeCount) |
1102 | * GpeDevice - Where the parent GPE Device is returned |
1103 | * |
1104 | * RETURN: Status |
1105 | * |
1106 | * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL |
1107 | * gpe device indicates that the gpe number is contained in one of |
1108 | * the FADT-defined gpe blocks. Otherwise, the GPE block device. |
1109 | * |
1110 | ******************************************************************************/ |
1111 | |
1112 | ACPI_STATUS |
1113 | AcpiGetGpeDevice ( |
1114 | UINT32 Index, |
1115 | ACPI_HANDLE *GpeDevice) |
1116 | { |
1117 | ACPI_GPE_DEVICE_INFO Info; |
1118 | ACPI_STATUS Status; |
1119 | |
1120 | |
1121 | ACPI_FUNCTION_TRACE (AcpiGetGpeDevice); |
1122 | |
1123 | |
1124 | if (!GpeDevice) |
1125 | { |
1126 | return_ACPI_STATUS (AE_BAD_PARAMETER); |
1127 | } |
1128 | |
1129 | if (Index >= AcpiCurrentGpeCount) |
1130 | { |
1131 | return_ACPI_STATUS (AE_NOT_EXIST); |
1132 | } |
1133 | |
1134 | /* Setup and walk the GPE list */ |
1135 | |
1136 | Info.Index = Index; |
1137 | Info.Status = AE_NOT_EXIST; |
1138 | Info.GpeDevice = NULL; |
1139 | Info.NextBlockBaseIndex = 0; |
1140 | |
1141 | Status = AcpiEvWalkGpeList (AcpiEvGetGpeDevice, &Info); |
1142 | if (ACPI_FAILURE (Status)) |
1143 | { |
1144 | return_ACPI_STATUS (Status); |
1145 | } |
1146 | |
1147 | *GpeDevice = ACPI_CAST_PTR (ACPI_HANDLE, Info.GpeDevice); |
1148 | return_ACPI_STATUS (Info.Status); |
1149 | } |
1150 | |
1151 | ACPI_EXPORT_SYMBOL (AcpiGetGpeDevice) |
1152 | |
1153 | #endif /* !ACPI_REDUCED_HARDWARE */ |
1154 | |