This source file includes following definitions.
- TAILQ_HEAD
- mapply
- config_search
- config_scan
- config_rootsearch
- config_found_sm
- config_rootfound
- config_attach
- config_make_softc
- config_detach
- config_activate
- config_deactivate
- config_defer
- config_process_deferred_children
- config_pending_incr
- config_pending_decr
- config_detach_children
- config_activate_children
- device_lookup
- device_ref
- device_unref
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
42
43
44
45
46 #include <sys/param.h>
47 #include <sys/device.h>
48 #include <sys/hotplug.h>
49 #include <sys/limits.h>
50 #include <sys/malloc.h>
51 #include <sys/systm.h>
52
53 #include <sys/queue.h>
54 #include <sys/proc.h>
55
56 #include "hotplug.h"
57
58
59
60
61
62 typedef int (*cond_predicate_t)(struct device *, void *);
63
64
65
66
67
68 extern short cfroots[];
69
70 #define ROOT ((struct device *)NULL)
71
72 struct matchinfo {
73 cfmatch_t fn;
74 struct device *parent;
75 void *match, *aux;
76 int indirect, pri;
77 };
78
79 struct cftable_head allcftables;
80
81 static struct cftable staticcftable = {
82 cfdata
83 };
84
85 #ifndef AUTOCONF_VERBOSE
86 #define AUTOCONF_VERBOSE 0
87 #endif
88 int autoconf_verbose = AUTOCONF_VERBOSE;
89
90 static void mapply(struct matchinfo *, struct cfdata *);
91
92 struct deferred_config {
93 TAILQ_ENTRY(deferred_config) dc_queue;
94 struct device *dc_dev;
95 void (*dc_func)(struct device *);
96 };
97
98 TAILQ_HEAD(, deferred_config) deferred_config_queue;
99
100 void config_process_deferred_children(struct device *);
101
102 struct devicelist alldevs;
103
104 __volatile int config_pending;
105
106
107
108
109
110
111 void
112 config_init(void)
113 {
114 TAILQ_INIT(&deferred_config_queue);
115 TAILQ_INIT(&alldevs);
116 TAILQ_INIT(&allcftables);
117 TAILQ_INSERT_TAIL(&allcftables, &staticcftable, list);
118 }
119
120
121
122
123
124 void
125 mapply(struct matchinfo *m, struct cfdata *cf)
126 {
127 int pri;
128 void *match;
129
130 if (m->indirect)
131 match = config_make_softc(m->parent, cf);
132 else
133 match = cf;
134
135 if (autoconf_verbose) {
136 printf(">>> probing for %s", cf->cf_driver->cd_name);
137 if (cf->cf_fstate == FSTATE_STAR)
138 printf("*\n");
139 else
140 printf("%d\n", cf->cf_unit);
141 }
142 if (m->fn != NULL)
143 pri = (*m->fn)(m->parent, match, m->aux);
144 else {
145 if (cf->cf_attach->ca_match == NULL) {
146 panic("mapply: no match function for '%s' device",
147 cf->cf_driver->cd_name);
148 }
149 pri = (*cf->cf_attach->ca_match)(m->parent, match, m->aux);
150 }
151 if (autoconf_verbose)
152 printf(">>> %s probe returned %d\n", cf->cf_driver->cd_name,
153 pri);
154
155 if (pri > m->pri) {
156 if (m->indirect && m->match)
157 free(m->match, M_DEVBUF);
158 m->match = match;
159 m->pri = pri;
160 } else {
161 if (m->indirect)
162 free(match, M_DEVBUF);
163 }
164 }
165
166
167
168
169
170
171
172
173
174
175
176
177 void *
178 config_search(cfmatch_t fn, struct device *parent, void *aux)
179 {
180 struct cfdata *cf;
181 short *p;
182 struct matchinfo m;
183 struct cftable *t;
184
185 m.fn = fn;
186 m.parent = parent;
187 m.match = NULL;
188 m.aux = aux;
189 m.indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
190 m.pri = 0;
191 TAILQ_FOREACH(t, &allcftables, list) {
192 for (cf = t->tab; cf->cf_driver; cf++) {
193
194
195
196
197
198 if (cf->cf_fstate == FSTATE_FOUND)
199 continue;
200 if (cf->cf_fstate == FSTATE_DNOTFOUND ||
201 cf->cf_fstate == FSTATE_DSTAR)
202 continue;
203 for (p = cf->cf_parents; *p >= 0; p++)
204 if (parent->dv_cfdata == &(t->tab)[*p])
205 mapply(&m, cf);
206 }
207 }
208 if (autoconf_verbose) {
209 if (m.match) {
210 if (m.indirect)
211 cf = ((struct device *)m.match)->dv_cfdata;
212 else
213 cf = (struct cfdata *)m.match;
214 printf(">>> %s probe won\n",
215 cf->cf_driver->cd_name);
216 } else
217 printf(">>> no winning probe\n");
218 }
219 return (m.match);
220 }
221
222
223
224
225
226
227
228
229
230 void
231 config_scan(cfscan_t fn, struct device *parent)
232 {
233 struct cfdata *cf;
234 short *p;
235 void *match;
236 int indirect;
237 struct cftable *t;
238
239 indirect = parent && parent->dv_cfdata->cf_driver->cd_indirect;
240 TAILQ_FOREACH(t, &allcftables, list) {
241 for (cf = t->tab; cf->cf_driver; cf++) {
242
243
244
245
246
247 if (cf->cf_fstate == FSTATE_FOUND)
248 continue;
249 if (cf->cf_fstate == FSTATE_DNOTFOUND ||
250 cf->cf_fstate == FSTATE_DSTAR)
251 continue;
252 for (p = cf->cf_parents; *p >= 0; p++)
253 if (parent->dv_cfdata == &(t->tab)[*p]) {
254 match = indirect?
255 config_make_softc(parent, cf) :
256 (void *)cf;
257 (*fn)(parent, match);
258 }
259 }
260 }
261 }
262
263
264
265
266
267 void *
268 config_rootsearch(cfmatch_t fn, char *rootname, void *aux)
269 {
270 struct cfdata *cf;
271 short *p;
272 struct matchinfo m;
273
274 m.fn = fn;
275 m.parent = ROOT;
276 m.match = NULL;
277 m.aux = aux;
278 m.indirect = 0;
279 m.pri = 0;
280
281
282
283
284
285 for (p = cfroots; *p >= 0; p++) {
286 cf = &cfdata[*p];
287 if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
288 mapply(&m, cf);
289 }
290 return (m.match);
291 }
292
293 char *msgs[3] = { "", " not configured\n", " unsupported\n" };
294
295
296
297
298
299
300
301
302
303 struct device *
304 config_found_sm(struct device *parent, void *aux, cfprint_t print,
305 cfmatch_t submatch)
306 {
307 void *match;
308
309 if ((match = config_search(submatch, parent, aux)) != NULL)
310 return (config_attach(parent, match, aux, print));
311 if (print)
312 printf(msgs[(*print)(aux, parent->dv_xname)]);
313 return (NULL);
314 }
315
316
317
318
319 struct device *
320 config_rootfound(char *rootname, void *aux)
321 {
322 void *match;
323
324 if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
325 return (config_attach(ROOT, match, aux, (cfprint_t)NULL));
326 printf("root device %s not configured\n", rootname);
327 return (NULL);
328 }
329
330
331
332
333 struct device *
334 config_attach(struct device *parent, void *match, void *aux, cfprint_t print)
335 {
336 struct cfdata *cf;
337 struct device *dev;
338 struct cfdriver *cd;
339 struct cfattach *ca;
340 struct cftable *t;
341
342 if (parent && parent->dv_cfdata->cf_driver->cd_indirect) {
343 dev = match;
344 cf = dev->dv_cfdata;
345 } else {
346 cf = match;
347 dev = config_make_softc(parent, cf);
348 }
349
350 cd = cf->cf_driver;
351 ca = cf->cf_attach;
352
353 cd->cd_devs[dev->dv_unit] = dev;
354
355
356
357
358
359 if (cf->cf_fstate == FSTATE_STAR) {
360 if (dev->dv_unit == cf->cf_unit)
361 cf->cf_unit++;
362 } else
363 cf->cf_fstate = FSTATE_FOUND;
364
365 TAILQ_INSERT_TAIL(&alldevs, dev, dv_list);
366 device_ref(dev);
367
368 if (parent == ROOT)
369 printf("%s at root", dev->dv_xname);
370 else {
371 printf("%s at %s", dev->dv_xname, parent->dv_xname);
372 if (print)
373 (void) (*print)(aux, (char *)0);
374 }
375
376
377
378
379
380
381 TAILQ_FOREACH(t, &allcftables, list) {
382 for (cf = t->tab; cf->cf_driver; cf++)
383 if (cf->cf_driver == cd &&
384 cf->cf_unit == dev->dv_unit) {
385 if (cf->cf_fstate == FSTATE_NOTFOUND)
386 cf->cf_fstate = FSTATE_FOUND;
387 if (cf->cf_fstate == FSTATE_STAR)
388 cf->cf_unit++;
389 }
390 }
391 device_register(dev, aux);
392 (*ca->ca_attach)(parent, dev, aux);
393 config_process_deferred_children(dev);
394 #if NHOTPLUG > 0
395 if (!cold)
396 hotplug_device_attach(cd->cd_class, dev->dv_xname);
397 #endif
398 return (dev);
399 }
400
401 struct device *
402 config_make_softc(struct device *parent, struct cfdata *cf)
403 {
404 struct device *dev;
405 struct cfdriver *cd;
406 struct cfattach *ca;
407
408 cd = cf->cf_driver;
409 ca = cf->cf_attach;
410 if (ca->ca_devsize < sizeof(struct device))
411 panic("config_make_softc");
412
413
414 dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT);
415 if (!dev)
416 panic("config_make_softc: allocation for device softc failed");
417 bzero(dev, ca->ca_devsize);
418 dev->dv_class = cd->cd_class;
419 dev->dv_cfdata = cf;
420 dev->dv_flags = DVF_ACTIVE;
421
422
423 if (cf->cf_fstate == FSTATE_STAR) {
424 for (dev->dv_unit = cf->cf_starunit1;
425 dev->dv_unit < cf->cf_unit; dev->dv_unit++)
426 if (cd->cd_ndevs == 0 ||
427 dev->dv_unit >= cd->cd_ndevs ||
428 cd->cd_devs[dev->dv_unit] == NULL)
429 break;
430 } else
431 dev->dv_unit = cf->cf_unit;
432
433
434 if (snprintf(dev->dv_xname, sizeof(dev->dv_xname), "%s%d",
435 cd->cd_name, dev->dv_unit) >= sizeof(dev->dv_xname))
436 panic("config_make_softc: device name too long");
437 dev->dv_parent = parent;
438
439
440 if (dev->dv_unit >= cd->cd_ndevs) {
441
442
443
444 int old = cd->cd_ndevs, new;
445 void **nsp;
446
447 if (old == 0)
448 new = MINALLOCSIZE / sizeof(void *);
449 else
450 new = old * 2;
451 while (new <= dev->dv_unit)
452 new *= 2;
453 cd->cd_ndevs = new;
454 nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT);
455 if (nsp == 0)
456 panic("config_make_softc: %sing dev array",
457 old != 0 ? "expand" : "creat");
458 bzero(nsp + old, (new - old) * sizeof(void *));
459 if (old != 0) {
460 bcopy(cd->cd_devs, nsp, old * sizeof(void *));
461 free(cd->cd_devs, M_DEVBUF);
462 }
463 cd->cd_devs = nsp;
464 }
465 if (cd->cd_devs[dev->dv_unit])
466 panic("config_make_softc: duplicate %s", dev->dv_xname);
467
468 dev->dv_ref = 1;
469
470 return (dev);
471 }
472
473
474
475
476
477
478
479
480
481
482 int
483 config_detach(struct device *dev, int flags)
484 {
485 struct cfdata *cf;
486 struct cfattach *ca;
487 struct cfdriver *cd;
488 int rv = 0, i;
489 #ifdef DIAGNOSTIC
490 struct device *d;
491 #endif
492 #if NHOTPLUG > 0
493 char devname[16];
494 #endif
495
496 #if NHOTPLUG > 0
497 strlcpy(devname, dev->dv_xname, sizeof(devname));
498 #endif
499
500 cf = dev->dv_cfdata;
501 #ifdef DIAGNOSTIC
502 if (cf->cf_fstate != FSTATE_FOUND && cf->cf_fstate != FSTATE_STAR)
503 panic("config_detach: bad device fstate");
504 #endif
505 ca = cf->cf_attach;
506 cd = cf->cf_driver;
507
508
509
510
511
512
513
514 if (ca->ca_activate != NULL)
515 rv = config_deactivate(dev);
516
517
518
519
520
521
522 if (rv == 0) {
523 if (ca->ca_detach != NULL)
524 rv = (*ca->ca_detach)(dev, flags);
525 else
526 rv = EOPNOTSUPP;
527 }
528 if (rv != 0) {
529 if ((flags & DETACH_FORCE) == 0)
530 return (rv);
531 else
532 panic("config_detach: forced detach of %s failed (%d)",
533 dev->dv_xname, rv);
534 }
535
536
537
538
539
540 #ifdef DIAGNOSTIC
541
542
543
544
545
546
547 for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
548 d = TAILQ_NEXT(d, dv_list)) {
549 if (d->dv_parent == dev)
550 panic("config_detach: detached device has children");
551 }
552 #endif
553
554
555
556
557
558
559 for (cf = cfdata; cf->cf_driver; cf++) {
560 if (cf->cf_driver == cd) {
561 if (cf->cf_fstate == FSTATE_FOUND &&
562 cf->cf_unit == dev->dv_unit)
563 cf->cf_fstate = FSTATE_NOTFOUND;
564 if (cf->cf_fstate == FSTATE_STAR &&
565 cf->cf_unit == dev->dv_unit + 1)
566 cf->cf_unit--;
567 }
568 }
569
570
571
572
573 TAILQ_REMOVE(&alldevs, dev, dv_list);
574 device_unref(dev);
575
576
577
578
579 cd->cd_devs[dev->dv_unit] = NULL;
580 if ((flags & DETACH_QUIET) == 0)
581 printf("%s detached\n", dev->dv_xname);
582
583 device_unref(dev);
584
585
586
587 for (i = 0; i < cd->cd_ndevs; i++)
588 if (cd->cd_devs[i] != NULL)
589 break;
590 if (i == cd->cd_ndevs) {
591 free(cd->cd_devs, M_DEVBUF);
592 cd->cd_devs = NULL;
593 cd->cd_ndevs = 0;
594 cf->cf_unit = 0;
595 }
596
597 #if NHOTPLUG > 0
598 if (!cold)
599 hotplug_device_detach(cd->cd_class, devname);
600 #endif
601
602
603
604
605 return (0);
606 }
607
608 int
609 config_activate(struct device *dev)
610 {
611 struct cfattach *ca = dev->dv_cfdata->cf_attach;
612 int rv = 0, oflags = dev->dv_flags;
613
614 if (ca->ca_activate == NULL)
615 return (EOPNOTSUPP);
616
617 if ((dev->dv_flags & DVF_ACTIVE) == 0) {
618 dev->dv_flags |= DVF_ACTIVE;
619 rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE);
620 if (rv)
621 dev->dv_flags = oflags;
622 }
623 return (rv);
624 }
625
626 int
627 config_deactivate(struct device *dev)
628 {
629 struct cfattach *ca = dev->dv_cfdata->cf_attach;
630 int rv = 0, oflags = dev->dv_flags;
631
632 if (ca->ca_activate == NULL)
633 return (EOPNOTSUPP);
634
635 if (dev->dv_flags & DVF_ACTIVE) {
636 dev->dv_flags &= ~DVF_ACTIVE;
637 rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);
638 if (rv)
639 dev->dv_flags = oflags;
640 }
641 return (rv);
642 }
643
644
645
646
647
648 void
649 config_defer(struct device *dev, void (*func)(struct device *))
650 {
651 struct deferred_config *dc;
652
653 if (dev->dv_parent == NULL)
654 panic("config_defer: can't defer config of a root device");
655
656 #ifdef DIAGNOSTIC
657 for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
658 dc = TAILQ_NEXT(dc, dc_queue)) {
659 if (dc->dc_dev == dev)
660 panic("config_defer: deferred twice");
661 }
662 #endif
663
664 if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL)
665 panic("config_defer: can't allocate defer structure");
666
667 dc->dc_dev = dev;
668 dc->dc_func = func;
669 TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
670 config_pending_incr();
671 }
672
673
674
675
676 void
677 config_process_deferred_children(struct device *parent)
678 {
679 struct deferred_config *dc, *ndc;
680
681 for (dc = TAILQ_FIRST(&deferred_config_queue);
682 dc != NULL; dc = ndc) {
683 ndc = TAILQ_NEXT(dc, dc_queue);
684 if (dc->dc_dev->dv_parent == parent) {
685 TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue);
686 (*dc->dc_func)(dc->dc_dev);
687 free(dc, M_DEVBUF);
688 config_pending_decr();
689 }
690 }
691 }
692
693
694
695
696 void
697 config_pending_incr(void)
698 {
699
700 config_pending++;
701 }
702
703 void
704 config_pending_decr(void)
705 {
706
707 #ifdef DIAGNOSTIC
708 if (config_pending == 0)
709 panic("config_pending_decr: config_pending == 0");
710 #endif
711 config_pending--;
712 if (config_pending == 0)
713 wakeup((void *)&config_pending);
714 }
715
716 int
717 config_detach_children(struct device *parent, int flags)
718 {
719 struct device *dev, *next_dev, *prev_dev;
720 int rv = 0;
721
722
723
724
725
726
727
728
729
730
731
732
733
734 for (prev_dev = NULL, dev = TAILQ_LAST(&alldevs, devicelist);
735 dev != NULL; dev = next_dev) {
736 if (dev->dv_parent == parent) {
737 if ((rv = config_detach(dev, flags)) != 0)
738 return (rv);
739 next_dev = prev_dev ? prev_dev : TAILQ_LAST(&alldevs,
740 devicelist);
741 } else {
742 prev_dev = dev;
743 next_dev = TAILQ_PREV(dev, devicelist, dv_list);
744 }
745 }
746
747 return (0);
748 }
749
750 int
751 config_activate_children(struct device *parent, enum devact act)
752 {
753 struct device *dev, *next_dev;
754 int rv = 0;
755
756
757
758
759
760
761
762 for (dev = TAILQ_FIRST(&alldevs);
763 dev != NULL; dev = next_dev) {
764 next_dev = TAILQ_NEXT(dev, dv_list);
765 if (dev->dv_parent == parent) {
766 switch (act) {
767 case DVACT_ACTIVATE:
768 rv = config_activate(dev);
769 break;
770 case DVACT_DEACTIVATE:
771 rv = config_deactivate(dev);
772 break;
773 default:
774 #ifdef DIAGNOSTIC
775 printf ("config_activate_children: shouldn't get here");
776 #endif
777 rv = EOPNOTSUPP;
778 break;
779
780 }
781
782 if (rv)
783 break;
784 }
785 }
786
787 return (rv);
788 }
789
790
791
792
793
794
795
796
797
798
799 struct device *
800 device_lookup(struct cfdriver *cd, int unit)
801 {
802 struct device *dv = NULL;
803
804 if (unit >= 0 && unit < cd->cd_ndevs)
805 dv = (struct device *)(cd->cd_devs[unit]);
806
807 if (!dv)
808 return (NULL);
809
810 if (!(dv->dv_flags & DVF_ACTIVE))
811 dv = NULL;
812
813 if (dv != NULL)
814 device_ref(dv);
815
816 return (dv);
817 }
818
819
820
821
822
823
824
825
826 void
827 device_ref(struct device *dv)
828 {
829 dv->dv_ref++;
830 }
831
832
833
834
835
836
837
838
839 void
840 device_unref(struct device *dv)
841 {
842 dv->dv_ref--;
843 if (dv->dv_ref == 0) {
844 free(dv, M_DEVBUF);
845 }
846 }