--- /dev/null
+<!-- Copyright (C) 2003 Red Hat, Inc. -->
+<!-- This material may be distributed only subject to the terms -->
+<!-- and conditions set forth in the Open Publication License, v1.0 -->
+<!-- or later (the latest version is presently available at -->
+<!-- http://www.opencontent.org/openpub/). -->
+<!-- Distribution of the work or derivative of the work in any -->
+<!-- standard (paper) book form is prohibited unless prior -->
+<!-- permission is obtained from the copyright holder. -->
+<HTML
+><HEAD
+><TITLE
+>Generic Ethernet Device Driver</TITLE
+><meta name="MSSmartTagsPreventParsing" content="TRUE">
+<META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
+"><LINK
+REL="HOME"
+TITLE="eCos Reference Manual"
+HREF="ecos-ref.html"><LINK
+REL="UP"
+TITLE="Ethernet Device Drivers"
+HREF="io-eth-drv-generic.html"><LINK
+REL="PREVIOUS"
+TITLE="Ethernet Device Drivers"
+HREF="io-eth-drv-generic.html"><LINK
+REL="NEXT"
+TITLE="Review of the functions"
+HREF="io-eth-drv-api-funcs.html"></HEAD
+><BODY
+CLASS="CHAPTER"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="NAVHEADER"
+><TABLE
+SUMMARY="Header navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TH
+COLSPAN="3"
+ALIGN="center"
+>eCos Reference Manual</TH
+></TR
+><TR
+><TD
+WIDTH="10%"
+ALIGN="left"
+VALIGN="bottom"
+><A
+HREF="io-eth-drv-generic.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="80%"
+ALIGN="center"
+VALIGN="bottom"
+></TD
+><TD
+WIDTH="10%"
+ALIGN="right"
+VALIGN="bottom"
+><A
+HREF="io-eth-drv-api-funcs.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+></TABLE
+><HR
+ALIGN="LEFT"
+WIDTH="100%"></DIV
+><DIV
+CLASS="CHAPTER"
+><H1
+><A
+NAME="IO-ETH-DRV-GENERIC1">Chapter 46. Generic Ethernet Device Driver</H1
+><DIV
+CLASS="TOC"
+><DL
+><DT
+><B
+>Table of Contents</B
+></DT
+><DT
+><A
+HREF="io-eth-drv-generic1.html#IO-ETH-DRV-API"
+>Generic Ethernet API</A
+></DT
+><DT
+><A
+HREF="io-eth-drv-api-funcs.html"
+>Review of the functions</A
+></DT
+><DT
+><A
+HREF="io-eth-drv-upper-api.html"
+>Upper Layer Functions</A
+></DT
+><DT
+><A
+HREF="io-eth-call-graph.html"
+>Calling graph for Transmission and Reception</A
+></DT
+></DL
+></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="IO-ETH-DRV-API">Generic Ethernet API</H1
+><P
+>This file provides a simple description of how to write a low-level,
+hardware dependent ethernet driver.</P
+><P
+>There is a high-level driver (which is only code — with no state of
+its own) that is part of the stack. There will be one or more low-level
+drivers tied to the actual network hardware. Each of these drivers
+contains one or more driver instances. The intent 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
+<SPAN
+CLASS="PRODUCTNAME"
+>eCos</SPAN
+>
+supported
+<SPAN
+CLASS="ACRONYM"
+>TCP/IP</SPAN
+>
+stack,
+<SPAN
+CLASS="PRODUCTNAME"
+>RedBoot</SPAN
+>,
+or any other, with no changes.</P
+><P
+>A driver instance is contained within a
+<SPAN
+CLASS="TYPE"
+>struct eth_drv_sc</SPAN
+>:
+<TABLE
+BORDER="5"
+BGCOLOR="#E0E0F0"
+WIDTH="70%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>struct eth_hwr_funs {
+ // Initialize hardware (including startup)
+ void (*start)(struct eth_drv_sc *sc,
+ unsigned char *enaddr,
+ int flags);
+ // Shut down hardware
+ void (*stop)(struct eth_drv_sc *sc);
+ // Device control (ioctl pass-thru)
+ int (*control)(struct eth_drv_sc *sc,
+ unsigned long key,
+ void *data,
+ int data_length);
+ // Query - 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;
+ int state;
+ struct arpcom sc_arpcom; /* ethernet common */
+};</PRE
+></TD
+></TR
+></TABLE
+></P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>If you have two instances of the same hardware, you only need one
+<SPAN
+CLASS="TYPE"
+>struct eth_hwr_funs</SPAN
+> shared between them.</P
+></BLOCKQUOTE
+></DIV
+><P
+>There is another structure which is used to communicate with the rest of
+the stack:
+<TABLE
+BORDER="5"
+BGCOLOR="#E0E0F0"
+WIDTH="70%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>struct eth_drv_funs {
+ // Logical driver - initialization
+ void (*init)(struct eth_drv_sc *sc,
+ unsigned char *enaddr);
+ // Logical driver - incoming packet notifier
+ void (*recv)(struct eth_drv_sc *sc,
+ int total_len);
+ // Logical driver - outgoing packet notifier
+ void (*tx_done)(struct eth_drv_sc *sc,
+ CYG_ADDRESS key,
+ int status);
+};</PRE
+></TD
+></TR
+></TABLE
+>
+Your driver does <SPAN
+CLASS="emphasis"
+><I
+CLASS="EMPHASIS"
+>not</I
+></SPAN
+> create an instance of this
+structure. It is provided for driver code to use in the
+<SPAN
+CLASS="TYPE"
+>eth_drv</SPAN
+> member of the function record.
+Its usage is described below in <A
+HREF="io-eth-drv-upper-api.html"
+>the Section called <I
+>Upper Layer Functions</I
+></A
+></P
+><P
+>One more function completes the API with which your driver communicates
+with the rest of the stack:
+<TABLE
+BORDER="5"
+BGCOLOR="#E0E0F0"
+WIDTH="70%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>extern void eth_drv_dsr(cyg_vector_t vector,
+ cyg_ucount32 count,
+ cyg_addrword_t data);</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>This function is designed so that it can be registered as the DSR for your
+interrupt handler. It will awaken the
+“Network Delivery Thread”
+to call your deliver routine. See <A
+HREF="io-eth-drv-api-funcs.html#IO-ETH-DRV-API-DELIVER"
+>the Section called <I
+>Deliver function</I
+></A
+>.</P
+><P
+>You create an instance of <SPAN
+CLASS="TYPE"
+>struct eth_drv_sc</SPAN
+>
+using the
+<TT
+CLASS="FUNCTION"
+>ETH_DRV_SC()</TT
+>
+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.</P
+><P
+>The “magic”
+which gets the drivers started (and indeed, linked) is
+similar to what is used for the I/O subsystem.
+This is done using the
+<TT
+CLASS="FUNCTION"
+>NETDEVTAB_ENTRY()</TT
+>
+macro, which defines an initialization function
+and the basic data structures for the low-level driver.</P
+><P
+><TABLE
+BORDER="5"
+BGCOLOR="#E0E0F0"
+WIDTH="70%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> 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;</PRE
+></TD
+></TR
+></TABLE
+>
+The <TT
+CLASS="VARNAME"
+>device_instance</TT
+>
+entry here would point to the <SPAN
+CLASS="TYPE"
+>struct eth_drv_sc</SPAN
+>
+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 <SPAN
+CLASS="ACRONYM"
+>PPP</SPAN
+>
+drivers, etc. These will
+use the <TT
+CLASS="FUNCTION"
+>NETDEVTAB_ENTRY()</TT
+>
+setup to create the basic driver, but they will
+most likely be built on top of other high-level device driver layers.</P
+><P
+>To instantiate itself, and connect it to the system,
+a hardware driver will have a template
+(boilerplate) which looks something like this:
+<TABLE
+BORDER="5"
+BGCOLOR="#E0E0F0"
+WIDTH="70%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>#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(<TT
+CLASS="REPLACEABLE"
+><I
+>DRV</I
+></TT
+>_sc,
+ 0, // No driver specific data needed
+ "eth0", // Name for this interface
+ <TT
+CLASS="REPLACEABLE"
+><I
+>HRDWR</I
+></TT
+>_start,
+ <TT
+CLASS="REPLACEABLE"
+><I
+>HRDWR</I
+></TT
+>_stop,
+ <TT
+CLASS="REPLACEABLE"
+><I
+>HRDWR</I
+></TT
+>_control,
+ <TT
+CLASS="REPLACEABLE"
+><I
+>HRDWR</I
+></TT
+>_can_send
+ <TT
+CLASS="REPLACEABLE"
+><I
+>HRDWR</I
+></TT
+>_send,
+ <TT
+CLASS="REPLACEABLE"
+><I
+>HRDWR</I
+></TT
+>_recv,
+ <TT
+CLASS="REPLACEABLE"
+><I
+>HRDWR</I
+></TT
+>_deliver,
+ <TT
+CLASS="REPLACEABLE"
+><I
+>HRDWR</I
+></TT
+>_poll,
+ <TT
+CLASS="REPLACEABLE"
+><I
+>HRDWR</I
+></TT
+>_int_vector
+);
+
+NETDEVTAB_ENTRY(<TT
+CLASS="REPLACEABLE"
+><I
+>DRV</I
+></TT
+>_netdev,
+ "<TT
+CLASS="REPLACEABLE"
+><I
+>DRV</I
+></TT
+>",
+ <TT
+CLASS="REPLACEABLE"
+><I
+>DRV_HRDWR</I
+></TT
+>_init,
+ &<TT
+CLASS="REPLACEABLE"
+><I
+>DRV</I
+></TT
+>_sc);</PRE
+></TD
+></TR
+></TABLE
+></P
+><P
+>This, along with the referenced functions, completely define the driver.</P
+><DIV
+CLASS="NOTE"
+><BLOCKQUOTE
+CLASS="NOTE"
+><P
+><B
+>Note: </B
+>If one needed the same low-level driver to handle
+multiple similar hardware interfaces, you would need multiple invocations
+of the
+<TT
+CLASS="FUNCTION"
+>ETH_DRV_SC()</TT
+>/<TT
+CLASS="FUNCTION"
+>NETDEVTAB_ENTRY()</TT
+>
+macros. You would add a pointer
+to some instance specific data, e.g. containing base addresses, interrupt
+numbers, etc, where the
+<TABLE
+BORDER="5"
+BGCOLOR="#E0E0F0"
+WIDTH="70%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+> 0, // No driver specific data</PRE
+></TD
+></TR
+></TABLE
+>
+is currently.</P
+></BLOCKQUOTE
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="NAVFOOTER"
+><HR
+ALIGN="LEFT"
+WIDTH="100%"><TABLE
+SUMMARY="Footer navigation table"
+WIDTH="100%"
+BORDER="0"
+CELLPADDING="0"
+CELLSPACING="0"
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+><A
+HREF="io-eth-drv-generic.html"
+ACCESSKEY="P"
+>Prev</A
+></TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="ecos-ref.html"
+ACCESSKEY="H"
+>Home</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+><A
+HREF="io-eth-drv-api-funcs.html"
+ACCESSKEY="N"
+>Next</A
+></TD
+></TR
+><TR
+><TD
+WIDTH="33%"
+ALIGN="left"
+VALIGN="top"
+>Ethernet Device Drivers</TD
+><TD
+WIDTH="34%"
+ALIGN="center"
+VALIGN="top"
+><A
+HREF="io-eth-drv-generic.html"
+ACCESSKEY="U"
+>Up</A
+></TD
+><TD
+WIDTH="33%"
+ALIGN="right"
+VALIGN="top"
+>Review of the functions</TD
+></TR
+></TABLE
+></DIV
+></BODY
+></HTML
+>
\ No newline at end of file