| /* |
| * 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; |
| } |
| } |