* Copyright (c) 1992 Regents of the University of California.
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratories.
* %sccs.include.redist.c%
* @(#)subr_autoconf.c 7.6 (Berkeley) %G%
* from: $Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp $ (LBL)
* Autoconfiguration subroutines.
* ioconf.c exports exactly two names: cfdata and cfroots. All system
* devices and drivers are found via these tables.
extern struct cfdata cfdata
[];
#define ROOT ((struct device *)NULL)
* Apply the matching function and choose the best. This is used
* a few times and we want to keep the code small.
register struct matchinfo
*m
;
register struct cfdata
*cf
;
pri
= (*m
->fn
)(m
->parent
, cf
, m
->aux
);
pri
= (*cf
->cf_driver
->cd_match
)(m
->parent
, cf
, m
->aux
);
* Iterate over all potential children of some device, calling the given
* function (default being the child's match function) for each one.
* Nonzero returns are matches; the highest value returned is considered
* the best match. Return the `found child' if we got a match, or NULL
* otherwise. The `aux' pointer is simply passed on through.
* Note that this function is designed so that it can be used to apply
* an arbitrary function to all potential children (its return value
config_search(fn
, parent
, aux
)
register struct device
*parent
;
register struct cfdata
*cf
;
for (cf
= cfdata
; cf
->cf_driver
; cf
++) {
* Skip cf if no longer eligible, otherwise scan through
* parents for one matching `parent', and try match function.
if (cf
->cf_fstate
== FSTATE_FOUND
)
for (p
= cf
->cf_parents
; *p
>= 0; p
++)
if (parent
->dv_cfdata
== &cfdata
[*p
])
* Find the given root device.
* This is much like config_search, but there is no parent.
config_rootsearch(fn
, rootname
, aux
)
register struct cfdata
*cf
;
* Look at root entries for matching name. We do not bother
* with found-state here since only one root should ever be
* searched (and it must be done first).
for (p
= cfroots
; *p
>= 0; p
++) {
if (strcmp(cf
->cf_driver
->cd_name
, rootname
) == 0)
static char *msgs
[3] = { "", " not configured\n", " unsupported\n" };
* The given `aux' argument describes a device that has been found
* on the given parent, but not necessarily configured. Locate the
* configuration data for that device (using the cd_match configuration
* driver function) and attach it, and return true. If the device was
* not configured, call the given `print' function and return 0.
config_found(parent
, aux
, print
)
if ((cf
= config_search((cfmatch_t
)NULL
, parent
, aux
)) != NULL
) {
config_attach(parent
, cf
, aux
, print
);
printf(msgs
[(*print
)(aux
, parent
->dv_xname
)]);
* As above, but for root devices.
config_rootfound(rootname
, aux
)
if ((cf
= config_rootsearch((cfmatch_t
)NULL
, rootname
, aux
)) != NULL
) {
config_attach(ROOT
, cf
, aux
, (cfprint_t
)NULL
);
printf("root device %s not configured\n", rootname
);
/* just like sprintf(buf, "%d") except that it works from the end */
* Attach a found device. Allocates memory for device variables.
config_attach(parent
, cf
, aux
, print
)
register struct device
*parent
;
register struct cfdata
*cf
;
register struct device
*dev
;
register struct cfdriver
*cd
;
register size_t lname
, lunit
;
static struct device
**nextp
= &alldevs
;
if (cd
->cd_devsize
< sizeof(struct device
))
if (cf
->cf_fstate
== FSTATE_NOTFOUND
)
cf
->cf_fstate
= FSTATE_FOUND
;
/* compute length of name and decimal expansion of unit number */
lname
= strlen(cd
->cd_name
);
xunit
= number(&num
[sizeof num
], myunit
);
lunit
= &num
[sizeof num
] - xunit
;
if (lname
+ lunit
>= sizeof(dev
->dv_xname
))
panic("config_attach: device name too long");
/* get memory for all device vars */
dev
= (struct device
*)malloc(cd
->cd_devsize
, M_DEVBUF
, M_WAITOK
);
bzero(dev
, cd
->cd_devsize
);
*nextp
= dev
; /* link up */
dev
->dv_class
= cd
->cd_class
;
bcopy(cd
->cd_name
, dev
->dv_xname
, lname
);
bcopy(xunit
, dev
->dv_xname
+ lname
, lunit
);
printf("%s (root)", dev
->dv_xname
);
printf("%s at %s", dev
->dv_xname
, parent
->dv_xname
);
(void) (*print
)(aux
, (char *)0);
/* put this device in the devices array */
if (dev
->dv_unit
>= cd
->cd_ndevs
) {
* Need to expand the array.
int old
= cd
->cd_ndevs
, oldbytes
, new, newbytes
;
nsp
= malloc(MINALLOCSIZE
, M_DEVBUF
, M_WAITOK
); /*XXX*/
bzero(nsp
, MINALLOCSIZE
);
cd
->cd_ndevs
= MINALLOCSIZE
/ sizeof(void *);
} while (new <= dev
->dv_unit
);
oldbytes
= old
* sizeof(void *);
newbytes
= new * sizeof(void *);
nsp
= malloc(newbytes
, M_DEVBUF
, M_WAITOK
); /*XXX*/
bcopy(cd
->cd_devs
, nsp
, oldbytes
);
bzero(&nsp
[old
], newbytes
- oldbytes
);
free(cd
->cd_devs
, M_DEVBUF
);
if (cd
->cd_devs
[dev
->dv_unit
])
panic("config_attach: duplicate %s", dev
->dv_xname
);
cd
->cd_devs
[dev
->dv_unit
] = dev
;
* Before attaching, clobber any unfound devices that are
for (cf
= cfdata
; cf
->cf_driver
; cf
++)
if (cf
->cf_driver
== cd
&& cf
->cf_unit
== dev
->dv_unit
&&
cf
->cf_fstate
== FSTATE_NOTFOUND
)
cf
->cf_fstate
= FSTATE_FOUND
;
(*cd
->cd_attach
)(parent
, dev
, aux
);
* Attach an event. These must come from initially-zero space (see
* commented-out assignments below), but that occurs naturally for
* device instance variables.
evcnt_attach(dev
, name
, ev
)
static struct evcnt
**nextp
= &allevents
;
if (strlen(name
) >= sizeof(ev
->ev_name
))
/* ev->ev_next = NULL; */
strcpy(ev
->ev_name
, name
);