diff options
-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); |