diff options
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-acpi.c | 60 |
1 files changed, 59 insertions, 1 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index a276c06dda95..5ebbf16f3af1 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -14,6 +14,7 @@ #include <linux/acpi.h> #include <linux/libata.h> #include <linux/pci.h> +#include <scsi/scsi_device.h> #include "libata.h" #include <acpi/acpi_bus.h> @@ -95,6 +96,47 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) } } +static void ata_acpi_handle_hotplug (struct ata_port *ap, struct kobject *kobj, + u32 event) +{ + char event_string[12]; + char *envp[] = { event_string, NULL }; + struct ata_eh_info *ehi = &ap->link.eh_info; + + if (event == 0 || event == 1) { + unsigned long flags; + spin_lock_irqsave(ap->lock, flags); + ata_ehi_clear_desc(ehi); + ata_ehi_push_desc(ehi, "ACPI event"); + ata_ehi_hotplugged(ehi); + ata_port_freeze(ap); + spin_unlock_irqrestore(ap->lock, flags); + } + + if (kobj) { + sprintf(event_string, "BAY_EVENT=%d", event); + kobject_uevent_env(kobj, KOBJ_CHANGE, envp); + } +} + +static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data) +{ + struct ata_device *dev = data; + struct kobject *kobj = NULL; + + if (dev->sdev) + kobj = &dev->sdev->sdev_gendev.kobj; + + ata_acpi_handle_hotplug (dev->link->ap, kobj, event); +} + +static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data) +{ + struct ata_port *ap = data; + + ata_acpi_handle_hotplug (ap, &ap->dev->kobj, event); +} + /** * ata_acpi_associate - associate ATA host with ACPI objects * @host: target ATA host @@ -110,7 +152,7 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap) */ void ata_acpi_associate(struct ata_host *host) { - int i; + int i, j; if (!is_pci_dev(host->dev) || libata_noacpi) return; @@ -126,6 +168,22 @@ void ata_acpi_associate(struct ata_host *host) ata_acpi_associate_sata_port(ap); else ata_acpi_associate_ide_port(ap); + + if (ap->acpi_handle) + acpi_install_notify_handler (ap->acpi_handle, + ACPI_SYSTEM_NOTIFY, + ata_acpi_ap_notify, + ap); + + for (j = 0; j < ata_link_max_devices(&ap->link); j++) { + struct ata_device *dev = &ap->link.device[j]; + + if (dev->acpi_handle) + acpi_install_notify_handler (dev->acpi_handle, + ACPI_SYSTEM_NOTIFY, + ata_acpi_dev_notify, + dev); + } } } |