Cs8900网卡驱动程序分析

Cs8900网卡驱动程序分析

首先介绍Cs8900一些寄存器的情况:

LINECTL(线控制寄存器)(0112H)用于决定网卡工作模式情况。

RXCTL(接收控制寄存器)(0104H)表示接收网络上的广播或目的接收地址同本地mac地址 相同的数据包。

RXCFG(接收配置寄存器)(0102H)当收到包后是否产生接受中断。

BUSCT0116H)可控制芯片的I/O接口的一些操作,设置初始值为8017H,打开cs8900的中断总控位。

ISQ(中断状态寄存器)保存了到底发生那种中断,内部映射接受中断状态寄存器和发送中断状态寄存器的内容。

PORT0(0000H):发送和接收数据时,CPU通过PORT0传输数据。 

TXCMD(0004H):发送控制寄存器,如果写入数据00C0H,那么网卡芯片在全部写入数据后开始发送数据。

TXLENG0006H):发送数据长度寄存器,发送数据时,首先写入发送数据长度,然后将数据通过PORT0写入芯片。

系统工作之前,应首先对网卡芯片初始化,即写寄存器LINECTLRXCTLRCCFGBUSCT

发送数据时,按如下流程操作寄存器:将发送命令写入TXCMD,把数据长度写入TXLENG,最后将发送数据依次写入PORT0口。接受:当数据到达之后,网卡会产生一个中断,利用中断把数据通过PORT0读出数据。

下面分析程序

1:模块初始化函数

static  int  __init init_cs8900a_s3c2410(void)

{

struct net_local *lp ;

int  ret = 0 ;

dev_cs89x0.irq = irq ;

dev_cs89x0.base_addr = io ;

dev_cs89x0.init = cs89x0_probe ;  //struct net_device初始化

 

request_region(dev_cs89x0.base_addr, NETCARD_IO_EXITENT,  “cs8900a”) ;

//申请使用I/O端口

if (register_netdev (&dev_cs89x0) != 0) //注册一个网卡

//当使用register注册设备时,内核会调用init(),即probe(), 并不知道网卡存在。

}

static int __init cs89x0_probel (struct net_device *dev, int ioaddr) {

//获取芯片类型

rev_type = readreg(dev, PRODUCT_ID_ADD);

lp->chip_type = rev_type&~REVOSON_BITS;

lp->chip_revision = ((rev_type & REVISION_BITS) >> 8) + ‘A’;

 

if(lp->chip_type != CS8900) {  //设备匹配

printk(__FILE__ “:wrong device !\n”);

ret =- ENODEV;

Goto after_kmalloc;

}

 

dev->dev_addr[0] = 0x00 ;

dev->dev_addr[1] = 0x00 ;

dev->dev_addr[2] = 0xc0 ;

dev->dev_addr[3] = 0xff ;

dev->dev_addr[4] = 0xee ;

dev->dev_addr[5] = 0x08 ;

set_mac_address(dev,  dev->dev_addr) ;

 

dev_irq = IRQ_LAN ;

printk(“ ,  IRQ %d”,  dev_irq) ;

 

//struct net_device成员和方法设置

dev->open = net_open ;

dev->stop = net_device ;

dev->tx_timeout = net_timeout ;

dev->watchdog_timeo = 3 Hz ;

dev->hard_start_xmit = net_send_packet ;  //设置数据发送函数

dev->get_stats = net_get_stats ;

dev->set_multicast_list = set_multicast_list ;

dev->set_mac_address = set_mac_address ;

 

ether_setup(dev) ;  //以太网卡设置

}

2:数据发送:

static int net_send_paket (struct sk_buff  *skb,  struct net_device *dev) {

netif_stop_queue(dev) ; //发送数据时要停掉发送队列

writeword(dev, TX_CMD_PORT,  lp->send_cmd) ;

wrtieword(dev, TX_LEN_PORT,  skb->len) ; 

 

if((reagreg(dev, PP_BusST) & READ_FOR_TX_NOW) == 0) {

spin_unlock_irq(&lp->lock) ;

DPRINTK(1, “cs89x0: Tx buffer not free !\n”) ;

return 1;

}

writeblock(dev, skb->data, skb->len) ;            skb->dataskb有效数据地址

return 0;

}

 

inline void writeblock(struct net_device *dev, char *pData, int Length) {

    int i;

 

    for (i = 0 ; i < (Length/2); i++) {

        writeword(dev, TX_FRAME_PORT, *(u16 *)pData );  

//16位寄存器,每次发16位数据,Length以字节(8位)计数

        pData += 2;

    }

 

    if (Length % 2) {

        u16 OddWordValue = *pData;

        writeword(dev, TX_FRAME_PORT, OddWordValue);

    }

}

inline void writeword(struct net_device *dev, int portno, int value) {

//把数据写到PORT0寄存器

outw(value, dev->base_addr + portno);

}

 

3:中断

static void net_interrupt (int irq,  void *dev_id,  struct pt_regs *regs) {

while((status = readword(dev,  ISQ_PORT))) { //ISQ寄存器判断中断类型

switch (status & ISQ_EVENT_MASK) {

case ISQ_RECEIVER_EVENT : //接收中断

net_rx (dev) ;

break ;

 

case ISQ_TRANSMITTER_EVENT : //发送中断

lp->status.tx_packets++ ;

netif_wake_queue (dev) ;

break ;

}

}

}

4:接收

static void net_rx (struct net_device *dev) {

status = inw (ioaddr + RX_FRAME_PORT) ;

if ((status & RX_OK) == 0) { //RX_OK判断接收是否是正确接收

count_rx_errors(status, lp) ;

return ;

}

Length = inw(ioaddr + RX_FRAME_PORT) ;

//从寄存器中获取接收数据包的长度

skb = dev_alloc_skb (length + 2) ;//利用长度分配skb

if(NULL == skb) {

lp = stats.rx_dropped++ ;

return ;

}

skb_reserve (skb, 2) ;

//mac头是14字节,一开始保留两个字节,正是为了保证IP头的开始是4字节对其的

skb->len = length ;

skb->dev = dev ;

readblock(dev, skb->data, skb->len) ;

//从硬件将数据读到skb中。

skb->protocol=eth_type_trans(skb, dev) ;

netif_rx (skb) ;

}

inline void readblock(struct net_device *dev, char *pData, int Length) {

    u16 InputWord;

    int i;

 

    for (i=0; i < (Length/2); i++) {

        InputWord = readword(dev, RX_FRAME_PORT);

        *(u8*)pData++ = (u8) InputWord & 0xFF;

        *(u8*)pData++ = (u8) (InputWord >> 8) & 0xFF;

    }

 

    if (Length & 0x1) //判断奇数,读取最后一个字节

      *pData = (u8) (readword(dev, RX_FRAME_PORT) & 0xff);

 

netif_rx(skb);//把收到的包交给设备无关层,按照协议类型交给相应的协议处理函数

}

发送由内核主动调用函数指针引起的,接收是当网卡受到完整数据包后产生中断。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值