在网络设备驱动程序完成模块注册时,会调用dm9000_probe()函数进行初始化,分配并初始化net_device结构体。其中有些成员在dm9000_probe()中已经完成初始化,还有一些函数指针例如(*open)()、(*release)()等函数,也是在驱动程序中进行定义。
4.dm9000_open()
open函数在执行ifconfig命令时会被激活。主要作用是打开网络设备,获得设备所需的IO地址,IRQ、DMA通道等。注册中断、设置寄存器、启动发送队列。
在字符设备驱动中是把中断注册放在模块初始化函数中,而网卡驱动则放在open函数中。原因是网卡有禁用操作,当被禁用的时候,要把占用的中断号释放。
- m9000_open(struct net_device *dev)
- {
- board_info_t *db = netdev_priv(dev);//获取设备私有数据 返回board_info_t的地址
- 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 there is no IRQ type specified, default to something that
- * may work, and tell the user that this is a problem */
- 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;
- /* Initialize DM9000 board */
- dm9000_reset(db); //复位DM9000
- dm9000_init_dm9000(dev); //初始化dm9000中net_device结构中的成员
- /* Init driver variable */
- db->dbug_cnt = 0;
- mii_check_media(&db->mii, netif_msg_link(db), 1);//检测mii接口状态
- netif_start_queue(dev); //启动发送队列 协议栈向网卡发送
-
- dm9000_schedule_poll(db);
- return 0;
- }
5.stop()
设备关闭函数- tatic 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); /* 终止phy_poll队列中被延迟的任务 */
- netif_stop_queue(ndev); /* 关闭发送队列 */
- netif_carrier_off(ndev);
- /* free interrupt */
- free_irq(ndev->irq, ndev);
/* 释放中断 */
- dm9000_shutdown(ndev); /* 关闭DM9000网卡 */
- return 0;
- }
6.dm9000_shutdown()
下面是调用的dm9000_shutdown(ndev)函数,该函数的功能是复位phy,配置寄存器GPR位0为1,关闭dm9000电源,配置寄存器IMR位7为1,disable中断,配置寄存器RCR,disable接收.
- static void dm9000_shutdown(struct net_device *dev)
- {
- board_info_t *db = netdev_priv(dev);
- /* RESET device */
- dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET ,复位PHY*/
- iow(db, DM9000_GPR, 0x01); /* Power-Down PHY */
- iow(db, DM9000_IMR, IMR_PAR); /* Disable all interrupt ,关闭所有的中断*/
- iow(db, DM9000_RCR, 0x00); /* Disable RX ,不再接受数据*/
- }
7.数据发送函数
数据包发送流程:
1)设备驱动程序从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将有效数据放入临时缓冲区中。
2)设置硬件寄存器,驱动网络设备进行数据发送操作。
- 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); //获得自旋锁
- /* Move data to DM9000 TX RAM */
- writeb(DM9000_MWCMD, db->io_addr); //根据 IO 操作模式(8-bit or 16-bit)来增加写指针 1 或 2
- (db->outblk)(db->io_data, skb->data, skb->len); //将数据从sk_buff中copy到网卡的TX SRAM中
- dev->stats.tx_bytes += skb->len; //统计发送的字节数
- db->tx_pkt_cnt++; //待发送计数
- /* TX control: First packet immediately send, second packet queue */
- if (db->tx_pkt_cnt == 1) { //如果计数为1,直接发送
- dm9000_send_packet(dev, skb->ip_summed, skb->len);
- } else {
- /* Second packet */
- db->queue_pkt_len = skb->len;
- db->queue_ip_summed = skb->ip_summed;
- netif_stop_queue(dev); //告诉上层停止发送
- }
- spin_unlock_irqrestore(&db->lock, flags);//解锁
- /* free this SKB */
- dev_kfree_skb(skb); //释放SKB
- return NETDEV_TX_OK;
- }
dm9000_start_xmit通过调用dm9000_send_packet来发送数据。
阅读(637) | 评论(0) | 转发(0) |