diff options
| -rw-r--r-- | arch/ia64/include/asm/acpi.h | 6 | ||||
| -rw-r--r-- | arch/ia64/kernel/acpi.c | 14 | ||||
| -rw-r--r-- | arch/x86/include/asm/acpi.h | 5 | ||||
| -rw-r--r-- | arch/x86/kernel/acpi/sleep.c | 13 | ||||
| -rw-r--r-- | arch/x86/kernel/acpi/sleep.h | 2 | ||||
| -rw-r--r-- | drivers/acpi/acpica/aclocal.h | 7 | ||||
| -rw-r--r-- | drivers/acpi/acpica/evgpe.c | 17 | ||||
| -rw-r--r-- | drivers/acpi/acpica/evxfgpe.c | 42 | ||||
| -rw-r--r-- | drivers/acpi/button.c | 11 | ||||
| -rw-r--r-- | drivers/acpi/debugfs.c | 20 | ||||
| -rw-r--r-- | drivers/acpi/nvs.c | 22 | ||||
| -rw-r--r-- | drivers/acpi/osl.c | 112 | ||||
| -rw-r--r-- | drivers/acpi/scan.c | 1 | ||||
| -rw-r--r-- | drivers/acpi/sleep.c | 28 | ||||
| -rw-r--r-- | drivers/pci/pci-acpi.c | 16 | ||||
| -rw-r--r-- | include/acpi/acpi_bus.h | 1 | ||||
| -rw-r--r-- | include/linux/acpi_io.h | 3 |
17 files changed, 178 insertions, 142 deletions
diff --git a/arch/ia64/include/asm/acpi.h b/arch/ia64/include/asm/acpi.h index 837dc82a013e..a06dfb13d518 100644 --- a/arch/ia64/include/asm/acpi.h +++ b/arch/ia64/include/asm/acpi.h | |||
| @@ -128,9 +128,9 @@ static inline const char *acpi_get_sysname (void) | |||
| 128 | int acpi_request_vector (u32 int_type); | 128 | int acpi_request_vector (u32 int_type); |
| 129 | int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); | 129 | int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); |
| 130 | 130 | ||
| 131 | /* routines for saving/restoring kernel state */ | 131 | /* Low-level suspend routine. */ |
| 132 | extern int acpi_save_state_mem(void); | 132 | extern int acpi_suspend_lowlevel(void); |
| 133 | extern void acpi_restore_state_mem(void); | 133 | |
| 134 | extern unsigned long acpi_wakeup_address; | 134 | extern unsigned long acpi_wakeup_address; |
| 135 | 135 | ||
| 136 | /* | 136 | /* |
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 90ebceb899a0..a54d054ed4b0 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c | |||
| @@ -1034,18 +1034,8 @@ int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base) | |||
| 1034 | EXPORT_SYMBOL(acpi_unregister_ioapic); | 1034 | EXPORT_SYMBOL(acpi_unregister_ioapic); |
| 1035 | 1035 | ||
| 1036 | /* | 1036 | /* |
| 1037 | * acpi_save_state_mem() - save kernel state | 1037 | * acpi_suspend_lowlevel() - save kernel state and suspend. |
| 1038 | * | 1038 | * |
| 1039 | * TBD when when IA64 starts to support suspend... | 1039 | * TBD when when IA64 starts to support suspend... |
| 1040 | */ | 1040 | */ |
| 1041 | int acpi_save_state_mem(void) { return 0; } | 1041 | int acpi_suspend_lowlevel(void) { return 0; } |
| 1042 | |||
| 1043 | /* | ||
| 1044 | * acpi_restore_state() | ||
| 1045 | */ | ||
| 1046 | void acpi_restore_state_mem(void) {} | ||
| 1047 | |||
| 1048 | /* | ||
| 1049 | * do_suspend_lowlevel() | ||
| 1050 | */ | ||
| 1051 | void do_suspend_lowlevel(void) {} | ||
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index 211ca3f7fd16..aa92684aa674 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h | |||
| @@ -112,9 +112,8 @@ static inline void acpi_disable_pci(void) | |||
| 112 | acpi_noirq_set(); | 112 | acpi_noirq_set(); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | /* routines for saving/restoring kernel state */ | 115 | /* Low-level suspend routine. */ |
| 116 | extern int acpi_save_state_mem(void); | 116 | extern int acpi_suspend_lowlevel(void); |
| 117 | extern void acpi_restore_state_mem(void); | ||
| 118 | 117 | ||
| 119 | extern unsigned long acpi_wakeup_address; | 118 | extern unsigned long acpi_wakeup_address; |
| 120 | 119 | ||
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 68d1537b8c81..5f1b747f6ef1 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c | |||
| @@ -29,14 +29,14 @@ static char temp_stack[4096]; | |||
| 29 | #endif | 29 | #endif |
| 30 | 30 | ||
| 31 | /** | 31 | /** |
| 32 | * acpi_save_state_mem - save kernel state | 32 | * acpi_suspend_lowlevel - save kernel state |
| 33 | * | 33 | * |
| 34 | * Create an identity mapped page table and copy the wakeup routine to | 34 | * Create an identity mapped page table and copy the wakeup routine to |
| 35 | * low memory. | 35 | * low memory. |
| 36 | * | 36 | * |
| 37 | * Note that this is too late to change acpi_wakeup_address. | 37 | * Note that this is too late to change acpi_wakeup_address. |
| 38 | */ | 38 | */ |
| 39 | int acpi_save_state_mem(void) | 39 | int acpi_suspend_lowlevel(void) |
| 40 | { | 40 | { |
| 41 | struct wakeup_header *header; | 41 | struct wakeup_header *header; |
| 42 | 42 | ||
| @@ -107,17 +107,10 @@ int acpi_save_state_mem(void) | |||
| 107 | saved_magic = 0x123456789abcdef0L; | 107 | saved_magic = 0x123456789abcdef0L; |
| 108 | #endif /* CONFIG_64BIT */ | 108 | #endif /* CONFIG_64BIT */ |
| 109 | 109 | ||
| 110 | do_suspend_lowlevel(); | ||
| 110 | return 0; | 111 | return 0; |
| 111 | } | 112 | } |
| 112 | 113 | ||
| 113 | /* | ||
| 114 | * acpi_restore_state - undo effects of acpi_save_state_mem | ||
| 115 | */ | ||
| 116 | void acpi_restore_state_mem(void) | ||
| 117 | { | ||
| 118 | } | ||
| 119 | |||
| 120 | |||
| 121 | /** | 114 | /** |
| 122 | * acpi_reserve_wakeup_memory - do _very_ early ACPI initialisation | 115 | * acpi_reserve_wakeup_memory - do _very_ early ACPI initialisation |
| 123 | * | 116 | * |
diff --git a/arch/x86/kernel/acpi/sleep.h b/arch/x86/kernel/acpi/sleep.h index adbcbaa6f1df..31ce13f20297 100644 --- a/arch/x86/kernel/acpi/sleep.h +++ b/arch/x86/kernel/acpi/sleep.h | |||
| @@ -14,3 +14,5 @@ extern char swsusp_pg_dir[PAGE_SIZE]; | |||
| 14 | 14 | ||
| 15 | extern unsigned long acpi_copy_wakeup_routine(unsigned long); | 15 | extern unsigned long acpi_copy_wakeup_routine(unsigned long); |
| 16 | extern void wakeup_long64(void); | 16 | extern void wakeup_long64(void); |
| 17 | |||
| 18 | extern void do_suspend_lowlevel(void); | ||
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 54784bb42cec..edc25867ad9d 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h | |||
| @@ -416,10 +416,15 @@ struct acpi_gpe_handler_info { | |||
| 416 | u8 originally_enabled; /* True if GPE was originally enabled */ | 416 | u8 originally_enabled; /* True if GPE was originally enabled */ |
| 417 | }; | 417 | }; |
| 418 | 418 | ||
| 419 | struct acpi_gpe_notify_object { | ||
| 420 | struct acpi_namespace_node *node; | ||
| 421 | struct acpi_gpe_notify_object *next; | ||
| 422 | }; | ||
| 423 | |||
| 419 | union acpi_gpe_dispatch_info { | 424 | union acpi_gpe_dispatch_info { |
| 420 | struct acpi_namespace_node *method_node; /* Method node for this GPE level */ | 425 | struct acpi_namespace_node *method_node; /* Method node for this GPE level */ |
| 421 | struct acpi_gpe_handler_info *handler; /* Installed GPE handler */ | 426 | struct acpi_gpe_handler_info *handler; /* Installed GPE handler */ |
| 422 | struct acpi_namespace_node *device_node; /* Parent _PRW device for implicit notify */ | 427 | struct acpi_gpe_notify_object device; /* List of _PRW devices for implicit notify */ |
| 423 | }; | 428 | }; |
| 424 | 429 | ||
| 425 | /* | 430 | /* |
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 14988a86066f..f4725212eb48 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c | |||
| @@ -457,6 +457,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | |||
| 457 | acpi_status status; | 457 | acpi_status status; |
| 458 | struct acpi_gpe_event_info *local_gpe_event_info; | 458 | struct acpi_gpe_event_info *local_gpe_event_info; |
| 459 | struct acpi_evaluate_info *info; | 459 | struct acpi_evaluate_info *info; |
| 460 | struct acpi_gpe_notify_object *notify_object; | ||
| 460 | 461 | ||
| 461 | ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); | 462 | ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); |
| 462 | 463 | ||
| @@ -508,10 +509,18 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | |||
| 508 | * from this thread -- because handlers may in turn run other | 509 | * from this thread -- because handlers may in turn run other |
| 509 | * control methods. | 510 | * control methods. |
| 510 | */ | 511 | */ |
| 511 | status = | 512 | status = acpi_ev_queue_notify_request( |
| 512 | acpi_ev_queue_notify_request(local_gpe_event_info->dispatch. | 513 | local_gpe_event_info->dispatch.device.node, |
| 513 | device_node, | 514 | ACPI_NOTIFY_DEVICE_WAKE); |
| 514 | ACPI_NOTIFY_DEVICE_WAKE); | 515 | |
| 516 | notify_object = local_gpe_event_info->dispatch.device.next; | ||
| 517 | while (ACPI_SUCCESS(status) && notify_object) { | ||
| 518 | status = acpi_ev_queue_notify_request( | ||
| 519 | notify_object->node, | ||
| 520 | ACPI_NOTIFY_DEVICE_WAKE); | ||
| 521 | notify_object = notify_object->next; | ||
| 522 | } | ||
| 523 | |||
| 515 | break; | 524 | break; |
| 516 | 525 | ||
| 517 | case ACPI_GPE_DISPATCH_METHOD: | 526 | case ACPI_GPE_DISPATCH_METHOD: |
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 3b20a3401b64..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 | ||
| @@ -221,27 +223,49 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, | |||
| 221 | goto unlock_and_exit; | 223 | goto unlock_and_exit; |
| 222 | } | 224 | } |
| 223 | 225 | ||
| 226 | if (wake_device == ACPI_ROOT_OBJECT) { | ||
| 227 | goto out; | ||
| 228 | } | ||
| 229 | |||
| 224 | /* | 230 | /* |
| 225 | * If there is no method or handler for this GPE, then the | 231 | * If there is no method or handler for this GPE, then the |
| 226 | * wake_device will be notified whenever this GPE fires (aka | 232 | * wake_device will be notified whenever this GPE fires (aka |
| 227 | * "implicit notify") Note: The GPE is assumed to be | 233 | * "implicit notify") Note: The GPE is assumed to be |
| 228 | * level-triggered (for windows compatibility). | 234 | * level-triggered (for windows compatibility). |
| 229 | */ | 235 | */ |
| 230 | if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == | 236 | gpe_dispatch_mask = gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK; |
| 231 | ACPI_GPE_DISPATCH_NONE) && (wake_device != ACPI_ROOT_OBJECT)) { | 237 | if (gpe_dispatch_mask != ACPI_GPE_DISPATCH_NONE |
| 238 | && gpe_dispatch_mask != ACPI_GPE_DISPATCH_NOTIFY) { | ||
| 239 | goto out; | ||
| 240 | } | ||
| 232 | 241 | ||
| 233 | /* Validate wake_device is of type Device */ | 242 | /* Validate wake_device is of type Device */ |
| 234 | 243 | ||
| 235 | device_node = ACPI_CAST_PTR(struct acpi_namespace_node, | 244 | device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); |
| 236 | wake_device); | 245 | if (device_node->type != ACPI_TYPE_DEVICE) { |
| 237 | if (device_node->type != ACPI_TYPE_DEVICE) { | 246 | goto unlock_and_exit; |
| 238 | goto unlock_and_exit; | 247 | } |
| 239 | } | 248 | |
| 249 | if (gpe_dispatch_mask == ACPI_GPE_DISPATCH_NONE) { | ||
| 240 | gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY | | 250 | gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY | |
| 241 | ACPI_GPE_LEVEL_TRIGGERED); | 251 | ACPI_GPE_LEVEL_TRIGGERED); |
| 242 | gpe_event_info->dispatch.device_node = device_node; | 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. */ | ||
| 256 | |||
| 257 | notify_object = ACPI_ALLOCATE_ZEROED(sizeof(*notify_object)); | ||
| 258 | if (!notify_object) { | ||
| 259 | status = AE_NO_MEMORY; | ||
| 260 | goto unlock_and_exit; | ||
| 261 | } | ||
| 262 | |||
| 263 | notify_object->node = device_node; | ||
| 264 | notify_object->next = gpe_event_info->dispatch.device.next; | ||
| 265 | gpe_event_info->dispatch.device.next = notify_object; | ||
| 243 | } | 266 | } |
| 244 | 267 | ||
| 268 | out: | ||
| 245 | gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; | 269 | gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; |
| 246 | status = AE_OK; | 270 | status = AE_OK; |
| 247 | 271 | ||
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 76bbb78a5ad9..12c28f4adb67 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c | |||
| @@ -98,6 +98,7 @@ struct acpi_button { | |||
| 98 | struct input_dev *input; | 98 | struct input_dev *input; |
| 99 | char phys[32]; /* for input device */ | 99 | char phys[32]; /* for input device */ |
| 100 | unsigned long pushed; | 100 | unsigned long pushed; |
| 101 | bool wakeup_enabled; | ||
| 101 | }; | 102 | }; |
| 102 | 103 | ||
| 103 | static const struct file_operations acpi_button_info_fops = { | 104 | static const struct file_operations acpi_button_info_fops = { |
| @@ -430,8 +431,10 @@ static int acpi_button_add(struct acpi_device *device) | |||
| 430 | /* Button's GPE is run-wake GPE */ | 431 | /* Button's GPE is run-wake GPE */ |
| 431 | acpi_enable_gpe(device->wakeup.gpe_device, | 432 | acpi_enable_gpe(device->wakeup.gpe_device, |
| 432 | device->wakeup.gpe_number); | 433 | device->wakeup.gpe_number); |
| 433 | device->wakeup.run_wake_count++; | 434 | if (!device_may_wakeup(&device->dev)) { |
| 434 | device_set_wakeup_enable(&device->dev, true); | 435 | device_set_wakeup_enable(&device->dev, true); |
| 436 | button->wakeup_enabled = true; | ||
| 437 | } | ||
| 435 | } | 438 | } |
| 436 | 439 | ||
| 437 | printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); | 440 | printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); |
| @@ -453,8 +456,8 @@ static int acpi_button_remove(struct acpi_device *device, int type) | |||
| 453 | if (device->wakeup.flags.valid) { | 456 | if (device->wakeup.flags.valid) { |
| 454 | acpi_disable_gpe(device->wakeup.gpe_device, | 457 | acpi_disable_gpe(device->wakeup.gpe_device, |
| 455 | device->wakeup.gpe_number); | 458 | device->wakeup.gpe_number); |
| 456 | device->wakeup.run_wake_count--; | 459 | if (button->wakeup_enabled) |
| 457 | device_set_wakeup_enable(&device->dev, false); | 460 | device_set_wakeup_enable(&device->dev, false); |
| 458 | } | 461 | } |
| 459 | 462 | ||
| 460 | acpi_button_remove_fs(device); | 463 | acpi_button_remove_fs(device); |
diff --git a/drivers/acpi/debugfs.c b/drivers/acpi/debugfs.c index 5df67f1d6c61..384f7abcff77 100644 --- a/drivers/acpi/debugfs.c +++ b/drivers/acpi/debugfs.c | |||
| @@ -26,7 +26,9 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, | |||
| 26 | size_t count, loff_t *ppos) | 26 | size_t count, loff_t *ppos) |
| 27 | { | 27 | { |
| 28 | static char *buf; | 28 | static char *buf; |
| 29 | static int uncopied_bytes; | 29 | static u32 max_size; |
| 30 | static u32 uncopied_bytes; | ||
| 31 | |||
| 30 | struct acpi_table_header table; | 32 | struct acpi_table_header table; |
| 31 | acpi_status status; | 33 | acpi_status status; |
| 32 | 34 | ||
| @@ -37,19 +39,24 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, | |||
| 37 | if (copy_from_user(&table, user_buf, | 39 | if (copy_from_user(&table, user_buf, |
| 38 | sizeof(struct acpi_table_header))) | 40 | sizeof(struct acpi_table_header))) |
| 39 | return -EFAULT; | 41 | return -EFAULT; |
| 40 | uncopied_bytes = table.length; | 42 | uncopied_bytes = max_size = table.length; |
| 41 | buf = kzalloc(uncopied_bytes, GFP_KERNEL); | 43 | buf = kzalloc(max_size, GFP_KERNEL); |
| 42 | if (!buf) | 44 | if (!buf) |
| 43 | return -ENOMEM; | 45 | return -ENOMEM; |
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | if (uncopied_bytes < count) { | 48 | if (buf == NULL) |
| 47 | kfree(buf); | 49 | return -EINVAL; |
| 50 | |||
| 51 | if ((*ppos > max_size) || | ||
| 52 | (*ppos + count > max_size) || | ||
| 53 | (*ppos + count < count) || | ||
| 54 | (count > uncopied_bytes)) | ||
| 48 | return -EINVAL; | 55 | return -EINVAL; |
| 49 | } | ||
| 50 | 56 | ||
| 51 | if (copy_from_user(buf + (*ppos), user_buf, count)) { | 57 | if (copy_from_user(buf + (*ppos), user_buf, count)) { |
| 52 | kfree(buf); | 58 | kfree(buf); |
| 59 | buf = NULL; | ||
| 53 | return -EFAULT; | 60 | return -EFAULT; |
| 54 | } | 61 | } |
| 55 | 62 | ||
| @@ -59,6 +66,7 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, | |||
| 59 | if (!uncopied_bytes) { | 66 | if (!uncopied_bytes) { |
| 60 | status = acpi_install_method(buf); | 67 | status = acpi_install_method(buf); |
| 61 | kfree(buf); | 68 | kfree(buf); |
| 69 | buf = NULL; | ||
| 62 | if (ACPI_FAILURE(status)) | 70 | if (ACPI_FAILURE(status)) |
| 63 | return -EINVAL; | 71 | return -EINVAL; |
| 64 | add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); | 72 | add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); |
diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index fa5a1df42b79..096787b43c96 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c | |||
| @@ -26,6 +26,7 @@ struct nvs_page { | |||
| 26 | unsigned int size; | 26 | unsigned int size; |
| 27 | void *kaddr; | 27 | void *kaddr; |
| 28 | void *data; | 28 | void *data; |
| 29 | bool unmap; | ||
| 29 | struct list_head node; | 30 | struct list_head node; |
| 30 | }; | 31 | }; |
| 31 | 32 | ||
| @@ -44,6 +45,9 @@ int suspend_nvs_register(unsigned long start, unsigned long size) | |||
| 44 | { | 45 | { |
| 45 | struct nvs_page *entry, *next; | 46 | struct nvs_page *entry, *next; |
| 46 | 47 | ||
| 48 | pr_info("PM: Registering ACPI NVS region at %lx (%ld bytes)\n", | ||
| 49 | start, size); | ||
| 50 | |||
| 47 | while (size > 0) { | 51 | while (size > 0) { |
| 48 | unsigned int nr_bytes; | 52 | unsigned int nr_bytes; |
| 49 | 53 | ||
| @@ -81,7 +85,13 @@ void suspend_nvs_free(void) | |||
| 81 | free_page((unsigned long)entry->data); | 85 | free_page((unsigned long)entry->data); |
| 82 | entry->data = NULL; | 86 | entry->data = NULL; |
| 83 | if (entry->kaddr) { | 87 | if (entry->kaddr) { |
| 84 | iounmap(entry->kaddr); | 88 | if (entry->unmap) { |
| 89 | iounmap(entry->kaddr); | ||
| 90 | entry->unmap = false; | ||
| 91 | } else { | ||
| 92 | acpi_os_unmap_memory(entry->kaddr, | ||
| 93 | entry->size); | ||
| 94 | } | ||
| 85 | entry->kaddr = NULL; | 95 | entry->kaddr = NULL; |
| 86 | } | 96 | } |
| 87 | } | 97 | } |
| @@ -115,8 +125,14 @@ int suspend_nvs_save(void) | |||
| 115 | 125 | ||
| 116 | list_for_each_entry(entry, &nvs_list, node) | 126 | list_for_each_entry(entry, &nvs_list, node) |
| 117 | if (entry->data) { | 127 | if (entry->data) { |
| 118 | entry->kaddr = acpi_os_ioremap(entry->phys_start, | 128 | unsigned long phys = entry->phys_start; |
| 119 | entry->size); | 129 | unsigned int size = entry->size; |
| 130 | |||
| 131 | entry->kaddr = acpi_os_get_iomem(phys, size); | ||
| 132 | if (!entry->kaddr) { | ||
| 133 | entry->kaddr = acpi_os_ioremap(phys, size); | ||
| 134 | entry->unmap = !!entry->kaddr; | ||
| 135 | } | ||
| 120 | if (!entry->kaddr) { | 136 | if (!entry->kaddr) { |
| 121 | suspend_nvs_free(); | 137 | suspend_nvs_free(); |
| 122 | return -ENOMEM; | 138 | return -ENOMEM; |
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 187dff96356b..45c6ac8790d7 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
| @@ -104,11 +104,11 @@ struct acpi_ioremap { | |||
| 104 | void __iomem *virt; | 104 | void __iomem *virt; |
| 105 | acpi_physical_address phys; | 105 | acpi_physical_address phys; |
| 106 | acpi_size size; | 106 | acpi_size size; |
| 107 | struct kref ref; | 107 | unsigned long refcount; |
| 108 | }; | 108 | }; |
| 109 | 109 | ||
| 110 | static LIST_HEAD(acpi_ioremaps); | 110 | static LIST_HEAD(acpi_ioremaps); |
| 111 | static DEFINE_SPINLOCK(acpi_ioremap_lock); | 111 | static DEFINE_MUTEX(acpi_ioremap_lock); |
| 112 | 112 | ||
| 113 | static void __init acpi_osi_setup_late(void); | 113 | static void __init acpi_osi_setup_late(void); |
| 114 | 114 | ||
| @@ -284,6 +284,22 @@ acpi_map_vaddr_lookup(acpi_physical_address phys, unsigned int size) | |||
| 284 | return NULL; | 284 | return NULL; |
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size) | ||
| 288 | { | ||
| 289 | struct acpi_ioremap *map; | ||
| 290 | void __iomem *virt = NULL; | ||
| 291 | |||
| 292 | mutex_lock(&acpi_ioremap_lock); | ||
| 293 | map = acpi_map_lookup(phys, size); | ||
| 294 | if (map) { | ||
| 295 | virt = map->virt + (phys - map->phys); | ||
| 296 | map->refcount++; | ||
| 297 | } | ||
| 298 | mutex_unlock(&acpi_ioremap_lock); | ||
| 299 | return virt; | ||
| 300 | } | ||
| 301 | EXPORT_SYMBOL_GPL(acpi_os_get_iomem); | ||
| 302 | |||
| 287 | /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ | 303 | /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ |
| 288 | static struct acpi_ioremap * | 304 | static struct acpi_ioremap * |
| 289 | acpi_map_lookup_virt(void __iomem *virt, acpi_size size) | 305 | acpi_map_lookup_virt(void __iomem *virt, acpi_size size) |
| @@ -301,8 +317,7 @@ acpi_map_lookup_virt(void __iomem *virt, acpi_size size) | |||
| 301 | void __iomem *__init_refok | 317 | void __iomem *__init_refok |
| 302 | acpi_os_map_memory(acpi_physical_address phys, acpi_size size) | 318 | acpi_os_map_memory(acpi_physical_address phys, acpi_size size) |
| 303 | { | 319 | { |
| 304 | struct acpi_ioremap *map, *tmp_map; | 320 | struct acpi_ioremap *map; |
| 305 | unsigned long flags; | ||
| 306 | void __iomem *virt; | 321 | void __iomem *virt; |
| 307 | acpi_physical_address pg_off; | 322 | acpi_physical_address pg_off; |
| 308 | acpi_size pg_sz; | 323 | acpi_size pg_sz; |
| @@ -315,14 +330,25 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size) | |||
| 315 | if (!acpi_gbl_permanent_mmap) | 330 | if (!acpi_gbl_permanent_mmap) |
| 316 | return __acpi_map_table((unsigned long)phys, size); | 331 | return __acpi_map_table((unsigned long)phys, size); |
| 317 | 332 | ||
| 333 | mutex_lock(&acpi_ioremap_lock); | ||
| 334 | /* Check if there's a suitable mapping already. */ | ||
| 335 | map = acpi_map_lookup(phys, size); | ||
| 336 | if (map) { | ||
| 337 | map->refcount++; | ||
| 338 | goto out; | ||
| 339 | } | ||
| 340 | |||
| 318 | map = kzalloc(sizeof(*map), GFP_KERNEL); | 341 | map = kzalloc(sizeof(*map), GFP_KERNEL); |
| 319 | if (!map) | 342 | if (!map) { |
| 343 | mutex_unlock(&acpi_ioremap_lock); | ||
| 320 | return NULL; | 344 | return NULL; |
| 345 | } | ||
| 321 | 346 | ||
| 322 | pg_off = round_down(phys, PAGE_SIZE); | 347 | pg_off = round_down(phys, PAGE_SIZE); |
| 323 | pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; | 348 | pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; |
| 324 | virt = acpi_os_ioremap(pg_off, pg_sz); | 349 | virt = acpi_os_ioremap(pg_off, pg_sz); |
| 325 | if (!virt) { | 350 | if (!virt) { |
| 351 | mutex_unlock(&acpi_ioremap_lock); | ||
| 326 | kfree(map); | 352 | kfree(map); |
| 327 | return NULL; | 353 | return NULL; |
| 328 | } | 354 | } |
| @@ -331,62 +357,51 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size) | |||
| 331 | map->virt = virt; | 357 | map->virt = virt; |
| 332 | map->phys = pg_off; | 358 | map->phys = pg_off; |
| 333 | map->size = pg_sz; | 359 | map->size = pg_sz; |
| 334 | kref_init(&map->ref); | 360 | map->refcount = 1; |
| 335 | 361 | ||
| 336 | spin_lock_irqsave(&acpi_ioremap_lock, flags); | ||
| 337 | /* Check if page has already been mapped. */ | ||
| 338 | tmp_map = acpi_map_lookup(phys, size); | ||
| 339 | if (tmp_map) { | ||
| 340 | kref_get(&tmp_map->ref); | ||
| 341 | spin_unlock_irqrestore(&acpi_ioremap_lock, flags); | ||
| 342 | iounmap(map->virt); | ||
| 343 | kfree(map); | ||
| 344 | return tmp_map->virt + (phys - tmp_map->phys); | ||
| 345 | } | ||
| 346 | list_add_tail_rcu(&map->list, &acpi_ioremaps); | 362 | list_add_tail_rcu(&map->list, &acpi_ioremaps); |
| 347 | spin_unlock_irqrestore(&acpi_ioremap_lock, flags); | ||
| 348 | 363 | ||
| 364 | out: | ||
| 365 | mutex_unlock(&acpi_ioremap_lock); | ||
| 349 | return map->virt + (phys - map->phys); | 366 | return map->virt + (phys - map->phys); |
| 350 | } | 367 | } |
| 351 | EXPORT_SYMBOL_GPL(acpi_os_map_memory); | 368 | EXPORT_SYMBOL_GPL(acpi_os_map_memory); |
| 352 | 369 | ||
| 353 | static void acpi_kref_del_iomap(struct kref *ref) | 370 | static void acpi_os_drop_map_ref(struct acpi_ioremap *map) |
| 354 | { | 371 | { |
| 355 | struct acpi_ioremap *map; | 372 | if (!--map->refcount) |
| 373 | list_del_rcu(&map->list); | ||
| 374 | } | ||
| 356 | 375 | ||
| 357 | map = container_of(ref, struct acpi_ioremap, ref); | 376 | static void acpi_os_map_cleanup(struct acpi_ioremap *map) |
| 358 | list_del_rcu(&map->list); | 377 | { |
| 378 | if (!map->refcount) { | ||
| 379 | synchronize_rcu(); | ||
| 380 | iounmap(map->virt); | ||
| 381 | kfree(map); | ||
| 382 | } | ||
| 359 | } | 383 | } |
| 360 | 384 | ||
| 361 | void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) | 385 | void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) |
| 362 | { | 386 | { |
| 363 | struct acpi_ioremap *map; | 387 | struct acpi_ioremap *map; |
| 364 | unsigned long flags; | ||
| 365 | int del; | ||
| 366 | 388 | ||
| 367 | if (!acpi_gbl_permanent_mmap) { | 389 | if (!acpi_gbl_permanent_mmap) { |
| 368 | __acpi_unmap_table(virt, size); | 390 | __acpi_unmap_table(virt, size); |
| 369 | return; | 391 | return; |
| 370 | } | 392 | } |
| 371 | 393 | ||
| 372 | spin_lock_irqsave(&acpi_ioremap_lock, flags); | 394 | mutex_lock(&acpi_ioremap_lock); |
| 373 | map = acpi_map_lookup_virt(virt, size); | 395 | map = acpi_map_lookup_virt(virt, size); |
| 374 | if (!map) { | 396 | if (!map) { |
| 375 | spin_unlock_irqrestore(&acpi_ioremap_lock, flags); | 397 | mutex_unlock(&acpi_ioremap_lock); |
| 376 | printk(KERN_ERR PREFIX "%s: bad address %p\n", __func__, virt); | 398 | WARN(true, PREFIX "%s: bad address %p\n", __func__, virt); |
| 377 | dump_stack(); | ||
| 378 | return; | 399 | return; |
| 379 | } | 400 | } |
| 401 | acpi_os_drop_map_ref(map); | ||
| 402 | mutex_unlock(&acpi_ioremap_lock); | ||
| 380 | 403 | ||
| 381 | del = kref_put(&map->ref, acpi_kref_del_iomap); | 404 | acpi_os_map_cleanup(map); |
| 382 | spin_unlock_irqrestore(&acpi_ioremap_lock, flags); | ||
| 383 | |||
| 384 | if (!del) | ||
| 385 | return; | ||
| 386 | |||
| 387 | synchronize_rcu(); | ||
| 388 | iounmap(map->virt); | ||
| 389 | kfree(map); | ||
| 390 | } | 405 | } |
| 391 | EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); | 406 | EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); |
| 392 | 407 | ||
| @@ -396,7 +411,7 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) | |||
| 396 | __acpi_unmap_table(virt, size); | 411 | __acpi_unmap_table(virt, size); |
| 397 | } | 412 | } |
| 398 | 413 | ||
| 399 | int acpi_os_map_generic_address(struct acpi_generic_address *addr) | 414 | static int acpi_os_map_generic_address(struct acpi_generic_address *addr) |
| 400 | { | 415 | { |
| 401 | void __iomem *virt; | 416 | void __iomem *virt; |
| 402 | 417 | ||
| @@ -412,13 +427,10 @@ int acpi_os_map_generic_address(struct acpi_generic_address *addr) | |||
| 412 | 427 | ||
| 413 | return 0; | 428 | return 0; |
| 414 | } | 429 | } |
| 415 | EXPORT_SYMBOL_GPL(acpi_os_map_generic_address); | ||
| 416 | 430 | ||
| 417 | void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) | 431 | static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) |
| 418 | { | 432 | { |
| 419 | void __iomem *virt; | 433 | struct acpi_ioremap *map; |
| 420 | unsigned long flags; | ||
| 421 | acpi_size size = addr->bit_width / 8; | ||
| 422 | 434 | ||
| 423 | if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) | 435 | if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) |
| 424 | return; | 436 | return; |
| @@ -426,13 +438,17 @@ void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) | |||
| 426 | if (!addr->address || !addr->bit_width) | 438 | if (!addr->address || !addr->bit_width) |
| 427 | return; | 439 | return; |
| 428 | 440 | ||
| 429 | spin_lock_irqsave(&acpi_ioremap_lock, flags); | 441 | mutex_lock(&acpi_ioremap_lock); |
| 430 | virt = acpi_map_vaddr_lookup(addr->address, size); | 442 | map = acpi_map_lookup(addr->address, addr->bit_width / 8); |
| 431 | spin_unlock_irqrestore(&acpi_ioremap_lock, flags); | 443 | if (!map) { |
| 444 | mutex_unlock(&acpi_ioremap_lock); | ||
| 445 | return; | ||
| 446 | } | ||
| 447 | acpi_os_drop_map_ref(map); | ||
| 448 | mutex_unlock(&acpi_ioremap_lock); | ||
| 432 | 449 | ||
| 433 | acpi_os_unmap_memory(virt, size); | 450 | acpi_os_map_cleanup(map); |
| 434 | } | 451 | } |
| 435 | EXPORT_SYMBOL_GPL(acpi_os_unmap_generic_address); | ||
| 436 | 452 | ||
| 437 | #ifdef ACPI_FUTURE_USAGE | 453 | #ifdef ACPI_FUTURE_USAGE |
| 438 | acpi_status | 454 | acpi_status |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b99e62494607..b136c9c1e531 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
| @@ -797,7 +797,6 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) | |||
| 797 | acpi_status status; | 797 | acpi_status status; |
| 798 | acpi_event_status event_status; | 798 | acpi_event_status event_status; |
| 799 | 799 | ||
| 800 | device->wakeup.run_wake_count = 0; | ||
| 801 | device->wakeup.flags.notifier_present = 0; | 800 | device->wakeup.flags.notifier_present = 0; |
| 802 | 801 | ||
| 803 | /* Power button, Lid switch always enable wakeup */ | 802 | /* Power button, Lid switch always enable wakeup */ |
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index d6a8cd14de2e..84f57143ad7c 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
| @@ -199,8 +199,6 @@ static void acpi_pm_end(void) | |||
| 199 | #endif /* CONFIG_ACPI_SLEEP */ | 199 | #endif /* CONFIG_ACPI_SLEEP */ |
| 200 | 200 | ||
| 201 | #ifdef CONFIG_SUSPEND | 201 | #ifdef CONFIG_SUSPEND |
| 202 | extern void do_suspend_lowlevel(void); | ||
| 203 | |||
| 204 | static u32 acpi_suspend_states[] = { | 202 | static u32 acpi_suspend_states[] = { |
| 205 | [PM_SUSPEND_ON] = ACPI_STATE_S0, | 203 | [PM_SUSPEND_ON] = ACPI_STATE_S0, |
| 206 | [PM_SUSPEND_STANDBY] = ACPI_STATE_S1, | 204 | [PM_SUSPEND_STANDBY] = ACPI_STATE_S1, |
| @@ -243,20 +241,11 @@ static int acpi_suspend_begin(suspend_state_t pm_state) | |||
| 243 | static int acpi_suspend_enter(suspend_state_t pm_state) | 241 | static int acpi_suspend_enter(suspend_state_t pm_state) |
| 244 | { | 242 | { |
| 245 | acpi_status status = AE_OK; | 243 | acpi_status status = AE_OK; |
| 246 | unsigned long flags = 0; | ||
| 247 | u32 acpi_state = acpi_target_sleep_state; | 244 | u32 acpi_state = acpi_target_sleep_state; |
| 245 | int error; | ||
| 248 | 246 | ||
| 249 | ACPI_FLUSH_CPU_CACHE(); | 247 | ACPI_FLUSH_CPU_CACHE(); |
| 250 | 248 | ||
| 251 | /* Do arch specific saving of state. */ | ||
| 252 | if (acpi_state == ACPI_STATE_S3) { | ||
| 253 | int error = acpi_save_state_mem(); | ||
| 254 | |||
| 255 | if (error) | ||
| 256 | return error; | ||
| 257 | } | ||
| 258 | |||
| 259 | local_irq_save(flags); | ||
| 260 | switch (acpi_state) { | 249 | switch (acpi_state) { |
| 261 | case ACPI_STATE_S1: | 250 | case ACPI_STATE_S1: |
| 262 | barrier(); | 251 | barrier(); |
| @@ -264,7 +253,10 @@ static int acpi_suspend_enter(suspend_state_t pm_state) | |||
| 264 | break; | 253 | break; |
| 265 | 254 | ||
| 266 | case ACPI_STATE_S3: | 255 | case ACPI_STATE_S3: |
| 267 | do_suspend_lowlevel(); | 256 | error = acpi_suspend_lowlevel(); |
| 257 | if (error) | ||
| 258 | return error; | ||
| 259 | pr_info(PREFIX "Low-level resume complete\n"); | ||
| 268 | break; | 260 | break; |
| 269 | } | 261 | } |
| 270 | 262 | ||
| @@ -290,13 +282,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state) | |||
| 290 | /* Allow EC transactions to happen. */ | 282 | /* Allow EC transactions to happen. */ |
| 291 | acpi_ec_unblock_transactions_early(); | 283 | acpi_ec_unblock_transactions_early(); |
| 292 | 284 | ||
| 293 | local_irq_restore(flags); | ||
| 294 | printk(KERN_DEBUG "Back to C!\n"); | ||
| 295 | |||
| 296 | /* restore processor state */ | ||
| 297 | if (acpi_state == ACPI_STATE_S3) | ||
| 298 | acpi_restore_state_mem(); | ||
| 299 | |||
| 300 | suspend_nvs_restore(); | 285 | suspend_nvs_restore(); |
| 301 | 286 | ||
| 302 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; | 287 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; |
| @@ -472,16 +457,13 @@ static int acpi_hibernation_begin(void) | |||
| 472 | static int acpi_hibernation_enter(void) | 457 | static int acpi_hibernation_enter(void) |
| 473 | { | 458 | { |
| 474 | acpi_status status = AE_OK; | 459 | acpi_status status = AE_OK; |
| 475 | unsigned long flags = 0; | ||
| 476 | 460 | ||
| 477 | ACPI_FLUSH_CPU_CACHE(); | 461 | ACPI_FLUSH_CPU_CACHE(); |
| 478 | 462 | ||
| 479 | local_irq_save(flags); | ||
| 480 | /* This shouldn't return. If it returns, we have a problem */ | 463 | /* This shouldn't return. If it returns, we have a problem */ |
| 481 | status = acpi_enter_sleep_state(ACPI_STATE_S4); | 464 | status = acpi_enter_sleep_state(ACPI_STATE_S4); |
| 482 | /* Reprogram control registers and execute _BFS */ | 465 | /* Reprogram control registers and execute _BFS */ |
| 483 | acpi_leave_sleep_state_prep(ACPI_STATE_S4); | 466 | acpi_leave_sleep_state_prep(ACPI_STATE_S4); |
| 484 | local_irq_restore(flags); | ||
| 485 | 467 | ||
| 486 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; | 468 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; |
| 487 | } | 469 | } |
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 6fe0772e0e7d..7c3b18e78cee 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
| @@ -293,19 +293,11 @@ static int acpi_dev_run_wake(struct device *phys_dev, bool enable) | |||
| 293 | } | 293 | } |
| 294 | 294 | ||
| 295 | if (enable) { | 295 | if (enable) { |
| 296 | if (!dev->wakeup.run_wake_count++) { | 296 | acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); |
| 297 | acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); | 297 | acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); |
| 298 | acpi_enable_gpe(dev->wakeup.gpe_device, | ||
| 299 | dev->wakeup.gpe_number); | ||
| 300 | } | ||
| 301 | } else if (dev->wakeup.run_wake_count > 0) { | ||
| 302 | if (!--dev->wakeup.run_wake_count) { | ||
| 303 | acpi_disable_gpe(dev->wakeup.gpe_device, | ||
| 304 | dev->wakeup.gpe_number); | ||
| 305 | acpi_disable_wakeup_device_power(dev); | ||
| 306 | } | ||
| 307 | } else { | 298 | } else { |
| 308 | error = -EALREADY; | 299 | acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); |
| 300 | acpi_disable_wakeup_device_power(dev); | ||
| 309 | } | 301 | } |
| 310 | 302 | ||
| 311 | return error; | 303 | return error; |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 78ca429929f7..f50ebb9bc53b 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
| @@ -250,7 +250,6 @@ struct acpi_device_wakeup { | |||
| 250 | struct acpi_handle_list resources; | 250 | struct acpi_handle_list resources; |
| 251 | struct acpi_device_wakeup_flags flags; | 251 | struct acpi_device_wakeup_flags flags; |
| 252 | int prepare_count; | 252 | int prepare_count; |
| 253 | int run_wake_count; | ||
| 254 | }; | 253 | }; |
| 255 | 254 | ||
| 256 | /* Device */ | 255 | /* Device */ |
diff --git a/include/linux/acpi_io.h b/include/linux/acpi_io.h index 7180013a4a3a..4afd7102459d 100644 --- a/include/linux/acpi_io.h +++ b/include/linux/acpi_io.h | |||
| @@ -10,7 +10,6 @@ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, | |||
| 10 | return ioremap_cache(phys, size); | 10 | return ioremap_cache(phys, size); |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | int acpi_os_map_generic_address(struct acpi_generic_address *addr); | 13 | void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size); |
| 14 | void acpi_os_unmap_generic_address(struct acpi_generic_address *addr); | ||
| 15 | 14 | ||
| 16 | #endif | 15 | #endif |
