diff options
| author | Toshi Kani <toshi.kani@hp.com> | 2012-05-23 22:25:20 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2012-06-04 01:09:19 -0400 |
| commit | c4753e57b78b213f2384fa0dbafa348b087114fa (patch) | |
| tree | 045c893416303dd0a3ea191848597ad401a48e5c | |
| parent | 275c58d77062bbb85dbeb3843ba04f34aa50cf8e (diff) | |
ACPI: Add _OST support for sysfs eject
Changed acpi_bus_hot_remove_device() to support _OST. This function is
also changed to global so that it can be called from hotplug notify
handlers to perform hot-remove operation.
Changed acpi_eject_store(), which is the sysfs eject handler. It checks
eject_pending to see if the request was originated from ACPI eject
notification. If not, it calls _OST(0x103,84,) per Figure 6-37 in ACPI
5.0 spec.
Added eject_pending bit to acpi_device_flags. This bit is set when the
kernel has received an ACPI eject notification, but does not initiate
its hot-remove operation by itself.
Added struct acpi_eject_event. This structure is used to pass extended
information to acpi_bus_hot_remove_device(), which has a single argument
to support asynchronous call
Signed-off-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
| -rw-r--r-- | drivers/acpi/scan.c | 58 | ||||
| -rw-r--r-- | include/acpi/acpi_bus.h | 9 |
2 files changed, 57 insertions, 10 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 85cbfdccc97c..bea3ab6b524f 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
| @@ -83,19 +83,29 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha | |||
| 83 | } | 83 | } |
| 84 | static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); | 84 | static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); |
| 85 | 85 | ||
| 86 | static void acpi_bus_hot_remove_device(void *context) | 86 | /** |
| 87 | * acpi_bus_hot_remove_device: hot-remove a device and its children | ||
| 88 | * @context: struct acpi_eject_event pointer (freed in this func) | ||
| 89 | * | ||
| 90 | * Hot-remove a device and its children. This function frees up the | ||
| 91 | * memory space passed by arg context, so that the caller may call | ||
| 92 | * this function asynchronously through acpi_os_hotplug_execute(). | ||
| 93 | */ | ||
| 94 | void acpi_bus_hot_remove_device(void *context) | ||
| 87 | { | 95 | { |
| 96 | struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context; | ||
| 88 | struct acpi_device *device; | 97 | struct acpi_device *device; |
| 89 | acpi_handle handle = context; | 98 | acpi_handle handle = ej_event->handle; |
| 90 | struct acpi_object_list arg_list; | 99 | struct acpi_object_list arg_list; |
| 91 | union acpi_object arg; | 100 | union acpi_object arg; |
| 92 | acpi_status status = AE_OK; | 101 | acpi_status status = AE_OK; |
| 102 | u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ | ||
| 93 | 103 | ||
| 94 | if (acpi_bus_get_device(handle, &device)) | 104 | if (acpi_bus_get_device(handle, &device)) |
| 95 | return; | 105 | goto err_out; |
| 96 | 106 | ||
| 97 | if (!device) | 107 | if (!device) |
| 98 | return; | 108 | goto err_out; |
| 99 | 109 | ||
| 100 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 110 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
| 101 | "Hot-removing device %s...\n", dev_name(&device->dev))); | 111 | "Hot-removing device %s...\n", dev_name(&device->dev))); |
| @@ -103,7 +113,7 @@ static void acpi_bus_hot_remove_device(void *context) | |||
| 103 | if (acpi_bus_trim(device, 1)) { | 113 | if (acpi_bus_trim(device, 1)) { |
| 104 | printk(KERN_ERR PREFIX | 114 | printk(KERN_ERR PREFIX |
| 105 | "Removing device failed\n"); | 115 | "Removing device failed\n"); |
| 106 | return; | 116 | goto err_out; |
| 107 | } | 117 | } |
| 108 | 118 | ||
| 109 | /* power off device */ | 119 | /* power off device */ |
| @@ -129,10 +139,21 @@ static void acpi_bus_hot_remove_device(void *context) | |||
| 129 | * TBD: _EJD support. | 139 | * TBD: _EJD support. |
| 130 | */ | 140 | */ |
| 131 | status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); | 141 | status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); |
| 132 | if (ACPI_FAILURE(status)) | 142 | if (ACPI_FAILURE(status)) { |
| 133 | printk(KERN_WARNING PREFIX | 143 | if (status != AE_NOT_FOUND) |
| 134 | "Eject device failed\n"); | 144 | printk(KERN_WARNING PREFIX |
| 145 | "Eject device failed\n"); | ||
| 146 | goto err_out; | ||
| 147 | } | ||
| 148 | |||
| 149 | kfree(context); | ||
| 150 | return; | ||
| 135 | 151 | ||
| 152 | err_out: | ||
| 153 | /* Inform firmware the hot-remove operation has completed w/ error */ | ||
| 154 | (void) acpi_evaluate_hotplug_ost(handle, | ||
| 155 | ej_event->event, ost_code, NULL); | ||
| 156 | kfree(context); | ||
| 136 | return; | 157 | return; |
| 137 | } | 158 | } |
| 138 | 159 | ||
| @@ -144,6 +165,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, | |||
| 144 | acpi_status status; | 165 | acpi_status status; |
| 145 | acpi_object_type type = 0; | 166 | acpi_object_type type = 0; |
| 146 | struct acpi_device *acpi_device = to_acpi_device(d); | 167 | struct acpi_device *acpi_device = to_acpi_device(d); |
| 168 | struct acpi_eject_event *ej_event; | ||
| 147 | 169 | ||
| 148 | if ((!count) || (buf[0] != '1')) { | 170 | if ((!count) || (buf[0] != '1')) { |
| 149 | return -EINVAL; | 171 | return -EINVAL; |
| @@ -160,7 +182,25 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, | |||
| 160 | goto err; | 182 | goto err; |
| 161 | } | 183 | } |
| 162 | 184 | ||
| 163 | acpi_os_hotplug_execute(acpi_bus_hot_remove_device, acpi_device->handle); | 185 | ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); |
| 186 | if (!ej_event) { | ||
| 187 | ret = -ENOMEM; | ||
| 188 | goto err; | ||
| 189 | } | ||
| 190 | |||
| 191 | ej_event->handle = acpi_device->handle; | ||
| 192 | if (acpi_device->flags.eject_pending) { | ||
| 193 | /* event originated from ACPI eject notification */ | ||
| 194 | ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; | ||
| 195 | acpi_device->flags.eject_pending = 0; | ||
| 196 | } else { | ||
| 197 | /* event originated from user */ | ||
| 198 | ej_event->event = ACPI_OST_EC_OSPM_EJECT; | ||
| 199 | (void) acpi_evaluate_hotplug_ost(ej_event->handle, | ||
| 200 | ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); | ||
| 201 | } | ||
| 202 | |||
| 203 | acpi_os_hotplug_execute(acpi_bus_hot_remove_device, (void *)ej_event); | ||
| 164 | err: | 204 | err: |
| 165 | return ret; | 205 | return ret; |
| 166 | } | 206 | } |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 1139f3a01209..62eb514f8e3a 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
| @@ -182,7 +182,8 @@ struct acpi_device_flags { | |||
| 182 | u32 suprise_removal_ok:1; | 182 | u32 suprise_removal_ok:1; |
| 183 | u32 power_manageable:1; | 183 | u32 power_manageable:1; |
| 184 | u32 performance_manageable:1; | 184 | u32 performance_manageable:1; |
| 185 | u32 reserved:24; | 185 | u32 eject_pending:1; |
| 186 | u32 reserved:23; | ||
| 186 | }; | 187 | }; |
| 187 | 188 | ||
| 188 | /* File System */ | 189 | /* File System */ |
| @@ -334,6 +335,11 @@ struct acpi_bus_event { | |||
| 334 | u32 data; | 335 | u32 data; |
| 335 | }; | 336 | }; |
| 336 | 337 | ||
| 338 | struct acpi_eject_event { | ||
| 339 | acpi_handle handle; | ||
| 340 | u32 event; | ||
| 341 | }; | ||
| 342 | |||
| 337 | extern struct kobject *acpi_kobj; | 343 | extern struct kobject *acpi_kobj; |
| 338 | extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); | 344 | extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); |
| 339 | void acpi_bus_private_data_handler(acpi_handle, void *); | 345 | void acpi_bus_private_data_handler(acpi_handle, void *); |
| @@ -371,6 +377,7 @@ int acpi_bus_register_driver(struct acpi_driver *driver); | |||
| 371 | void acpi_bus_unregister_driver(struct acpi_driver *driver); | 377 | void acpi_bus_unregister_driver(struct acpi_driver *driver); |
| 372 | int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, | 378 | int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, |
| 373 | acpi_handle handle, int type); | 379 | acpi_handle handle, int type); |
| 380 | void acpi_bus_hot_remove_device(void *context); | ||
| 374 | int acpi_bus_trim(struct acpi_device *start, int rmdevice); | 381 | int acpi_bus_trim(struct acpi_device *start, int rmdevice); |
| 375 | int acpi_bus_start(struct acpi_device *device); | 382 | int acpi_bus_start(struct acpi_device *device); |
| 376 | acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd); | 383 | acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd); |
