Deleted Added
full compact
acpi_powerres.c (89054) acpi_powerres.c (91125)
1/*-
2 * Copyright (c) 2001 Michael Smith
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
1/*-
2 * Copyright (c) 2001 Michael Smith
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/acpica/acpi_powerres.c 89054 2002-01-08 06:46:01Z msmith $
26 * $FreeBSD: head/sys/dev/acpica/acpi_powerres.c 91125 2002-02-23 05:28:22Z msmith $
27 */
28
29#include "opt_acpi.h" /* XXX trim includes */
30#include <sys/param.h>
31#include <sys/kernel.h>
32#include <sys/proc.h>
33#include <sys/lock.h>
34#include <sys/malloc.h>
35#include <sys/mutex.h>
36#include <sys/bus.h>
37#include <sys/conf.h>
38#include <sys/ioccom.h>
39#include <sys/reboot.h>
40#include <sys/sysctl.h>
41#include <sys/systm.h>
42#include <sys/ctype.h>
43
44#include <machine/clock.h>
45
46#include <machine/resource.h>
47
48#include "acpi.h"
49
50#include <dev/acpica/acpivar.h>
51#include <dev/acpica/acpiio.h>
52
53/*
54 * ACPI power resource management.
55 *
56 * Power resource behaviour is slightly complicated by the fact that
57 * a single power resource may provide power for more than one device.
58 * Thus, we must track the device(s) being powered by a given power
59 * resource, and only deactivate it when there are no powered devices.
60 *
61 * Note that this only manages resources for known devices. There is an
62 * ugly case where we may turn of power to a device which is in use because
63 * we don't know that it depends on a given resource. We should perhaps
64 * try to be smarter about this, but a more complete solution would involve
65 * scanning all of the ACPI namespace to find devices we're not currently
66 * aware of, and this raises questions about whether they should be left
67 * on, turned off, etc.
68 *
69 * XXX locking
70 */
71
72MALLOC_DEFINE(M_ACPIPWR, "acpipwr", "ACPI power resources");
73
74/*
75 * Hooks for the ACPI CA debugging infrastructure
76 */
77#define _COMPONENT ACPI_POWER
27 */
28
29#include "opt_acpi.h" /* XXX trim includes */
30#include <sys/param.h>
31#include <sys/kernel.h>
32#include <sys/proc.h>
33#include <sys/lock.h>
34#include <sys/malloc.h>
35#include <sys/mutex.h>
36#include <sys/bus.h>
37#include <sys/conf.h>
38#include <sys/ioccom.h>
39#include <sys/reboot.h>
40#include <sys/sysctl.h>
41#include <sys/systm.h>
42#include <sys/ctype.h>
43
44#include <machine/clock.h>
45
46#include <machine/resource.h>
47
48#include "acpi.h"
49
50#include <dev/acpica/acpivar.h>
51#include <dev/acpica/acpiio.h>
52
53/*
54 * ACPI power resource management.
55 *
56 * Power resource behaviour is slightly complicated by the fact that
57 * a single power resource may provide power for more than one device.
58 * Thus, we must track the device(s) being powered by a given power
59 * resource, and only deactivate it when there are no powered devices.
60 *
61 * Note that this only manages resources for known devices. There is an
62 * ugly case where we may turn of power to a device which is in use because
63 * we don't know that it depends on a given resource. We should perhaps
64 * try to be smarter about this, but a more complete solution would involve
65 * scanning all of the ACPI namespace to find devices we're not currently
66 * aware of, and this raises questions about whether they should be left
67 * on, turned off, etc.
68 *
69 * XXX locking
70 */
71
72MALLOC_DEFINE(M_ACPIPWR, "acpipwr", "ACPI power resources");
73
74/*
75 * Hooks for the ACPI CA debugging infrastructure
76 */
77#define _COMPONENT ACPI_POWER
78MODULE_NAME("POWERRES")
78ACPI_MODULE_NAME("POWERRES")
79
80/* return values from _STA on a power resource */
81#define ACPI_PWR_OFF 0
82#define ACPI_PWR_ON 1
83
84/*
85 * A relationship between a power resource and a consumer.
86 */
87struct acpi_powerreference {
88 struct acpi_powerconsumer *ar_consumer;
89 struct acpi_powerresource *ar_resource;
90 TAILQ_ENTRY(acpi_powerreference) ar_rlink; /* link on resource list */
91 TAILQ_ENTRY(acpi_powerreference) ar_clink; /* link on consumer */
92};
93
94/*
95 * A power-managed device.
96 */
97struct acpi_powerconsumer {
98 ACPI_HANDLE ac_consumer; /* device which is powered */
99 int ac_state;
100 TAILQ_ENTRY(acpi_powerconsumer) ac_link;
101 TAILQ_HEAD(,acpi_powerreference) ac_references;
102};
103
104/*
105 * A power resource.
106 */
107struct acpi_powerresource {
108 TAILQ_ENTRY(acpi_powerresource) ap_link;
109 TAILQ_HEAD(,acpi_powerreference) ap_references;
110 ACPI_HANDLE ap_resource; /* the resource's handle */
111 ACPI_INTEGER ap_systemlevel;
112 ACPI_INTEGER ap_order;
113};
114
115static TAILQ_HEAD(acpi_powerresource_list, acpi_powerresource) acpi_powerresources;
116static TAILQ_HEAD(acpi_powerconsumer_list, acpi_powerconsumer) acpi_powerconsumers;
117
118static ACPI_STATUS acpi_pwr_register_consumer(ACPI_HANDLE consumer);
119static ACPI_STATUS acpi_pwr_deregister_consumer(ACPI_HANDLE consumer);
120static ACPI_STATUS acpi_pwr_register_resource(ACPI_HANDLE res);
121static ACPI_STATUS acpi_pwr_deregister_resource(ACPI_HANDLE res);
122static void acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg);
123static ACPI_STATUS acpi_pwr_switch_power(void);
124static struct acpi_powerresource *acpi_pwr_find_resource(ACPI_HANDLE res);
125static struct acpi_powerconsumer *acpi_pwr_find_consumer(ACPI_HANDLE consumer);
126
127/*
128 * Initialise our lists.
129 */
130static void
131acpi_pwr_init(void *junk)
132{
133 TAILQ_INIT(&acpi_powerresources);
134 TAILQ_INIT(&acpi_powerconsumers);
135}
136SYSINIT(acpi_powerresource, SI_SUB_TUNABLES, SI_ORDER_ANY, acpi_pwr_init, NULL);
137
138/*
139 * Register a power resource.
140 *
141 * It's OK to call this if we already know about the resource.
142 */
143static ACPI_STATUS
144acpi_pwr_register_resource(ACPI_HANDLE res)
145{
146 ACPI_STATUS status;
147 ACPI_BUFFER buf;
148 ACPI_OBJECT *obj;
149 struct acpi_powerresource *rp, *srp;
150
79
80/* return values from _STA on a power resource */
81#define ACPI_PWR_OFF 0
82#define ACPI_PWR_ON 1
83
84/*
85 * A relationship between a power resource and a consumer.
86 */
87struct acpi_powerreference {
88 struct acpi_powerconsumer *ar_consumer;
89 struct acpi_powerresource *ar_resource;
90 TAILQ_ENTRY(acpi_powerreference) ar_rlink; /* link on resource list */
91 TAILQ_ENTRY(acpi_powerreference) ar_clink; /* link on consumer */
92};
93
94/*
95 * A power-managed device.
96 */
97struct acpi_powerconsumer {
98 ACPI_HANDLE ac_consumer; /* device which is powered */
99 int ac_state;
100 TAILQ_ENTRY(acpi_powerconsumer) ac_link;
101 TAILQ_HEAD(,acpi_powerreference) ac_references;
102};
103
104/*
105 * A power resource.
106 */
107struct acpi_powerresource {
108 TAILQ_ENTRY(acpi_powerresource) ap_link;
109 TAILQ_HEAD(,acpi_powerreference) ap_references;
110 ACPI_HANDLE ap_resource; /* the resource's handle */
111 ACPI_INTEGER ap_systemlevel;
112 ACPI_INTEGER ap_order;
113};
114
115static TAILQ_HEAD(acpi_powerresource_list, acpi_powerresource) acpi_powerresources;
116static TAILQ_HEAD(acpi_powerconsumer_list, acpi_powerconsumer) acpi_powerconsumers;
117
118static ACPI_STATUS acpi_pwr_register_consumer(ACPI_HANDLE consumer);
119static ACPI_STATUS acpi_pwr_deregister_consumer(ACPI_HANDLE consumer);
120static ACPI_STATUS acpi_pwr_register_resource(ACPI_HANDLE res);
121static ACPI_STATUS acpi_pwr_deregister_resource(ACPI_HANDLE res);
122static void acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg);
123static ACPI_STATUS acpi_pwr_switch_power(void);
124static struct acpi_powerresource *acpi_pwr_find_resource(ACPI_HANDLE res);
125static struct acpi_powerconsumer *acpi_pwr_find_consumer(ACPI_HANDLE consumer);
126
127/*
128 * Initialise our lists.
129 */
130static void
131acpi_pwr_init(void *junk)
132{
133 TAILQ_INIT(&acpi_powerresources);
134 TAILQ_INIT(&acpi_powerconsumers);
135}
136SYSINIT(acpi_powerresource, SI_SUB_TUNABLES, SI_ORDER_ANY, acpi_pwr_init, NULL);
137
138/*
139 * Register a power resource.
140 *
141 * It's OK to call this if we already know about the resource.
142 */
143static ACPI_STATUS
144acpi_pwr_register_resource(ACPI_HANDLE res)
145{
146 ACPI_STATUS status;
147 ACPI_BUFFER buf;
148 ACPI_OBJECT *obj;
149 struct acpi_powerresource *rp, *srp;
150
151 FUNCTION_TRACE(__func__);
151 ACPI_FUNCTION_TRACE(__func__);
152
153 rp = NULL;
152
153 rp = NULL;
154 obj = NULL;
154 buf.Pointer = NULL;
155
156 /* look to see if we know about this resource */
157 if (acpi_pwr_find_resource(res) != NULL)
158 return_ACPI_STATUS(AE_OK); /* already know about it */
159
160 /* allocate a new resource */
161 if ((rp = malloc(sizeof(*rp), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) {
162 status = AE_NO_MEMORY;
163 goto out;
164 }
165 TAILQ_INIT(&rp->ap_references);
166 rp->ap_resource = res;
167
168 /* get the Power Resource object */
155
156 /* look to see if we know about this resource */
157 if (acpi_pwr_find_resource(res) != NULL)
158 return_ACPI_STATUS(AE_OK); /* already know about it */
159
160 /* allocate a new resource */
161 if ((rp = malloc(sizeof(*rp), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) {
162 status = AE_NO_MEMORY;
163 goto out;
164 }
165 TAILQ_INIT(&rp->ap_references);
166 rp->ap_resource = res;
167
168 /* get the Power Resource object */
169 bzero(&buf, sizeof(buf));
170 if ((status = acpi_EvaluateIntoBuffer(res, NULL, NULL, &buf)) != AE_OK) {
169 buf.Length = ACPI_ALLOCATE_BUFFER;
170 if (ACPI_FAILURE(status = AcpiEvaluateObject(res, NULL, NULL, &buf))) {
171 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "no power resource object\n"));
172 goto out;
173 }
174 obj = buf.Pointer;
175 if (obj->Type != ACPI_TYPE_POWER) {
176 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "questionable power resource object %s\n", acpi_name(res)));
177 status = AE_TYPE;
178 goto out;
179 }
180 rp->ap_systemlevel = obj->PowerResource.SystemLevel;
181 rp->ap_order = obj->PowerResource.ResourceOrder;
182
183 /* sort the resource into the list */
184 status = AE_OK;
185 srp = TAILQ_FIRST(&acpi_powerresources);
186 if ((srp == NULL) || (rp->ap_order < srp->ap_order)) {
187 TAILQ_INSERT_HEAD(&acpi_powerresources, rp, ap_link);
188 goto done;
189 }
190 TAILQ_FOREACH(srp, &acpi_powerresources, ap_link)
191 if (rp->ap_order < srp->ap_order) {
192 TAILQ_INSERT_BEFORE(srp, rp, ap_link);
193 goto done;
194 }
195 TAILQ_INSERT_TAIL(&acpi_powerresources, rp, ap_link);
196
197 done:
198 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "registered power resource %s\n", acpi_name(res)));
199 out:
171 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "no power resource object\n"));
172 goto out;
173 }
174 obj = buf.Pointer;
175 if (obj->Type != ACPI_TYPE_POWER) {
176 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "questionable power resource object %s\n", acpi_name(res)));
177 status = AE_TYPE;
178 goto out;
179 }
180 rp->ap_systemlevel = obj->PowerResource.SystemLevel;
181 rp->ap_order = obj->PowerResource.ResourceOrder;
182
183 /* sort the resource into the list */
184 status = AE_OK;
185 srp = TAILQ_FIRST(&acpi_powerresources);
186 if ((srp == NULL) || (rp->ap_order < srp->ap_order)) {
187 TAILQ_INSERT_HEAD(&acpi_powerresources, rp, ap_link);
188 goto done;
189 }
190 TAILQ_FOREACH(srp, &acpi_powerresources, ap_link)
191 if (rp->ap_order < srp->ap_order) {
192 TAILQ_INSERT_BEFORE(srp, rp, ap_link);
193 goto done;
194 }
195 TAILQ_INSERT_TAIL(&acpi_powerresources, rp, ap_link);
196
197 done:
198 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "registered power resource %s\n", acpi_name(res)));
199 out:
200 if (obj != NULL)
201 AcpiOsFree(obj);
202 if ((status != AE_OK) && (rp != NULL))
200 if (buf.Pointer != NULL)
201 AcpiOsFree(buf.Pointer);
202 if (ACPI_FAILURE(status) && (rp != NULL))
203 free(rp, M_ACPIPWR);
204 return_ACPI_STATUS(status);
205}
206
207/*
208 * Deregister a power resource.
209 */
210static ACPI_STATUS
211acpi_pwr_deregister_resource(ACPI_HANDLE res)
212{
213 struct acpi_powerresource *rp;
214
203 free(rp, M_ACPIPWR);
204 return_ACPI_STATUS(status);
205}
206
207/*
208 * Deregister a power resource.
209 */
210static ACPI_STATUS
211acpi_pwr_deregister_resource(ACPI_HANDLE res)
212{
213 struct acpi_powerresource *rp;
214
215 FUNCTION_TRACE(__func__);
215 ACPI_FUNCTION_TRACE(__func__);
216
217 rp = NULL;
218
219 /* find the resource */
220 if ((rp = acpi_pwr_find_resource(res)) == NULL)
221 return_ACPI_STATUS(AE_BAD_PARAMETER);
222
223 /* check that there are no consumers referencing this resource */
224 if (TAILQ_FIRST(&rp->ap_references) != NULL)
225 return_ACPI_STATUS(AE_BAD_PARAMETER);
226
227 /* pull it off the list and free it */
228 TAILQ_REMOVE(&acpi_powerresources, rp, ap_link);
229 free(rp, M_ACPIPWR);
230
231 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "deregistered power resource %s\n", acpi_name(res)));
232
233 return_ACPI_STATUS(AE_OK);
234}
235
236/*
237 * Register a power consumer.
238 *
239 * It's OK to call this if we already know about the consumer.
240 */
241static ACPI_STATUS
242acpi_pwr_register_consumer(ACPI_HANDLE consumer)
243{
244 struct acpi_powerconsumer *pc;
245
216
217 rp = NULL;
218
219 /* find the resource */
220 if ((rp = acpi_pwr_find_resource(res)) == NULL)
221 return_ACPI_STATUS(AE_BAD_PARAMETER);
222
223 /* check that there are no consumers referencing this resource */
224 if (TAILQ_FIRST(&rp->ap_references) != NULL)
225 return_ACPI_STATUS(AE_BAD_PARAMETER);
226
227 /* pull it off the list and free it */
228 TAILQ_REMOVE(&acpi_powerresources, rp, ap_link);
229 free(rp, M_ACPIPWR);
230
231 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "deregistered power resource %s\n", acpi_name(res)));
232
233 return_ACPI_STATUS(AE_OK);
234}
235
236/*
237 * Register a power consumer.
238 *
239 * It's OK to call this if we already know about the consumer.
240 */
241static ACPI_STATUS
242acpi_pwr_register_consumer(ACPI_HANDLE consumer)
243{
244 struct acpi_powerconsumer *pc;
245
246 FUNCTION_TRACE(__func__);
246 ACPI_FUNCTION_TRACE(__func__);
247
248 /* check to see whether we know about this consumer already */
249 if ((pc = acpi_pwr_find_consumer(consumer)) != NULL)
250 return_ACPI_STATUS(AE_OK);
251
252 /* allocate a new power consumer */
253 if ((pc = malloc(sizeof(*pc), M_ACPIPWR, M_NOWAIT)) == NULL)
254 return_ACPI_STATUS(AE_NO_MEMORY);
255 TAILQ_INSERT_HEAD(&acpi_powerconsumers, pc, ac_link);
256 TAILQ_INIT(&pc->ac_references);
257 pc->ac_consumer = consumer;
258
259 pc->ac_state = ACPI_STATE_UNKNOWN; /* XXX we should try to find its current state */
260
261 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "registered power consumer %s\n", acpi_name(consumer)));
262
263 return_ACPI_STATUS(AE_OK);
264}
265
266/*
267 * Deregister a power consumer.
268 *
269 * This should only be done once the consumer has been powered off.
270 * (XXX is this correct? Check once implemented)
271 */
272static ACPI_STATUS
273acpi_pwr_deregister_consumer(ACPI_HANDLE consumer)
274{
275 struct acpi_powerconsumer *pc;
276
247
248 /* check to see whether we know about this consumer already */
249 if ((pc = acpi_pwr_find_consumer(consumer)) != NULL)
250 return_ACPI_STATUS(AE_OK);
251
252 /* allocate a new power consumer */
253 if ((pc = malloc(sizeof(*pc), M_ACPIPWR, M_NOWAIT)) == NULL)
254 return_ACPI_STATUS(AE_NO_MEMORY);
255 TAILQ_INSERT_HEAD(&acpi_powerconsumers, pc, ac_link);
256 TAILQ_INIT(&pc->ac_references);
257 pc->ac_consumer = consumer;
258
259 pc->ac_state = ACPI_STATE_UNKNOWN; /* XXX we should try to find its current state */
260
261 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "registered power consumer %s\n", acpi_name(consumer)));
262
263 return_ACPI_STATUS(AE_OK);
264}
265
266/*
267 * Deregister a power consumer.
268 *
269 * This should only be done once the consumer has been powered off.
270 * (XXX is this correct? Check once implemented)
271 */
272static ACPI_STATUS
273acpi_pwr_deregister_consumer(ACPI_HANDLE consumer)
274{
275 struct acpi_powerconsumer *pc;
276
277 FUNCTION_TRACE(__func__);
277 ACPI_FUNCTION_TRACE(__func__);
278
279 /* find the consumer */
280 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL)
281 return_ACPI_STATUS(AE_BAD_PARAMETER);
282
283 /* make sure the consumer's not referencing anything right now */
284 if (TAILQ_FIRST(&pc->ac_references) != NULL)
285 return_ACPI_STATUS(AE_BAD_PARAMETER);
286
287 /* pull the consumer off the list and free it */
288 TAILQ_REMOVE(&acpi_powerconsumers, pc, ac_link);
289
290 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "deregistered power consumer %s\n", acpi_name(consumer)));
291
292 return_ACPI_STATUS(AE_OK);
293}
294
295/*
296 * Set a power consumer to a particular power state.
297 */
298ACPI_STATUS
299acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
300{
301 struct acpi_powerconsumer *pc;
302 struct acpi_powerreference *pr;
303 ACPI_HANDLE method_handle, reslist_handle, pr0_handle;
304 ACPI_BUFFER reslist_buffer;
305 ACPI_OBJECT *reslist_object;
306 ACPI_STATUS status;
307 char *method_name, *reslist_name;
308 int res_changed;
309
278
279 /* find the consumer */
280 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL)
281 return_ACPI_STATUS(AE_BAD_PARAMETER);
282
283 /* make sure the consumer's not referencing anything right now */
284 if (TAILQ_FIRST(&pc->ac_references) != NULL)
285 return_ACPI_STATUS(AE_BAD_PARAMETER);
286
287 /* pull the consumer off the list and free it */
288 TAILQ_REMOVE(&acpi_powerconsumers, pc, ac_link);
289
290 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "deregistered power consumer %s\n", acpi_name(consumer)));
291
292 return_ACPI_STATUS(AE_OK);
293}
294
295/*
296 * Set a power consumer to a particular power state.
297 */
298ACPI_STATUS
299acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
300{
301 struct acpi_powerconsumer *pc;
302 struct acpi_powerreference *pr;
303 ACPI_HANDLE method_handle, reslist_handle, pr0_handle;
304 ACPI_BUFFER reslist_buffer;
305 ACPI_OBJECT *reslist_object;
306 ACPI_STATUS status;
307 char *method_name, *reslist_name;
308 int res_changed;
309
310 FUNCTION_TRACE(__func__);
310 ACPI_FUNCTION_TRACE(__func__);
311
312 /* find the consumer */
313 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) {
311
312 /* find the consumer */
313 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) {
314 if ((status = acpi_pwr_register_consumer(consumer)) != AE_OK)
314 if (ACPI_FAILURE(status = acpi_pwr_register_consumer(consumer)))
315 return_ACPI_STATUS(status);
316 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) {
317 return_ACPI_STATUS(AE_ERROR); /* something very wrong */
318 }
319 }
320
321 /* check for valid transitions */
322 if ((pc->ac_state == ACPI_STATE_D3) && (state != ACPI_STATE_D0))
323 return_ACPI_STATUS(AE_BAD_PARAMETER); /* can only go to D0 from D3 */
324
325 /* find transition mechanism(s) */
326 switch(state) {
327 case ACPI_STATE_D0:
328 method_name = "_PS0";
329 reslist_name = "_PR0";
330 break;
331 case ACPI_STATE_D1:
332 method_name = "_PS1";
333 reslist_name = "_PR1";
334 break;
335 case ACPI_STATE_D2:
336 method_name = "_PS2";
337 reslist_name = "_PR2";
338 break;
339 case ACPI_STATE_D3:
340 method_name = "_PS3";
341 reslist_name = "_PR3";
342 break;
343 default:
344 return_ACPI_STATUS(AE_BAD_PARAMETER);
345 }
346 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "setup to switch %s D%d -> D%d\n",
347 acpi_name(consumer), pc->ac_state, state));
348
349 /*
350 * Verify that this state is supported, ie. one of method or
351 * reslist must be present. We need to do this before we go
352 * dereferencing resources (since we might be trying to go to
353 * a state we don't support).
354 *
355 * Note that if any states are supported, the device has to
356 * support D0 and D3. It's never an error to try to go to
357 * D0.
358 */
315 return_ACPI_STATUS(status);
316 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) {
317 return_ACPI_STATUS(AE_ERROR); /* something very wrong */
318 }
319 }
320
321 /* check for valid transitions */
322 if ((pc->ac_state == ACPI_STATE_D3) && (state != ACPI_STATE_D0))
323 return_ACPI_STATUS(AE_BAD_PARAMETER); /* can only go to D0 from D3 */
324
325 /* find transition mechanism(s) */
326 switch(state) {
327 case ACPI_STATE_D0:
328 method_name = "_PS0";
329 reslist_name = "_PR0";
330 break;
331 case ACPI_STATE_D1:
332 method_name = "_PS1";
333 reslist_name = "_PR1";
334 break;
335 case ACPI_STATE_D2:
336 method_name = "_PS2";
337 reslist_name = "_PR2";
338 break;
339 case ACPI_STATE_D3:
340 method_name = "_PS3";
341 reslist_name = "_PR3";
342 break;
343 default:
344 return_ACPI_STATUS(AE_BAD_PARAMETER);
345 }
346 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "setup to switch %s D%d -> D%d\n",
347 acpi_name(consumer), pc->ac_state, state));
348
349 /*
350 * Verify that this state is supported, ie. one of method or
351 * reslist must be present. We need to do this before we go
352 * dereferencing resources (since we might be trying to go to
353 * a state we don't support).
354 *
355 * Note that if any states are supported, the device has to
356 * support D0 and D3. It's never an error to try to go to
357 * D0.
358 */
359 reslist_buffer.Pointer = NULL;
359 reslist_object = NULL;
360 reslist_object = NULL;
360 if (AcpiGetHandle(consumer, method_name, &method_handle) != AE_OK)
361 if (ACPI_FAILURE(AcpiGetHandle(consumer, method_name, &method_handle)))
361 method_handle = NULL;
362 method_handle = NULL;
362 if (AcpiGetHandle(consumer, reslist_name, &reslist_handle) != AE_OK)
363 if (ACPI_FAILURE(AcpiGetHandle(consumer, reslist_name, &reslist_handle)))
363 reslist_handle = NULL;
364 if ((reslist_handle == NULL) && (method_handle == NULL)) {
365 if (state == ACPI_STATE_D0) {
366 pc->ac_state = ACPI_STATE_D0;
367 return_ACPI_STATUS(AE_OK);
368 }
369 if (state != ACPI_STATE_D3) {
370 goto bad;
371 }
372
373 /* turn off the resources listed in _PR0 to go to D3. */
364 reslist_handle = NULL;
365 if ((reslist_handle == NULL) && (method_handle == NULL)) {
366 if (state == ACPI_STATE_D0) {
367 pc->ac_state = ACPI_STATE_D0;
368 return_ACPI_STATUS(AE_OK);
369 }
370 if (state != ACPI_STATE_D3) {
371 goto bad;
372 }
373
374 /* turn off the resources listed in _PR0 to go to D3. */
374 if (AcpiGetHandle(consumer, "_PR0", &pr0_handle) != AE_OK) {
375 if (ACPI_FAILURE(AcpiGetHandle(consumer, "_PR0", &pr0_handle))) {
375 goto bad;
376 }
376 goto bad;
377 }
377 bzero(&reslist_buffer, sizeof(reslist_buffer));
378 status = acpi_EvaluateIntoBuffer(pr0_handle, NULL, NULL, &reslist_buffer);
379 if (status != AE_OK) {
378 reslist_buffer.Length = ACPI_ALLOCATE_BUFFER;
379 if (ACPI_FAILURE(status = AcpiEvaluateObject(pr0_handle, NULL, NULL, &reslist_buffer))) {
380 goto bad;
381 }
382 reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer;
383 if ((reslist_object->Type != ACPI_TYPE_PACKAGE) ||
384 (reslist_object->Package.Count == 0)) {
385 goto bad;
386 }
380 goto bad;
381 }
382 reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer;
383 if ((reslist_object->Type != ACPI_TYPE_PACKAGE) ||
384 (reslist_object->Package.Count == 0)) {
385 goto bad;
386 }
387 AcpiOsFree(reslist_object);
387 AcpiOsFree(reslist_buffer.Pointer);
388 reslist_buffer.Pointer = NULL;
389 reslist_object = NULL;
388 }
389
390 /*
391 * Check that we can actually fetch the list of power resources
392 */
393 if (reslist_handle != NULL) {
390 }
391
392 /*
393 * Check that we can actually fetch the list of power resources
394 */
395 if (reslist_handle != NULL) {
394 bzero(&reslist_buffer, sizeof(reslist_buffer));
395 if ((status = acpi_EvaluateIntoBuffer(reslist_handle, NULL, NULL, &reslist_buffer)) != AE_OK) {
396 reslist_buffer.Length = ACPI_ALLOCATE_BUFFER;
397 if (ACPI_FAILURE(status = AcpiEvaluateObject(reslist_handle, NULL, NULL, &reslist_buffer))) {
396 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't evaluate resource list %s\n",
397 acpi_name(reslist_handle)));
398 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't evaluate resource list %s\n",
399 acpi_name(reslist_handle)));
398 return_ACPI_STATUS(status);
400 goto out;
399 }
400 reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer;
401 if (reslist_object->Type != ACPI_TYPE_PACKAGE) {
402 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "resource list is not ACPI_TYPE_PACKAGE (%d)\n",
403 reslist_object->Type));
401 }
402 reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer;
403 if (reslist_object->Type != ACPI_TYPE_PACKAGE) {
404 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "resource list is not ACPI_TYPE_PACKAGE (%d)\n",
405 reslist_object->Type));
404 return_ACPI_STATUS(AE_TYPE);
406 status = AE_TYPE;
407 goto out;
405 }
408 }
406 } else {
407 reslist_object = NULL;
408 }
409
410 /*
411 * Now we are ready to switch, so kill off any current power resource references.
412 */
413 res_changed = 0;
414 while((pr = TAILQ_FIRST(&pc->ac_references)) != NULL) {
415 res_changed = 1;
416 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "removing reference to %s\n", acpi_name(pr->ar_resource->ap_resource)));
417 TAILQ_REMOVE(&pr->ar_resource->ap_references, pr, ar_rlink);
418 TAILQ_REMOVE(&pc->ac_references, pr, ar_clink);
419 free(pr, M_ACPIPWR);
420 }
421
422 /*
423 * Add new power resource references, if we have any. Traverse the
424 * package that we got from evaluating reslist_handle, and look up each
425 * of the resources that are referenced.
426 */
427 if (reslist_object != NULL) {
428 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "referencing %d new resources\n",
429 reslist_object->Package.Count));
430 acpi_ForeachPackageObject(reslist_object, acpi_pwr_reference_resource, pc);
431 res_changed = 1;
432 }
433
434 /*
435 * If we changed anything in the resource list, we need to run a switch
436 * pass now.
437 */
409 }
410
411 /*
412 * Now we are ready to switch, so kill off any current power resource references.
413 */
414 res_changed = 0;
415 while((pr = TAILQ_FIRST(&pc->ac_references)) != NULL) {
416 res_changed = 1;
417 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "removing reference to %s\n", acpi_name(pr->ar_resource->ap_resource)));
418 TAILQ_REMOVE(&pr->ar_resource->ap_references, pr, ar_rlink);
419 TAILQ_REMOVE(&pc->ac_references, pr, ar_clink);
420 free(pr, M_ACPIPWR);
421 }
422
423 /*
424 * Add new power resource references, if we have any. Traverse the
425 * package that we got from evaluating reslist_handle, and look up each
426 * of the resources that are referenced.
427 */
428 if (reslist_object != NULL) {
429 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "referencing %d new resources\n",
430 reslist_object->Package.Count));
431 acpi_ForeachPackageObject(reslist_object, acpi_pwr_reference_resource, pc);
432 res_changed = 1;
433 }
434
435 /*
436 * If we changed anything in the resource list, we need to run a switch
437 * pass now.
438 */
438 if ((status = acpi_pwr_switch_power()) != AE_OK) {
439 if (ACPI_FAILURE(status = acpi_pwr_switch_power())) {
439 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to correctly switch resources to move %s to D%d\n",
440 acpi_name(consumer), state));
440 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to correctly switch resources to move %s to D%d\n",
441 acpi_name(consumer), state));
441 return_ACPI_STATUS(status); /* XXX is this appropriate? Should we return to previous state? */
442 goto out; /* XXX is this appropriate? Should we return to previous state? */
442 }
443
444 /* invoke power state switch method (if present) */
445 if (method_handle != NULL) {
446 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "invoking state transition method %s\n",
447 acpi_name(method_handle)));
443 }
444
445 /* invoke power state switch method (if present) */
446 if (method_handle != NULL) {
447 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "invoking state transition method %s\n",
448 acpi_name(method_handle)));
448 if ((status = AcpiEvaluateObject(method_handle, NULL, NULL, NULL)) != AE_OK)
449 pc->ac_state = ACPI_STATE_UNKNOWN;
450 return_ACPI_STATUS(status); /* XXX is this appropriate? Should we return to previous state? */
449 if (ACPI_FAILURE(status = AcpiEvaluateObject(method_handle, NULL, NULL, NULL))) {
450 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to set state - %s\n",
451 AcpiFormatException(status)));
452 pc->ac_state = ACPI_STATE_UNKNOWN;
453 goto out; /* XXX Should we return to previous state? */
454 }
451 }
455 }
452
456
453 /* transition was successful */
454 pc->ac_state = state;
455 return_ACPI_STATUS(AE_OK);
456
457 bad:
458 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "attempt to set unsupported state D%d\n",
459 state));
457 /* transition was successful */
458 pc->ac_state = state;
459 return_ACPI_STATUS(AE_OK);
460
461 bad:
462 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "attempt to set unsupported state D%d\n",
463 state));
460 if (reslist_object)
461 AcpiOsFree(reslist_object);
462 return_ACPI_STATUS(AE_BAD_PARAMETER);
464 status = AE_BAD_PARAMETER;
465
466 out:
467 if (reslist_buffer.Pointer != NULL)
468 AcpiOsFree(reslist_buffer.Pointer);
469 return_ACPI_STATUS(status);
463}
464
465/*
466 * Called to create a reference between a power consumer and a power resource
467 * identified in the object.
468 */
469static void
470acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg)
471{
472 struct acpi_powerconsumer *pc = (struct acpi_powerconsumer *)arg;
473 struct acpi_powerreference *pr;
474 struct acpi_powerresource *rp;
475 ACPI_HANDLE res;
476 ACPI_STATUS status;
477
470}
471
472/*
473 * Called to create a reference between a power consumer and a power resource
474 * identified in the object.
475 */
476static void
477acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg)
478{
479 struct acpi_powerconsumer *pc = (struct acpi_powerconsumer *)arg;
480 struct acpi_powerreference *pr;
481 struct acpi_powerresource *rp;
482 ACPI_HANDLE res;
483 ACPI_STATUS status;
484
478 FUNCTION_TRACE(__func__);
485 ACPI_FUNCTION_TRACE(__func__);
479
480 /* check the object type */
481 if (obj->Type != ACPI_TYPE_STRING) {
482 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "don't know how to create a power reference to object type %d\n",
483 obj->Type));
484 return_VOID;
485 }
486
487 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "building reference from %s to %s\n",
488 acpi_name(pc->ac_consumer), obj->String.Pointer));
489
490 /* get the handle of the resource */
491 if (ACPI_FAILURE(status = AcpiGetHandle(NULL, obj->String.Pointer, &res))) {
492 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "couldn't find power resource %s\n",
493 obj->String.Pointer));
494 return_VOID;
495 }
496
497 /* create/look up the resource */
498 if (ACPI_FAILURE(status = acpi_pwr_register_resource(res))) {
499 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "couldn't register power resource %s - %s\n",
500 obj->String.Pointer, AcpiFormatException(status)));
501 return_VOID;
502 }
503 if ((rp = acpi_pwr_find_resource(res)) == NULL) {
504 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "power resource list corrupted\n"));
505 return_VOID;
506 }
507 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "found power resource %s\n", acpi_name(rp->ap_resource)));
508
509 /* create a reference between the consumer and resource */
510 if ((pr = malloc(sizeof(*pr), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) {
511 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "couldn't allocate memory for a power consumer reference\n"));
512 return_VOID;
513 }
514 pr->ar_consumer = pc;
515 pr->ar_resource = rp;
516 TAILQ_INSERT_TAIL(&pc->ac_references, pr, ar_clink);
517 TAILQ_INSERT_TAIL(&rp->ap_references, pr, ar_rlink);
518
519 return_VOID;
520}
521
522
523/*
524 * Switch power resources to conform to the desired state.
525 *
526 * Consumers may have modified the power resource list in an arbitrary
527 * fashion; we sweep it in sequence order.
528 */
529static ACPI_STATUS
530acpi_pwr_switch_power(void)
531{
532 struct acpi_powerresource *rp;
533 ACPI_STATUS status;
534 int cur;
535
486
487 /* check the object type */
488 if (obj->Type != ACPI_TYPE_STRING) {
489 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "don't know how to create a power reference to object type %d\n",
490 obj->Type));
491 return_VOID;
492 }
493
494 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "building reference from %s to %s\n",
495 acpi_name(pc->ac_consumer), obj->String.Pointer));
496
497 /* get the handle of the resource */
498 if (ACPI_FAILURE(status = AcpiGetHandle(NULL, obj->String.Pointer, &res))) {
499 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "couldn't find power resource %s\n",
500 obj->String.Pointer));
501 return_VOID;
502 }
503
504 /* create/look up the resource */
505 if (ACPI_FAILURE(status = acpi_pwr_register_resource(res))) {
506 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "couldn't register power resource %s - %s\n",
507 obj->String.Pointer, AcpiFormatException(status)));
508 return_VOID;
509 }
510 if ((rp = acpi_pwr_find_resource(res)) == NULL) {
511 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "power resource list corrupted\n"));
512 return_VOID;
513 }
514 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "found power resource %s\n", acpi_name(rp->ap_resource)));
515
516 /* create a reference between the consumer and resource */
517 if ((pr = malloc(sizeof(*pr), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) {
518 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "couldn't allocate memory for a power consumer reference\n"));
519 return_VOID;
520 }
521 pr->ar_consumer = pc;
522 pr->ar_resource = rp;
523 TAILQ_INSERT_TAIL(&pc->ac_references, pr, ar_clink);
524 TAILQ_INSERT_TAIL(&rp->ap_references, pr, ar_rlink);
525
526 return_VOID;
527}
528
529
530/*
531 * Switch power resources to conform to the desired state.
532 *
533 * Consumers may have modified the power resource list in an arbitrary
534 * fashion; we sweep it in sequence order.
535 */
536static ACPI_STATUS
537acpi_pwr_switch_power(void)
538{
539 struct acpi_powerresource *rp;
540 ACPI_STATUS status;
541 int cur;
542
536 FUNCTION_TRACE(__func__);
543 ACPI_FUNCTION_TRACE(__func__);
537
538 /*
539 * Sweep the list forwards turning things on.
540 */
541 TAILQ_FOREACH(rp, &acpi_powerresources, ap_link) {
542 if (TAILQ_FIRST(&rp->ap_references) == NULL) {
543 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s has no references, not turning on\n",
544 acpi_name(rp->ap_resource)));
545 continue;
546 }
547
548 /* we could cache this if we trusted it not to change under us */
544
545 /*
546 * Sweep the list forwards turning things on.
547 */
548 TAILQ_FOREACH(rp, &acpi_powerresources, ap_link) {
549 if (TAILQ_FIRST(&rp->ap_references) == NULL) {
550 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s has no references, not turning on\n",
551 acpi_name(rp->ap_resource)));
552 continue;
553 }
554
555 /* we could cache this if we trusted it not to change under us */
549 if ((status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur)) != AE_OK) {
556 if (ACPI_FAILURE(status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur))) {
550 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get status of %s - %d\n",
551 acpi_name(rp->ap_resource), status));
552 continue; /* XXX is this correct? Always switch if in doubt? */
553 }
554
555 /*
556 * Switch if required. Note that we ignore the result of the switch
557 * effort; we don't know what to do if it fails, so checking wouldn't
558 * help much.
559 */
560 if (cur != ACPI_PWR_ON) {
561 if (ACPI_FAILURE(status = AcpiEvaluateObject(rp->ap_resource, "_ON", NULL, NULL))) {
562 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to switch %s on - %s\n",
563 acpi_name(rp->ap_resource), AcpiFormatException(status)));
564 } else {
565 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s on\n", acpi_name(rp->ap_resource)));
566 }
567 } else {
568 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s is already on\n", acpi_name(rp->ap_resource)));
569 }
570 }
571
572 /*
573 * Sweep the list backwards turning things off.
574 */
575 TAILQ_FOREACH_REVERSE(rp, &acpi_powerresources, acpi_powerresource_list, ap_link) {
576 if (TAILQ_FIRST(&rp->ap_references) != NULL) {
577 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s has references, not turning off\n",
578 acpi_name(rp->ap_resource)));
579 continue;
580 }
581
582 /* we could cache this if we trusted it not to change under us */
557 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get status of %s - %d\n",
558 acpi_name(rp->ap_resource), status));
559 continue; /* XXX is this correct? Always switch if in doubt? */
560 }
561
562 /*
563 * Switch if required. Note that we ignore the result of the switch
564 * effort; we don't know what to do if it fails, so checking wouldn't
565 * help much.
566 */
567 if (cur != ACPI_PWR_ON) {
568 if (ACPI_FAILURE(status = AcpiEvaluateObject(rp->ap_resource, "_ON", NULL, NULL))) {
569 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to switch %s on - %s\n",
570 acpi_name(rp->ap_resource), AcpiFormatException(status)));
571 } else {
572 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s on\n", acpi_name(rp->ap_resource)));
573 }
574 } else {
575 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s is already on\n", acpi_name(rp->ap_resource)));
576 }
577 }
578
579 /*
580 * Sweep the list backwards turning things off.
581 */
582 TAILQ_FOREACH_REVERSE(rp, &acpi_powerresources, acpi_powerresource_list, ap_link) {
583 if (TAILQ_FIRST(&rp->ap_references) != NULL) {
584 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s has references, not turning off\n",
585 acpi_name(rp->ap_resource)));
586 continue;
587 }
588
589 /* we could cache this if we trusted it not to change under us */
583 if ((status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur)) != AE_OK) {
590 if (ACPI_FAILURE(status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur))) {
584 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get status of %s - %d\n",
585 acpi_name(rp->ap_resource), status));
586 continue; /* XXX is this correct? Always switch if in doubt? */
587 }
588
589 /*
590 * Switch if required. Note that we ignore the result of the switch
591 * effort; we don't know what to do if it fails, so checking wouldn't
592 * help much.
593 */
594 if (cur != ACPI_PWR_OFF) {
595 if (ACPI_FAILURE(status = AcpiEvaluateObject(rp->ap_resource, "_OFF", NULL, NULL))) {
596 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to switch %s off - %s\n",
597 acpi_name(rp->ap_resource), AcpiFormatException(status)));
598 } else {
599 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s off\n", acpi_name(rp->ap_resource)));
600 }
601 } else {
602 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s is already off\n", acpi_name(rp->ap_resource)));
603 }
604 }
605 return_ACPI_STATUS(AE_OK);
606}
607
608/*
609 * Find a power resource's control structure.
610 */
611static struct acpi_powerresource *
612acpi_pwr_find_resource(ACPI_HANDLE res)
613{
614 struct acpi_powerresource *rp;
615
591 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get status of %s - %d\n",
592 acpi_name(rp->ap_resource), status));
593 continue; /* XXX is this correct? Always switch if in doubt? */
594 }
595
596 /*
597 * Switch if required. Note that we ignore the result of the switch
598 * effort; we don't know what to do if it fails, so checking wouldn't
599 * help much.
600 */
601 if (cur != ACPI_PWR_OFF) {
602 if (ACPI_FAILURE(status = AcpiEvaluateObject(rp->ap_resource, "_OFF", NULL, NULL))) {
603 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to switch %s off - %s\n",
604 acpi_name(rp->ap_resource), AcpiFormatException(status)));
605 } else {
606 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s off\n", acpi_name(rp->ap_resource)));
607 }
608 } else {
609 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s is already off\n", acpi_name(rp->ap_resource)));
610 }
611 }
612 return_ACPI_STATUS(AE_OK);
613}
614
615/*
616 * Find a power resource's control structure.
617 */
618static struct acpi_powerresource *
619acpi_pwr_find_resource(ACPI_HANDLE res)
620{
621 struct acpi_powerresource *rp;
622
616 FUNCTION_TRACE(__func__);
623 ACPI_FUNCTION_TRACE(__func__);
617
618 TAILQ_FOREACH(rp, &acpi_powerresources, ap_link)
619 if (rp->ap_resource == res)
620 break;
621 return_PTR(rp);
622}
623
624/*
625 * Find a power consumer's control structure.
626 */
627static struct acpi_powerconsumer *
628acpi_pwr_find_consumer(ACPI_HANDLE consumer)
629{
630 struct acpi_powerconsumer *pc;
631
624
625 TAILQ_FOREACH(rp, &acpi_powerresources, ap_link)
626 if (rp->ap_resource == res)
627 break;
628 return_PTR(rp);
629}
630
631/*
632 * Find a power consumer's control structure.
633 */
634static struct acpi_powerconsumer *
635acpi_pwr_find_consumer(ACPI_HANDLE consumer)
636{
637 struct acpi_powerconsumer *pc;
638
632 FUNCTION_TRACE(__func__);
639 ACPI_FUNCTION_TRACE(__func__);
633
634 TAILQ_FOREACH(pc, &acpi_powerconsumers, ac_link)
635 if (pc->ac_consumer == consumer)
636 break;
637 return_PTR(pc);
638}
639
640
641 TAILQ_FOREACH(pc, &acpi_powerconsumers, ac_link)
642 if (pc->ac_consumer == consumer)
643 break;
644 return_PTR(pc);
645}
646