blob: 18b3f1468b7daeebd94dbe43216a4078951d9972 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/******************************************************************************
2 *
3 * Module Name: evxfevnt - External Interfaces, ACPI event disable/enable
4 *
5 *****************************************************************************/
6
7/*
Bob Moorea8357b02010-01-22 19:07:36 +08008 * Copyright (C) 2000 - 2010, Intel Corp.
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <acpi/acpi.h>
Len Browne2f7a772009-01-09 00:30:03 -050045#include "accommon.h"
46#include "acevents.h"
47#include "acnamesp.h"
48#include "actables.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50#define _COMPONENT ACPI_EVENTS
Len Brown4be44fc2005-08-05 00:44:28 -040051ACPI_MODULE_NAME("evxfevnt")
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
Bob Mooree97d6bf2008-12-30 09:45:17 +080053/* Local prototypes */
Bob Mooree4c1ebf2009-04-22 13:02:06 +080054static acpi_status
Bob Mooree97d6bf2008-12-30 09:45:17 +080055acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
56 struct acpi_gpe_block_info *gpe_block, void *context);
57
Linus Torvalds1da177e2005-04-16 15:20:36 -070058/*******************************************************************************
59 *
60 * FUNCTION: acpi_enable
61 *
62 * PARAMETERS: None
63 *
64 * RETURN: Status
65 *
66 * DESCRIPTION: Transfers the system into ACPI mode.
67 *
68 ******************************************************************************/
Bob Mooree97d6bf2008-12-30 09:45:17 +080069
Len Brown4be44fc2005-08-05 00:44:28 -040070acpi_status acpi_enable(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070071{
Len Brownb430acb2010-05-06 17:41:08 -040072 acpi_status status;
Len Brown3d695832010-06-28 20:55:01 -040073 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Bob Mooreb229cf92006-04-21 17:15:00 -040075 ACPI_FUNCTION_TRACE(acpi_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
Bob Moorec8573032007-02-02 19:48:23 +030077 /* ACPI tables must be present */
78
79 if (!acpi_tb_tables_loaded()) {
80 return_ACPI_STATUS(AE_NO_ACPI_TABLES);
81 }
82
83 /* Check current mode */
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
Len Brown4be44fc2005-08-05 00:44:28 -040086 ACPI_DEBUG_PRINT((ACPI_DB_INIT,
87 "System is already in ACPI mode\n"));
Len Brownb430acb2010-05-06 17:41:08 -040088 return_ACPI_STATUS(AE_OK);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 }
90
Len Brownb430acb2010-05-06 17:41:08 -040091 /* Transition to ACPI mode */
92
93 status = acpi_hw_set_mode(ACPI_SYS_MODE_ACPI);
94 if (ACPI_FAILURE(status)) {
95 ACPI_ERROR((AE_INFO,
96 "Could not transition to ACPI mode"));
97 return_ACPI_STATUS(status);
98 }
99
100 /* Sanity check that transition succeeded */
101
Len Brown3d695832010-06-28 20:55:01 -0400102 for (retry = 0; retry < 30000; ++retry) {
103 if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
104 if (retry != 0)
105 ACPI_WARNING((AE_INFO,
106 "Platform took > %d00 usec to enter ACPI mode", retry));
107 return_ACPI_STATUS(AE_OK);
108 }
109 acpi_os_stall(100); /* 100 usec */
Len Brownb430acb2010-05-06 17:41:08 -0400110 }
111
Len Brown3d695832010-06-28 20:55:01 -0400112 ACPI_ERROR((AE_INFO, "Hardware did not enter ACPI mode"));
113 return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114}
115
Bob Moore83135242006-10-03 00:00:00 -0400116ACPI_EXPORT_SYMBOL(acpi_enable)
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118/*******************************************************************************
119 *
120 * FUNCTION: acpi_disable
121 *
122 * PARAMETERS: None
123 *
124 * RETURN: Status
125 *
Robert Moore44f6c012005-04-18 22:49:35 -0400126 * DESCRIPTION: Transfers the system into LEGACY (non-ACPI) mode.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 *
128 ******************************************************************************/
Len Brown4be44fc2005-08-05 00:44:28 -0400129acpi_status acpi_disable(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
Len Brown4be44fc2005-08-05 00:44:28 -0400131 acpi_status status = AE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Bob Mooreb229cf92006-04-21 17:15:00 -0400133 ACPI_FUNCTION_TRACE(acpi_disable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) {
Len Brown4be44fc2005-08-05 00:44:28 -0400136 ACPI_DEBUG_PRINT((ACPI_DB_INIT,
137 "System is already in legacy (non-ACPI) mode\n"));
138 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 /* Transition to LEGACY mode */
140
Len Brown4be44fc2005-08-05 00:44:28 -0400141 status = acpi_hw_set_mode(ACPI_SYS_MODE_LEGACY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
Len Brown4be44fc2005-08-05 00:44:28 -0400143 if (ACPI_FAILURE(status)) {
Bob Mooreb8e4d892006-01-27 16:43:00 -0500144 ACPI_ERROR((AE_INFO,
145 "Could not exit ACPI mode to legacy mode"));
Len Brown4be44fc2005-08-05 00:44:28 -0400146 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 }
148
Len Brown4be44fc2005-08-05 00:44:28 -0400149 ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI mode disabled\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 }
151
Len Brown4be44fc2005-08-05 00:44:28 -0400152 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153}
154
Bob Moore83135242006-10-03 00:00:00 -0400155ACPI_EXPORT_SYMBOL(acpi_disable)
156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157/*******************************************************************************
158 *
159 * FUNCTION: acpi_enable_event
160 *
161 * PARAMETERS: Event - The fixed eventto be enabled
162 * Flags - Reserved
163 *
164 * RETURN: Status
165 *
166 * DESCRIPTION: Enable an ACPI event (fixed)
167 *
168 ******************************************************************************/
Len Brown4be44fc2005-08-05 00:44:28 -0400169acpi_status acpi_enable_event(u32 event, u32 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170{
Len Brown4be44fc2005-08-05 00:44:28 -0400171 acpi_status status = AE_OK;
172 u32 value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
Bob Mooreb229cf92006-04-21 17:15:00 -0400174 ACPI_FUNCTION_TRACE(acpi_enable_event);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
176 /* Decode the Fixed Event */
177
178 if (event > ACPI_EVENT_MAX) {
Len Brown4be44fc2005-08-05 00:44:28 -0400179 return_ACPI_STATUS(AE_BAD_PARAMETER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 }
181
182 /*
Bob Moore9f15fc62008-11-12 16:01:56 +0800183 * Enable the requested fixed event (by writing a one to the enable
184 * register bit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 */
Len Brown4be44fc2005-08-05 00:44:28 -0400186 status =
Bob Moore50ffba12009-02-23 15:02:07 +0800187 acpi_write_bit_register(acpi_gbl_fixed_event_info[event].
Bob Moore768aaaf2009-03-06 09:49:25 +0800188 enable_register_id, ACPI_ENABLE_EVENT);
Len Brown4be44fc2005-08-05 00:44:28 -0400189 if (ACPI_FAILURE(status)) {
190 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 }
192
193 /* Make sure that the hardware responded */
194
Len Brown4be44fc2005-08-05 00:44:28 -0400195 status =
Bob Moore50ffba12009-02-23 15:02:07 +0800196 acpi_read_bit_register(acpi_gbl_fixed_event_info[event].
197 enable_register_id, &value);
Len Brown4be44fc2005-08-05 00:44:28 -0400198 if (ACPI_FAILURE(status)) {
199 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 }
201
202 if (value != 1) {
Bob Mooreb8e4d892006-01-27 16:43:00 -0500203 ACPI_ERROR((AE_INFO,
204 "Could not enable %s event",
205 acpi_ut_get_event_name(event)));
Len Brown4be44fc2005-08-05 00:44:28 -0400206 return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 }
208
Len Brown4be44fc2005-08-05 00:44:28 -0400209 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Bob Moore83135242006-10-03 00:00:00 -0400212ACPI_EXPORT_SYMBOL(acpi_enable_event)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
214/*******************************************************************************
215 *
Rafael J. Wysockifd247442010-06-08 10:49:08 +0200216 * FUNCTION: acpi_clear_and_enable_gpe
217 *
218 * PARAMETERS: gpe_event_info - GPE to enable
219 *
220 * RETURN: Status
221 *
222 * DESCRIPTION: Clear the given GPE from stale events and enable it.
223 *
224 ******************************************************************************/
225static acpi_status
226acpi_clear_and_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
227{
228 acpi_status status;
229
230 /*
231 * We will only allow a GPE to be enabled if it has either an
232 * associated method (_Lxx/_Exx) or a handler. Otherwise, the
233 * GPE will be immediately disabled by acpi_ev_gpe_dispatch the
234 * first time it fires.
235 */
236 if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
237 return_ACPI_STATUS(AE_NO_HANDLER);
238 }
239
240 /* Clear the GPE (of stale events) */
241 status = acpi_hw_clear_gpe(gpe_event_info);
242 if (ACPI_FAILURE(status)) {
243 return_ACPI_STATUS(status);
244 }
245
246 /* Enable the requested GPE */
247 status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
248
249 return_ACPI_STATUS(status);
250}
251
252/*******************************************************************************
253 *
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100254 * FUNCTION: acpi_set_gpe
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 *
Lin Ming0f849d22010-04-06 14:52:37 +0800256 * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 * gpe_number - GPE level within the GPE block
Lin Ming0f849d22010-04-06 14:52:37 +0800258 * action - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 *
260 * RETURN: Status
261 *
Lin Ming0f849d22010-04-06 14:52:37 +0800262 * DESCRIPTION: Enable or disable an individual GPE. This function bypasses
263 * the reference count mechanism used in the acpi_enable_gpe and
264 * acpi_disable_gpe interfaces -- and should be used with care.
265 *
266 * Note: Typically used to disable a runtime GPE for short period of time,
267 * then re-enable it, without disturbing the existing reference counts. This
268 * is useful, for example, in the Embedded Controller (EC) driver.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 *
270 ******************************************************************************/
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100271acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272{
Len Brown4be44fc2005-08-05 00:44:28 -0400273 struct acpi_gpe_event_info *gpe_event_info;
Lin Ming0f849d22010-04-06 14:52:37 +0800274 acpi_status status;
275 acpi_cpu_flags flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100277 ACPI_FUNCTION_TRACE(acpi_set_gpe);
278
279 flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
281 /* Ensure that we have a valid GPE number */
282
Len Brown4be44fc2005-08-05 00:44:28 -0400283 gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 if (!gpe_event_info) {
285 status = AE_BAD_PARAMETER;
286 goto unlock_and_exit;
287 }
288
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100289 /* Perform the action */
290
291 switch (action) {
292 case ACPI_GPE_ENABLE:
Rafael J. Wysockifd247442010-06-08 10:49:08 +0200293 status = acpi_clear_and_enable_gpe(gpe_event_info);
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100294 break;
295
296 case ACPI_GPE_DISABLE:
Rafael J. Wysockifd247442010-06-08 10:49:08 +0200297 status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100298 break;
299
300 default:
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100301 status = AE_BAD_PARAMETER;
302 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 }
304
Len Brown4be44fc2005-08-05 00:44:28 -0400305 unlock_and_exit:
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100306 acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
Len Brown4be44fc2005-08-05 00:44:28 -0400307 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100310ACPI_EXPORT_SYMBOL(acpi_set_gpe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312/*******************************************************************************
313 *
314 * FUNCTION: acpi_enable_gpe
315 *
Lin Ming0f849d22010-04-06 14:52:37 +0800316 * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 * gpe_number - GPE level within the GPE block
Lin Ming0f849d22010-04-06 14:52:37 +0800318 * gpe_type - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
319 * or both
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 *
321 * RETURN: Status
322 *
Lin Ming0f849d22010-04-06 14:52:37 +0800323 * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
324 * hardware-enabled (for runtime GPEs), or the GPE register mask
325 * is updated (for wake GPEs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 *
327 ******************************************************************************/
Lin Ming0f849d22010-04-06 14:52:37 +0800328acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
Len Brown4be44fc2005-08-05 00:44:28 -0400330 acpi_status status = AE_OK;
331 struct acpi_gpe_event_info *gpe_event_info;
Lin Ming0f849d22010-04-06 14:52:37 +0800332 acpi_cpu_flags flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Bob Mooreb229cf92006-04-21 17:15:00 -0400334 ACPI_FUNCTION_TRACE(acpi_enable_gpe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Lin Ming0f849d22010-04-06 14:52:37 +0800336 /* Parameter validation */
337
338 if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) {
Rafael J. Wysockicbbc0de2010-02-24 00:52:08 +0100339 return_ACPI_STATUS(AE_BAD_PARAMETER);
Lin Ming0f849d22010-04-06 14:52:37 +0800340 }
Rafael J. Wysockicbbc0de2010-02-24 00:52:08 +0100341
Alexey Starikovskiy0b7084a2008-10-25 21:48:46 +0400342 flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344 /* Ensure that we have a valid GPE number */
345
Len Brown4be44fc2005-08-05 00:44:28 -0400346 gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 if (!gpe_event_info) {
348 status = AE_BAD_PARAMETER;
349 goto unlock_and_exit;
350 }
351
Lin Ming0f849d22010-04-06 14:52:37 +0800352 if (gpe_type & ACPI_GPE_TYPE_RUNTIME) {
353 if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) {
354 status = AE_LIMIT; /* Too many references */
355 goto unlock_and_exit;
356 }
357
358 gpe_event_info->runtime_count++;
359 if (gpe_event_info->runtime_count == 1) {
Rafael J. Wysockifd247442010-06-08 10:49:08 +0200360 status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
361 if (ACPI_SUCCESS(status)) {
362 status = acpi_clear_and_enable_gpe(gpe_event_info);
363 }
364
Lin Ming0f849d22010-04-06 14:52:37 +0800365 if (ACPI_FAILURE(status)) {
Rafael J. Wysockicbbc0de2010-02-24 00:52:08 +0100366 gpe_event_info->runtime_count--;
Lin Ming0f849d22010-04-06 14:52:37 +0800367 goto unlock_and_exit;
368 }
Rafael J. Wysockicbbc0de2010-02-24 00:52:08 +0100369 }
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Lin Ming0f849d22010-04-06 14:52:37 +0800372 if (gpe_type & ACPI_GPE_TYPE_WAKE) {
373 /* The GPE must have the ability to wake the system */
374
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100375 if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
Lin Ming0f849d22010-04-06 14:52:37 +0800376 status = AE_TYPE;
377 goto unlock_and_exit;
378 }
379
380 if (gpe_event_info->wakeup_count == ACPI_UINT8_MAX) {
381 status = AE_LIMIT; /* Too many references */
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100382 goto unlock_and_exit;
383 }
384
385 /*
Lin Ming0f849d22010-04-06 14:52:37 +0800386 * Update the enable mask on the first wakeup reference. Wake GPEs
387 * are only hardware-enabled just before sleeping.
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100388 */
Lin Ming0f849d22010-04-06 14:52:37 +0800389 gpe_event_info->wakeup_count++;
390 if (gpe_event_info->wakeup_count == 1) {
Rafael J. Wysockifd247442010-06-08 10:49:08 +0200391 status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
Lin Ming0f849d22010-04-06 14:52:37 +0800392 }
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100393 }
394
395unlock_and_exit:
Alexey Starikovskiy0b7084a2008-10-25 21:48:46 +0400396 acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
Len Brown4be44fc2005-08-05 00:44:28 -0400397 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398}
Bob Moore83135242006-10-03 00:00:00 -0400399ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
401/*******************************************************************************
402 *
403 * FUNCTION: acpi_disable_gpe
404 *
Lin Ming0f849d22010-04-06 14:52:37 +0800405 * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 * gpe_number - GPE level within the GPE block
Lin Ming0f849d22010-04-06 14:52:37 +0800407 * gpe_type - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
408 * or both
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 *
410 * RETURN: Status
411 *
Lin Ming0f849d22010-04-06 14:52:37 +0800412 * DESCRIPTION: Remove a reference to a GPE. When the last reference is
413 * removed, only then is the GPE disabled (for runtime GPEs), or
414 * the GPE mask bit disabled (for wake GPEs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 *
416 ******************************************************************************/
Lin Ming0f849d22010-04-06 14:52:37 +0800417acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418{
Len Brown4be44fc2005-08-05 00:44:28 -0400419 acpi_status status = AE_OK;
420 struct acpi_gpe_event_info *gpe_event_info;
Lin Ming0f849d22010-04-06 14:52:37 +0800421 acpi_cpu_flags flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
Bob Mooreb229cf92006-04-21 17:15:00 -0400423 ACPI_FUNCTION_TRACE(acpi_disable_gpe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
Lin Ming0f849d22010-04-06 14:52:37 +0800425 /* Parameter validation */
426
427 if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) {
Rafael J. Wysockicbbc0de2010-02-24 00:52:08 +0100428 return_ACPI_STATUS(AE_BAD_PARAMETER);
Lin Ming0f849d22010-04-06 14:52:37 +0800429 }
Rafael J. Wysockicbbc0de2010-02-24 00:52:08 +0100430
Alexey Starikovskiy0b7084a2008-10-25 21:48:46 +0400431 flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
Lin Ming0f849d22010-04-06 14:52:37 +0800432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 /* Ensure that we have a valid GPE number */
434
Len Brown4be44fc2005-08-05 00:44:28 -0400435 gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 if (!gpe_event_info) {
437 status = AE_BAD_PARAMETER;
438 goto unlock_and_exit;
439 }
440
Lin Ming0f849d22010-04-06 14:52:37 +0800441 /* Hardware-disable a runtime GPE on removal of the last reference */
442
443 if (gpe_type & ACPI_GPE_TYPE_RUNTIME) {
444 if (!gpe_event_info->runtime_count) {
445 status = AE_LIMIT; /* There are no references to remove */
446 goto unlock_and_exit;
447 }
448
449 gpe_event_info->runtime_count--;
450 if (!gpe_event_info->runtime_count) {
Rafael J. Wysockifd247442010-06-08 10:49:08 +0200451 status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
452 if (ACPI_SUCCESS(status)) {
453 status = acpi_hw_low_set_gpe(gpe_event_info,
454 ACPI_GPE_DISABLE);
455 }
456
Lin Ming0f849d22010-04-06 14:52:37 +0800457 if (ACPI_FAILURE(status)) {
458 gpe_event_info->runtime_count++;
459 goto unlock_and_exit;
460 }
461 }
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100462 }
463
Lin Ming0f849d22010-04-06 14:52:37 +0800464 /*
465 * Update masks for wake GPE on removal of the last reference.
466 * No need to hardware-disable wake GPEs here, they are not currently
467 * enabled.
468 */
469 if (gpe_type & ACPI_GPE_TYPE_WAKE) {
470 if (!gpe_event_info->wakeup_count) {
471 status = AE_LIMIT; /* There are no references to remove */
472 goto unlock_and_exit;
473 }
474
475 gpe_event_info->wakeup_count--;
476 if (!gpe_event_info->wakeup_count) {
Rafael J. Wysockifd247442010-06-08 10:49:08 +0200477 status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
Lin Ming0f849d22010-04-06 14:52:37 +0800478 }
Rafael J. Wysocki9630bdd2010-02-17 23:41:07 +0100479 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
Alexey Starikovskiy0b7084a2008-10-25 21:48:46 +0400481unlock_and_exit:
482 acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
Len Brown4be44fc2005-08-05 00:44:28 -0400483 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484}
Bob Moore83135242006-10-03 00:00:00 -0400485ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487/*******************************************************************************
488 *
489 * FUNCTION: acpi_disable_event
490 *
491 * PARAMETERS: Event - The fixed eventto be enabled
492 * Flags - Reserved
493 *
494 * RETURN: Status
495 *
496 * DESCRIPTION: Disable an ACPI event (fixed)
497 *
498 ******************************************************************************/
Len Brown4be44fc2005-08-05 00:44:28 -0400499acpi_status acpi_disable_event(u32 event, u32 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
Len Brown4be44fc2005-08-05 00:44:28 -0400501 acpi_status status = AE_OK;
502 u32 value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
Bob Mooreb229cf92006-04-21 17:15:00 -0400504 ACPI_FUNCTION_TRACE(acpi_disable_event);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
506 /* Decode the Fixed Event */
507
508 if (event > ACPI_EVENT_MAX) {
Len Brown4be44fc2005-08-05 00:44:28 -0400509 return_ACPI_STATUS(AE_BAD_PARAMETER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 }
511
512 /*
Bob Moore9f15fc62008-11-12 16:01:56 +0800513 * Disable the requested fixed event (by writing a zero to the enable
514 * register bit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 */
Len Brown4be44fc2005-08-05 00:44:28 -0400516 status =
Bob Moore50ffba12009-02-23 15:02:07 +0800517 acpi_write_bit_register(acpi_gbl_fixed_event_info[event].
Bob Moore768aaaf2009-03-06 09:49:25 +0800518 enable_register_id, ACPI_DISABLE_EVENT);
Len Brown4be44fc2005-08-05 00:44:28 -0400519 if (ACPI_FAILURE(status)) {
520 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 }
522
Len Brown4be44fc2005-08-05 00:44:28 -0400523 status =
Bob Moore50ffba12009-02-23 15:02:07 +0800524 acpi_read_bit_register(acpi_gbl_fixed_event_info[event].
525 enable_register_id, &value);
Len Brown4be44fc2005-08-05 00:44:28 -0400526 if (ACPI_FAILURE(status)) {
527 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 }
529
530 if (value != 0) {
Bob Mooreb8e4d892006-01-27 16:43:00 -0500531 ACPI_ERROR((AE_INFO,
532 "Could not disable %s events",
533 acpi_ut_get_event_name(event)));
Len Brown4be44fc2005-08-05 00:44:28 -0400534 return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 }
536
Len Brown4be44fc2005-08-05 00:44:28 -0400537 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
Bob Moore83135242006-10-03 00:00:00 -0400540ACPI_EXPORT_SYMBOL(acpi_disable_event)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
542/*******************************************************************************
543 *
544 * FUNCTION: acpi_clear_event
545 *
546 * PARAMETERS: Event - The fixed event to be cleared
547 *
548 * RETURN: Status
549 *
550 * DESCRIPTION: Clear an ACPI event (fixed)
551 *
552 ******************************************************************************/
Len Brown4be44fc2005-08-05 00:44:28 -0400553acpi_status acpi_clear_event(u32 event)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554{
Len Brown4be44fc2005-08-05 00:44:28 -0400555 acpi_status status = AE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
Bob Mooreb229cf92006-04-21 17:15:00 -0400557 ACPI_FUNCTION_TRACE(acpi_clear_event);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
559 /* Decode the Fixed Event */
560
561 if (event > ACPI_EVENT_MAX) {
Len Brown4be44fc2005-08-05 00:44:28 -0400562 return_ACPI_STATUS(AE_BAD_PARAMETER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 }
564
565 /*
Bob Moore9f15fc62008-11-12 16:01:56 +0800566 * Clear the requested fixed event (By writing a one to the status
567 * register bit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 */
Len Brown4be44fc2005-08-05 00:44:28 -0400569 status =
Bob Moore50ffba12009-02-23 15:02:07 +0800570 acpi_write_bit_register(acpi_gbl_fixed_event_info[event].
Bob Moore768aaaf2009-03-06 09:49:25 +0800571 status_register_id, ACPI_CLEAR_STATUS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
Len Brown4be44fc2005-08-05 00:44:28 -0400573 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
Bob Moore83135242006-10-03 00:00:00 -0400576ACPI_EXPORT_SYMBOL(acpi_clear_event)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
578/*******************************************************************************
579 *
580 * FUNCTION: acpi_clear_gpe
581 *
Lin Ming0f849d22010-04-06 14:52:37 +0800582 * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 * gpe_number - GPE level within the GPE block
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 *
585 * RETURN: Status
586 *
587 * DESCRIPTION: Clear an ACPI event (general purpose)
588 *
589 ******************************************************************************/
Lin Ming0f849d22010-04-06 14:52:37 +0800590acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591{
Len Brown4be44fc2005-08-05 00:44:28 -0400592 acpi_status status = AE_OK;
593 struct acpi_gpe_event_info *gpe_event_info;
Lin Ming0f849d22010-04-06 14:52:37 +0800594 acpi_cpu_flags flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Bob Mooreb229cf92006-04-21 17:15:00 -0400596 ACPI_FUNCTION_TRACE(acpi_clear_gpe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
Lin Ming0f849d22010-04-06 14:52:37 +0800598 flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
600 /* Ensure that we have a valid GPE number */
601
Len Brown4be44fc2005-08-05 00:44:28 -0400602 gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 if (!gpe_event_info) {
604 status = AE_BAD_PARAMETER;
605 goto unlock_and_exit;
606 }
607
Len Brown4be44fc2005-08-05 00:44:28 -0400608 status = acpi_hw_clear_gpe(gpe_event_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
Len Brown4be44fc2005-08-05 00:44:28 -0400610 unlock_and_exit:
Lin Ming0f849d22010-04-06 14:52:37 +0800611 acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
Len Brown4be44fc2005-08-05 00:44:28 -0400612 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613}
614
Bob Moore83135242006-10-03 00:00:00 -0400615ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616/*******************************************************************************
617 *
618 * FUNCTION: acpi_get_event_status
619 *
620 * PARAMETERS: Event - The fixed event
Robert Moore44f6c012005-04-18 22:49:35 -0400621 * event_status - Where the current status of the event will
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 * be returned
623 *
624 * RETURN: Status
625 *
626 * DESCRIPTION: Obtains and returns the current status of the event
627 *
628 ******************************************************************************/
Len Brown4be44fc2005-08-05 00:44:28 -0400629acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
Len Brown4be44fc2005-08-05 00:44:28 -0400631 acpi_status status = AE_OK;
Zhang Rui71b58cb2008-06-20 09:42:47 +0800632 u32 value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
Bob Mooreb229cf92006-04-21 17:15:00 -0400634 ACPI_FUNCTION_TRACE(acpi_get_event_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
636 if (!event_status) {
Len Brown4be44fc2005-08-05 00:44:28 -0400637 return_ACPI_STATUS(AE_BAD_PARAMETER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 }
639
640 /* Decode the Fixed Event */
641
642 if (event > ACPI_EVENT_MAX) {
Len Brown4be44fc2005-08-05 00:44:28 -0400643 return_ACPI_STATUS(AE_BAD_PARAMETER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 }
645
646 /* Get the status of the requested fixed event */
647
Len Brown4be44fc2005-08-05 00:44:28 -0400648 status =
Bob Moore50ffba12009-02-23 15:02:07 +0800649 acpi_read_bit_register(acpi_gbl_fixed_event_info[event].
Zhang Rui71b58cb2008-06-20 09:42:47 +0800650 enable_register_id, &value);
651 if (ACPI_FAILURE(status))
652 return_ACPI_STATUS(status);
653
654 *event_status = value;
655
656 status =
Bob Moore50ffba12009-02-23 15:02:07 +0800657 acpi_read_bit_register(acpi_gbl_fixed_event_info[event].
Zhang Rui71b58cb2008-06-20 09:42:47 +0800658 status_register_id, &value);
659 if (ACPI_FAILURE(status))
660 return_ACPI_STATUS(status);
661
662 if (value)
663 *event_status |= ACPI_EVENT_FLAG_SET;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
Zhang Ruied206fa2008-10-27 14:01:02 -0700665 if (acpi_gbl_fixed_event_handlers[event].handler)
666 *event_status |= ACPI_EVENT_FLAG_HANDLE;
667
Len Brown4be44fc2005-08-05 00:44:28 -0400668 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669}
670
Bob Moore83135242006-10-03 00:00:00 -0400671ACPI_EXPORT_SYMBOL(acpi_get_event_status)
672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673/*******************************************************************************
674 *
675 * FUNCTION: acpi_get_gpe_status
676 *
Lin Ming0f849d22010-04-06 14:52:37 +0800677 * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 * gpe_number - GPE level within the GPE block
Robert Moore44f6c012005-04-18 22:49:35 -0400679 * event_status - Where the current status of the event will
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 * be returned
681 *
682 * RETURN: Status
683 *
684 * DESCRIPTION: Get status of an event (general purpose)
685 *
686 ******************************************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400688acpi_get_gpe_status(acpi_handle gpe_device,
Lin Ming0f849d22010-04-06 14:52:37 +0800689 u32 gpe_number, acpi_event_status *event_status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
Len Brown4be44fc2005-08-05 00:44:28 -0400691 acpi_status status = AE_OK;
692 struct acpi_gpe_event_info *gpe_event_info;
Lin Ming0f849d22010-04-06 14:52:37 +0800693 acpi_cpu_flags flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
Bob Mooreb229cf92006-04-21 17:15:00 -0400695 ACPI_FUNCTION_TRACE(acpi_get_gpe_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
Lin Ming0f849d22010-04-06 14:52:37 +0800697 flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699 /* Ensure that we have a valid GPE number */
700
Len Brown4be44fc2005-08-05 00:44:28 -0400701 gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 if (!gpe_event_info) {
703 status = AE_BAD_PARAMETER;
704 goto unlock_and_exit;
705 }
706
707 /* Obtain status on the requested GPE number */
708
Len Brown4be44fc2005-08-05 00:44:28 -0400709 status = acpi_hw_get_gpe_status(gpe_event_info, event_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
Zhang Ruied206fa2008-10-27 14:01:02 -0700711 if (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)
712 *event_status |= ACPI_EVENT_FLAG_HANDLE;
713
Len Brown4be44fc2005-08-05 00:44:28 -0400714 unlock_and_exit:
Lin Ming0f849d22010-04-06 14:52:37 +0800715 acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
Len Brown4be44fc2005-08-05 00:44:28 -0400716 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717}
Bob Moore83135242006-10-03 00:00:00 -0400718
719ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720/*******************************************************************************
721 *
722 * FUNCTION: acpi_install_gpe_block
723 *
724 * PARAMETERS: gpe_device - Handle to the parent GPE Block Device
725 * gpe_block_address - Address and space_iD
726 * register_count - Number of GPE register pairs in the block
Robert Moore6f42ccf2005-05-13 00:00:00 -0400727 * interrupt_number - H/W interrupt for the block
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 *
729 * RETURN: Status
730 *
731 * DESCRIPTION: Create and Install a block of GPE registers
732 *
733 ******************************************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400735acpi_install_gpe_block(acpi_handle gpe_device,
736 struct acpi_generic_address *gpe_block_address,
737 u32 register_count, u32 interrupt_number)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738{
Len Brown4be44fc2005-08-05 00:44:28 -0400739 acpi_status status;
740 union acpi_operand_object *obj_desc;
741 struct acpi_namespace_node *node;
742 struct acpi_gpe_block_info *gpe_block;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Bob Mooreb229cf92006-04-21 17:15:00 -0400744 ACPI_FUNCTION_TRACE(acpi_install_gpe_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Len Brown4be44fc2005-08-05 00:44:28 -0400746 if ((!gpe_device) || (!gpe_block_address) || (!register_count)) {
747 return_ACPI_STATUS(AE_BAD_PARAMETER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 }
749
Len Brown4be44fc2005-08-05 00:44:28 -0400750 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
751 if (ACPI_FAILURE(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 return (status);
753 }
754
Bob Mooref24b6642009-12-11 14:57:00 +0800755 node = acpi_ns_validate_handle(gpe_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 if (!node) {
757 status = AE_BAD_PARAMETER;
758 goto unlock_and_exit;
759 }
760
761 /*
762 * For user-installed GPE Block Devices, the gpe_block_base_number
763 * is always zero
764 */
Len Brown4be44fc2005-08-05 00:44:28 -0400765 status =
766 acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0,
767 interrupt_number, &gpe_block);
768 if (ACPI_FAILURE(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 goto unlock_and_exit;
770 }
771
Lin Ming0f849d22010-04-06 14:52:37 +0800772 /* Install block in the device_object attached to the node */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
Len Brown4be44fc2005-08-05 00:44:28 -0400774 obj_desc = acpi_ns_get_attached_object(node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 if (!obj_desc) {
Bob Moore52fc0b02006-10-02 00:00:00 -0400776
Lin Ming0f849d22010-04-06 14:52:37 +0800777 /*
778 * No object, create a new one (Device nodes do not always have
779 * an attached object)
780 */
Len Brown4be44fc2005-08-05 00:44:28 -0400781 obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (!obj_desc) {
783 status = AE_NO_MEMORY;
784 goto unlock_and_exit;
785 }
786
Len Brown4be44fc2005-08-05 00:44:28 -0400787 status =
788 acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_DEVICE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
790 /* Remove local reference to the object */
791
Len Brown4be44fc2005-08-05 00:44:28 -0400792 acpi_ut_remove_reference(obj_desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
Len Brown4be44fc2005-08-05 00:44:28 -0400794 if (ACPI_FAILURE(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 goto unlock_and_exit;
796 }
797 }
798
Lin Ming0f849d22010-04-06 14:52:37 +0800799 /* Now install the GPE block in the device_object */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
801 obj_desc->device.gpe_block = gpe_block;
802
Lin Ming0f849d22010-04-06 14:52:37 +0800803 /* Run the _PRW methods and enable the runtime GPEs in the new block */
804
805 status = acpi_ev_initialize_gpe_block(node, gpe_block);
806
Len Brown4be44fc2005-08-05 00:44:28 -0400807 unlock_and_exit:
808 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
809 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Bob Moore83135242006-10-03 00:00:00 -0400812ACPI_EXPORT_SYMBOL(acpi_install_gpe_block)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
814/*******************************************************************************
815 *
816 * FUNCTION: acpi_remove_gpe_block
817 *
818 * PARAMETERS: gpe_device - Handle to the parent GPE Block Device
819 *
820 * RETURN: Status
821 *
822 * DESCRIPTION: Remove a previously installed block of GPE registers
823 *
824 ******************************************************************************/
Len Brown4be44fc2005-08-05 00:44:28 -0400825acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826{
Len Brown4be44fc2005-08-05 00:44:28 -0400827 union acpi_operand_object *obj_desc;
828 acpi_status status;
829 struct acpi_namespace_node *node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
Bob Mooreb229cf92006-04-21 17:15:00 -0400831 ACPI_FUNCTION_TRACE(acpi_remove_gpe_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833 if (!gpe_device) {
Len Brown4be44fc2005-08-05 00:44:28 -0400834 return_ACPI_STATUS(AE_BAD_PARAMETER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 }
836
Len Brown4be44fc2005-08-05 00:44:28 -0400837 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
838 if (ACPI_FAILURE(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 return (status);
840 }
841
Bob Mooref24b6642009-12-11 14:57:00 +0800842 node = acpi_ns_validate_handle(gpe_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 if (!node) {
844 status = AE_BAD_PARAMETER;
845 goto unlock_and_exit;
846 }
847
848 /* Get the device_object attached to the node */
849
Len Brown4be44fc2005-08-05 00:44:28 -0400850 obj_desc = acpi_ns_get_attached_object(node);
851 if (!obj_desc || !obj_desc->device.gpe_block) {
852 return_ACPI_STATUS(AE_NULL_OBJECT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 }
854
855 /* Delete the GPE block (but not the device_object) */
856
Len Brown4be44fc2005-08-05 00:44:28 -0400857 status = acpi_ev_delete_gpe_block(obj_desc->device.gpe_block);
858 if (ACPI_SUCCESS(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 obj_desc->device.gpe_block = NULL;
860 }
861
Len Brown4be44fc2005-08-05 00:44:28 -0400862 unlock_and_exit:
863 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
864 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865}
Robert Moore44f6c012005-04-18 22:49:35 -0400866
Bob Moore83135242006-10-03 00:00:00 -0400867ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block)
Bob Mooree97d6bf2008-12-30 09:45:17 +0800868
869/*******************************************************************************
870 *
871 * FUNCTION: acpi_get_gpe_device
872 *
873 * PARAMETERS: Index - System GPE index (0-current_gpe_count)
874 * gpe_device - Where the parent GPE Device is returned
875 *
876 * RETURN: Status
877 *
878 * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL
879 * gpe device indicates that the gpe number is contained in one of
880 * the FADT-defined gpe blocks. Otherwise, the GPE block device.
881 *
882 ******************************************************************************/
883acpi_status
884acpi_get_gpe_device(u32 index, acpi_handle *gpe_device)
885{
886 struct acpi_gpe_device_info info;
887 acpi_status status;
888
889 ACPI_FUNCTION_TRACE(acpi_get_gpe_device);
890
891 if (!gpe_device) {
892 return_ACPI_STATUS(AE_BAD_PARAMETER);
893 }
894
895 if (index >= acpi_current_gpe_count) {
896 return_ACPI_STATUS(AE_NOT_EXIST);
897 }
898
899 /* Setup and walk the GPE list */
900
901 info.index = index;
902 info.status = AE_NOT_EXIST;
903 info.gpe_device = NULL;
904 info.next_block_base_index = 0;
905
906 status = acpi_ev_walk_gpe_list(acpi_ev_get_gpe_device, &info);
907 if (ACPI_FAILURE(status)) {
908 return_ACPI_STATUS(status);
909 }
910
911 *gpe_device = info.gpe_device;
912 return_ACPI_STATUS(info.status);
913}
914
915ACPI_EXPORT_SYMBOL(acpi_get_gpe_device)
916
917/*******************************************************************************
918 *
919 * FUNCTION: acpi_ev_get_gpe_device
920 *
921 * PARAMETERS: GPE_WALK_CALLBACK
922 *
923 * RETURN: Status
924 *
925 * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE
926 * block device. NULL if the GPE is one of the FADT-defined GPEs.
927 *
928 ******************************************************************************/
Bob Mooree4c1ebf2009-04-22 13:02:06 +0800929static acpi_status
Bob Mooree97d6bf2008-12-30 09:45:17 +0800930acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
931 struct acpi_gpe_block_info *gpe_block, void *context)
932{
933 struct acpi_gpe_device_info *info = context;
934
935 /* Increment Index by the number of GPEs in this block */
936
Lin Ming0f849d22010-04-06 14:52:37 +0800937 info->next_block_base_index += gpe_block->gpe_count;
Bob Mooree97d6bf2008-12-30 09:45:17 +0800938
939 if (info->index < info->next_block_base_index) {
940 /*
941 * The GPE index is within this block, get the node. Leave the node
942 * NULL for the FADT-defined GPEs
943 */
944 if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) {
945 info->gpe_device = gpe_block->node;
946 }
947
948 info->status = AE_OK;
949 return (AE_CTRL_END);
950 }
951
952 return (AE_OK);
953}
Bob Moore08ac07b2008-12-30 09:55:48 +0800954
955/******************************************************************************
956 *
957 * FUNCTION: acpi_disable_all_gpes
958 *
959 * PARAMETERS: None
960 *
961 * RETURN: Status
962 *
963 * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
964 *
965 ******************************************************************************/
966
967acpi_status acpi_disable_all_gpes(void)
968{
969 acpi_status status;
970
971 ACPI_FUNCTION_TRACE(acpi_disable_all_gpes);
972
973 status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
974 if (ACPI_FAILURE(status)) {
975 return_ACPI_STATUS(status);
976 }
977
978 status = acpi_hw_disable_all_gpes();
979 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
980
981 return_ACPI_STATUS(status);
982}
983
984/******************************************************************************
985 *
986 * FUNCTION: acpi_enable_all_runtime_gpes
987 *
988 * PARAMETERS: None
989 *
990 * RETURN: Status
991 *
992 * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
993 *
994 ******************************************************************************/
995
996acpi_status acpi_enable_all_runtime_gpes(void)
997{
998 acpi_status status;
999
1000 ACPI_FUNCTION_TRACE(acpi_enable_all_runtime_gpes);
1001
1002 status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
1003 if (ACPI_FAILURE(status)) {
1004 return_ACPI_STATUS(status);
1005 }
1006
1007 status = acpi_hw_enable_all_runtime_gpes();
1008 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
1009
1010 return_ACPI_STATUS(status);
1011}