diff options
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r-- | drivers/acpi/scan.c | 158 |
1 files changed, 91 insertions, 67 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5b42948ea97f..464746257d8e 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -222,100 +222,124 @@ acpi_eject_store(struct acpi_device *device, const char *buf, size_t count) | |||
222 | /* -------------------------------------------------------------------------- | 222 | /* -------------------------------------------------------------------------- |
223 | ACPI Bus operations | 223 | ACPI Bus operations |
224 | -------------------------------------------------------------------------- */ | 224 | -------------------------------------------------------------------------- */ |
225 | static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state) | 225 | static int acpi_device_suspend(struct device *dev, pm_message_t state) |
226 | { | 226 | { |
227 | struct acpi_device * dev, * next; | 227 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
228 | int result; | 228 | struct acpi_driver *acpi_drv = acpi_dev->driver; |
229 | 229 | ||
230 | spin_lock(&acpi_device_lock); | 230 | if (acpi_drv && acpi_drv->ops.suspend) |
231 | list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) { | 231 | return acpi_drv->ops.suspend(acpi_dev, state); |
232 | if (dev->driver && dev->driver->ops.suspend) { | ||
233 | spin_unlock(&acpi_device_lock); | ||
234 | result = dev->driver->ops.suspend(dev, 0); | ||
235 | if (result) { | ||
236 | printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n", | ||
237 | acpi_device_name(dev), | ||
238 | acpi_device_bid(dev), result); | ||
239 | } | ||
240 | spin_lock(&acpi_device_lock); | ||
241 | } | ||
242 | } | ||
243 | spin_unlock(&acpi_device_lock); | ||
244 | return 0; | 232 | return 0; |
245 | } | 233 | } |
246 | 234 | ||
247 | static int acpi_device_suspend(struct device * dev, pm_message_t state) | 235 | static int acpi_device_resume(struct device *dev) |
248 | { | 236 | { |
249 | struct acpi_device * acpi_dev = to_acpi_device(dev); | 237 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
238 | struct acpi_driver *acpi_drv = acpi_dev->driver; | ||
250 | 239 | ||
251 | /* | 240 | if (acpi_drv && acpi_drv->ops.resume) |
252 | * For now, we should only register 1 generic device - | 241 | return acpi_drv->ops.resume(acpi_dev); |
253 | * the ACPI root device - and from there, we walk the | ||
254 | * tree of ACPI devices to suspend each one using the | ||
255 | * ACPI driver methods. | ||
256 | */ | ||
257 | if (acpi_dev->handle == ACPI_ROOT_OBJECT) | ||
258 | root_suspend(acpi_dev, state); | ||
259 | return 0; | 242 | return 0; |
260 | } | 243 | } |
261 | 244 | ||
262 | static int root_resume(struct acpi_device * acpi_dev) | 245 | static int acpi_bus_match(struct device *dev, struct device_driver *drv) |
263 | { | 246 | { |
264 | struct acpi_device * dev, * next; | 247 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
265 | int result; | 248 | struct acpi_driver *acpi_drv = to_acpi_driver(drv); |
266 | 249 | ||
267 | spin_lock(&acpi_device_lock); | 250 | if (acpi_drv->ops.match) |
268 | list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) { | 251 | return !acpi_drv->ops.match(acpi_dev, acpi_drv); |
269 | if (dev->driver && dev->driver->ops.resume) { | 252 | return !acpi_match_ids(acpi_dev, acpi_drv->ids); |
270 | spin_unlock(&acpi_device_lock); | 253 | } |
271 | result = dev->driver->ops.resume(dev, 0); | 254 | |
272 | if (result) { | 255 | static int acpi_device_uevent(struct device *dev, char **envp, int num_envp, |
273 | printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n", | 256 | char *buffer, int buffer_size) |
274 | acpi_device_name(dev), | 257 | { |
275 | acpi_device_bid(dev), result); | 258 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
276 | } | 259 | int i = 0, length = 0, ret = 0; |
277 | spin_lock(&acpi_device_lock); | 260 | |
261 | if (acpi_dev->flags.hardware_id) | ||
262 | ret = add_uevent_var(envp, num_envp, &i, | ||
263 | buffer, buffer_size, &length, | ||
264 | "HWID=%s", acpi_dev->pnp.hardware_id); | ||
265 | if (ret) | ||
266 | return -ENOMEM; | ||
267 | if (acpi_dev->flags.compatible_ids) { | ||
268 | int j; | ||
269 | struct acpi_compatible_id_list *cid_list; | ||
270 | |||
271 | cid_list = acpi_dev->pnp.cid_list; | ||
272 | |||
273 | for (j = 0; j < cid_list->count; j++) { | ||
274 | ret = add_uevent_var(envp, num_envp, &i, buffer, | ||
275 | buffer_size, &length, "COMPTID=%s", | ||
276 | cid_list->id[j].value); | ||
277 | if (ret) | ||
278 | return -ENOMEM; | ||
278 | } | 279 | } |
279 | } | 280 | } |
280 | spin_unlock(&acpi_device_lock); | 281 | |
282 | envp[i] = NULL; | ||
281 | return 0; | 283 | return 0; |
282 | } | 284 | } |
283 | 285 | ||
284 | static int acpi_device_resume(struct device * dev) | 286 | static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *); |
287 | static int acpi_start_single_object(struct acpi_device *); | ||
288 | static int acpi_device_probe(struct device * dev) | ||
285 | { | 289 | { |
286 | struct acpi_device * acpi_dev = to_acpi_device(dev); | 290 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
291 | struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); | ||
292 | int ret; | ||
293 | |||
294 | ret = acpi_bus_driver_init(acpi_dev, acpi_drv); | ||
295 | if (!ret) { | ||
296 | acpi_start_single_object(acpi_dev); | ||
297 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
298 | "Found driver [%s] for device [%s]\n", | ||
299 | acpi_drv->name, acpi_dev->pnp.bus_id)); | ||
300 | get_device(dev); | ||
301 | } | ||
302 | return ret; | ||
303 | } | ||
287 | 304 | ||
288 | /* | 305 | static int acpi_device_remove(struct device * dev) |
289 | * For now, we should only register 1 generic device - | 306 | { |
290 | * the ACPI root device - and from there, we walk the | 307 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
291 | * tree of ACPI devices to resume each one using the | 308 | struct acpi_driver *acpi_drv = acpi_dev->driver; |
292 | * ACPI driver methods. | 309 | |
293 | */ | 310 | if (acpi_drv) { |
294 | if (acpi_dev->handle == ACPI_ROOT_OBJECT) | 311 | if (acpi_drv->ops.stop) |
295 | root_resume(acpi_dev); | 312 | acpi_drv->ops.stop(acpi_dev, ACPI_BUS_REMOVAL_NORMAL); |
313 | if (acpi_drv->ops.remove) | ||
314 | acpi_drv->ops.remove(acpi_dev, ACPI_BUS_REMOVAL_NORMAL); | ||
315 | } | ||
316 | acpi_dev->driver = NULL; | ||
317 | acpi_driver_data(dev) = NULL; | ||
318 | |||
319 | put_device(dev); | ||
296 | return 0; | 320 | return 0; |
297 | } | 321 | } |
298 | 322 | ||
299 | /** | 323 | static void acpi_device_shutdown(struct device *dev) |
300 | * acpi_bus_match - match device IDs to driver's supported IDs | ||
301 | * @device: the device that we are trying to match to a driver | ||
302 | * @driver: driver whose device id table is being checked | ||
303 | * | ||
304 | * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it | ||
305 | * matches the specified driver's criteria. | ||
306 | */ | ||
307 | static int | ||
308 | acpi_bus_match(struct acpi_device *device, struct acpi_driver *driver) | ||
309 | { | 324 | { |
310 | if (driver && driver->ops.match) | 325 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
311 | return driver->ops.match(device, driver); | 326 | struct acpi_driver *acpi_drv = acpi_dev->driver; |
312 | return acpi_match_ids(device, driver->ids); | 327 | |
328 | if (acpi_drv && acpi_drv->ops.shutdown) | ||
329 | acpi_drv->ops.shutdown(acpi_dev); | ||
330 | |||
331 | return ; | ||
313 | } | 332 | } |
314 | 333 | ||
315 | static struct bus_type acpi_bus_type = { | 334 | static struct bus_type acpi_bus_type = { |
316 | .name = "acpi", | 335 | .name = "acpi", |
317 | .suspend = acpi_device_suspend, | 336 | .suspend = acpi_device_suspend, |
318 | .resume = acpi_device_resume, | 337 | .resume = acpi_device_resume, |
338 | .shutdown = acpi_device_shutdown, | ||
339 | .match = acpi_bus_match, | ||
340 | .probe = acpi_device_probe, | ||
341 | .remove = acpi_device_remove, | ||
342 | .uevent = acpi_device_uevent, | ||
319 | }; | 343 | }; |
320 | 344 | ||
321 | static void acpi_device_register(struct acpi_device *device, | 345 | static void acpi_device_register(struct acpi_device *device, |
@@ -449,7 +473,7 @@ static void acpi_driver_attach(struct acpi_driver *drv) | |||
449 | continue; | 473 | continue; |
450 | spin_unlock(&acpi_device_lock); | 474 | spin_unlock(&acpi_device_lock); |
451 | 475 | ||
452 | if (!acpi_bus_match(dev, drv)) { | 476 | if (!acpi_bus_match(&(dev->dev), &(drv->drv))) { |
453 | if (!acpi_bus_driver_init(dev, drv)) { | 477 | if (!acpi_bus_driver_init(dev, drv)) { |
454 | acpi_start_single_object(dev); | 478 | acpi_start_single_object(dev); |
455 | atomic_inc(&drv->references); | 479 | atomic_inc(&drv->references); |
@@ -551,7 +575,7 @@ static int acpi_bus_find_driver(struct acpi_device *device) | |||
551 | 575 | ||
552 | atomic_inc(&driver->references); | 576 | atomic_inc(&driver->references); |
553 | spin_unlock(&acpi_device_lock); | 577 | spin_unlock(&acpi_device_lock); |
554 | if (!acpi_bus_match(device, driver)) { | 578 | if (!acpi_bus_match(&(device->dev), &(driver->drv))) { |
555 | result = acpi_bus_driver_init(device, driver); | 579 | result = acpi_bus_driver_init(device, driver); |
556 | if (!result) | 580 | if (!result) |
557 | goto Done; | 581 | goto Done; |