?? 網(wǎng)口程序?qū)嵗?txt
字號:
if (bpf) bpf為真,即加入了BSD包過濾
bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
if (ng_ether_attach_p != NULL)
(*ng_ether_attach_p)(ifp);
}
*/
printf("el%d: 3c501 address %6D\n",idev->;id_unit,
sc->;arpcom.ac_enaddr, ":");
dprintf(("el_attach() finished.\n"));
return(1);
}
/* 該例程重設(shè)接口. 在el_watchdog()中調(diào)用,因為watchdog不在本驅(qū)動程序中支持,所以從不被調(diào)用*/
static void
el_reset(xsc)/*上面的一個函數(shù),重設(shè)硬件*/
void *xsc;
{
struct el_softc *sc = xsc;
int s;
dprintf(("elreset()\n"));
s = splimp();/*關(guān)網(wǎng)絡(luò)中斷*/
el_stop(sc);/*下面的一個函數(shù)*/
el_init(sc);/*重新初始化卡*/
splx(s);/*開網(wǎng)絡(luò)中斷*/
}
/*停止接口,在el_ioctl()和el_reset()中調(diào)用*/
static void el_stop(xsc)
void *xsc;
{
struct el_softc *sc = xsc;
outb(sc->;el_base+EL_AC,0);/*用0寫輔助命令寄存器*/
}
/* 初始化接口. */
static void
el_init(xsc)
void *xsc;
{
struct el_softc *sc = xsc;
struct ifnet *ifp;
int s;
u_short base;
ifp = &sc->;arpcom.ac_if;/*定位ifnet結(jié)構(gòu)*/
base = sc->;el_base;/*網(wǎng)卡基本I/O地址*/
/* 如果地址不知道,什么也不做. */
if(TAILQ_EMPTY(&ifp->;if_addrhead)) /* 在if.c中的if_attach例程
中已經(jīng)填充,由el_attach調(diào)用
ether_attach時再調(diào)用if_attach */
return;
s = splimp();/*關(guān)網(wǎng)絡(luò)中斷*/
/* 重設(shè)板卡. */
dprintf(("Resetting board...\n"));
el_hardreset(sc);/*該函數(shù)在上面,重設(shè)硬件*/
/* 設(shè)置接收寄存器 rx */
dprintf(("Configuring rx...\n"));
if(ifp->;if_flags & IFF_PROMISC) /*是混雜模式?EL_RXC是0X6接收命令寄存器*/
outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
else
outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
outb(base+EL_RBC,0);/*接收緩沖寄存器清0*/
/* 設(shè)置傳輸寄存器 TX */
dprintf(("Configuring tx...\n"));
outb(base+EL_TXC,0);
/* 開始接收 */
dprintf(("Starting reception...\n"));
outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));/*EL_AC_IRQE是IRQ enable(可用) EL_AC_RX為接收寄存器*/
/* 設(shè)置一些開始使用的標志 */
ifp->;if_flags |= IFF_RUNNING;/*加上正在運行標志*/
ifp->;if_flags &= ~IFF_OACTIVE;/*去掉正在傳輸標志*/
/* 調(diào)用輸出. */
el_start(ifp);
splx(s);/*開網(wǎng)絡(luò)中斷*/
}
/* 開始在接口上輸出.從隊列中得到包并輸出他們,在輸出中,留出接收用一
部分時間,即打開中斷再關(guān)閉中斷,這樣使接口接到的一些數(shù)據(jù)包不會丟失.
*/
static void
el_start(struct ifnet *ifp)
{
struct el_softc *sc;
u_short base;
struct mbuf *m, *m0;
int s, i, len, retries, done;
/* 定位softc結(jié)構(gòu)的指針*/
sc = ifp->;if_softc;
base = sc->;el_base;/*基地址在輸入輸出指令時常要用到*/
dprintf(("el_start()...\n"));
s = splimp();/*因為下面涉及到if_flags的操作,所以要關(guān)閉網(wǎng)絡(luò)中斷*/
/* 如果輸出正在進行,則退出 */
if(sc->;arpcom.ac_if.if_flags & IFF_OACTIVE)
return;
sc->;arpcom.ac_if.if_flags |= IFF_OACTIVE;/*加上輸出正在進行傳輸標志*/
/* 主循環(huán)
*/
while(1) {/*唯一出口是準備傳輸?shù)臄?shù)據(jù)為空,即m0==NULL時*/
/* 從隊列中移出下一數(shù)據(jù)包到m0中,請看頭文件if_var.h
#define IF_DEQUEUE(ifq, m) { \
(m) = (ifq)->;ifq_head; \ ifq是一mbuf指針隊列,把第一個mbuf指針放到m中
if (m) { \
if (((ifq)->;ifq_head = (m)->;m_nextpkt) == 0) \重排隊列
(ifq)->;ifq_tail = 0; \
(m)->;m_nextpkt = 0; \
(ifq)->;ifq_len--; \
} \
}
*/
IF_DEQUEUE(&sc->;arpcom.ac_if.if_snd,m0);/* &sc->;arpcom.ac_if.if_snd指向發(fā)送隊列,
該宏取出第一個mubf的指針放到m0中,看上面的說明.
這是數(shù)據(jù)結(jié)構(gòu)的好教材*/
/* 如果發(fā)送緩沖區(qū)指針為空,即已經(jīng)發(fā)送完,則退出,此是該無窮循環(huán)的唯一出口. */
if(m0 == NULL) {
sc->;arpcom.ac_if.if_flags &= ~IFF_OACTIVE;/*出去前當然要去掉輸出正在進行標志*/
splx(s);
return;
}
/* 關(guān)閉接收 */
outb(base+EL_AC,EL_AC_HOST);/*EL_AC_HOST為系統(tǒng)總線可訪問緩沖,即系統(tǒng)總線網(wǎng)卡要用 */
outb(base+EL_RBC,0);/*接收緩沖寄存器清0*/
/* 拷貝mbuf中的數(shù)據(jù)到softc結(jié)構(gòu)定義的成員el_pktbuf中,緩沖大小是EL_BUFSIZ即2048. */
len = 0;
for(m = m0; m != NULL; m = m->;m_next) { /* m0是一mbuf指針,也是一mbuf鏈的第一個,此
次要發(fā)送的是一mbuf鏈,不是一單個mbuf*/
if(m->;m_len == 0)
continue;
bcopy(mtod(m,caddr_t),sc->;el_pktbuf+len,m->;m_len);/*m->;len是該mbuf鏈的數(shù)據(jù)長度,
sc->;el_pktbuf是該卡的發(fā)送臨時緩沖,要發(fā)
送的數(shù)據(jù)在這集中,然后傳送到網(wǎng)卡上,太費
時間了,應(yīng)該直接放置到網(wǎng)卡的存儲器中.*/
len += m->;m_len; /*len是這次要發(fā)送的總數(shù)*/
}
m_freem(m0); /*釋放該mbuf鏈*/
len = max(len,ETHER_MIN_LEN); /*ETHER_MIN_LEN是發(fā)送的最小長度*/
/* 如果有BPF,就交給BPF驗證 */
if(sc->;arpcom.ac_if.if_bpf)
bpf_tap(&sc->;arpcom.ac_if, sc->;el_pktbuf, len);/*你當然可以在這寫一點自己的驗證過程*/
/* 傳送數(shù)據(jù)包到板卡 */
dprintf(("el: xfr pkt length=%d...\n",len));
i = EL_BUFSIZ - len;/*EL_BUFSIZ=2048字節(jié)*/
outb(base+EL_GPBL,(i & 0xff)); /*告訴發(fā)送的長度*/
outb(base+EL_GPBH,((i>;>;8)&0xff));
outsb(base+EL_BUF,sc->;el_pktbuf,len);/*傳輸數(shù)據(jù)到板卡*/
/* 開始發(fā)送數(shù)據(jù)包 */
retries=0;/*下面做循環(huán)用的,在發(fā)不出去時,循環(huán)15次*/
done=0; /*done=1時發(fā)送成功了*/
while(!done) {
if(el_xmit(sc,len)) { /* 調(diào)用發(fā)送例程,其實只要傳送base就可以了 */
done = -1;
break;
}
/* 檢查輸出后的狀態(tài),如果你要對watchdog支持,可以在這加上代碼,即在5毫秒沒發(fā)送出去,就調(diào)用el_watchdog() */
i = inb(base+EL_TXS);
dprintf(("tx status=0x%x\n",i));
if(!(i & EL_TXS_READY)) { /* 如果傳輸狀態(tài)寄存器不是準備接受新幀就緒 */
dprintf(("el: err txs=%x\n",i)); /*那就是出錯了*/
sc->;arpcom.ac_if.if_oerrors++;
if(i & (EL_TXS_COLL|EL_TXS_COLL16)) {/*網(wǎng)絡(luò)數(shù)據(jù)包碰撞*/
if((!(i & EL_TXC_DCOLL16)) && retries < 15) {/*做循環(huán)的目的是為了有錯誤時可重傳15次*/
retries++;
outb(base+EL_AC,EL_AC_HOST);/*EL_AC_HOST為系統(tǒng)總線可訪問緩沖 */
}
}
else
done = 1;
}
else {
sc->;arpcom.ac_if.if_opackets++;/*統(tǒng)計用的,說明該卡成功發(fā)送一包*/
done = 1;
}
}
if(done == -1) /* 包沒有傳輸(失敗) */
continue;
/* 現(xiàn)在給板卡一個機會接收.注意:在linux中曾經(jīng)ALEN先生批評此卡好恐怖(他說要進博物館,哈哈),并說在傳輸時
會丟失進來的數(shù)據(jù)包,我查看了LINUX的驅(qū)動程序,確實是這樣,但在FreeBSD中,給了一個機會,由此可證明他的
關(guān)于"丟失包的說法不一定成立",但關(guān)于一個緩沖和一次只能發(fā)送一數(shù)據(jù)包的說法確實是真的,還有多播方面也
不支持,我也希望大家最好不要去買這東西,和NE2000,PCI中的RTL8139芯片的網(wǎng)卡一樣,性能太差了.*/
(void)inb(base+EL_AS);/*讀輔助狀態(tài)寄存器*/
outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));/* 用IRQ(中斷)使能和接收 寫輔助命令寄存器*/
splx(s);
/* 這有可能接收到中斷(包到達) */
s = splimp();
}
}
/* 這是真正的傳輸包,由el_start()調(diào)用
*/
static int
el_xmit(struct el_softc *sc,int len)
{
int gpl;
int i;
gpl = EL_BUFSIZ - len;
dprintf(("el: xmit..."));
outb((sc->;el_base)+EL_GPBL,(gpl & 0xff));
outb((sc->;el_base)+EL_GPBH,((gpl>;>;8)&0xff));
outb((sc->;el_base)+EL_AC,EL_AC_TXFRX);/*真正的傳送指令*/
i = 20000;
while((inb((sc->;el_base)+EL_AS) & EL_AS_TXBUSY) && (i>;0))/*如果傳送還在忙,循環(huán)20000次等待*/
i--;
if(i == 0) {/*這里有一個bug,大家發(fā)現(xiàn)沒有,i到了0時也有可能傳送成功,解決辦法是把(i>;0)這條件放到前面*/
/*我稍微講一下C,在編譯C程序時,象while ( (a>;b) && (i>;0) )時,是這個樣子
top:if a>;b then
if i>;0 then
執(zhí)行體
endif
endif
goto top
也就是說,當i=0時候,inb((sc->;el_base)+EL_AS)這指令還會執(zhí)行,也有可能這時候傳送完成了,而下面有給打出
一個什么"tx not ready"的東東,而且返回失敗,有得重新傳送一次.
*/
dprintf(("tx not ready\n"));
sc->;arpcom.ac_if.if_oerrors++;
return(-1);
}
dprintf(("%d cycles.\n",(20000-i)));
return(0);/*成功*/
}
/* 傳遞包到更高一級協(xié)議處理,即ether_input()例程.由elintr()調(diào)用 */
static __inline void
elread(struct el_softc *sc,caddr_t buf,int len)
{
register struct ether_header *eh;
struct mbuf *m;
eh = (struct ether_header *)buf;/*從buf中分出以太網(wǎng)頭部*/
/*
* elget函數(shù)是把包放入一mbuf緩沖鏈中
*/
m = elget(buf,len,&sc->;arpcom.ac_if);
if(m == 0)/*出錯了*/
return;
ether_input(&sc->;arpcom.ac_if,eh,m);/*傳輸給上一層的包括ifnet結(jié)構(gòu),以太網(wǎng)頭部,一mbuf*/
}
/* 中斷例程 */
static void
elintr(int unit)
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -