Browse Source

Pull bugzilla-5000 into release branch

Len Brown 19 years ago
parent
commit
8f2ddb37e5
5 changed files with 178 additions and 8 deletions
  1. 8 6
      drivers/acpi/bus.c
  2. 40 0
      drivers/acpi/fan.c
  3. 110 0
      drivers/acpi/scan.c
  4. 16 0
      drivers/acpi/thermal.c
  5. 4 2
      include/acpi/acpi_bus.h

+ 8 - 6
drivers/acpi/bus.c

@@ -205,12 +205,14 @@ int acpi_bus_set_power(acpi_handle handle, int state)
 	 * Get device's current power state if it's unknown
 	 * Get device's current power state if it's unknown
 	 * This means device power state isn't initialized or previous setting failed
 	 * This means device power state isn't initialized or previous setting failed
 	 */
 	 */
-	if (device->power.state == ACPI_STATE_UNKNOWN)
-		acpi_bus_get_power(device->handle, &device->power.state);
-	if (state == device->power.state) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
-				  state));
-		return_VALUE(0);
+	if (!device->flags.force_power_state) {
+		if (device->power.state == ACPI_STATE_UNKNOWN)
+			acpi_bus_get_power(device->handle, &device->power.state);
+		if (state == device->power.state) {
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
+					  state));
+			return_VALUE(0);
+		}
 	}
 	}
 	if (!device->power.states[state].flags.valid) {
 	if (!device->power.states[state].flags.valid) {
 		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device does not support D%d\n",
 		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device does not support D%d\n",

+ 40 - 0
drivers/acpi/fan.c

@@ -48,6 +48,8 @@ MODULE_LICENSE("GPL");
 
 
 static int acpi_fan_add(struct acpi_device *device);
 static int acpi_fan_add(struct acpi_device *device);
 static int acpi_fan_remove(struct acpi_device *device, int type);
 static int acpi_fan_remove(struct acpi_device *device, int type);
+static int acpi_fan_suspend(struct acpi_device *device, int state);
+static int acpi_fan_resume(struct acpi_device *device, int state);
 
 
 static struct acpi_driver acpi_fan_driver = {
 static struct acpi_driver acpi_fan_driver = {
 	.name = ACPI_FAN_DRIVER_NAME,
 	.name = ACPI_FAN_DRIVER_NAME,
@@ -56,6 +58,8 @@ static struct acpi_driver acpi_fan_driver = {
 	.ops = {
 	.ops = {
 		.add = acpi_fan_add,
 		.add = acpi_fan_add,
 		.remove = acpi_fan_remove,
 		.remove = acpi_fan_remove,
+		.suspend = acpi_fan_suspend,
+		.resume = acpi_fan_resume,
 		},
 		},
 };
 };
 
 
@@ -206,6 +210,10 @@ static int acpi_fan_add(struct acpi_device *device)
 		goto end;
 		goto end;
 	}
 	}
 
 
+	device->flags.force_power_state = 1;
+	acpi_bus_set_power(device->handle, state);
+	device->flags.force_power_state = 0;
+
 	result = acpi_fan_add_fs(device);
 	result = acpi_fan_add_fs(device);
 	if (result)
 	if (result)
 		goto end;
 		goto end;
@@ -239,6 +247,38 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
 	return_VALUE(0);
 	return_VALUE(0);
 }
 }
 
 
+static int acpi_fan_suspend(struct acpi_device *device, int state)
+{
+	if (!device)
+		return -EINVAL;
+
+	acpi_bus_set_power(device->handle, ACPI_STATE_D0);
+
+	return AE_OK;
+}
+
+static int acpi_fan_resume(struct acpi_device *device, int state)
+{
+	int result = 0;
+	int power_state = 0;
+
+	if (!device)
+		return -EINVAL;
+
+	result = acpi_bus_get_power(device->handle, &power_state);
+	if (result) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				  "Error reading fan power state\n"));
+		return result;
+	}
+
+	device->flags.force_power_state = 1;
+	acpi_bus_set_power(device->handle, power_state);
+	device->flags.force_power_state = 0;
+
+	return result;
+}
+
 static int __init acpi_fan_init(void)
 static int __init acpi_fan_init(void)
 {
 {
 	int result = 0;
 	int result = 0;

+ 110 - 0
drivers/acpi/scan.c

@@ -1341,6 +1341,100 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
 	return_VALUE(result);
 	return_VALUE(result);
 }
 }
 
 
+
+static inline struct acpi_device * to_acpi_dev(struct device * dev)
+{
+	return container_of(dev, struct acpi_device, dev);
+}
+
+
+static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state)
+{
+	struct acpi_device * dev, * next;
+	int result;
+
+	spin_lock(&acpi_device_lock);
+	list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) {
+		if (dev->driver && dev->driver->ops.suspend) {
+			spin_unlock(&acpi_device_lock);
+			result = dev->driver->ops.suspend(dev, 0);
+			if (result) {
+				printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n",
+				       acpi_device_name(dev),
+				       acpi_device_bid(dev), result);
+			}
+			spin_lock(&acpi_device_lock);
+		}
+	}
+	spin_unlock(&acpi_device_lock);
+	return 0;
+}
+
+
+static int acpi_device_suspend(struct device * dev, pm_message_t state)
+{
+	struct acpi_device * acpi_dev = to_acpi_dev(dev);
+
+	/*
+	 * For now, we should only register 1 generic device -
+	 * the ACPI root device - and from there, we walk the
+	 * tree of ACPI devices to suspend each one using the
+	 * ACPI driver methods.
+	 */
+	if (acpi_dev->handle == ACPI_ROOT_OBJECT)
+		root_suspend(acpi_dev, state);
+	return 0;
+}
+
+
+
+static int root_resume(struct acpi_device * acpi_dev)
+{
+	struct acpi_device * dev, * next;
+	int result;
+
+	spin_lock(&acpi_device_lock);
+	list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) {
+		if (dev->driver && dev->driver->ops.resume) {
+			spin_unlock(&acpi_device_lock);
+			result = dev->driver->ops.resume(dev, 0);
+			if (result) {
+				printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n",
+				       acpi_device_name(dev),
+				       acpi_device_bid(dev), result);
+			}
+			spin_lock(&acpi_device_lock);
+		}
+	}
+	spin_unlock(&acpi_device_lock);
+	return 0;
+}
+
+
+static int acpi_device_resume(struct device * dev)
+{
+	struct acpi_device * acpi_dev = to_acpi_dev(dev);
+
+	/*
+	 * For now, we should only register 1 generic device -
+	 * the ACPI root device - and from there, we walk the
+	 * tree of ACPI devices to resume each one using the
+	 * ACPI driver methods.
+	 */
+	if (acpi_dev->handle == ACPI_ROOT_OBJECT)
+		root_resume(acpi_dev);
+	return 0;
+}
+
+
+struct bus_type acpi_bus_type = {
+	.name		= "acpi",
+	.suspend	= acpi_device_suspend,
+	.resume		= acpi_device_resume,
+};
+
+
+
 static int __init acpi_scan_init(void)
 static int __init acpi_scan_init(void)
 {
 {
 	int result;
 	int result;
@@ -1353,6 +1447,12 @@ static int __init acpi_scan_init(void)
 
 
 	kset_register(&acpi_namespace_kset);
 	kset_register(&acpi_namespace_kset);
 
 
+	result = bus_register(&acpi_bus_type);
+	if (result) {
+		/* We don't want to quit even if we failed to add suspend/resume */
+		printk(KERN_ERR PREFIX "Could not register bus type\n");
+	}
+
 	/*
 	/*
 	 * Create the root device in the bus's device tree
 	 * Create the root device in the bus's device tree
 	 */
 	 */
@@ -1362,6 +1462,16 @@ static int __init acpi_scan_init(void)
 		goto Done;
 		goto Done;
 
 
 	result = acpi_start_single_object(acpi_root);
 	result = acpi_start_single_object(acpi_root);
+	if (result)
+		goto Done;
+
+	acpi_root->dev.bus = &acpi_bus_type;
+	snprintf(acpi_root->dev.bus_id, BUS_ID_SIZE, "%s", acpi_bus_type.name);
+	result = device_register(&acpi_root->dev);
+	if (result) {
+		/* We don't want to quit even if we failed to add suspend/resume */
+		printk(KERN_ERR PREFIX "Could not register device\n");
+	}
 
 
 	/*
 	/*
 	 * Enumerate devices in the ACPI namespace.
 	 * Enumerate devices in the ACPI namespace.

+ 16 - 0
drivers/acpi/thermal.c

@@ -82,6 +82,7 @@ MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
 
 
 static int acpi_thermal_add(struct acpi_device *device);
 static int acpi_thermal_add(struct acpi_device *device);
 static int acpi_thermal_remove(struct acpi_device *device, int type);
 static int acpi_thermal_remove(struct acpi_device *device, int type);
+static int acpi_thermal_resume(struct acpi_device *device, int state);
 static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
 static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
 static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
 static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
 static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
 static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
@@ -103,6 +104,7 @@ static struct acpi_driver acpi_thermal_driver = {
 	.ops = {
 	.ops = {
 		.add = acpi_thermal_add,
 		.add = acpi_thermal_add,
 		.remove = acpi_thermal_remove,
 		.remove = acpi_thermal_remove,
+		.resume = acpi_thermal_resume,
 		},
 		},
 };
 };
 
 
@@ -1417,6 +1419,20 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
 	return_VALUE(0);
 	return_VALUE(0);
 }
 }
 
 
+static int acpi_thermal_resume(struct acpi_device *device, int state)
+{
+	struct acpi_thermal *tz = NULL;
+
+	if (!device || !acpi_driver_data(device))
+		return_VALUE(-EINVAL);
+
+	tz = (struct acpi_thermal *)acpi_driver_data(device);
+
+	acpi_thermal_check(tz);
+
+	return AE_OK;
+}
+
 static int __init acpi_thermal_init(void)
 static int __init acpi_thermal_init(void)
 {
 {
 	int result = 0;
 	int result = 0;

+ 4 - 2
include/acpi/acpi_bus.h

@@ -26,7 +26,7 @@
 #ifndef __ACPI_BUS_H__
 #ifndef __ACPI_BUS_H__
 #define __ACPI_BUS_H__
 #define __ACPI_BUS_H__
 
 
-#include <linux/kobject.h>
+#include <linux/device.h>
 
 
 #include <acpi/acpi.h>
 #include <acpi/acpi.h>
 
 
@@ -169,7 +169,8 @@ struct acpi_device_flags {
 	u32 power_manageable:1;
 	u32 power_manageable:1;
 	u32 performance_manageable:1;
 	u32 performance_manageable:1;
 	u32 wake_capable:1;	/* Wakeup(_PRW) supported? */
 	u32 wake_capable:1;	/* Wakeup(_PRW) supported? */
-	u32 reserved:20;
+	u32 force_power_state:1;
+	u32 reserved:19;
 };
 };
 
 
 /* File System */
 /* File System */
@@ -296,6 +297,7 @@ struct acpi_device {
 	struct acpi_driver *driver;
 	struct acpi_driver *driver;
 	void *driver_data;
 	void *driver_data;
 	struct kobject kobj;
 	struct kobject kobj;
+	struct device dev;
 };
 };
 
 
 #define acpi_driver_data(d)	((d)->driver_data)
 #define acpi_driver_data(d)	((d)->driver_data)