subr_device.c revision 1.1.2.2 1 /* $NetBSD: subr_device.c,v 1.1.2.2 2008/01/30 22:08:51 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.2 2008/01/30 22:08:51 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 /*
198 * The reason why device_private(NULL) is allowed is to simplify the
199 * work of a lot of userspace request handlers (i.e., c/bdev
200 * handlers) which grab cfdriver_t->cd_units[n].
201 * It avoids having them test for it to be NULL and only then calling
202 * device_private.
203 */
204 return dev == NULL ? NULL : dev->dv_private;
205 }
206
207 prop_dictionary_t
208 device_properties(device_t dev)
209 {
210
211 return (dev->dv_properties);
212 }
213
214 /*
215 * device_is_a:
216 *
217 * Returns true if the device is an instance of the specified
218 * driver.
219 */
220 bool
221 device_is_a(device_t dev, const char *dname)
222 {
223
224 return (strcmp(dev->dv_cfdriver->cd_name, dname) == 0);
225 }
226
227 /*
228 * Power management related functions.
229 */
230
231 bool
232 device_pmf_is_registered(device_t dev)
233 {
234 return (dev->dv_flags & DVF_POWER_HANDLERS) != 0;
235 }
236
237 bool
238 device_pmf_driver_suspend(device_t dev)
239 {
240 if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
241 return true;
242 if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
243 return false;
244 if (*dev->dv_driver_suspend != NULL &&
245 !(*dev->dv_driver_suspend)(dev))
246 return false;
247
248 dev->dv_flags |= DVF_DRIVER_SUSPENDED;
249 return true;
250 }
251
252 bool
253 device_pmf_driver_resume(device_t dev)
254 {
255 if ((dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
256 return true;
257 if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
258 return false;
259 if (*dev->dv_driver_resume != NULL &&
260 !(*dev->dv_driver_resume)(dev))
261 return false;
262
263 dev->dv_flags &= ~DVF_DRIVER_SUSPENDED;
264 return true;
265 }
266
267 void
268 device_pmf_driver_register(device_t dev,
269 bool (*suspend)(device_t), bool (*resume)(device_t))
270 {
271 dev->dv_driver_suspend = suspend;
272 dev->dv_driver_resume = resume;
273 dev->dv_flags |= DVF_POWER_HANDLERS;
274 }
275
276 void
277 device_pmf_driver_deregister(device_t dev)
278 {
279 dev->dv_driver_suspend = NULL;
280 dev->dv_driver_resume = NULL;
281 dev->dv_flags &= ~DVF_POWER_HANDLERS;
282 }
283
284 bool
285 device_pmf_driver_child_register(device_t dev)
286 {
287 device_t parent = device_parent(dev);
288
289 if (parent == NULL || parent->dv_driver_child_register == NULL)
290 return true;
291 return (*parent->dv_driver_child_register)(dev);
292 }
293
294 void
295 device_pmf_driver_set_child_register(device_t dev,
296 bool (*child_register)(device_t))
297 {
298 dev->dv_driver_child_register = child_register;
299 }
300
301 void *
302 device_pmf_bus_private(device_t dev)
303 {
304 return dev->dv_bus_private;
305 }
306
307 bool
308 device_pmf_bus_suspend(device_t dev)
309 {
310 if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0)
311 return true;
312 if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0 ||
313 (dev->dv_flags & DVF_DRIVER_SUSPENDED) == 0)
314 return false;
315 if (*dev->dv_bus_suspend != NULL &&
316 !(*dev->dv_bus_suspend)(dev))
317 return false;
318
319 dev->dv_flags |= DVF_BUS_SUSPENDED;
320 return true;
321 }
322
323 bool
324 device_pmf_bus_resume(device_t dev)
325 {
326 if ((dev->dv_flags & DVF_BUS_SUSPENDED) == 0)
327 return true;
328 if (*dev->dv_bus_resume != NULL &&
329 !(*dev->dv_bus_resume)(dev))
330 return false;
331
332 dev->dv_flags &= ~DVF_BUS_SUSPENDED;
333 return true;
334 }
335
336 void
337 device_pmf_bus_register(device_t dev, void *priv,
338 bool (*suspend)(device_t), bool (*resume)(device_t),
339 void (*deregister)(device_t))
340 {
341 dev->dv_bus_private = priv;
342 dev->dv_bus_resume = resume;
343 dev->dv_bus_suspend = suspend;
344 dev->dv_bus_deregister = deregister;
345 }
346
347 void
348 device_pmf_bus_deregister(device_t dev)
349 {
350 if (dev->dv_bus_deregister == NULL)
351 return;
352 (*dev->dv_bus_deregister)(dev);
353 dev->dv_bus_private = NULL;
354 dev->dv_bus_suspend = NULL;
355 dev->dv_bus_resume = NULL;
356 dev->dv_bus_deregister = NULL;
357 }
358
359 void *
360 device_pmf_class_private(device_t dev)
361 {
362 return dev->dv_class_private;
363 }
364
365 bool
366 device_pmf_class_suspend(device_t dev)
367 {
368 if ((dev->dv_flags & DVF_CLASS_SUSPENDED) != 0)
369 return true;
370 if (*dev->dv_class_suspend != NULL &&
371 !(*dev->dv_class_suspend)(dev))
372 return false;
373
374 dev->dv_flags |= DVF_CLASS_SUSPENDED;
375 return true;
376 }
377
378 bool
379 device_pmf_class_resume(device_t dev)
380 {
381 if ((dev->dv_flags & DVF_CLASS_SUSPENDED) == 0)
382 return true;
383 if ((dev->dv_flags & DVF_BUS_SUSPENDED) != 0 ||
384 (dev->dv_flags & DVF_DRIVER_SUSPENDED) != 0)
385 return false;
386 if (*dev->dv_class_resume != NULL &&
387 !(*dev->dv_class_resume)(dev))
388 return false;
389
390 dev->dv_flags &= ~DVF_CLASS_SUSPENDED;
391 return true;
392 }
393
394 void
395 device_pmf_class_register(device_t dev, void *priv,
396 bool (*suspend)(device_t), bool (*resume)(device_t),
397 void (*deregister)(device_t))
398 {
399 dev->dv_class_private = priv;
400 dev->dv_class_suspend = suspend;
401 dev->dv_class_resume = resume;
402 dev->dv_class_deregister = deregister;
403 }
404
405 void
406 device_pmf_class_deregister(device_t dev)
407 {
408 if (dev->dv_class_deregister == NULL)
409 return;
410 (*dev->dv_class_deregister)(dev);
411 dev->dv_class_private = NULL;
412 dev->dv_class_suspend = NULL;
413 dev->dv_class_resume = NULL;
414 dev->dv_class_deregister = NULL;
415 }
416
417 bool
418 device_active(device_t dev, devactive_t type)
419 {
420 size_t i;
421
422 if (dev->dv_activity_count == 0)
423 return false;
424
425 for (i = 0; i < dev->dv_activity_count; ++i)
426 (*dev->dv_activity_handlers[i])(dev, type);
427
428 return true;
429 }
430
431 bool
432 device_active_register(device_t dev, void (*handler)(device_t, devactive_t))
433 {
434 void (**new_handlers)(device_t, devactive_t);
435 void (**old_handlers)(device_t, devactive_t);
436 size_t i, new_size;
437 int s;
438
439 old_handlers = dev->dv_activity_handlers;
440
441 for (i = 0; i < dev->dv_activity_count; ++i) {
442 if (old_handlers[i] == handler)
443 panic("Double registering of idle handlers");
444 }
445
446 new_size = dev->dv_activity_count + 1;
447 new_handlers = malloc(sizeof(void *) * new_size, M_DEVBUF, M_WAITOK);
448
449 memcpy(new_handlers, old_handlers,
450 sizeof(void *) * dev->dv_activity_count);
451 new_handlers[new_size - 1] = handler;
452
453 s = splhigh();
454 dev->dv_activity_count = new_size;
455 dev->dv_activity_handlers = new_handlers;
456 splx(s);
457
458 if (old_handlers != NULL)
459 free(old_handlers, M_DEVBUF);
460
461 return true;
462 }
463
464 void
465 device_active_deregister(device_t dev, void (*handler)(device_t, devactive_t))
466 {
467 void (**new_handlers)(device_t, devactive_t);
468 void (**old_handlers)(device_t, devactive_t);
469 size_t i, new_size;
470 int s;
471
472 old_handlers = dev->dv_activity_handlers;
473
474 for (i = 0; i < dev->dv_activity_count; ++i) {
475 if (old_handlers[i] == handler)
476 break;
477 }
478
479 if (i == dev->dv_activity_count)
480 return; /* XXX panic? */
481
482 new_size = dev->dv_activity_count - 1;
483
484 if (new_size == 0) {
485 new_handlers = NULL;
486 } else {
487 new_handlers = malloc(sizeof(void *) * new_size, M_DEVBUF,
488 M_WAITOK);
489 memcpy(new_handlers, old_handlers, sizeof(void *) * i);
490 memcpy(new_handlers + i, old_handlers + i + 1,
491 sizeof(void *) * (new_size - i));
492 }
493
494 s = splhigh();
495 dev->dv_activity_count = new_size;
496 dev->dv_activity_handlers = new_handlers;
497 splx(s);
498
499 free(old_handlers, M_DEVBUF);
500 }
501