?? (ldd) ch14-網絡驅動程序(上)(轉載).htm
字號:
color=#ffffff size=3>
<P>但主要目的是提供一個參考而不是要被記住。本章的其余部分在一個域被示例代碼用到<BR>的時候會簡單地描述一下,所以你不必不停地回頭來參考本節。<BR> <BR>結構device在結構上可以分為兩個部分:“可見的”和“不可見的”。可見部分由那些<BR>在靜態device結構中顯式賦值的域組成,象前面給出的在snull中出現的兩項。其余的域<BR>內部使用。有些被驅動程序訪問(例如在初始化時被賦值的那些),而有些不能動。本<BR>章在版本2.0.30前都是完全的。<BR> <BR>可見的頭<BR> <BR>結構device的第一部分由下列域組成,按序為:<BR> <BR>char *name;<BR> <BR>設備名。如果第一個字符是0(NULL字符)或空格,register_netdev給它分配名字ethn<BR>,n取合適的值。<BR> <BR>unsigned long rmem_end;<BR> <BR>unsigned long rmem_start;<BR> <BR>unsigned long mem_end;<BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>unsigned long mem_start;<BR> <BR>這些域存有設備使用的共享內存的開始和結束地址。如果設備有不同的發送和接收內存<BR>,那么mem域就用做發送內存,而rmem用做接收內存。mem_end和mem_start可以在系統引<BR>導時在核心命令行指定,它們的值由ifconfig獲取。Rmem域在驅動程序以外不會被引用<BR>。一般地,end域被設置成使得end-start為板上可用內存量。<BR> <BR>unsigned long base_addr;<BR> <BR>I/O基地址。這個域,和前面的一樣,在設備檢測時被賦值。ifconfig可以用來顯示和修<BR>改當前值。base_addr可以在系統引導或加載時在核心命令行顯式賦值。<BR> <BR>unsigned char irq;<BR> <BR>被賦予的中斷號。當接口被列出時dev->irq由ifconfig打印出來。這個值通常在引導或<BR>加載時被設置,以后可以用ifconfig修改。<BR> <BR>unsigned char start;<BR> <BR>unsigned char interrupt;<BR> <BR>這些域是二進制標志。start通常在設備打開時設置,在關閉時清楚。在接口準備號運行<BR></P></FONT><FONT
color=#ffffff size=3>
<P>這些域是二進制標志。start通常在設備打開時設置,在關閉時清楚。在接口準備號運行<BR>時它是非零。interrupt是用來告訴代碼的高層一個中斷到達接口,并正在處理中。<BR> <BR>unsigned long tbusy;<BR> <BR>這個域表明“傳送忙”。當驅動程序不能再接收新的包發送時(既所有的輸出緩沖區都<BR>滿了),它應該為非零。使用long類型而不是char是因為有時要使用原子的位操作以避<BR>免競爭條件。注意在核心1.2,tbusy的確是個八位的域,向后可移植的驅動程序應該注<BR>意這一點。原子的位操作在第九章的“使用鎖變量”一節中介紹過。<BR> <BR>struct device *next;<BR> <BR>用來維護鏈表;任何驅動程序都不能動這個域。<BR> <BR>int (*init)(struct device *dev);<BR> <BR>初始化函數。這個域通常是device結構中顯式列出的最后一個域。<BR> <BR>隱藏的域<BR> <BR>device結構包含幾個額外的域,通常在設備初始化時被賦值。這些域中的一些攜帶了接<BR>口的信息,一些存在只是為了方便驅動程序(也就是說,核心并不使用它們);還有一<BR>些域,最引人注意的是一些設備方法,它們是核心和驅動程序的接口。<BR></P></FONT><FONT
color=#ffffff size=3>
<P>些域,最引人注意的是一些設備方法,它們是核心和驅動程序的接口。<BR> <BR>我想分別列為三組,與域的實際順序無關,那并不重要。<BR> <BR>接口信息<BR> <BR>多數接口信息都由函數ether_setup來正確設置。以太網卡在大部分域都可以依賴這個通<BR>用目的的函數,但flags和dev_addr域是設備特定的,必須在初始化時顯式地賦值。<BR> <BR>一些非以太網的接口可以使用類似于ether_setup的助手函數。driver/net/net_init.c<BR>引出tr_setup(令牌環)和fddi_setup。如果你的設備不屬于這些類中的一種,你需要自<BR>己為所有的域賦值。<BR> <BR>unsigned short hard_header_len;<BR> <BR>“硬件包頭長”。發送包頭中IP頭(或其它協議信息)之前那部分的八元組個數。對以<BR>太網接口來說,這個值是14。<BR> <BR>unsigned short mtu;<BR> <BR>“最大傳送單元”。在包傳輸時,這個域由網絡層使用。以太網的MTU為1500個八元組。<BR> <BR>__u32 tx_queue_len;<BR></P></FONT><FONT
color=#ffffff size=3>
<P>__u32 tx_queue_len;<BR> <BR>在設備傳送隊列中可以排隊的最大禎數。ether_setup將這個值設為100,不過你可以改<BR>變它。例如,plip使用10以避免浪費系統內存(plip比實際的以太網接口吞吐率要低)<BR>。<BR> <BR>unsigned short type;<BR> <BR>接口的硬件類型。這個域被ARP使用以判斷接口支持的硬件地址類型。以太網接口把它設<BR>為ARPHRD_ETHER----ether_setup為你做這件事。<BR> <BR>unsigned char addr_len;<BR> <BR>unsigned char broadcast[MAX_ADDR_LEN];<BR> <BR>unsigned char dev_addr[MAX_ADDR_LEN];<BR> <BR>以太網地址長為六個八元組(我們是指接口板的硬件標志),播送地址由六個0xff八元<BR>組組成;ether_setup負責這些值的正確設置。另一方面,設備地址必須以設備特定的方<BR>式從接口板中讀出,驅動程序應把它復制到dev_addr。這個硬件地址用來在把包交給驅<BR>動程序傳送前產生正確的以太網包頭。snull并不使用物理接口,它生成一個它自己的物<BR>理地址。<BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>unsigned short family;<BR> <BR>接口的地址族,通常為AF_INET。接口并不常查看這個域或者向其賦值。<BR> <BR>unsigned short pa_alen;<BR> <BR>協議地址長。對AF_INET來說為四個八元組。接口不需要修改這個數。<BR> <BR>unsigned long pa_addr;<BR> <BR>unsigned long pa_brdaddr;<BR> <BR>unsigned long pa_mask;<BR> <BR>刻劃接口的三個地址:接口地址,播送地址,及網絡掩碼。這些值是協議特定的(既它<BR>們是“協議地址”);如果dev->family是INET,則它們為IP地址。這些域由ifconfig賦<BR>值,對驅動程序是只讀的。<BR> <BR>unsigned long pa_dstaddr;<BR> <BR>plip和ppp一類點到點協議使用這個域記錄連接另一側的IP號碼。和前面的域一樣,它也<BR>是只讀的。<BR></P></FONT><FONT
color=#ffffff size=3>
<P>是只讀的。<BR> <BR>unsigned short flags;<BR> <BR>接口標志。這個域含有下列位值。前綴IFF意為接口標志(InterFace Flags)。有些標<BR>志由核心管理,有些則是在初始化時由接口設置,以確認接口的能力。有效的標志是:<BR> <BR>IFF_UP<BR> <BR>當接口是活躍的時,核心置上該標志。這個標志對驅動程序是只讀的。<BR> <BR>IFF_BROADCAST<BR> <BR>這個標志表明接口的播送地址是有效的。以太網卡支持播送。<BR> <BR>IFF_DEBUG<BR> <BR>查錯模式。這標志控制printk調用的嘮叨,還用在其它一些查錯目的。盡管目前沒有官<BR>方驅動程序使用它,用戶程序可以通過ioctl來對其置位或者清除,你的驅動程序可以使<BR>用它。misc-progs/netifdebug程序可以用來將這個標志打開或關閉。<BR> <BR>IFF_LOOPBACK<BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>這個標志在環回接口中要被置位。核心檢測這個標志而不是將名字lo作為特殊接口硬寫<BR>入程序。<BR> <BR>IFF_POINTOPOINT<BR> <BR>點到點的初始化函數應置位這個標志。例如,plip對它置位。ifconfig工具也可以對其<BR>置位和清除。當它被置位時,dev->pa_dstaddr應該指向連接的另一端。<BR> <BR>IFF_NOARP<BR> <BR>常規網絡接口可以傳送ARP包。如果接口不能進行ARP,它必須置這個標志。例如,點到<BR>點接口并不需要運行ARP,它只能增加額外的通信,卻不能獲取任何有用的信息。snull<BR>不具有ARP能力,因此它要對其置位。<BR> <BR>IFF_PROMISC<BR> <BR>這個標志被置位以獲得雜類操作。在缺省情況下,以太網接口使用硬件過濾器以保證它<BR>只收到播送包和指向其硬件地址的包。而象tcpdump一類包監視器則在接口上設置雜類模<BR>式,以獲取經過接口傳輸介質的所有包。<BR> <BR>IFF_MULTICAST<BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>能進行選播傳送的接口要置這個標志。ether_setup在缺省情況下對其置位。所以如果你<BR>的驅動程序不支持選播,它必須在初始化時清除這個標志。<BR> <BR>IFF_ALLMULTI<BR> <BR>這個標志告訴接口接收所有的選播包。只有當IFF_MULTICAST被置位,而主機由進行選播<BR>路由時,核心對其置位。它對接口時只讀的。IFF_MULTICAST和IFF_ALLMULTI早在1.2版<BR>就已經定義了,但那時并未使用。在后面“選播”一節我們將看到它是如何使用的。<BR> <BR>IFF_MASTER<BR> <BR>IFF_SLAVE<BR> <BR>這些標志被加載均衡代碼使用。接口驅動程序不需要知道它們。<BR> <BR>IFF_NOTRAILERS<BR> <BR>IFF_RUNNING<BR> <BR>這些標志在Linux中不使用,只是為了和BSD兼容而存在。<BR> <BR>當一個程序改變IFF_UP,open和close方法會被調用。當IFF_UP或其它標志被修改時,se<BR></P></FONT><FONT
color=#ffffff size=3>
<P>當一個程序改變IFF_UP,open和close方法會被調用。當IFF_UP或其它標志被修改時,se<BR>t_multicast_list方法被調用。如果驅動程序因為標志的修改而要執行一些動作,那么<BR>必須在set_multicast_list中進行。例如,當IFF_PROMIS被置位或清除時,板上硬件過<BR>濾器必須被通知。這個設備方法的責任將在后面的“選播”一節簡單介紹。<BR> <BR> <BR> <BR>設備方法<BR> <BR>與字符設備和塊設備的情況一樣,每個網絡設備要聲明在其上操作的函數。可以在網絡<BR>接口上進行的操作列在下面。一些操作可以留為NULL,還有一些通常不去動它們,因為e<BR>ther_setup給它們分配合適的方法。<BR> <BR>一個網絡接口的設備方法可以分為兩類:基本的和可選的。基本的包括那些為訪問接口<BR>所需要的;可選的方法實現一些并不嚴格要求的高級功能。下面是基本方法:<BR> <BR>int (*open)(struct device *dev);<BR> <BR>打開接口。只要ifconfig激活一個接口,它就被打開了。open方法要注冊它需要的所有<BR>資源(I/O端口,IRQ,DMA,等),打開硬件,增加模塊的使用計數。<BR> <BR>int (*stop)(struct device *dev);<BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>終止接口。接口在關閉時就終止了;在打開時進行的操作應被保留。<BR> <BR>int (*hard_start_xmit)(struct sk_buff *skb, struct device *dev);<BR> <BR>硬件開始傳送。這個方法請求一個包的傳送。這個包含在一個套接字緩沖區結構(sk_bu<BR>ff)中。套接字緩沖區在下面介紹。<BR> <BR>int (*rebuild_header)(void *buf, struct device *dev, unsigned long raddr,<BR>struct sk_buffer *skb);<BR> <BR>這個函數用來在一個包傳送之前重構硬件包頭。這個以太網設備使用的缺省包頭用ARP向<BR>包中填入缺少的信息。snull驅動程序實現了它自己的這個方法,因為ARP并不在sn接口<BR>上運行。(在本章的后面會介紹ARP。)這個方法的參數是一些指針,分別指向硬件包頭<BR>,設備,“路由器地址”(包的初始目的地),以及被傳送的緩沖區。<BR> <BR>int (*hard_header)(struct sk_buffer *skb, struct device *dev, unsigned<BR>short type,<BR> <BR> void *daddr, void *saddr, unsigned len);<BR> <BR>硬件包頭。這個函數用以前獲取的源和目的地址構造包頭;它的任務是組織那些以參數<BR>的形式傳給它的信息。eth_header是以太網類接口的缺省函數, ether_setup相應地對<BR></P></FONT><FONT
color=#ffffff size=3>
<P>的形式傳給它的信息。eth_header是以太網類接口的缺省函數, ether_setup相應地對<BR>這個域賦值。給出的參數順序適用于核心2.0或更高版本,但與1.2有所不同。這個改變<BR>對以太網驅動程序是透明的,因為它繼承了 eth_header的實現;其它驅動程序可能要處<BR>理一下這個不同,如果它們想保持向后兼容的話。<BR> <BR>struct enet_statistics * (*get_stats)(struct device *dev);<BR> <BR>當應用希望獲得接口的統計信息時需要調用這個方法,例如,當運行ifconfig或netstat<BR> –i時。在snull中的一個示例實現將在后面“統計信息”中介紹。<BR> <BR>int (*set_config)(struct device *dev, struct ifmap *map);<BR> <BR>改變接口的配置。這個方法是配置驅動程序的入口點。設備的I/O地址和中斷號可以在運<BR>行時用set_config改變。在接口不能探測到時,系統管理員可以適用這個能力。這個方<BR>法在后面的“運行時配置”中介紹。<BR> <BR> <BR> <BR>其余的設備方法是被我稱為可選的那些。傳遞給其中一些的參數在Linux1.2到Linux2.0<BR>的轉變中改了好幾次。如果你想寫一個可以在兩個版本核心都工作的驅動程序,你可以<BR>只為從2.0開始的版本實現這些操作。<BR> <BR>int (*do_ioctl)(struct devices *dev, struct ifreg *ifr, int cmd);<BR></P></FONT><FONT
color=#ffffff size=3>
<P>int (*do_ioctl)(struct devices *dev, struct ifreg *ifr, int cmd);<BR> <BR>執行接口特定的ioctl命令。這些命令的實現在后面的“自定義ioctl命令”中描述。這<BR>里給出的原形在1.2以上的核心都能工作。如果接口不需要任何接口特定的命令,那么結<BR>構device中相應的域可以留為NULL。<BR> <BR>void (*set_multicast_list)(struct device *dev);<BR> <BR>當設備的選播列表改變和標志改變時,將調用這個方法。這里的參數傳遞與1.2版本不同<BR>。更多的細節和一個示例實現見“選播”一節。<BR> <BR>int (*set_mac_address)(struct device *dev, void *addr);<BR> <BR>如果接口支持改變硬件地址的能力,可實現這個函數。多數接口要么不支持這個能力,<BR>要么使用缺省的eth_mac_addr實現。這個原形與1.2版也不同。<BR> <BR>#define HAVE_HEADER_CACHE<BR> <BR>void (*header_cache_bind)(struct hh_cache **hhp, struct device *dev,<BR>unsigned short htype, __u32 daddr);<BR> <BR>void (*header_cache_update)(struct hh_cache *hh, struct device *dev,<BR>unsigned char *haddr);<BR></P></FONT><FONT
color=#ffffff size=3>
<P>unsigned char *haddr);<BR> <BR>這些函數和宏在Linux1.2中沒有。以太網驅動程序不必關心header_cache的問題,因為e<BR>th_setup會安排使用缺省的方法。<BR> <BR>#define HAVE_CACHE_MTU<BR> <BR>int (*change_mtu)(struct device *dev, int new_mtu);<BR> <BR>如果接口的MTU(最大傳送單元)發生了改變,這個函數負責采取動作。這個函數和宏在<BR>Linux1.2中都沒有。當MTU改變時,如果驅動程序要做一些特殊的事情,它應該聲明它自<BR>己的函數,不然將由缺省函數來完成。如果你感興趣,snull有一個這個函數的模版。<BR> <BR> <BR> <BR>工具域<BR> <BR>其余的結構device中的域被接口用來保存一些有用的狀態信息。其中一些被ifconfig和n<BR>etstat用來向用戶提供當前配置的信息。因此,接口應該對這些域賦值。<BR> <BR>unsigned long trans_start;<BR> <BR>unsigned long last_rx;<BR></P></FONT><FONT
color=#ffffff size=3>
<P>unsigned long last_rx;<BR> <BR>這兩個域用來保存一些瞬間值。它們目前不用,但核心有可能將來使用這些計時提示。<BR>驅動程序負責在傳送開始時和收到包時更新這些值。trans_start域還可以被驅動程序用<BR>來檢測鎖定。驅動程序可以在等待一個“傳送完成”的中斷時用trans_start來檢查超時<BR>。<BR> <BR>void *priv<BR> <BR>等價于filp->private_data。驅動程序擁有這個指針,可以隨意使用。通常這個私有數<BR>據結構含有一個enet_statistics結構項。這個域在以前的“初始化每個設備”中用過。<BR> <BR> <BR>unsigned char if_prot;<BR> <BR>這個域用來記錄哪個硬件端口被接口使用(例如,BNC,AUI,TP)。任何數值都可以按<BR>需要賦給它。<BR> <BR>unsigned char dma;<BR> <BR>被接口使用的DMA通道。這個域被ioctl的SIOCGIFMAP命令使用。<BR> <BR>struct dev_mc_list *mc_list;<BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>unsigned char dma;<BR> <BR>被接口使用的DMA通道。這個域被ioctl的SIOCGIFMAP命令使用。<BR> <BR>struct dev_mc_list *mc_list;<BR> <BR>int mc_count<BR> <BR>這兩個域被用來處理選播傳送。Mc_count是mc_list中項的個數。更多的細節見“選播”<BR>結構device中還有一些別的域,但驅動程序沒有使用它們<BR>--<BR><FONT
color=#00ff00>※ 來源:.華南網木棉站 bbs.gznet.edu.cn.[FROM: 202.38.196.234]</FONT><BR>--<BR><FONT
color=#00ffff>※ 轉寄:.華南網木棉站 bbs.gznet.edu.cn.[FROM: 211.80.41.106]</FONT><BR>--<BR><FONT
color=#0000ff>※ 轉寄:.華南網木棉站 bbs.gznet.edu.cn.[FROM: 211.80.41.106]</FONT><BR>--<BR><FONT
color=#ffff00>※ 轉載:.南京大學小百合站 bbs.nju.edu.cn.[FROM: 211.80.41.106]</FONT><BR>--<BR><FONT
color=#ff0000>※ 轉載:·飲水思源 bbs.sjtu.edu.cn·[FROM: 211.80.41.106]</FONT><BR></P></FONT>
<P align=center><A href="http://joyfire.net/lsdp/index.htm"><FONT
color=#ffffff size=2>目錄頁</FONT></A> | <A
href="http://joyfire.net/lsdp/16.htm"><FONT color=#ffffff
size=2>上一頁</FONT></A> | <A href="http://joyfire.net/lsdp/18.htm"><FONT
color=#ffffff size=2>下一頁</FONT></A></P></SPAN></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0>
<TBODY>
<TR>
<TD colSpan=3 height=2>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -