mini2440 dm9000 网卡驱动详解 2

来源:互联网 发布:隐藏php版本 编辑:程序博客网 时间:2024/05/22 13:54

3. platform_driver的remove, suspend和resume的实现

       remove函数的功能是把设备从内核中移除,释放内存区域。该函数在卸载模块时被调用。代码清单如下:

 

[cpp] view plaincopy
  1. static int __devexit      
  2. dm9000_drv_remove(struct platform_device *pdev)      
  3. {      
  4.     struct net_device *ndev = platform_get_drvdata(pdev);      
  5.      
  6.     platform_set_drvdata(pdev, NULL);      
  7.      
  8.     unregister_netdev(ndev);      
  9.     dm9000_release_board(pdev, (board_info_t *) netdev_priv(ndev));      
  10.     free_netdev(ndev);      /* free device structure */     
  11.      
  12.     dev_dbg(&pdev->dev, "released and freed device\n");      
  13.     return 0;      
  14. }    

       suspend函数并不真正把设备从内核中移除,而只是标志设备为removed状态,并设置挂起标志位,最后关闭设备。代码清单如下:

 

[cpp] view plaincopy
  1. static int dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)      
  2. {      
  3.     struct net_device *ndev = platform_get_drvdata(dev);      
  4.     board_info_t *db;      
  5.      
  6.     if (ndev) {      
  7.         db = netdev_priv(ndev);      
  8.         db->in_suspend = 1;      
  9.      
  10.         if (netif_running(ndev)) {      
  11.             netif_device_detach(ndev);      
  12.             dm9000_shutdown(ndev);      
  13.         }      
  14.     }      
  15.     return 0;      
  16. }    

     resume函数将挂起的设备复位并初始化,软后将设备标志为attached状态,并设置挂起标志位。代码清单如下:

 

[cpp] view plaincopy
  1. static int dm9000_drv_resume(structplatform_device *dev)     
  2.   
  3. {     
  4.   
  5.    struct net_device *ndev = platform_get_drvdata(dev);     
  6.   
  7.    board_info_t *db = netdev_priv(ndev);     
  8.   
  9.     
  10.   
  11.    if (ndev) {     
  12.   
  13.     
  14.   
  15.        if (netif_running(ndev)) {     
  16.   
  17.            dm9000_reset(db);     
  18.   
  19.            dm9000_init_dm9000(ndev);     
  20.   
  21.     
  22.   
  23.            netif_device_attach(ndev);     
  24.   
  25.        }     
  26.   
  27.     
  28.   
  29.        db->in_suspend = 0;     
  30.   
  31.    }     
  32.   
  33.    return 0;     
  34.   
  35. }   

4. 下面看一下用于填充net_device中netdev_ops和ethtool_ops的一些函数。

    代码在上面已经写出来了,为了看着方便在下面再写一遍,可以看出虽然mini2440的板子上没有为DM9000挂EEPROM,但这里还是定义了操作EEPROM的函数。就是说写驱动的时候是不考虑具体的板子的,你板子用不用是你的事,但是我们的驱动应该所有的功能都考虑进去。这也体现了驱动和平台分离的设计思想。

 

 

[cpp] view plaincopy
  1. static const struct net_device_ops dm9000_netdev_ops = {      
  2.     .ndo_open       = dm9000_open,      
  3.     .ndo_stop       = dm9000_stop,      
  4.     .ndo_start_xmit     = dm9000_start_xmit,      
  5.     .ndo_tx_timeout     = dm9000_timeout,      
  6.     .ndo_set_multicast_list = dm9000_hash_table,      
  7.     .ndo_do_ioctl       = dm9000_ioctl,      
  8.     .ndo_change_mtu     = eth_change_mtu,      
  9.     .ndo_validate_addr  = eth_validate_addr,      
  10.     .ndo_set_mac_address    = eth_mac_addr,     
  11. #ifdef CONFIG_NET_POLL_CONTROLLER      
  12.     .ndo_poll_controller    = dm9000_poll_controller,     
  13. #endif      
  14. };    
  15.   
  16.   
  17.    
  18. static const struct ethtool_ops dm9000_ethtool_ops = {      
  19.     .get_drvinfo        = dm9000_get_drvinfo,      
  20.     .get_settings       = dm9000_get_settings,      
  21.     .set_settings       = dm9000_set_settings,      
  22.     .get_msglevel       = dm9000_get_msglevel,      
  23.     .set_msglevel       = dm9000_set_msglevel,      
  24.     .nway_reset     = dm9000_nway_reset,      
  25.     .get_link       = dm9000_get_link,      
  26.     .get_eeprom_len     = dm9000_get_eeprom_len,      
  27.     .get_eeprom     = dm9000_get_eeprom,      
  28.     .set_eeprom     = dm9000_set_eeprom,      
  29. };    

  *dm9000_open()

 

    进行的工作有 向内核注册中断,复位并初始化dm9000,检查MII接口,使能传输等。代码清单如下:

 

[cpp] view plaincopy
  1. /*    
  2.  *  Open the interface.    
  3.  *  The interface is opened whenever "ifconfig" actives it.    
  4.  */     
  5. static int     
  6. dm9000_open(struct net_device *dev)      
  7. {      
  8.     board_info_t *db = netdev_priv(dev);      
  9.     unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;      
  10.      
  11.     if (netif_msg_ifup(db))      
  12.         dev_dbg(db->dev, "enabling %s\n", dev->name);      
  13.      
  14.     /* If there is no IRQ type specified, default to something that    
  15.      * may work, and tell the user that this is a problem */     
  16.      
  17.     if (irqflags == IRQF_TRIGGER_NONE)      
  18.         dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");      
  19.      
  20.     irqflags |= IRQF_SHARED;      
  21.      
  22.     if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))/*注册一个中断,中断处理函数为dm9000_interrupt()*/     
  23.         return -EAGAIN;      
  24.      
  25.     /* Initialize DM9000 board */     
  26.     dm9000_reset(db);      
  27.     dm9000_init_dm9000(dev);      
  28.      
  29.     /* Init driver variable */     
  30.     db->dbug_cnt = 0;      
  31.      
  32.     mii_check_media(&db->mii, netif_msg_link(db), 1);      
  33.     netif_start_queue(dev);      
  34.           
  35.     dm9000_schedule_poll(db);/*之前在probe函数中已经使用INIT_DELAYED_WORK来初始化一个延迟工作队列并关联了一个操作函数dm9000_poll_work(), 此时运行schedule来调用这个函数*/     
  36.      
  37.     return 0;      
  38. }    

*dm9000_stop()

     做的工作基本上和open相反。代码清单如下:

 

[cpp] view plaincopy
  1. /*    
  2.  * Stop the interface.    
  3.  * The interface is stopped when it is brought.    
  4.  */     
  5. static int     
  6. dm9000_stop(struct net_device *ndev)      
  7. {      
  8.     board_info_t *db = netdev_priv(ndev);      
  9.      
  10.     if (netif_msg_ifdown(db))      
  11.         dev_dbg(db->dev, "shutting down %s\n", ndev->name);      
  12.      
  13.     cancel_delayed_work_sync(&db->phy_poll); /*杀死延迟工作队列phy_poll*/     
  14.      
  15.         /*停止传输并清空carrier*/     
  16.     netif_stop_queue(ndev);      
  17.     netif_carrier_off(ndev);      
  18.      
  19.     /* free interrupt */     
  20.     free_irq(ndev->irq, ndev);      
  21.      
  22.     dm9000_shutdown(ndev);      
  23.      
  24.     return 0;      
  25. }    

   *dm9000_start_xmit()

 

    重要的发送数据包函数。从上层发送sk_buff包。在看代码之前先来看一下DM9000是如何发送数据包的。


如上图所示,在DM9000内部SRAM中,地址0x0000~0x0BFF是TX Buffer,地址0x0C00~0x3FFF是RX Buffer。在发送一个包之前,包中的有效数据必须先被存储到TX Buffer中并且使用输出端口命令来选择MWCMD寄存器。包的长度定义在TXPLL和TXPLH中。最后设置TXCR寄存器的bit[0] TXREQ来自动发送包。如果设置了IMR寄存器的PTM位,则DM9000会产生一个中断触发在ISR寄存器的bit[1]=PTS=1, 同时设置一个完成标志在NSR寄存器的bit[2]=TX1END或者 bit[3]=TX2END,表示包已经发送完了。发送一个包的具体步骤如下:

 

Step 1: 检查存储数据宽度。通过读取中断状态寄存器(ISR)的bit[7:6]来确定是8bit,16bit还是32bit。

 

Step 2: 写数据到TX SRAM中。

 

Step 3: 写传输长度到TXPLL和TXPLH寄存器中。

 

Step 4: 设置TXCR寄存器的bit[0]TXREQ来开始发送一个包。

 

代码清单如下,让我们看看在获得自旋锁这段期间都干了些什么:

 

[cpp] view plaincopy
  1. /*    
  2.  *  Hardware start transmission.    
  3.  *  Send a packet to media from the upper layer.    
  4.  */     
  5. static int     
  6. dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)      
  7. {      
  8.     unsigned long flags;      
  9.     board_info_t *db = netdev_priv(dev);      
  10.      
  11.     dm9000_dbg(db, 3, "%s:\n", __func__);      
  12.      
  13.     if (db->tx_pkt_cnt > 1)      
  14.         return NETDEV_TX_BUSY;      
  15.      
  16.         /*获得自旋锁*/     
  17.     spin_lock_irqsave(&db->lock, flags);       
  18.      
  19.     /* Move data to DM9000 TX RAM */     
  20.         /*下面四行代码将skb中的data部分写入DM9000的TX RAM,并更新已发送字节数和发送计数*/     
  21.     writeb(DM9000_MWCMD, db->io_addr);      
  22.      
  23.     (db->outblk)(db->io_data, skb->data, skb->len);      
  24.     dev->stats.tx_bytes += skb->len;      
  25.      
  26.     db->tx_pkt_cnt++;      
  27.     /* TX control: First packet immediately send, second packet queue */     
  28.         /*如果发送的是第一个包,则设置一下包的长度后直接发送*/     
  29.         /*如果发的不是第一个包,*/     
  30.     if (db->tx_pkt_cnt == 1) {      
  31.         /* Set TX length to DM9000 */     
  32.         iow(db, DM9000_TXPLL, skb->len);      
  33.         iow(db, DM9000_TXPLH, skb->len >> 8);      
  34.      
  35.         /* Issue TX polling command */     
  36.         iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */     
  37.      
  38.         dev->trans_start = jiffies;  /* save the time stamp */     
  39.     } else {      
  40.         /* Second packet */     
  41.                 /*如果发送的是第二个数据包(表明队列中此时有包发送),则将其加入队列中:将skb->len和skb->ip_summed(控制校验操作)赋值给board_info_t中有关队列的相关成员。调用函数netif_stop_queue(dev),通知内核现在queue已满,不能再将发送数据传到队列中,注:第二个包的发送将在tx_done中实现。*/     
  42.         db->queue_pkt_len = skb->len;      
  43.         netif_stop_queue(dev);      
  44.     }      
  45.      
  46.         /*释放自旋锁*/     
  47.     spin_unlock_irqrestore(&db->lock, flags);      
  48.      
  49.     /* free this SKB */     
  50.     dev_kfree_skb(skb);      
  51.      
  52.     return 0;      
  53. }    

*dm9000_timeout()

    当watchdog超时时调用该函数。主要的功能是保存寄存器地址,停止队列,重启并初始化DM9000,唤醒队列,恢复寄存器地址。

 

    代码清单如下:

[cpp] view plaincopy
  1. /* Our watchdog timed out. Called by the networking layer */     
  2. static void dm9000_timeout(struct net_device *dev)      
  3. {      
  4.     board_info_t *db = netdev_priv(dev);      
  5.     u8 reg_save;      
  6.     unsigned long flags;      
  7.      
  8.     /* Save previous register address */     
  9.     reg_save = readb(db->io_addr);      
  10.     spin_lock_irqsave(&db->lock, flags);      
  11.      
  12.     netif_stop_queue(dev);      
  13.     dm9000_reset(db);      
  14.     dm9000_init_dm9000(dev);      
  15.     /* We can accept TX packets again */     
  16.     dev->trans_start = jiffies;      
  17.     netif_wake_queue(dev);      
  18.      
  19.     /* Restore previous register address */     
  20.     writeb(reg_save, db->io_addr);      
  21.     spin_unlock_irqrestore(&db->lock, flags);      
  22. }    

   *dm9000_hash_table()

 

    该函数用来设置DM9000的组播地址。代码清单如下:

[cpp] view plaincopy
  1. /*    
  2.  *  Set DM9000 multicast address    
  3.  */     
  4. static void     
  5. dm9000_hash_table(struct net_device *dev)      
  6. {      
  7.     board_info_t *db = netdev_priv(dev);      
  8.     struct dev_mc_list *mcptr = dev->mc_list;      
  9.     int mc_cnt = dev->mc_count;      
  10.     int i, oft;      
  11.     u32 hash_val;      
  12.     u16 hash_table[4];      
  13.     u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN;      
  14.     unsigned long flags;      
  15.      
  16.     dm9000_dbg(db, 1, "entering %s\n", __func__);      
  17.      
  18.     spin_lock_irqsave(&db->lock, flags);      
  19.      
  20.     for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)      
  21.         iow(db, oft, dev->dev_addr[i]);      
  22.      
  23.     /* Clear Hash Table */     
  24.     for (i = 0; i < 4; i++)      
  25.         hash_table[i] = 0x0;      
  26.      
  27.     /* broadcast address */     
  28.     hash_table[3] = 0x8000;      
  29.      
  30.     if (dev->flags & IFF_PROMISC)      
  31.         rcr |= RCR_PRMSC;      
  32.      
  33.     if (dev->flags & IFF_ALLMULTI)      
  34.         rcr |= RCR_ALL;      
  35.      
  36.     /* the multicast address in Hash Table : 64 bits */     
  37.     for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {      
  38.         hash_val = ether_crc_le(6, mcptr->dmi_addr) & 0x3f;      
  39.         hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);      
  40.     }      
  41.      
  42.     /* Write the hash table to MAC MD table */     
  43.     for (i = 0, oft = DM9000_MAR; i < 4; i++) {      
  44.         iow(db, oft++, hash_table[i]);      
  45.         iow(db, oft++, hash_table[i] >> 8);      
  46.     }      
  47.      
  48.     iow(db, DM9000_RCR, rcr);      
  49.     spin_unlock_irqrestore(&db->lock, flags);      
  50. }    

   *dm9000_ioctl()

 

    从源码可以看出,dm9000的ioctl实际上是使用了mii的ioctl。代码清单如下:

[cpp] view plaincopy
  1. static int dm9000_ioctl(struct net_device *dev, struct ifreq *req, int cmd)      
  2. {      
  3.     board_info_t *dm = to_dm9000_board(dev);      
  4.      
  5.     if (!netif_running(dev))      
  6.         return -EINVAL;      
  7.      
  8.     return generic_mii_ioctl(&dm->mii, if_mii(req), cmd, NULL);      
  9. }    
  10.   
  11.     *dm9000_poll_controller()  
  12.   
  13.     当内核配置Netconsole时该函数生效。代码清单如下:  
  14.   
  15. #ifdef CONFIG_NET_POLL_CONTROLLER      
  16. /*    
  17.  *Used by netconsole    
  18.  */     
  19. static void dm9000_poll_controller(struct net_device *dev)      
  20. {      
  21.     disable_irq(dev->irq);      
  22.     dm9000_interrupt(dev->irq, dev);      
  23.     enable_irq(dev->irq);      
  24. }     
  25. #endif    
0 0
原创粉丝点击