您的位置 首页 产品

ARM-Linux驱动–DM9000网卡驱动剖析(三)

ARM-Linux驱动–DM9000网卡驱动分析(二)硬件平台:FL2440(s3c2440)内核版本:2.6.35主机平台:Ubuntu11.04内核版本:2.6.39交叉编译器…

ARMLinux驱动DM9000网卡驱动剖析(二)硬件渠道:FL2440(s3c2440

内核版别:2.6.35
主机渠道:Ubuntu11.04
内核版别:2.6.39
穿插编译器:arm-linuc-gcc4.3.2
原创著作,转载请标明出处http://blog.csdn.net/yming0221/article/details/6615027
本文接上文
ARM-Linux驱动–DM9000网卡驱动剖析(一)
ARM-Linux驱动–DM9000网卡驱动剖析(二)
下面开端看网卡设备的翻开、封闭函数和操作函数
view plainprint?
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和网卡的私有数据是一同分配的,详见函数的完成
view plainprint?
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()函数回来的是网卡的私有数据的地址,函数的完成如下:
view plainprint?
static inline void *netdev_priv(const struct net_device *dev)
{
return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
}
这样两者会一起生计和消失。
dm9000_open()函数
view plainprint?
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、网卡封闭函数
view plainprint?
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接纳
函数如下:
view plainprint?
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
上图能够看出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来发送包
view plainprint?
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来发送数据
view plainprint?
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
view plainprint?
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);
}
}

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/xinpin/chanpin/264502.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部