diff --git a/src/core/dev.c b/src/core/dev.c index 0f9936a0..002fa7aa 100644 --- a/src/core/dev.c +++ b/src/core/dev.c @@ -2,6 +2,20 @@ #include "stddef.h" #include "dev.h" +/* + * Each driver specifies a name, the bus-scanning function + * (find_bus_boot_device) that it wants to use, a driver information + * structure (bus_driver) containing e.g. device IDs to be passed to + * find_bus_boot_device, and a probe function (probe) to be called + * whenever a suitable device is found. + * + * The generic device-probing code knows nothing about particular bus + * types; it simply passes the driver information structure + * (bus_driver) to the bus-scanning function (find_bus_boot_device), + * then passes the result of that function (if not NULL) to the probe + * function (probe). + */ + /* Defined by linker */ extern struct boot_driver boot_drivers[]; extern struct boot_driver boot_drivers_end[]; @@ -19,19 +33,30 @@ void print_drivers ( void ) { } /* Get the next available boot device */ -int probe ( struct dev *dev ) { - +int find_boot_device ( struct dev *dev ) { for ( ; boot_driver < boot_drivers_end ; boot_driver++ ) { - dev->name = "unknown"; - if ( boot_driver->probe ( dev ) ) + dev->driver = boot_driver; + dev->name = boot_driver->name; + DBG ( "Probing driver %s...\n", dev->name ); + if ( boot_driver->find_bus_boot_device ( dev, + boot_driver->bus_driver ) ) { + DBG ( "Found device %s (ID %hhx:%hx:%hx)\n", + dev->name, dev->devid->bus_type, + dev->devid->vendor_id, dev->devid->device_id ); return 1; + } } - + /* No more boot devices found */ boot_driver = boot_drivers; return 0; } +/* Probe the boot device */ +int probe ( struct dev *dev ) { + return dev->driver->probe ( dev, dev->bus ); +} + /* Disable a device */ void disable ( struct dev *dev ) { if ( dev->dev_op ) { diff --git a/src/core/main.c b/src/core/main.c index 3cc777a8..bf0a4b0e 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -144,7 +144,7 @@ static int initialized; /* Global instance of the current boot device */ -DEV_BUS(struct {}, dev_bus); +DEV_BUS(struct bus_device, dev_bus); struct dev dev = { .bus = &dev_bus, }; @@ -181,8 +181,17 @@ int main ( void ) { for ( ; ; disable ( &dev ), call_reset_fns() ) { /* Get next boot device */ - if ( ! probe ( &dev ) ) { + if ( ! find_boot_device ( &dev ) ) { /* Reached end of device list */ + printf ( "No more boot devices\n" ); + continue; + } + + /* Probe boot device */ + if ( ! probe ( &dev ) ) { + /* Device found on bus, but probe failed */ + printf ( "Probe failed on %s, trying next device\n", + dev.name ); continue; } @@ -192,12 +201,14 @@ int main ( void ) { /* Load configuration (e.g. DHCP) */ if ( ! load_configuration ( &dev ) ) { /* DHCP failed */ + printf ( "Could not configure device %s\n", dev.name ); continue; } /* Load image */ if ( ! load ( &dev ) ) /* Load failed */ + printf ( "Could not boot from device %s\n", dev.name ); continue; } diff --git a/src/include/dev.h b/src/include/dev.h index 73a4ca65..9ade0e1f 100644 --- a/src/include/dev.h +++ b/src/include/dev.h @@ -23,11 +23,12 @@ struct dev { struct dev_operations *dev_op; const char *name; struct dev_id devid; /* device ID string (sent to DHCP server) */ + struct boot_driver *driver; /* driver being used for boot */ /* Pointer to bus information for device. Whatever sets up * the struct dev must make sure that this points to a buffer * large enough for the required struct _device. */ - void *bus; + struct bus_device *bus; /* All possible device types */ union { struct nic nic; @@ -49,20 +50,33 @@ struct dev_operations { int ( *load ) ( struct dev * ); }; +/* + * Table to describe a bootable device driver. See comments in dev.c + * for an explanation. + * + */ +struct bus_device {}; +struct bus_driver {}; struct boot_driver { char *name; - int (*probe) ( struct dev * ); + struct bus_device * ( *find_bus_boot_device ) ( struct dev *dev, + struct bus_driver *driver ); + struct bus_driver *bus_driver; + int ( *probe ) ( struct dev *dev, struct bus_device *bus_device ); }; -#define BOOT_DRIVER( driver_name, probe_func ) \ +#define BOOT_DRIVER( _name, _find_bus_boot_device, _bus_driver, _probe ) \ static struct boot_driver boot_driver_ ## probe_func \ __attribute__ ((used,__section__(".boot_drivers"))) = { \ - .name = driver_name, \ - .probe = probe_func, \ + .name = _name, \ + .find_bus_boot_device = ( void * ) _find_bus_boot_device, \ + .bus_driver = ( void * ) _bus_driver, \ + .probe = ( void * ) _probe, \ }; /* Functions in dev.c */ extern void print_drivers ( void ); +extern int find_boot_device ( struct dev *dev ); extern int probe ( struct dev *dev ); extern void disable ( struct dev *dev ); static inline void print_info ( struct dev *dev ) {