subr_bus.c revision 36849
1/*-
2 * Copyright (c) 1997 Doug Rabson
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 *	$Id$
27 */
28
29#include <sys/param.h>
30#include <sys/queue.h>
31#include <sys/malloc.h>
32#include <sys/kernel.h>
33#include <sys/module.h>
34#include <sys/bus_private.h>
35#include <sys/systm.h>
36
37device_t
38bus_get_device(bus_t bus)
39{
40    return bus->dev;
41}
42
43void
44bus_print_device(bus_t bus, device_t dev)
45{
46    printf("%s%d", device_get_name(dev), device_get_unit(dev));
47    if (device_is_alive(dev)) {
48	if (device_get_desc(dev))
49	    printf(": <%s>", device_get_desc(dev));
50	bus->ops->print_device(bus, dev);
51    } else
52	printf(" not found");
53    printf("\n");
54}
55
56int
57bus_read_ivar(bus_t bus, device_t dev,
58	      int index, u_long *result)
59{
60    return bus->ops->read_ivar(bus, dev, index, result);
61}
62
63int
64bus_write_ivar(bus_t bus, device_t dev,
65	       int index, u_long value)
66{
67    return bus->ops->write_ivar(bus, dev, index, value);
68}
69
70int
71bus_map_intr(bus_t bus, device_t dev, driver_intr_t *intr, void *arg)
72{
73    return bus->ops->map_intr(bus, dev, intr, arg);
74}
75
76static devclass_list_t devclasses;
77
78static void
79devclass_init(void)
80{
81    TAILQ_INIT(&devclasses);
82}
83
84static devclass_t
85devclass_find_internal(const char *classname, int create)
86{
87    devclass_t dc;
88
89    for (dc = TAILQ_FIRST(&devclasses); dc; dc = TAILQ_NEXT(dc, link))
90	if (!strcmp(dc->name, classname))
91	    return dc;
92
93    if (create) {
94	dc = malloc(sizeof(struct devclass) + strlen(classname) + 1,
95		    M_DEVBUF, M_NOWAIT);
96	if (!dc)
97	    return NULL;
98	dc->name = (char*) (dc + 1);
99	strcpy(dc->name, classname);
100	dc->devices = NULL;
101	dc->maxunit = 0;
102	dc->nextunit = 0;
103	TAILQ_INIT(&dc->drivers);
104	TAILQ_INSERT_TAIL(&devclasses, dc, link);
105    }
106
107    return dc;
108}
109
110devclass_t
111devclass_find(const char *classname)
112{
113    return devclass_find_internal(classname, FALSE);
114}
115
116int
117devclass_add_driver(devclass_t dc, driver_t *driver)
118{
119    /*
120     * Make sure the devclass which the driver is implementing exists.
121     */
122    devclass_find_internal(driver->name, TRUE);
123
124    TAILQ_INSERT_TAIL(&dc->drivers, driver, link);
125
126    return 0;
127}
128
129int
130devclass_delete_driver(devclass_t dc, driver_t *driver)
131{
132    bus_t bus;
133    device_t dev;
134    int i;
135    int error;
136
137    /*
138     * Disassociate from any devices.  We iterate through all the
139     * devices attached to any bus in this class.
140     */
141    for (i = 0; i < dc->maxunit; i++) {
142	if (dc->devices[i]) {
143	    bus = dc->devices[i]->softc;
144	    for (dev = TAILQ_FIRST(&bus->devices); dev;
145		 dev = TAILQ_NEXT(dev, link))
146		if (dev->driver == driver) {
147		    if (error = device_detach(dev))
148			return error;
149		    device_set_driver(dev, NULL);
150		}
151	}
152    }
153
154    TAILQ_REMOVE(&dc->drivers, driver, link);
155    return 0;
156}
157
158driver_t *
159devclass_find_driver(devclass_t dc, const char *classname)
160{
161    driver_t *driver;
162
163    for (driver = TAILQ_FIRST(&dc->drivers); driver;
164	 driver = TAILQ_NEXT(driver, link))
165	if (!strcmp(driver->name, classname))
166	    return driver;
167
168    return NULL;
169}
170
171const char *
172devclass_get_name(devclass_t dc)
173{
174    return dc->name;
175}
176
177device_t
178devclass_get_device(devclass_t dc, int unit)
179{
180    if (unit < 0 || unit >= dc->maxunit)
181	return NULL;
182    return dc->devices[unit];
183}
184
185void *
186devclass_get_softc(devclass_t dc, int unit)
187{
188    device_t dev;
189
190    if (unit < 0 || unit >= dc->maxunit)
191	return NULL;
192    dev = dc->devices[unit];
193    if (!dev || dev->state < DS_ATTACHED)
194	return NULL;
195    return dev->softc;
196}
197
198int
199devclass_get_devices(devclass_t dc, device_t **devlistp, int *devcountp)
200{
201    int i;
202    int count;
203    device_t dev;
204    device_t *list;
205
206    count = 0;
207    for (i = 0; i < dc->maxunit; i++)
208	if (dc->devices[i])
209	    count++;
210
211    list = malloc(count * sizeof(device_t), M_TEMP, M_NOWAIT);
212    if (!list)
213	return ENOMEM;
214
215    count = 0;
216    for (i = 0; i < dc->maxunit; i++)
217	if (dc->devices[i]) {
218	    list[count] = dc->devices[i];
219	    count++;
220	}
221
222    *devlistp = list;
223    *devcountp = count;
224
225    return 0;
226}
227
228int
229devclass_get_maxunit(devclass_t dc)
230{
231    return dc->maxunit;
232}
233
234static int
235devclass_alloc_unit(devclass_t dc, int *unitp)
236{
237    int unit = *unitp;
238
239    /*
240     * If we have been given a wired unit number, check for existing
241     * device.
242     */
243    if (unit != -1) {
244	device_t dev;
245	dev = devclass_get_device(dc, unit);
246	if (dev) {
247	    printf("devclass_alloc_unit: %s%d already exists, using next available unit number\n", dc->name, unit);
248	    unit = -1;
249	}
250    }
251
252    if (unit == -1) {
253	unit = dc->nextunit;
254	dc->nextunit++;
255    } else if (dc->nextunit <= unit)
256	dc->nextunit = unit + 1;
257
258    if (unit >= dc->maxunit) {
259	device_t *newlist;
260	int newsize;
261
262	newsize = (dc->maxunit ? 2 * dc->maxunit
263		   : MINALLOCSIZE / sizeof(device_t));
264	newlist = malloc(sizeof(device_t) * newsize, M_DEVBUF, M_NOWAIT);
265	if (!newlist)
266	    return ENOMEM;
267	bcopy(dc->devices, newlist, sizeof(device_t) * dc->maxunit);
268	bzero(newlist + dc->maxunit,
269	      sizeof(device_t) * (newsize - dc->maxunit));
270	if (dc->devices)
271	    free(dc->devices, M_DEVBUF);
272	dc->devices = newlist;
273	dc->maxunit = newsize;
274    }
275
276    *unitp = unit;
277    return 0;
278}
279
280static int
281devclass_add_device(devclass_t dc, device_t dev)
282{
283    int error;
284
285    if (error = devclass_alloc_unit(dc, &dev->unit))
286	return error;
287    dc->devices[dev->unit] = dev;
288    dev->devclass = dc;
289    return 0;
290}
291
292static int
293devclass_delete_device(devclass_t dc, device_t dev)
294{
295    if (dev->devclass != dc
296	|| dc->devices[dev->unit] != dev)
297	panic("devclass_delete_device: inconsistent device class");
298    dc->devices[dev->unit] = NULL;
299    if (dev->flags & DF_WILDCARD)
300	dev->unit = -1;
301    dev->devclass = NULL;
302    while (dc->nextunit > 0 && dc->devices[dc->nextunit - 1] == NULL)
303	dc->nextunit--;
304    return 0;
305}
306
307static device_t
308make_device(bus_t bus, const char *name,
309	    int unit, void *ivars)
310{
311    driver_t *driver;
312    device_t dev;
313    devclass_t dc;
314    int error;
315
316    if (name) {
317	dc = devclass_find_internal(name, TRUE);
318	if (!dc) {
319	    printf("make_device: can't find device class %s\n", name);
320	    return NULL;
321	}
322
323	if (error = devclass_alloc_unit(dc, &unit))
324	    return NULL;
325    } else
326	dc = NULL;
327
328    dev = malloc(sizeof(struct device), M_DEVBUF, M_NOWAIT);
329    if (!dev)
330	return 0;
331
332    dev->parent = bus;
333    dev->driver = NULL;
334    dev->devclass = dc;
335    dev->unit = unit;
336    dev->desc = NULL;
337    dev->busy = 0;
338    dev->flags = DF_ENABLED;
339    if (unit == -1)
340	dev->flags |= DF_WILDCARD;
341    if (name)
342	dev->flags |= DF_FIXEDCLASS;
343    dev->ivars = ivars;
344    dev->softc = NULL;
345
346    if (dc)
347	dc->devices[unit] = dev;
348
349    dev->state = DS_NOTPRESENT;
350
351    return dev;
352}
353
354void
355bus_init(bus_t bus, device_t dev, bus_ops_t *ops)
356{
357	bus->ops = ops;
358	bus->dev = dev;
359	TAILQ_INIT(&bus->devices);
360}
361
362device_t
363bus_add_device(bus_t bus, const char *name, int unit, void *ivars)
364{
365    device_t dev;
366
367    dev = make_device(bus, name, unit, ivars);
368
369    TAILQ_INSERT_TAIL(&bus->devices, dev, link);
370
371    return dev;
372}
373
374device_t
375bus_add_device_after(bus_t bus, device_t place, const char *name,
376		     int unit, void *ivars)
377{
378    device_t dev;
379
380    dev = make_device(bus, name, unit, ivars);
381
382    if (place) {
383	TAILQ_INSERT_AFTER(&bus->devices, place, dev, link);
384    } else {
385	TAILQ_INSERT_HEAD(&bus->devices, dev, link);
386    }
387
388    return dev;
389}
390
391int
392bus_delete_device(bus_t bus, device_t dev)
393{
394    int error;
395
396    if (error = device_detach(dev))
397	return error;
398    if (dev->devclass)
399	devclass_delete_device(dev->devclass, dev);
400    TAILQ_REMOVE(&bus->devices, dev, link);
401    free(dev, M_DEVBUF);
402
403    return 0;
404}
405
406/*
407 * Find only devices attached to this bus.
408 */
409device_t
410bus_find_device(bus_t bus, const char *classname, int unit)
411{
412    devclass_t dc;
413    device_t dev;
414
415    dc = devclass_find(classname);
416    if (!dc)
417	return NULL;
418
419    dev = devclass_get_device(dc, unit);
420    if (dev && dev->parent == bus)
421	return dev;
422    return NULL;
423}
424
425static driver_t *
426first_matching_driver(devclass_t dc, device_t dev)
427{
428    if (dev->devclass)
429	return devclass_find_driver(dc, dev->devclass->name);
430    else
431	return TAILQ_FIRST(&dc->drivers);
432}
433
434static driver_t *
435next_matching_driver(devclass_t dc, device_t dev, driver_t *last)
436{
437    if (dev->devclass) {
438	driver_t *driver;
439	for (driver = TAILQ_NEXT(last, link); driver;
440	     driver = TAILQ_NEXT(driver, link))
441	    if (!strcmp(dev->devclass->name, driver->name))
442		return driver;
443	return NULL;
444    } else
445	return TAILQ_NEXT(last, link);
446}
447
448static int
449bus_probe_device(bus_t bus, device_t dev)
450{
451    devclass_t dc;
452    driver_t *driver;
453    void *softc;
454
455    dc = bus->dev->devclass;
456    if (dc == NULL)
457	panic("bus_probe_device: bus' device has no devclass");
458
459    if (dev->state == DS_ALIVE)
460	return 0;
461
462    for (driver = first_matching_driver(dc, dev);
463	 driver;
464	 driver = next_matching_driver(dc, dev, driver)) {
465	device_set_driver(dev, driver);
466	if (driver->probe(bus, dev) == 0) {
467	    if (!dev->devclass)
468		device_set_devclass(dev, driver->name);
469	    dev->state = DS_ALIVE;
470	    return 0;
471	}
472    }
473
474    return ENXIO;
475}
476
477int
478bus_generic_attach(bus_t parent, device_t busdev)
479{
480    bus_t bus = busdev->softc;
481    device_t dev;
482    int error;
483
484    for (dev = TAILQ_FIRST(&bus->devices);
485	 dev; dev = TAILQ_NEXT(dev, link))
486	device_probe_and_attach(dev);
487
488    return 0;
489}
490
491int
492bus_generic_detach(bus_t parent, device_t busdev)
493{
494    bus_t bus = busdev->softc;
495    device_t dev;
496    int error;
497
498    if (busdev->state != DS_ATTACHED)
499	return EBUSY;
500
501    for (dev = TAILQ_FIRST(&bus->devices);
502	 dev; dev = TAILQ_NEXT(dev, link))
503	device_detach(dev);
504
505    return 0;
506}
507
508int
509bus_generic_shutdown(bus_t parent, device_t busdev)
510{
511    bus_t bus = busdev->softc;
512    device_t dev;
513
514    for (dev = TAILQ_FIRST(&bus->devices);
515	 dev; dev = TAILQ_NEXT(dev, link))
516	device_shutdown(dev);
517
518    return 0;
519}
520
521bus_t
522device_get_parent(device_t dev)
523{
524    return dev->parent;
525}
526
527driver_t *
528device_get_driver(device_t dev)
529{
530    return dev->driver;
531}
532
533devclass_t
534device_get_devclass(device_t dev)
535{
536    return dev->devclass;
537}
538
539const char *
540device_get_name(device_t dev)
541{
542    if (dev->devclass)
543	return devclass_get_name(dev->devclass);
544    return NULL;
545}
546
547int
548device_get_unit(device_t dev)
549{
550    return dev->unit;
551}
552
553const char *
554device_get_desc(device_t dev)
555{
556    return dev->desc;
557}
558
559void
560device_set_desc(device_t dev, const char* desc)
561{
562    dev->desc = desc;
563}
564
565void *
566device_get_softc(device_t dev)
567{
568    return dev->softc;
569}
570
571void *
572device_get_ivars(device_t dev)
573{
574    return dev->ivars;
575}
576
577device_state_t
578device_get_state(device_t dev)
579{
580    return dev->state;
581}
582
583void
584device_enable(device_t dev)
585{
586    dev->flags |= DF_ENABLED;
587}
588
589void
590device_disable(device_t dev)
591{
592    dev->flags &= ~DF_ENABLED;
593}
594
595void
596device_busy(device_t dev)
597{
598    if (dev->state < DS_ATTACHED)
599	panic("device_busy: called for unattached device");
600    if (dev->busy == 0 && dev->parent)
601	device_busy(dev->parent->dev);
602    dev->busy++;
603    dev->state = DS_BUSY;
604}
605
606void
607device_unbusy(device_t dev)
608{
609    if (dev->state != DS_BUSY)
610	panic("device_unbusy: called for non-busy device");
611    dev->busy--;
612    if (dev->busy == 0) {
613	if (dev->parent->dev)
614	    device_unbusy(dev->parent->dev);
615	dev->state = DS_ATTACHED;
616    }
617}
618
619int
620device_is_enabled(device_t dev)
621{
622    return (dev->flags & DF_ENABLED) != 0;
623}
624
625int
626device_is_alive(device_t dev)
627{
628    return dev->state >= DS_ALIVE;
629}
630
631int
632device_set_devclass(device_t dev, const char *classname)
633{
634    devclass_t dc;
635
636    if (dev->devclass) {
637	printf("device_set_devclass: device class already set\n");
638	return EINVAL;
639    }
640
641    dc = devclass_find_internal(classname, TRUE);
642    if (!dc)
643	return ENOMEM;
644
645    return devclass_add_device(dc, dev);
646}
647
648int
649device_set_driver(device_t dev, driver_t *driver)
650{
651    if (dev->state >= DS_ATTACHED)
652	return EBUSY;
653
654    if (dev->driver == driver)
655	return 0;
656
657    if (dev->softc) {
658	free(dev->softc, M_DEVBUF);
659	dev->softc = NULL;
660    }
661    dev->driver = driver;
662    if (driver) {
663	dev->softc = malloc(driver->softc, M_DEVBUF, M_NOWAIT);
664	bzero(dev->softc, driver->softc);
665    }
666    return 0;
667}
668
669int
670device_probe_and_attach(device_t dev)
671{
672    bus_t bus = dev->parent;
673    int error;
674
675    if (dev->state >= DS_ALIVE)
676	return 0;
677
678    if (dev->flags & DF_ENABLED) {
679	bus_probe_device(bus, dev);
680	bus_print_device(bus, dev);
681	if (dev->state == DS_ALIVE) {
682	    error = dev->driver->attach(bus, dev);
683	    if (!error)
684		dev->state = DS_ATTACHED;
685	    else {
686		printf("device_probe_and_attach: %s%n attach returned %d\n",
687		       dev->driver->name, dev->unit, error);
688		device_set_driver(dev, NULL);
689		dev->state = DS_NOTPRESENT;
690	    }
691	}
692    } else
693	printf("%s%d: disabled, not probed.\n",
694	       dev->devclass->name, dev->unit);
695
696    return 0;
697}
698
699int
700device_detach(device_t dev)
701{
702    int error;
703
704    if (dev->state == DS_BUSY)
705	return EBUSY;
706    if (dev->state != DS_ATTACHED)
707	return 0;
708
709    if (dev->driver->detach) {
710	if (error = dev->driver->detach(dev->parent, dev))
711	    return error;
712    } else
713	return EBUSY;
714
715    if (!(dev->flags & DF_FIXEDCLASS))
716	devclass_delete_device(dev->devclass, dev);
717
718    dev->state = DS_NOTPRESENT;
719    device_set_driver(dev, NULL);
720
721    return 0;
722}
723
724int
725device_shutdown(device_t dev)
726{
727    if (dev->state < DS_ATTACHED)
728	return 0;
729    if (dev->driver->shutdown)
730	return dev->driver->shutdown(dev->parent, dev);
731    else
732	return 0;
733}
734
735void
736null_print_device(bus_t bus, device_t dev)
737{
738}
739
740int
741null_read_ivar(bus_t bus, device_t dev, int index, u_long* result)
742{
743    return ENOENT;
744}
745
746int
747null_write_ivar(bus_t bus, device_t dev, int index, u_long value)
748{
749    return ENOENT;
750}
751
752int
753null_map_intr(bus_t bus, device_t dev, driver_intr_t *intr, void *arg)
754{
755    /* Propagate up the bus hierarchy until someone handles it. */
756    if (bus->dev)
757	return bus_map_intr(bus->dev->parent, bus->dev, intr, arg);
758    else
759	return EINVAL;
760}
761
762bus_ops_t null_bus_ops = {
763    null_print_device,
764    null_read_ivar,
765    null_write_ivar,
766    null_map_intr,
767};
768
769static void
770root_bus_print_device(bus_t bus, device_t dev)
771{
772}
773
774static int root_bus_map_intr(bus_t bus, device_t dev,
775			     driver_intr_t *intr, void *arg)
776{
777    return EINVAL;
778}
779
780static bus_ops_t root_bus_ops = {
781    root_bus_print_device,
782    null_read_ivar,
783    null_write_ivar,
784    root_bus_map_intr,
785};
786
787static struct bus the_root_bus;
788bus_t root_bus = &the_root_bus;
789device_t root_device;
790devclass_t root_devclass;
791
792static int
793root_bus_module_handler(module_t mod, modeventtype_t what, void* arg)
794{
795    switch (what) {
796    case MOD_LOAD:
797	devclass_init();
798	root_device = make_device(NULL, "root", 0, NULL);
799	root_device->state = DS_ATTACHED;
800	bus_init(root_bus, root_device, &root_bus_ops);
801	root_devclass = devclass_find("root");
802	return 0;
803    }
804
805    return 0;
806}
807
808static moduledata_t root_bus_mod = {
809	"rootbus",
810	root_bus_module_handler,
811	0
812};
813DECLARE_MODULE(rootbus, root_bus_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
814
815void
816root_bus_configure()
817{
818    device_t dev;
819    int error;
820
821    for (dev = TAILQ_FIRST(&root_bus->devices); dev;
822	 dev = TAILQ_NEXT(dev, link)) {
823	device_probe_and_attach(dev);
824    }
825}
826
827int
828driver_module_handler(module_t mod, modeventtype_t what, void* arg)
829{
830    struct driver_module_data* data = (struct driver_module_data*) arg;
831    devclass_t bus_devclass = devclass_find_internal(data->busname, TRUE);
832    int error;
833
834    switch (what) {
835    case MOD_LOAD:
836	if (error = devclass_add_driver(bus_devclass,
837					data->driver))
838	    return error;
839	*data->devclass =
840	    devclass_find_internal(data->driver->name, TRUE);
841	break;
842
843    case MOD_UNLOAD:
844	if (error = devclass_delete_driver(bus_devclass,
845					   data->driver))
846	    return error;
847	break;
848    }
849
850    if (data->chainevh)
851	return data->chainevh(mod, what, data->chainarg);
852    else
853	return 0;
854}
855