ACPI / PM: Add functions for manipulating lists of power resources
authorRafael J. Wysocki <rjw@sisk.pl>
Wed, 24 Nov 2010 23:06:09 +0000 (00:06 +0100)
committerLen Brown <len.brown@intel.com>
Wed, 12 Jan 2011 09:48:43 +0000 (04:48 -0500)
ACPI device power resources should be reference counted during
device initialization, so that their reference counters are always
up to date.  It is convenient to do that with the help of a function
that will reference count and possibly turn on power resources in
a given list, so introduce that function, acpi_power_on_list().
For symmetry, introduce acpi_power_off_list() for performing the
reverse operation and use the both of them to simplify
acpi_power_transition().

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Len Brown <len.brown@intel.com>
drivers/acpi/power.c

index 9bd1b60..95fedbd 100644 (file)
@@ -266,6 +266,35 @@ static int acpi_power_off_device(acpi_handle handle)
        return result;
 }
 
+static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res)
+{
+       int i;
+
+       for (i = num_res - 1; i >= 0 ; i--)
+               acpi_power_off_device(list->handles[i]);
+}
+
+static void acpi_power_off_list(struct acpi_handle_list *list)
+{
+       __acpi_power_off_list(list, list->count);
+}
+
+static int acpi_power_on_list(struct acpi_handle_list *list)
+{
+       int result = 0;
+       int i;
+
+       for (i = 0; i < list->count; i++) {
+               result = acpi_power_on(list->handles[i]);
+               if (result) {
+                       __acpi_power_off_list(list, i);
+                       break;
+               }
+       }
+
+       return result;
+}
+
 /**
  * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
  *                          ACPI 3.0) _PSW (Power State Wake)
@@ -458,10 +487,7 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
 
 int acpi_power_transition(struct acpi_device *device, int state)
 {
-       int result = 0;
-       struct acpi_handle_list *cl = NULL;     /* Current Resources */
-       struct acpi_handle_list *tl = NULL;     /* Target Resources */
-       int i = 0;
+       int result;
 
        if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
                return -EINVAL;
@@ -473,37 +499,20 @@ int acpi_power_transition(struct acpi_device *device, int state)
            || (device->power.state > ACPI_STATE_D3))
                return -ENODEV;
 
-       cl = &device->power.states[device->power.state].resources;
-       tl = &device->power.states[state].resources;
-
        /* TBD: Resources must be ordered. */
 
        /*
         * First we reference all power resources required in the target list
-        * (e.g. so the device doesn't lose power while transitioning).
+        * (e.g. so the device doesn't lose power while transitioning).  Then,
+        * we dereference all power resources used in the current list.
         */
-       for (i = 0; i < tl->count; i++) {
-               result = acpi_power_on(tl->handles[i]);
-               if (result)
-                       goto end;
-       }
+       result = acpi_power_on_list(&device->power.states[state].resources);
+       if (!result)
+               acpi_power_off_list(
+                       &device->power.states[device->power.state].resources);
 
-       /*
-        * Then we dereference all power resources used in the current list.
-        */
-       for (i = 0; i < cl->count; i++) {
-               result = acpi_power_off_device(cl->handles[i]);
-               if (result)
-                       goto end;
-       }
-
-     end:
-       if (result)
-               device->power.state = ACPI_STATE_UNKNOWN;
-       else {
-       /* We shouldn't change the state till all above operations succeed */
-               device->power.state = state;
-       }
+       /* We shouldn't change the state unless the above operations succeed. */
+       device->power.state = result ? ACPI_STATE_UNKNOWN : state;
 
        return result;
 }