printk(KERN_WARNING PREFIX
"Transitioning device [%s] to D%d\n",
device->pnp.bus_id, state);
- else
+ else {
+ device->power.state = state;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device [%s] transitioned to D%d\n",
device->pnp.bus_id, state));
+ }
return result;
}
}
EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
+/**
+ * ide_acpi_set_state - set the channel power state
+ * @hwif: target IDE interface
+ * @on: state, on/off
+ *
+ * This function executes the _PS0/_PS3 ACPI method to set the power state.
+ * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
+ */
+void ide_acpi_set_state(ide_hwif_t *hwif, int on)
+{
+ int unit;
+
+ if (ide_noacpi)
+ return;
+
+ DEBPRINT("ENTER:\n");
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ return;
+ }
+ /* channel first and then drives for power on and verse versa for power off */
+ if (on)
+ acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ if (!drive->acpidata->obj_handle)
+ drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
+
+ if (drive->acpidata->obj_handle && drive->present) {
+ acpi_bus_set_power(drive->acpidata->obj_handle,
+ on? ACPI_STATE_D0: ACPI_STATE_D3);
+ }
+ }
+ if (!on)
+ acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_set_state);
+
/**
* ide_acpi_init - initialize the ACPI link for an IDE interface
* @hwif: target IDE interface (channel)
return;
}
+ /* ACPI _PS0 before _STM */
+ ide_acpi_set_state(hwif, 1);
/*
* ACPI requires us to call _STM on startup
*/
struct request rq;
struct request_pm_state rqpm;
ide_task_t args;
+ int ret;
/* Call ACPI _GTM only once */
if (!(drive->dn % 2))
mesg.event = PM_EVENT_FREEZE;
rqpm.pm_state = mesg.event;
- return ide_do_drive_cmd(drive, &rq, ide_wait);
+ ret = ide_do_drive_cmd(drive, &rq, ide_wait);
+ /* only call ACPI _PS3 after both drivers are suspended */
+ if (!ret && (((drive->dn % 2) && hwif->drives[0].present
+ && hwif->drives[1].present)
+ || !hwif->drives[0].present
+ || !hwif->drives[1].present))
+ ide_acpi_set_state(hwif, 0);
+ return ret;
}
static int generic_ide_resume(struct device *dev)
int err;
/* Call ACPI _STM only once */
- if (!(drive->dn % 2))
+ if (!(drive->dn % 2)) {
+ ide_acpi_set_state(hwif, 1);
ide_acpi_push_timing(hwif);
+ }
ide_acpi_exec_tfs(drive);
extern void ide_acpi_get_timing(ide_hwif_t *hwif);
extern void ide_acpi_push_timing(ide_hwif_t *hwif);
extern void ide_acpi_init(ide_hwif_t *hwif);
+extern void ide_acpi_set_state(ide_hwif_t *hwif, int on);
#else
static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
static inline void ide_acpi_init(ide_hwif_t *hwif) { ; }
+static inline void ide_acpi_set_state(ide_hwif_t *hwif, int on) {}
#endif
extern int ide_hwif_request_regions(ide_hwif_t *hwif);