DM9000网卡驱动程序分析《转》

615阅读 0评论2012-06-13 nanye1984
分类:

转载:衡阳师范学院08电2  K-Style  http://blog.csdn.net/ayangke,QQ:843308498 邮箱:yangkeemail@qq.com

DM9000是开发板经采用的网络芯片,是一种高度集成而且功耗很低的高速网络控制器,可以和CPU直连,支持10/100M以太网连接,芯片内部自带16K SARM(3KB用来发送,13KB用来接收).

1.模块初始化

 

  1. static struct platform_driver dm9000_driver = {  
  2.     .driver = {  
  3.         .name    = "dm9000",  
  4.         .owner   = THIS_MODULE,  
  5.     },  
  6.     .probe   = dm9000_probe,  
  7.     .remove  = __devexit_p(dm9000_drv_remove),  
  8.     .suspend = dm9000_drv_suspend,  
  9.     .resume  = dm9000_drv_resume,  
  10. };  
  11.   
  12. static int __init  
  13. dm9000_init(void)  
  14. {  
  15.     printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);  
  16.   
  17.     return platform_driver_register(&dm9000_driver);  
  18. }  

模块初始化完成了基于platfrom平台的DM9000网卡驱动的注册,当DM9000网卡找到其对应的能处理的platform设备后调用probe函数。

 

2.DM9000网卡初始化

 

在probe函数中完成了对DM9000网卡的初始化

DM9000的特性:DM9000地址信号和数据信号复用使用CMD引脚区分它们(CMD为低是读写DM900地址寄存器,CMD为高时读写 DM9000数据寄存器),访问DM9000内部寄存器时,先将CMD置低,写DM900地址寄存器,然后将CMD置高,读写DM9000数据寄存器。

  1. static int __devinit  
  2. dm9000_probe(struct platform_device *pdev)  
  3. {     
  4.     struct dm9000_plat_data *pdata = pdev->dev.platform_data;  
  5.     struct board_info *db;  /* Point a board information structure */  
  6.     struct net_device *ndev;  
  7.     const unsigned char *mac_src;  
  8.     int ret = 0;  
  9.     int iosize;  
  10.     int i;  
  11.     u32 id_val;  
  12.   
  13.     /* Init network device */  
  14.     //申请net_device结构  
  15.     ndev = alloc_etherdev(sizeof(struct board_info));  
  16.     if (!ndev) {  
  17.         dev_err(&pdev->dev, "could not allocate device.\n");  
  18.         return -ENOMEM;  
  19.     }  
  20.   
  21.   
  22. //将net_device的parent指针指向platform_device对象,表示该设备挂载platform设备上。  
  23.     SET_NETDEV_DEV(ndev, &pdev->dev);   
  24.   
  25.     dev_dbg(&pdev->dev, "dm9000_probe()\n");  
  26.   
  27.     /* setup board info structure */  
  28.     //获取net_device私有数据结构指针  
  29.     db = netdev_priv(ndev);  
  30.     memset(db, 0, sizeof(*db));  
  31.   
  32.     //设置相关设备  
  33.     db->dev = &pdev->dev;  
  34.     db->ndevndev = ndev;  
  35.   
  36.     spin_lock_init(&db->lock);  
  37.     mutex_init(&db->addr_lock);  
  38.   
  39.     INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);  
  40.       
  41.     //获取平台设备资源。包括DM9000地址寄存器地址,DM9000数据寄存器地址,和DM900所占用的中断号  
  42.   
  43.     db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  44.     db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);  
  45.     db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);  
  46.   
  47.     if (db->addr_res == NULL || db->data_res == NULL ||  
  48.         db->irq_res == NULL) {  
  49.         dev_err(db->dev, "insufficient resources\n");  
  50.         ret = -ENOENT;  
  51.         goto out;  
  52.     }  
  53.   
  54.     //申请地址寄存器IO内存区域并映射  
  55.     iosize = res_size(db->addr_res);  
  56.     db->addr_req = request_mem_region(db->addr_res->start, iosize,  
  57.                       pdev->name);  
  58.   
  59.     if (db->addr_req == NULL) {  
  60.         dev_err(db->dev, "cannot claim address reg area\n");  
  61.         ret = -EIO;  
  62.         goto out;  
  63.     }  
  64.   
  65.     db->io_addr = ioremap(db->addr_res->start, iosize);  
  66.   
  67.     if (db->io_addr == NULL) {  
  68.         dev_err(db->dev, "failed to ioremap address reg\n");  
  69.         ret = -EINVAL;  
  70.         goto out;  
  71.     }  
  72.   
  73.     //申请数据寄存器IO内存区域并映射  
  74.     iosize = res_size(db->data_res);  
  75.     db->data_req = request_mem_region(db->data_res->start, iosize,  
  76.                       pdev->name);  
  77.   
  78.     if (db->data_req == NULL) {  
  79.         dev_err(db->dev, "cannot claim data reg area\n");  
  80.         ret = -EIO;  
  81.         goto out;  
  82.     }  
  83.   
  84.     db->io_data = ioremap(db->data_res->start, iosize);  
  85.   
  86.     if (db->io_data == NULL) {  
  87.         dev_err(db->dev, "failed to ioremap data reg\n");  
  88.         ret = -EINVAL;  
  89.         goto out;  
  90.     }  
  91.   
  92.     /* fill in parameters for net-dev structure */  
  93.     ndev->base_addr = (unsigned long)db->io_addr;  
  94.     ndev->irq    = db->irq_res->start;  
  95.   
  96.     //设置数据位宽  
  97.     /* ensure at least we have a default set of IO routines */  
  98.     dm9000_set_io(db, iosize);  
  99.   
  100.     /* check to see if anything is being over-ridden */  
  101.     if (pdata != NULL) {  
  102.         /* check to see if the driver wants to over-ride the  
  103.          * default IO width */  
  104.   
  105.         if (pdata->flags & DM9000_PLATF_8BITONLY)  
  106.             dm9000_set_io(db, 1);  
  107.   
  108.         if (pdata->flags & DM9000_PLATF_16BITONLY)  
  109.             dm9000_set_io(db, 2);  
  110.   
  111.         if (pdata->flags & DM9000_PLATF_32BITONLY)  
  112.             dm9000_set_io(db, 4);  
  113.   
  114.         /* check to see if there are any IO routine  
  115.          * over-rides */  
  116.   
  117.         if (pdata->inblk != NULL)  
  118.             db->inblk = pdata->inblk;  
  119.   
  120.         if (pdata->outblk != NULL)  
  121.             db->outblk = pdata->outblk;  
  122.   
  123.         if (pdata->dumpblk != NULL)  
  124.             db->dumpblk = pdata->dumpblk;  
  125.   
  126.         db->flags = pdata->flags;  
  127.     }  
  128.   
  129. #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL  
  130.     db->flags |= DM9000_PLATF_SIMPLE_PHY;  
  131. #endif  
  132.   
  133.     //复位网卡芯片  
  134.     dm9000_reset(db);  
  135.   
  136.     //读取设备ID,判断是否是驱动能够处理的网卡芯片  
  137.     /* try multiple times, DM9000 sometimes gets the read wrong */  
  138.     for (i = 0; i < 8; i++) {  
  139.         id_val  = ior(db, DM9000_VIDL);  
  140.         id_val |= (u32)ior(db, DM9000_VIDH) << 8;  
  141.         id_val |= (u32)ior(db, DM9000_PIDL) << 16;  
  142.         id_val |= (u32)ior(db, DM9000_PIDH) << 24;  
  143.   
  144.         if (id_val == DM9000_ID)  
  145.             break;  
  146.         dev_err(db->dev, "read wrong id 0x%08x\n", id_val);  
  147.     }  
  148.   
  149.     if (id_val != DM9000_ID) {  
  150.         dev_err(db->dev, "wrong id: 0x%08x\n", id_val);  
  151.         ret = -ENODEV;  
  152.         goto out;  
  153.     }  
  154.   
  155.     /* Identify what type of DM9000 we are working on */  
  156.   
  157.     id_val = ior(db, DM9000_CHIPR);  
  158.     dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);  
  159.   
  160.     switch (id_val) {  
  161.     case CHIPR_DM9000A:  
  162.         db->type = TYPE_DM9000A;  
  163.         break;  
  164.     case CHIPR_DM9000B:  
  165.         db->type = TYPE_DM9000B;  
  166.         break;  
  167.     default:  
  168.         dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);  
  169.         db->type = TYPE_DM9000E;  
  170.     }  
  171.   
  172.     /* from this point we assume that we have found a DM9000 */  
  173.   
  174.     /* driver system function */  
  175.     ether_setup(ndev);  
  176.   
  177.     //设置网卡芯片的接口函数  
  178.     ndev->open        = &dm9000_open;  
  179.     ndev->hard_start_xmit    = &dm9000_start_xmit;  
  180.     ndev->tx_timeout         = &dm9000_timeout;  
  181.     ndev->watchdog_timeo = msecs_to_jiffies(watchdog);  
  182.     ndev->stop        = &dm9000_stop;  
  183.     ndev->set_multicast_list = &dm9000_hash_table;  
  184.     ndev->ethtool_ops     = &dm9000_ethtool_ops;  
  185.     ndev->do_ioctl        = &dm9000_ioctl;  
  186.   
  187. #ifdef CONFIG_NET_POLL_CONTROLLER  
  188.     ndev->poll_controller     = &dm9000_poll_controller;  
  189. #endif  
  190.   
  191.     db->msg_enable       = NETIF_MSG_LINK;  
  192.     db->mii.phy_id_mask  = 0x1f;  
  193.     db->mii.reg_num_mask = 0x1f;  
  194.     db->mii.force_media  = 0;  
  195.     db->mii.full_duplex  = 0;  
  196.     db->mii.dev       = ndev;  
  197.     db->mii.mdio_read    = dm9000_phy_read;  
  198.     db->mii.mdio_write   = dm9000_phy_write;  
  199.   
  200.     mac_src = "eeprom";  
  201.   
  202.     //从EEPROM中读取MAC地址填充dev_addr  
  203.     /* try reading the node address from the attached EEPROM */  
  204.     for (i = 0; i < 6; i += 2)  
  205.         dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);  
  206.   
  207.     if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {  
  208.         mac_src = "platform data";  
  209.         memcpy(ndev->dev_addr, pdata->dev_addr, 6);  
  210.     }  
  211.   
  212.     if (!is_valid_ether_addr(ndev->dev_addr)) {  
  213.         /* try reading from mac */  
  214.           
  215.         mac_src = "chip";  
  216.         for (i = 0; i < 6; i++)  
  217.             ndev->dev_addr[i] = ior(db, i+DM9000_PAR);  
  218.     }  
  219.   
  220.     if (!is_valid_ether_addr(ndev->dev_addr))  
  221.         dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "  
  222.              "set using ifconfig\n", ndev->name);  
  223.   
  224.     //设置平台设备驱动的dev成员为ndev。  
  225.     platform_set_drvdata(pdev, ndev);  
  226.   
  227.     //注册网络设备驱动  
  228.     ret = register_netdev(ndev);  
  229.   
  230.     if (ret == 0)  
  231.         printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",  
  232.                ndev->name, dm9000_type_to_char(db->type),  
  233.                db->io_addr, db->io_data, ndev->irq,  
  234.                ndev->dev_addr, mac_src);  
  235.     return 0;  
  236.   
  237. out:  
  238.     dev_err(db->dev, "not found (%d).\n", ret);  
  239.   
  240.     dm9000_release_board(pdev, db);  
  241.     free_netdev(ndev);  
  242.   
  243.     return ret;  
  244. }  

我们在来看看读写网卡寄存器所用的ior和iow

  1. static u8  
  2. ior(board_info_t * db, int reg)  
  3. {  
  4.     writeb(reg, db->io_addr);  
  5.     return readb(db->io_data);  
  6. }  
  7.   
  8. static void  
  9. iow(board_info_t * db, int reg, int value)  
  10. {  
  11.     writeb(reg, db->io_addr);  
  12.     writeb(value, db->io_data);  
  13. }  

可以看得出是先将要访问的寄存器地址写入到地址寄存器,然后在将数据写入到数据寄存器。地址。

             

3.打开网卡

 

在linux终端下使用ifconfig命令时调用net_device的open函数打开网卡设备

  1. static int  
  2. dm9000_open(struct net_device *dev)  
  3. {  
  4.     board_info_t *db = netdev_priv(dev);  
  5.     unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;  
  6.   
  7.     if (netif_msg_ifup(db))  
  8.         dev_dbg(db->dev, "enabling %s\n", dev->name);  
  9.   
  10.     /* If there is no IRQ type specified, default to something that  
  11.      * may work, and tell the user that this is a problem */  
  12.   
  13.     if (irqflags == IRQF_TRIGGER_NONE)  
  14.         dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");  
  15.   
  16.     irqflags |= IRQF_SHARED;  
  17.   
  18.     //申请中断  
  19.     if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))  
  20.         return -EAGAIN;  
  21.   
  22.     /* Initialize DM9000 board */  
  23.     //复位网卡芯片  
  24.     dm9000_reset(db);  
  25.   
  26.     //初始化网卡(相关寄存器设置)  
  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.   
  34.     //打开发送队列  
  35.     netif_start_queue(dev);  
  36.       
  37.     //调度发送队列开始工作  
  38.     dm9000_schedule_poll(db);  
  39.   
  40.     return 0;  
  41. }   

4.数据发送

 

下面说一下DM9000A中的存储部分,DM9000A内部有一个4K Dword SRAM,其中3KB是作为发送,16KB作为接收,如下图所示。其中0x0000~0x0BFF是传说中的TX buffer(TX buffer中只能存放两个包),0x0C00~0x3FFF是RX buffer。因此在写内存操作时,当IMR的第7位被设置,如果到达了地址的结尾比如到了3KB,则回卷到0。相似的方式,在读操作中,当IMR的第7 位被设置如果到达了地址的结尾比如16K,则回卷到0x0C00。


DM9000的TX RAM可以同时放两个包,可以第9行代码中看出如果大于TXRAM中的包大于2则返回,DM9000会先发送第一个包,然后再发第二个包。

  1. pre><pre name="code" class="html">static int  
  2. dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)  
  3. {  
  4.     unsigned long flags;  
  5.     board_info_t *db = netdev_priv(dev);  
  6.   
  7.     dm9000_dbg(db, 3, "%s:\n", __func__);  
  8.   
  9.     //如果TX RAM中的包大于2个包则返回  
  10.     if (db->tx_pkt_cnt > 1)  
  11.         return 1;  
  12.   
  13.     spin_lock_irqsave(&db->lock, flags);  
  14.   
  15.     *MWCMD是Memory data write command with address increment Register(F8H)   
  16.      *将要访问的TXRAM地址写入地址寄存器。  
  17.   
  18.     /* Move data to DM9000 TX RAM */  
  19.     writeb(DM9000_MWCMD, db->io_addr);  
  20.   
  21.     //拷贝数据到TXRAM  
  22.     (db->outblk)(db->io_data, skb->data, skb->len);  
  23.     dev->stats.tx_bytes += skb->len;  
  24.   
  25.     db->tx_pkt_cnt++;//增加数据包计数,这个值会在发送完成中断时进行自减  
  26.   
  27.     如果是第一个包则直接发送  
  28.     /* TX control: First packet immediately send, second packet queue */  
  29.     if (db->tx_pkt_cnt == 1) {  
  30.   
  31.         /* Set TX length to DM9000 */  
  32.       /*把数据的长度填到TXPLL(发送包长度低字节)和TXPLH(发送包长度高字节)中*/    
  33.         iow(db, DM9000_TXPLL, skb->len);    
  34.         iow(db, DM9000_TXPLH, skb->len >> 8);    
  35.         /*置发送控制寄存器(TX Control Register)的发送请求位TXREQ(Auto clears after sending completely),这样就可以发送出去了*/   
  36.   
  37.     /*   
  38.          *记下此时的时间,这里起一个时间戳的作用,之后的超时会用到。如果当前的系统时间超过设备的trans_start时间   
  39.          *至少一个超时周期,网络层将最终调用驱动程序的tx_timeout。那个这个"一个超时周期"又是什么呢?这个是我们在   
  40.              *probe函数中设置的,ndev->watchdog_timeo = msecs_to_jiffies(watchdog);   
  41.          */  
  42.         dev->trans_start = jiffies;  /* save the time stamp */  
  43.     } else {          
  44. //如果是第二个包,则暂时不发送,等待第一个包发送完成时tx_pkt_cnt减为1的时候再发送。  
  45.         /* Second packet */  
  46.         db->queue_pkt_len = skb->len;  
  47.         netif_stop_queue(dev);//停止发送队列  
  48.     }  
  49.   
  50.     spin_unlock_irqrestore(&db->lock, flags);  
  51.   
  52.     /* free this SKB */  
  53.     dev_kfree_skb(skb);  
  54.   
  55.     return 0;  
  56. }  


4.中断

  1. static irqreturn_t dm9000_interrupt(intirq, void *dev_id)  
  2. {  
  3.          structnet_device *dev = dev_id;  
  4.          board_info_t*db = netdev_priv(dev);  
  5.          intint_status;  
  6.          unsignedlong flags;  
  7.          u8reg_save;  
  8.    
  9.          dm9000_dbg(db,3, "entering %s\n", __func__);  
  10.    
  11.          /*A real interrupt coming */  
  12.    
  13.          //禁止所用中断  
  14.          /*holders of db->lock must always block IRQs */  
  15.          spin_lock_irqsave(&db->lock,flags);  
  16.    
  17.          //保存寄存器地址  
  18.          /*Save previous register address */  
  19.          reg_savereadb(db->io_addr);  
  20.    
  21.          //禁止DM9000的所有中断  
  22.          /*Disable all interrupts */  
  23.          iow(db,DM9000_IMR, IMR_PAR);  
  24.    
  25.          /*Got DM9000 interrupt status */  
  26.          //获取中断状态寄存器的值  
  27.          int_statusior(db, DM9000_ISR); /* Got ISR */  
  28.          iow(db,DM9000_ISR, int_status); /* Clear ISRstatus */  
  29.    
  30.          if(netif_msg_intr(db))  
  31.                    dev_dbg(db->dev,"interrupt status %02x\n", int_status);  
  32.    
  33.          /*Received the coming packet */  
  34.          //如果是读取中断,则开始读取  
  35.          if(int_status & ISR_PRS)  
  36.                    dm9000_rx(dev);  
  37.    
  38.          /*Trnasmit Interrupt check */  
  39.          //是发送完成中断则处理发送完成后的事情  
  40.          if(int_status & ISR_PTS)  
  41.                    dm9000_tx_done(dev,db);  
  42.    
  43.          if(db->type != TYPE_DM9000E) {  
  44.                    if(int_status & ISR_LNKCHNG) {  
  45.                             /*fire a link-change request */  
  46.                             schedule_delayed_work(&db->phy_poll,1);  
  47.                    }  
  48.          }  
  49.    
  50.          /*Re-enable interrupt mask */  
  51.          //重新打开DM9000的内部中断  
  52.          iow(db,DM9000_IMR, db->imr_all);  
  53.    
  54.          /*Restore previous register address */  
  55.          //恢复寄存器的值  
  56.          writeb(reg_save,db->io_addr);  
  57.    
  58.          //重新允许所有中断  
  59.          spin_unlock_irqrestore(&db->lock,flags);  
  60.    
  61.          returnIRQ_HANDLED;  
  62. }  

5.接收数据

  1. pre><pre name="code" class="html">static void  
  2. dm9000_rx(struct net_device *dev)  
  3. {  
  4.     board_info_t *db = netdev_priv(dev);  
  5.     struct dm9000_rxhdr rxhdr;  
  6.     struct sk_buff *skb;  
  7.     u8 rxbyte, *rdptr;  
  8.     bool GoodPacket;  
  9.     int RxLen;  
  10.   
  11.     /* Check packet ready or not */  
  12.     do {  
  13.         ior(db, DM9000_MRCMDX); /* Dummy read */  
  14.   
  15.         //获取接收数据的长度  
  16.         /* Get most updated data */  
  17.         rxbyte = readb(db->io_data);  
  18.   
  19.         //检查设备接收状态  
  20.         /* Status check: this byte must be 0 or 1 */  
  21.         if (rxbyte > DM9000_PKT_RDY) {  
  22.             dev_warn(db->dev, "status check fail: %d\n", rxbyte);  
  23.             iow(db, DM9000_RCR, 0x00);  /* Stop Device */  
  24.             iow(db, DM9000_ISR, IMR_PAR);   /* Stop INT request */  
  25.             return;  
  26.         }  
  27.   
  28.         if (rxbyte != DM9000_PKT_RDY)  
  29.             return;  
  30.   
  31.           
  32.         /* A packet ready now  & Get status/length */  
  33.         GoodPacket = true;  
  34.         writeb(DM9000_MRCMD, db->io_addr);  
  35.   
  36.         (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));  
  37.   
  38.         RxLen = le16_to_cpu(rxhdr.RxLen);  
  39.   
  40.         if (netif_msg_rx_status(db))  
  41.             dev_dbg(db->dev, "RX: status %02x, length %04x\n",  
  42.                 rxhdr.RxStatus, RxLen);  
  43.   
  44.         /* Packet Status check */  
  45.         if (RxLen < 0x40) {  
  46.             GoodPacket = false;  
  47.             if (netif_msg_rx_err(db))  
  48.                 dev_dbg(db->dev, "RX: Bad Packet (runt)\n");  
  49.         }  
  50.   
  51.         if (RxLen > DM9000_PKT_MAX) {  
  52.             dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);  
  53.         }  
  54.   
  55.         /* rxhdr.RxStatus is identical to RSR register. */  
  56.         if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |  
  57.                       RSR_PLE | RSR_RWTO |  
  58.                       RSR_LCS | RSR_RF)) {  
  59.             GoodPacket = false;  
  60.             if (rxhdr.RxStatus & RSR_FOE) {  
  61.                 if (netif_msg_rx_err(db))  
  62.                     dev_dbg(db->dev, "fifo error\n");  
  63.                 dev->stats.rx_fifo_errors++;  
  64.             }  
  65.             if (rxhdr.RxStatus & RSR_CE) {  
  66.                 if (netif_msg_rx_err(db))  
  67.                     dev_dbg(db->dev, "crc error\n");  
  68.                 dev->stats.rx_crc_errors++;  
  69.             }  
  70.             if (rxhdr.RxStatus & RSR_RF) {  
  71.                 if (netif_msg_rx_err(db))  
  72.                     dev_dbg(db->dev, "length error\n");  
  73.                 dev->stats.rx_length_errors++;  
  74.             }  
  75.         }  
  76.   
  77.         /* Move data from DM9000 */  
  78.         //如果接收正确,开始接收  
  79.         if (GoodPacket  
  80.             && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {  
  81.             skb_reserve(skb, 2);  
  82.             rdptr = (u8 *) skb_put(skb, RxLen - 4);//获取skb的数据指针  
  83.   
  84.             /* Read received packet from RX SRAM */  
  85.   
  86.             (db->inblk)(db->io_data, rdptr, RxLen);//读取数据  
  87.             dev->stats.rx_bytes += RxLen;  
  88.   
  89.             /* Pass to upper layer */  
  90.             skb->protocol = eth_type_trans(skb, dev);  
  91.             netif_rx(skb);//将接收到的skb交给协议层  
  92.             dev->stats.rx_packets++;  
  93.   
  94.         } else {  
  95.             /* need to dump the packet's data */  
  96.   
  97.             (db->dumpblk)(db->io_data, RxLen);  
  98.         }  
  99.     } while (rxbyte == DM9000_PKT_RDY);  


上一篇:arm linux驱动编写中,能否直接进行ioremap?
下一篇:网络设备驱动基本原理和框架《转》