mirror of https://github.com/ipxe/ipxe.git
Created a bus/device API that allows for the ROM prefix to specify an
initial device, and will also allow for e.g. a device menu to be presented to the user.pull/1/head
parent
905ca1f21d
commit
98ff29345e
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 = .;
|
||||
|
|
|
@ -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
|
||||
|
|
167
src/core/dev.c
167
src/core/dev.c
|
@ -16,51 +16,154 @@
|
|||
* 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 );
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* No more boot devices found */
|
||||
boot_driver = boot_drivers;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Probe the boot device */
|
||||
int probe ( struct dev *dev ) {
|
||||
return dev->driver->probe ( dev, dev->bus );
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/* Disable a device */
|
||||
void disable ( struct dev *dev ) {
|
||||
if ( dev->dev_op ) {
|
||||
dev->dev_op->disable ( dev );
|
||||
dev->dev_op = NULL;
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
111
src/core/nic.c
111
src/core/nic.c
|
@ -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;
|
||||
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";
|
||||
|
||||
printf ( "Found %s NIC (MAC %!)\n", dev->name, nic->node_addr );
|
||||
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)) {
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
#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.
|
||||
*
|
||||
*/
|
||||
DEV_BUS( struct pci_device, pci_dev );
|
||||
static char pci_magic[0]; /* guaranteed unique symbol */
|
||||
|
||||
/*
|
||||
* pci_io.c may know how many buses we have, in which case it can
|
||||
* overwrite this value.
|
||||
|
@ -18,13 +11,39 @@ static char pci_magic[0]; /* guaranteed unique symbol */
|
|||
*/
|
||||
unsigned int pci_max_bus = 0xff;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
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 );
|
||||
}
|
||||
|
|
|
@ -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 */
|
|
@ -2,91 +2,276 @@
|
|||
#define DEV_H
|
||||
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
#include "dhcp.h" /* for dhcp_dev_id */
|
||||
|
||||
/* Device types */
|
||||
#include "nic.h"
|
||||
|
||||
/* 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));
|
||||
|
||||
/* Dont use sizeof, that will include the padding */
|
||||
#define DEV_ID_SIZE 8
|
||||
|
||||
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.
|
||||
/*
|
||||
* Forward declarations
|
||||
*
|
||||
*/
|
||||
struct bus_device *bus;
|
||||
/* All possible device types */
|
||||
union {
|
||||
struct nic nic;
|
||||
};
|
||||
struct type_dev;
|
||||
struct type_driver;
|
||||
struct bus_driver;
|
||||
struct bus_dev;
|
||||
struct device_driver;
|
||||
|
||||
/*
|
||||
* 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 on a bus.
|
||||
*
|
||||
*/
|
||||
#define BUS_LOC_SIZE 4
|
||||
struct bus_loc {
|
||||
char bytes[BUS_LOC_SIZE];
|
||||
};
|
||||
|
||||
/*
|
||||
* Macro to help create a common symbol with enough space for any
|
||||
* struct <bus>_device.
|
||||
* A structure fully describing a physical device on a bus.
|
||||
*
|
||||
* 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 BUS_DEV_SIZE 32
|
||||
struct bus_dev {
|
||||
char bytes[BUS_DEV_SIZE];
|
||||
};
|
||||
|
||||
/*
|
||||
* Table to describe a bootable device driver. See comments in dev.c
|
||||
* for an explanation.
|
||||
* 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!
|
||||
*
|
||||
*/
|
||||
struct bus_device {};
|
||||
struct bus_driver {};
|
||||
struct boot_driver {
|
||||
|
||||
#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" ) ))
|
||||
|
||||
/*
|
||||
* 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 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 */
|
||||
|
|
|
@ -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 */
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "stdint.h"
|
||||
|
||||
#define ISA_BUS_TYPE 2
|
||||
|
||||
/*
|
||||
* Construct a vendor ID from three ASCII characters
|
||||
*
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "isa_ids.h"
|
||||
#include "dev.h"
|
||||
|
||||
#define MCA_BUS_TYPE 3
|
||||
|
||||
/*
|
||||
* MCA constants
|
||||
*
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#ifndef NIC_H
|
||||
#define NIC_H
|
||||
|
||||
#include "dev.h"
|
||||
#include "byteswap.h"
|
||||
#include "dhcp.h"
|
||||
|
||||
typedef enum {
|
||||
DISABLE = 0,
|
||||
ENABLE,
|
||||
|
@ -33,7 +37,8 @@ struct nic {
|
|||
unsigned char irqno;
|
||||
unsigned int mbps;
|
||||
duplex_t duplex;
|
||||
void *priv_data; /* driver can hang private data here */
|
||||
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 */
|
||||
|
|
|
@ -22,8 +22,10 @@
|
|||
*/
|
||||
|
||||
#include "stdint.h"
|
||||
#include "nic.h"
|
||||
#include "pci_ids.h"
|
||||
#include "dev.h"
|
||||
|
||||
#define PCI_BUS_TYPE 1
|
||||
|
||||
/*
|
||||
* PCI constants
|
||||
|
@ -233,33 +235,45 @@
|
|||
#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
|
||||
#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 location on a PCI bus
|
||||
*
|
||||
*/
|
||||
struct pci_loc {
|
||||
uint16_t busdevfn;
|
||||
};
|
||||
|
||||
/*
|
||||
* A physical PCI device
|
||||
*
|
||||
*/
|
||||
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 vendor_id, device_id;
|
||||
uint16_t class;
|
||||
uint16_t busdevfn;
|
||||
uint8_t revision;
|
||||
uint8_t irq;
|
||||
uint8_t already_tried;
|
||||
};
|
||||
} __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 */
|
||||
|
|
Loading…
Reference in New Issue