ACPI support for IDE devices

This patch implements ACPI integration for generic IDE devices.
The ACPI spec mandates that some methods are called during suspend and
resume. And consequently there most modern Laptops cannot resume
properly without it.

According to the spec, we should call '_GTM' (Get Timing) upon suspend
to store the current IDE adapter settings.
Upon resume we should call '_STM' (Set Timing) to initialize the
adapter with the stored settings; afterwards '_GTF' (Get Taskfile)
should be called which returns a buffer with some IDE initialisation
commands. Those commands should be passed to the drive.

There are two module params which control the behaviour of this patch:

'ide=noacpi'
	Do not call any ACPI methods (Disables any ACPI method calls)
'ide=acpigtf'
	Enable execution of _GTF methods upon resume.
	Has no effect if 'ide=noacpi' is set.
'ide=acpionboot'
	Enable execution of ACPI methods during boot.
	This might be required on some machines if 'ide=acpigtf' is
	selected as some machines modify the _GTF information
	depending on the drive identification passed down with _STM.

Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>

diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 6c9bd51..c750f6c 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -187,6 +187,12 @@
 
 EXPORT_SYMBOL(noautodma);
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+int ide_noacpi = 0;
+int ide_noacpitfs = 1;
+int ide_noacpionboot = 1;
+#endif
+
 /*
  * This is declared extern in ide.h, for access by other IDE modules:
  */
@@ -1214,10 +1220,15 @@
 static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 {
 	ide_drive_t *drive = dev->driver_data;
+	ide_hwif_t *hwif = HWIF(drive);
 	struct request rq;
 	struct request_pm_state rqpm;
 	ide_task_t args;
 
+	/* Call ACPI _GTM only once */
+	if (!(drive->dn % 2))
+		ide_acpi_get_timing(hwif);
+
 	memset(&rq, 0, sizeof(rq));
 	memset(&rqpm, 0, sizeof(rqpm));
 	memset(&args, 0, sizeof(args));
@@ -1235,10 +1246,17 @@
 static int generic_ide_resume(struct device *dev)
 {
 	ide_drive_t *drive = dev->driver_data;
+	ide_hwif_t *hwif = HWIF(drive);
 	struct request rq;
 	struct request_pm_state rqpm;
 	ide_task_t args;
 
+	/* Call ACPI _STM only once */
+	if (!(drive->dn % 2))
+		ide_acpi_push_timing(hwif);
+
+	ide_acpi_exec_tfs(drive);
+
 	memset(&rq, 0, sizeof(rq));
 	memset(&rqpm, 0, sizeof(rqpm));
 	memset(&args, 0, sizeof(args));
@@ -1543,6 +1561,24 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+	if (!strcmp(s, "ide=noacpi")) {
+		//printk(" : Disable IDE ACPI support.\n");
+		ide_noacpi = 1;
+		return 1;
+	}
+	if (!strcmp(s, "ide=acpigtf")) {
+		//printk(" : Enable IDE ACPI _GTF support.\n");
+		ide_noacpitfs = 0;
+		return 1;
+	}
+	if (!strcmp(s, "ide=acpionboot")) {
+		//printk(" : Call IDE ACPI methods on boot.\n");
+		ide_noacpionboot = 0;
+		return 1;
+	}
+#endif /* CONFIG_BLK_DEV_IDEACPI */
+
 	/*
 	 * Look for drive options:  "hdx="
 	 */