diff options
| author | Zhang Rui <rui.zhang@intel.com> | 2006-12-07 07:56:16 -0500 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2006-12-15 23:38:34 -0500 |
| commit | 9e89dde2b063ca73fcdc9244fe68e2dea32c5088 (patch) | |
| tree | 25a9697eeddd65b5be0ae4c4d2d1f43fff91553f | |
| parent | cc016448b0bf0764928275d034e367753bde8162 (diff) | |
ACPI: clean up scan.c
Adjust the code and make code doing similar things together.
No logic changes.
Signed-off-by : Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
| -rw-r--r-- | drivers/acpi/scan.c | 645 |
1 files changed, 316 insertions, 329 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 698a1540e303..e0255cbd5e19 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
| @@ -111,233 +111,6 @@ static struct kset acpi_namespace_kset = { | |||
| 111 | .uevent_ops = &namespace_uevent_ops, | 111 | .uevent_ops = &namespace_uevent_ops, |
| 112 | }; | 112 | }; |
| 113 | 113 | ||
| 114 | static void acpi_device_register(struct acpi_device *device, | ||
| 115 | struct acpi_device *parent) | ||
| 116 | { | ||
| 117 | int err; | ||
| 118 | |||
| 119 | /* | ||
| 120 | * Linkage | ||
| 121 | * ------- | ||
| 122 | * Link this device to its parent and siblings. | ||
| 123 | */ | ||
| 124 | INIT_LIST_HEAD(&device->children); | ||
| 125 | INIT_LIST_HEAD(&device->node); | ||
| 126 | INIT_LIST_HEAD(&device->g_list); | ||
| 127 | INIT_LIST_HEAD(&device->wakeup_list); | ||
| 128 | |||
| 129 | spin_lock(&acpi_device_lock); | ||
| 130 | if (device->parent) { | ||
| 131 | list_add_tail(&device->node, &device->parent->children); | ||
| 132 | list_add_tail(&device->g_list, &device->parent->g_list); | ||
| 133 | } else | ||
| 134 | list_add_tail(&device->g_list, &acpi_device_list); | ||
| 135 | if (device->wakeup.flags.valid) | ||
| 136 | list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); | ||
| 137 | spin_unlock(&acpi_device_lock); | ||
| 138 | |||
| 139 | strlcpy(device->kobj.name, device->pnp.bus_id, KOBJ_NAME_LEN); | ||
| 140 | if (parent) | ||
| 141 | device->kobj.parent = &parent->kobj; | ||
| 142 | device->kobj.ktype = &ktype_acpi_ns; | ||
| 143 | device->kobj.kset = &acpi_namespace_kset; | ||
| 144 | err = kobject_register(&device->kobj); | ||
| 145 | if (err < 0) | ||
| 146 | printk(KERN_WARNING "%s: kobject_register error: %d\n", | ||
| 147 | __FUNCTION__, err); | ||
| 148 | create_sysfs_device_files(device); | ||
| 149 | } | ||
| 150 | |||
| 151 | static void acpi_device_unregister(struct acpi_device *device, int type) | ||
| 152 | { | ||
| 153 | spin_lock(&acpi_device_lock); | ||
| 154 | if (device->parent) { | ||
| 155 | list_del(&device->node); | ||
| 156 | list_del(&device->g_list); | ||
| 157 | } else | ||
| 158 | list_del(&device->g_list); | ||
| 159 | |||
| 160 | list_del(&device->wakeup_list); | ||
| 161 | |||
| 162 | spin_unlock(&acpi_device_lock); | ||
| 163 | |||
| 164 | acpi_detach_data(device->handle, acpi_bus_data_handler); | ||
| 165 | remove_sysfs_device_files(device); | ||
| 166 | kobject_unregister(&device->kobj); | ||
| 167 | } | ||
| 168 | |||
| 169 | void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) | ||
| 170 | { | ||
| 171 | |||
| 172 | /* TBD */ | ||
| 173 | |||
| 174 | return; | ||
| 175 | } | ||
| 176 | |||
| 177 | static int acpi_bus_get_power_flags(struct acpi_device *device) | ||
| 178 | { | ||
| 179 | acpi_status status = 0; | ||
| 180 | acpi_handle handle = NULL; | ||
| 181 | u32 i = 0; | ||
| 182 | |||
| 183 | |||
| 184 | /* | ||
| 185 | * Power Management Flags | ||
| 186 | */ | ||
| 187 | status = acpi_get_handle(device->handle, "_PSC", &handle); | ||
| 188 | if (ACPI_SUCCESS(status)) | ||
| 189 | device->power.flags.explicit_get = 1; | ||
| 190 | status = acpi_get_handle(device->handle, "_IRC", &handle); | ||
| 191 | if (ACPI_SUCCESS(status)) | ||
| 192 | device->power.flags.inrush_current = 1; | ||
| 193 | |||
| 194 | /* | ||
| 195 | * Enumerate supported power management states | ||
| 196 | */ | ||
| 197 | for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { | ||
| 198 | struct acpi_device_power_state *ps = &device->power.states[i]; | ||
| 199 | char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' }; | ||
| 200 | |||
| 201 | /* Evaluate "_PRx" to se if power resources are referenced */ | ||
| 202 | acpi_evaluate_reference(device->handle, object_name, NULL, | ||
| 203 | &ps->resources); | ||
| 204 | if (ps->resources.count) { | ||
| 205 | device->power.flags.power_resources = 1; | ||
| 206 | ps->flags.valid = 1; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* Evaluate "_PSx" to see if we can do explicit sets */ | ||
| 210 | object_name[2] = 'S'; | ||
| 211 | status = acpi_get_handle(device->handle, object_name, &handle); | ||
| 212 | if (ACPI_SUCCESS(status)) { | ||
| 213 | ps->flags.explicit_set = 1; | ||
| 214 | ps->flags.valid = 1; | ||
| 215 | } | ||
| 216 | |||
| 217 | /* State is valid if we have some power control */ | ||
| 218 | if (ps->resources.count || ps->flags.explicit_set) | ||
| 219 | ps->flags.valid = 1; | ||
| 220 | |||
| 221 | ps->power = -1; /* Unknown - driver assigned */ | ||
| 222 | ps->latency = -1; /* Unknown - driver assigned */ | ||
| 223 | } | ||
| 224 | |||
| 225 | /* Set defaults for D0 and D3 states (always valid) */ | ||
| 226 | device->power.states[ACPI_STATE_D0].flags.valid = 1; | ||
| 227 | device->power.states[ACPI_STATE_D0].power = 100; | ||
| 228 | device->power.states[ACPI_STATE_D3].flags.valid = 1; | ||
| 229 | device->power.states[ACPI_STATE_D3].power = 0; | ||
| 230 | |||
| 231 | /* TBD: System wake support and resource requirements. */ | ||
| 232 | |||
| 233 | device->power.state = ACPI_STATE_UNKNOWN; | ||
| 234 | |||
| 235 | return 0; | ||
| 236 | } | ||
| 237 | |||
| 238 | int acpi_match_ids(struct acpi_device *device, char *ids) | ||
| 239 | { | ||
| 240 | if (device->flags.hardware_id) | ||
| 241 | if (strstr(ids, device->pnp.hardware_id)) | ||
| 242 | return 0; | ||
| 243 | |||
| 244 | if (device->flags.compatible_ids) { | ||
| 245 | struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; | ||
| 246 | int i; | ||
| 247 | |||
| 248 | /* compare multiple _CID entries against driver ids */ | ||
| 249 | for (i = 0; i < cid_list->count; i++) { | ||
| 250 | if (strstr(ids, cid_list->id[i].value)) | ||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | return -ENOENT; | ||
| 255 | } | ||
| 256 | |||
| 257 | static acpi_status | ||
| 258 | acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, | ||
| 259 | union acpi_object *package) | ||
| 260 | { | ||
| 261 | int i = 0; | ||
| 262 | union acpi_object *element = NULL; | ||
| 263 | |||
| 264 | if (!device || !package || (package->package.count < 2)) | ||
| 265 | return AE_BAD_PARAMETER; | ||
| 266 | |||
| 267 | element = &(package->package.elements[0]); | ||
| 268 | if (!element) | ||
| 269 | return AE_BAD_PARAMETER; | ||
| 270 | if (element->type == ACPI_TYPE_PACKAGE) { | ||
| 271 | if ((element->package.count < 2) || | ||
| 272 | (element->package.elements[0].type != | ||
| 273 | ACPI_TYPE_LOCAL_REFERENCE) | ||
| 274 | || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) | ||
| 275 | return AE_BAD_DATA; | ||
| 276 | device->wakeup.gpe_device = | ||
| 277 | element->package.elements[0].reference.handle; | ||
| 278 | device->wakeup.gpe_number = | ||
| 279 | (u32) element->package.elements[1].integer.value; | ||
| 280 | } else if (element->type == ACPI_TYPE_INTEGER) { | ||
| 281 | device->wakeup.gpe_number = element->integer.value; | ||
| 282 | } else | ||
| 283 | return AE_BAD_DATA; | ||
| 284 | |||
| 285 | element = &(package->package.elements[1]); | ||
| 286 | if (element->type != ACPI_TYPE_INTEGER) { | ||
| 287 | return AE_BAD_DATA; | ||
| 288 | } | ||
| 289 | device->wakeup.sleep_state = element->integer.value; | ||
| 290 | |||
| 291 | if ((package->package.count - 2) > ACPI_MAX_HANDLES) { | ||
| 292 | return AE_NO_MEMORY; | ||
| 293 | } | ||
| 294 | device->wakeup.resources.count = package->package.count - 2; | ||
| 295 | for (i = 0; i < device->wakeup.resources.count; i++) { | ||
| 296 | element = &(package->package.elements[i + 2]); | ||
| 297 | if (element->type != ACPI_TYPE_ANY) { | ||
| 298 | return AE_BAD_DATA; | ||
| 299 | } | ||
| 300 | |||
| 301 | device->wakeup.resources.handles[i] = element->reference.handle; | ||
| 302 | } | ||
| 303 | |||
| 304 | return AE_OK; | ||
| 305 | } | ||
| 306 | |||
| 307 | static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) | ||
| 308 | { | ||
| 309 | acpi_status status = 0; | ||
| 310 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 311 | union acpi_object *package = NULL; | ||
| 312 | |||
| 313 | |||
| 314 | /* _PRW */ | ||
| 315 | status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); | ||
| 316 | if (ACPI_FAILURE(status)) { | ||
| 317 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); | ||
| 318 | goto end; | ||
| 319 | } | ||
| 320 | |||
| 321 | package = (union acpi_object *)buffer.pointer; | ||
| 322 | status = acpi_bus_extract_wakeup_device_power_package(device, package); | ||
| 323 | if (ACPI_FAILURE(status)) { | ||
| 324 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); | ||
| 325 | goto end; | ||
| 326 | } | ||
| 327 | |||
| 328 | kfree(buffer.pointer); | ||
| 329 | |||
| 330 | device->wakeup.flags.valid = 1; | ||
| 331 | /* Power button, Lid switch always enable wakeup */ | ||
| 332 | if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E")) | ||
| 333 | device->wakeup.flags.run_wake = 1; | ||
| 334 | |||
| 335 | end: | ||
| 336 | if (ACPI_FAILURE(status)) | ||
| 337 | device->flags.wake_capable = 0; | ||
| 338 | return 0; | ||
| 339 | } | ||
| 340 | |||
| 341 | /* -------------------------------------------------------------------------- | 114 | /* -------------------------------------------------------------------------- |
| 342 | ACPI sysfs device file support | 115 | ACPI sysfs device file support |
| 343 | -------------------------------------------------------------------------- */ | 116 | -------------------------------------------------------------------------- */ |
| @@ -447,20 +220,86 @@ acpi_eject_store(struct acpi_device *device, const char *buf, size_t count) | |||
| 447 | } | 220 | } |
| 448 | 221 | ||
| 449 | /* -------------------------------------------------------------------------- | 222 | /* -------------------------------------------------------------------------- |
| 450 | Performance Management | 223 | ACPI Bus operations |
| 451 | -------------------------------------------------------------------------- */ | 224 | -------------------------------------------------------------------------- */ |
| 225 | static inline struct acpi_device * to_acpi_dev(struct device * dev) | ||
| 226 | { | ||
| 227 | return container_of(dev, struct acpi_device, dev); | ||
| 228 | } | ||
| 452 | 229 | ||
| 453 | static int acpi_bus_get_perf_flags(struct acpi_device *device) | 230 | static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state) |
| 454 | { | 231 | { |
| 455 | device->performance.state = ACPI_STATE_UNKNOWN; | 232 | struct acpi_device * dev, * next; |
| 233 | int result; | ||
| 234 | |||
| 235 | spin_lock(&acpi_device_lock); | ||
| 236 | list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) { | ||
| 237 | if (dev->driver && dev->driver->ops.suspend) { | ||
| 238 | spin_unlock(&acpi_device_lock); | ||
| 239 | result = dev->driver->ops.suspend(dev, 0); | ||
| 240 | if (result) { | ||
| 241 | printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n", | ||
| 242 | acpi_device_name(dev), | ||
| 243 | acpi_device_bid(dev), result); | ||
| 244 | } | ||
| 245 | spin_lock(&acpi_device_lock); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | spin_unlock(&acpi_device_lock); | ||
| 456 | return 0; | 249 | return 0; |
| 457 | } | 250 | } |
| 458 | 251 | ||
| 459 | /* -------------------------------------------------------------------------- | 252 | static int acpi_device_suspend(struct device * dev, pm_message_t state) |
| 460 | Driver Management | 253 | { |
| 461 | -------------------------------------------------------------------------- */ | 254 | struct acpi_device * acpi_dev = to_acpi_dev(dev); |
| 462 | 255 | ||
| 463 | static LIST_HEAD(acpi_bus_drivers); | 256 | /* |
| 257 | * For now, we should only register 1 generic device - | ||
| 258 | * the ACPI root device - and from there, we walk the | ||
| 259 | * tree of ACPI devices to suspend each one using the | ||
| 260 | * ACPI driver methods. | ||
| 261 | */ | ||
| 262 | if (acpi_dev->handle == ACPI_ROOT_OBJECT) | ||
| 263 | root_suspend(acpi_dev, state); | ||
| 264 | return 0; | ||
| 265 | } | ||
| 266 | |||
| 267 | static int root_resume(struct acpi_device * acpi_dev) | ||
| 268 | { | ||
| 269 | struct acpi_device * dev, * next; | ||
| 270 | int result; | ||
| 271 | |||
| 272 | spin_lock(&acpi_device_lock); | ||
| 273 | list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) { | ||
| 274 | if (dev->driver && dev->driver->ops.resume) { | ||
| 275 | spin_unlock(&acpi_device_lock); | ||
| 276 | result = dev->driver->ops.resume(dev, 0); | ||
| 277 | if (result) { | ||
| 278 | printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n", | ||
| 279 | acpi_device_name(dev), | ||
| 280 | acpi_device_bid(dev), result); | ||
| 281 | } | ||
| 282 | spin_lock(&acpi_device_lock); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | spin_unlock(&acpi_device_lock); | ||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | static int acpi_device_resume(struct device * dev) | ||
| 290 | { | ||
| 291 | struct acpi_device * acpi_dev = to_acpi_dev(dev); | ||
| 292 | |||
| 293 | /* | ||
| 294 | * For now, we should only register 1 generic device - | ||
| 295 | * the ACPI root device - and from there, we walk the | ||
| 296 | * tree of ACPI devices to resume each one using the | ||
| 297 | * ACPI driver methods. | ||
| 298 | */ | ||
| 299 | if (acpi_dev->handle == ACPI_ROOT_OBJECT) | ||
| 300 | root_resume(acpi_dev); | ||
| 301 | return 0; | ||
| 302 | } | ||
| 464 | 303 | ||
| 465 | /** | 304 | /** |
| 466 | * acpi_bus_match - match device IDs to driver's supported IDs | 305 | * acpi_bus_match - match device IDs to driver's supported IDs |
| @@ -478,6 +317,72 @@ acpi_bus_match(struct acpi_device *device, struct acpi_driver *driver) | |||
| 478 | return acpi_match_ids(device, driver->ids); | 317 | return acpi_match_ids(device, driver->ids); |
| 479 | } | 318 | } |
| 480 | 319 | ||
| 320 | static struct bus_type acpi_bus_type = { | ||
| 321 | .name = "acpi", | ||
| 322 | .suspend = acpi_device_suspend, | ||
| 323 | .resume = acpi_device_resume, | ||
| 324 | }; | ||
| 325 | |||
| 326 | static void acpi_device_register(struct acpi_device *device, | ||
| 327 | struct acpi_device *parent) | ||
| 328 | { | ||
| 329 | int err; | ||
| 330 | |||
| 331 | /* | ||
| 332 | * Linkage | ||
| 333 | * ------- | ||
| 334 | * Link this device to its parent and siblings. | ||
| 335 | */ | ||
| 336 | INIT_LIST_HEAD(&device->children); | ||
| 337 | INIT_LIST_HEAD(&device->node); | ||
| 338 | INIT_LIST_HEAD(&device->g_list); | ||
| 339 | INIT_LIST_HEAD(&device->wakeup_list); | ||
| 340 | |||
| 341 | spin_lock(&acpi_device_lock); | ||
| 342 | if (device->parent) { | ||
| 343 | list_add_tail(&device->node, &device->parent->children); | ||
| 344 | list_add_tail(&device->g_list, &device->parent->g_list); | ||
| 345 | } else | ||
| 346 | list_add_tail(&device->g_list, &acpi_device_list); | ||
| 347 | if (device->wakeup.flags.valid) | ||
| 348 | list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); | ||
| 349 | spin_unlock(&acpi_device_lock); | ||
| 350 | |||
| 351 | strlcpy(device->kobj.name, device->pnp.bus_id, KOBJ_NAME_LEN); | ||
| 352 | if (parent) | ||
| 353 | device->kobj.parent = &parent->kobj; | ||
| 354 | device->kobj.ktype = &ktype_acpi_ns; | ||
| 355 | device->kobj.kset = &acpi_namespace_kset; | ||
| 356 | err = kobject_register(&device->kobj); | ||
| 357 | if (err < 0) | ||
| 358 | printk(KERN_WARNING "%s: kobject_register error: %d\n", | ||
| 359 | __FUNCTION__, err); | ||
| 360 | create_sysfs_device_files(device); | ||
| 361 | } | ||
| 362 | |||
| 363 | static void acpi_device_unregister(struct acpi_device *device, int type) | ||
| 364 | { | ||
| 365 | spin_lock(&acpi_device_lock); | ||
| 366 | if (device->parent) { | ||
| 367 | list_del(&device->node); | ||
| 368 | list_del(&device->g_list); | ||
| 369 | } else | ||
| 370 | list_del(&device->g_list); | ||
| 371 | |||
| 372 | list_del(&device->wakeup_list); | ||
| 373 | |||
| 374 | spin_unlock(&acpi_device_lock); | ||
| 375 | |||
| 376 | acpi_detach_data(device->handle, acpi_bus_data_handler); | ||
| 377 | remove_sysfs_device_files(device); | ||
| 378 | kobject_unregister(&device->kobj); | ||
| 379 | } | ||
| 380 | |||
| 381 | /* -------------------------------------------------------------------------- | ||
| 382 | Driver Management | ||
| 383 | -------------------------------------------------------------------------- */ | ||
| 384 | static LIST_HEAD(acpi_bus_drivers); | ||
| 385 | |||
| 481 | /** | 386 | /** |
| 482 | * acpi_bus_driver_init - add a device to a driver | 387 | * acpi_bus_driver_init - add a device to a driver |
| 483 | * @device: the device to add and initialize | 388 | * @device: the device to add and initialize |
| @@ -668,7 +573,6 @@ static int acpi_bus_find_driver(struct acpi_device *device) | |||
| 668 | /* -------------------------------------------------------------------------- | 573 | /* -------------------------------------------------------------------------- |
| 669 | Device Enumeration | 574 | Device Enumeration |
| 670 | -------------------------------------------------------------------------- */ | 575 | -------------------------------------------------------------------------- */ |
| 671 | |||
| 672 | acpi_status | 576 | acpi_status |
| 673 | acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) | 577 | acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) |
| 674 | { | 578 | { |
| @@ -691,6 +595,183 @@ acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) | |||
| 691 | } | 595 | } |
| 692 | EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); | 596 | EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); |
| 693 | 597 | ||
| 598 | void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) | ||
| 599 | { | ||
| 600 | |||
| 601 | /* TBD */ | ||
| 602 | |||
| 603 | return; | ||
| 604 | } | ||
| 605 | |||
| 606 | int acpi_match_ids(struct acpi_device *device, char *ids) | ||
| 607 | { | ||
| 608 | if (device->flags.hardware_id) | ||
| 609 | if (strstr(ids, device->pnp.hardware_id)) | ||
| 610 | return 0; | ||
| 611 | |||
| 612 | if (device->flags.compatible_ids) { | ||
| 613 | struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; | ||
| 614 | int i; | ||
| 615 | |||
| 616 | /* compare multiple _CID entries against driver ids */ | ||
| 617 | for (i = 0; i < cid_list->count; i++) { | ||
| 618 | if (strstr(ids, cid_list->id[i].value)) | ||
| 619 | return 0; | ||
| 620 | } | ||
| 621 | } | ||
| 622 | return -ENOENT; | ||
| 623 | } | ||
| 624 | |||
| 625 | static int acpi_bus_get_perf_flags(struct acpi_device *device) | ||
| 626 | { | ||
| 627 | device->performance.state = ACPI_STATE_UNKNOWN; | ||
| 628 | return 0; | ||
| 629 | } | ||
| 630 | |||
| 631 | static acpi_status | ||
| 632 | acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, | ||
| 633 | union acpi_object *package) | ||
| 634 | { | ||
| 635 | int i = 0; | ||
| 636 | union acpi_object *element = NULL; | ||
| 637 | |||
| 638 | if (!device || !package || (package->package.count < 2)) | ||
| 639 | return AE_BAD_PARAMETER; | ||
| 640 | |||
| 641 | element = &(package->package.elements[0]); | ||
| 642 | if (!element) | ||
| 643 | return AE_BAD_PARAMETER; | ||
| 644 | if (element->type == ACPI_TYPE_PACKAGE) { | ||
| 645 | if ((element->package.count < 2) || | ||
| 646 | (element->package.elements[0].type != | ||
| 647 | ACPI_TYPE_LOCAL_REFERENCE) | ||
| 648 | || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) | ||
| 649 | return AE_BAD_DATA; | ||
| 650 | device->wakeup.gpe_device = | ||
| 651 | element->package.elements[0].reference.handle; | ||
| 652 | device->wakeup.gpe_number = | ||
| 653 | (u32) element->package.elements[1].integer.value; | ||
| 654 | } else if (element->type == ACPI_TYPE_INTEGER) { | ||
| 655 | device->wakeup.gpe_number = element->integer.value; | ||
| 656 | } else | ||
| 657 | return AE_BAD_DATA; | ||
| 658 | |||
| 659 | element = &(package->package.elements[1]); | ||
| 660 | if (element->type != ACPI_TYPE_INTEGER) { | ||
| 661 | return AE_BAD_DATA; | ||
| 662 | } | ||
| 663 | device->wakeup.sleep_state = element->integer.value; | ||
| 664 | |||
| 665 | if ((package->package.count - 2) > ACPI_MAX_HANDLES) { | ||
| 666 | return AE_NO_MEMORY; | ||
| 667 | } | ||
| 668 | device->wakeup.resources.count = package->package.count - 2; | ||
| 669 | for (i = 0; i < device->wakeup.resources.count; i++) { | ||
| 670 | element = &(package->package.elements[i + 2]); | ||
| 671 | if (element->type != ACPI_TYPE_ANY) { | ||
| 672 | return AE_BAD_DATA; | ||
| 673 | } | ||
| 674 | |||
| 675 | device->wakeup.resources.handles[i] = element->reference.handle; | ||
| 676 | } | ||
| 677 | |||
| 678 | return AE_OK; | ||
| 679 | } | ||
| 680 | |||
| 681 | static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) | ||
| 682 | { | ||
| 683 | acpi_status status = 0; | ||
| 684 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 685 | union acpi_object *package = NULL; | ||
| 686 | |||
| 687 | |||
| 688 | /* _PRW */ | ||
| 689 | status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); | ||
| 690 | if (ACPI_FAILURE(status)) { | ||
| 691 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); | ||
| 692 | goto end; | ||
| 693 | } | ||
| 694 | |||
| 695 | package = (union acpi_object *)buffer.pointer; | ||
| 696 | status = acpi_bus_extract_wakeup_device_power_package(device, package); | ||
| 697 | if (ACPI_FAILURE(status)) { | ||
| 698 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); | ||
| 699 | goto end; | ||
| 700 | } | ||
| 701 | |||
| 702 | kfree(buffer.pointer); | ||
| 703 | |||
| 704 | device->wakeup.flags.valid = 1; | ||
| 705 | /* Power button, Lid switch always enable wakeup */ | ||
| 706 | if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E")) | ||
| 707 | device->wakeup.flags.run_wake = 1; | ||
| 708 | |||
| 709 | end: | ||
| 710 | if (ACPI_FAILURE(status)) | ||
| 711 | device->flags.wake_capable = 0; | ||
| 712 | return 0; | ||
| 713 | } | ||
| 714 | |||
| 715 | static int acpi_bus_get_power_flags(struct acpi_device *device) | ||
| 716 | { | ||
| 717 | acpi_status status = 0; | ||
| 718 | acpi_handle handle = NULL; | ||
| 719 | u32 i = 0; | ||
| 720 | |||
| 721 | |||
| 722 | /* | ||
| 723 | * Power Management Flags | ||
| 724 | */ | ||
| 725 | status = acpi_get_handle(device->handle, "_PSC", &handle); | ||
| 726 | if (ACPI_SUCCESS(status)) | ||
| 727 | device->power.flags.explicit_get = 1; | ||
| 728 | status = acpi_get_handle(device->handle, "_IRC", &handle); | ||
| 729 | if (ACPI_SUCCESS(status)) | ||
| 730 | device->power.flags.inrush_current = 1; | ||
| 731 | |||
| 732 | /* | ||
| 733 | * Enumerate supported power management states | ||
| 734 | */ | ||
| 735 | for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { | ||
| 736 | struct acpi_device_power_state *ps = &device->power.states[i]; | ||
| 737 | char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' }; | ||
| 738 | |||
| 739 | /* Evaluate "_PRx" to se if power resources are referenced */ | ||
| 740 | acpi_evaluate_reference(device->handle, object_name, NULL, | ||
| 741 | &ps->resources); | ||
| 742 | if (ps->resources.count) { | ||
| 743 | device->power.flags.power_resources = 1; | ||
| 744 | ps->flags.valid = 1; | ||
| 745 | } | ||
| 746 | |||
| 747 | /* Evaluate "_PSx" to see if we can do explicit sets */ | ||
| 748 | object_name[2] = 'S'; | ||
| 749 | status = acpi_get_handle(device->handle, object_name, &handle); | ||
| 750 | if (ACPI_SUCCESS(status)) { | ||
| 751 | ps->flags.explicit_set = 1; | ||
| 752 | ps->flags.valid = 1; | ||
| 753 | } | ||
| 754 | |||
| 755 | /* State is valid if we have some power control */ | ||
| 756 | if (ps->resources.count || ps->flags.explicit_set) | ||
| 757 | ps->flags.valid = 1; | ||
| 758 | |||
| 759 | ps->power = -1; /* Unknown - driver assigned */ | ||
| 760 | ps->latency = -1; /* Unknown - driver assigned */ | ||
| 761 | } | ||
| 762 | |||
| 763 | /* Set defaults for D0 and D3 states (always valid) */ | ||
| 764 | device->power.states[ACPI_STATE_D0].flags.valid = 1; | ||
| 765 | device->power.states[ACPI_STATE_D0].power = 100; | ||
| 766 | device->power.states[ACPI_STATE_D3].flags.valid = 1; | ||
| 767 | device->power.states[ACPI_STATE_D3].power = 0; | ||
| 768 | |||
| 769 | /* TBD: System wake support and resource requirements. */ | ||
| 770 | |||
| 771 | device->power.state = ACPI_STATE_UNKNOWN; | ||
| 772 | |||
| 773 | return 0; | ||
| 774 | } | ||
| 694 | 775 | ||
| 695 | static int acpi_bus_get_flags(struct acpi_device *device) | 776 | static int acpi_bus_get_flags(struct acpi_device *device) |
| 696 | { | 777 | { |
| @@ -1353,100 +1434,6 @@ static int acpi_bus_scan_fixed(struct acpi_device *root) | |||
| 1353 | return result; | 1434 | return result; |
| 1354 | } | 1435 | } |
| 1355 | 1436 | ||
| 1356 | |||
| 1357 | static inline struct acpi_device * to_acpi_dev(struct device * dev) | ||
| 1358 | { | ||
| 1359 | return container_of(dev, struct acpi_device, dev); | ||
| 1360 | } | ||
| 1361 | |||
| 1362 | |||
| 1363 | static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state) | ||
| 1364 | { | ||
| 1365 | struct acpi_device * dev, * next; | ||
| 1366 | int result; | ||
| 1367 | |||
| 1368 | spin_lock(&acpi_device_lock); | ||
| 1369 | list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) { | ||
| 1370 | if (dev->driver && dev->driver->ops.suspend) { | ||
| 1371 | spin_unlock(&acpi_device_lock); | ||
| 1372 | result = dev->driver->ops.suspend(dev, 0); | ||
| 1373 | if (result) { | ||
| 1374 | printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n", | ||
| 1375 | acpi_device_name(dev), | ||
| 1376 | acpi_device_bid(dev), result); | ||
| 1377 | } | ||
| 1378 | spin_lock(&acpi_device_lock); | ||
| 1379 | } | ||
| 1380 | } | ||
| 1381 | spin_unlock(&acpi_device_lock); | ||
| 1382 | return 0; | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | |||
| 1386 | static int acpi_device_suspend(struct device * dev, pm_message_t state) | ||
| 1387 | { | ||
| 1388 | struct acpi_device * acpi_dev = to_acpi_dev(dev); | ||
| 1389 | |||
| 1390 | /* | ||
| 1391 | * For now, we should only register 1 generic device - | ||
| 1392 | * the ACPI root device - and from there, we walk the | ||
| 1393 | * tree of ACPI devices to suspend each one using the | ||
| 1394 | * ACPI driver methods. | ||
| 1395 | */ | ||
| 1396 | if (acpi_dev->handle == ACPI_ROOT_OBJECT) | ||
| 1397 | root_suspend(acpi_dev, state); | ||
| 1398 | return 0; | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | |||
| 1402 | |||
| 1403 | static int root_resume(struct acpi_device * acpi_dev) | ||
| 1404 | { | ||
| 1405 | struct acpi_device * dev, * next; | ||
| 1406 | int result; | ||
| 1407 | |||
| 1408 | spin_lock(&acpi_device_lock); | ||
| 1409 | list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) { | ||
| 1410 | if (dev->driver && dev->driver->ops.resume) { | ||
| 1411 | spin_unlock(&acpi_device_lock); | ||
| 1412 | result = dev->driver->ops.resume(dev, 0); | ||
| 1413 | if (result) { | ||
| 1414 | printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n", | ||
| 1415 | acpi_device_name(dev), | ||
| 1416 | acpi_device_bid(dev), result); | ||
| 1417 | } | ||
| 1418 | spin_lock(&acpi_device_lock); | ||
| 1419 | } | ||
| 1420 | } | ||
| 1421 | spin_unlock(&acpi_device_lock); | ||
| 1422 | return 0; | ||
| 1423 | } | ||
| 1424 | |||
| 1425 | |||
| 1426 | static int acpi_device_resume(struct device * dev) | ||
| 1427 | { | ||
| 1428 | struct acpi_device * acpi_dev = to_acpi_dev(dev); | ||
| 1429 | |||
| 1430 | /* | ||
| 1431 | * For now, we should only register 1 generic device - | ||
| 1432 | * the ACPI root device - and from there, we walk the | ||
| 1433 | * tree of ACPI devices to resume each one using the | ||
| 1434 | * ACPI driver methods. | ||
| 1435 | */ | ||
| 1436 | if (acpi_dev->handle == ACPI_ROOT_OBJECT) | ||
| 1437 | root_resume(acpi_dev); | ||
| 1438 | return 0; | ||
| 1439 | } | ||
| 1440 | |||
| 1441 | |||
| 1442 | static struct bus_type acpi_bus_type = { | ||
| 1443 | .name = "acpi", | ||
| 1444 | .suspend = acpi_device_suspend, | ||
| 1445 | .resume = acpi_device_resume, | ||
| 1446 | }; | ||
| 1447 | |||
| 1448 | |||
| 1449 | |||
| 1450 | static int __init acpi_scan_init(void) | 1437 | static int __init acpi_scan_init(void) |
| 1451 | { | 1438 | { |
| 1452 | int result; | 1439 | int result; |
