Created a bus/device API that allows for the ROM prefix to specify an
authorMichael Brown <mcb30@etherboot.org>
Thu, 21 Apr 2005 18:18:29 +0000 (18:18 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 21 Apr 2005 18:18:29 +0000 (18:18 +0000)
initial device, and will also allow for e.g. a device menu to be presented
to the user.

16 files changed:
src/arch/i386/prefix/select_isapnp.c
src/arch/i386/prefix/select_pci.c
src/arch/i386/scripts/i386.lds
src/core/btext.c
src/core/dev.c
src/core/main.c
src/core/nic.c
src/core/pxe_export.c
src/drivers/bus/pci.c
src/include/bus.h [deleted file]
src/include/dev.h
src/include/dhcp.h [new file with mode: 0644]
src/include/isa_ids.h
src/include/mca.h
src/include/nic.h
src/include/pci.h

index ac1af21..14e3db0 100644 (file)
@@ -1,3 +1,4 @@
+#include "dev.h"
 #include "isapnp.h"
 #include "registers.h"
 
@@ -16,5 +17,16 @@ void i386_select_isapnp_device ( struct i386_all_regs *regs ) {
         * address in %dx.
         *
         */
-       select_isapnp_device ( regs->dx, regs->bx );
+       union {
+               struct bus_loc bus_loc;
+               struct isapnp_loc isapnp_loc;
+       } u;
+
+       /* Set ISAPnP read port */
+       isapnp_set_read_port ( regs->dx );
+       
+       /* Select ISAPnP bus and specified CSN as first boot device */
+       memset ( &u, 0, sizeof ( u ) );
+       u.isapnp_loc.csn = regs->bx;
+       select_device ( &dev, &isapnp_driver, &u.bus_loc );
 }
index 046c59f..c9a62d5 100644 (file)
@@ -1,3 +1,4 @@
+#include "dev.h"
 #include "pci.h"
 #include "registers.h"
 
@@ -15,5 +16,13 @@ void i386_select_pci_device ( struct i386_all_regs *regs ) {
         * PCI BIOS passes busdevfn in %ax
         *
         */
-       select_pci_device ( regs->ax );
+       union {
+               struct bus_loc bus_loc;
+               struct pci_loc pci_loc;
+       } u;
+       
+       /* Select PCI bus and specified busdevfn as first boot device */
+       memset ( &u, 0, sizeof ( u ) );
+       u.pci_loc.busdevfn = regs->ax;
+       select_device ( &dev, &pci_driver, &u.bus_loc );
 }
index fc44683..0ed9955 100644 (file)
@@ -142,9 +142,15 @@ SECTIONS {
        *(.data.*)
 
        /* Various tables */
-       boot_drivers = .;
-       *(.boot_drivers)
-       boot_drivers_end = .;
+       device_drivers = .;
+       *(.drivers.device)
+       device_drivers_end = .;
+       bus_drivers = .;
+       *(.drivers.bus)
+       bus_drivers_end = .;
+       type_drivers = .;
+       *(.drivers.type)
+       type_drivers_end = .;
        console_drivers = .;
        *(.drivers.console)
        console_drivers_end = .;
index 663fd4a..86bbba3 100644 (file)
@@ -408,7 +408,7 @@ static void btext_init(void)
 
     #warning "pci_find_device_x no longer exists; use find_pci_device instead"
     /*    pci_find_device_x(0x1002, 0x4752, 0, &dev); */
-    if(dev.vendor==0) return; // no fb
+    if(dev.vendor_id==0) return; // no fb
 
     frame_buffer = (uint32_t)dev.membase;
 #else
index 9c53688..5d13f70 100644 (file)
  * function (probe).
  */
 
-/* Defined by linker */
-extern struct boot_driver boot_drivers[];
-extern struct boot_driver boot_drivers_end[];
+/* Current attempted boot device */
+struct dev dev = {
+       .bus_driver = bus_drivers,
+       .device_driver = device_drivers,
+};
 
-/* Current attempted boot driver */
-static struct boot_driver *boot_driver = boot_drivers;
-
-/* Print all drivers */
+/*
+ * Print all drivers 
+ *
+ */
 void print_drivers ( void ) {
-       struct boot_driver *driver;
+       struct device_driver *driver;
 
-       for ( driver = boot_drivers ; driver < boot_drivers_end ; driver++ ) {
+       for ( driver = device_drivers ;
+             driver < device_drivers_end ;
+             driver++ ) {
                printf ( "%s ", driver->name );
        }
 }
 
-/* Get the next available boot device */
-int find_boot_device ( struct dev *dev ) {
-       for ( ; boot_driver < boot_drivers_end ; boot_driver++ ) {
-               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;
-               }
-       }
+/*
+ * Move to the next location on any bus
+ *
+ */
+static inline int next_location ( struct bus_driver **bus_driver,
+                                 struct bus_loc *bus_loc ) {
+       /* Move to next location on this bus, if any */
+       if ( (*bus_driver)->next_location ( bus_loc ) )
+               return 1;
+
+       /* Move to first (zeroed) location on next bus, if any */
+       if ( ++(*bus_driver) < bus_drivers_end )
+               return 1;
+
+       /* Reset to first bus, return "no more locations" */
+       *bus_driver = bus_drivers;
+       return 0;
+}
+
+/*
+ * Find the next available device on any bus
+ *
+ * Set skip=1 to skip over the current device
+ *
+ */
+int find_any ( struct bus_driver **bus_driver, struct bus_loc *bus_loc,
+              struct bus_dev *bus_dev, signed int skip ) {
+       DBG ( "searching for any device\n" );
+       do {
+               if ( --skip >= 0 )
+                       continue;
+               if ( ! (*bus_driver)->fill_device ( bus_dev, bus_loc ) )
+                       continue;
+               DBG ( "found device %s\n",
+                     (*bus_driver)->describe ( bus_dev ) );
+               return 1;
+       } while ( next_location ( bus_driver, bus_loc ) );
+
+       DBG ( "found no device\n" );
+       return 0;
+}
 
-       /* No more boot devices found */
-       boot_driver = boot_drivers;
+/*
+ * Find a driver by specified device.
+ *
+ * Set skip=1 to skip over the current driver
+ *
+ */
+int find_by_device ( struct device_driver **device_driver,
+                    struct bus_driver *bus_driver, struct bus_dev *bus_dev,
+                    signed int skip ) {
+       DBG ( "searching for a driver for device %s\n",
+             bus_driver->describe ( bus_dev ) );
+       do {
+               if ( --skip >= 0 )
+                       continue;
+               if ( (*device_driver)->bus_driver != bus_driver )
+                       continue;
+               if ( ! bus_driver->check_driver ( bus_dev, *device_driver ))
+                       continue;
+               DBG ( "found driver %s\n", (*device_driver)->name );
+               return 1;
+       } while ( ++(*device_driver) < device_drivers_end );
+       
+       /* Reset to first driver, return "not found" */
+       DBG ( "found no driver for device %s\n",
+             bus_driver->describe ( bus_dev ) );
+       *device_driver = device_drivers;
        return 0;
 }
 
-/* Probe the boot device */
-int probe ( struct dev *dev ) {
-       return dev->driver->probe ( dev, dev->bus );
+/*
+ * Find a device by specified driver.
+ *
+ * Set skip=1 to skip over the current device
+ *
+ */
+int find_by_driver ( struct bus_loc *bus_loc, struct bus_dev *bus_dev,
+                    struct device_driver *device_driver,
+                    signed int skip ) {
+       struct bus_driver *bus_driver = device_driver->bus_driver;
+       
+       DBG ( "searching for a device for driver %s\n", device_driver->name );
+       do {
+               if ( --skip >= 0 )
+                       continue;
+               if ( ! bus_driver->fill_device ( bus_dev, bus_loc ) )
+                       continue;
+               if ( ! bus_driver->check_driver ( bus_dev, device_driver ) )
+                       continue;
+               DBG ( "found device %s\n", bus_driver->describe ( bus_dev ) );
+               return 1;
+       } while ( bus_driver->next_location ( bus_loc ) );
+
+       DBG ( "found no device for driver %s\n" );
+       return 0;
 }
 
-/* Disable a device */
-void disable ( struct dev *dev ) {
-       if ( dev->dev_op ) {
-               dev->dev_op->disable ( dev );
-               dev->dev_op = NULL;
+/*
+ * Find the next available (device,driver) combination
+ *
+ * Set skip=1 to skip over the current (device,driver)
+ *
+ * Note that the struct dev may not have been previously used, and so
+ * may not contain a valid (device,driver) combination.
+ *
+ */
+int find_any_with_driver ( struct dev *dev, signed int skip ) {
+       signed int skip_device = 0;
+       signed int skip_driver = skip;
+
+       while ( find_any ( &dev->bus_driver, &dev->bus_loc, &dev->bus_dev,
+                          skip_device ) ) {
+               if ( find_by_device ( &dev->device_driver, dev->bus_driver,
+                                     &dev->bus_dev, skip_driver ) ) {
+                       /* Set type_driver to be that of the device
+                        * driver
+                        */
+                       dev->type_driver = dev->device_driver->type_driver;
+                       /* Set type device instance to be the single
+                        * instance provided by the type driver
+                        */
+                       dev->type_dev = dev->type_driver->type_dev;
+                       return 1;
+               }
+               skip_driver = 0;
+               skip_device = 1;
        }
+
+       return 0;
 }
index 01e616c..bcfdd5c 100644 (file)
@@ -143,12 +143,6 @@ static int exit_status;
 static int initialized;
 
 
-/* Global instance of the current boot device */
-DEV_BUS(struct bus_device, dev_bus);
-struct dev dev = {
-       .bus = &dev_bus,
-};
-
 /**************************************************************************
  * initialise() - perform any C-level initialisation
  *
@@ -169,6 +163,7 @@ void initialise ( void ) {
 MAIN - Kick off routine
 **************************************************************************/
 int main ( void ) {
+       int skip = 0;
 
        /* Print out configuration */
        print_config();
@@ -181,36 +176,34 @@ int main ( void ) {
        for ( ; ; disable ( &dev ), call_reset_fns() ) {
 
                /* Get next boot device */
-               if ( ! find_boot_device ( &dev ) ) {
+               if ( ! find_any_with_driver ( &dev, skip ) ) {
                        /* Reached end of device list */
                        printf ( "No more boot devices\n" );
+                       skip = 0;
                        sleep ( 2 );
                        continue;
                }
 
+               /* Skip this device the next time we encounter it */
+               skip = 1;
+
+               /* Print out what we're doing */
+               printf ( "Booting from %s %s at %s "
+                        "using the %s driver\n",
+                        dev.bus_driver->name ( &dev.bus_dev ),
+                        dev.type_driver->name,
+                        dev.bus_driver->describe ( &dev.bus_dev ),
+                        dev.device_driver->name );
+
                /* Probe boot device */
                if ( ! probe ( &dev ) ) {
                        /* Device found on bus, but probe failed */
-                       printf ( "Probe failed on %s, trying next device\n",
-                                dev.name );
+                       printf ( "...probe failed on %s\n" );
                        continue;
                }
                
-               /* Print device info */
-               print_info ( &dev );
-
-               /* 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;
+               printf ( "%s: %s\n", dev.bus_driver->name ( &dev.bus_dev ),
+                        dev.type_driver->describe ( dev.type_dev ) );
        }
 
        /* Call registered per-object exit functions */
@@ -463,8 +456,7 @@ void cleanup(void)
        nfs_umountall(ARP_SERVER);
 #endif
        /* Stop receiving packets */
-       eth_disable();
-       disk_disable();
+       disable ( &dev );
        initialized = 0;
 }
 
index 50ca4e8..166eedd 100644 (file)
@@ -52,7 +52,7 @@ static unsigned char dhcp_machine_info[] = {
        /* Our enclosing DHCP tag */
        RFC1533_VENDOR_ETHERBOOT_ENCAP, 11,
        /* Our boot device */
-       RFC1533_VENDOR_NIC_DEV_ID, 5, PCI_BUS_TYPE, 0, 0, 0, 0,
+       RFC1533_VENDOR_NIC_DEV_ID, 5, 0, 0, 0, 0, 0,
        /* Our current architecture */
        RFC1533_VENDOR_ARCH, 2, EM_CURRENT & 0xff, (EM_CURRENT >> 8) & 0xff,
 #ifdef EM_CURRENT_64
@@ -231,13 +231,10 @@ static int bootp(void);
 static unsigned short tcpudpchksum(struct iphdr *ip);
 
 
-struct nic *nic = &dev.nic;
-
 /*
  * Find out what our boot parameters are
  */
-static int nic_load_configuration ( struct dev *dev ) {
-       struct nic *nic = &dev->nic;
+static int nic_load_configuration ( struct nic *nic ) {
        int server_found;
 
        if ( ! nic->nic_op->connect ( nic ) ) {
@@ -321,35 +318,31 @@ static int nic_load(struct dev *dev __unused)
        return 0;
 }
 
-
-static void nic_disable ( struct dev *dev ) {
-       struct nic *nic = &dev->nic;
-
+void nic_disable ( struct nic *nic __unused ) {
 #ifdef MULTICAST_LEVEL2
        int i;
        for(i = 0; i < MAX_IGMP; i++) {
                leave_group(i);
        }
 #endif
-       
-       nic->nic_op->disable ( nic );
 }
 
-static void nic_print_info ( struct dev *dev ) {
-       struct nic *nic = &dev->nic;
-
-       printf ( "Found %s NIC (MAC %!)\n", dev->name, nic->node_addr );
+static char * nic_describe ( struct type_dev *type_dev ) {
+       struct nic *nic = ( struct nic * ) type_dev;
+       static char nic_description[] = "MAC 00:00:00:00:00:00";
+       
+       sprintf ( nic_description + 4, "%!", nic->node_addr );
+       return nic_description;
 }
 
 /* 
  * Device operations tables
  *
  */
-static struct dev_operations nic_operations = {
-       .disable = nic_disable,
-       .print_info = nic_print_info,
-       .load_configuration = nic_load_configuration,
-       .load = nic_load,
+struct type_driver nic_driver = {
+       .name           = "NIC",
+       .type_dev       = ( struct type_dev * ) &nic,
+       .describe       = nic_describe,
 };
 
 /* Careful.  We need an aligned buffer to avoid problems on machines
@@ -360,19 +353,10 @@ static struct dev_operations nic_operations = {
  */
 static char    packet[ETH_FRAME_LEN + ETH_DATA_ALIGN] __aligned;
 
-/*
- * Set up a struct dev to operate as a NIC, return the struct nic *
- *
- */
-struct nic * nic_device ( struct dev *dev ) {
-       struct nic *nic = &dev->nic;
-
-       memset ( nic, 0, sizeof ( *nic ) );
-       nic->node_addr = arptable[ARP_CLIENT].node;
-       nic->packet = packet + ETH_DATA_ALIGN;
-       dev->dev_op = &nic_operations;
-       return nic;
-}
+struct nic nic = {
+       .node_addr = arptable[ARP_CLIENT].node,
+       .packet = packet + ETH_DATA_ALIGN,
+};
 
 
 
@@ -408,9 +392,9 @@ static int await_arp(int ival, void *ptr,
        struct  arprequest *arpreply;
        if (ptype != ETH_P_ARP)
                return 0;
-       if (nic->packetlen < ETH_HLEN + sizeof(struct arprequest))
+       if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
                return 0;
-       arpreply = (struct arprequest *)&nic->packet[ETH_HLEN];
+       arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
 
        if (arpreply->opcode != htons(ARP_REPLY)) 
                return 0;
@@ -697,7 +681,7 @@ int tftp_block ( struct tftpreq_info_t *request, struct tftpblk_info_t *block )
                        continue; /* Back to waiting for packet */
                }
                /* Packet has been received */
-               rcvd = (struct tftp_t *)&nic->packet[ETH_HLEN];
+               rcvd = (struct tftp_t *)&nic.packet[ETH_HLEN];
                recvlen = ntohs(rcvd->udp.len) - sizeof(struct udphdr)
                        - sizeof(rcvd->opcode);
                rport = ntohs(rcvd->udp.src);
@@ -777,9 +761,9 @@ static int await_rarp(int ival, void *ptr,
        struct arprequest *arpreply;
        if (ptype != ETH_P_RARP)
                return 0;
-       if (nic->packetlen < ETH_HLEN + sizeof(struct arprequest))
+       if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
                return 0;
-       arpreply = (struct arprequest *)&nic->packet[ETH_HLEN];
+       arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
        if (arpreply->opcode != htons(RARP_REPLY))
                return 0;
        if ((arpreply->opcode == htons(RARP_REPLY)) &&
@@ -841,9 +825,9 @@ static int await_bootp(int ival __unused, void *ptr __unused,
        if (!udp) {
                return 0;
        }
-       bootpreply = (struct bootp_t *)&nic->packet[ETH_HLEN + 
+       bootpreply = (struct bootp_t *)&nic.packet[ETH_HLEN + 
                sizeof(struct iphdr) + sizeof(struct udphdr)];
-       if (nic->packetlen < ETH_HLEN + sizeof(struct iphdr) + 
+       if (nic.packetlen < ETH_HLEN + sizeof(struct iphdr) + 
                sizeof(struct udphdr) + 
 #ifdef NO_DHCP_SUPPORT
                sizeof(struct bootp_t)
@@ -916,14 +900,7 @@ static int bootp(void)
        unsigned char *bp_vend;
 
 #ifndef        NO_DHCP_SUPPORT
-       struct {
-               uint8_t bus_type;
-               uint16_t vendor_id;
-               uint16_t device_id;
-       } __attribute__((packed)) *dhcp_dev_id = (void*)&dhcp_machine_info[4];
-       dhcp_dev_id->bus_type = dev.devid.bus_type;
-       dhcp_dev_id->vendor_id = htons ( dev.devid.vendor_id );
-       dhcp_dev_id->device_id = htons ( dev.devid.device_id );
+       * ( ( struct dhcp_dev_id * ) &dhcp_machine_info[4] ) = nic.dhcp_dev_id;
 #endif /* NO_DHCP_SUPPORT */
        memset(&ip, 0, sizeof(struct bootpip_t));
        ip.bp.bp_op = BOOTP_REQUEST;
@@ -1089,11 +1066,11 @@ static void process_igmp(struct iphdr *ip, unsigned long now)
        int i;
        unsigned iplen;
        if (!ip || (ip->protocol == IP_IGMP) ||
-               (nic->packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
+               (nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
                return;
        }
        iplen = (ip->verhdrlen & 0xf)*4;
-       igmp = (struct igmp *)&nic->packet[sizeof(struct iphdr)];
+       igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)];
        if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0)
                return;
        if ((igmp->type == IGMP_QUERY) && 
@@ -1300,7 +1277,7 @@ int tcp_transaction(unsigned long destip, unsigned int destsock, void *ptr,
               syn_ack = state == CLOSED || state == SYN_RCVD;
               consumed = ntohl(tcp->ack) - send_seq - syn_ack;
               if (consumed < 0 || consumed > can_send) {
-                      tcp_reset((struct iphdr *)&nic->packet[ETH_HLEN]);
+                      tcp_reset((struct iphdr *)&nic.packet[ETH_HLEN]);
                       goto recv_data;
               }
 
@@ -1342,7 +1319,7 @@ int tcp_transaction(unsigned long destip, unsigned int destsock, void *ptr,
        }
 
  consume_data:
-       ip  = (struct iphdr *)&nic->packet[ETH_HLEN];
+       ip  = (struct iphdr *)&nic.packet[ETH_HLEN];
        header_size = sizeof(struct iphdr) + ((ntohs(tcp->ctrl)>>10)&0x3C);
        payload = ntohs(ip->len) - header_size;
        if (payload > 0 && state == ESTABLISHED) {
@@ -1351,7 +1328,7 @@ int tcp_transaction(unsigned long destip, unsigned int destsock, void *ptr,
                       recv_seq += payload - old_bytes;
                       if (state != FIN_WAIT_1 && state != FIN_WAIT_2 &&
                           !recv(payload - old_bytes,
-                                &nic->packet[ETH_HLEN+header_size+old_bytes],
+                                &nic.packet[ETH_HLEN+header_size+old_bytes],
                                 ptr)) {
                               goto close;
                       }
@@ -1463,15 +1440,15 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
                /* We have something! */
 
                /* Find the Ethernet packet type */
-               if (nic->packetlen >= ETH_HLEN) {
-                       ptype = ((unsigned short) nic->packet[12]) << 8
-                               | ((unsigned short) nic->packet[13]);
+               if (nic.packetlen >= ETH_HLEN) {
+                       ptype = ((unsigned short) nic.packet[12]) << 8
+                               | ((unsigned short) nic.packet[13]);
                } else continue; /* what else could we do with it? */
                /* Verify an IP header */
                ip = 0;
-               if ((ptype == ETH_P_IP) && (nic->packetlen >= ETH_HLEN + sizeof(struct iphdr))) {
+               if ((ptype == ETH_P_IP) && (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr))) {
                        unsigned ipoptlen;
-                       ip = (struct iphdr *)&nic->packet[ETH_HLEN];
+                       ip = (struct iphdr *)&nic.packet[ETH_HLEN];
                        if ((ip->verhdrlen < 0x45) || (ip->verhdrlen > 0x4F)) 
                                continue;
                        iplen = (ip->verhdrlen & 0xf) * 4;
@@ -1493,17 +1470,17 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
                                /* Delete the ip options, to guarantee
                                 * good alignment, and make etherboot simpler.
                                 */
-                               memmove(&nic->packet[ETH_HLEN + sizeof(struct iphdr)], 
-                                       &nic->packet[ETH_HLEN + iplen],
-                                       nic->packetlen - ipoptlen);
-                               nic->packetlen -= ipoptlen;
+                               memmove(&nic.packet[ETH_HLEN + sizeof(struct iphdr)], 
+                                       &nic.packet[ETH_HLEN + iplen],
+                                       nic.packetlen - ipoptlen);
+                               nic.packetlen -= ipoptlen;
                        }
                }
                udp = 0;
                if (ip && (ip->protocol == IP_UDP) && 
-                       (nic->packetlen >= 
+                       (nic.packetlen >= 
                        ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr))) {
-                       udp = (struct udphdr *)&nic->packet[ETH_HLEN + sizeof(struct iphdr)];
+                       udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)];
 
                        /* Make certain we have a reasonable packet length */
                        if (ntohs(udp->len) > (ntohs(ip->len) - iplen))
@@ -1517,9 +1494,9 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
                tcp = 0;
 #ifdef DOWNLOAD_PROTO_HTTP
                if (ip && (ip->protocol == IP_TCP) &&
-                   (nic->packetlen >=
+                   (nic.packetlen >=
                     ETH_HLEN + sizeof(struct iphdr) + sizeof(struct tcphdr))){
-                       tcp = (struct tcphdr *)&nic->packet[ETH_HLEN +
+                       tcp = (struct tcphdr *)&nic.packet[ETH_HLEN +
                                                         sizeof(struct iphdr)];
                        /* Make certain we have a reasonable packet length */
                        if (((ntohs(tcp->ctrl) >> 10) & 0x3C) >
@@ -1541,11 +1518,11 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
                 * action.  This allows us reply to arp, igmp, and lacp queries.
                 */
                if ((ptype == ETH_P_ARP) &&
-                       (nic->packetlen >= ETH_HLEN + sizeof(struct arprequest))) {
+                       (nic.packetlen >= ETH_HLEN + sizeof(struct arprequest))) {
                        struct  arprequest *arpreply;
                        unsigned long tmp;
                
-                       arpreply = (struct arprequest *)&nic->packet[ETH_HLEN];
+                       arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
                        memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
                        if ((arpreply->opcode == htons(ARP_REQUEST)) &&
                                (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
index f1f7c5e..3fb173b 100644 (file)
@@ -169,7 +169,7 @@ int pxe_shutdown_nic ( void ) {
        if ( pxe_stack->state <= MIDWAY ) return 1;
 
        eth_irq ( DISABLE );
-       eth_disable();
+       disable ( &dev );
        pxe_stack->state = MIDWAY;
        return 1;
 }
@@ -433,7 +433,7 @@ PXENV_EXIT_t pxenv_undi_set_station_address ( t_PXENV_UNDI_SET_STATION_ADDRESS
         * the current value anyway then return success, otherwise
         * return UNSUPPORTED.
         */
-       if ( memcmp ( nic->node_addr,
+       if ( memcmp ( nic.node_addr,
                      &undi_set_station_address->StationAddress,
                      ETH_ALEN ) == 0 ) {
                undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
@@ -465,8 +465,8 @@ PXENV_EXIT_t pxenv_undi_get_information ( t_PXENV_UNDI_GET_INFORMATION
        DBG ( "PXENV_UNDI_GET_INFORMATION" );
        ENSURE_READY ( undi_get_information );
 
-       undi_get_information->BaseIo = nic->ioaddr;
-       undi_get_information->IntNumber = nic->irqno;
+       undi_get_information->BaseIo = nic.ioaddr;
+       undi_get_information->IntNumber = nic.irqno;
        /* Cheat: assume all cards can cope with this */
        undi_get_information->MaxTranUnit = ETH_MAX_MTU;
        /* Cheat: we only ever have Ethernet cards */
@@ -476,12 +476,12 @@ PXENV_EXIT_t pxenv_undi_get_information ( t_PXENV_UNDI_GET_INFORMATION
         * node address.  This is a valid assumption within Etherboot
         * at the time of writing.
         */
-       memcpy ( &undi_get_information->CurrentNodeAddress, nic->node_addr,
+       memcpy ( &undi_get_information->CurrentNodeAddress, nic.node_addr,
                 ETH_ALEN );
-       memcpy ( &undi_get_information->PermNodeAddress, nic->node_addr,
+       memcpy ( &undi_get_information->PermNodeAddress, nic.node_addr,
                 ETH_ALEN );
        undi_get_information->ROMAddress = 0;
-               /* nic->rom_info->rom_segment; */
+               /* nic.rom_info->rom_segment; */
        /* We only provide the ability to receive or transmit a single
         * packet at a time.  This is a bootloader, not an OS.
         */
@@ -637,7 +637,7 @@ PXENV_EXIT_t pxenv_undi_get_iface_info ( t_PXENV_UNDI_GET_IFACE_INFO
  * Status: working
  */
 PXENV_EXIT_t pxenv_undi_isr ( t_PXENV_UNDI_ISR *undi_isr ) {
-       media_header_t *media_header = (media_header_t*)nic->packet;
+       media_header_t *media_header = (media_header_t*)nic.packet;
 
        DBG ( "PXENV_UNDI_ISR" );
        /* We can't call ENSURE_READY, because this could be being
@@ -683,8 +683,8 @@ PXENV_EXIT_t pxenv_undi_isr ( t_PXENV_UNDI_ISR *undi_isr ) {
                 */
                DBG ( " PROCESS" );
                if ( eth_poll ( 1 ) ) {
-                       DBG ( " RECEIVE %d", nic->packetlen );
-                       if ( nic->packetlen > sizeof(pxe_stack->packet) ) {
+                       DBG ( " RECEIVE %d", nic.packetlen );
+                       if ( nic.packetlen > sizeof(pxe_stack->packet) ) {
                                /* Should never happen */
                                undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
                                undi_isr->Status =
@@ -692,10 +692,10 @@ PXENV_EXIT_t pxenv_undi_isr ( t_PXENV_UNDI_ISR *undi_isr ) {
                                return PXENV_EXIT_FAILURE;
                        }
                        undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
-                       undi_isr->BufferLength = nic->packetlen;
-                       undi_isr->FrameLength = nic->packetlen;
+                       undi_isr->BufferLength = nic.packetlen;
+                       undi_isr->FrameLength = nic.packetlen;
                        undi_isr->FrameHeaderLength = ETH_HLEN;
-                       memcpy ( pxe_stack->packet, nic->packet, nic->packetlen);
+                       memcpy ( pxe_stack->packet, nic.packet, nic.packetlen);
                        PTR_TO_SEGOFF16 ( pxe_stack->packet, undi_isr->Frame );
                        switch ( ntohs(media_header->nstype) ) {
                        case IP :       undi_isr->ProtType = P_IP;      break;
@@ -1026,7 +1026,7 @@ PXENV_EXIT_t pxenv_udp_read ( t_PXENV_UDP_READ *udp_read ) {
 PXENV_EXIT_t pxenv_udp_write ( t_PXENV_UDP_WRITE *udp_write ) {
        uint16_t src_port;
        uint16_t dst_port;
-       struct udppacket *packet = (struct udppacket *)nic->packet;
+       struct udppacket *packet = (struct udppacket *)nic.packet;
        int packet_size;
 
        DBG ( "PXENV_UDP_WRITE" );
index e109d03..3cbe67e 100644 (file)
@@ -1,30 +1,49 @@
 #include "stdint.h"
 #include "string.h"
 #include "console.h"
+#include "nic.h"
 #include "pci.h"
 
 /*
- * Ensure that there is sufficient space in the shared dev_bus
- * structure for a struct pci_device.
+ * pci_io.c may know how many buses we have, in which case it can
+ * overwrite this value.
  *
  */
-DEV_BUS( struct pci_device, pci_dev );
-static char pci_magic[0]; /* guaranteed unique symbol */
+unsigned int pci_max_bus = 0xff;
 
 /*
- * pci_io.c may know how many buses we have, in which case it can
- * overwrite this value.
+ * Increment a bus_loc structure to the next possible PCI location.
+ * Leave the structure zeroed and return 0 if there are no more valid
+ * locations.
  *
  */
-unsigned int pci_max_bus = 0xff;
+static int pci_next_location ( struct bus_loc *bus_loc ) {
+       struct pci_loc *pci_loc = ( struct pci_loc * ) bus_loc;
+       
+       /*
+        * Ensure that there is sufficient space in the shared bus
+        * structures for a struct pci_loc and a struct
+        * pci_dev, as mandated by bus.h.
+        *
+        */
+       BUS_LOC_CHECK ( struct pci_loc );
+       BUS_DEV_CHECK ( struct pci_device );
+
+       return ( ++pci_loc->busdevfn );
+}
 
 /*
  * Fill in parameters (vendor & device ids, class, membase etc.) for a
  * PCI device based on bus & devfn.
  *
  * Returns 1 if a device was found, 0 for no device present.
+ *
  */
-static int fill_pci_device ( struct pci_device *pci ) {
+static int pci_fill_device ( struct bus_dev *bus_dev,
+                            struct bus_loc *bus_loc ) {
+       struct pci_loc *pci_loc = ( struct pci_loc * ) bus_loc;
+       struct pci_device *pci = ( struct pci_device * ) bus_dev;
+       uint16_t busdevfn = pci_loc->busdevfn;
        static struct {
                uint16_t devfn0;
                int is_present;
@@ -32,8 +51,12 @@ static int fill_pci_device ( struct pci_device *pci ) {
        uint32_t l;
        int reg;
 
+       /* Store busdevfn in struct pci_device and set default values */
+       pci->busdevfn = busdevfn;
+       pci->name = "?";
+
        /* Check bus is within range */
-       if ( PCI_BUS ( pci->busdevfn ) > pci_max_bus ) {
+       if ( PCI_BUS ( busdevfn ) > pci_max_bus ) {
                return 0;
        }
 
@@ -41,8 +64,8 @@ static int fill_pci_device ( struct pci_device *pci ) {
         * non-zero function on a non-existent card.  This is done to
         * increase scan speed by a factor of 8.
         */
-       if ( ( PCI_FUNC ( pci->busdevfn ) != 0 ) &&
-            ( PCI_FN0 ( pci->busdevfn ) == cache.devfn0 ) &&
+       if ( ( PCI_FUNC ( busdevfn ) != 0 ) &&
+            ( PCI_FN0 ( busdevfn ) == cache.devfn0 ) &&
             ( ! cache.is_present ) ) {
                return 0;
        }
@@ -52,28 +75,27 @@ static int fill_pci_device ( struct pci_device *pci ) {
        pci_read_config_dword ( pci, PCI_VENDOR_ID, &l );
        /* some broken boards return 0 if a slot is empty: */
        if ( ( l == 0xffffffff ) || ( l == 0x00000000 ) ) {
-               if ( PCI_FUNC ( pci->busdevfn ) == 0 ) {
+               if ( PCI_FUNC ( busdevfn ) == 0 ) {
                        /* Don't look for subsequent functions if the
                         * card itself is not present.
                         */
-                       cache.devfn0 = pci->busdevfn;
+                       cache.devfn0 = busdevfn;
                        cache.is_present = 0;
                }
                return 0;
        }
-       pci->vendor = l & 0xffff;
-       pci->dev_id = ( l >> 16 ) & 0xffff;
+       pci->vendor_id = l & 0xffff;
+       pci->device_id = ( l >> 16 ) & 0xffff;
        
        /* Check that we're not a duplicate function on a
         * non-multifunction device.
         */
-       if ( PCI_FUNC ( pci->busdevfn ) != 0 ) {
-               uint16_t save_busdevfn = pci->busdevfn;
+       if ( PCI_FUNC ( busdevfn ) != 0 ) {
                uint8_t header_type;
 
-               pci->busdevfn &= PCI_FN0 ( pci->busdevfn );
+               pci->busdevfn &= PCI_FN0 ( busdevfn );
                pci_read_config_byte ( pci, PCI_HEADER_TYPE, &header_type );
-               pci->busdevfn = save_busdevfn;
+               pci->busdevfn = busdevfn;
 
                if ( ! ( header_type & 0x80 ) ) {
                        return 0;
@@ -108,14 +130,87 @@ static int fill_pci_device ( struct pci_device *pci ) {
                pci_read_config_byte ( pci, PCI_INTERRUPT_LINE, &pci->irq );
        }
 
-       DBG ( "PCI found device %hhx:%hhx.%d Class %hx: %hx:%hx (rev %hhx)\n",
+       DBG ( "found device %hhx:%hhx.%d Class %hx: %hx:%hx (rev %hhx)\n",
              PCI_BUS ( pci->busdevfn ), PCI_DEV ( pci->busdevfn ),
-             PCI_FUNC ( pci->busdevfn ), pci->class, pci->vendor, pci->dev_id,
-             pci->revision );
+             PCI_FUNC ( pci->busdevfn ), pci->class, pci->vendor_id,
+             pci->device_id, pci->revision );
 
        return 1;
 }
 
+/*
+ * Test whether or not a driver is capable of driving the device.
+ *
+ */
+static int pci_check_driver ( struct bus_dev *bus_dev,
+                      struct device_driver *device_driver ) {
+       struct pci_device *pci = ( struct pci_device * ) bus_dev;
+       struct pci_driver_info *pci_driver_info
+               = ( struct pci_driver_info * ) device_driver->bus_driver_info;
+       unsigned int i;
+
+       /* If driver has a class, and class matches, use it */
+       if ( pci_driver_info->class && 
+            ( pci_driver_info->class == pci->class ) ) {
+               DBG ( "driver %s matches class %hx\n",
+                     device_driver->name, pci_driver_info->class );
+               pci->name = device_driver->name;
+               return 1;
+       }
+               
+       /* If any of driver's IDs match, use it */
+       for ( i = 0 ; i < pci_driver_info->id_count; i++ ) {
+               struct pci_id *id = &pci_driver_info->ids[i];
+               
+               if ( ( pci->vendor_id == id->vendor_id ) &&
+                    ( pci->device_id == id->device_id ) ) {
+                       DBG ( "driver %s device %s matches ID %hx:%hx\n",
+                             device_driver->name, id->name,
+                             id->vendor_id, id->device_id );
+                       pci->name = id->name;
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Describe a PCI device
+ *
+ */
+static char * pci_describe ( struct bus_dev *bus_dev ) {
+       struct pci_device *pci = ( struct pci_device * ) bus_dev;
+       static char pci_description[] = "PCI 00:00.0";
+
+       sprintf ( pci_description + 4, "%hhx:%hhx.%d",
+                 PCI_BUS ( pci->busdevfn ), PCI_DEV ( pci->busdevfn ),
+                 PCI_FUNC ( pci->busdevfn ) );
+       return pci_description;
+}
+
+/*
+ * Name a PCI device
+ *
+ */
+static char * pci_name ( struct bus_dev *bus_dev ) {
+       struct pci_device *pci = ( struct pci_device * ) bus_dev;
+       
+       return pci->name;
+}
+
+/*
+ * PCI bus operations table
+ *
+ */
+struct bus_driver pci_driver __bus_driver = {
+       .next_location  = pci_next_location,
+       .fill_device    = pci_fill_device,
+       .check_driver   = pci_check_driver,
+       .describe       = pci_describe,
+       .name           = pci_name,
+};
+
 /*
  * Set device to be a busmaster in case BIOS neglected to do so.  Also
  * adjust PCI latency timer to a reasonable value, 32.
@@ -127,7 +222,7 @@ void adjust_pci_device ( struct pci_device *pci ) {
        pci_read_config_word ( pci, PCI_COMMAND, &pci_command );
        new_command = pci_command | PCI_COMMAND_MASTER | PCI_COMMAND_IO;
        if ( pci_command != new_command ) {
-               DBG ( "PCI BIOS has not enabled device %hhx:%hhx.%d! "
+               DBG ( "BIOS has not enabled device %hhx:%hhx.%d! "
                      "Updating PCI command %hX->%hX\n",
                      PCI_BUS ( pci->busdevfn ), PCI_DEV ( pci->busdevfn ),
                      PCI_FUNC ( pci->busdevfn ), pci_command, new_command );
@@ -135,7 +230,7 @@ void adjust_pci_device ( struct pci_device *pci ) {
        }
        pci_read_config_byte ( pci, PCI_LATENCY_TIMER, &pci_latency);
        if ( pci_latency < 32 ) {
-               DBG ( "PCI device %hhx:%hhx.%d latency timer is "
+               DBG ( "device %hhx:%hhx.%d latency timer is "
                      "unreasonably low at %d. Setting to 32.\n",
                      PCI_BUS ( pci->busdevfn ), PCI_DEV ( pci->busdevfn ),
                      PCI_FUNC ( pci->busdevfn ), pci_latency );
@@ -143,100 +238,6 @@ void adjust_pci_device ( struct pci_device *pci ) {
        }
 }
 
-/*
- * Set PCI device to use.
- *
- * This routine can be called by e.g. the ROM prefix to specify that
- * the first device to be tried should be the device on which the ROM
- * was physically located.
- *
- */
-void set_pci_device ( uint16_t busdevfn ) {
-       pci_dev.magic = pci_magic;
-       pci_dev.busdevfn = busdevfn;
-       pci_dev.already_tried = 0;
-}
-
-/*
- * Find a PCI device matching the specified driver
- *
- */
-int find_pci_device ( struct pci_device *pci,
-                     struct pci_driver *driver ) {
-       int i;
-
-       /* Initialise struct pci if it's the first time it's been used. */
-       if ( pci->magic != pci_magic ) {
-               memset ( pci, 0, sizeof ( *pci ) );
-               pci->magic = pci_magic;
-       }
-
-       /* Iterate through all possible PCI bus:dev.fn combinations,
-        * starting where we left off.
-        */
-       DBG ( "PCI searching for device matching driver %s\n", driver->name );
-       do {
-               /* If we've already used this device, skip it */
-               if ( pci->already_tried ) {
-                       pci->already_tried = 0;
-                       continue;
-               }
-               
-               /* Fill in device parameters, if device present */
-               if ( ! fill_pci_device ( pci ) ) {
-                       continue;
-               }
-               
-               /* If driver has a class, and class matches, use it */
-               if ( driver->class && 
-                    ( driver->class == pci->class ) ) {
-                       DBG ( "PCI found class %hx matching driver %s\n",
-                             driver->class, driver->name );
-                       pci->name = driver->name;
-                       pci->already_tried = 1;
-                       return 1;
-               }
-               
-               /* If any of driver's IDs match, use it */
-               for ( i = 0 ; i < driver->id_count; i++ ) {
-                       struct pci_id *id = &driver->ids[i];
-                       
-                       if ( ( pci->vendor == id->vendor ) &&
-                            ( pci->dev_id == id->dev_id ) ) {
-                               DBG ( "PCI found ID %hx:%hx (device %s) "
-                                     "matching driver %s\n", id->vendor,
-                                     id->dev_id, id->name, driver->name );
-                               pci->name = id->name;
-                               pci->already_tried = 1;
-                               return 1;
-                       }
-               }
-       } while ( ++pci->busdevfn );
-
-       /* No device found */
-       DBG ( "PCI found no device matching driver %s\n", driver->name );
-       return 0;
-}
-
-/*
- * Find the next PCI device that can be used to boot using the
- * specified driver.
- *
- */
-int find_pci_boot_device ( struct dev *dev, struct pci_driver *driver ) {
-       struct pci_device *pci = ( struct pci_device * )dev->bus;
-
-       if ( ! find_pci_device ( pci, driver ) )
-               return 0;
-
-       dev->name = pci->name;
-       dev->devid.bus_type = PCI_BUS_TYPE;
-       dev->devid.vendor_id = pci->vendor;
-       dev->devid.device_id = pci->dev_id;
-
-       return 1;
-}
-
 /*
  * Find the start of a pci resource.
  */
@@ -346,3 +347,19 @@ int pci_find_capability ( struct pci_device *pci, int cap ) {
        }
        return 0;
 }
+
+/*
+ * Fill in a DHCP device ID structure
+ *
+ */
+void pci_fill_nic ( struct nic *nic, struct pci_device *pci ) {
+
+       /* Fill in ioaddr and irqno */
+       nic->ioaddr = pci->ioaddr;
+       nic->irqno = pci->irq;
+
+       /* Fill in DHCP device ID structure */
+       nic->dhcp_dev_id.bus_type = PCI_BUS_TYPE;
+       nic->dhcp_dev_id.vendor_id = htons ( pci->vendor_id );
+       nic->dhcp_dev_id.device_id = htons ( pci->device_id );
+}
diff --git a/src/include/bus.h b/src/include/bus.h
deleted file mode 100644 (file)
index 80faa0e..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-#ifndef BUS_H
-#define BUS_H
-
-#include "stdint.h"
-
-/*
- * When looking at the following data structures, mentally substitute
- * "<bus>_" in place of "bus_" and everything will become clear.
- * "struct bus_location" becomes "struct <bus>_location", which means
- * "the location of a device on a <bus> bus", where <bus> is a
- * particular type of bus such as "pci" or "isapnp".
- *
- */
-
-/*
- * A physical device location.
- *
- */
-#define BUS_LOCATION_SIZE 4
-struct bus_location {
-       char bytes[BUS_LOCATION_SIZE];
-};
-
-/* 
- * A structure fully describing a physical device.
- *
- */
-#define BUS_DEVICE_SIZE 32
-struct bus_device {
-       char bytes[BUS_DEVICE_SIZE];
-};
-
-/*
- * Individual buses will have different sizes for their <bus>_location
- * and <bus>_device structures.  We need to be able to allocate static
- * storage that's large enough to contain these structures for any
- * bus type that's being used in the current binary.
- *
- * We can't just create a union of all the various types, because some
- * may be architecture-dependent (and some are even embedded in
- * specific drivers, e.g. 3c509), so this would quickly get messy.
- *
- * We could use the magic of common symbols.  Each bus could declare a
- * common symbol with the name "_bus_device" of the correct size; this
- * is easily done using code like
- *     struct pci_device _bus_device;
- * The linker would then use the largest size of the "_bus_device"
- * symbol in any included object, thus giving us a single _bus_device
- * symbol of *exactly* the required size.  However, there's no way to
- * extract the size of this symbol, either directly as a linker symbol
- * ("_bus_device_size = SIZEOF(_bus_device)"; the linker language just
- * doesn't provide this construct) or via any linker trickery I can
- * think of (such as creating a special common symbol section just for
- * this symbol then using SIZE(section) to read the size of the
- * section; ld recognises only a single common symbol section called
- * "COMMON").
- *
- * Since there's no way to get the size of the symbol, this
- * effectively limits us to just one instance of the symbol.  This is
- * all very well for the simple case of "just boot from any single
- * device you can", but becomes limiting when you want to do things
- * like introducing PCMCIA buses (which must instantiate other devices
- * such as PCMCIA controllers).
- *
- * So, we declare the maximum sizes of these constructions to be
- * compile-time constants.  Each individual bus driver should define
- * its own struct <bus>_location and struct <bus>_device however it
- * likes, and can freely cast pointers from struct bus_location to
- * struct <bus>_location (and similarly for bus_device).  To guard
- * against bounding errors, each bus driver *MUST* use the macros
- * BUS_LOCATION_CHECK() and BUS_DEVICE_CHECK(), as in:
- *
- *   BUS_LOCATION_CHECK ( struct pci_location );
- *   BUS_DEVICE_CHECK ( struct pci_device );
- *
- * These macros will generate a link-time error if the size of the
- * <bus> structure exceeds the declared maximum size.
- *
- * The macros will generate no binary object code, but must be placed
- * inside a function (in order to generate syntactically valid C).
- * The easiest wy to do this is to place them in the
- * <bus>_next_location() function.
- *
- * If anyone can think of a better way of doing this that avoids *ALL*
- * of the problems described above, please implement it!
- *
- */
-
-#define LINKER_ASSERT(test,error_symbol)               \
-       if ( ! (test) ) {                               \
-               extern void error_symbol ( void );      \
-               error_symbol();                         \
-       }
-
-#define BUS_LOCATION_CHECK(datatype) \
-       LINKER_ASSERT( ( sizeof (datatype) < sizeof (struct bus_location) ),
-                      __BUS_LOCATION_SIZE_is_too_small__see_dev_h )
-#define BUS_DEVICE_CHECK(datatype) \
-       LINKER_ASSERT( ( sizeof (datatype) < sizeof (struct bus_device) ),
-                      __BUS_DEVICE_SIZE_is_too_small__see_dev_h )
-
-/*
- * A description of a device.  This is used to send information about
- * the device to a DHCP server, and to provide a text string to
- * describe the device to the user.
- *
- * Note that "text" is allowed to be NULL, in which case the
- * describe_device() method will print the information directly to the
- * console rather than writing it into a buffer.  (This happens
- * transparently because sprintf(NULL,...) is exactly equivalent to
- * printf(...) in our vsprintf.c).
- *
- */
-struct bus_description {
-       char *text;
-       uint16_t        vendor_id;
-       uint16_t        device_id;
-       uint8_t         bus_type;
-};
-
-/*
- * A driver definition
- *
- */
-struct bus_driver;
-
-/*
- * Bus-level operations.
- *
- * int next_location ( struct bus_location * bus_location )
- *
- *     Increment bus_location to point to the next possible device on
- *     the bus (e.g. the next PCI busdevfn, or the next ISAPnP CSN).
- *     If there are no more valid locations, return 0 and leave
- *     struct bus_location zeroed, otherwise return true.
- *
- * int fill_device ( struct bus_location *bus_location,
- *                  struct bus_device *bus_device )
- *
- *     Fill out a bus_device structure with the parameters for the
- *     device at bus_location.  (For example, fill in the PCI vendor
- *     and device IDs).  Return true if there is a device physically
- *     present at this location, otherwise 0.
- *
- * int check_driver ( )
- *
- */
-struct bus_operations {
-       int ( *next_location ) ( struct bus_location * bus_location );
-       int ( *fill_device ) ( struct bus_location * bus_location,
-                              struct bus_device * bus_device );
-       int ( *check_driver ) ( struct bus_device * bus_device,
-                               struct bus_driver * bus_driver );
-       void ( *describe_device ) ( struct bus_device * bus_device,
-                                   struct bus_driver * bus_driver,
-                                   struct bus_description * bus_description );
-};
-
-
-
-#endif /* BUS_H */
index 555712a..327a271 100644 (file)
 #define DEV_H
 
 #include "stdint.h"
+#include "string.h"
+#include "dhcp.h" /* for dhcp_dev_id */
 
-/* Device types */
-#include "nic.h"
+/*
+ * Forward declarations
+ *
+ */
+struct type_dev;
+struct type_driver;
+struct bus_driver;
+struct bus_dev;
+struct device_driver;
 
-/* Need to check the packing of this struct if Etherboot is ported */
-struct dev_id {
-       uint16_t        vendor_id;
-       uint16_t        device_id;
-       uint8_t         bus_type;
-#define        PCI_BUS_TYPE    1
-#define        ISA_BUS_TYPE    2
-#define MCA_BUS_TYPE   3
-} __attribute__ ((packed));
+/*
+ * When looking at the following data structures, mentally substitute
+ * "<bus>_" in place of "bus_" and everything will become clear.
+ * "struct bus_location" becomes "struct <bus>_location", which means
+ * "the location of a device on a <bus> bus", where <bus> is a
+ * particular type of bus such as "pci" or "isapnp".
+ *
+ */
 
-/* Dont use sizeof, that will include the padding */
-#define        DEV_ID_SIZE     8
+/*
+ * A physical device location on a bus.
+ *
+ */
+#define BUS_LOC_SIZE 4
+struct bus_loc {
+       char bytes[BUS_LOC_SIZE];
+};
 
-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 <bus>_device.
-        */
-       struct bus_device *bus;
-       /* All possible device types */
-       union {
-               struct nic      nic;
-       };
+/* 
+ * A structure fully describing a physical device on a bus.
+ *
+ */
+#define BUS_DEV_SIZE 32
+struct bus_dev {
+       char bytes[BUS_DEV_SIZE];
 };
 
 /*
- * Macro to help create a common symbol with enough space for any
- * struct <bus>_device.
+ * Individual buses will have different sizes for their <bus>_location
+ * and <bus>_device structures.  We need to be able to allocate static
+ * storage that's large enough to contain these structures for any
+ * bus type that's being used in the current binary.
+ *
+ * We can't just create a union of all the various types, because some
+ * may be architecture-dependent (and some are even embedded in
+ * specific drivers, e.g. 3c509), so this would quickly get messy.
+ *
+ * We could use the magic of common symbols.  Each bus could declare a
+ * common symbol with the name "_bus_dev" of the correct size; this
+ * is easily done using code like
+ *     struct pci_device _bus_dev;
+ * The linker would then use the largest size of the "_bus_dev" symbol
+ * in any included object, thus giving us a single _bus_dev symbol of
+ * *exactly* the required size.  However, there's no way to extract
+ * the size of this symbol, either directly as a linker symbol
+ * ("_bus_dev_size = SIZEOF(_bus_dev)"; the linker language just
+ * doesn't provide this construct) or via any linker trickery I can
+ * think of (such as creating a special common symbol section just for
+ * this symbol then using SIZE(section) to read the size of the
+ * section; ld recognises only a single common symbol section called
+ * "COMMON").
+ *
+ * Since there's no way to get the size of the symbol, this
+ * effectively limits us to just one instance of the symbol.  This is
+ * all very well for the simple case of "just boot from any single
+ * device you can", but becomes limiting when you want to do things
+ * like introducing PCMCIA buses (which must instantiate other devices
+ * such as PCMCIA controllers).
+ *
+ * So, we declare the maximum sizes of these constructions to be
+ * compile-time constants.  Each individual bus driver should define
+ * its own struct <bus>_location and struct <bus>_device however it
+ * likes, and can freely cast pointers from struct bus_loc to
+ * struct <bus>_location (and similarly for bus_dev).  To guard
+ * against bounding errors, each bus driver *MUST* use the macros
+ * BUS_LOC_CHECK() and BUS_DEV_CHECK(), as in:
+ *
+ *   BUS_LOC_CHECK ( struct pci_location );
+ *   BUS_DEV_CHECK ( struct pci_device );
+ *
+ * These macros will generate a link-time error if the size of the
+ * <bus> structure exceeds the declared maximum size.
+ *
+ * The macros will generate no binary object code, but must be placed
+ * inside a function (in order to generate syntactically valid C).
+ * The easiest wy to do this is to place them in the
+ * <bus>_next_location() function.
+ *
+ * If anyone can think of a better way of doing this that avoids *ALL*
+ * of the problems described above, please implement it!
  *
- * Use as e.g. DEV_BUS(struct pci_device);
  */
-#define DEV_BUS(datatype,symbol) datatype symbol __asm__ ( "_dev_bus" );
 
-struct dev_operations {
-       void ( *disable ) ( struct dev * );
-       void ( *print_info ) ( struct dev * );
-       int ( *load_configuration ) ( struct dev * );
-       int ( *load ) ( struct dev * );
+#define LINKER_ASSERT(test,error_symbol)               \
+       if ( ! (test) ) {                               \
+               extern void error_symbol ( void );      \
+               error_symbol();                         \
+       }
+
+#define BUS_LOC_CHECK(datatype)                                              \
+       LINKER_ASSERT( ( sizeof (datatype) < sizeof (struct bus_loc) ),  \
+                      __BUS_LOC_SIZE_is_too_small__see_dev_h )
+#define BUS_DEV_CHECK(datatype)                                              \
+       LINKER_ASSERT( ( sizeof (datatype) < sizeof (struct bus_dev) ),    \
+                      __BUS_DEV_SIZE_is_too_small__see_dev_h )
+
+/*
+ * Bus-level operations.
+ *
+ * int next_location ( struct bus_loc * bus_loc )
+ *
+ *     Increment bus_loc to point to the next possible device on
+ *     the bus (e.g. the next PCI busdevfn, or the next ISAPnP CSN).
+ *     If there are no more valid locations, return 0 and leave
+ *     struct bus_loc zeroed, otherwise return true.
+ *
+ * int fill_device ( struct bus_dev *bus_dev,
+ *                  struct bus_loc *bus_loc )
+ *
+ *     Fill out a bus_dev structure with the parameters for the
+ *     device at bus_loc.  (For example, fill in the PCI vendor
+ *     and device IDs).  Return true if there is a device physically
+ *     present at this location, otherwise 0.
+ *
+ * int check_driver ( struct bus_dev *bus_dev,
+ *                   struct device_driver *device_driver )
+ *
+ *     Test whether or not the specified driver is capable of driving
+ *     the specified device by, for example, comparing the device's
+ *     PCI IDs against the list of PCI IDs claimed by the driver.
+ *
+ * char * describe ( struct bus_dev *bus_dev )
+ *
+ *     Return a text string describing the bus device bus_dev
+ *     (e.g. "PCI 00:01.2")
+ *
+ * char * name ( struct bus_dev *bus_dev )
+ *
+ *     Return a text string describing the bus device bus_dev
+ *     (e.g. "dfe538")
+ *
+ */
+struct bus_driver {
+       int ( *next_location ) ( struct bus_loc *bus_loc );
+       int ( *fill_device ) ( struct bus_dev *bus_dev,
+                              struct bus_loc *bus_loc );
+       int ( *check_driver ) ( struct bus_dev *bus_dev,
+                               struct device_driver *device_driver );
+       char * ( *describe ) ( struct bus_dev *bus_dev );
+       char * ( *name ) ( struct bus_dev *bus_dev );
 };
 
+#define __bus_driver __attribute__ (( used, __section__ ( ".drivers.bus" ) ))
+
 /*
- * Table to describe a bootable device driver.  See comments in dev.c
- * for an explanation.
+ * A structure fully describing the bus-independent parts of a
+ * particular type (e.g. nic or disk) of device.
+ *
+ * Unlike struct bus_dev, e can limit ourselves to having no more than
+ * one instance of this data structure.  We therefore place an
+ * instance in each type driver file (e.g. nic.c), and simply use a
+ * pointer to the struct type_dev in the struct dev.
  *
  */
-struct bus_device {};
-struct bus_driver {};
-struct boot_driver {
+struct type_dev;
+
+/*
+ * A type driver (e.g. nic, disk)
+ *
+ */
+struct type_driver {
        char *name;
-       struct bus_device * ( *find_bus_boot_device ) ( struct dev *dev,
-                                                  struct bus_driver *driver );
+       struct type_dev *type_dev; /* single instance */
+       char * ( * describe ) ( struct type_dev *type_dev );
+};
+
+#define __type_driver __attribute__ (( used, __section__ ( ".drivers.type" ) ))
+
+/*
+ * A driver for a device.
+ *
+ */
+struct device_driver {
+       const char *name;
+       struct type_driver *type_driver;
        struct bus_driver *bus_driver;
-       int ( *probe ) ( struct dev *dev, struct bus_device *bus_device );
+       struct bus_driver_info *bus_driver_info;
+       int ( * probe ) ( struct type_dev *type_dev,
+                         struct bus_dev *bus_dev );
+       void ( * disable ) ( struct type_dev *type_dev,
+                            struct bus_dev *bus_dev );
 };
 
-#define BOOT_DRIVER( _name, _find_bus_boot_device, _bus_driver,        _probe )      \
-       static struct boot_driver boot_ ## _bus_driver                        \
-           __attribute__ ((used,__section__(".boot_drivers"))) = {           \
-               .name = _name,                                                \
-               .find_bus_boot_device = ( void * ) _find_bus_boot_device,     \
-               .bus_driver = ( void * ) &_bus_driver,                        \
-               .probe = ( void * ) _probe,                                   \
+#define __device_driver \
+       __attribute__ (( used, __section__ ( ".drivers.device" ) ))
+
+#define DRIVER(_name,_name_string,_type_driver,_bus_driver,_bus_info,        \
+              _probe,_disable)                                               \
+       static struct device_driver _name __device_driver = {                 \
+               .name = _name_string,                                         \
+               .type_driver = &_type_driver,                                 \
+               .bus_driver = &_bus_driver,                                   \
+               .bus_driver_info = ( struct bus_driver_info * ) &_bus_info,   \
+               .probe = ( int (*) () ) _probe,                               \
+               .disable = ( void (*) () ) _disable,                          \
        };
 
-/* Functions in dev.c */
+/*
+ * A bootable device, comprising a physical device on a bus, a driver
+ * for that device, and a type device
+ *
+ */
+struct dev {
+       struct bus_driver       *bus_driver;
+       struct bus_loc          bus_loc;
+       struct bus_dev          bus_dev;
+       struct device_driver    *device_driver;
+       struct type_driver      *type_driver;
+       struct type_dev         *type_dev;
+};
+
+/* The current boot device */
+extern struct dev dev;
+
+/*
+ * 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 ) {
-       dev->dev_op->print_info ( dev );
+extern int find_any ( struct bus_driver **bus_driver, struct bus_loc *bus_loc,
+                     struct bus_dev *bus_dev, signed int skip );
+extern int find_by_device ( struct device_driver **device_driver,
+                           struct bus_driver *bus_driver,
+                           struct bus_dev *bus_dev,
+                           signed int skip );
+extern int find_by_driver ( struct bus_loc *bus_loc, struct bus_dev *bus_dev,
+                           struct device_driver *device_driver,
+                           signed int skip );
+extern int find_any_with_driver ( struct dev *dev, signed int skip );
+
+/*
+ * Functions inlined to save space
+ *
+ */
+
+/* Probe a device */
+static inline int probe ( struct dev *dev ) {
+       return dev->device_driver->probe ( dev->type_dev, &dev->bus_dev );
 }
-static inline int load_configuration ( struct dev *dev ) {
-       return dev->dev_op->load_configuration ( dev );
+/* Disable a device */
+static inline void disable ( struct dev *dev ) {
+       dev->device_driver->disable ( dev->type_dev, &dev->bus_dev );
 }
-static inline int load ( struct dev *dev ) {
-       return dev->dev_op->load ( dev );
+/* Set the default boot device */
+static inline void select_device ( struct dev *dev,
+                                  struct bus_driver *bus_driver,
+                                  struct bus_loc *bus_loc ) {
+       dev->bus_driver = bus_driver;
+       memcpy ( &dev->bus_loc, bus_loc, sizeof ( dev->bus_loc ) );
 }
 
+/* Linker symbols for the various tables */
+extern struct bus_driver bus_drivers[];
+extern struct bus_driver bus_drivers_end[];
+extern struct type_driver type_drivers[];
+extern struct type_driver type_drivers_end[];
+extern struct device_driver device_drivers[];
+extern struct device_driver device_drivers_end[];
+
 #endif /* DEV_H */
diff --git a/src/include/dhcp.h b/src/include/dhcp.h
new file mode 100644 (file)
index 0000000..deba219
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef DHCP_H
+#define DHCP_H
+
+#include "stdint.h"
+
+struct dhcp_dev_id {
+       uint8_t         bus_type;
+       uint16_t        vendor_id;
+       uint16_t        device_id;
+} __attribute__ (( packed ));
+
+#endif /* DHCP_H */
index f21a093..7d77f0d 100644 (file)
@@ -19,6 +19,8 @@
 
 #include "stdint.h"
 
+#define        ISA_BUS_TYPE    2
+
 /*
  * Construct a vendor ID from three ASCII characters
  *
index e5daf71..3b4de21 100644 (file)
@@ -11,6 +11,8 @@
 #include "isa_ids.h"
 #include "dev.h"
 
+#define MCA_BUS_TYPE   3
+
 /*
  * MCA constants
  *
index 02fcafc..7b12c5b 100644 (file)
@@ -8,6 +8,10 @@
 #ifndef        NIC_H
 #define NIC_H
 
+#include "dev.h"
+#include "byteswap.h"
+#include "dhcp.h"
+
 typedef enum {
        DISABLE = 0,
        ENABLE,
@@ -24,16 +28,17 @@ typedef enum duplex {
  *     functions.
  */
 struct nic {
-       struct nic_operations *nic_op;
-       int             flags;  /* driver specific flags */
-       unsigned char   *node_addr;
-       unsigned char   *packet;
-       unsigned int    packetlen;
-       unsigned int    ioaddr;
-       unsigned char   irqno;
-       unsigned int    mbps;
-       duplex_t        duplex;
-       void            *priv_data;     /* driver can hang private data here */
+       struct nic_operations   *nic_op;
+       int                     flags;  /* driver specific flags */
+       unsigned char           *node_addr;
+       unsigned char           *packet;
+       unsigned int            packetlen;
+       unsigned int            ioaddr;
+       unsigned char           irqno;
+       unsigned int            mbps;
+       duplex_t                duplex;
+       struct dhcp_dev_id      dhcp_dev_id;
+       void                    *priv_data;     /* driver private data */
 };
 
 struct nic_operations {
@@ -42,52 +47,43 @@ struct nic_operations {
        void ( *transmit ) ( struct nic *, const char *,
                             unsigned int, unsigned int, const char * );
        void ( *irq ) ( struct nic *, irq_action_t );
-       void ( *disable ) ( struct nic * );
 };
 
+extern struct type_driver nic_driver;
+
 /*
  * Function prototypes
  *
  */
-struct dev;
-extern struct nic * nic_device ( struct dev * dev );
 extern int dummy_connect ( struct nic *nic );
 extern void dummy_irq ( struct nic *nic, irq_action_t irq_action );
+extern void nic_disable ( struct nic *nic );
 
 /*
  * Functions that implicitly operate on the current boot device
  *
- * "nic" always points to &dev.nic
  */
 
-extern struct nic *nic;
+extern struct nic nic;
 
 static inline int eth_connect ( void ) {
-       return nic->nic_op->connect ( nic );
+       return nic.nic_op->connect ( &nic );
 }
 
 static inline int eth_poll ( int retrieve ) {
-       return nic->nic_op->poll ( nic, retrieve );
+       return nic.nic_op->poll ( &nic, retrieve );
 }
 
 static inline void eth_transmit ( const char *dest, unsigned int type,
                                  unsigned int size, const void *packet ) {
-       nic->nic_op->transmit ( nic, dest, type, size, packet );
+       nic.nic_op->transmit ( &nic, dest, type, size, packet );
 }
 
 static inline void eth_irq ( irq_action_t action ) {
-       nic->nic_op->irq ( nic, action );
+       nic.nic_op->irq ( &nic, action );
 }
 
 /* Should be using disable() rather than eth_disable() */
-static inline void eth_disable ( void ) __attribute__ (( deprecated ));
-static inline void eth_disable ( void ) {
-       nic->nic_op->disable ( nic );
-}
-
-/* dev.h needs declarations from nic.h */
-#include "dev.h"
-/* to get global "dev" */
-#include "main.h"
+extern void eth_disable ( void ) __attribute__ (( deprecated ));
 
 #endif /* NIC_H */
index fd6ac9b..f904504 100644 (file)
  */
 
 #include "stdint.h"
+#include "nic.h"
 #include "pci_ids.h"
-#include "dev.h"
+
+#define        PCI_BUS_TYPE    1
 
 /*
  * PCI constants
 #define PCI_MSI_DATA_32                8       /* 16 bits of data for 32-bit devices */
 #define PCI_MSI_DATA_64                12      /* 16 bits of data for 64-bit devices */
 /*
- * A physical PCI device
+ * A location on a PCI bus
  *
  */
-struct pci_device {
-       char *                  magic; /* must be first */
-       const char *            name;
-       uint32_t                membase;        /* BAR 1 */
-       uint32_t                ioaddr;         /* first IO BAR */
-       uint16_t                vendor, dev_id;
-       uint16_t                class;
+struct pci_loc {
        uint16_t                busdevfn;
-       uint8_t                 revision;
-       uint8_t                 irq;
-       uint8_t                 already_tried;
 };
+
+/*
+ * A physical PCI device
+ *
+ */
+struct pci_device {
+       const char *    name;
+       uint32_t        membase;        /* BAR 1 */
+       uint32_t        ioaddr;         /* first IO BAR */
+       uint16_t        vendor_id, device_id;
+       uint16_t        class;
+       uint16_t        busdevfn;
+       uint8_t         revision;
+       uint8_t         irq;
+} __attribute__ (( packed ));
+
+/*
+ * Useful busdevfn calculations
+ *
+ */
 #define PCI_BUS(busdevfn)      ( ( uint8_t ) ( ( (busdevfn) >> 8 ) & 0xff ) )
 #define PCI_DEV(busdevfn)      ( ( uint8_t ) ( ( (busdevfn) >> 3 ) & 0x1f ) )
 #define PCI_FUNC(busdevfn)      ( ( uint8_t ) ( (busdevfn) & 0x07 ) )
 #define PCI_FN0(busdevfn)      ( ( uint16_t ) ( (busdevfn) & 0xfff8 ) )
+#define PCI_MAX_BUSDEVFN       0xffff
 
 /*
  * An individual PCI device identified by vendor and device IDs
  *
  */
 struct pci_id {
-       unsigned short vendor, dev_id;
+       unsigned short vendor_id, device_id;
        const char *name;
 };
 
@@ -268,24 +282,23 @@ struct pci_id {
  * is also parsed by parserom.pl to generate Makefile rules and files
  * for rom-o-matic.
  */
-#define PCI_ROM( rom_vendor, rom_dev_id, rom_name, rom_description ) { \
-       .vendor = rom_vendor,                                           \
-       .dev_id = rom_dev_id,                                           \
-       .name = rom_name,                                               \
+#define PCI_ROM( _vendor_id, _device_id, _name, _description ) {       \
+       .vendor_id = _vendor_id,                                        \
+       .device_id = _device_id,                                        \
+       .name = _name,                                                  \
 }
 
 /*
- * A PCI driver, with a device ID (struct pci_id) table and an
- * optional class.
+ * A PCI driver information table, with a device ID (struct pci_id)
+ * table and an optional class.
  *
  * Set the class to something other than PCI_NO_CLASS if the driver
  * can handle an entire class of devices.
  *
  */
-struct pci_driver {
-       const char *name;
+struct pci_driver_info {
        struct pci_id *ids;
-       int id_count;
+       unsigned int id_count;
        uint16_t class;
 };
 #define PCI_NO_CLASS 0
@@ -294,30 +307,30 @@ struct pci_driver {
  * Define a PCI driver.
  *
  */
-#define PCI_DRIVER( driver_name, pci_ids, pci_class ) {                        \
-       .name = driver_name,                                            \
-       .ids = pci_ids,                                                 \
-       .id_count = sizeof ( pci_ids ) / sizeof ( pci_ids[0] ),         \
-       .class = pci_class,                                             \
-}
+#define PCI_DRIVER( _info_name, _ids, _class )                         \
+       static struct pci_driver_info _info_name = {                    \
+               .ids = _ids,                                            \
+               .id_count = sizeof ( _ids ) / sizeof ( _ids[0] ),       \
+               .class = _class,                                        \
+       };
 
 /*
  * These are the functions we expect pci_io.c to provide.
  *
  */
-extern int pci_read_config_byte        ( struct pci_device *dev, unsigned int where,
+extern int pci_read_config_byte        ( struct pci_device *pci, unsigned int where,
                                  uint8_t *value );
-extern int pci_write_config_byte ( struct pci_device *dev, unsigned int where,
+extern int pci_write_config_byte ( struct pci_device *pci, unsigned int where,
                                   uint8_t value );
-extern int pci_read_config_word ( struct pci_device *dev, unsigned int where,
+extern int pci_read_config_word ( struct pci_device *pci, unsigned int where,
                                  uint16_t *value );
-extern int pci_write_config_word ( struct pci_device *dev, unsigned int where,
+extern int pci_write_config_word ( struct pci_device *pci, unsigned int where,
                                   uint16_t value );
-extern int pci_read_config_dword ( struct pci_device *dev, unsigned int where,
+extern int pci_read_config_dword ( struct pci_device *pci, unsigned int where,
                                   uint32_t *value );
-extern int pci_write_config_dword ( struct pci_device *dev, unsigned int where,
+extern int pci_write_config_dword ( struct pci_device *pci, unsigned int where,
                                    uint32_t value );
-extern unsigned long pci_bus_base ( struct pci_device *dev );
+extern unsigned long pci_bus_base ( struct pci_device *pci );
 
 /*
  * pci_io.c is allowed to overwrite pci_max_bus if it knows what the
@@ -330,13 +343,17 @@ extern unsigned int pci_max_bus;
  * Functions in pci.c
  *
  */
-extern int find_pci_device ( struct pci_device *pci,
-                            struct pci_driver *driver );
-extern int find_pci_boot_device ( struct dev *dev, struct pci_driver *driver );
 extern void adjust_pci_device ( struct pci_device *pci );
 extern unsigned long pci_bar_start ( struct pci_device *pci,
                                     unsigned int bar );
 extern unsigned long pci_bar_size ( struct pci_device *pci, unsigned int bar );
 extern int pci_find_capability ( struct pci_device *pci, int capability );
+extern void pci_fill_nic ( struct nic *nic, struct pci_device *pci );
+
+/*
+ * PCI bus global definition
+ *
+ */
+extern struct bus_driver pci_driver;
 
 #endif /* PCI_H */