赞
踩
先来介绍下,物理层网卡的硬件驱动,实验板采用的是Xscale的CPU,网卡芯片是CS8900,运行的操作系统为Linux2.4的核,很多代码在2.6中已经有很大改变了。
下面所显示的代码目录在/linux/drivers/net/cs89x0.c下。
先来介绍下,物理层网卡的硬件驱动,实验板采用的是Xscale的CPU,网卡芯片是CS8900,运行的操作系统为Linux2.4的核,很多代码在2.6中已经有很大改变了。
下面所显示的代码目录在/linux/drivers/net/cs89x0.c下。
net_device 结构体定义在linux/include/linux/netdevice.h中
net_local 结构体定义在/linux/drivers/net/cs89x0.c中
int init_module(void) //初始化模块函数
{
struct net_local *lp;
int ret = 0;
//dev_cs89x0 为 net_device 结构
dev_cs89x0.irq = irq;//分配中断号
dev_cs89x0.base_addr = io;//指定IO地址
dev_cs89x0.init = cs89x0_probe;//检测实际的网络设备是否存在,在space.c中完成了cs89x0_probe在isa_probes管理结构体管理上的注册
dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);//指向net_local结构的一个指针
if (dev_cs89x0.priv == 0) {
printk(KERN_ERR "cs89x0.c: Out of memory./n");
return -ENOMEM;
}
memset(dev_cs89x0.priv, 0, sizeof(struct net_local));
lp = (struct net_local *)dev_cs89x0.priv;
spin_lock_init(&lp->lock);
。。。。。。 省略部分代码
if (io == 0) {
printk(KERN_ERR "cs89x0.c: Module autoprobing not allowed./n");
printk(KERN_ERR "cs89x0.c: Append io=0xNNN/n");
ret = -EPERM;
goto out;
}
// 注册net_device结构体
if (register_netdev(&dev_cs89x0) != 0) {
printk(KERN_ERR "cs89x0.c: No card found at 0x%x/n", io);
ret = -ENXIO;
goto out;
}
out:
if (ret)
kfree(dev_cs89x0.priv);
return ret;
}
void cleanup_module(void)
{
if (dev_cs89x0.priv != NULL) {
/* Free up the private structure, or leak memory :-) */
unregister_netdev(&dev_cs89x0);
outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT);
kfree(dev_cs89x0.priv);
dev_cs89x0.priv = NULL;/* gets re-allocated by cs89x0_probe1 */
/* If we don't do this, we can't re-insmod it later. */
release_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT);//释放虚拟地址对应的物理地址
}
}
static int net_open(struct net_device *dev)
{ //对应命令 ifconfig eth up
申请中断,reques_irq();
初始化网络的内部数据结构;
运行硬件的初始化;
netif_start_queue(dev);//设置发送队列标记
}
static int net_close(struct net_device *dev)
{ //对应命令 ifconfig eth down
struct net_local *lp = (struct net_local *)dev->priv;
//停止发送队列标记
netif_stop_queue(dev);
//使硬件停止工作
writereg(dev, PP_RxCFG, 0);
writereg(dev, PP_TxCFG, 0);
writereg(dev, PP_BufCFG, 0);
writereg(dev, PP_BusCTL, 0);
//释放中断
free_irq(dev->irq, dev);
/* Update the statistics here. */
return 0;
}
网络设备的发送:从内核堆栈上获得数据,再传输到网络硬件上,
网络设备的接收:从网络硬件上获得数据,再传输到内核堆栈上
内核堆栈的数据类型为:sk_buffer结构
发送函数:int(*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev);
static int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
spin_lock_irq(&lp->lock);
netif_stop_queue(dev);// 停止更新发送队列
/* initiate a transmit sequence */
writeword(dev, TX_CMD_PORT, lp->send_cmd);//发送命令
writeword(dev, TX_LEN_PORT, skb->len);//长度信息
/* Test to see if the chip has allocated memory for the packet */
if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
spin_unlock_irq(&lp->lock);
if (net_debug) printk("cs89x0: Tx buffer not free!/n");
return 1;
}
/* Write the contents of the packet */
outsw(dev->base_addr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1);//往网卡里边写数据
spin_unlock_irq(&lp->lock);
dev->trans_start = jiffies;//纪录发送的开始时间
dev_kfree_skb (skb);
return 0;
}
中断函数:网卡采用中断共享的方法,request_irq(SA_SHIRQ)。在中断服务函数net_interrupt中通过读取网卡硬件端口 readword(dev, ISQ_PORT)来判断发生了何种事件。其中分别对应于
ISQ_RECEIVER_EVENT :当硬件接收到一个数据帧时,此时将dev对应的数据拷贝,再交给上层处理
,这里调用了net_rx函数,完成后续工作。
ISQ_TRANSMITTER_EVENT:当发生发送事件,ISQ_BUFFER_EVENT:网卡有足够发送空间
二者都是调用了函数netif_wake_queue(dev);此函数的功能,一个是用来删除dev中已发送的队列
二来是从dev的队列中取出skb结构来再次发送数据。
ISQ_RX_MISS_EVENT、ISQ_TX_COL_EVENT,是对Miss,Collsion两个错误情况的处理,无非是一些统计。
static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
while ((status = readword(dev, ISQ_PORT))) {
if (net_debug > 4)printk("%s: event=%04x/n", dev->name, status);
switch(status & ISQ_EVENT_MASK) {
case ISQ_RECEIVER_EVENT://硬件收到数据
net_rx(dev);//硬件收到数据,递交给内核堆栈
break;
case ISQ_TRANSMITTER_EVENT://数据包发送完毕
lp->stats.tx_packets++;
netif_wake_queue(dev);/* Inform upper layers. 重新开始发送*/
if ((status & (TX_OK | //更新统计信息,错误率,发送总数
TX_LOST_CRS |
TX_SQE_ERROR |
TX_LATE_COL |
TX_16_COL)) != TX_OK) {
if ((status & TX_OK) == 0) lp->stats.tx_errors++;
if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
if (status & TX_LATE_COL) lp->stats.tx_window_errors++;
if (status & TX_16_COL) lp->stats.tx_aborted_errors++;
}
break;
case ISQ_BUFFER_EVENT://确定有空间发送,可以发送数据
if (status & READY_FOR_TX) {//发送执行成功
netif_wake_queue(dev);/* Inform upper layers. */
}
if (status & TX_UNDERRUN) {//发送没有执行成功
if (net_debug > 0) printk("%s: transmit underrun/n", dev->name);
lp->send_underrun++;
if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381;
else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
netif_wake_queue(dev);/* Inform upper layers. */
}
break;
case ISQ_RX_MISS_EVENT://接收丢失
lp->stats.rx_missed_errors += (status >>6);
break;
case ISQ_TX_COL_EVENT://发送碰撞
lp->stats.collisions += (status >>6);
break;
}
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。