显示驱动包含在Linux内核层,驱动程序层(上) - Linux内核--网络栈实现分析_Linux编程_Linux公社-Linux系统门户网站...
經(jīng)過(guò)前面兩篇博文的分析,已經(jīng)對(duì)Linux的內(nèi)核網(wǎng)絡(luò)棧的結(jié)構(gòu)有了一個(gè)模糊的認(rèn)識(shí),這里我們開(kāi)始從底層開(kāi)始詳細(xì)分析Linux內(nèi)核網(wǎng)絡(luò)棧的實(shí)現(xiàn)。由于這是早期版本,代碼的層次隔離做的還不是很好,這里說(shuō)是從底層分析,但是不免會(huì)牽扯上層或下層的函數(shù),許多關(guān)鍵代碼都在驅(qū)動(dòng)的文件夾下。
我們首先有第一篇博文中知道在網(wǎng)絡(luò)棧初始化的時(shí)候在net/socket.c中的函數(shù)sock_init()函數(shù)中當(dāng)proto_init()完成后會(huì)執(zhí)行dev_init()來(lái)進(jìn)行網(wǎng)絡(luò)設(shè)備模塊的初始化。
首先說(shuō)明一下,在drivers/net/space.c中定義了設(shè)備首節(jié)點(diǎn)地址dev_base,其實(shí)際上是回環(huán)設(shè)備的地址。
structdevice?loopback_dev?=?{
"lo",/*?Software?Loopback?interface??????*/
0x0,/*?recv?memory?end??????????*/
0x0,/*?recv?memory?start????????????*/
0x0,/*?memory?end???????????????*/
0x0,/*?memory?start?????????????*/
0,/*?base?I/O?address?????????*/
0,/*?IRQ??????????????????*/
0,?0,?0,/*?flags????????????????*/
NEXT_DEV,/*?next?device??????????????*/
loopback_init/*?loopback_init?should?set?up?the?rest?*/
};
structdevice?*dev_base?=?&loopback_dev;而NEXT_DEV宏定義即定義了下一個(gè)網(wǎng)絡(luò)設(shè)備的地址,這樣可以把設(shè)備串成鏈。
附網(wǎng)絡(luò)設(shè)備的定義(include/linux/netdevice.h)如下:
/*
*?The?DEVICE?structure.
*?Actually,?this?whole?structure?is?a?big?mistake.??It?mixes?I/O
*?data?with?strictly?"high-level"?data,?and?it?has?to?know?about
*?almost?every?data?structure?used?in?the?INET?module.
*/
structdevice
{
/*
*?This?is?the?first?field?of?the?"visible"?part?of?this?structure
*?(i.e.?as?seen?by?users?in?the?"Space.c"?file).??It?is?the?name
*?the?interface.
*/
char*name;
/*?I/O?specific?fields?-?FIXME:?Merge?these?and?struct?ifmap?into?one?*/
unsignedlongrmem_end;/*?shmem?"recv"?end?*/
unsignedlongrmem_start;/*?shmem?"recv"?start???*/
unsignedlongmem_end;/*?sahared?mem?end??*/
unsignedlongmem_start;/*?shared?mem?start?*/
unsignedlongbase_addr;/*?device?I/O?address???*/
unsignedcharirq;/*?device?IRQ?number????*/
/*?Low-level?status?flags.?*/
volatileunsignedcharstart,/*?start?an?operation???*/
tbusy,/*?transmitter?busy?*/
interrupt;/*?interrupt?arrived????*/
structdevice???????*next;
/*?The?device?initialization?function.?Called?only?once.?*/
int(*init)(structdevice?*dev);
/*?Some?hardware?also?needs?these?fields,?but?they?are?not?part?of?the
usual?set?specified?in?Space.c.?*/
unsignedcharif_port;/*?Selectable?AUI,?TP,..*/
unsignedchardma;/*?DMA?channel??????*/
structenet_statistics*?(*get_stats)(structdevice?*dev);
/*
*?This?marks?the?end?of?the?"visible"?part?of?the?structure.?All
*?fields?hereafter?are?internal?to?the?system,?and?may?change?at
*?will?(read:?may?be?cleaned?up?at?will).
*/
/*?These?may?be?needed?for?future?network-power-down?code.?*/
unsignedlongtrans_start;/*?Time?(in?jiffies)?of?last?Tx?*/
unsignedlonglast_rx;/*?Time?of?last?Rx??????*/
unsignedshortflags;/*?interface?flags?(a?la?BSD)???*/
unsignedshortfamily;/*?address?family?ID?(AF_INET)??*/
unsignedshortmetric;/*?routing?metric?(not?used)????*/
unsignedshortmtu;/*?interface?MTU?value??????*/
unsignedshorttype;/*?interface?hardware?type??*/
unsignedshorthard_header_len;/*?hardware?hdr?length??*/
void*priv;/*?pointer?to?private?data??*/
/*?Interface?address?info.?*/
unsignedcharbroadcast[MAX_ADDR_LEN];/*?hw?bcast?add?*/
unsignedchardev_addr[MAX_ADDR_LEN];/*?hw?address???*/
unsignedcharaddr_len;/*?hardware?address?length??*/
unsignedlongpa_addr;/*?protocol?address?????*/
unsignedlongpa_brdaddr;/*?protocol?broadcast?addr??*/
unsignedlongpa_dstaddr;/*?protocol?P-P?other?side?addr?*/
unsignedlongpa_mask;/*?protocol?netmask?????*/
unsignedshortpa_alen;/*?protocol?address?length??*/
structdev_mc_list?????*mc_list;/*?Multicast?mac?addresses??*/
intmc_count;/*?Number?of?installed?mcasts???*/
structip_mc_list??*ip_mc_list;/*?IP?multicast?filter?chain????*/
/*?For?load?balancing?driver?pair?support?*/
unsignedlongpkt_queue;/*?Packets?queued?*/
structdevice???????*slave;/*?Slave?device?*/
/*?Pointer?to?the?interface?buffers.?*/
structsk_buff_head?????buffs[DEV_NUMBUFFS];
/*?Pointers?to?interface?service?routines.?*/
int(*open)(structdevice?*dev);
int(*stop)(structdevice?*dev);
int(*hard_start_xmit)?(structsk_buff?*skb,
structdevice?*dev);
int(*hard_header)?(unsignedchar*buff,
structdevice?*dev,
unsignedshorttype,
void*daddr,
void*saddr,
unsigned?len,
structsk_buff?*skb);
int(*rebuild_header)(void*eth,structdevice?*dev,
unsignedlongraddr,structsk_buff?*skb);
unsignedshort(*type_trans)?(structsk_buff?*skb,
structdevice?*dev);
#define?HAVE_MULTICAST
void(*set_multicast_list)(structdevice?*dev,
intnum_addrs,void*addrs);
#define?HAVE_SET_MAC_ADDR
int(*set_mac_address)(structdevice?*dev,void*addr);
#define?HAVE_PRIVATE_IOCTL
int(*do_ioctl)(structdevice?*dev,structifreq?*ifr,intcmd);
#define?HAVE_SET_CONFIG
int(*set_config)(structdevice?*dev,structifmap?*map);
};dev_init()網(wǎng)絡(luò)設(shè)備的初始化函數(shù)如下:
/*
*??Initialize?the?DEV?module.?At?boot?time?this?walks?the?device?list?and
*??unhooks?any?devices?that?fail?to?initialise?(normally?hardware?not
*??present)?and?leaves?us?with?a?valid?list?of?present?and?active?devices.
*
*??The?PCMCIA?code?may?need?to?change?this?a?little,?and?add?a?pair
*??of?register_inet_device()?unregister_inet_device()?calls.?This?will?be
*??needed?for?ethernet?as?modules?support.
*/
voiddev_init(void)
{
structdevice?*dev,?*dev2;
/*
*??Add?the?devices.
*??If?the?call?to?dev->init?fails,?the?dev?is?removed
*??from?the?chain?disconnecting?the?device?until?the
*??next?reboot.
*/
dev2?=?NULL;
for(dev?=?dev_base;?dev?!=?NULL;?dev=dev->next)//循環(huán)移除設(shè)備由璞傅絛ev_base指向的網(wǎng)絡(luò)設(shè)備鏈表
{
if(dev->init?&&?dev->init(dev))//如果設(shè)備有初始化函數(shù)并且初始化失敗,則從鏈表摘除設(shè)備(init()函數(shù)成功返回0)
{
/*
*??It?failed?to?come?up.?Unhook?it.這個(gè)函數(shù)還挺有技巧性的,從默認(rèn)配置的設(shè)備中掃描不存在的設(shè)備,將其移除
*/
if(dev2?==?NULL)
dev_base?=?dev->next;
else
dev2->next?=?dev->next;
}
else
{
dev2?=?dev;
}
}
}這里我們看一下dev_base這個(gè)隊(duì)列是如何定義的,這里我們僅僅看eth網(wǎng)卡的定義方式即可
/*?"eth0"?defaults?to?autoprobe?(==?0),?other?use?a?base?of?0xffe0?(==?-0x20),
which?means?"don't?probe".??These?entries?exist?to?only?to?provide?empty
slots?which?may?be?enabled?at?boot-time.?*/
staticstructdevice?eth3_dev?=?{
"eth3",?0,0,0,0,0xffe0/*?I/O?base*/,?0,0,0,0,?NEXT_DEV,?ethif_probe?};
staticstructdevice?eth2_dev?=?{
"eth2",?0,0,0,0,0xffe0/*?I/O?base*/,?0,0,0,0,?e3_dev,?ethif_probe?};
staticstructdevice?eth1_dev?=?{
"eth1",?0,0,0,0,0xffe0/*?I/O?base*/,?0,0,0,0,?e2_dev,?ethif_probe?};
staticstructdevice?eth0_dev?=?{
"eth0",?0,?0,?0,?0,?ETH0_ADDR,?ETH0_IRQ,?0,?0,?0,?e1_dev,?ethif_probe?};
#???undef?NEXT_DEV
#???define?NEXT_DEV?(e0_dev)可以看出eth系列網(wǎng)卡設(shè)備的init函數(shù)定義為ethif_probe(),該函數(shù)會(huì)調(diào)用具體網(wǎng)卡的探測(cè)函數(shù),我們還是以?NS8390 ethernet網(wǎng)卡為例來(lái)分析,該網(wǎng)卡的驅(qū)動(dòng)實(shí)現(xiàn)文件為drivers/net/ne.c
ethif_probe()函數(shù)會(huì)調(diào)用函數(shù)ne_probe()探測(cè)函數(shù),而該函數(shù)對(duì)設(shè)備地址進(jìn)行檢查后調(diào)用ne_probe1()函數(shù),具體工作有ne_probe1()函數(shù)完成。
函數(shù)如下:
staticintne_probe1(structdevice?*dev,intioaddr)
{
.....................//合法性檢查
/*?Fixup?for?users?that?don't?know?that?IRQ?2?is?really?IRQ?9,
or?don't?know?which?one?to?set.?*/
dev->irq?=?9;//設(shè)置中斷類(lèi)型號(hào)
/*?Snarf?the?interrupt?now.??There's?no?point?in?waiting?since?we?cannot
share?and?the?board?will?usually?be?enabled.?*/
{
intirqval?=?request_irq?(dev->irq,?ei_interrupt,?0,?wordlength==2??"ne2000":"ne1000");//注冊(cè)申請(qǐng)中斷,中斷處理函數(shù)為ei_interrupt
if(irqval)?{
printk?("?unable?to?get?IRQ?%d?(irqval=%d).\n",?dev->irq,?irqval);
returnEAGAIN;
}
}
dev->base_addr?=?ioaddr;
request_region(ioaddr,?NE_IO_EXTENT,?wordlength==2??"ne2000":"ne1000");//申請(qǐng)內(nèi)存空間
for(i?=?0;?i?
dev->dev_addr[i]?=?SA_prom[i];
ethdev_init(dev);//調(diào)用函數(shù)對(duì)dev設(shè)備結(jié)構(gòu)體進(jìn)行初始化
printk("\n%s:?%s?found?at?%#x,?using?IRQ?%d.\n",
dev->name,?name,?ioaddr,?dev->irq);
if(ei_debug?>?0)
printk(version);
ei_status.name?=?name;
ei_status.tx_start_page?=?start_page;
ei_status.stop_page?=?stop_page;
ei_status.word16?=?(wordlength?==?2);
ei_status.rx_start_page?=?start_page?+?TX_PAGES;
#ifdef?PACKETBUF_MEMSIZE
/*?Allow?the?packet?buffer?size?to?be?overridden?by?know-it-alls.?*/
ei_status.stop_page?=?ei_status.tx_start_page?+?PACKETBUF_MEMSIZE;
#endif
ei_status.reset_8390?=?&ne_reset_8390;
ei_status.block_input?=?&ne_block_input;
ei_status.block_output?=?&ne_block_output;
NS8390_init(dev,?0);//配置網(wǎng)卡中的寄存器等到默認(rèn)狀態(tài)
return0;
}初始化函數(shù)ethdev_init()在文件drivers/net/8390.c中。如下:
/*?Initialize?the?rest?of?the?8390?device?structure.?*/
intethdev_init(structdevice?*dev)
{
if(ei_debug?>?1)
printk(version);
if(dev->priv?==?NULL)?{//申請(qǐng)私有空間存儲(chǔ)具體網(wǎng)卡的結(jié)構(gòu)體信息
structei_device?*ei_local;//8390網(wǎng)卡設(shè)備的結(jié)構(gòu)體
dev->priv?=?kmalloc(sizeof(structei_device),?GFP_KERNEL);//申請(qǐng)內(nèi)核內(nèi)存空間
memset(dev->priv,?0,sizeof(structei_device));
ei_local?=?(structei_device?*)dev->priv;
#ifndef?NO_PINGPONG
ei_local->pingpong?=?1;
#endif
}
/*?The?open?call?may?be?overridden?by?the?card-specific?code.?*/
if(dev->open?==?NULL)
dev->open?=?&ei_open;//設(shè)備的打開(kāi)函數(shù)
/*?We?should?have?a?dev->stop?entry?also.?*/
dev->hard_start_xmit?=?&ei_start_xmit;//設(shè)備的發(fā)送函數(shù),定義在8390.c中
dev->get_stats???=?get_stats;
#ifdef?HAVE_MULTICAST
dev->set_multicast_list?=?&set_multicast_list;
#endif
ether_setup(dev);//進(jìn)一步調(diào)用函數(shù)設(shè)置dev設(shè)備結(jié)構(gòu)體
return0;
}ether_setup()函數(shù)的實(shí)現(xiàn)如下:
voidether_setup(structdevice?*dev)
{
inti;
/*?Fill?in?the?fields?of?the?device?structure?with?ethernet-generic?values.
This?should?be?in?a?common?file?instead?of?per-driver.??*/
for(i?=?0;?i?
skb_queue_head_init(&dev->buffs[i]);//緩沖隊(duì)列初始化
/*?register?boot-defined?"eth"?devices?*/
if(dev->name?&&?(strncmp(dev->name,"eth",?3)?==?0))?{//定義eth網(wǎng)卡的名稱(chēng)
i?=?simple_strtoul(dev->name?+?3,?NULL,?0);
if(ethdev_index[i]?==?NULL)?{
ethdev_index[i]?=?dev;
}
elseif(dev?!=?ethdev_index[i])?{
/*?Really?shouldn't?happen!?*/
printk("ether_setup:?Ouch!?Someone?else?took?%s\n",
dev->name);
}
}
dev->hard_header?=?eth_header;//該函數(shù)的作用是創(chuàng)建鏈路層首部,定義在eth.c中
dev->rebuild_header?=?eth_rebuild_header;//該函數(shù)的作用是重建鏈路層首部,用于ARP協(xié)議
dev->type_trans?=?eth_type_trans;
dev->type????????=?ARPHRD_ETHER;
dev->hard_header_len?=?ETH_HLEN;
dev->mtu?????=?1500;/*?eth_mtu?*/
dev->addr_len????=?ETH_ALEN;
for(i?=?0;?i?
dev->broadcast[i]=0xff;
}
/*?New-style?flags.?*/
dev->flags???????=?IFF_BROADCAST|IFF_MULTICAST;
dev->family??????=?AF_INET;
dev->pa_addr?=?0;
dev->pa_brdaddr?=?0;
dev->pa_mask?=?0;
dev->pa_alen?=sizeof(unsignedlong);
}這樣,網(wǎng)絡(luò)設(shè)備的初始化工作就完成了。
在drivers/net/8390.c中實(shí)現(xiàn)了該網(wǎng)卡的設(shè)備的基本操作函數(shù),
設(shè)備的打開(kāi)函數(shù)ei_open()比較簡(jiǎn)單,下面列出該設(shè)備的發(fā)送和接收函數(shù),在這里不做具體的分析,如果想更多了解請(qǐng)點(diǎn)擊前面分析過(guò)的DM9000網(wǎng)卡驅(qū)動(dòng),下面給出鏈接:
ei_start_xmit()
staticintei_start_xmit(structsk_buff?*skb,structdevice?*dev)
{
inte8390_base?=?dev->base_addr;
structei_device?*ei_local?=?(structei_device?*)?dev->priv;
intlength,?send_length;
unsignedlongflags;
/*
*??We?normally?shouldn't?be?called?if?dev->tbusy?is?set,?but?the
*??existing?code?does?anyway.?If?it?has?been?too?long?since?the
*??last?Tx,?we?assume?the?board?has?died?and?kick?it.
*/
if(dev->tbusy)?{/*?Do?timeouts,?just?like?the?8003?driver.?*/
inttxsr?=?inb(e8390_base+EN0_TSR),?isr;
inttickssofar?=?jiffies?-?dev->trans_start;
if(tickssofar?
return1;
}
isr?=?inb(e8390_base+EN0_ISR);
if(dev->start?==?0)?{
printk("%s:?xmit?on?stopped?card\n",?dev->name);
return1;
}
printk(KERN_DEBUG"%s:?transmit?timed?out,?TX?status?%#2x,?ISR?%#2x.\n",
dev->name,?txsr,?isr);
/*?Does?the?8390?thinks?it?has?posted?an?interrupt??*/
if(isr)
printk(KERN_DEBUG"%s:?Possible?IRQ?conflict?on?IRQ%d?\n",?dev->name,?dev->irq);
else{
/*?The?8390?probably?hasn't?gotten?on?the?cable?yet.?*/
printk(KERN_DEBUG"%s:?Possible?network?cable?problem?\n",?dev->name);
if(ei_local->stat.tx_packets==0)
ei_local->interface_num?^=?1;/*?Try?a?different?xcvr.??*/
}
/*?Try?to?restart?the?card.??Perhaps?the?user?has?fixed?something.?*/
ei_reset_8390(dev);
NS8390_init(dev,?1);
dev->trans_start?=?jiffies;
}
/*?Sending?a?NULL?skb?means?some?higher?layer?thinks?we've?missed?an
tx-done?interrupt.?Caution:?dev_tint()?handles?the?cli()/sti()
itself.?*/
if(skb?==?NULL)?{
dev_tint(dev);
return0;
}
length?=?skb->len;
if(skb->len?<=?0)
return0;
save_flags(flags);
cli();
/*?Block?a?timer-based?transmit?from?overlapping.?*/
if((set_bit(0,?(void*)&dev->tbusy)?!=?0)?||?ei_local->irqlock)?{
printk("%s:?Tx?access?conflict.?irq=%d?lock=%d?tx1=%d?tx2=%d?last=%d\n",
dev->name,?dev->interrupt,?ei_local->irqlock,?ei_local->tx1,
ei_local->tx2,?ei_local->lasttx);
restore_flags(flags);
return1;
}
/*?Mask?interrupts?from?the?ethercard.?*/
outb(0x00,?e8390_base?+?EN0_IMR);
ei_local->irqlock?=?1;
restore_flags(flags);
send_length?=?ETH_ZLEN?
if(ei_local->pingpong)?{
intoutput_page;
if(ei_local->tx1?==?0)?{
output_page?=?ei_local->tx_start_page;
ei_local->tx1?=?send_length;
if(ei_debug??&&??ei_local->tx2?>?0)
printk("%s:?idle?transmitter?tx2=%d,?lasttx=%d,?txing=%d.\n",
dev->name,?ei_local->tx2,?ei_local->lasttx,
ei_local->txing);
}elseif(ei_local->tx2?==?0)?{
output_page?=?ei_local->tx_start_page?+?6;
ei_local->tx2?=?send_length;
if(ei_debug??&&??ei_local->tx1?>?0)
printk("%s:?idle?transmitter,?tx1=%d,?lasttx=%d,?txing=%d.\n",
dev->name,?ei_local->tx1,?ei_local->lasttx,
ei_local->txing);
}else{/*?We?should?never?get?here.?*/
if(ei_debug)
printk("%s:?No?Tx?buffers?free.?irq=%d?tx1=%d?tx2=%d?last=%d\n",
dev->name,?dev->interrupt,?ei_local->tx1,
ei_local->tx2,?ei_local->lasttx);
ei_local->irqlock?=?0;
dev->tbusy?=?1;
outb_p(ENISR_ALL,?e8390_base?+?EN0_IMR);
return1;
}
ei_block_output(dev,?length,?skb->data,?output_page);
if(!?ei_local->txing)?{
ei_local->txing?=?1;
NS8390_trigger_send(dev,?send_length,?output_page);
dev->trans_start?=?jiffies;
if(output_page?==?ei_local->tx_start_page)
ei_local->tx1?=?-1,?ei_local->lasttx?=?-1;
else
ei_local->tx2?=?-1,?ei_local->lasttx?=?-2;
}else
ei_local->txqueue++;
dev->tbusy?=?(ei_local->tx1??&&??ei_local->tx2);
}else{/*?No?pingpong,?just?a?single?Tx?buffer.?*/
ei_block_output(dev,?length,?skb->data,?ei_local->tx_start_page);
ei_local->txing?=?1;
NS8390_trigger_send(dev,?send_length,?ei_local->tx_start_page);
dev->trans_start?=?jiffies;
dev->tbusy?=?1;
}
/*?Turn?8390?interrupts?back?on.?*/
ei_local->irqlock?=?0;
outb_p(ENISR_ALL,?e8390_base?+?EN0_IMR);
dev_kfree_skb?(skb,?FREE_WRITE);
return0;
}ei_receive()函數(shù)
staticvoidei_receive(structdevice?*dev)
{
inte8390_base?=?dev->base_addr;
structei_device?*ei_local?=?(structei_device?*)?dev->priv;
intrxing_page,?this_frame,?next_frame,?current_offset;
intrx_pkt_count?=?0;
structe8390_pkt_hdr?rx_frame;
intnum_rx_pages?=?ei_local->stop_page-ei_local->rx_start_page;
while(++rx_pkt_count?
intpkt_len;
/*?Get?the?rx?page?(incoming?packet?pointer).?*/
outb_p(E8390_NODMA+E8390_PAGE1,?e8390_base?+?E8390_CMD);
rxing_page?=?inb_p(e8390_base?+?EN1_CURPAG);
outb_p(E8390_NODMA+E8390_PAGE0,?e8390_base?+?E8390_CMD);
/*?Remove?one?frame?from?the?ring.??Boundary?is?always?a?page?behind.?*/
this_frame?=?inb_p(e8390_base?+?EN0_BOUNDARY)?+?1;
if(this_frame?>=?ei_local->stop_page)
this_frame?=?ei_local->rx_start_page;
/*?Someday?we'll?omit?the?previous,?iff?we?never?get?this?message.
(There?is?at?least?one?clone?claimed?to?have?a?problem.)??*/
if(ei_debug?>?0??&&??this_frame?!=?ei_local->current_page)
printk("%s:?mismatched?read?page?pointers?%2x?vs?%2x.\n",
dev->name,?this_frame,?ei_local->current_page);
if(this_frame?==?rxing_page)/*?Read?all?the?frames??*/
break;/*?Done?for?now?*/
current_offset?=?this_frame?<
ei_block_input(dev,sizeof(rx_frame),?(char*)&rx_frame,
current_offset);
pkt_len?=?rx_frame.count?-sizeof(rx_frame);
next_frame?=?this_frame?+?1?+?((pkt_len+4)>>8);
/*?Check?for?bogosity?warned?by?3c503?book:?the?status?byte?is?never
written.??This?happened?a?lot?during?testing!?This?code?should?be
cleaned?up?someday.?*/
if(rx_frame.next?!=?next_frame
&&?rx_frame.next?!=?next_frame?+?1
&&?rx_frame.next?!=?next_frame?-?num_rx_pages
&&?rx_frame.next?!=?next_frame?+?1?-?num_rx_pages)?{
ei_local->current_page?=?rxing_page;
outb(ei_local->current_page-1,?e8390_base+EN0_BOUNDARY);
ei_local->stat.rx_errors++;
continue;
}
if(pkt_len??1518)?{
if(ei_debug)
printk("%s:?bogus?packet?size:?%d,?status=%#2x?nxpg=%#2x.\n",
dev->name,?rx_frame.count,?rx_frame.status,
rx_frame.next);
ei_local->stat.rx_errors++;
}elseif((rx_frame.status?&?0x0F)?==?ENRSR_RXOK)?{
structsk_buff?*skb;
skb?=?alloc_skb(pkt_len,?GFP_ATOMIC);
if(skb?==?NULL)?{
if(ei_debug?>?1)
printk("%s:?Couldn't?allocate?a?sk_buff?of?size?%d.\n",
dev->name,?pkt_len);
ei_local->stat.rx_dropped++;
break;
}else{
skb->len?=?pkt_len;
skb->dev?=?dev;
ei_block_input(dev,?pkt_len,?(char*)?skb->data,
current_offset?+sizeof(rx_frame));
netif_rx(skb);
ei_local->stat.rx_packets++;
}
}else{
interrs?=?rx_frame.status;
if(ei_debug)
printk("%s:?bogus?packet:?status=%#2x?nxpg=%#2x?size=%d\n",
dev->name,?rx_frame.status,?rx_frame.next,
rx_frame.count);
if(errs?&?ENRSR_FO)
ei_local->stat.rx_fifo_errors++;
}
next_frame?=?rx_frame.next;
/*?This?_should_?never?happen:?it's?here?for?avoiding?bad?clones.?*/
if(next_frame?>=?ei_local->stop_page)?{
printk("%s:?next?frame?inconsistency,?%#2x\n",?dev->name,
next_frame);
next_frame?=?ei_local->rx_start_page;
}
ei_local->current_page?=?next_frame;
outb_p(next_frame-1,?e8390_base+EN0_BOUNDARY);
}
/*?If?any?worth-while?packets?have?been?received,?dev_rint()
has?done?a?mark_bh(NET_BH)?for?us?and?will?work?on?them
when?we?get?to?the?bottom-half?routine.?*/
/*?Record?the?maximum?Rx?packet?queue.?*/
if(rx_pkt_count?>?high_water_mark)
high_water_mark?=?rx_pkt_count;
/*?Bug?alert!??Reset?ENISR_OVER?to?avoid?spurious?overruns!?*/
outb_p(ENISR_RX+ENISR_RX_ERR+ENISR_OVER,?e8390_base+EN0_ISR);
return;
}
總結(jié)
以上是生活随笔為你收集整理的显示驱动包含在Linux内核层,驱动程序层(上) - Linux内核--网络栈实现分析_Linux编程_Linux公社-Linux系统门户网站...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux修改响应时间,linux下使用
- 下一篇: linux ftp做yum源,在RedH