diff options
Diffstat (limited to 'drivers/acpi/bus.c')
| -rw-r--r-- | drivers/acpi/bus.c | 88 | 
1 files changed, 57 insertions, 31 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 3188da3df8da..adceafda9c17 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -182,41 +182,66 @@ EXPORT_SYMBOL(acpi_bus_get_private_data);                                   Power Management     -------------------------------------------------------------------------- */ +static const char *state_string(int state) +{ +	switch (state) { +	case ACPI_STATE_D0: +		return "D0"; +	case ACPI_STATE_D1: +		return "D1"; +	case ACPI_STATE_D2: +		return "D2"; +	case ACPI_STATE_D3_HOT: +		return "D3hot"; +	case ACPI_STATE_D3_COLD: +		return "D3"; +	default: +		return "(unknown)"; +	} +} +  static int __acpi_bus_get_power(struct acpi_device *device, int *state)  { -	int result = 0; -	acpi_status status = 0; -	unsigned long long psc = 0; +	int result = ACPI_STATE_UNKNOWN;  	if (!device || !state)  		return -EINVAL; -	*state = ACPI_STATE_UNKNOWN; - -	if (device->flags.power_manageable) { -		/* -		 * Get the device's power state either directly (via _PSC) or -		 * indirectly (via power resources). -		 */ -		if (device->power.flags.power_resources) { -			result = acpi_power_get_inferred_state(device, state); -			if (result) -				return result; -		} else if (device->power.flags.explicit_get) { -			status = acpi_evaluate_integer(device->handle, "_PSC", -						       NULL, &psc); -			if (ACPI_FAILURE(status)) -				return -ENODEV; -			*state = (int)psc; -		} -	} else { +	if (!device->flags.power_manageable) {  		/* TBD: Non-recursive algorithm for walking up hierarchy. */  		*state = device->parent ?  			device->parent->power.state : ACPI_STATE_D0; +		goto out; +	} + +	/* +	 * Get the device's power state either directly (via _PSC) or +	 * indirectly (via power resources). +	 */ +	if (device->power.flags.explicit_get) { +		unsigned long long psc; +		acpi_status status = acpi_evaluate_integer(device->handle, +							   "_PSC", NULL, &psc); +		if (ACPI_FAILURE(status)) +			return -ENODEV; + +		result = psc; +	} +	/* The test below covers ACPI_STATE_UNKNOWN too. */ +	if (result <= ACPI_STATE_D2) { +	  ; /* Do nothing. */ +	} else if (device->power.flags.power_resources) { +		int error = acpi_power_get_inferred_state(device, &result); +		if (error) +			return error; +	} else if (result == ACPI_STATE_D3_HOT) { +		result = ACPI_STATE_D3;  	} +	*state = result; -	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n", -			  device->pnp.bus_id, *state)); + out: +	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n", +			  device->pnp.bus_id, state_string(*state)));  	return 0;  } @@ -234,13 +259,14 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state)  	/* Make sure this is a valid target state */  	if (state == device->power.state) { -		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", -				  state)); +		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n", +				  state_string(state)));  		return 0;  	}  	if (!device->power.states[state].flags.valid) { -		printk(KERN_WARNING PREFIX "Device does not support D%d\n", state); +		printk(KERN_WARNING PREFIX "Device does not support %s\n", +		       state_string(state));  		return -ENODEV;  	}  	if (device->parent && (state < device->parent->power.state)) { @@ -294,13 +320,13 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state)        end:  	if (result)  		printk(KERN_WARNING PREFIX -			      "Device [%s] failed to transition to D%d\n", -			      device->pnp.bus_id, state); +			      "Device [%s] failed to transition to %s\n", +			      device->pnp.bus_id, state_string(state));  	else {  		device->power.state = state;  		ACPI_DEBUG_PRINT((ACPI_DB_INFO, -				  "Device [%s] transitioned to D%d\n", -				  device->pnp.bus_id, state)); +				  "Device [%s] transitioned to %s\n", +				  device->pnp.bus_id, state_string(state)));  	}  	return result;  | 
