diff options
Diffstat (limited to 'drivers/acpi/acpica/evxfgpe.c')
-rw-r--r-- | drivers/acpi/acpica/evxfgpe.c | 67 |
1 files changed, 47 insertions, 20 deletions
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index e9562a7cb2f9..52aaff3df562 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c | |||
@@ -198,7 +198,9 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, | |||
198 | acpi_status status = AE_BAD_PARAMETER; | 198 | acpi_status status = AE_BAD_PARAMETER; |
199 | struct acpi_gpe_event_info *gpe_event_info; | 199 | struct acpi_gpe_event_info *gpe_event_info; |
200 | struct acpi_namespace_node *device_node; | 200 | struct acpi_namespace_node *device_node; |
201 | struct acpi_gpe_notify_object *notify_object; | ||
201 | acpi_cpu_flags flags; | 202 | acpi_cpu_flags flags; |
203 | u8 gpe_dispatch_mask; | ||
202 | 204 | ||
203 | ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake); | 205 | ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake); |
204 | 206 | ||
@@ -212,37 +214,62 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, | |||
212 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 214 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
213 | } | 215 | } |
214 | 216 | ||
217 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | ||
218 | |||
219 | /* Ensure that we have a valid GPE number */ | ||
220 | |||
221 | gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); | ||
222 | if (!gpe_event_info) { | ||
223 | goto unlock_and_exit; | ||
224 | } | ||
225 | |||
226 | if (wake_device == ACPI_ROOT_OBJECT) { | ||
227 | goto out; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * If there is no method or handler for this GPE, then the | ||
232 | * wake_device will be notified whenever this GPE fires (aka | ||
233 | * "implicit notify") Note: The GPE is assumed to be | ||
234 | * level-triggered (for windows compatibility). | ||
235 | */ | ||
236 | gpe_dispatch_mask = gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK; | ||
237 | if (gpe_dispatch_mask != ACPI_GPE_DISPATCH_NONE | ||
238 | && gpe_dispatch_mask != ACPI_GPE_DISPATCH_NOTIFY) { | ||
239 | goto out; | ||
240 | } | ||
241 | |||
215 | /* Validate wake_device is of type Device */ | 242 | /* Validate wake_device is of type Device */ |
216 | 243 | ||
217 | device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); | 244 | device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); |
218 | if (device_node->type != ACPI_TYPE_DEVICE) { | 245 | if (device_node->type != ACPI_TYPE_DEVICE) { |
219 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 246 | goto unlock_and_exit; |
220 | } | 247 | } |
221 | 248 | ||
222 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | 249 | if (gpe_dispatch_mask == ACPI_GPE_DISPATCH_NONE) { |
250 | gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY | | ||
251 | ACPI_GPE_LEVEL_TRIGGERED); | ||
252 | gpe_event_info->dispatch.device.node = device_node; | ||
253 | gpe_event_info->dispatch.device.next = NULL; | ||
254 | } else { | ||
255 | /* There are multiple devices to notify implicitly. */ | ||
223 | 256 | ||
224 | /* Ensure that we have a valid GPE number */ | 257 | notify_object = ACPI_ALLOCATE_ZEROED(sizeof(*notify_object)); |
225 | 258 | if (!notify_object) { | |
226 | gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); | 259 | status = AE_NO_MEMORY; |
227 | if (gpe_event_info) { | 260 | goto unlock_and_exit; |
228 | /* | ||
229 | * If there is no method or handler for this GPE, then the | ||
230 | * wake_device will be notified whenever this GPE fires (aka | ||
231 | * "implicit notify") Note: The GPE is assumed to be | ||
232 | * level-triggered (for windows compatibility). | ||
233 | */ | ||
234 | if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == | ||
235 | ACPI_GPE_DISPATCH_NONE) { | ||
236 | gpe_event_info->flags = | ||
237 | (ACPI_GPE_DISPATCH_NOTIFY | | ||
238 | ACPI_GPE_LEVEL_TRIGGERED); | ||
239 | gpe_event_info->dispatch.device_node = device_node; | ||
240 | } | 261 | } |
241 | 262 | ||
242 | gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; | 263 | notify_object->node = device_node; |
243 | status = AE_OK; | 264 | notify_object->next = gpe_event_info->dispatch.device.next; |
265 | gpe_event_info->dispatch.device.next = notify_object; | ||
244 | } | 266 | } |
245 | 267 | ||
268 | out: | ||
269 | gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; | ||
270 | status = AE_OK; | ||
271 | |||
272 | unlock_and_exit: | ||
246 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | 273 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
247 | return_ACPI_STATUS(status); | 274 | return_ACPI_STATUS(status); |
248 | } | 275 | } |