root/kern/conf/config

/* [<][>][^][v][top][bottom][index][help] */
#!/bin/sh
#
# Kernel config script for OS/161.
#
# Usage: ./config conf-name
#
#    WARNING! IF YOU JUST RUN "config" INSTEAD OF "./config" YOU WILL
#    PROBABLY GET THE HOST SYSTEM'S KERNEL CONFIG INSTEAD OF THIS ONE,
#    WHICH WILL CAUSE WEIRD THINGS TO HAPPEN. DON'T DO IT.
#
#
# Recognized directives:
#
#    file <filename>          use source file
#    debug                    turn on debug info
#    defoption <sym>          define an option
#    optfile <sym> <file>     if option <sym> is enabled, use file <file>
#    optofffile <sym> <file>  if option <sym> is disabled, use file <file>
#    defdevice <dev> <file>   define a device
#    defattach <dev> <bus> <file> 
#                             define an attachment for a device to a bus
#    pseudoattach <dev>       define a pseudo-attachment for a device
#
#    options <sym>            enable an option
#    device <dev> [at <bus>]  enable a particular device [on a particular bus]
#
#    include <filename>       get additional directives from another file
#
# Filenames are relative to the top of the kernel tree.
#
# The comment character is '#'. 
#
# The idea is that the first group of directives is used to set up a
# static description of all possible configurations for each supported
# architecture. Then a kernel config file uses the second group of
# directives to specify a particular configuration. Then this script
# is used to first check that the configuration is one of the possible
# ones, and then to set up the compile directory, makefiles, and 
# associated material necessary to actually build that configuration.
#
# Further documentation is at the top of conf.kern.
#


#
# Make sure we're in the right place.
#
if [ ! -d ../startup ]; then
        echo "$0: Run me from src/kern/conf"
        exit 1
fi

########################################
#
# 1. Get configuration name and config file.
#

CONFNAME=$1
if [ "x$CONFNAME" = x ]; then
    echo "Usage: $0 CONFIG-NAME"
    exit 1
fi

FOO=`echo $CONFNAME | tr -d 'a-zA-Z0-9_-'`
if [ "x$FOO" != x ]; then
    echo "Illegal configuration name $CONFNAME"
    exit 1
fi

if [ ! -f $CONFNAME ]; then
    echo "$0: $CONFNAME not found"
    exit 1
fi
echo "Configuration $CONFNAME"

COMPILEDIR="../compile/$CONFNAME"

########################################
#
# 2. Process includes.
#    Also strip comments.
#    Simultaneously, do a basic syntax check.
#
#    For an introduction to awk, see 
#        http://www.hcs.harvard.edu/~dholland/computers/awk.html
#

CONFTMP=.conftmp

rm -f $CONFTMP

echo "$CONFNAME" $CONFTMP | awk '
    BEGIN {
        #
        # Initialize list of directives and required numbers of words for each.
        #
        nfields["include"] = 2;
        nfields["file"] = 2;
        nfields["debug"] = 1;
        nfields["defoption"] = 2;
        nfields["optfile"] = 3;
        nfields["optofffile"] = 3;
        nfields["defdevice"] = 3;
        nfields["defattach"] = 4;
        nfields["pseudoattach"] = 2;
        nfields["options"] = 2;
        nfields["device"] = 4;   # actually 2 or 4, handled specially
        #
        # Directives that can be made machine-dependent with "machine"
        # or "platform".
        #
        okmd["file"] = 1;
        okmd["optfile"] = 1;
        okmd["optofffile"] = 1;
    }

    function doinclude(file,     lineno) {
        #
        # Include a file.
        #
        # lineno is a local.
        #
        # Read lines and hand them off recursively to processline().
        #
        lineno = 1;
        while (getline < file) {
            if (ERRNO) {
                printf "%s: %s\n", file, ERRNO;
                exit(1);
            }
            processline(file, lineno);
            lineno++;
        }
    }

    function processline(filename, lineno) {
        #
        # Handle a single config line.
        #

        # Strip comments.
        sub("#.*", "", $0);

        # Ignore blank lines.
        if (NF==0) return;

        direct = $1;
        foundfields = NF;

        if (direct == "machine" && NF > 2 && okmd[$3]) {
            # machine mips file ...
            direct = $3;
            foundfields -= 2; 
        }
        else if (direct == "platform" && NF > 2 && okmd[$3]) {
            # platform sys161 file ...
            direct = $3;
            foundfields -= 2; 
        }

        # Syntax check: reject unknown directives
        if (!nfields[direct]) {
            printf "%s: %d: Unknown directive %s\n", filename, lineno, direct;
            exit(1);
        }

        # Syntax check: require correct # of args.
        if (direct=="device") {
            # special case - device directive can have 2 or 4 words
            if ((NF!=2 && NF!=4) || (NF==4 && $3!="at")) {
                msg = sprintf("%s: Invalid arguments", direct); 
                printf "%s: %d: %s\n", filename, lineno, msg;
                exit(1);
            }
        }
        else if (nfields[direct]!=foundfields) {
            printf "%s: %d: %s: Invalid arguments\n", filename, lineno, direct;
            exit(1);
        }

        # Now actually process the directives we need at this stage - which
        # is only "include". Handle includes.

        if (direct == "include") {
                doinclude("../" $2);
        }
        else {
                print >> outfile;
        }
    }

    #
    # Code called for lines input on stdin.
    # There is only one - the one generated above with echo, which
    # gives us the names of the input and output files to use.
    #
    {
        outfile = $2;
        doinclude($1);
    }
' || exit 1

########################################
#
# 3. Create compile dir.
#

if [ ! -d "$COMPILEDIR" ]; then
    mkdir $COMPILEDIR
fi

echo -n 'Generating files...'

########################################
#
# 4. Process device attachments into $CONFTMP.attach.
#    Also add device/attachment files to $CONFTMP.files.
#

rm -f $CONFTMP.files
rm -f $CONFTMP.attach

awk < $CONFTMP '

    #
    # Function to grab the "0" off "le0" or the "*" off "wd*".
    #
    function getunit(invalmsg, d,       u, tmp) {
        u = d;
        sub("^[a-zA-Z_]*", "", u);

        if (u!="*") {
            tmp = u;
            sub("[0-9]*", "", tmp);
            if (tmp!="") {
                printf "\n%s: Invalid device/unit specification\n", invalmsg;
                exit(1);
            }
        }

        return u;
    }

    #
    # Function to grab the "le" off "le0" or the "wd" off "wd*".
    #
    function getbase(invalmsg, d,       base) {
        base = d;
        sub("[\\*0-9]*$", "", base);

        if (!use[base]) {
            printf "\n%s: No such device\n", invalmsg;
            exit(1);
        }

        return base;
    }

    #
    # Routine invoked for "defdevice" directive lines.
    #
    $1=="defdevice" {
        dev = $2;
        file = $3;

        # Check for illegal characters in device name
        # (must be legal C symbol, and at this point must not have unit number)
        tmp = dev;
        sub("[a-zA-Z_]*", "", tmp);
        if (tmp!="") {
            printf "\ndefdevice %s: Illegal device name\n", dev;
            exit(1);
        }

        # Device must not have been already defined.
        if (use[dev]) {
            printf "\ndefdevice %s: %s already exists\n", dev, dev;
            exit(1);
        }

        # Note that it exists, but is not in use, and remember the 
        # source file for later.
        use[dev] = "no";
        files[dev] = file;
    }

    #
    # Routine called for "defattach" directive lines.
    #
    $1=="defattach" {
        dev = $2;
        bus = $3;
        file = $4;

        # Even though we do not use basebus, busunit, or devunit, 
        # call the routines to compute them, because they check the
        # syntax.

        devmsg = "defattach: device " dev;
        devunit = getunit(devmsg, dev);
        basedev = getbase(devmsg, dev);

        busmsg = "defattach: bus " bus;
        busunit = getunit(busmsg, bus);
        basebus = getbase(busmsg, bus);

        if (pseudo[basedev]) {
            printf "\n%s: Already declared pseudoattach\n", devmsg;
            exit(1);
        }

        # The attachment is the pair of bus and device.
        # We remember the specific names, including the unit numbers.
        # This is because "le* at sbus*" is different from "le0 at sbus0"
        # - the former allows le0 to be at sbus1, allows le1, etc.

        attachment = bus "." dev;
        attach[attachment] = "no";
        files[attachment] = file;

        # Remember that attachments are defined for this device. If
        # attachments are defined, when the device is turned on later
        # an attachment must be specified. 
        attachable[basedev] = 1;
    }

    #
    # Routine called for "pseudoattach" directive lines.
    #
    $1=="pseudoattach" {
        dev = $2;

        devmsg = "pseudoattach: device " dev;
        devunit = getunit(devmsg, dev);
        basedev = getbase(devmsg, dev);

        if (attachable[basedev]) {
            printf "\n%s: Attachments already declared\n", devmsg;
            exit(1);
        }

        # Remember that this device is a pseudo-device.
        pseudo[basedev] = 1;
    }

    #
    # Helper function for the "device" code.
    #
    function tryattach(combo) {
        if (!attachok && attach[combo]) {
            # This attachment is defined. Note to compile it in, and report
            # success.
            attach[combo] = "yes";
            attachok = 1;
        }
    }

    #
    # Routine called for "device" directive lines.
    #
    $1=="device" {
        dev = $2;
        if (NF==4) {
            devmsg = "device: " dev " at " $4;
        }
        else {
            devmsg = "device: device " dev;
        }
        devunit = getunit(devmsg, dev);
        basedev = getbase(devmsg, dev);
        gendev = basedev "*";

        if (NF==4) {
            #
            # The longer form, with an attachment ("bus").
            #
            bus = $4;
            busmsg = "device: " dev " at " bus ": " bus;
            busunit = getunit(busmsg, bus);
            basebus = getbase(busmsg, bus);
            genbus = basebus "*";

            if (use[basebus]!="yes") {
                printf "\ndevice: bus %s: Bus device is not enabled\n", bus;
                exit(1);
            }

            # If the line was "le0 at sbus0", we try to attach it using
            # the following attachments:
            #    First, the exact thing that was requested:
            #         sbus0.le0   (le0 at sbus0)
            #    Second, for any such device on that bus:
            #         sbus*.le0   (le0 at sbus*)
            #    Third, for that device on any such bus:
            #         sbus0.le*   (le* at sbus0)
            #    Fourth, for any such device on any such bus:
            #         sbus*.le*   (le* at sbus*)
            #
            # If the line was "le* at sbus0", some of these will be
            # redundant, but that is ok.

            attachok = 0;
            tryattach(bus "." dev);
            tryattach(bus "." gendev);
            tryattach(genbus "." dev);
            tryattach(genbus "." gendev);
            if (!attachok) {
                # No matching attachment found.
                printf "\ndevice: %s at %s: Undefined attachment\n", dev, bus;
                exit(1);
            }

            devattach = sprintf("%s %s", basedev, devunit);
            baseattach = sprintf("%s %s", basebus, busunit);
            printf "attach %s at %s\n", devattach, baseattach >> attachfile;
        }
        else {
            # No bus specified to attach the device to (really, to find the
            # device attached on.) This is only legal if no attachments
            # at all were defined for the device, which is the case if the
            # device is in fact not attached to anything else (like the main
            # system bus, or a device like /dev/null that has no hardware.)


            # The opposite check to this is not required in the
            # preceding section because no attachment can be found if
            # attachable[basedev] is false.

            if (attachable[basedev]) {
                printf "\ndevice %s: attachment required\n", dev;
                exit(1);
            }

            if (pseudo[basedev]) {
                if (devunit=="*") {
                    printf "\n%s: May not use wildcard units here\n", devmsg;
                    exit(1);
                }
                printf "pseudo %s %s\n", basedev, devunit >> attachfile;
            }
            else {
                printf "noattach %s\n", basedev >> attachfile;
            }
        }

        use[basedev] = "yes";
    }

    #
    # Routine invoked when we have seen all the input.
    #
    END {
        # Print out the source filenames for the devices and attachments
        # we are using.

        for (dev in use) {
            if (use[dev]=="yes") {
                printf "* * %s\n", files[dev] >> filelistfile;
            }
        }
        for (att in attach) {
            if (attach[att]=="yes") {
                printf "* * %s\n", files[att] >> filelistfile;
            }
        }
    }

' "attachfile=$CONFTMP.attach" "filelistfile=$CONFTMP.files" || exit 1

########################################
#
# 5. Process options.
#

awk < $CONFTMP '

    #
    # Routine for a defoption line.
    #
    $1=="defoption" {
        opt = $2;
        options[opt] = "no";
    }

    #
    # Routine for an optfile line.
    #
    $1=="optfile" || (($1=="machine" || $1=="platform") && $3=="optfile") {
        if ($1 == "optfile") {
            opt = $2;
            file = $3;
            platform = "*";
            machine = "*";
        }
        else {
            if ($1=="machine") {
                platform = "*";
                machine = $2;
            }
            else {
                platform = $2;
                machine = "*";
            }
            opt = $4;
            file = $5;
        }

        if (!options[opt]) {
            printf "\noptfile %s %s: No such option %s\n", opt, file, opt;
            exit(1);
        }

        controllers[file] = opt;
        platforms[file] = platform;
        machines[file] = machine;
    }

    #
    # Routine for an optofffile line.
    #
    $1=="optofffile" || (($1=="machine" || $1=="platform") &&$3=="optofffile"){
        if ($1 == "optofffile") {
            opt = $2;
            file = $3;
            platform = "*";
            machine = "*";
        }
        else {
            if ($1=="machine") {
                platform = "*";
                machine = $2;
            }
            else {
                platform = $2;
                machine = "*";
            }
            opt = $4;
            file = $5;
        }

        if (!options[opt]) {
            printf "\noptofffile %s %s: No such option %s\n", opt, file, opt;
            exit(1);
        }

        offcontrollers[file] = opt;
        platforms[file] = platform;
        machines[file] = machine;
    }

    #
    # Routine for an options line.
    #
    $1=="options" {
        opt = $2;

        if (!options[$2]) {
            printf "\noptions %s: No such option\n", opt;
            exit(1);
        }

        options[$2] = "yes";
    }

    #
    # Routine invoked when we have seen everything.
    #
    END {
        #
        # First, add any files to the list of sources we are building.
        #
        for (file in controllers) {
            if (options[controllers[file]]=="yes") {
                line = sprintf("%s %s %s",
                                platforms[file], machines[file], file);
                printf "%s\n", line >> filelistfile;
            }
        }
        for (file in offcontrollers) {
            if (options[offcontrollers[file]]=="no") {
                line = sprintf("%s %s %s",
                                platforms[file], machines[file], file);
                printf "%s\n", line >> filelistfile;
            }
        }
        close(filelistfile);

        #
        # Now, generate the .h file for every option
        # (both the ones that are on and the ones that are off)
        #
        for (opt in options) {
            realfile = compiledir "/opt-" opt ".h";
            file = realfile ".new";
            sym = toupper(opt);
            printf "/* Automatically generated; do not edit */\n" > file;
            printf "#ifndef _OPT_%s_H_\n", sym >> file;
            printf "#define _OPT_%s_H_\n", sym >> file;
            val = options[opt]=="yes" ? 1 : 0;
            printf "#define OPT_%s %d\n", sym, val >> file;
            printf "#endif /* _OPT_%s_H_ */\n", sym >> file;
            close(file);
        }
    }

' "compiledir=$COMPILEDIR" "filelistfile=$CONFTMP.files" || exit 1

# Avoid changing the actual headers if they aren't different, so as to
# reduce unnecessary recompiles.

(
    cd $COMPILEDIR
    for NF in opt-*.h.new; do
        OF=`echo $NF | sed 's/\.new$//'`
        if diff $OF $NF >/dev/null 2>&1; then
            rm -f $NF      # unchanged
        else
            mv -f $NF $OF  # it changed
        fi
        echo -n " $OF"
    done
)

########################################
#
# 6. Add in the unconditional files.
#

awk < $CONFTMP '
    $1=="file" {
        printf "* * %s\n", $2 >> filelistfile;
    }
    $1=="machine" && $3=="file" {
        printf "* %s %s\n", $2, $4 >> filelistfile;
    }
    $1=="platform" && $3=="file" {
        printf "%s * %s\n", $2, $4 >> filelistfile;
    }
    
' "filelistfile=$CONFTMP.files" || exit 1

#
# autoconf.c (which we generate further down) is always compiled in but
# is not in the list yet. Note that the path to it is where we are about
# to put it: it lives in the build directory, because it's part of a 
# particular build.
#
echo "* * compile/$CONFNAME/autoconf.c" >> $CONFTMP.files

########################################
#
# 7. We now have the compile file list.
#    Generate files.mk.
#

#
# Validate list first.
#
# We allow C++ files, because the makefile rules we generate are
# sufficient to compile them. However, some low-level kernel hacking
# will be needed to actually use C++ in OS/161.
#

awk < $CONFTMP.files '
    /\.cc$/ { next; }
    /\.cpp$/ { next; }
    /\.C$/ { next; }
    /\.c$/ { next; }
    #/\.l$/ { next; }   # will require some makefile hacking to make work
    #/\.y$/ { next; }   # will require some makefile hacking to make work
    /\.S$/ { next; }
    /\.o$/ { next; }
    { 
        printf "\n%s: Unrecognized source file type\n", $1;
        exit(1);
    }
' || exit 1;

#
# Do it.
# Generate a make rule for each file.
#

sort < $CONFTMP.files | awk '
    BEGIN {
        printf "# Automatically generated by config; do not edit\n";
    }

    {
        platform = $1;
        machine = $2;
        file = $3;

        # get basename
        basename = file;
        sub(".*/", "", basename);

        # get extension
        ext = basename;
        sub(".*\\.", "", ext);
        sub("\\.[^\\.]*$", "", basename);

        if (file ~ "^\\.\\./") {
            sub("^...", "", file);
            path = "$(TOP)/" file;
        }
        else {
            path = "$(KTOP)/" file;
        }

        #
        # For now a file cannot be both platform-dependent and
        # machine-dependent, so this sequence of tests is enough.
        #
        if (platform != "*") {
            printf "SRCS.PLATFORM.%s+=%s\n", platform, path;
        }
        else if (machine != "*") {
            printf "SRCS.MACHINE.%s+=%s\n", machine, path;
        }
        else {
            printf "SRCS+=%s\n", path;
        }
    }
' > $COMPILEDIR/files.mk

rm -f $CONFTMP.files

echo -n ' files.mk'

########################################
#
# 8. (reserved)
#

########################################
#
# 9. Generate Makefile
#

(
    echo "# Automatically generated by config; do not edit."
    echo "#"
    echo
    echo '# Top of the kernel tree'
    echo 'KTOP=../..'
    echo '# Top of the whole tree'
    echo 'TOP=$(KTOP)/..'

    echo '# Debug vs. optimize'
    awk < $CONFTMP '
        # Default: optimize.
        BEGIN { debugflags="-O2"; }
        $1=="debug" { 
            debugflags="-g";
        }

        END {
            printf "KDEBUG=%s\n", debugflags;
        }
    '
    echo '# Name of the kernel config file'
    echo "CONFNAME=$CONFNAME"
    echo
    echo '.include "$(TOP)/mk/os161.config.mk"'
    echo '.include "files.mk"'
    echo '.include "$(TOP)/mk/os161.kernel.mk"'

) > $COMPILEDIR/Makefile || exit 1

echo -n ' Makefile'

########################################
#
# 10. (reserved)
#

########################################
#
# 11. Process attachment list.
#     Generate autoconf.[ch].
#

ACHREAL=$COMPILEDIR/autoconf.h
ACH=$COMPILEDIR/autoconf.h.new
ACC=$COMPILEDIR/autoconf.c

echo '/* Automatically generated; do not edit */' > $ACH
echo '/* Automatically generated; do not edit */' > $ACC

echo '#ifndef _AUTOCONF_H_' >> $ACH
echo '#define _AUTOCONF_H_' >> $ACH

#
# first, declare struct foo_softc for all devices foo.
#

echo >> $ACH
awk < $CONFTMP.attach '{ printf "struct %s_softc;\n", $2 }' >> $ACH

#
# second, declare the autoconf_foo functions for unattached devices.
#
# The autoconf_foo functions for attached devices are file-static 
# in autoconf.c.
#

echo >> $ACH
awk < $CONFTMP.attach '$1=="noattach" { print $2 }' | sort -u | awk '
    {
        printf "void autoconf_%s(struct %s_softc *dev, int unit);\n", $1, $1;
    }
' >> $ACH

#
# third, declare the attach functions.
#

echo >> $ACH
awk < $CONFTMP.attach '
    $1=="attach" {
        dev = $2;
        bus = $5;
        f = sprintf("struct %s_softc *attach_%s_to_%s", dev, dev, bus);
        printf "%s(int devunit, struct %s_softc *bus);\n", f, bus;
    }
    $1=="pseudo" {
        dev = $2;
        printf "struct %s_softc *pseudoattach_%s(int devunit);\n", dev, dev;
    }
' >> $ACH

#
# fourth, declare the config functions.
#

echo >> $ACH
awk < $CONFTMP.attach '
    $1=="attach" {
        dev = $2;
        printf "int config_%s(struct %s_softc *dev, int unit);\n", dev, dev;
    }
' >> $ACH

#
# Declare pseudoconfig()
#
echo >> $ACH
echo 'void pseudoconfig(void);' >> $ACH
echo >> $ACH

#
# Done with the header file.
#
echo '#endif /* _AUTOCONF_H_ */' >> $ACH

#
# Avoid changing the actual autoconf.h if it's not different, so as to
# reduce unnecessary recompiles.
#

if diff $ACHREAL $ACH >/dev/null 2>&1; then
    rm -f $ACH            # unchanged
else
    mv -f $ACH $ACHREAL   # it changed
fi

echo -n ' autoconf.h'

#
# now, autoconf.c
#

echo '#include <types.h>' >> $ACC
echo '#include <lib.h>' >> $ACC
echo '#include "autoconf.h"' >> $ACC

#
# first, declare the static autoconf_foo functions and the nextunit_foo vars
#
echo >> $ACC
awk < $CONFTMP.attach '$1=="attach" || $1=="pseudo" { print $2 }' | sort -u |\
  awk '
    { 
        printf "static void autoconf_%s(struct %s_softc *, int);\n", $1, $1;
    }
' >> $ACC
awk < $CONFTMP.attach '$1=="attach" { print $2 }' | sort -u | awk '
    { 
        printf "static int nextunit_%s;\n", $1;
    }
' >> $ACC
echo >> $ACC

#
# Now generate the tryattach_ functions.
#

awk < $CONFTMP.attach '
    $1=="attach" {
        dev = $2;
        bus = $5;
        printf "static\n";
        printf "int\n";
        printf "tryattach_%s_to_%s", dev, bus;
        printf "(int devunit, struct %s_softc *bus, int busunit)\n", bus;
        printf "{\n";
        printf "\tstruct %s_softc *dev;\n", dev;
        printf "\tint result;\n", dev;
        printf "\n";
        printf "\tdev = attach_%s_to_%s(devunit, bus);\n", dev, bus;
        printf "\tif (dev==NULL) {\n";
        printf "\t\treturn -1;\n";
        printf "\t}\n";
        printf "\tkprintf(\"%s%%d at %s%%d\", devunit, busunit);\n", dev, bus;
        printf "\tresult = config_%s(dev, devunit);\n", dev;
        printf "\tif (result != 0) {\n";
        printf "\t\tkprintf(\": %%s\\n\", strerror(result));\n";
                # Note: we leak the device softc instead of trying 
                # to clean it up.
        printf "\t\t/* should really clean up dev */\n";
        printf "\t\treturn result;\n";
        printf "\t}\n";
        printf "\tkprintf(\"\\n\");\n";
        printf "\tnextunit_%s = devunit+1;\n", dev;
        printf "\tautoconf_%s(dev, devunit);\n", dev;
        printf "\treturn 0;\n";
        printf "}\n";
        printf "\n";
    }
' >> $ACC
echo >> $ACC


#
# Now comes the tricky part, actually writing those autoconf
# functions.  We need one for every device. In each one, there needs
# to be a probe section for each line in $CONFTMP.attach in which that
# device appears on the *right hand* (bus) side.
#

awk < $CONFTMP.attach '
    BEGIN { nlines=0; npseudo=0; }
    $1=="attach" {
        devs[nlines] = $2;
        devunits[nlines] = $3;
        buses[nlines] = $5;
        busunits[nlines] = $6;
        alldevs[$2] = 1;
        nlines++;
    }
    $1=="noattach" {
        alldevs[$2] = 0;
    }
    $1=="pseudo" {
        alldevs[$2] = 0;
        pseudodevs[npseudo] = $2;
        pseudounits[npseudo] = $3;
        npseudo++;
    }

    function genprobe(dev, devunit, bus, busunit) {

        tryfunc = sprintf("tryattach_%s_to_%s", dev, bus);
            
        if (busunit!="*") {
            printf "\tif (busunit==%d) {\n", busunit;
        }
        else {
            printf "\t{\n";
        }

        if (devunit!="*") {
            printf "\t\tif (nextunit_%s <= %d) {\n", dev, devunit;
            printf "\t\t\t%s(%d, bus, busunit);\n", tryfunc, devunit;
            printf "\t\t}\n";
        }
        else {
            printf "\t\tint result, devunit=nextunit_%s;\n", dev;
            printf "\t\tdo {\n";
            printf "\t\t\tresult = %s(devunit, bus, busunit);\n", tryfunc;
            printf "\t\t\tdevunit++;\n";
            printf "\t\t} while (result==0);\n";
        }

        printf "\t}\n";
    }

    END {
        for (bus in alldevs) {
            softc = sprintf("struct %s_softc", bus);

            if (alldevs[bus]) printf "static\n";
            printf "void\n";
            printf "autoconf_%s(%s *bus, int busunit)\n", bus, softc;
            printf "{\n";
            printf "\t(void)bus; (void)busunit;\n";

            for (i=0; i<nlines; i++) {
                if (buses[i]==bus) {
                    genprobe(devs[i], devunits[i], buses[i], busunits[i]);
                }
            }

            printf "}\n\n";
        }

        printf "void\n";
        printf "pseudoconfig(void)\n";
        printf "{\n";
        for (i=0; i<npseudo; i++) {
            dev = pseudodevs[i];
            unit = pseudounits[i];
            printf "\t{\n";
            printf "\t\tstruct %s_softc *s;\n", dev;
            printf "\t\t\n";
            printf "\t\ts = pseudoattach_%s(%s);\n", dev, unit;
            printf "\t\tif (s!=NULL) {\n";
            printf "\t\t\tkprintf(\"%s%d (virtual)\\n\");\n", dev, unit;
            printf "\t\t\tautoconf_%s(s, %s);\n", dev, unit;
            printf "\t\t}\n";
            printf "\t}\n";
        }
        printf "}\n\n";
    }
' >> $ACC

echo -n ' autoconf.c'

rm -f $CONFTMP $CONFTMP.attach

########################################
#
# Done.
#

echo
echo "Configuration in ../compile/$CONFNAME done"
echo "Remember to bmake depend"

/* [<][>][^][v][top][bottom][index][help] */