diff options
Diffstat (limited to 'drivers/pci/hotplug/acpi_pcihp.c')
-rw-r--r-- | drivers/pci/hotplug/acpi_pcihp.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index e17ef54f0efc..c62ab8d240aa 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c | |||
@@ -501,5 +501,74 @@ int acpi_root_bridge(acpi_handle handle) | |||
501 | } | 501 | } |
502 | EXPORT_SYMBOL_GPL(acpi_root_bridge); | 502 | EXPORT_SYMBOL_GPL(acpi_root_bridge); |
503 | 503 | ||
504 | |||
505 | static int is_ejectable(acpi_handle handle) | ||
506 | { | ||
507 | acpi_status status; | ||
508 | acpi_handle tmp; | ||
509 | unsigned long long removable; | ||
510 | status = acpi_get_handle(handle, "_ADR", &tmp); | ||
511 | if (ACPI_FAILURE(status)) | ||
512 | return 0; | ||
513 | status = acpi_get_handle(handle, "_EJ0", &tmp); | ||
514 | if (ACPI_SUCCESS(status)) | ||
515 | return 1; | ||
516 | status = acpi_evaluate_integer(handle, "_RMV", NULL, &removable); | ||
517 | if (ACPI_SUCCESS(status) && removable) | ||
518 | return 1; | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | /** | ||
523 | * acpi_pcihp_check_ejectable - check if handle is ejectable ACPI PCI slot | ||
524 | * @pbus: the PCI bus of the PCI slot corresponding to 'handle' | ||
525 | * @handle: ACPI handle to check | ||
526 | * | ||
527 | * Return 1 if handle is ejectable PCI slot, 0 otherwise. | ||
528 | */ | ||
529 | int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle) | ||
530 | { | ||
531 | acpi_handle bridge_handle, parent_handle; | ||
532 | |||
533 | if (!(bridge_handle = acpi_pci_get_bridge_handle(pbus))) | ||
534 | return 0; | ||
535 | if ((ACPI_FAILURE(acpi_get_parent(handle, &parent_handle)))) | ||
536 | return 0; | ||
537 | if (bridge_handle != parent_handle) | ||
538 | return 0; | ||
539 | return is_ejectable(handle); | ||
540 | } | ||
541 | EXPORT_SYMBOL_GPL(acpi_pci_check_ejectable); | ||
542 | |||
543 | static acpi_status | ||
544 | check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv) | ||
545 | { | ||
546 | int *found = (int *)context; | ||
547 | if (is_ejectable(handle)) { | ||
548 | *found = 1; | ||
549 | return AE_CTRL_TERMINATE; | ||
550 | } | ||
551 | return AE_OK; | ||
552 | } | ||
553 | |||
554 | /** | ||
555 | * acpi_pci_detect_ejectable - check if the PCI bus has ejectable slots | ||
556 | * @pbus - PCI bus to scan | ||
557 | * | ||
558 | * Returns 1 if the PCI bus has ACPI based ejectable slots, 0 otherwise. | ||
559 | */ | ||
560 | int acpi_pci_detect_ejectable(struct pci_bus *pbus) | ||
561 | { | ||
562 | acpi_handle handle; | ||
563 | int found = 0; | ||
564 | |||
565 | if (!(handle = acpi_pci_get_bridge_handle(pbus))) | ||
566 | return 0; | ||
567 | acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, | ||
568 | check_hotplug, (void *)&found, NULL); | ||
569 | return found; | ||
570 | } | ||
571 | EXPORT_SYMBOL_GPL(acpi_pci_detect_ejectable); | ||
572 | |||
504 | module_param(debug_acpi, bool, 0644); | 573 | module_param(debug_acpi, bool, 0644); |
505 | MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not"); | 574 | MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not"); |