Mercurial > nand-ecoscentric
changeset 2005:5d432466ea7c
* doc/driver_doc: Removed, it has been superseded by the sgml
documentation.
| author | asl |
|---|---|
| date | Wed, 29 Jun 2005 11:10:26 +0000 |
| parents | d3a8cc4f7931 |
| children | 21764aa405ca |
| files | packages/io/eth/current/ChangeLog packages/io/eth/current/doc/driver_doc |
| diffstat | 2 files changed, 7 insertions(+), 375 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/io/eth/current/ChangeLog +++ b/packages/io/eth/current/ChangeLog @@ -1,7 +1,12 @@ +2005-06-29 Andrew Lunn <andrew.lunn@ascom.ch> + + * doc/driver_doc: Removed, it has been superseded by the sgml + documentation. + 2005-03-27 Andrew Lunn <andrew.lunn@ascom.ch> - * src/net/eth_drv.c (eth_drv_send): Fixed a compiler warning about type of - parameter passed to diag_printf. + * src/net/eth_drv.c (eth_drv_send): Fixed a compiler warning about + type of parameter passed to diag_printf. 2004-08-06 Jani Monoses <jani@iv.ro>
deleted file mode 100644 --- a/packages/io/eth/current/doc/driver_doc +++ /dev/null @@ -1,373 +0,0 @@ -This file provides a simple description of how to write a low-level, -hardware dependent ethernet driver. - -The basic idea is that there is a high-level driver (which is only -code/functions) that is part of the stack. There will be one or more -low-level driver tied to the actual network hardware. Each of these -drivers contains one or more driver instances. The principal idea is -that the low-level drivers know nothing of the details of the stack that -will be using them. Thus, the same driver can be used by the eCos -supported TCP/IP stack, or any other, with no changes. - -A driver instance is contained within a "struct eth_drv_sc". - - struct eth_hwr_funs { - // Initialize hardware (including startup) - void (*start)(struct eth_drv_sc *sc, - unsigned char *enaddr); - // Shut down hardware - void (*stop)(struct eth_drv_sc *sc); - // Control interface - int (*control)(struct eth_drv_sc *sc, - unsigned long cmd, - void *data, - int len); - // Query interface - can a packet be sent? - int (*can_send)(struct eth_drv_sc *sc); - // Send a packet of data - void (*send)(struct eth_drv_sc *sc, - struct eth_drv_sg *sg_list, - int sg_len, - int total_len, - unsigned long key); - // Receive [unload] a packet of data - void (*recv)(struct eth_drv_sc *sc, - struct eth_drv_sg *sg_list, - int sg_len); - // Deliver data to/from device from/to stack memory space - // (moves lots of memcpy()s out of DSRs into thread) - void (*deliver)(struct eth_drv_sc *sc); - // Poll for interrupts/device service - void (*poll)(struct eth_drv_sc *sc); - // Get interrupt information from hardware driver - int (*int_vector)(struct eth_drv_sc *sc); - // Logical driver interface - struct eth_drv_funs *eth_drv, *eth_drv_old; - }; - - struct eth_drv_sc { - struct eth_hwr_funs *funs; - void *driver_private; - const char *dev_name; - struct arpcom sc_arpcom; /* ethernet common */ - }; - -You create one of these instances using the "ETH_DRV_SC()" macro which -sets up the structure, including the prototypes for the functions, etc. -By doing things this way, if the internal design of the ethernet drivers -changes (e.g. we need to add a new low-level implementation function), -existing drivers will no longer compile until updated. This is much -better than to have all of the definitions in the low-level drivers -themselves and have them be [quietly] broken if the interfaces change. - -The "magic" which gets the drivers started [and indeed, linked] is -similar to what is used for the I/O subsystem. [Note: I may try and -make it part of the I/O subsystem later.] This is done using the -"NETDEVTAB_ENTRY()" macro, which defines an initialization function -and the basic data structures for the low-level driver. - - typedef struct cyg_netdevtab_entry { - const char *name; - bool (*init)(struct cyg_netdevtab_entry *tab); - void *device_instance; - unsigned long status; - } cyg_netdevtab_entry_t; - -The "device_instance" entry here would point to the "struct -eth_drv_sc" entry previously defined. This allows the network driver -setup to work with any class of driver, not just ethernet drivers. In -the future, there will surely be serial PPP drivers, etc. These will -use the "NETDEVTAB" setup to create the basic driver, but they will -most likely be built on top of other high-level device driver layers. - -So, the bottom line is that a hardware driver will have a template -(boilerplate) which looks like this: - - #include <cyg/infra/cyg_type.h> - #include <cyg/hal/hal_arch.h> - #include <cyg/infra/diag.h> - #include <cyg/hal/drv_api.h> - #include <cyg/io/eth/netdev.h> - #include <cyg/io/eth/eth_drv.h> - - ETH_DRV_SC(DRV_sc, - 0, // No driver specific data needed - "eth0", // Name for this interface - HRDWR_start, - HRDWR_stop, - HRDWR_control, - HRDWR_can_send - HRDWR_send, - HRDWR_recv); - - NETDEVTAB_ENTRY(DRV_netdev, - "DRV", - DRV_HRDWR_init, - &DRV_sc); - -This, along with the referenced functions, completely define the driver. -Extensibility note: if one needed the same low-level driver to handle -multiple similar hardware interfaces, you would need multiple invocations -of the "ETH_DRV_SC()/NETDEVTAB_ENTRY()" macros. You would add a pointer -to some instance specific data, e.g. containing base addresses, interrupt -numbers, etc, where the "0, // No driver specific data" is currently. - -Now a quick waltz through the functions. This discussion will use the -generic names from above. - -static bool DRV_HDWR_init(struct cyg_netdevtab_entry *tab) -========================================================== - -This function is called as part of system initialization. Its primary -function is to decide if the hardware [as indicated via -tab->device_instance] is working and if the interface needs to be made -available in the system. If this is the case, this function needs to -finish with a call to the ethernet driver function: - - eth_drv_init((struct eth_drv_sc *)tab->device_instance, - unsigned char *enaddr); - -where 'enaddr' is a pointer to the ethernet station address for this -unit. Note: the ethernet station address is supposed to be a -world-unique, 48 bit address for this particular ethernet interface. -Typically it is provided by the board/hardware manufacturer in ROM. - -In many packages it is possible for the ESA to be set from RedBoot, -(perhaps from 'fconfig' data), hard-coded from CDL, or from an EPROM. -A driver should choose a run-time specified ESA (e.g. from RedBoot) -preferentially, otherwise (in order) it should use a CDL specified -ESA if one has been set, otherwise an EPROM set ESA, or otherwise -fail. See the cl/cs8900a eth driver for an example. - -static void -HRDWR_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags) -==================================================================== - -This function is called, perhaps much later than system initialization -time, when the system (an application) is ready for the interface to -become active. The purpose of this function is to set up the hardware -interface to start accepting packets from the network and be able to -send packets out. Note: this function will be called whenever the -up/down state of the logical interface changes, e.g. when the IP address -changes. This may occur more than one time, so this function needs to -be prepared for that case. - -FUTURE: the "flags" field (currently unused) may be used to tell the -function how to start up, e.g. whether interrupts will be used, -selection of "promiscuous" mode etc. - -static void HRDWR_stop(struct eth_drv_sc *sc) -============================================= - -This function is the inverse of "start". It should shut down the -hardware and keep it from interacting with the physical network. - -static int -HRDWR_control(struct eth_drv_sc *sc, unsigned long key, void *data, int len) -============================================================================ - -This function is used to perform low-level "control" operations on the -interface. These operations would be initiated via 'ioctl()' in the BSD -stack, and would be anything that would require the hardware setup to -possibly change (i.e. cannot be performed totally by the -platform-independent layers). - -Current operations: - -ETH_DRV_SET_MAC_ADDRESS: - This function sets the ethernet station address (ESA or MAC) for the - device. Normally this address is kept in non-volatile memory and is - unique in the world. This function must at least set the interface to - use the new address. It may also update the NVM as appropriate. - -This function should return zero if the specified operation was -completed successfully. It should return non-zero if the operation -could not be performed, for any reason. - -static int HRDWR_can_send(struct eth_drv_sc *sc) -================================================ - -This function is called to determine if it is possible to start the -transmission of a packet on the interface. Some interfaces will allow -multiple packets to be "queued" and this function allows for the highest -possible utilization of that mode. - -Return the number of packets which could be accepted at this time, zero -implies that the interface is saturated/busy. - -static void -HRDWR_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, - int total_len, unsigned long key) -========================================================================= - -This function is used to send a packet of data to the network. It is -the responsibility of this function to somehow hand the data over to the -hardware interface. This will most likely require copying, but just the -address/length values could be used by smart hardware. - -NOTE: All data in/out of the driver is specified via a "scatter-gather" -list. This is just an array of address/length pairs which describe -sections of data to move (in the order given by the array). - -Once the data has been successfully sent by the interface (or if an -error occurs), the driver should call 'eth_drv_tx_done()' using the -specified 'key'. Only then will the upper layers release the resources -for that packet and start another transmission. - -FUTURE: This function may be extended so that the data need not be -copied by having the function return a "disposition" code (done, send -pending, etc). At this point, you should move the data to some "safe" -location before returning. - -static void -HRDWR_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len) -========================================================================= - -This function is actually a call back, only invoked after the -upper-level function - eth_drv_recv(struct eth_drv_sc *sc, int total_len) -has been called. This upper level function is called by the hardware -driver when it knows that a packet of data is available on the -interface. The 'eth_drv_recv()' function then arranges network buffers -and structures for the data and then calls "HRDWR_recv()" to actually -move the data from the interface. - -static void -HRDWR_deliver(struct eth_drv_sc *sc) -========================================================================= - -This function is actually a call back, and notifies the driver that delivery -is happening. This allows it to actually do the copy of packet data to/from -the hardware from/to the packet buffer. And once that's done, then do things -like unmask its interrupts, and free any relevant resources so it can process -further packets. - -In general it will be called from the user thread responsible for delivering -network packets. - -static void -HRDWR_poll(struct eth_drv_sc *sc) -========================================================================= - -This function is used when in a non-interrupt driven system, e.g. when -interrupts are completely disabled. This allows the driver time to check -whether anything needs doing either for transmission, or to check if -anything has been received, or if any other processing needs doing.. - -static int -HRDWR_int_vector(struct eth_drv_sc *sc) -========================================================================= - -This function returns the interrupt vector number used for RX interrupts. -This is so the common GDB stubs infrastructure can detect when to check -for incoming ctrl-c's when doing debugging over ethernet. - -Upper layer functions - called by drivers -========================================= - -These functions are defined by the upper layers (machine independent) of -the networking driver support. They are present to hide the interfaces -to the actual networking stack so that the hardware drivers may possibly -be used by any network stack implementation. - -These functions require a pointer to a "struct eth_drv_sc" table which -describes the interface at a logical level. It is assumed that the -driver [lowest level hardware support] will keep track of this pointer -so it may be passed "up" as appropriate. - - struct eth_drv_sc { - struct eth_drv_funs *funs; // Pointer to hardware functions (see above) - void *driver_private; // Device specific data - const char *dev_name; - struct arpcom sc_arpcom; // ethernet common - }; - -This structure is created, one per logical interface, via ETH_DRV_SC macro. - -void eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr) -=============================================================== - -This function establishes the device at initialization time. The -hardware should be totally intialized (not "started") when this function -is called. - -void eth_drv_tx_done(struct eth_drv_sc *sc, unsigned long key, int status) -========================================================================== - -This function is called when a packet completes transmission on the -interface. The 'key' value must be one of the keys provided to -"HRDWR_send()" above. The value 'status' should be non-zero (currently -undefined) to indicate that an error occurred during the transmission. - -void eth_drv_recv(struct eth_drv_sc *sc, int len) -================================================= - -This function is called to indicate that a packet of length 'len' has -arrived at the interface. The callback "HRDWR_recv()" function -described above will be used to actually unload the data from the -interface into buffers used by the machine independent layers. - - - -Calling graph for Transmit and Receive --------------------------------------- - -It may be worth clarifying further the flow of control in the transmit -and receive cases, where the hardware driver does use interrupts and so -DSRs to tell the "foreground" when something asynchronous has occurred. - -Transmit: - Foreground task calls into network stack to send a packet (or the - stack decides to send a packet in response to incoming traffic). - The driver calls the HRDWR_can_send() function in the hardware driver. - HRDWR_can_send() returns the number of available "slots" in which it - can store a pending transmit packet. - If it cannot send at this time, the packet is queued outside the - hardware driver for later; in this case, the hardware is already busy - transmitting, so expect an interrupt as described below for completion - of the packet currently outgoing. - If it can send right now, HRDWR_send() is called. - HRDWR_send() copies the data into special hardware buffers, or - instructs the hardware to "send that". - It also remembers the key that is associated with this tx request. - these calls return. - ... - - Asynchronously, the hardware makes an interrupt to say "transmit is - done"; the ISR quietens the interrupt source in the hardware and - requests that the associated DSR be run. - The DSR realizes that a transmit request has completed, and calls - eth_drv_tx_done() with the same key that it remembered for this tx. - eth_drv_tx_done() uses the key to find the resources associated with - this transmit request; thus the stack knows that the transmit has - completed and its resources can be freed. - eth_drv_tx_done() also enquires whether HRDWR_can_send() now says - "yes, we can send" and if so, dequeues a further transmit request - which may have been queued as described above. If so: - HRDWR_send() copies the data into the hardware buffers, or - instructs the hardware to "send that" and remembers the new key. - these calls return to the DSR and thus to the foreground. - ... - - -Receive: - ... - - Asynchronously, the hardware makes an interrupt to say "there is ready - data in a receive buffer"; the ISR quietens the interrupt source in - the hardware and requests that the associated DSR be run. - The DSR realizes that there is data ready and calls eth_drv_recv() - with the length of the data that is available. - eth_drv_recv() prepares a set of scatter-gather buffers that can - accommodate that data. - It then calls back into the hardware driver routine HRDWR_recv(). - HRDWR_recv() must copy the data from the hardware's buffers into - the scatter-gather buffers provided, and return. - eth_drv_recv() sends the new packet up the network stack and returns. - Back in the DSR now, the driver cleans the receive buffer and returns - it to the hardware's control, available to receive another packet from - the network. - The DSR returns to the foreground. - ... - -
