[PATCH] PCI: Add pci_device_shutdown to pci_bus_type
[powerpc.git] / drivers / pci / pci-acpi.c
index f94c86f..6917c6c 100644 (file)
@@ -17,6 +17,7 @@
 #include <acpi/acpi_bus.h>
 
 #include <linux/pci-acpi.h>
+#include "pci.h"
 
 static u32 ctrlset_buf[3] = {0, 0, 0};
 static u32 global_ctrlsets = 0;
@@ -90,9 +91,7 @@ acpi_query_osc (
 static acpi_status  
 acpi_run_osc (
        acpi_handle     handle,
-       u32             level,
-       void            *context,
-       void            **retval )
+       void            *context)
 {
        acpi_status             status;
        struct acpi_object_list input;
@@ -179,11 +178,12 @@ EXPORT_SYMBOL(pci_osc_support_set);
 
 /**
  * pci_osc_control_set - commit requested control to Firmware
+ * @handle: acpi_handle for the target ACPI object
  * @flags: driver's requested control bits
  *
  * Attempt to take control from Firmware on requested control bits.
  **/
-acpi_status pci_osc_control_set(u32 flags)
+acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
 {
        acpi_status     status;
        u32             ctrlset;
@@ -197,10 +197,7 @@ acpi_status pci_osc_control_set(u32 flags)
                return AE_SUPPORT;
        }
        ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset;
-       status = acpi_get_devices ( PCI_ROOT_HID_STRING,
-                               acpi_run_osc,
-                               ctrlset_buf,
-                               NULL );
+       status = acpi_run_osc(handle, ctrlset_buf);
        if (ACPI_FAILURE (status)) {
                ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset;
        }
@@ -209,6 +206,56 @@ acpi_status pci_osc_control_set(u32 flags)
 }
 EXPORT_SYMBOL(pci_osc_control_set);
 
+/*
+ * _SxD returns the D-state with the highest power
+ * (lowest D-state number) supported in the S-state "x".
+ *
+ * If the devices does not have a _PRW
+ * (Power Resources for Wake) supporting system wakeup from "x"
+ * then the OS is free to choose a lower power (higher number
+ * D-state) than the return value from _SxD.
+ *
+ * But if _PRW is enabled at S-state "x", the OS
+ * must not choose a power lower than _SxD --
+ * unless the device has an _SxW method specifying
+ * the lowest power (highest D-state number) the device
+ * may enter while still able to wake the system.
+ *
+ * ie. depending on global OS policy:
+ *
+ * if (_PRW at S-state x)
+ *     choose from highest power _SxD to lowest power _SxW
+ * else // no _PRW at S-state x
+ *     choose highest power _SxD or any lower power
+ *
+ * currently we simply return _SxD, if present.
+ */
+
+static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state)
+{
+       /* TBD */
+
+       return -ENODEV;
+}
+
+static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
+{
+       acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
+       static int state_conv[] = {
+               [0] = 0,
+               [1] = 1,
+               [2] = 2,
+               [3] = 3,
+               [4] = 3
+       };
+       int acpi_state = state_conv[(int __force) state];
+
+       if (!handle)
+               return -ENODEV;
+       return acpi_bus_set_power(handle, acpi_state);
+}
+
+
 /* ACPI bus type */
 static int pci_acpi_find_device(struct device *dev, acpi_handle *handle)
 {
@@ -255,6 +302,8 @@ static int __init pci_acpi_init(void)
        ret = register_acpi_bus_type(&pci_acpi_bus);
        if (ret)
                return 0;
+       platform_pci_choose_state = acpi_pci_choose_state;
+       platform_pci_set_power_state = acpi_pci_set_power_state;
        return 0;
 }
 arch_initcall(pci_acpi_init);