* Factor out the object system from new-bus so that it can be used by
non-device code. * Re-implement the method dispatch to improve efficiency. The new system takes about 40ns for a method dispatch on a 300Mhz PII which is only 10ns slower than a direct function call on the same hardware. This changes the new-bus ABI slightly so make sure you re-compile any driver modules which you use.
This commit is contained in:
parent
c685012659
commit
f7b7769172
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=59093
@ -26,6 +26,7 @@
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
#include <sys/bus.h>
|
||||
#include <machine/clockvar.h>
|
||||
|
||||
INTERFACE clock;
|
||||
|
@ -73,7 +73,7 @@ NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC}
|
||||
NORMAL_S= ${CC} -c ${ASM_CFLAGS} ${.IMPSRC}
|
||||
PROFILE_C= ${CC} -c ${CFLAGS} ${.IMPSRC}
|
||||
|
||||
NORMAL_M= perl5 $S/kern/makedevops.pl -c $<; \
|
||||
NORMAL_M= perl5 $S/kern/makeobjops.pl -c $<; \
|
||||
${CC} -c ${CFLAGS} ${PROF} ${.PREFIX}.c
|
||||
|
||||
GEN_CFILES= $S/$M/$M/genassym.c
|
||||
@ -127,7 +127,7 @@ ${SYSTEM_OBJS}: vnode_if.h ${BEFORE_DEPEND:M*.h} ${MFILES:T:S/.m$/.h/}
|
||||
|
||||
.for mfile in ${MFILES}
|
||||
${mfile:T:S/.m$/.h/}: ${mfile}
|
||||
perl5 $S/kern/makedevops.pl -h ${mfile}
|
||||
perl5 $S/kern/makeobjops.pl -h ${mfile}
|
||||
.endfor
|
||||
|
||||
clean:
|
||||
|
@ -73,7 +73,7 @@ NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC}
|
||||
NORMAL_S= ${CC} -c ${ASM_CFLAGS} ${.IMPSRC}
|
||||
PROFILE_C= ${CC} -c ${CFLAGS} ${.IMPSRC}
|
||||
|
||||
NORMAL_M= perl5 $S/kern/makedevops.pl -c $<; \
|
||||
NORMAL_M= perl5 $S/kern/makeobjops.pl -c $<; \
|
||||
${CC} -c ${CFLAGS} ${PROF} ${.PREFIX}.c
|
||||
|
||||
GEN_CFILES= $S/$M/$M/genassym.c
|
||||
@ -126,7 +126,7 @@ ${SYSTEM_OBJS}: vnode_if.h ${BEFORE_DEPEND:M*.h} ${MFILES:T:S/.m$/.h/}
|
||||
|
||||
.for mfile in ${MFILES}
|
||||
${mfile:T:S/.m$/.h/}: ${mfile}
|
||||
perl5 $S/kern/makedevops.pl -h ${mfile}
|
||||
perl5 $S/kern/makeobjops.pl -h ${mfile}
|
||||
.endfor
|
||||
|
||||
clean:
|
||||
|
@ -73,7 +73,7 @@ NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC}
|
||||
NORMAL_S= ${CC} -c ${ASM_CFLAGS} ${.IMPSRC}
|
||||
PROFILE_C= ${CC} -c ${CFLAGS} ${.IMPSRC}
|
||||
|
||||
NORMAL_M= perl5 $S/kern/makedevops.pl -c $<; \
|
||||
NORMAL_M= perl5 $S/kern/makeobjops.pl -c $<; \
|
||||
${CC} -c ${CFLAGS} ${PROF} ${.PREFIX}.c
|
||||
|
||||
GEN_CFILES= $S/$M/$M/genassym.c
|
||||
@ -126,7 +126,7 @@ ${SYSTEM_OBJS}: vnode_if.h ${BEFORE_DEPEND:M*.h} ${MFILES:T:S/.m$/.h/}
|
||||
|
||||
.for mfile in ${MFILES}
|
||||
${mfile:T:S/.m$/.h/}: ${mfile}
|
||||
perl5 $S/kern/makedevops.pl -h ${mfile}
|
||||
perl5 $S/kern/makeobjops.pl -h ${mfile}
|
||||
.endfor
|
||||
|
||||
clean:
|
||||
|
@ -408,6 +408,7 @@ kern/subr_devstat.c standard
|
||||
kern/subr_disk.c standard
|
||||
kern/subr_diskslice.c standard
|
||||
kern/subr_eventhandler.c standard
|
||||
kern/subr_kobj.c standard
|
||||
kern/subr_log.c standard
|
||||
kern/subr_module.c standard
|
||||
kern/subr_prf.c standard
|
||||
|
@ -26,6 +26,8 @@
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
INTERFACE mcclock;
|
||||
|
||||
#
|
||||
|
@ -26,6 +26,8 @@
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
INTERFACE iicbb;
|
||||
|
||||
#
|
||||
|
@ -26,6 +26,8 @@
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
INTERFACE iicbus;
|
||||
|
||||
#
|
||||
|
@ -1,5 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
INTERFACE miibus;
|
||||
|
||||
#
|
||||
|
@ -940,7 +940,7 @@ compat_pci_handler(module_t mod, int type, void *data)
|
||||
bzero(driver, sizeof(driver_t));
|
||||
driver->name = dvp->pd_name;
|
||||
driver->methods = pci_compat_methods;
|
||||
driver->softc = sizeof(struct pci_devinfo *);
|
||||
driver->size = sizeof(struct pci_devinfo *);
|
||||
driver->priv = dvp;
|
||||
devclass_add_driver(pci_devclass, driver);
|
||||
break;
|
||||
|
@ -26,6 +26,8 @@
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
INTERFACE pci;
|
||||
|
||||
METHOD u_int32_t read_config {
|
||||
|
@ -26,6 +26,7 @@
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
#include <sys/bus.h>
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
|
||||
INTERFACE ppbus;
|
||||
|
@ -26,6 +26,8 @@
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
INTERFACE smbus;
|
||||
|
||||
#
|
||||
|
@ -31,6 +31,8 @@
|
||||
# USB interface description
|
||||
#
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
INTERFACE usb;
|
||||
|
||||
# The device should start probing for new drivers again
|
||||
|
@ -289,7 +289,7 @@ isa_wrap_old_drivers(void)
|
||||
bzero(driver, sizeof(driver_t));
|
||||
driver->name = op->driver->name;
|
||||
driver->methods = isa_compat_methods;
|
||||
driver->softc = sizeof(struct isa_device);
|
||||
driver->size = sizeof(struct isa_device);
|
||||
driver->priv = op;
|
||||
if (op->driver->sensitive_hw)
|
||||
resource_set_int(op->driver->name, -1, "sensitive", 1);
|
||||
|
@ -26,9 +26,8 @@
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
CODE {
|
||||
#include <sys/bus.h>
|
||||
#include <isa/isavar.h>
|
||||
};
|
||||
|
||||
INTERFACE isa;
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
INTERFACE bus;
|
||||
|
||||
#
|
||||
|
@ -26,6 +26,8 @@
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
INTERFACE device;
|
||||
|
||||
#
|
||||
|
481
sys/kern/makeobjops.pl
Normal file
481
sys/kern/makeobjops.pl
Normal file
@ -0,0 +1,481 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# Copyright (c) 1992, 1993
|
||||
# The Regents of the University of California. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. 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, Berkeley and its contributors.
|
||||
# 4. Neither the name of the University nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# From @(#)vnode_if.sh 8.1 (Berkeley) 6/10/93
|
||||
# From @(#)makedevops.sh 1.1 1998/06/14 13:53:12 dfr Exp $
|
||||
# From @(#)makedevops.sh ?.? 1998/10/05
|
||||
# From src/sys/kern/makedevops.pl,v 1.12 1999/11/22 14:40:04 n_hibma Exp
|
||||
#
|
||||
# $FreeBSD$
|
||||
|
||||
#
|
||||
# Script to produce kobj front-end sugar.
|
||||
#
|
||||
|
||||
$debug = 0;
|
||||
$cfile = 0; # by default do not produce any file type
|
||||
$hfile = 0;
|
||||
|
||||
$keepcurrentdir = 1;
|
||||
|
||||
$line_width = 80;
|
||||
|
||||
# Process the command line
|
||||
#
|
||||
while ( $arg = shift @ARGV ) {
|
||||
if ( $arg eq '-c' ) {
|
||||
warn "Producing .c output files"
|
||||
if $debug;
|
||||
$cfile = 1;
|
||||
} elsif ( $arg eq '-h' ) {
|
||||
warn "Producing .h output files"
|
||||
if $debug;
|
||||
$hfile = 1;
|
||||
} elsif ( $arg eq '-ch' || $arg eq '-hc' ) {
|
||||
warn "Producing .c and .h output files"
|
||||
if $debug;
|
||||
$cfile = 1;
|
||||
$hfile = 1;
|
||||
} elsif ( $arg eq '-d' ) {
|
||||
$debug = 1;
|
||||
} elsif ( $arg eq '-p' ) {
|
||||
warn "Will produce files in original not in current directory"
|
||||
if $debug;
|
||||
$keepcurrentdir = 0;
|
||||
} elsif ( $arg eq '-l' ) {
|
||||
if ( $line_width = shift @ARGV and $line_width > 0 ) {
|
||||
warn "Line width set to $line_width"
|
||||
if $debug;
|
||||
} else {
|
||||
die "Please specify a valid line width after -l";
|
||||
}
|
||||
} elsif ( $arg =~ m/\.m$/ ) {
|
||||
warn "Filename: $arg"
|
||||
if $debug;
|
||||
push @filenames, $arg;
|
||||
} else {
|
||||
warn "$arg ignored"
|
||||
if $debug;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Validate the command line parameters
|
||||
#
|
||||
die "usage: $0 [-d] [-p] [-l <nr>] [-c|-h] srcfile
|
||||
where -c produce only .c files
|
||||
-h produce only .h files
|
||||
-p use the path component in the source file for destination dir
|
||||
-l set line width for output files [80]
|
||||
-d switch on debugging
|
||||
"
|
||||
unless ($cfile or $hfile)
|
||||
and $#filenames != -1;
|
||||
|
||||
# FIXME should be able to do this more easily
|
||||
#
|
||||
$tmpdir = $ENV{'TMPDIR'}; # environment variables
|
||||
$tmpdir = $ENV{'TMP'}
|
||||
if !$tmpdir;
|
||||
$tmpdir = $ENV{'TEMP'}
|
||||
if !$tmpdir;
|
||||
$tmpdir = '/tmp' # look for a physical directory
|
||||
if !$tmpdir and -d '/tmp';
|
||||
$tmpdir = '/usr/tmp'
|
||||
if !$tmpdir and -d '/usr/tmp';
|
||||
$tmpdir = '/var/tmp'
|
||||
if !$tmpdir and -d '/var/tmp';
|
||||
$tmpdir = '.' # give up and use current dir
|
||||
if !$tmpdir;
|
||||
|
||||
foreach $src ( @filenames ) {
|
||||
# Names of the created files
|
||||
$ctmpname = "$tmpdir/ctmp.$$";
|
||||
$htmpname = "$tmpdir/htmp.$$";
|
||||
|
||||
($name, $path, $suffix) = &fileparse($src, '.m');
|
||||
$path = '.'
|
||||
if $keepcurrentdir;
|
||||
$cfilename="$path/$name.c";
|
||||
$hfilename="$path/$name.h";
|
||||
|
||||
warn "Processing from $src to $cfilename / $hfilename via $ctmpname / $htmpname"
|
||||
if $debug;
|
||||
|
||||
die "Could not open $src, $!"
|
||||
if !open SRC, "$src";
|
||||
die "Could not open $ctmpname, $!"
|
||||
if $cfile and !open CFILE, ">$ctmpname";
|
||||
die "Could not open $htmpname, $!"
|
||||
if $hfile and !open HFILE, ">$htmpname";
|
||||
|
||||
if ($cfile) {
|
||||
# Produce the header of the C file
|
||||
#
|
||||
print CFILE "/*\n";
|
||||
print CFILE " * This file is produced automatically.\n";
|
||||
print CFILE " * Do not modify anything in here by hand.\n";
|
||||
print CFILE " *\n";
|
||||
print CFILE " * Created from source file\n";
|
||||
print CFILE " * $src\n";
|
||||
print CFILE " * with\n";
|
||||
print CFILE " * $0\n";
|
||||
print CFILE " *\n";
|
||||
print CFILE " * See the source file for legal information\n";
|
||||
print CFILE " */\n";
|
||||
print CFILE "\n";
|
||||
print CFILE "#include <sys/param.h>\n";
|
||||
print CFILE "#include <sys/queue.h>\n";
|
||||
print CFILE "#include <sys/kernel.h>\n";
|
||||
print CFILE "#include <sys/kobj.h>\n";
|
||||
}
|
||||
|
||||
if ($hfile) {
|
||||
# Produce the header of the H file
|
||||
#
|
||||
print HFILE "/*\n";
|
||||
print HFILE " * This file is produced automatically.\n";
|
||||
print HFILE " * Do not modify anything in here by hand.\n";
|
||||
print HFILE " *\n";
|
||||
print HFILE " * Created from source file\n";
|
||||
print HFILE " * $src\n";
|
||||
print HFILE " * with\n";
|
||||
print HFILE " * $0\n";
|
||||
print HFILE " *\n";
|
||||
print HFILE " * See the source file for legal information\n";
|
||||
print HFILE " */\n";
|
||||
print HFILE "\n";
|
||||
}
|
||||
|
||||
%methods = (); # clear list of methods
|
||||
@mnames = ();
|
||||
@defaultmethods = ();
|
||||
$lineno = 0;
|
||||
$error = 0; # to signal clean up and gerror setting
|
||||
|
||||
LINE:
|
||||
while ( $line = <SRC> ) {
|
||||
$lineno++;
|
||||
|
||||
# take special notice of include directives.
|
||||
#
|
||||
if ( $line =~ m/^#\s*include\s+(["<])([^">]+)([">]).*/i ) {
|
||||
warn "Included file: $1$2" . ($1 eq '<'? '>':'"')
|
||||
if $debug;
|
||||
print CFILE "#include $1$2" . ($1 eq '<'? '>':'"') . "\n"
|
||||
if $cfile;
|
||||
}
|
||||
|
||||
$line =~ s/#.*//; # remove comments
|
||||
$line =~ s/^\s+//; # remove leading ...
|
||||
$line =~ s/\s+$//; # remove trailing whitespace
|
||||
|
||||
if ( $line =~ m/^$/ ) { # skip empty lines
|
||||
# nop
|
||||
|
||||
} elsif ( $line =~ m/^INTERFACE\s*([^\s;]*)(\s*;?)/i ) {
|
||||
$intname = $1;
|
||||
$semicolon = $2;
|
||||
unless ( $intname =~ m/^[a-z_][a-z0-9_]*$/ ) {
|
||||
warn $line
|
||||
if $debug;
|
||||
warn "$src:$lineno: Invalid interface name '$intname', use [a-z_][a-z0-9_]*";
|
||||
$error = 1;
|
||||
last LINE;
|
||||
}
|
||||
|
||||
warn "$src:$lineno: semicolon missing at end of line, no problem"
|
||||
if $semicolon !~ s/;$//;
|
||||
|
||||
warn "Interface $intname"
|
||||
if $debug;
|
||||
|
||||
print HFILE '#ifndef _'.$intname."_if_h_\n"
|
||||
if $hfile;
|
||||
print HFILE '#define _'.$intname."_if_h_\n\n"
|
||||
if $hfile;
|
||||
print CFILE '#include "'.$intname.'_if.h"'."\n\n"
|
||||
if $cfile;
|
||||
} elsif ( $line =~ m/^CODE\s*{$/i ) {
|
||||
$code = "";
|
||||
$line = <SRC>;
|
||||
$line =~ m/^(\s*)/;
|
||||
$indent = $1; # find the indent used
|
||||
while ( $line !~ m/^}/ ) {
|
||||
$line =~ s/^$indent//g; # remove the indent
|
||||
$code .= $line;
|
||||
$line = <SRC>;
|
||||
$lineno++
|
||||
}
|
||||
if ($cfile) {
|
||||
print CFILE "\n".$code."\n";
|
||||
}
|
||||
} elsif ( $line =~ m/^HEADER\s*{$/i ) {
|
||||
$header = "";
|
||||
$line = <SRC>;
|
||||
$line =~ m/^(\s*)/;
|
||||
$indent = $1; # find the indent used
|
||||
while ( $line !~ m/^}/ ) {
|
||||
$line =~ s/^$indent//g; # remove the indent
|
||||
$header .= $line;
|
||||
$line = <SRC>;
|
||||
$lineno++
|
||||
}
|
||||
if ($hfile) {
|
||||
print HFILE $header;
|
||||
}
|
||||
} 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.
|
||||
#
|
||||
if ( !$intname ) {
|
||||
warn "$src:$lineno: No interface name defined";
|
||||
$error = 1;
|
||||
last LINE;
|
||||
}
|
||||
$line =~ s/^(STATIC|)METHOD\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
|
||||
|
||||
warn "Method: name=$name return type=$ret"
|
||||
if $debug;
|
||||
|
||||
if ( !$name or !$ret ) {
|
||||
warn $line
|
||||
if $debug;
|
||||
warn "$src:$lineno: Invalid method specification";
|
||||
$error = 1;
|
||||
last LINE;
|
||||
}
|
||||
|
||||
unless ( $name =~ m/^[a-z_][a-z_0-9]*$/ ) {
|
||||
warn $line
|
||||
if $debug;
|
||||
warn "$src:$lineno: Invalid method name '$name', use [a-z_][a-z0-9_]*";
|
||||
$error = 1;
|
||||
last LINE;
|
||||
}
|
||||
|
||||
if ( defined($methods{$name}) ) {
|
||||
warn "$src:$lineno: Duplicate method name";
|
||||
$error = 1;
|
||||
last LINE;
|
||||
}
|
||||
|
||||
$methods{$name} = $name;
|
||||
push @mnames, $name;
|
||||
|
||||
while ( $line !~ m/}/ and $line .= <SRC> ) {
|
||||
$lineno++
|
||||
}
|
||||
|
||||
$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
|
||||
#
|
||||
$line =~ s/^\s+//; # remove leading ...
|
||||
$line =~ s/\s+$//; # ... and trailing whitespace
|
||||
$line =~ s/\s+/ /g; # remove double spaces
|
||||
|
||||
@arguments = split m/\s*;\s*/, $line;
|
||||
@varnames = (); # list of varnames
|
||||
foreach $argument (@arguments) {
|
||||
next # skip argument if argument is empty
|
||||
if !$argument;
|
||||
|
||||
@ar = split m/[*\s]+/, $argument;
|
||||
if ( $#ar == 0 ) { # only 1 word in argument?
|
||||
warn "$src:$lineno: no type for '$argument'";
|
||||
$error = 1;
|
||||
last LINE;
|
||||
}
|
||||
|
||||
push @varnames, $ar[-1]; # last element is name of variable
|
||||
};
|
||||
|
||||
warn 'Arguments: ' . join(', ', @arguments) . "\n"
|
||||
. 'Varnames: ' . join(', ', @varnames)
|
||||
if $debug;
|
||||
|
||||
$mname = $intname.'_'.$name; # method name
|
||||
$umname = uc($mname); # uppercase method name
|
||||
|
||||
$arguments = join(", ", @arguments);
|
||||
$firstvar = $varnames[0];
|
||||
$varnames = join(", ", @varnames);
|
||||
|
||||
$default = "0" if $default eq "";
|
||||
push @defaultmethods, $default;
|
||||
|
||||
if ($hfile) {
|
||||
# the method description
|
||||
print HFILE "extern struct kobjop_desc $mname\_desc;\n";
|
||||
# the method typedef
|
||||
print HFILE &format_line("typedef $ret $mname\_t($arguments);",
|
||||
$line_width, ', ',
|
||||
',',' ' x length("typedef $ret $mname\_t("))
|
||||
. "\n";
|
||||
}
|
||||
|
||||
if ($cfile) {
|
||||
# Print out the method desc
|
||||
print CFILE "struct kobjop_desc $mname\_desc = {\n";
|
||||
print CFILE "\t0, (kobjop_t) $default\n";
|
||||
print CFILE "};\n\n";
|
||||
}
|
||||
|
||||
if ($hfile) {
|
||||
# Print out the method itself
|
||||
if (0) { # haven't chosen the format yet
|
||||
print HFILE "static __inline $ret $umname($varnames)\n";
|
||||
print HFILE "\t".join(";\n\t", @arguments).";\n";
|
||||
} else {
|
||||
print HFILE &format_line("static __inline $ret $umname($arguments)",
|
||||
$line_width, ', ',
|
||||
',', ' ' x length("$ret $umname(")) . "\n";
|
||||
}
|
||||
print HFILE "{\n";
|
||||
print HFILE "\tkobjop_t _m;\n";
|
||||
if ( $static ) {
|
||||
print HFILE "\tKOBJOPLOOKUP($firstvar->ops,$mname);\n";
|
||||
} else {
|
||||
print HFILE "\tKOBJOPLOOKUP(((kobj_t)$firstvar)->ops,$mname);\n";
|
||||
}
|
||||
print HFILE "\t";
|
||||
if ($ret ne 'void') {
|
||||
print HFILE "return ";
|
||||
}
|
||||
print HFILE "(($mname\_t *) _m)($varnames);\n";
|
||||
print HFILE "}\n\n";
|
||||
}
|
||||
} else {
|
||||
warn $line
|
||||
if $debug;
|
||||
warn "$src:$lineno: Invalid line encountered";
|
||||
$error = 1;
|
||||
last LINE;
|
||||
}
|
||||
} # end LINE
|
||||
|
||||
# print the final '#endif' in the header file
|
||||
#
|
||||
print HFILE "#endif /* _".$intname."_if_h_ */\n"
|
||||
if $hfile;
|
||||
|
||||
close SRC;
|
||||
close CFILE
|
||||
if $cfile;
|
||||
close HFILE
|
||||
if $hfile;
|
||||
|
||||
if ( !$error ) {
|
||||
if ($cfile) {
|
||||
($rc = system("mv $ctmpname $cfilename"))
|
||||
and warn "mv $ctmpname $cfilename failed, $rc";
|
||||
}
|
||||
|
||||
if ($hfile) {
|
||||
($rc = system("mv $htmpname $hfilename"))
|
||||
and warn "mv $htmpname $hfilename failed, $rc";
|
||||
}
|
||||
} else {
|
||||
warn 'Output skipped';
|
||||
($rc = system("rm -f $htmpname $ctmpname"))
|
||||
and warn "rm -f $htmpname $ctmpname failed, $rc";
|
||||
$gerror = 1;
|
||||
}
|
||||
}
|
||||
|
||||
exit $gerror;
|
||||
|
||||
|
||||
sub format_line {
|
||||
my ($line, $maxlength, $break, $new_end, $new_start) = @_;
|
||||
my $rline = "";
|
||||
|
||||
while ( length($line) > $maxlength
|
||||
and ($i = rindex $line, $break, $maxlength-length($new_end)) != -1 ) {
|
||||
$rline .= substr($line, 0, $i) . $new_end . "\n";
|
||||
$line = $new_start . substr($line, $i+length($break));
|
||||
}
|
||||
|
||||
return $rline . $line;
|
||||
}
|
||||
|
||||
# This routine is a crude replacement for one in File::Basename. We
|
||||
# cannot use any library code because it fouls up the Perl bootstrap
|
||||
# when we update a perl version. MarkM
|
||||
|
||||
sub fileparse {
|
||||
my ($filename, @suffix) = @_;
|
||||
my ($dir, $name, $type, $i);
|
||||
|
||||
$type = '';
|
||||
foreach $i (@suffix) {
|
||||
if ($filename =~ m|$i$|) {
|
||||
$filename =~ s|$i$||;
|
||||
$type = $i;
|
||||
}
|
||||
}
|
||||
if ($filename =~ m|/|) {
|
||||
$filename =~ m|([^/]*)$|;
|
||||
$name = $1;
|
||||
$dir = $filename;
|
||||
$dir =~ s|$name$||;
|
||||
}
|
||||
else {
|
||||
$dir = '';
|
||||
$name = $filename;
|
||||
}
|
||||
($name, $dir, $type);
|
||||
}
|
||||
|
||||
sub write_interface {
|
||||
$mcount = $#mnames + 1;
|
||||
}
|
@ -36,6 +36,7 @@
|
||||
#ifdef DEVICE_SYSCTLS
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#include <sys/kobj.h>
|
||||
#include <sys/bus_private.h>
|
||||
#include <sys/systm.h>
|
||||
#include <machine/bus.h>
|
||||
@ -56,7 +57,6 @@ MALLOC_DEFINE(M_BUS, "bus", "Bus data structures");
|
||||
#define indentprintf(p) do { int iJ; printf("."); for (iJ=0; iJ<indent; iJ++) printf(" "); printf p ; } while(0)
|
||||
|
||||
static void print_method_list(device_method_t *m, int indent);
|
||||
static void print_device_ops(device_ops_t ops, int indent);
|
||||
static void print_device_short(device_t dev, int indent);
|
||||
static void print_device(device_t dev, int indent);
|
||||
void print_device_tree_short(device_t dev, int indent);
|
||||
@ -77,7 +77,6 @@ void print_devclass_list(void);
|
||||
#define DEVCLANAME(d) /* nop */
|
||||
|
||||
#define print_method_list(m,i) /* nop */
|
||||
#define print_device_ops(o,i) /* nop */
|
||||
#define print_device_short(d,i) /* nop */
|
||||
#define print_device(d,i) /* nop */
|
||||
#define print_device_tree_short(d,i) /* nop */
|
||||
@ -96,146 +95,11 @@ static void device_register_oids(device_t dev);
|
||||
static void device_unregister_oids(device_t dev);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Method table handling
|
||||
*/
|
||||
static int error_method(void);
|
||||
static int next_method_offset = 1;
|
||||
|
||||
LIST_HEAD(methodlist, method) methods;
|
||||
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 */
|
||||
kobj_method_t null_methods[] = {
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static void
|
||||
register_method(struct device_op_desc *desc)
|
||||
{
|
||||
struct method* m;
|
||||
|
||||
if (desc->method) {
|
||||
desc->method->refs++;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that desc->deflt is always valid to simplify dispatch.
|
||||
*/
|
||||
if (!desc->deflt)
|
||||
desc->deflt = error_method;
|
||||
|
||||
for (m = LIST_FIRST(&methods); m; m = LIST_NEXT(m, link)) {
|
||||
if (!strcmp(m->name, desc->name)) {
|
||||
desc->offset = m->offset;
|
||||
desc->method = m;
|
||||
m->refs++;
|
||||
PDEBUG(("method %p has the same name, %s, with offset %d",
|
||||
(void *)m, desc->name, desc->offset));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m = (struct method *) malloc(sizeof(struct method)
|
||||
+ strlen(desc->name) + 1,
|
||||
M_BUS, M_NOWAIT);
|
||||
if (!m)
|
||||
panic("register_method: out of memory");
|
||||
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);
|
||||
|
||||
desc->offset = m->offset;
|
||||
desc->method = m;
|
||||
}
|
||||
|
||||
static void
|
||||
unregister_method(struct device_op_desc *desc)
|
||||
{
|
||||
struct method *m = desc->method;
|
||||
m->refs--;
|
||||
if (m->refs == 0) {
|
||||
PDEBUG(("method %s, reached refcount 0", desc->name));
|
||||
LIST_REMOVE(m, link);
|
||||
free(m, M_BUS);
|
||||
desc->method = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int error_method(void)
|
||||
{
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static struct device_ops null_ops = {
|
||||
1,
|
||||
{ error_method }
|
||||
};
|
||||
|
||||
static void
|
||||
compile_methods(driver_t *driver)
|
||||
{
|
||||
device_ops_t ops;
|
||||
struct device_method *m;
|
||||
struct method *cm;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* First register any methods which need it.
|
||||
*/
|
||||
for (i = 0, m = driver->methods; m->desc; i++, m++)
|
||||
register_method(m->desc);
|
||||
|
||||
/*
|
||||
* Then allocate the compiled op table.
|
||||
*/
|
||||
ops = malloc(sizeof(struct device_ops) + (next_method_offset-1) * sizeof(devop_t),
|
||||
M_BUS, M_NOWAIT);
|
||||
if (!ops)
|
||||
panic("compile_methods: out of memory");
|
||||
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",
|
||||
DRIVERNAME(driver), i, (i==1?"":"s"),
|
||||
(next_method_offset-i)*sizeof(devop_t)));
|
||||
|
||||
driver->ops = ops;
|
||||
}
|
||||
|
||||
static void
|
||||
free_methods(driver_t *driver)
|
||||
{
|
||||
int i;
|
||||
struct device_method *m;
|
||||
|
||||
/*
|
||||
* Unregister any methods which are no longer used.
|
||||
*/
|
||||
for (i = 0, m = driver->methods; m->desc; i++, m++)
|
||||
unregister_method(m->desc);
|
||||
|
||||
/*
|
||||
* Free memory and clean up.
|
||||
*/
|
||||
free(driver->ops, M_BUS);
|
||||
driver->ops = 0;
|
||||
}
|
||||
DEFINE_CLASS(null, null_methods, 0);
|
||||
|
||||
/*
|
||||
* Devclass implementation
|
||||
@ -302,8 +166,7 @@ devclass_add_driver(devclass_t dc, driver_t *driver)
|
||||
/*
|
||||
* Compile the driver's methods.
|
||||
*/
|
||||
if (!driver->ops)
|
||||
compile_methods(driver);
|
||||
kobj_class_compile((kobj_class_t) driver);
|
||||
|
||||
/*
|
||||
* Make sure the devclass which the driver is implementing exists.
|
||||
@ -379,7 +242,7 @@ devclass_delete_driver(devclass_t busclass, driver_t *driver)
|
||||
|
||||
driver->refs--;
|
||||
if (driver->refs == 0)
|
||||
free_methods(driver);
|
||||
kobj_class_free((kobj_class_t) driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -609,7 +472,7 @@ make_device(device_t parent, const char *name, int unit)
|
||||
|
||||
dev->parent = parent;
|
||||
TAILQ_INIT(&dev->children);
|
||||
dev->ops = &null_ops;
|
||||
kobj_init((kobj_t) dev, &null_class);
|
||||
dev->driver = NULL;
|
||||
dev->devclass = NULL;
|
||||
dev->unit = unit;
|
||||
@ -630,6 +493,8 @@ make_device(device_t parent, const char *name, int unit)
|
||||
|
||||
dev->state = DS_NOTPRESENT;
|
||||
|
||||
kobj_init((kobj_t) dev, &null_class);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
@ -1112,18 +977,19 @@ device_set_driver(device_t dev, driver_t *driver)
|
||||
free(dev->softc, M_BUS);
|
||||
dev->softc = NULL;
|
||||
}
|
||||
dev->ops = &null_ops;
|
||||
kobj_delete((kobj_t) dev, 0);
|
||||
dev->driver = driver;
|
||||
if (driver) {
|
||||
dev->ops = driver->ops;
|
||||
dev->softc = malloc(driver->softc, M_BUS, M_NOWAIT);
|
||||
kobj_init((kobj_t) dev, (kobj_class_t) driver);
|
||||
dev->softc = malloc(driver->size, M_BUS, M_NOWAIT);
|
||||
if (!dev->softc) {
|
||||
dev->ops = &null_ops;
|
||||
kobj_init((kobj_t) dev, &null_class);
|
||||
dev->driver = NULL;
|
||||
return ENOMEM;
|
||||
}
|
||||
bzero(dev->softc, driver->softc);
|
||||
}
|
||||
bzero(dev->softc, driver->size);
|
||||
} else
|
||||
kobj_init((kobj_t) dev, &null_class);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2180,17 +2046,17 @@ root_setup_intr(device_t dev, device_t child, driver_intr_t *intr, void *arg,
|
||||
panic("root_setup_intr");
|
||||
}
|
||||
|
||||
static device_method_t root_methods[] = {
|
||||
static kobj_method_t root_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
KOBJMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
KOBJMETHOD(device_suspend, bus_generic_suspend),
|
||||
KOBJMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* Bus interface */
|
||||
DEVMETHOD(bus_print_child, root_print_child),
|
||||
DEVMETHOD(bus_read_ivar, bus_generic_read_ivar),
|
||||
DEVMETHOD(bus_write_ivar, bus_generic_write_ivar),
|
||||
DEVMETHOD(bus_setup_intr, root_setup_intr),
|
||||
KOBJMETHOD(bus_print_child, root_print_child),
|
||||
KOBJMETHOD(bus_read_ivar, bus_generic_read_ivar),
|
||||
KOBJMETHOD(bus_write_ivar, bus_generic_write_ivar),
|
||||
KOBJMETHOD(bus_setup_intr, root_setup_intr),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
@ -2209,10 +2075,10 @@ root_bus_module_handler(module_t mod, int what, void* arg)
|
||||
{
|
||||
switch (what) {
|
||||
case MOD_LOAD:
|
||||
compile_methods(&root_driver);
|
||||
kobj_class_compile((kobj_class_t) &root_driver);
|
||||
root_bus = make_device(NULL, "root", 0);
|
||||
root_bus->desc = "System root bus";
|
||||
root_bus->ops = root_driver.ops;
|
||||
kobj_init((kobj_t) root_bus, (kobj_class_t) &root_driver);
|
||||
root_bus->driver = &root_driver;
|
||||
root_bus->state = DS_ATTACHED;
|
||||
root_devclass = devclass_find_internal("root", FALSE);
|
||||
@ -2317,36 +2183,6 @@ print_method_list(device_method_t *m, int indent)
|
||||
i, m->desc->name, m->desc->offset));
|
||||
}
|
||||
|
||||
static void
|
||||
print_device_ops(device_ops_t ops, int indent)
|
||||
{
|
||||
int i;
|
||||
int count = 0;
|
||||
|
||||
if (!ops)
|
||||
return;
|
||||
|
||||
/* we present a list of the methods that are pointing to the
|
||||
* error_method, but ignore the 0'th elements; it is always
|
||||
* error_method.
|
||||
*/
|
||||
for (i = 1; i < ops->maxoffset; i++) {
|
||||
if (ops->methods[i] == error_method) {
|
||||
if (count == 0)
|
||||
indentprintf(("error_method:"));
|
||||
printf(" %d", i);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count)
|
||||
printf("\n");
|
||||
|
||||
indentprintf(("(%d method%s, %d valid, %d error_method%s)\n",
|
||||
ops->maxoffset-1, (ops->maxoffset-1 == 1? "":"s"),
|
||||
ops->maxoffset-1-count,
|
||||
count, (count == 1? "":"'s")));
|
||||
}
|
||||
|
||||
static void
|
||||
print_device_short(device_t dev, int indent)
|
||||
{
|
||||
@ -2376,8 +2212,6 @@ print_device(device_t dev, int indent)
|
||||
|
||||
indentprintf(("Parent:\n"));
|
||||
print_device_short(dev->parent, indent+1);
|
||||
indentprintf(("Methods:\n"));
|
||||
print_device_ops(dev->ops, indent+1);
|
||||
indentprintf(("Driver:\n"));
|
||||
print_driver_short(dev->driver, indent+1);
|
||||
indentprintf(("Devclass:\n"));
|
||||
@ -2435,8 +2269,6 @@ print_driver(driver_t *driver, int indent)
|
||||
print_driver_short(driver, indent);
|
||||
indentprintf(("Methods:\n"));
|
||||
print_method_list(driver->methods, indent+1);
|
||||
indentprintf(("Operations:\n"));
|
||||
print_device_ops(driver->ops, indent+1);
|
||||
}
|
||||
|
||||
|
||||
|
197
sys/kern/subr_kobj.c
Normal file
197
sys/kern/subr_kobj.c
Normal file
@ -0,0 +1,197 @@
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/errno.h>
|
||||
#ifndef TEST
|
||||
#include <sys/systm.h>
|
||||
#endif
|
||||
#include <sys/kobj.h>
|
||||
|
||||
#ifdef TEST
|
||||
#include "usertest.h"
|
||||
#endif
|
||||
|
||||
static MALLOC_DEFINE(M_KOBJ, "kobj", "Kernel object structures");
|
||||
|
||||
#ifdef KOBJ_STATS
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
int kobj_lookup_hits;
|
||||
int kobj_lookup_misses;
|
||||
|
||||
SYSCTL_INT(_kern, OID_AUTO, kobj_hits, CTLFLAG_RD,
|
||||
&kobj_lookup_hits, 0, "")
|
||||
SYSCTL_INT(_kern, OID_AUTO, kobj_misses, CTLFLAG_RD,
|
||||
&kobj_lookup_misses, 0, "")
|
||||
|
||||
#endif
|
||||
|
||||
static int kobj_next_id = 1;
|
||||
|
||||
static int
|
||||
kobj_error_method(void)
|
||||
{
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static void
|
||||
kobj_register_method(struct kobjop_desc *desc)
|
||||
{
|
||||
if (desc->id == 0)
|
||||
desc->id = kobj_next_id++;
|
||||
}
|
||||
|
||||
static void
|
||||
kobj_unregister_method(struct kobjop_desc *desc)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
kobj_class_compile(kobj_class_t cls)
|
||||
{
|
||||
kobj_ops_t ops;
|
||||
kobj_method_t *m;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Don't do anything if we are already compiled.
|
||||
*/
|
||||
if (cls->ops)
|
||||
return;
|
||||
|
||||
/*
|
||||
* First register any methods which need it.
|
||||
*/
|
||||
for (i = 0, m = cls->methods; m->desc; i++, m++)
|
||||
kobj_register_method(m->desc);
|
||||
|
||||
/*
|
||||
* Then allocate the compiled op table.
|
||||
*/
|
||||
ops = malloc(sizeof(struct kobj_ops), M_KOBJ, M_NOWAIT);
|
||||
if (!ops)
|
||||
panic("kobj_compile_methods: out of memory");
|
||||
bzero(ops, sizeof(struct kobj_ops));
|
||||
ops->cls = cls;
|
||||
cls->ops = ops;
|
||||
}
|
||||
|
||||
void
|
||||
kobj_lookup_method(kobj_method_t *methods,
|
||||
kobj_method_t *ce,
|
||||
kobjop_desc_t desc)
|
||||
{
|
||||
ce->desc = desc;
|
||||
for (; methods && methods->desc; methods++) {
|
||||
if (methods->desc == desc) {
|
||||
ce->func = methods->func;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (desc->deflt)
|
||||
ce->func = desc->deflt;
|
||||
else
|
||||
ce->func = kobj_error_method;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
kobj_class_free(kobj_class_t cls)
|
||||
{
|
||||
int i;
|
||||
kobj_method_t *m;
|
||||
|
||||
/*
|
||||
* Unregister any methods which are no longer used.
|
||||
*/
|
||||
for (i = 0, m = cls->methods; m->desc; i++, m++)
|
||||
kobj_unregister_method(m->desc);
|
||||
|
||||
/*
|
||||
* Free memory and clean up.
|
||||
*/
|
||||
free(cls->ops, M_KOBJ);
|
||||
cls->ops = 0;
|
||||
}
|
||||
|
||||
kobj_t
|
||||
kobj_create(kobj_class_t cls,
|
||||
struct malloc_type *mtype,
|
||||
int mflags)
|
||||
{
|
||||
kobj_t obj;
|
||||
|
||||
/*
|
||||
* Allocate and initialise the new object.
|
||||
*/
|
||||
obj = malloc(cls->size, mtype, mflags);
|
||||
if (!obj)
|
||||
return 0;
|
||||
bzero(obj, cls->size);
|
||||
kobj_init(obj, cls);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void
|
||||
kobj_init(kobj_t obj, kobj_class_t cls)
|
||||
{
|
||||
/*
|
||||
* Consider compiling the class' method table.
|
||||
*/
|
||||
if (!cls->ops)
|
||||
kobj_class_compile(cls);
|
||||
|
||||
obj->ops = cls->ops;
|
||||
cls->instances++;
|
||||
}
|
||||
|
||||
void
|
||||
kobj_delete(kobj_t obj, struct malloc_type *mtype)
|
||||
{
|
||||
kobj_class_t cls = obj->ops->cls;
|
||||
|
||||
/*
|
||||
* Consider freeing the compiled method table for the class
|
||||
* after its last instance is deleted. As an optimisation, we
|
||||
* should defer this for a short while to avoid thrashing.
|
||||
*/
|
||||
cls->instances--;
|
||||
if (!cls->instances)
|
||||
kobj_class_free(cls);
|
||||
|
||||
obj->ops = 0;
|
||||
if (mtype)
|
||||
free(obj, mtype);
|
||||
}
|
@ -940,7 +940,7 @@ compat_pci_handler(module_t mod, int type, void *data)
|
||||
bzero(driver, sizeof(driver_t));
|
||||
driver->name = dvp->pd_name;
|
||||
driver->methods = pci_compat_methods;
|
||||
driver->softc = sizeof(struct pci_devinfo *);
|
||||
driver->size = sizeof(struct pci_devinfo *);
|
||||
driver->priv = dvp;
|
||||
devclass_add_driver(pci_devclass, driver);
|
||||
break;
|
||||
|
@ -26,6 +26,8 @@
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
#include <sys/bus.h>
|
||||
|
||||
INTERFACE pci;
|
||||
|
||||
METHOD u_int32_t read_config {
|
||||
|
@ -32,16 +32,15 @@
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <sys/kobj.h>
|
||||
|
||||
/*
|
||||
* Forward declarations
|
||||
*/
|
||||
typedef struct device *device_t;
|
||||
typedef struct driver driver_t;
|
||||
typedef struct device_method device_method_t;
|
||||
typedef struct devclass *devclass_t;
|
||||
typedef struct device_ops *device_ops_t;
|
||||
typedef struct device_op_desc *device_op_desc_t;
|
||||
#define device_method_t kobj_method_t
|
||||
|
||||
typedef void driver_intr_t(void*);
|
||||
|
||||
@ -63,17 +62,9 @@ enum intr_type {
|
||||
|
||||
typedef int (*devop_t)(void);
|
||||
|
||||
struct device_method {
|
||||
device_op_desc_t desc;
|
||||
devop_t func;
|
||||
};
|
||||
|
||||
struct driver {
|
||||
const char *name; /* driver name */
|
||||
device_method_t *methods; /* method table */
|
||||
size_t softc; /* size of device softc struct */
|
||||
KOBJ_CLASS_FIELDS;
|
||||
void *priv; /* driver private data */
|
||||
device_ops_t ops; /* compiled method table */
|
||||
int refs; /* # devclasses containing driver */
|
||||
};
|
||||
|
||||
@ -301,7 +292,7 @@ int resource_count(void);
|
||||
/*
|
||||
* Shorthand for constructing method tables.
|
||||
*/
|
||||
#define DEVMETHOD(NAME, FUNC) { &NAME##_desc, (devop_t) FUNC }
|
||||
#define DEVMETHOD KOBJMETHOD
|
||||
|
||||
/*
|
||||
* Some common device interfaces.
|
||||
|
@ -79,35 +79,16 @@ struct config_device {
|
||||
struct config_resource *resources;
|
||||
};
|
||||
|
||||
/*
|
||||
* Compiled device methods.
|
||||
*/
|
||||
struct device_ops {
|
||||
int maxoffset;
|
||||
devop_t methods[1];
|
||||
};
|
||||
|
||||
/*
|
||||
* Helpers for device method wrappers.
|
||||
*/
|
||||
#define DEVOPDESC(OP) (&OP##_##desc)
|
||||
|
||||
#define DEVOPS(DEV) (DEV->ops)
|
||||
#define DEVOPMETH(DEV, OP) \
|
||||
((DEVOPDESC(OP)->offset >= DEVOPS(DEV)->maxoffset) \
|
||||
? DEVOPDESC(OP)->deflt \
|
||||
: DEVOPS(DEV)->methods[DEVOPDESC(OP)->offset])
|
||||
|
||||
#define DRVOPS(DRV) ((struct device_ops *)DRV->ops)
|
||||
#define DRVOPMETH(DRV, OP) \
|
||||
((DEVOPDESC(OP)->offset >= DRVOPS(DRV)->maxoffset) \
|
||||
? DEVOPDESC(OP)->deflt \
|
||||
: DRVOPS(DRV)->methods[DEVOPDESC(OP)->offset])
|
||||
|
||||
/*
|
||||
* Implementation of device.
|
||||
*/
|
||||
struct device {
|
||||
/*
|
||||
* A device is a kernel object. The first field must be the
|
||||
* current ops table for the object.
|
||||
*/
|
||||
KOBJ_FIELDS;
|
||||
|
||||
/*
|
||||
* Device hierarchy.
|
||||
*/
|
||||
@ -118,7 +99,6 @@ struct device {
|
||||
/*
|
||||
* Details of this device.
|
||||
*/
|
||||
device_ops_t ops;
|
||||
driver_t *driver;
|
||||
devclass_t devclass; /* device class which we are in */
|
||||
int unit;
|
||||
|
164
sys/sys/kobj.h
Normal file
164
sys/sys/kobj.h
Normal file
@ -0,0 +1,164 @@
|
||||
#define KOBJ_STATS
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _SYS_KOBJ_H_
|
||||
#define _SYS_KOBJ_H_
|
||||
|
||||
/*
|
||||
* Forward declarations
|
||||
*/
|
||||
typedef struct kobj *kobj_t;
|
||||
typedef struct kobj_class *kobj_class_t;
|
||||
typedef struct kobj_method kobj_method_t;
|
||||
typedef int (*kobjop_t)(void);
|
||||
typedef struct kobj_ops *kobj_ops_t;
|
||||
typedef struct kobjop_desc *kobjop_desc_t;
|
||||
struct malloc_type;
|
||||
|
||||
struct kobj_method {
|
||||
kobjop_desc_t desc;
|
||||
kobjop_t func;
|
||||
};
|
||||
|
||||
/*
|
||||
* A class is simply a method table and a sizeof value. When the first
|
||||
* instance of the class is created, the method table will be compiled
|
||||
* into a form more suited to efficient method dispatch. This compiled
|
||||
* method table is always the first field of the object.
|
||||
*/
|
||||
#define KOBJ_CLASS_FIELDS \
|
||||
const char *name; /* class name */ \
|
||||
kobj_method_t *methods; /* method table */ \
|
||||
size_t size; /* object size */ \
|
||||
u_int instances; /* instance count */ \
|
||||
kobj_ops_t ops /* compiled method table */
|
||||
|
||||
struct kobj_class {
|
||||
KOBJ_CLASS_FIELDS;
|
||||
};
|
||||
|
||||
/*
|
||||
* Implementation of kobj.
|
||||
*/
|
||||
#define KOBJ_FIELDS \
|
||||
kobj_ops_t ops;
|
||||
|
||||
struct kobj {
|
||||
KOBJ_FIELDS;
|
||||
};
|
||||
|
||||
/*
|
||||
* The ops table is used as a cache of results from kobj_lookup_method().
|
||||
*/
|
||||
|
||||
#define KOBJ_CACHE_SIZE 256
|
||||
|
||||
struct kobj_ops {
|
||||
kobj_method_t cache[KOBJ_CACHE_SIZE];
|
||||
kobj_class_t cls;
|
||||
};
|
||||
|
||||
struct kobjop_desc {
|
||||
unsigned int id; /* unique ID */
|
||||
kobjop_t deflt; /* default implementation */
|
||||
};
|
||||
|
||||
/*
|
||||
* Shorthand for constructing method tables.
|
||||
*/
|
||||
#define KOBJMETHOD(NAME, FUNC) { &NAME##_desc, (kobjop_t) FUNC }
|
||||
|
||||
#define DEFINE_CLASS(name, methods, size) \
|
||||
\
|
||||
struct kobj_class name ## _class = { \
|
||||
#name, methods, size \
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile the method table in a class.
|
||||
*/
|
||||
void kobj_class_compile(kobj_class_t cls);
|
||||
|
||||
/*
|
||||
* Free the compiled method table in a class.
|
||||
*/
|
||||
void kobj_class_free(kobj_class_t cls);
|
||||
|
||||
/*
|
||||
* Allocate memory for and initalise a new object.
|
||||
*/
|
||||
kobj_t kobj_create(kobj_class_t cls,
|
||||
struct malloc_type *mtype,
|
||||
int mflags);
|
||||
|
||||
/*
|
||||
* Initialise a pre-allocated object.
|
||||
*/
|
||||
void kobj_init(kobj_t obj, kobj_class_t cls);
|
||||
|
||||
/*
|
||||
* Delete an object. If mtype is non-zero, free the memory.
|
||||
*/
|
||||
void kobj_delete(kobj_t obj, struct malloc_type *mtype);
|
||||
|
||||
/*
|
||||
* Maintain stats on hits/misses in lookup caches.
|
||||
*/
|
||||
#ifdef KOBJ_STATS
|
||||
extern int kobj_lookup_hits;
|
||||
extern int kobj_lookup_misses;
|
||||
#define KOBJOPHIT do { kobj_lookup_hits++; } while (0)
|
||||
#define KOBJOPMISS do { kobj_lookup_misses++; } while (0)
|
||||
#else
|
||||
#define KOBJOPHIT do { } while (0)
|
||||
#define KOBJOPMISS do { } while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Lookup the method in the cache and if it isn't there look it up the
|
||||
* slow way.
|
||||
*/
|
||||
#define KOBJOPLOOKUP(OPS,OP) do { \
|
||||
kobjop_desc_t _desc = &OP##_##desc; \
|
||||
kobj_method_t *_ce = \
|
||||
&OPS->cache[_desc->id & (KOBJ_CACHE_SIZE-1)]; \
|
||||
if (_ce->desc != _desc) { \
|
||||
KOBJOPMISS; \
|
||||
kobj_lookup_method(OPS->cls->methods, _ce, _desc); \
|
||||
} else { \
|
||||
KOBJOPHIT; \
|
||||
} \
|
||||
_m = _ce->func; \
|
||||
} while(0)
|
||||
|
||||
void kobj_lookup_method(kobj_method_t *methods,
|
||||
kobj_method_t *ce,
|
||||
kobjop_desc_t desc);
|
||||
|
||||
#endif /* !_SYS_KOBJ_H_ */
|
Loading…
Reference in New Issue
Block a user