ARM-Linux驱动--DM9000网卡驱动分析(三)
ARM-Linux驱动--DM9000网卡驱动分析(二)硬件平台:FL2440(s3c2440) .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, .ndo_poll_controller = dm9000_poll_controller, void (*setup)(struct net_device *), unsigned int queue_count) 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; } 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; } return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN); 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 %sn", 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; board_info_t *db = netdev_priv(ndev); if (netif_msg_ifdown(db)) dev_dbg(db->dev, "shutting down %sn", 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; 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); 
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; 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); 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 xn", tx_status); if (db->tx_pkt_cnt > 0) dm9000_send_packet(dev, db->queue_ip_summed, db->queue_pkt_len); netif_wake_queue(dev); }
内核版本: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 = {
#ifdef CONFIG_NET_POLL_CONTROLLER
#endif
};
1、DM9000的打开函数
由于在函数alloc_netdev_mq()中分配net_device和网卡的私有数据是一起分配的,详见函数的实现
view plainprint?
struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
{
...................
alloc_size = sizeof(struct net_device);
#ifdef CONFIG_RPS
..............
}
所以使用函数netdev_priv()函数返回的是网卡的私有数据的地址,函数的实现如下:
view plainprint?
static inline void *netdev_priv(const struct net_device *dev)
{
}
这样两者会同时生存和消失。
dm9000_open()函数
view plainprint?
static int
dm9000_open(struct net_device *dev)
{
}
2、网卡关闭函数
view plainprint?
static int
dm9000_stop(struct net_device *ndev)
{
}
下面是调用的dm9000_shutdown(ndev)函数,该函数的功能是复位phy,配置寄存器GPR位0为1,关闭dm9000电源,配置寄存器IMR位7为1,disable中断,配置寄存器RCR,disable接收
函数如下:
view plainprint?
static void
dm9000_shutdown(struct net_device *dev)
{
}
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)
{
}
上面函数调用下面的函数 dm9000_send_packet来发送数据
view plainprint?
static void dm9000_send_packet(struct net_device *dev,
{
}
5、下面看一下当一个数据包发送完成后的中断处理函数dm9000_tx_done
view plainprint?
static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
{
}
关键词: ARMLinux驱动DM9000网卡驱

加入微信
获取电子行业最新资讯
搜索微信公众号:EEPW
或用微信扫描左侧二维码