arm linux的网卡驱动,ARM-Linux驱动--DM9000网卡驱动分析(三)

硬件平台:FL2440(s3c2440)

内核版本:2.6.35

主机平台:Ubuntu11.04

内核版本:2.6.39

交叉编译器:arm-linuc-gcc4.3.2

本文接上文

下面开始看网卡设备的打开、关闭函数和操作函数

staticconststructnet_device_ops dm9000_netdev_ops = {

.ndo_open = dm9000_open,

.ndo_stop = dm9000_stop,

.ndo_start_xmit = dm9000_start_xmit,

.ndo_tx_timeout = dm9000_timeout,

.ndo_set_multicast_list = dm9000_hash_table,

.ndo_do_ioctl = dm9000_ioctl,

.ndo_change_mtu = eth_change_mtu,

.ndo_validate_addr = eth_validate_addr,

.ndo_set_mac_address = eth_mac_addr,

#ifdef CONFIG_NET_POLL_CONTROLLER

.ndo_poll_controller = dm9000_poll_controller,

#endif

};

static const struct net_device_ops dm9000_netdev_ops = {

.ndo_open = dm9000_open,

.ndo_stop = dm9000_stop,

.ndo_start_xmit = dm9000_start_xmit,

.ndo_tx_timeout = dm9000_timeout,

.ndo_set_multicast_list = dm9000_hash_table,

.ndo_do_ioctl = dm9000_ioctl,

.ndo_change_mtu = eth_change_mtu,

.ndo_validate_addr = eth_validate_addr,

.ndo_set_mac_address = eth_mac_addr,

#ifdef CONFIG_NET_POLL_CONTROLLER

.ndo_poll_controller = dm9000_poll_controller,

#endif

};

1、DM9000的打开函数

由于在函数alloc_netdev_mq()中分配net_device和网卡的私有数据是一起分配的,详见函数的实现

structnet_device *alloc_netdev_mq(intsizeof_priv,constchar*name,

void(*setup)(structnet_device *), unsignedintqueue_count)

{

...................

alloc_size =sizeof(structnet_device);

if(sizeof_priv) {

alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);

alloc_size += sizeof_priv;

}

alloc_size += NETDEV_ALIGN - 1;

p = kzalloc(alloc_size, GFP_KERNEL);

if(!p) {

printk(KERN_ERR"alloc_netdev: Unable to allocate device.\n");

returnNULL;

}

tx = kcalloc(queue_count,sizeof(structnetdev_queue), GFP_KERNEL);

if(!tx) {

printk(KERN_ERR"alloc_netdev: Unable to allocate "

"tx qdiscs.\n");

gotofree_p;

}

#ifdef CONFIG_RPS

rx = kcalloc(queue_count,sizeof(structnetdev_rx_queue), GFP_KERNEL);

if(!rx) {

printk(KERN_ERR"alloc_netdev: Unable to allocate "

"rx queues.\n");

gotofree_tx;

}

..............

}

struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,

void (*setup)(struct net_device *), unsigned int queue_count)

{

...................

alloc_size = sizeof(struct net_device);

if (sizeof_priv) {

alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);

alloc_size += sizeof_priv;

}

alloc_size += NETDEV_ALIGN - 1;

p = kzalloc(alloc_size, GFP_KERNEL);

if (!p) {

printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n");

return NULL;

}

tx = kcalloc(queue_count, sizeof(struct netdev_queue), GFP_KERNEL);

if (!tx) {

printk(KERN_ERR "alloc_netdev: Unable to allocate "

"tx qdiscs.\n");

goto free_p;

}

#ifdef CONFIG_RPS

rx = kcalloc(queue_count, sizeof(struct netdev_rx_queue), GFP_KERNEL);

if (!rx) {

printk(KERN_ERR "alloc_netdev: Unable to allocate "

"rx queues.\n");

goto free_tx;

}

..............

}

所以使用函数netdev_priv()函数返回的是网卡的私有数据的地址,函数的实现如下:

staticinlinevoid*netdev_priv(conststructnet_device *dev)

{

return(char*)dev + ALIGN(sizeof(structnet_device), NETDEV_ALIGN);

}

static inline void *netdev_priv(const struct net_device *dev)

{

return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);

}

这样两者会同时生存和消失。

dm9000_open()函数

staticint

dm9000_open(structnet_device *dev)

{

board_info_t *db = netdev_priv(dev);

unsignedlongirqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;

if(netif_msg_ifup(db))

dev_dbg(db->dev,"enabling %s\n", dev->name);

if(irqflags == IRQF_TRIGGER_NONE)

dev_warn(db->dev,"WARNING: no IRQ resource flags set.\n");

irqflags |= IRQF_SHARED;

if(request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))

return-EAGAIN;

dm9000_reset(db);

dm9000_init_dm9000(dev);

db->dbug_cnt = 0;

mii_check_media(&db->mii, netif_msg_link(db), 1);

netif_start_queue(dev);

dm9000_schedule_poll(db);

return0;

}

static int

dm9000_open(struct net_device *dev)

{

board_info_t *db = netdev_priv(dev);

unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;

if (netif_msg_ifup(db))

dev_dbg(db->dev, "enabling %s\n", dev->name);

if (irqflags == IRQF_TRIGGER_NONE)

dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");

irqflags |= IRQF_SHARED;

if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))

return -EAGAIN;

dm9000_reset(db);

dm9000_init_dm9000(dev);

db->dbug_cnt = 0;

mii_check_media(&db->mii, netif_msg_link(db), 1);

netif_start_queue(dev);

dm9000_schedule_poll(db);

return 0;

}

2、网卡关闭函数

staticint

dm9000_stop(structnet_device *ndev)

{

board_info_t *db = netdev_priv(ndev);

if(netif_msg_ifdown(db))

dev_dbg(db->dev,"shutting down %s\n", ndev->name);

cancel_delayed_work_sync(&db->phy_poll);

netif_stop_queue(ndev);

netif_carrier_off(ndev);

free_irq(ndev->irq, ndev);

dm9000_shutdown(ndev);

return0;

}

static int

dm9000_stop(struct net_device *ndev)

{

board_info_t *db = netdev_priv(ndev);

if (netif_msg_ifdown(db))

dev_dbg(db->dev, "shutting down %s\n", ndev->name);

cancel_delayed_work_sync(&db->phy_poll);

netif_stop_queue(ndev);

netif_carrier_off(ndev);

free_irq(ndev->irq, ndev);

dm9000_shutdown(ndev);

return 0;

}

下面是调用的dm9000_shutdown(ndev)函数,该函数的功能是复位phy,配置寄存器GPR位0为1,关闭dm9000电源,配置寄存器IMR位7为1,disable中断,配置寄存器RCR,disable接收

函数如下:

staticvoid

dm9000_shutdown(structnet_device *dev)

{

board_info_t *db = netdev_priv(dev);

dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);

iow(db, DM9000_GPR, 0x01);

iow(db, DM9000_IMR, IMR_PAR);

iow(db, DM9000_RCR, 0x00);

}

static void

dm9000_shutdown(struct net_device *dev)

{

board_info_t *db = netdev_priv(dev);

dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);

iow(db, DM9000_GPR, 0x01);

iow(db, DM9000_IMR, IMR_PAR);

iow(db, DM9000_RCR, 0x00);

}

3、接下来了解一下数据的发送函数dm9000_start_xmit

a4c26d1e5885305701be709a3d33442f.png

上图可以看出DM9000的SRAM中地址0x0000到0x0BFF是TXBuffer,从0x0C00到0x3FFF是RXBuffer,包的有效数据必须提前放到TXBuffer缓冲区,使用端口命令来选择MWCMD寄存器。最后设置TXCR寄存器的bit[0]TXREQ来自动发送包。发送包的步骤如下:

(1)检查存储器宽度,通过读取ISR的bit[7:6]来确定位数(2)写数据到TXSRAM(3)写传输长度到TXPLL和TXPLH寄存器(4)设置TXCR的bit[0]TXREQ来发送包

staticint

dm9000_start_xmit(structsk_buff *skb,structnet_device *dev)

{

unsignedlongflags;

board_info_t *db = netdev_priv(dev);

dm9000_dbg(db, 3,"%s:\n", __func__);

if(db->tx_pkt_cnt > 1)

returnNETDEV_TX_BUSY;

spin_lock_irqsave(&db->lock, flags);

writeb(DM9000_MWCMD, db->io_addr);

(db->outblk)(db->io_data, skb->data, skb->len);

dev->stats.tx_bytes += skb->len;

db->tx_pkt_cnt++;

if(db->tx_pkt_cnt == 1) {

dm9000_send_packet(dev, skb->ip_summed, skb->len);

}else{

db->queue_pkt_len = skb->len;

db->queue_ip_summed = skb->ip_summed;

netif_stop_queue(dev);

}

spin_unlock_irqrestore(&db->lock, flags);

dev_kfree_skb(skb);

returnNETDEV_TX_OK;

}

static int

dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)

{

unsigned long flags;

board_info_t *db = netdev_priv(dev);

dm9000_dbg(db, 3, "%s:\n", __func__);

if (db->tx_pkt_cnt > 1)

return NETDEV_TX_BUSY;

spin_lock_irqsave(&db->lock, flags);

writeb(DM9000_MWCMD, db->io_addr);

(db->outblk)(db->io_data, skb->data, skb->len);

dev->stats.tx_bytes += skb->len;

db->tx_pkt_cnt++;

if (db->tx_pkt_cnt == 1) {

dm9000_send_packet(dev, skb->ip_summed, skb->len);

} else {

db->queue_pkt_len = skb->len;

db->queue_ip_summed = skb->ip_summed;

netif_stop_queue(dev);

}

spin_unlock_irqrestore(&db->lock, flags);

dev_kfree_skb(skb);

return NETDEV_TX_OK;

}

上面函数调用下面的函数dm9000_send_packet来发送数据

staticvoiddm9000_send_packet(structnet_device *dev,

intip_summed,

u16 pkt_len)

{

board_info_t *dm = to_dm9000_board(dev);

if(dm->ip_summed != ip_summed) {

if(ip_summed == CHECKSUM_NONE)

iow(dm, DM9000_TCCR, 0);

else

iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);

dm->ip_summed = ip_summed;

}

iow(dm, DM9000_TXPLL, pkt_len);

iow(dm, DM9000_TXPLH, pkt_len >> 8);

iow(dm, DM9000_TCR, TCR_TXREQ);

}

static void dm9000_send_packet(struct net_device *dev,

int ip_summed,

u16 pkt_len)

{

board_info_t *dm = to_dm9000_board(dev);

if (dm->ip_summed != ip_summed) {

if (ip_summed == CHECKSUM_NONE)

iow(dm, DM9000_TCCR, 0);

else

iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);

dm->ip_summed = ip_summed;

}

iow(dm, DM9000_TXPLL, pkt_len);

iow(dm, DM9000_TXPLH, pkt_len >> 8);

iow(dm, DM9000_TCR, TCR_TXREQ);

}

5、下面看一下当一个数据包发送完成后的中断处理函数dm9000_tx_done

staticvoiddm9000_tx_done(structnet_device *dev, board_info_t *db)

{

inttx_status = ior(db, DM9000_NSR);

if(tx_status & (NSR_TX2END | NSR_TX1END)) {

db->tx_pkt_cnt--;

dev->stats.tx_packets++;

if(netif_msg_tx_done(db))

dev_dbg(db->dev,"tx done, NSR x\n", tx_status);

if(db->tx_pkt_cnt > 0)

dm9000_send_packet(dev, db->queue_ip_summed,

db->queue_pkt_len);

netif_wake_queue(dev);

}

}

static void dm9000_tx_done(struct net_device *dev, board_info_t *db)

{

int tx_status = ior(db, DM9000_NSR);

if (tx_status & (NSR_TX2END | NSR_TX1END)) {

db->tx_pkt_cnt--;

dev->stats.tx_packets++;

if (netif_msg_tx_done(db))

dev_dbg(db->dev, "tx done, NSR x\n", tx_status);

if (db->tx_pkt_cnt > 0)

dm9000_send_packet(dev, db->queue_ip_summed,

db->queue_pkt_len);

netif_wake_queue(dev);

}

}

转载自:http://blog.csdn.net/yming0221/article/details/6615027

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值