📄 io-eth-drv-generic1.html
字号:
<!-- 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"><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+"><LINKREL="HOME"TITLE="eCos Reference Manual"HREF="ecos-ref.html"><LINKREL="UP"TITLE="Ethernet Device Drivers"HREF="io-eth-drv-generic.html"><LINKREL="PREVIOUS"TITLE="Ethernet Device Drivers"HREF="io-eth-drv-generic.html"><LINKREL="NEXT"TITLE="Review of the functions"HREF="io-eth-drv-api-funcs.html"></HEAD><BODYCLASS="CHAPTER"BGCOLOR="#FFFFFF"TEXT="#000000"LINK="#0000FF"VLINK="#840084"ALINK="#0000FF"><DIVCLASS="NAVHEADER"><TABLESUMMARY="Header navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><THCOLSPAN="3"ALIGN="center">eCos Reference Manual</TH></TR><TR><TDWIDTH="10%"ALIGN="left"VALIGN="bottom"><AHREF="io-eth-drv-generic.html"ACCESSKEY="P">Prev</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom"></TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="io-eth-drv-api-funcs.html"ACCESSKEY="N">Next</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="CHAPTER"><H1><ANAME="IO-ETH-DRV-GENERIC1">Chapter 46. Generic Ethernet Device Driver</H1><DIVCLASS="TOC"><DL><DT><B>Table of Contents</B></DT><DT><AHREF="io-eth-drv-generic1.html#IO-ETH-DRV-API">Generic Ethernet API</A></DT><DT><AHREF="io-eth-drv-api-funcs.html">Review of the functions</A></DT><DT><AHREF="io-eth-drv-upper-api.html">Upper Layer Functions</A></DT><DT><AHREF="io-eth-call-graph.html">Calling graph for Transmission and Reception</A></DT></DL></DIV><DIVCLASS="SECT1"><H1CLASS="SECT1"><ANAME="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 ofits own) that is part of the stack. There will be one or more low-leveldrivers tied to the actual network hardware. Each of these driverscontains one or more driver instances. The intent is that thelow-level drivers know nothing of the details of the stack that will beusing them. Thus, the same driver can be used by the<SPANCLASS="PRODUCTNAME">eCos</SPAN>supported<SPANCLASS="ACRONYM">TCP/IP</SPAN>stack,<SPANCLASS="PRODUCTNAME">RedBoot</SPAN>,or any other, with no changes.</P><P>A driver instance is contained within a<SPANCLASS="TYPE">struct eth_drv_sc</SPAN>:<TABLEBORDER="5"BGCOLOR="#E0E0F0"WIDTH="70%"><TR><TD><PRECLASS="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><DIVCLASS="NOTE"><BLOCKQUOTECLASS="NOTE"><P><B>Note: </B>If you have two instances of the same hardware, you only need one<SPANCLASS="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 ofthe stack:<TABLEBORDER="5"BGCOLOR="#E0E0F0"WIDTH="70%"><TR><TD><PRECLASS="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 <SPANCLASS="emphasis"><ICLASS="EMPHASIS">not</I></SPAN> create an instance of thisstructure. It is provided for driver code to use in the<SPANCLASS="TYPE">eth_drv</SPAN> member of the function record.Its usage is described below in <AHREF="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 communicateswith the rest of the stack:<TABLEBORDER="5"BGCOLOR="#E0E0F0"WIDTH="70%"><TR><TD><PRECLASS="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 yourinterrupt handler. It will awaken the“Network Delivery Thread”to call your deliver routine. See <AHREF="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 <SPANCLASS="TYPE">struct eth_drv_sc</SPAN>using the<TTCLASS="FUNCTION">ETH_DRV_SC()</TT>macro whichsets up the structure, including the prototypes for the functions, etc.By doing things this way, if the internal design of the ethernet driverschanges (e.g. we need to add a new low-level implementation function),existing drivers will no longer compile until updated. This is muchbetter than to have all of the definitions in the low-level driversthemselves and have them be (quietly) broken if the interfaces change.</P><P>The “magic”which gets the drivers started (and indeed, linked) issimilar to what is used for the I/O subsystem.This is done using the<TTCLASS="FUNCTION">NETDEVTAB_ENTRY()</TT>macro, which defines an initialization functionand the basic data structures for the low-level driver.</P><P><TABLEBORDER="5"BGCOLOR="#E0E0F0"WIDTH="70%"><TR><TD><PRECLASS="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 <TTCLASS="VARNAME">device_instance</TT>entry here would point to the <SPANCLASS="TYPE">struct eth_drv_sc</SPAN>entry previously defined. This allows the network driversetup to work with any class of driver, not just ethernet drivers. Inthe future, there will surely be serial <SPANCLASS="ACRONYM">PPP</SPAN>drivers, etc. These willuse the <TTCLASS="FUNCTION">NETDEVTAB_ENTRY()</TT>setup to create the basic driver, but they willmost 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:<TABLEBORDER="5"BGCOLOR="#E0E0F0"WIDTH="70%"><TR><TD><PRECLASS="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(<TTCLASS="REPLACEABLE"><I>DRV</I></TT>_sc, 0, // No driver specific data needed "eth0", // Name for this interface <TTCLASS="REPLACEABLE"><I>HRDWR</I></TT>_start, <TTCLASS="REPLACEABLE"><I>HRDWR</I></TT>_stop, <TTCLASS="REPLACEABLE"><I>HRDWR</I></TT>_control, <TTCLASS="REPLACEABLE"><I>HRDWR</I></TT>_can_send <TTCLASS="REPLACEABLE"><I>HRDWR</I></TT>_send, <TTCLASS="REPLACEABLE"><I>HRDWR</I></TT>_recv, <TTCLASS="REPLACEABLE"><I>HRDWR</I></TT>_deliver, <TTCLASS="REPLACEABLE"><I>HRDWR</I></TT>_poll, <TTCLASS="REPLACEABLE"><I>HRDWR</I></TT>_int_vector);NETDEVTAB_ENTRY(<TTCLASS="REPLACEABLE"><I>DRV</I></TT>_netdev, "<TTCLASS="REPLACEABLE"><I>DRV</I></TT>", <TTCLASS="REPLACEABLE"><I>DRV_HRDWR</I></TT>_init, &<TTCLASS="REPLACEABLE"><I>DRV</I></TT>_sc);</PRE></TD></TR></TABLE></P><P>This, along with the referenced functions, completely define the driver.</P><DIVCLASS="NOTE"><BLOCKQUOTECLASS="NOTE"><P><B>Note: </B>If one needed the same low-level driver to handlemultiple similar hardware interfaces, you would need multiple invocationsof the<TTCLASS="FUNCTION">ETH_DRV_SC()</TT>/<TTCLASS="FUNCTION">NETDEVTAB_ENTRY()</TT>macros. You would add a pointerto some instance specific data, e.g. containing base addresses, interruptnumbers, etc, where the<TABLEBORDER="5"BGCOLOR="#E0E0F0"WIDTH="70%"><TR><TD><PRECLASS="PROGRAMLISTING"> 0, // No driver specific data</PRE></TD></TR></TABLE>is currently.</P></BLOCKQUOTE></DIV></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLESUMMARY="Footer navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="io-eth-drv-generic.html"ACCESSKEY="P">Prev</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="ecos-ref.html"ACCESSKEY="H">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="io-eth-drv-api-funcs.html"ACCESSKEY="N">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">Ethernet Device Drivers</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="io-eth-drv-generic.html"ACCESSKEY="U">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">Review of the functions</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -