power.c 16.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
/*
 *  acpi_power.c - ACPI Bus Power Management ($Revision: 39 $)
 *
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or (at
 *  your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */

/*
 * ACPI power-managed devices may be controlled in two ways:
 * 1. via "Device Specific (D-State) Control"
 * 2. via "Power Resource Control".
 * This module is used to manage devices relying on Power Resource Control.
 * 
 * An ACPI "power resource object" describes a software controllable power
 * plane, clock plane, or other resource used by a power managed device.
 * A device may rely on multiple power resources, and a power resource
 * may be shared by multiple devices.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
42
#include <linux/slab.h>
L
Linus Torvalds 已提交
43 44
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
45 46
#include "sleep.h"

47 48
#define PREFIX "ACPI: "

49
#define _COMPONENT			ACPI_POWER_COMPONENT
50
ACPI_MODULE_NAME("power");
L
Linus Torvalds 已提交
51 52 53 54 55 56 57
#define ACPI_POWER_CLASS		"power_resource"
#define ACPI_POWER_DEVICE_NAME		"Power Resource"
#define ACPI_POWER_FILE_INFO		"info"
#define ACPI_POWER_FILE_STATUS		"state"
#define ACPI_POWER_RESOURCE_STATE_OFF	0x00
#define ACPI_POWER_RESOURCE_STATE_ON	0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
58

L
Len Brown 已提交
59 60
static int acpi_power_add(struct acpi_device *device);
static int acpi_power_remove(struct acpi_device *device, int type);
61
static int acpi_power_resume(struct acpi_device *device);
L
Linus Torvalds 已提交
62

63
static const struct acpi_device_id power_device_ids[] = {
64 65 66 67 68
	{ACPI_POWER_HID, 0},
	{"", 0},
};
MODULE_DEVICE_TABLE(acpi, power_device_ids);

L
Linus Torvalds 已提交
69
static struct acpi_driver acpi_power_driver = {
L
Len Brown 已提交
70
	.name = "power",
L
Len Brown 已提交
71
	.class = ACPI_POWER_CLASS,
72
	.ids = power_device_ids,
L
Len Brown 已提交
73 74 75
	.ops = {
		.add = acpi_power_add,
		.remove = acpi_power_remove,
76
		.resume = acpi_power_resume,
L
Len Brown 已提交
77
		},
L
Linus Torvalds 已提交
78 79
};

L
Len Brown 已提交
80
struct acpi_power_resource {
81
	struct acpi_device * device;
L
Len Brown 已提交
82 83 84
	acpi_bus_id name;
	u32 system_level;
	u32 order;
85
	unsigned int ref_count;
86
	struct mutex resource_lock;
L
Linus Torvalds 已提交
87 88
};

L
Len Brown 已提交
89
static struct list_head acpi_power_resource_list;
L
Linus Torvalds 已提交
90 91 92 93 94 95

/* --------------------------------------------------------------------------
                             Power Resource Management
   -------------------------------------------------------------------------- */

static int
L
Len Brown 已提交
96 97
acpi_power_get_context(acpi_handle handle,
		       struct acpi_power_resource **resource)
L
Linus Torvalds 已提交
98
{
L
Len Brown 已提交
99 100
	int result = 0;
	struct acpi_device *device = NULL;
L
Linus Torvalds 已提交
101 102 103


	if (!resource)
104
		return -ENODEV;
L
Linus Torvalds 已提交
105 106 107

	result = acpi_bus_get_device(handle, &device);
	if (result) {
108
		printk(KERN_WARNING PREFIX "Getting context [%p]\n", handle);
109
		return result;
L
Linus Torvalds 已提交
110 111
	}

112
	*resource = acpi_driver_data(device);
113
	if (!*resource)
114
		return -ENODEV;
L
Linus Torvalds 已提交
115

116
	return 0;
L
Linus Torvalds 已提交
117 118
}

119
static int acpi_power_get_state(acpi_handle handle, int *state)
L
Linus Torvalds 已提交
120
{
L
Len Brown 已提交
121
	acpi_status status = AE_OK;
122
	unsigned long long sta = 0;
123 124
	char node_name[5];
	struct acpi_buffer buffer = { sizeof(node_name), node_name };
L
Linus Torvalds 已提交
125 126


127
	if (!handle || !state)
128
		return -EINVAL;
L
Linus Torvalds 已提交
129

130
	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
L
Linus Torvalds 已提交
131
	if (ACPI_FAILURE(status))
132
		return -ENODEV;
L
Linus Torvalds 已提交
133

134 135
	*state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON:
			      ACPI_POWER_RESOURCE_STATE_OFF;
L
Linus Torvalds 已提交
136

137 138
	acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);

L
Linus Torvalds 已提交
139
	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n",
140
			  node_name,
141
				*state ? "on" : "off"));
L
Linus Torvalds 已提交
142

143
	return 0;
L
Linus Torvalds 已提交
144 145
}

L
Len Brown 已提交
146
static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
L
Linus Torvalds 已提交
147
{
148
	int result = 0, state1;
L
Len Brown 已提交
149
	u32 i = 0;
L
Linus Torvalds 已提交
150 151 152


	if (!list || !state)
153
		return -EINVAL;
L
Linus Torvalds 已提交
154 155 156

	/* The state of the list is 'on' IFF all resources are 'on'. */

L
Len Brown 已提交
157
	for (i = 0; i < list->count; i++) {
158 159 160 161 162 163
		/*
		 * The state of the power resource can be obtained by
		 * using the ACPI handle. In such case it is unnecessary to
		 * get the Power resource first and then get its state again.
		 */
		result = acpi_power_get_state(list->handles[i], &state1);
L
Linus Torvalds 已提交
164
		if (result)
165
			return result;
L
Linus Torvalds 已提交
166

167
		*state = state1;
L
Linus Torvalds 已提交
168 169 170 171 172 173

		if (*state != ACPI_POWER_RESOURCE_STATE_ON)
			break;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n",
L
Len Brown 已提交
174
			  *state ? "on" : "off"));
L
Linus Torvalds 已提交
175

176
	return result;
L
Linus Torvalds 已提交
177 178
}

179
static int __acpi_power_on(struct acpi_power_resource *resource)
L
Linus Torvalds 已提交
180
{
L
Len Brown 已提交
181
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
182

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
	status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
	if (ACPI_FAILURE(status))
		return -ENODEV;

	/* Update the power resource's _device_ power state */
	resource->device->power.state = ACPI_STATE_D0;

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
			  resource->name));

	return 0;
}

static int acpi_power_on(acpi_handle handle)
{
	int result = 0;
	struct acpi_power_resource *resource = NULL;
L
Linus Torvalds 已提交
200 201 202

	result = acpi_power_get_context(handle, &resource);
	if (result)
203
		return result;
L
Linus Torvalds 已提交
204

205 206
	mutex_lock(&resource->resource_lock);

207 208 209 210 211 212
	if (resource->ref_count++) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Power resource [%s] already on",
				  resource->name));
	} else {
		result = __acpi_power_on(resource);
213 214
		if (result)
			resource->ref_count--;
215
	}
L
Linus Torvalds 已提交
216

217
	mutex_unlock(&resource->resource_lock);
L
Linus Torvalds 已提交
218

219
	return result;
L
Linus Torvalds 已提交
220 221
}

222
static int acpi_power_off(acpi_handle handle)
L
Linus Torvalds 已提交
223
{
224
	int result = 0;
L
Len Brown 已提交
225
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
226
	struct acpi_power_resource *resource = NULL;
227

L
Linus Torvalds 已提交
228 229
	result = acpi_power_get_context(handle, &resource);
	if (result)
230
		return result;
L
Linus Torvalds 已提交
231

232
	mutex_lock(&resource->resource_lock);
233 234 235 236 237 238

	if (!resource->ref_count) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Power resource [%s] already off",
				  resource->name));
		goto unlock;
239
	}
L
Linus Torvalds 已提交
240

241 242 243 244 245
	if (--resource->ref_count) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Power resource [%s] still in use\n",
				  resource->name));
		goto unlock;
L
Linus Torvalds 已提交
246 247
	}

248
	status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL);
249 250 251 252 253
	if (ACPI_FAILURE(status)) {
		result = -ENODEV;
	} else {
		/* Update the power resource's _device_ power state */
		resource->device->power.state = ACPI_STATE_D3;
L
Linus Torvalds 已提交
254

255 256 257 258
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Power resource [%s] turned off\n",
				  resource->name));
	}
L
Linus Torvalds 已提交
259

260 261
 unlock:
	mutex_unlock(&resource->resource_lock);
L
Linus Torvalds 已提交
262

263
	return result;
L
Linus Torvalds 已提交
264 265
}

266 267 268 269 270
static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res)
{
	int i;

	for (i = num_res - 1; i >= 0 ; i--)
271
		acpi_power_off(list->handles[i]);
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
}

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;
}

295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
/**
 * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
 *                          ACPI 3.0) _PSW (Power State Wake)
 * @dev: Device to handle.
 * @enable: 0 - disable, 1 - enable the wake capabilities of the device.
 * @sleep_state: Target sleep state of the system.
 * @dev_state: Target power state of the device.
 *
 * Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
 * State Wake) for the device, if present.  On failure reset the device's
 * wakeup.flags.valid flag.
 *
 * RETURN VALUE:
 * 0 if either _DSW or _PSW has been successfully executed
 * 0 if neither _DSW nor _PSW has been found
 * -ENODEV if the execution of either _DSW or _PSW has failed
 */
int acpi_device_sleep_wake(struct acpi_device *dev,
                           int enable, int sleep_state, int dev_state)
{
	union acpi_object in_arg[3];
	struct acpi_object_list arg_list = { 3, in_arg };
	acpi_status status = AE_OK;

	/*
	 * Try to execute _DSW first.
	 *
	 * Three agruments are needed for the _DSW object:
	 * Argument 0: enable/disable the wake capabilities
	 * Argument 1: target system state
	 * Argument 2: target device state
	 * When _DSW object is called to disable the wake capabilities, maybe
	 * the first argument is filled. The values of the other two agruments
	 * are meaningless.
	 */
	in_arg[0].type = ACPI_TYPE_INTEGER;
	in_arg[0].integer.value = enable;
	in_arg[1].type = ACPI_TYPE_INTEGER;
	in_arg[1].integer.value = sleep_state;
	in_arg[2].type = ACPI_TYPE_INTEGER;
	in_arg[2].integer.value = dev_state;
	status = acpi_evaluate_object(dev->handle, "_DSW", &arg_list, NULL);
	if (ACPI_SUCCESS(status)) {
		return 0;
	} else if (status != AE_NOT_FOUND) {
		printk(KERN_ERR PREFIX "_DSW execution failed\n");
		dev->wakeup.flags.valid = 0;
		return -ENODEV;
	}

	/* Execute _PSW */
	arg_list.count = 1;
	in_arg[0].integer.value = enable;
	status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
	if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
		printk(KERN_ERR PREFIX "_PSW execution failed\n");
		dev->wakeup.flags.valid = 0;
		return -ENODEV;
	}

	return 0;
}

L
Linus Torvalds 已提交
358 359 360
/*
 * Prepare a wakeup device, two steps (Ref ACPI 2.0:P229):
 * 1. Power on the power resources required for the wakeup device 
361 362
 * 2. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
 *    State Wake) for the device, if present
L
Linus Torvalds 已提交
363
 */
364
int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state)
L
Linus Torvalds 已提交
365
{
366
	int i, err = 0;
L
Linus Torvalds 已提交
367 368

	if (!dev || !dev->wakeup.flags.valid)
369
		return -EINVAL;
L
Linus Torvalds 已提交
370

371 372 373 374
	mutex_lock(&acpi_device_lock);

	if (dev->wakeup.prepare_count++)
		goto out;
375

L
Linus Torvalds 已提交
376 377
	/* Open power resource */
	for (i = 0; i < dev->wakeup.resources.count; i++) {
378
		int ret = acpi_power_on(dev->wakeup.resources.handles[i]);
L
Linus Torvalds 已提交
379
		if (ret) {
380
			printk(KERN_ERR PREFIX "Transition power state\n");
L
Linus Torvalds 已提交
381
			dev->wakeup.flags.valid = 0;
382 383
			err = -ENODEV;
			goto err_out;
L
Linus Torvalds 已提交
384 385 386
		}
	}

387 388 389 390
	/*
	 * Passing 3 as the third argument below means the device may be placed
	 * in arbitrary power state afterwards.
	 */
391 392
	err = acpi_device_sleep_wake(dev, 1, sleep_state, 3);

393 394 395 396 397 398
 err_out:
	if (err)
		dev->wakeup.prepare_count = 0;

 out:
	mutex_unlock(&acpi_device_lock);
399
	return err;
L
Linus Torvalds 已提交
400 401 402 403
}

/*
 * Shutdown a wakeup device, counterpart of above method
404 405
 * 1. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power
 *    State Wake) for the device, if present
L
Linus Torvalds 已提交
406 407
 * 2. Shutdown down the power resources
 */
L
Len Brown 已提交
408
int acpi_disable_wakeup_device_power(struct acpi_device *dev)
L
Linus Torvalds 已提交
409
{
410
	int i, err = 0;
L
Linus Torvalds 已提交
411 412

	if (!dev || !dev->wakeup.flags.valid)
413
		return -EINVAL;
L
Linus Torvalds 已提交
414

415 416 417 418 419
	mutex_lock(&acpi_device_lock);

	if (--dev->wakeup.prepare_count > 0)
		goto out;

420
	/*
421 422
	 * Executing the code below even if prepare_count is already zero when
	 * the function is called may be useful, for example for initialisation.
423
	 */
424 425
	if (dev->wakeup.prepare_count < 0)
		dev->wakeup.prepare_count = 0;
426

427 428 429
	err = acpi_device_sleep_wake(dev, 0, 0, 0);
	if (err)
		goto out;
L
Linus Torvalds 已提交
430 431 432

	/* Close power resource */
	for (i = 0; i < dev->wakeup.resources.count; i++) {
433
		int ret = acpi_power_off(dev->wakeup.resources.handles[i]);
L
Linus Torvalds 已提交
434
		if (ret) {
435
			printk(KERN_ERR PREFIX "Transition power state\n");
L
Linus Torvalds 已提交
436
			dev->wakeup.flags.valid = 0;
437 438
			err = -ENODEV;
			goto out;
L
Linus Torvalds 已提交
439 440 441
		}
	}

442 443 444
 out:
	mutex_unlock(&acpi_device_lock);
	return err;
L
Linus Torvalds 已提交
445 446 447 448 449 450
}

/* --------------------------------------------------------------------------
                             Device Power Management
   -------------------------------------------------------------------------- */

451
int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
L
Linus Torvalds 已提交
452
{
L
Len Brown 已提交
453 454 455 456
	int result = 0;
	struct acpi_handle_list *list = NULL;
	int list_state = 0;
	int i = 0;
L
Linus Torvalds 已提交
457

458
	if (!device || !state)
459
		return -EINVAL;
L
Linus Torvalds 已提交
460 461 462 463 464

	/*
	 * We know a device's inferred power state when all the resources
	 * required for a given D-state are 'on'.
	 */
L
Len Brown 已提交
465
	for (i = ACPI_STATE_D0; i < ACPI_STATE_D3; i++) {
L
Linus Torvalds 已提交
466 467 468 469 470 471
		list = &device->power.states[i].resources;
		if (list->count < 1)
			continue;

		result = acpi_power_get_list_state(list, &list_state);
		if (result)
472
			return result;
L
Linus Torvalds 已提交
473 474

		if (list_state == ACPI_POWER_RESOURCE_STATE_ON) {
475
			*state = i;
476
			return 0;
L
Linus Torvalds 已提交
477 478 479
		}
	}

480
	*state = ACPI_STATE_D3;
481
	return 0;
L
Linus Torvalds 已提交
482 483
}

484 485 486 487 488 489 490 491
int acpi_power_on_resources(struct acpi_device *device, int state)
{
	if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
		return -EINVAL;

	return acpi_power_on_list(&device->power.states[state].resources);
}

L
Len Brown 已提交
492
int acpi_power_transition(struct acpi_device *device, int state)
L
Linus Torvalds 已提交
493
{
494
	int result;
L
Linus Torvalds 已提交
495 496

	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
497
		return -EINVAL;
L
Linus Torvalds 已提交
498

499 500 501
	if (device->power.state == state)
		return 0;

L
Len Brown 已提交
502 503
	if ((device->power.state < ACPI_STATE_D0)
	    || (device->power.state > ACPI_STATE_D3))
504
		return -ENODEV;
L
Linus Torvalds 已提交
505 506 507 508 509

	/* TBD: Resources must be ordered. */

	/*
	 * First we reference all power resources required in the target list
510 511
	 * (e.g. so the device doesn't lose power while transitioning).  Then,
	 * we dereference all power resources used in the current list.
L
Linus Torvalds 已提交
512
	 */
513 514 515 516
	result = acpi_power_on_list(&device->power.states[state].resources);
	if (!result)
		acpi_power_off_list(
			&device->power.states[device->power.state].resources);
L
Linus Torvalds 已提交
517

518 519
	/* We shouldn't change the state unless the above operations succeed. */
	device->power.state = result ? ACPI_STATE_UNKNOWN : state;
L
Linus Torvalds 已提交
520

521
	return result;
L
Linus Torvalds 已提交
522 523 524 525 526 527
}

/* --------------------------------------------------------------------------
                                Driver Interface
   -------------------------------------------------------------------------- */

L
Len Brown 已提交
528
static int acpi_power_add(struct acpi_device *device)
L
Linus Torvalds 已提交
529
{
530
	int result = 0, state;
L
Len Brown 已提交
531
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
532
	struct acpi_power_resource *resource = NULL;
L
Len Brown 已提交
533 534
	union acpi_object acpi_object;
	struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object };
L
Linus Torvalds 已提交
535 536 537


	if (!device)
538
		return -EINVAL;
L
Linus Torvalds 已提交
539

540
	resource = kzalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
L
Linus Torvalds 已提交
541
	if (!resource)
542
		return -ENOMEM;
L
Linus Torvalds 已提交
543

544
	resource->device = device;
545
	mutex_init(&resource->resource_lock);
L
Linus Torvalds 已提交
546 547 548
	strcpy(resource->name, device->pnp.bus_id);
	strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
	strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
549
	device->driver_data = resource;
L
Linus Torvalds 已提交
550 551

	/* Evalute the object to get the system level and resource order. */
552
	status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer);
L
Linus Torvalds 已提交
553 554 555 556 557 558 559
	if (ACPI_FAILURE(status)) {
		result = -ENODEV;
		goto end;
	}
	resource->system_level = acpi_object.power_resource.system_level;
	resource->order = acpi_object.power_resource.resource_order;

560
	result = acpi_power_get_state(device->handle, &state);
L
Linus Torvalds 已提交
561 562 563
	if (result)
		goto end;

564
	switch (state) {
L
Linus Torvalds 已提交
565 566 567 568 569 570 571 572 573 574 575 576
	case ACPI_POWER_RESOURCE_STATE_ON:
		device->power.state = ACPI_STATE_D0;
		break;
	case ACPI_POWER_RESOURCE_STATE_OFF:
		device->power.state = ACPI_STATE_D3;
		break;
	default:
		device->power.state = ACPI_STATE_UNKNOWN;
		break;
	}

	printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device),
577
	       acpi_device_bid(device), state ? "on" : "off");
L
Linus Torvalds 已提交
578

L
Len Brown 已提交
579
      end:
L
Linus Torvalds 已提交
580 581
	if (result)
		kfree(resource);
L
Len Brown 已提交
582

583
	return result;
L
Linus Torvalds 已提交
584 585
}

L
Len Brown 已提交
586
static int acpi_power_remove(struct acpi_device *device, int type)
L
Linus Torvalds 已提交
587
{
588
	struct acpi_power_resource *resource;
L
Linus Torvalds 已提交
589

590
	if (!device)
591
		return -EINVAL;
L
Linus Torvalds 已提交
592

593
	resource = acpi_driver_data(device);
594 595
	if (!resource)
		return -EINVAL;
596

L
Linus Torvalds 已提交
597 598
	kfree(resource);

599
	return 0;
L
Linus Torvalds 已提交
600 601
}

602
static int acpi_power_resume(struct acpi_device *device)
603
{
604
	int result = 0, state;
605
	struct acpi_power_resource *resource;
606

607
	if (!device)
608 609
		return -EINVAL;

610
	resource = acpi_driver_data(device);
611 612 613 614
	if (!resource)
		return -EINVAL;

	mutex_lock(&resource->resource_lock);
615

616
	result = acpi_power_get_state(device->handle, &state);
617
	if (result)
618
		goto unlock;
619

620 621
	if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count)
		result = __acpi_power_on(resource);
622

623
 unlock:
624
	mutex_unlock(&resource->resource_lock);
625 626

	return result;
627 628
}

629
int __init acpi_power_init(void)
L
Linus Torvalds 已提交
630 631
{
	INIT_LIST_HEAD(&acpi_power_resource_list);
632
	return acpi_bus_register_driver(&acpi_power_driver);
L
Linus Torvalds 已提交
633
}