subr_autoconf.c revision 1.32 1 /* $NetBSD: subr_autoconf.c,v 1.32 1998/08/31 22:28:08 cgd Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 * This product includes software developed by the University of
14 * California, Lawrence Berkeley Laboratories.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 * must display the following acknowledgement:
26 * This product includes software developed by the University of
27 * California, Berkeley and its contributors.
28 * 4. Neither the name of the University nor the names of its contributors
29 * may be used to endorse or promote products derived from this software
30 * without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 *
44 * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp (LBL)
45 *
46 * @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94
47 */
48
49 #include <sys/param.h>
50 #include <sys/device.h>
51 #include <sys/malloc.h>
52 #include <sys/systm.h>
53 #include <machine/limits.h>
54
55 /*
56 * Autoconfiguration subroutines.
57 */
58
59 /*
60 * ioconf.c exports exactly two names: cfdata and cfroots. All system
61 * devices and drivers are found via these tables.
62 */
63 extern struct cfdata cfdata[];
64 extern short cfroots[];
65
66 #define ROOT ((struct device *)NULL)
67
68 struct matchinfo {
69 cfmatch_t fn;
70 struct device *parent;
71 void *aux;
72 struct cfdata *match;
73 int pri;
74 };
75
76 static char *number __P((char *, int));
77 static void mapply __P((struct matchinfo *, struct cfdata *));
78
79 struct deferred_config {
80 TAILQ_ENTRY(deferred_config) dc_queue;
81 struct device *dc_dev;
82 void (*dc_func) __P((struct device *));
83 };
84
85 TAILQ_HEAD(, deferred_config) deferred_config_queue;
86
87 static void config_process_deferred_children __P((struct device *));
88
89 struct devicelist alldevs; /* list of all devices */
90 struct evcntlist allevents; /* list of all event counters */
91
92 /*
93 * Initialize autoconfiguration data structures.
94 */
95 void
96 config_init()
97 {
98
99 TAILQ_INIT(&deferred_config_queue);
100 TAILQ_INIT(&alldevs);
101 TAILQ_INIT(&allevents);
102 }
103
104 /*
105 * Apply the matching function and choose the best. This is used
106 * a few times and we want to keep the code small.
107 */
108 static void
109 mapply(m, cf)
110 register struct matchinfo *m;
111 register struct cfdata *cf;
112 {
113 register int pri;
114
115 if (m->fn != NULL)
116 pri = (*m->fn)(m->parent, cf, m->aux);
117 else {
118 if (cf->cf_attach->ca_match == NULL) {
119 panic("mapply: no match function for '%s' device\n",
120 cf->cf_driver->cd_name);
121 }
122 pri = (*cf->cf_attach->ca_match)(m->parent, cf, m->aux);
123 }
124 if (pri > m->pri) {
125 m->match = cf;
126 m->pri = pri;
127 }
128 }
129
130 /*
131 * Iterate over all potential children of some device, calling the given
132 * function (default being the child's match function) for each one.
133 * Nonzero returns are matches; the highest value returned is considered
134 * the best match. Return the `found child' if we got a match, or NULL
135 * otherwise. The `aux' pointer is simply passed on through.
136 *
137 * Note that this function is designed so that it can be used to apply
138 * an arbitrary function to all potential children (its return value
139 * can be ignored).
140 */
141 struct cfdata *
142 config_search(fn, parent, aux)
143 cfmatch_t fn;
144 register struct device *parent;
145 void *aux;
146 {
147 register struct cfdata *cf;
148 register short *p;
149 struct matchinfo m;
150
151 m.fn = fn;
152 m.parent = parent;
153 m.aux = aux;
154 m.match = NULL;
155 m.pri = 0;
156 for (cf = cfdata; cf->cf_driver; cf++) {
157 /*
158 * Skip cf if no longer eligible, otherwise scan through
159 * parents for one matching `parent', and try match function.
160 */
161 if (cf->cf_fstate == FSTATE_FOUND)
162 continue;
163 for (p = cf->cf_parents; *p >= 0; p++)
164 if (parent->dv_cfdata == &cfdata[*p])
165 mapply(&m, cf);
166 }
167 return (m.match);
168 }
169
170 /*
171 * Find the given root device.
172 * This is much like config_search, but there is no parent.
173 */
174 struct cfdata *
175 config_rootsearch(fn, rootname, aux)
176 register cfmatch_t fn;
177 register char *rootname;
178 register void *aux;
179 {
180 register struct cfdata *cf;
181 register short *p;
182 struct matchinfo m;
183
184 m.fn = fn;
185 m.parent = ROOT;
186 m.aux = aux;
187 m.match = NULL;
188 m.pri = 0;
189 /*
190 * Look at root entries for matching name. We do not bother
191 * with found-state here since only one root should ever be
192 * searched (and it must be done first).
193 */
194 for (p = cfroots; *p >= 0; p++) {
195 cf = &cfdata[*p];
196 if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
197 mapply(&m, cf);
198 }
199 return (m.match);
200 }
201
202 static char *msgs[3] = { "", " not configured\n", " unsupported\n" };
203
204 /*
205 * The given `aux' argument describes a device that has been found
206 * on the given parent, but not necessarily configured. Locate the
207 * configuration data for that device (using the submatch function
208 * provided, or using candidates' cd_match configuration driver
209 * functions) and attach it, and return true. If the device was
210 * not configured, call the given `print' function and return 0.
211 */
212 struct device *
213 config_found_sm(parent, aux, print, submatch)
214 struct device *parent;
215 void *aux;
216 cfprint_t print;
217 cfmatch_t submatch;
218 {
219 struct cfdata *cf;
220
221 if ((cf = config_search(submatch, parent, aux)) != NULL)
222 return (config_attach(parent, cf, aux, print));
223 if (print)
224 printf(msgs[(*print)(aux, parent->dv_xname)]);
225 return (NULL);
226 }
227
228 /*
229 * As above, but for root devices.
230 */
231 struct device *
232 config_rootfound(rootname, aux)
233 char *rootname;
234 void *aux;
235 {
236 struct cfdata *cf;
237
238 if ((cf = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
239 return (config_attach(ROOT, cf, aux, (cfprint_t)NULL));
240 printf("root device %s not configured\n", rootname);
241 return (NULL);
242 }
243
244 /* just like sprintf(buf, "%d") except that it works from the end */
245 static char *
246 number(ep, n)
247 register char *ep;
248 register int n;
249 {
250
251 *--ep = 0;
252 while (n >= 10) {
253 *--ep = (n % 10) + '0';
254 n /= 10;
255 }
256 *--ep = n + '0';
257 return (ep);
258 }
259
260 /*
261 * Attach a found device. Allocates memory for device variables.
262 */
263 struct device *
264 config_attach(parent, cf, aux, print)
265 register struct device *parent;
266 register struct cfdata *cf;
267 register void *aux;
268 cfprint_t print;
269 {
270 register struct device *dev;
271 register struct cfdriver *cd;
272 register struct cfattach *ca;
273 register size_t lname, lunit;
274 register char *xunit;
275 int myunit;
276 char num[10];
277
278 cd = cf->cf_driver;
279 ca = cf->cf_attach;
280 if (ca->ca_devsize < sizeof(struct device))
281 panic("config_attach");
282 myunit = cf->cf_unit;
283 if (cf->cf_fstate == FSTATE_STAR)
284 cf->cf_unit++;
285 else {
286 KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
287 cf->cf_fstate = FSTATE_FOUND;
288 }
289
290 /* compute length of name and decimal expansion of unit number */
291 lname = strlen(cd->cd_name);
292 xunit = number(&num[sizeof(num)], myunit);
293 lunit = &num[sizeof(num)] - xunit;
294 if (lname + lunit >= sizeof(dev->dv_xname))
295 panic("config_attach: device name too long");
296
297 /* get memory for all device vars */
298 dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF, M_NOWAIT);
299 if (!dev)
300 panic("config_attach: memory allocation for device softc failed");
301 memset(dev, 0, ca->ca_devsize);
302 TAILQ_INSERT_TAIL(&alldevs, dev, dv_list); /* link up */
303 dev->dv_class = cd->cd_class;
304 dev->dv_cfdata = cf;
305 dev->dv_unit = myunit;
306 memcpy(dev->dv_xname, cd->cd_name, lname);
307 memcpy(dev->dv_xname + lname, xunit, lunit);
308 dev->dv_parent = parent;
309
310 if (parent == ROOT)
311 printf("%s (root)", dev->dv_xname);
312 else {
313 printf("%s at %s", dev->dv_xname, parent->dv_xname);
314 if (print)
315 (void) (*print)(aux, (char *)0);
316 }
317
318 /* put this device in the devices array */
319 if (dev->dv_unit >= cd->cd_ndevs) {
320 /*
321 * Need to expand the array.
322 */
323 int old = cd->cd_ndevs, new;
324 void **nsp;
325
326 if (old == 0)
327 new = MINALLOCSIZE / sizeof(void *);
328 else
329 new = old * 2;
330 while (new <= dev->dv_unit)
331 new *= 2;
332 cd->cd_ndevs = new;
333 nsp = malloc(new * sizeof(void *), M_DEVBUF, M_NOWAIT);
334 if (nsp == 0)
335 panic("config_attach: %sing dev array",
336 old != 0 ? "expand" : "creat");
337 memset(nsp + old, 0, (new - old) * sizeof(void *));
338 if (old != 0) {
339 memcpy(nsp, cd->cd_devs, old * sizeof(void *));
340 free(cd->cd_devs, M_DEVBUF);
341 }
342 cd->cd_devs = nsp;
343 }
344 if (cd->cd_devs[dev->dv_unit])
345 panic("config_attach: duplicate %s", dev->dv_xname);
346 cd->cd_devs[dev->dv_unit] = dev;
347
348 /*
349 * Before attaching, clobber any unfound devices that are
350 * otherwise identical, or bump the unit number on all starred
351 * cfdata for this device.
352 */
353 for (cf = cfdata; cf->cf_driver; cf++)
354 if (cf->cf_driver == cd && cf->cf_unit == dev->dv_unit) {
355 if (cf->cf_fstate == FSTATE_NOTFOUND)
356 cf->cf_fstate = FSTATE_FOUND;
357 if (cf->cf_fstate == FSTATE_STAR)
358 cf->cf_unit++;
359 }
360 #if defined(__alpha__) || defined(hp300) || defined(__i386__)
361 device_register(dev, aux);
362 #endif
363 (*ca->ca_attach)(parent, dev, aux);
364 config_process_deferred_children(dev);
365 return (dev);
366 }
367
368 /*
369 * Defer the configuration of the specified device until all
370 * of its parent's devices have been attached.
371 */
372 void
373 config_defer(dev, func)
374 struct device *dev;
375 void (*func) __P((struct device *));
376 {
377 struct deferred_config *dc;
378
379 if (dev->dv_parent == NULL)
380 panic("config_defer: can't defer config of a root device");
381
382 #ifdef DIAGNOSTIC
383 for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
384 dc = TAILQ_NEXT(dc, dc_queue)) {
385 if (dc->dc_dev == dev)
386 panic("config_defer: deferred twice");
387 }
388 #endif
389
390 if ((dc = malloc(sizeof(*dc), M_DEVBUF, M_NOWAIT)) == NULL)
391 panic("config_defer: can't allocate defer structure");
392
393 dc->dc_dev = dev;
394 dc->dc_func = func;
395 TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
396 }
397
398 /*
399 * Process the deferred configuration queue for a device.
400 */
401 static void
402 config_process_deferred_children(parent)
403 struct device *parent;
404 {
405 struct deferred_config *dc, *ndc;
406
407 for (dc = TAILQ_FIRST(&deferred_config_queue);
408 dc != NULL; dc = ndc) {
409 ndc = TAILQ_NEXT(dc, dc_queue);
410 if (dc->dc_dev->dv_parent == parent) {
411 TAILQ_REMOVE(&deferred_config_queue, dc, dc_queue);
412 (*dc->dc_func)(dc->dc_dev);
413 free(dc, M_DEVBUF);
414 }
415 }
416 }
417
418 /*
419 * Attach an event. These must come from initially-zero space (see
420 * commented-out assignments below), but that occurs naturally for
421 * device instance variables.
422 */
423 void
424 evcnt_attach(dev, name, ev)
425 struct device *dev;
426 const char *name;
427 struct evcnt *ev;
428 {
429
430 #ifdef DIAGNOSTIC
431 if (strlen(name) >= sizeof(ev->ev_name))
432 panic("evcnt_attach");
433 #endif
434 /* ev->ev_next = NULL; */
435 ev->ev_dev = dev;
436 /* ev->ev_count = 0; */
437 strcpy(ev->ev_name, name);
438 TAILQ_INSERT_TAIL(&allevents, ev, ev_list);
439 }
440