root/usr/src/grub/grub-0.97/netboot/config.c
/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2, or (at
 * your option) any later version.
 */

#include        "grub.h"
#include        "pci.h"
#include        "isa.h"
#include        "nic.h"

#ifdef CONFIG_PCI
static int pci_probe(struct dev *dev, const char *type_name)
{
/*
 *      NIC probing is in pci device order, followed by the 
 *      link order of the drivers.  A driver that matches 
 *      on vendor and device id will supersede a driver
 *      that matches on pci class.
 *
 *      If you want to probe for another device behind the same pci
 *      device just increment index.  And the previous probe call
 *      will be repeated.
 */
        struct pci_probe_state *state = &dev->state.pci;
        printf("Probing pci %s...\n", type_name);
        if (dev->how_probe == PROBE_FIRST) {
                state->advance    = 1;
                state->dev.driver = 0;
                state->dev.bus    = 0;
                state->dev.devfn  = 0;
                dev->index        = -1;
        }
        for(;;) {
                if ((dev->how_probe != PROBE_AWAKE) && state->advance) {
                        find_pci(dev->type, &state->dev);
                        dev->index = -1;
                }
                state->advance = 1;
                
                if (state->dev.driver == 0)
                        break;
                
#if 0
                /* FIXME the romaddr code needs a total rethought to be useful */
                if (state->dev.romaddr != ((unsigned long) rom.rom_segment << 4)) {
                        continue;
                }
#endif
                if (dev->how_probe != PROBE_AWAKE) {
                        dev->type_index++;
                }
                dev->devid.bus_type = PCI_BUS_TYPE;
                dev->devid.vendor_id = htons(state->dev.vendor);
                dev->devid.device_id = htons(state->dev.dev_id);
                /* FIXME how do I handle dev->index + PROBE_AGAIN?? */
                
                printf("[%s]", state->dev.name);
                if (state->dev.driver->probe(dev, &state->dev)) {
                        state->advance = (dev->index == -1);
                        return PROBE_WORKED;
                }
                putchar('\n');
        }
        return PROBE_FAILED;
}
#endif

#ifdef CONFIG_ISA
static int isa_probe(struct dev *dev, const char *type_name)
{
/*
 *      NIC probing is in the order the drivers were linked togeter.
 *      If for some reason you want to change the order,
 *      just change the order you list the drivers in.
 */
        struct isa_probe_state *state = &dev->state.isa;
        printf("Probing isa %s...\n", type_name);
        if (dev->how_probe == PROBE_FIRST) {
                state->advance = 0;
                state->driver  = isa_drivers;
                dev->index     = -1;
        }
        for(;;)
        {
                if ((dev->how_probe != PROBE_AWAKE) && state->advance) {
                        state->driver++;
                        dev->index = -1;
                }
                state->advance = 1;
                
                if (state->driver >= isa_drivers_end)
                        break;

                if (state->driver->type != dev->type)
                        continue;

                if (dev->how_probe != PROBE_AWAKE) {
                        dev->type_index++;
                }
                printf("[%s]", state->driver->name);
                dev->devid.bus_type = ISA_BUS_TYPE;
                /* FIXME how do I handle dev->index + PROBE_AGAIN?? */
                /* driver will fill in vendor and device IDs */
                if (state->driver->probe(dev, state->driver->ioaddrs)) {
                        state->advance = (dev->index == -1);
                        return PROBE_WORKED;
                }
                putchar('\n');
        }
        return PROBE_FAILED;
}
#else
#define isa_probe(d,tn) (PROBE_FAILED)
#endif
static const char *driver_name[] = {
        "nic", 
        "disk", 
        "floppy",
};
int probe(struct dev *dev)
{
        const char *type_name;

        EnterFunction("probe");

        type_name = "";
        if ((dev->type >= 0) && 
                (dev->type < sizeof(driver_name)/sizeof(driver_name[0]))) {
                type_name = driver_name[dev->type];
        }
        if (dev->how_probe == PROBE_FIRST) {
                dev->to_probe = PROBE_PCI;
                memset(&dev->state, 0, sizeof(dev->state));
        }
        if (dev->to_probe == PROBE_PCI) {
                dev->how_probe = pci_probe(dev, type_name);
                if (dev->how_probe == PROBE_FAILED) {
                        dev->to_probe = PROBE_ISA;
                }
        }
        if (dev->to_probe == PROBE_ISA) {
                dev->how_probe = isa_probe(dev, type_name);
                if (dev->how_probe == PROBE_FAILED) {
                        dev->to_probe = PROBE_NONE;
                }
        }
        if ((dev->to_probe != PROBE_PCI) &&
                (dev->to_probe != PROBE_ISA)) {
                dev->how_probe = PROBE_FAILED;
                
        }

        LeaveFunction("probe");
        return dev->how_probe;
}

void disable(struct dev *dev)
{
        if (dev->disable) {
                dev->disable(dev);
                dev->disable = 0;
        }
}