* 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.
This commit is contained in:
parent
276794a4a4
commit
8b2970bbe6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=46913
@ -23,11 +23,25 @@
|
||||
# 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
|
||||
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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,12 +747,51 @@ 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;
|
||||
|
@ -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) */
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user