mirror of
https://github.com/ipxe/ipxe
synced 2026-02-07 08:02:49 +03:00
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.
This commit is contained in:
@@ -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"
|
||||
/*
|
||||
* 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 )
|
||||
|
||||
/*
|
||||
* Table to describe a bootable device driver. See comments in dev.c
|
||||
* for an explanation.
|
||||
* 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_device {};
|
||||
struct bus_driver {};
|
||||
struct boot_driver {
|
||||
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 bus_driver *bus_driver;
|
||||
int ( *probe ) ( struct dev *dev, struct bus_device *bus_device );
|
||||
struct type_dev *type_dev; /* single instance */
|
||||
char * ( * describe ) ( struct type_dev *type_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 __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;
|
||||
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 __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 */
|
||||
|
||||
12
src/include/dhcp.h
Normal file
12
src/include/dhcp.h
Normal file
@@ -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,
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 class;
|
||||
uint16_t busdevfn;
|
||||
uint8_t revision;
|
||||
uint8_t irq;
|
||||
uint8_t already_tried;
|
||||
};
|
||||
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 */
|
||||
|
||||
Reference in New Issue
Block a user