Chinaunix首页 | 论坛 | 博客
  • 博客访问: 13100
  • 博文数量: 4
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2015-09-23 09:43
文章分类
文章存档

2016年(4)

我的朋友
最近访客

分类: LINUX

2016-08-10 11:33:25

原文地址:dm9000网卡驱动分析2 作者:zhongli_i

在网络设备驱动程序完成模块注册时,会调用dm9000_probe()函数进行初始化,分配并初始化net_device结构体。其中有些成员在dm9000_probe()中已经完成初始化,还有一些函数指针例如(*open)()、(*release)()等函数,也是在驱动程序中进行定义。

4.dm9000_open()
open函数在执行ifconfig命令时会被激活。主要作用是打开网络设备,获得设备所需的IO地址,IRQ、DMA通道等。注册中断、设置寄存器、启动发送队列。
在字符设备驱动中是把中断注册放在模块初始化函数中,而网卡驱动则放在open函数中。原因是网卡有禁用操作,当被禁用的时候,要把占用的中断号释放。

点击(此处)折叠或打开

  1. m9000_open(struct net_device *dev)
  2. {
  3.     board_info_t *db = netdev_priv(dev);//获取设备私有数据 返回board_info_t的地址
  4.     unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;

  5.     if (netif_msg_ifup(db))
  6.         dev_dbg(db->dev, "enabling %s\n", dev->name);

  7.     /* If there is no IRQ type specified, default to something that
  8.      * may work, and tell the user that this is a problem */

  9.     if (irqflags == IRQF_TRIGGER_NONE)
  10.         dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");

  11.     irqflags |= IRQF_SHARED;
  12. //注册中断
  13.     if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
  14.         return -EAGAIN;

  15.     /* Initialize DM9000 board */
  16.     dm9000_reset(db); //复位DM9000
  17.     dm9000_init_dm9000(dev); //初始化dm9000中net_device结构中的成员

  18.     /* Init driver variable */
  19.     db->dbug_cnt = 0;

  20.     mii_check_media(&db->mii, netif_msg_link(db), 1);//检测mii接口状态
  21.     netif_start_queue(dev); //启动发送队列  协议栈向网卡发送
  22.     
  23.     dm9000_schedule_poll(db);

  24.     return 0;
  25. }

5.stop()
设备关闭函数

点击(此处)折叠或打开

  1. tatic int dm9000_stop(struct net_device *ndev)
  2. {
  3.     board_info_t *db = netdev_priv(ndev);

  4.     if (netif_msg_ifdown(db))
  5.         dev_dbg(db->dev, "shutting down %s\n", ndev->name);

  6.     cancel_delayed_work_sync(&db->phy_poll)/* 终止phy_poll队列中被延迟的任务 */

  7.     netif_stop_queue(ndev); /* 关闭发送队列 */
  8.     netif_carrier_off(ndev)

  9.     /* free interrupt */
  10.     free_irq(ndev->irq, ndev)  /* 释放中断 */

  11.     dm9000_shutdown(ndev) /* 关闭DM9000网卡 */ 

  12.     return 0;
  13. }

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

点击(此处)折叠或打开

  1. static void dm9000_shutdown(struct net_device *dev)
  2. {
  3.     board_info_t *db = netdev_priv(dev);

  4.     /* RESET device */
  5.     dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);   /* PHY RESET ,复位PHY*/ 
  6.     iow(db, DM9000_GPR, 0x01);    /* Power-Down PHY */
  7.     iow(db, DM9000_IMR, IMR_PAR);  /* Disable all interrupt ,关闭所有的中断*/
  8.     iow(db, DM9000_RCR, 0x00);   /* Disable RX ,不再接受数据*/
  9. }

7.数据发送函数
数据包发送流程:
1)设备驱动程序从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将有效数据放入临时缓冲区中。
2)设置硬件寄存器,驱动网络设备进行数据发送操作。

点击(此处)折叠或打开

  1. static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
  2. {
  3.     unsigned long flags;
  4.     board_info_t *db = netdev_priv(dev);

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

  6.     if (db->tx_pkt_cnt > 1)
  7.         return NETDEV_TX_BUSY;

  8.     spin_lock_irqsave(&db->lock, flags); //获得自旋锁

  9.     /* Move data to DM9000 TX RAM */
  10.     writeb(DM9000_MWCMD, db->io_addr); //根据 IO 操作模式(8-bit or 16-bit)来增加写指针 1 或 2

  11.     (db->outblk)(db->io_data, skb->data, skb->len); //将数据从sk_buff中copy到网卡的TX SRAM中
  12.     dev->stats.tx_bytes += skb->len; //统计发送的字节数

  13.     db->tx_pkt_cnt++; //待发送计数 
  14.     /* TX control: First packet immediately send, second packet queue */
  15.     if (db->tx_pkt_cnt == 1) {  //如果计数为1,直接发送
  16.         dm9000_send_packet(dev, skb->ip_summed, skb->len);
  17.     } else {
  18.         /* Second packet */
  19.         db->queue_pkt_len = skb->len;
  20.         db->queue_ip_summed = skb->ip_summed;
  21.         netif_stop_queue(dev); //告诉上层停止发送
  22.     }

  23.     spin_unlock_irqrestore(&db->lock, flags);//解锁

  24.     /* free this SKB */
  25.     dev_kfree_skb(skb); //释放SKB

  26.     return NETDEV_TX_OK;
  27. }
dm9000_start_xmit通过调用dm9000_send_packet来发送数据。
阅读(1014) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~