subr_device.c revision 1.1.2.1 1 /* $NetBSD: subr_device.c,v 1.1.2.1 2007/12/16 18:54:06 cube Exp $ */
2
3 /*
4 * Copyright (c) 1996, 2000 Christopher G. Demetriou
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the
18 * NetBSD Project. See http://www.NetBSD.org/ for
19 * information about NetBSD.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 * --(license Id: LICENSE.proto,v 1.1 2000/06/13 21:40:26 cgd Exp )--
35 */
36
37 /*
38 * Copyright (c) 1992, 1993
39 * The Regents of the University of California. All rights reserved.
40 *
41 * This software was developed by the Computer Systems Engineering group
42 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
43 * contributed to Berkeley.
44 *
45 * All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Lawrence Berkeley Laboratories.
49 *
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 * 1. Redistributions of source code must retain the above copyright
54 * notice, this list of conditions and the following disclaimer.
55 * 2. Redistributions in binary form must reproduce the above copyright
56 * notice, this list of conditions and the following disclaimer in the
57 * documentation and/or other materials provided with the distribution.
58 * 3. Neither the name of the University nor the names of its contributors
59 * may be used to endorse or promote products derived from this software
60 * without specific prior written permission.
61 *
62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72 * SUCH DAMAGE.
73 *
74 * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp (LBL)
75 *
76 * @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94
77 */
78
79 #include <sys/cdefs.h>
80 __KERNEL_RCSID(0, "$NetBSD: subr_device.c,v 1.1.2.1 2007/12/16 18:54:06 cube Exp $");
81
82 #include <sys/param.h>
83 #include <sys/device.h>
84 #include <sys/malloc.h>
85
86 /* list of all devices */
87 struct devicelist alldevs = TAILQ_HEAD_INITIALIZER(alldevs);
88
89 /*
90 * device_lookup:
91 *
92 * Look up a device instance for a given driver.
93 */
94 void *
95 device_lookup(cfdriver_t cd, int unit)
96 {
97
98 if (unit < 0 || unit >= cd->cd_ndevs)
99 return (NULL);
100
101 return (cd->cd_devs[unit]);
102 }
103
104 /*
105 * Accessor functions for the device_t type.
106 */
107 devclass_t
108 device_class(device_t dev)
109 {
110
111 return (dev->dv_class);
112 }
113
114 cfdata_t
115 device_cfdata(device_t dev)
116 {
117
118 return (dev->dv_cfdata);
119 }
120
121 cfdriver_t
122 device_cfdriver(device_t dev)
123 {
124
125 return (dev->dv_cfdriver);
126 }
127
128 cfattach_t
129 device_cfattach(device_t dev)
130 {
131
132 return (dev->dv_cfattach);
133 }
134
135 int
136 device_unit(device_t dev)
137 {
138
139 return (dev->dv_unit);
140 }
141
142 const char *
143 device_xname(device_t dev)
144 {
145
146 return (dev->dv_xname);
147 }
148
149 device_t
150 device_parent(device_t dev)
151 {
152
153 return (dev->dv_parent);
154 }
155
156 bool
157 device_is_active(device_t dev)
158 {
159 int active_flags;
160
161 active_flags = DVF_ACTIVE;
162 active_flags |= DVF_CLASS_SUSPENDED;
163 active_flags |= DVF_DRIVER_SUSPENDED;
164 active_flags |= DVF_BUS_SUSPENDED;
165
166 return ((dev->dv_flags & active_flags) == DVF_ACTIVE);
167 }
168
169 bool
170 device_is_enabled(device_t dev)
171 {
172 return (dev->dv_flags & DVF_ACTIVE) == DVF_ACTIVE;
173 }
174
175 bool
176 device_has_power(device_t dev)
177 {
178 int active_flags;
179
180 active_flags = DVF_ACTIVE | DVF_BUS_SUSPENDED;
181
182 return ((dev->dv_flags & active_flags) == DVF_ACTIVE);
183 }
184
185 int
186 device_locator(device_t dev, u_int locnum)
187 {
188
189 KASSERT(dev->dv_locators != NULL);
190 return (dev->dv_locators[locnum]);
191 }
192
193 void *
194 device_private(device_t dev)
195 {
196
197 return (dev->dv_private);
198 }
199
200 prop_dictionary_t
201 device_properties(device_t dev)
202 {
203
204 return (dev->dv_properties);
205 }
206
207 /*
208 * device_is_a:
209 *
210 * Returns true if the device is an instance of the specified
211 * driver.
212 */
213 bool
214 device_is_a(device_t dev, const char *dname)
215 {
216
217 return (strcmp(dev->dv_cfdriver->cd_name, dname) == 0);
218 }
219
220 /*
221 * Power management related functions.
222 */
223
224 bool
225 device_pmf_is_registered(device_t dev)
226 {
227 return (dev->dv_flags & DVF_POWER_HANDLERS) != 0;
228 }
229
230 bool
231 device_pmf_driver_suspend(device_t dev)
232 {
233 if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
234 return true;
235 if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
236 return false;
237 if (*dev->dv_driver_suspend != NULL &&
238 !(*dev->dv_driver_suspend)(dev))
239 return false;
240
241 dev->dv_flags |= DVF_DRIVER_SUSPENDED;
242 return true;
243 }
244
245 bool
246 device_pmf_driver_resume(device_t dev)
247 {
248 if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
249 return true;
250 if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
251 return false;
252 if (*dev->dv_driver_resume != NULL &&
253 !(*dev->dv_driver_resume)(dev))
254 return false;
255
256 dev->dv_flags &= ~DVF_DRIVER_SUSPENDED;
257 return true;
258 }
259
260 void
261 device_pmf_driver_register(device_t dev,
262 bool (*suspend)(device_t), bool (*resume)(device_t))
263 {
264 dev->dv_driver_suspend = suspend;
265 dev->dv_driver_resume = resume;
266 dev->dv_flags |= DVF_POWER_HANDLERS;
267 }
268
269 void
270 device_pmf_driver_deregister(device_t dev)
271 {
272 dev->dv_driver_suspend = NULL;
273 dev->dv_driver_resume = NULL;
274 dev->dv_flags &= ~DVF_POWER_HANDLERS;
275 }
276
277 bool
278 device_pmf_driver_child_register(device_t dev)
279 {
280 device_t parent = device_parent(dev);
281
282 if (parent == NULL || parent->dv_driver_child_register == NULL)
283 return true;
284 return (*parent->dv_driver_child_register)(dev);
285 }
286
287 void
288 device_pmf_driver_set_child_register(device_t dev,
289 bool (*child_register)(device_t))
290 {
291 dev->dv_driver_child_register = child_register;
292 }
293
294 void *
295 device_pmf_bus_private(device_t dev)
296 {
297 return dev->dv_bus_private;
298 }
299
300 bool
301 device_pmf_bus_suspend(device_t dev)
302 {
303 if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
304 return true;
305 if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0 ||
306 (dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
307 return false;
308 if (*dev->dv_bus_suspend != NULL &&
309 !(*dev->dv_bus_suspend)(dev))
310 return false;
311
312 dev->dv_flags |= DVF_BUS_SUSPENDED;
313 return true;
314 }
315
316 bool
317 device_pmf_bus_resume(device_t dev)
318 {
319 if ((dev->dv_flags & DVF_BUS_SUSPENDED) == 0)
320 return true;
321 if (*dev->dv_bus_resume != NULL &&
322 !(*dev->dv_bus_resume)(dev))
323 return false;
324
325 dev->dv_flags &= ~DVF_BUS_SUSPENDED;
326 return true;
327 }
328
329 void
330 device_pmf_bus_register(device_t dev, void *priv,
331 bool (*suspend)(device_t), bool (*resume)(device_t),
332 void (*deregister)(device_t))
333 {
334 dev->dv_bus_private = priv;
335 dev->dv_bus_resume = resume;
336 dev->dv_bus_suspend = suspend;
337 dev->dv_bus_deregister = deregister;
338 }
339
340 void
341 device_pmf_bus_deregister(device_t dev)
342 {
343 if (dev->dv_bus_deregister == NULL)
344 return;
345 (*dev->dv_bus_deregister)(dev);
346 dev->dv_bus_private = NULL;
347 dev->dv_bus_suspend = NULL;
348 dev->dv_bus_resume = NULL;
349 dev->dv_bus_deregister = NULL;
350 }
351
352 void *
353 device_pmf_class_private(device_t dev)
354 {
355 return dev->dv_class_private;
356 }
357
358 bool
359 device_pmf_class_suspend(device_t dev)
360 {
361 if ((dev->dv_flags & DVF_CLASS_SUSPENDED) != 0)
362 return true;
363 if (*dev->dv_class_suspend != NULL &&
364 !(*dev->dv_class_suspend)(dev))
365 return false;
366
367 dev->dv_flags |= DVF_CLASS_SUSPENDED;
368 return true;
369 }
370
371 bool
372 device_pmf_class_resume(device_t dev)
373 {
374 if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
375 return true;
376 if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0 ||
377 (dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
378 return false;
379 if (*dev->dv_class_resume != NULL &&
380 !(*dev->dv_class_resume)(dev))
381 return false;
382
383 dev->dv_flags &= ~DVF_CLASS_SUSPENDED;
384 return true;
385 }
386
387 void
388 device_pmf_class_register(device_t dev, void *priv,
389 bool (*suspend)(device_t), bool (*resume)(device_t),
390 void (*deregister)(device_t))
391 {
392 dev->dv_class_private = priv;
393 dev->dv_class_suspend = suspend;
394 dev->dv_class_resume = resume;
395 dev->dv_class_deregister = deregister;
396 }
397
398 void
399 device_pmf_class_deregister(device_t dev)
400 {
401 if (dev->dv_class_deregister == NULL)
402 return;
403 (*dev->dv_class_deregister)(dev);
404 dev->dv_class_private = NULL;
405 dev->dv_class_suspend = NULL;
406 dev->dv_class_resume = NULL;
407 dev->dv_class_deregister = NULL;
408 }
409
410 bool
411 device_active(device_t dev, devactive_t type)
412 {
413 size_t i;
414
415 if (dev->dv_activity_count == 0)
416 return false;
417
418 for (i = 0; i < dev->dv_activity_count; ++i)
419 (*dev->dv_activity_handlers[i])(dev, type);
420
421 return true;
422 }
423
424 bool
425 device_active_register(device_t dev, void (*handler)(device_t, devactive_t))
426 {
427 void (**new_handlers)(device_t, devactive_t);
428 void (**old_handlers)(device_t, devactive_t);
429 size_t i, new_size;
430 int s;
431
432 old_handlers = dev->dv_activity_handlers;
433
434 for (i = 0; i < dev->dv_activity_count; ++i) {
435 if (old_handlers[i] == handler)
436 panic("Double registering of idle handlers");
437 }
438
439 new_size = dev->dv_activity_count + 1;
440 new_handlers = malloc(sizeof(void *) * new_size, M_DEVBUF, M_WAITOK);
441
442 memcpy(new_handlers, old_handlers,
443 sizeof(void *) * dev->dv_activity_count);
444 new_handlers[new_size - 1] = handler;
445
446 s = splhigh();
447 dev->dv_activity_count = new_size;
448 dev->dv_activity_handlers = new_handlers;
449 splx(s);
450
451 if (old_handlers != NULL)
452 free(old_handlers, M_DEVBUF);
453
454 return true;
455 }
456
457 void
458 device_active_deregister(device_t dev, void (*handler)(device_t, devactive_t))
459 {
460 void (**new_handlers)(device_t, devactive_t);
461 void (**old_handlers)(device_t, devactive_t);
462 size_t i, new_size;
463 int s;
464
465 old_handlers = dev->dv_activity_handlers;
466
467 for (i = 0; i < dev->dv_activity_count; ++i) {
468 if (old_handlers[i] == handler)
469 break;
470 }
471
472 if (i == dev->dv_activity_count)
473 return; /* XXX panic? */
474
475 new_size = dev->dv_activity_count - 1;
476
477 if (new_size == 0) {
478 new_handlers = NULL;
479 } else {
480 new_handlers = malloc(sizeof(void *) * new_size, M_DEVBUF,
481 M_WAITOK);
482 memcpy(new_handlers, old_handlers, sizeof(void *) * i);
483 memcpy(new_handlers + i, old_handlers + i + 1,
484 sizeof(void *) * (new_size - i));
485 }
486
487 s = splhigh();
488 dev->dv_activity_count = new_size;
489 dev->dv_activity_handlers = new_handlers;
490 splx(s);
491
492 free(old_handlers, M_DEVBUF);
493 }
494