diff options
author | dfr <dfr@FreeBSD.org> | 1999-05-10 17:06:14 +0000 |
---|---|---|
committer | dfr <dfr@FreeBSD.org> | 1999-05-10 17:06:14 +0000 |
commit | 1a3fdb21c5acf7af5eca2961539bd7f56a877ce4 (patch) | |
tree | bdc48f1aabde5d55cbfb9dfdcfa5aec92a0e21b3 /sys/kern/subr_bus.c | |
parent | 951dcb68cee2c9e6497dc48f2e3de3440be0b3c9 (diff) | |
download | FreeBSD-src-1a3fdb21c5acf7af5eca2961539bd7f56a877ce4.zip FreeBSD-src-1a3fdb21c5acf7af5eca2961539bd7f56a877ce4.tar.gz |
* Augment the interface language to allow arbitrary C code to be 'passed
through' to the C compiler.
* Allow the interface to specify a default implementation for methods.
* Allow 'static' methods which are not device specific.
* Add a simple scheme for probe routines to return a priority value. To
make life simple, priority values are negative numbers (positive numbers
are standard errno codes) with zero being the highest priority. The
driver which returns the highest priority will be chosen for the device.
Diffstat (limited to 'sys/kern/subr_bus.c')
-rw-r--r-- | sys/kern/subr_bus.c | 61 |
1 files changed, 55 insertions, 6 deletions
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index c9281f5..8224b4a 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: subr_bus.c,v 1.19 1999/05/08 18:08:59 peter Exp $ + * $Id: subr_bus.c,v 1.20 1999/05/08 21:59:35 dfr Exp $ */ #include <sys/param.h> @@ -100,6 +100,7 @@ struct method { LIST_ENTRY(method) link; /* linked list of methods */ int offset; /* offset in method table */ int refs; /* count of device_op_desc users */ + devop_t deflt; /* default implementation */ char* name; /* unique name of method */ }; @@ -132,6 +133,7 @@ register_method(struct device_op_desc *desc) bzero(m, sizeof(struct method) + strlen(desc->name) + 1); m->offset = next_method_offset++; m->refs = 1; + m->deflt = desc->deflt; m->name = (char*) (m + 1); strcpy(m->name, desc->name); LIST_INSERT_HEAD(&methods, m, link); @@ -167,6 +169,7 @@ compile_methods(driver_t *driver) { device_ops_t ops; struct device_method *m; + struct method *cm; int i; /* @@ -185,8 +188,13 @@ compile_methods(driver_t *driver) bzero(ops, sizeof(struct device_ops) + (next_method_offset-1) * sizeof(devop_t)); ops->maxoffset = next_method_offset; + /* Fill in default methods and then overwrite with driver methods */ for (i = 0; i < next_method_offset; i++) ops->methods[i] = error_method; + for (cm = LIST_FIRST(&methods); cm; cm = LIST_NEXT(cm, link)) { + if (cm->deflt) + ops->methods[cm->offset] = cm->deflt; + } for (i = 0, m = driver->methods; m->desc; i++, m++) ops->methods[m->desc->offset] = m->func; PDEBUG(("%s has %d method%s, wasting %d bytes", @@ -723,7 +731,9 @@ static int device_probe_child(device_t dev, device_t child) { devclass_t dc; + driverlink_t best = 0; driverlink_t dl; + int result, pri = 0; dc = dev->devclass; if (dc == NULL) @@ -737,14 +747,53 @@ device_probe_child(device_t dev, device_t child) dl = next_matching_driver(dc, child, dl)) { PDEBUG(("Trying %s", DRIVERNAME(dl->driver))); device_set_driver(child, dl->driver); - if (DEVICE_PROBE(child) == 0) { - if (!child->devclass) - device_set_devclass(child, dl->driver->name); - child->state = DS_ALIVE; - return 0; + result = DEVICE_PROBE(child); + + /* + * If the driver returns SUCCESS, there can be no higher match + * for this device. + */ + if (result == 0) { + best = dl; + pri = 0; + break; + } + + /* + * The driver returned an error so it certainly doesn't match. + */ + if (result > 0) + continue; + + /* + * A priority lower than SUCCESS, remember the best matching + * driver. Initialise the value of pri for the first match. + */ + if (best == 0 || result > pri) { + best = dl; + pri = result; + continue; } } + /* + * If we found a driver, change state and initialise the devclass. + */ + if (best) { + if (!child->devclass) + device_set_devclass(child, best->driver->name); + device_set_driver(child, best->driver); + if (pri < 0) { + /* + * A bit bogus. Call the probe method again to make sure + * that we have the right description. + */ + DEVICE_PROBE(child); + } + child->state = DS_ALIVE; + return 0; + } + return ENXIO; } |