diff options
author | Len Brown <len.brown@intel.com> | 2008-10-22 23:25:26 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-10-22 23:25:26 -0400 |
commit | 47bf31adc541bef0c20de15e800e0011f1ae70c7 (patch) | |
tree | 28903879a8570eaefa57942ec3d475d365f5a465 /drivers/ata | |
parent | 4538fad56ee1c16bce0294b5647d2551f0e03164 (diff) | |
parent | 0a918a9432cc30aede10f904253b66ea6ab485ac (diff) |
Merge branch 'dock' into test
Conflicts:
drivers/acpi/osl.c
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-acpi.c | 135 |
1 files changed, 48 insertions, 87 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 9330b7922f62..c012307d0ba6 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c | |||
@@ -120,21 +120,6 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) | |||
120 | ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; | 120 | ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; |
121 | } | 121 | } |
122 | 122 | ||
123 | static void ata_acpi_eject_device(acpi_handle handle) | ||
124 | { | ||
125 | struct acpi_object_list arg_list; | ||
126 | union acpi_object arg; | ||
127 | |||
128 | arg_list.count = 1; | ||
129 | arg_list.pointer = &arg; | ||
130 | arg.type = ACPI_TYPE_INTEGER; | ||
131 | arg.integer.value = 1; | ||
132 | |||
133 | if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0", | ||
134 | &arg_list, NULL))) | ||
135 | printk(KERN_ERR "Failed to evaluate _EJ0!\n"); | ||
136 | } | ||
137 | |||
138 | /* @ap and @dev are the same as ata_acpi_handle_hotplug() */ | 123 | /* @ap and @dev are the same as ata_acpi_handle_hotplug() */ |
139 | static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) | 124 | static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) |
140 | { | 125 | { |
@@ -157,7 +142,6 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) | |||
157 | * @ap: ATA port ACPI event occurred | 142 | * @ap: ATA port ACPI event occurred |
158 | * @dev: ATA device ACPI event occurred (can be NULL) | 143 | * @dev: ATA device ACPI event occurred (can be NULL) |
159 | * @event: ACPI event which occurred | 144 | * @event: ACPI event which occurred |
160 | * @is_dock_event: boolean indicating whether the event was a dock one | ||
161 | * | 145 | * |
162 | * All ACPI bay / device realted events end up in this function. If | 146 | * All ACPI bay / device realted events end up in this function. If |
163 | * the event is port-wide @dev is NULL. If the event is specific to a | 147 | * the event is port-wide @dev is NULL. If the event is specific to a |
@@ -171,117 +155,100 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) | |||
171 | * ACPI notify handler context. May sleep. | 155 | * ACPI notify handler context. May sleep. |
172 | */ | 156 | */ |
173 | static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, | 157 | static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, |
174 | u32 event, int is_dock_event) | 158 | u32 event) |
175 | { | 159 | { |
176 | char event_string[12]; | ||
177 | char *envp[] = { event_string, NULL }; | ||
178 | struct ata_eh_info *ehi = &ap->link.eh_info; | 160 | struct ata_eh_info *ehi = &ap->link.eh_info; |
179 | struct kobject *kobj = NULL; | ||
180 | int wait = 0; | 161 | int wait = 0; |
181 | unsigned long flags; | 162 | unsigned long flags; |
182 | acpi_handle handle, tmphandle; | 163 | acpi_handle handle; |
183 | unsigned long sta; | ||
184 | acpi_status status; | ||
185 | 164 | ||
186 | if (dev) { | 165 | if (dev) |
187 | if (dev->sdev) | ||
188 | kobj = &dev->sdev->sdev_gendev.kobj; | ||
189 | handle = dev->acpi_handle; | 166 | handle = dev->acpi_handle; |
190 | } else { | 167 | else |
191 | kobj = &ap->dev->kobj; | ||
192 | handle = ap->acpi_handle; | 168 | handle = ap->acpi_handle; |
193 | } | ||
194 | |||
195 | status = acpi_get_handle(handle, "_EJ0", &tmphandle); | ||
196 | if (ACPI_FAILURE(status)) | ||
197 | /* This device does not support hotplug */ | ||
198 | return; | ||
199 | |||
200 | if (event == ACPI_NOTIFY_BUS_CHECK || | ||
201 | event == ACPI_NOTIFY_DEVICE_CHECK) | ||
202 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); | ||
203 | 169 | ||
204 | spin_lock_irqsave(ap->lock, flags); | 170 | spin_lock_irqsave(ap->lock, flags); |
205 | 171 | /* | |
172 | * When dock driver calls into the routine, it will always use | ||
173 | * ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and | ||
174 | * ACPI_NOTIFY_EJECT_REQUEST for remove | ||
175 | */ | ||
206 | switch (event) { | 176 | switch (event) { |
207 | case ACPI_NOTIFY_BUS_CHECK: | 177 | case ACPI_NOTIFY_BUS_CHECK: |
208 | case ACPI_NOTIFY_DEVICE_CHECK: | 178 | case ACPI_NOTIFY_DEVICE_CHECK: |
209 | ata_ehi_push_desc(ehi, "ACPI event"); | 179 | ata_ehi_push_desc(ehi, "ACPI event"); |
210 | 180 | ||
211 | if (ACPI_FAILURE(status)) { | 181 | ata_ehi_hotplugged(ehi); |
212 | ata_port_printk(ap, KERN_ERR, | 182 | ata_port_freeze(ap); |
213 | "acpi: failed to determine bay status (0x%x)\n", | ||
214 | status); | ||
215 | break; | ||
216 | } | ||
217 | |||
218 | if (sta) { | ||
219 | ata_ehi_hotplugged(ehi); | ||
220 | ata_port_freeze(ap); | ||
221 | } else { | ||
222 | /* The device has gone - unplug it */ | ||
223 | ata_acpi_detach_device(ap, dev); | ||
224 | wait = 1; | ||
225 | } | ||
226 | break; | 183 | break; |
227 | case ACPI_NOTIFY_EJECT_REQUEST: | 184 | case ACPI_NOTIFY_EJECT_REQUEST: |
228 | ata_ehi_push_desc(ehi, "ACPI event"); | 185 | ata_ehi_push_desc(ehi, "ACPI event"); |
229 | 186 | ||
230 | if (!is_dock_event) | ||
231 | break; | ||
232 | |||
233 | /* undock event - immediate unplug */ | ||
234 | ata_acpi_detach_device(ap, dev); | 187 | ata_acpi_detach_device(ap, dev); |
235 | wait = 1; | 188 | wait = 1; |
236 | break; | 189 | break; |
237 | } | 190 | } |
238 | 191 | ||
239 | /* make sure kobj doesn't go away while ap->lock is released */ | ||
240 | kobject_get(kobj); | ||
241 | |||
242 | spin_unlock_irqrestore(ap->lock, flags); | 192 | spin_unlock_irqrestore(ap->lock, flags); |
243 | 193 | ||
244 | if (wait) { | 194 | if (wait) |
245 | ata_port_wait_eh(ap); | 195 | ata_port_wait_eh(ap); |
246 | ata_acpi_eject_device(handle); | ||
247 | } | ||
248 | |||
249 | if (kobj && !is_dock_event) { | ||
250 | sprintf(event_string, "BAY_EVENT=%d", event); | ||
251 | kobject_uevent_env(kobj, KOBJ_CHANGE, envp); | ||
252 | } | ||
253 | |||
254 | kobject_put(kobj); | ||
255 | } | 196 | } |
256 | 197 | ||
257 | static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) | 198 | static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) |
258 | { | 199 | { |
259 | struct ata_device *dev = data; | 200 | struct ata_device *dev = data; |
260 | 201 | ||
261 | ata_acpi_handle_hotplug(dev->link->ap, dev, event, 1); | 202 | ata_acpi_handle_hotplug(dev->link->ap, dev, event); |
262 | } | 203 | } |
263 | 204 | ||
264 | static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) | 205 | static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) |
265 | { | 206 | { |
266 | struct ata_port *ap = data; | 207 | struct ata_port *ap = data; |
267 | 208 | ||
268 | ata_acpi_handle_hotplug(ap, NULL, event, 1); | 209 | ata_acpi_handle_hotplug(ap, NULL, event); |
269 | } | 210 | } |
270 | 211 | ||
271 | static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) | 212 | static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev, |
213 | u32 event) | ||
272 | { | 214 | { |
273 | struct ata_device *dev = data; | 215 | struct kobject *kobj = NULL; |
216 | char event_string[20]; | ||
217 | char *envp[] = { event_string, NULL }; | ||
218 | |||
219 | if (dev) { | ||
220 | if (dev->sdev) | ||
221 | kobj = &dev->sdev->sdev_gendev.kobj; | ||
222 | } else | ||
223 | kobj = &ap->dev->kobj; | ||
274 | 224 | ||
275 | ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0); | 225 | if (kobj) { |
226 | snprintf(event_string, 20, "BAY_EVENT=%d", event); | ||
227 | kobject_uevent_env(kobj, KOBJ_CHANGE, envp); | ||
228 | } | ||
276 | } | 229 | } |
277 | 230 | ||
278 | static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data) | 231 | static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data) |
279 | { | 232 | { |
280 | struct ata_port *ap = data; | 233 | ata_acpi_uevent(data, NULL, event); |
234 | } | ||
281 | 235 | ||
282 | ata_acpi_handle_hotplug(ap, NULL, event, 0); | 236 | static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data) |
237 | { | ||
238 | struct ata_device *dev = data; | ||
239 | ata_acpi_uevent(dev->link->ap, dev, event); | ||
283 | } | 240 | } |
284 | 241 | ||
242 | static struct acpi_dock_ops ata_acpi_dev_dock_ops = { | ||
243 | .handler = ata_acpi_dev_notify_dock, | ||
244 | .uevent = ata_acpi_dev_uevent, | ||
245 | }; | ||
246 | |||
247 | static struct acpi_dock_ops ata_acpi_ap_dock_ops = { | ||
248 | .handler = ata_acpi_ap_notify_dock, | ||
249 | .uevent = ata_acpi_ap_uevent, | ||
250 | }; | ||
251 | |||
285 | /** | 252 | /** |
286 | * ata_acpi_associate - associate ATA host with ACPI objects | 253 | * ata_acpi_associate - associate ATA host with ACPI objects |
287 | * @host: target ATA host | 254 | * @host: target ATA host |
@@ -315,24 +282,18 @@ void ata_acpi_associate(struct ata_host *host) | |||
315 | ata_acpi_associate_ide_port(ap); | 282 | ata_acpi_associate_ide_port(ap); |
316 | 283 | ||
317 | if (ap->acpi_handle) { | 284 | if (ap->acpi_handle) { |
318 | acpi_install_notify_handler(ap->acpi_handle, | ||
319 | ACPI_SYSTEM_NOTIFY, | ||
320 | ata_acpi_ap_notify, ap); | ||
321 | /* we might be on a docking station */ | 285 | /* we might be on a docking station */ |
322 | register_hotplug_dock_device(ap->acpi_handle, | 286 | register_hotplug_dock_device(ap->acpi_handle, |
323 | ata_acpi_ap_notify_dock, ap); | 287 | &ata_acpi_ap_dock_ops, ap); |
324 | } | 288 | } |
325 | 289 | ||
326 | for (j = 0; j < ata_link_max_devices(&ap->link); j++) { | 290 | for (j = 0; j < ata_link_max_devices(&ap->link); j++) { |
327 | struct ata_device *dev = &ap->link.device[j]; | 291 | struct ata_device *dev = &ap->link.device[j]; |
328 | 292 | ||
329 | if (dev->acpi_handle) { | 293 | if (dev->acpi_handle) { |
330 | acpi_install_notify_handler(dev->acpi_handle, | ||
331 | ACPI_SYSTEM_NOTIFY, | ||
332 | ata_acpi_dev_notify, dev); | ||
333 | /* we might be on a docking station */ | 294 | /* we might be on a docking station */ |
334 | register_hotplug_dock_device(dev->acpi_handle, | 295 | register_hotplug_dock_device(dev->acpi_handle, |
335 | ata_acpi_dev_notify_dock, dev); | 296 | &ata_acpi_dev_dock_ops, dev); |
336 | } | 297 | } |
337 | } | 298 | } |
338 | } | 299 | } |