aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/kern/bus_if.m18
-rw-r--r--sys/kern/device_if.m43
-rw-r--r--sys/kern/makedevops.pl58
-rw-r--r--sys/kern/subr_bus.c61
-rw-r--r--sys/sys/bus_private.h14
5 files changed, 160 insertions, 34 deletions
diff --git a/sys/kern/bus_if.m b/sys/kern/bus_if.m
index d7c9cd4a8501..33383ff6c2bd 100644
--- a/sys/kern/bus_if.m
+++ b/sys/kern/bus_if.m
@@ -23,12 +23,26 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
-# $Id: bus_if.m,v 1.7 1999/04/16 21:22:37 peter Exp $
+# $Id: bus_if.m,v 1.8 1999/05/08 21:59:34 dfr Exp $
#
INTERFACE bus;
#
+# Default implementations of some methods.
+#
+CODE {
+ static struct resource *
+ null_alloc_resource(device_t dev, device_t child,
+ int type, int *rid,
+ u_long start, u_long end,
+ u_long count, u_int flags)
+ {
+ return 0;
+ }
+};
+
+#
# This is called from system code which prints out a description of a
# device. It should describe the attachment that the child has with
# the parent. For instance the TurboLaser bus prints which node the
@@ -112,7 +126,7 @@ METHOD struct resource * alloc_resource {
u_long end;
u_long count;
u_int flags;
-};
+} DEFAULT null_alloc_resource;
METHOD int activate_resource {
device_t dev;
diff --git a/sys/kern/device_if.m b/sys/kern/device_if.m
index f429e67759a0..0d8e8f425111 100644
--- a/sys/kern/device_if.m
+++ b/sys/kern/device_if.m
@@ -23,14 +23,47 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
-# $Id: device_if.m,v 1.2 1998/11/08 18:35:53 nsouch Exp $
+# $Id: device_if.m,v 1.3 1998/11/14 21:58:51 wollman Exp $
#
INTERFACE device;
#
+# Default implementations of some methods.
+#
+CODE {
+ static int null_shutdown(device_t dev)
+ {
+ return 0;
+ }
+
+ static int null_suspend(device_t dev)
+ {
+ return 0;
+ }
+
+ static int null_resume(device_t dev)
+ {
+ return 0;
+ }
+};
+
+#
# Probe to see if the device is present. Return 0 if the device exists,
-# ENXIO if it cannot be found.
+# ENXIO if it cannot be found. For cases where more than one driver
+# matches a device, a priority value can be returned. In this case,
+# success codes are values less than or equal to zero with the highest
+# value representing the best match. Failure codes are represented by
+# positive values and the regular unix error codes should be used for
+# the purpose.
+#
+# If a driver returns a success code which is less than zero, it must
+# not assume that it will be the same driver which is attached to the
+# device. In particular, it must not assume that any values stored in
+# the softc structure will be available for its attach method and any
+# resources allocated during probe must be released and re-allocated
+# if the attach method is called. If a success code of zero is
+# returned, the driver can assume that it will be the one attached.
#
# Devices which implement busses should use this method to probe for
# the existence of devices attached to the bus and add them as
@@ -66,7 +99,7 @@ METHOD int detach {
#
METHOD int shutdown {
device_t dev;
-};
+} DEFAULT null_shutdown;
#
# This is called by the power-management subsystem when a suspend has been
@@ -76,8 +109,8 @@ METHOD int shutdown {
#
METHOD int suspend {
device_t dev;
-};
+} DEFAULT null_suspend;
METHOD int resume {
device_t dev;
-};
+} DEFAULT null_resume;
diff --git a/sys/kern/makedevops.pl b/sys/kern/makedevops.pl
index 8b991b7984b8..0ab8e69a5916 100644
--- a/sys/kern/makedevops.pl
+++ b/sys/kern/makedevops.pl
@@ -35,7 +35,7 @@
# From @(#)makedevops.sh 1.1 1998/06/14 13:53:12 dfr Exp $
# From @(#)makedevops.sh ?.? 1998/10/05
#
-# $Id$
+# $Id: makedevops.pl,v 1.6 1999/05/02 08:55:27 markm Exp $
#
# Script to produce device front-end sugar.
@@ -219,7 +219,18 @@ foreach $src ( @filenames ) {
print CFILE '#include "'.$intname.'_if.h"'."\n\n"
if $cfile;
- } elsif ( $line =~ m/^METHOD/i ) {
+ } elsif ( $line =~ m/^CODE\s*{$/i ) {
+ $code = "";
+ $line = <SRC>;
+ while ( $line !~ m/^}/ ) {
+ $code .= $line;
+ $line = <SRC>;
+ $lineno++
+ }
+ if ( $cfile ) {
+ print CFILE $code;
+ }
+ } elsif ( $line =~ m/^(STATIC|)METHOD/i ) {
# Get the return type function name and delete that from
# the line. What is left is the possibly first function argument
# if it is on the same line.
@@ -231,8 +242,9 @@ foreach $src ( @filenames ) {
$error = 1;
last LINE;
}
- $line =~ s/^METHODE?\s+([^{]+?)\s*{\s*//i;
- @ret = split m/\s+/, $1;
+ $line =~ s/^(STATIC|)METHODE?\s+([^{]+?)\s*{\s*//i;
+ $static = $1;
+ @ret = split m/\s+/, $2;
$name = pop @ret; # last element is name of method
$ret = join(" ", @ret); # return type
@@ -267,14 +279,20 @@ foreach $src ( @filenames ) {
$lineno++
}
- if ( $line !~ s/};?(.*)// ) { # remove first '}' and trailing garbage
- # The '}' was not there (the rest is optional), so complain
- warn "$src:$lineno: Premature end of file";
- $error = 1;
- last LINE;
- }
- warn "$src:$lineno: Ignored '$1'" # warn about garbage at end of line
- if $debug and $1;
+ $default = "";
+ if ( $line !~ s/};?(.*)// ) { # remove first '}' and trailing garbage
+ # The '}' was not there (the rest is optional), so complain
+ warn "$src:$lineno: Premature end of file";
+ $error = 1;
+ last LINE;
+ }
+ $extra = $1;
+ if ( $extra =~ /\s*DEFAULT\s*([a-zA-Z_][a-zA-Z_0-9]*)\s*;/ ) {
+ $default = $1;
+ } else {
+ warn "$src:$lineno: Ignored '$1'" # warn about garbage at end of line
+ if $debug and $1;
+ }
# Create a list of variables without the types prepended
#
@@ -308,6 +326,8 @@ foreach $src ( @filenames ) {
$arguments = join(", ", @arguments);
$varnames = join(", ", @varnames);
+ $default = "0" if $default eq "";
+
if ( $hfile ) {
# the method description
print HFILE "extern struct device_op_desc $mname\_desc;\n";
@@ -323,7 +343,7 @@ foreach $src ( @filenames ) {
if ( $cfile ) {
# Print out the method desc
print CFILE "struct device_op_desc $mname\_desc = {\n";
- print CFILE "\t0, 0, \"$mname\"\n";
+ print CFILE "\t0, 0, (devop_t) $default, \"$mname\"\n";
print CFILE "};\n\n";
# Print out the method itself
@@ -336,9 +356,15 @@ foreach $src ( @filenames ) {
',', ' ' x length("$ret $umname(")) . "\n";
}
print CFILE "{\n";
- print CFILE &format_line("\t$mname\_t *m = ($mname\_t *) DEVOPMETH(dev, $mname);",
- $line_width-8, ' = ', ' =', "\t\t")
- . "\n";
+ if ($static) {
+ print CFILE &format_line("\t$mname\_t *m = ($mname\_t *) DRVOPMETH(driver, $mname);",
+ $line_width-8, ' = ', ' =', "\t\t")
+ . "\n";
+ } else {
+ print CFILE &format_line("\t$mname\_t *m = ($mname\_t *) DEVOPMETH(dev, $mname);",
+ $line_width-8, ' = ', ' =', "\t\t")
+ . "\n";
+ }
print CFILE "\t".($ret eq 'void'? '':'return ') . "m($varnames);\n";
print CFILE "}\n\n";
}
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index c9281f5d6924..8224b4a8c8c0 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;
}
diff --git a/sys/sys/bus_private.h b/sys/sys/bus_private.h
index 9c138c592386..cbc2872141cd 100644
--- a/sys/sys/bus_private.h
+++ b/sys/sys/bus_private.h
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: bus_private.h,v 1.5 1999/03/29 08:54:19 dfr Exp $
+ * $Id: bus_private.h,v 1.6 1999/04/16 21:22:54 peter Exp $
*/
#ifndef _SYS_BUS_PRIVATE_H_
@@ -93,12 +93,15 @@ struct device_ops {
*/
#define DEVOPDESC(OP) (&OP##_##desc)
-#define DEVOPOFF(DEV, OP) \
- ((DEVOPDESC(OP)->offset >= DEV->ops->maxoffset \
- || !DEV->ops->methods[DEVOPDESC(OP)->offset]) \
+#define DEVOPOFF(OPS, OP) \
+ ((DEVOPDESC(OP)->offset >= OPS->maxoffset \
+ || !OPS->methods[DEVOPDESC(OP)->offset]) \
? 0 : DEVOPDESC(OP)->offset)
-#define DEVOPMETH(DEV, OP) (DEV->ops->methods[DEVOPOFF(DEV, OP)])
+#define DEVOPS(DEV) (DEV->ops)
+#define DEVOPMETH(DEV, OP) (DEVOPS(DEV)->methods[DEVOPOFF(DEVOPS(DEV), OP)])
+#define DRVOPS(DRV) ((struct device_ops *)DRV->ops)
+#define DRVOPMETH(DRV, OP) (DRVOPS(DRV)->methods[DEVOPOFF(DRVOPS(DRV), OP)])
/*
* Implementation of device.
@@ -139,6 +142,7 @@ struct device {
struct device_op_desc {
unsigned int offset; /* offset in driver ops */
struct method* method; /* internal method implementation */
+ devop_t deflt; /* default implementation */
const char* name; /* unique name (for registration) */
};