zoukankan      html  css  js  c++  java
  • DM9000网卡驱动深度分析

    一、dm9000_porbe函数分析
    不同于u-boot代码,tq2440中的DM9000更加复杂,需要分析的点也很多:
    1. /*
    2.  * Search DM9000 board, allocate space and register it
    3.  */
    4. static int __devinit
    5. dm9000_probe(struct platform_device *pdev)
    6. {
    7.     struct dm9000_plat_data *pdata = pdev->dev.platform_data;
    8.     struct board_info *db;    /* Point a board information structure */
    9.     struct net_device *ndev;
    10.     const unsigned char *mac_src;
    11.     int ret = 0;
    12.     int iosize;
    13.     int i;
    14.     u32 id_val;

    15. #if defined(CONFIG_ARCH_S3C2410)
    16.     unsigned int oldval_bwscon = *(volatile unsigned int *)S3C2410_BWSCON;
    17.     unsigned int oldval_bankcon4 = *(volatile unsigned int *)S3C2410_BANKCON4;
    18. #endif

    19.     /* Init network device */
    20.     ndev = alloc_etherdev(sizeof(struct board_info));                                     //分配netdev结构
    21.     if (!ndev) {
    22.         dev_err(&pdev->dev, "could not allocate device. ");
    23.         return -ENOMEM;
    24.     }

    25.     SET_NETDEV_DEV(ndev, &pdev->dev);

    26.     dev_dbg(&pdev->dev, "dm9000_probe() ");                     //不管

    27. #if defined(CONFIG_ARCH_S3C2410)                                 //2410可以不管
    28. //    *((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
    29.     *((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 ;
    30.     *((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;
    31. #endif

    32.     /* setup board info structure */
    33.     db = netdev_priv(ndev);
    34.     memset(db, 0, sizeof(*db));

    35.     db->dev = &pdev->dev;
    36.     db->ndev = ndev;

    37.     spin_lock_init(&db->lock);
    38.     mutex_init(&db->addr_lock);

    39.     INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);

    40.     db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);                  //获取平台资源,对应的platform_driver
    41.     db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
    42.     db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    43.    
    44.    ..................
    45. }
    从这里可以引出之前的知识点:平台设备和平台驱动的相关知识。在dm9000.c中有:
    1. static struct platform_driver dm9000_driver = {
    2.     .driver    = {
    3.         .name = "dm9000",                                                //这个平台驱动通过name和tq2440中的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. };
    在arch/arm/mach-tq2440.c:
    1. struct platform_device s3c_device_dm9000 = {
    2.     .name        = "dm9000",                                          //这里有同样的name来实现
    3.     .id            = 0,
    4.     .num_resources    = ARRAY_SIZE(s3c_dm9k_resource),
    5.     .resource        = s3c_dm9k_resource,                             //这里保存着dm9000硬件的资源
    6.     .dev            = {
    7.         .platform_data = &s3c_dm9k_platdata,
    8.     }
    9. };
    同样在此文件中:
    1. static struct resource s3c_dm9k_resource[] = {
    2.     [0] = {                                               //用的片选4
    3.         .start    = S3C2410_CS4,                          //这里的起始地址是0x20000000和网上一些0x20000300不一样。wu'suo
    4.         .end    = S3C2410_CS4 + 3,                        //.end为什么尾地址是+3?因为一个地址需要四个字节。这是根据网卡来定义的
    5.         .flags    = IORESOURCE_MEM,
    6.     },
    7.     [1] = {                                               //0x20000004~0x20000007?
    8.         .start    = S3C2410_CS4 + 4,                      //这里的4意味着地址线2等于1,设置了cmd为高位,是数据内容
    9.         .end    = S3C2410_CS4 + 4 + 3,
    10.         .flags    = IORESOURCE_MEM,
    11.     },
    12.     [2] = {
    13.         .start    = IRQ_EINT7,                            //对应的中断信息
    14.         .end    = IRQ_EINT7,
    15.         .flags    = IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
    16.     }

    17. };
    回来继续看dm9000.c中的probe函数:
    1.     db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    2.     db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
    3.     db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

    4.     if (db->addr_res == NULL || db->data_res == NULL ||
    5.      db->irq_res == NULL) {
    6.         dev_err(db->dev, "insufficient resources ");
    7.         ret = -ENOENT;
    8.         goto out;
    9.     }

    10.     iosize = res_size(db->addr_res);
    11.     db->addr_req = request_mem_region(db->addr_res->start, iosize,
    12.                      pdev->name);

    13.     if (db->addr_req == NULL) {
    14.         dev_err(db->dev, "cannot claim address reg area ");
    15.         ret = -EIO;
    16.         goto out;
    17.     }

    18.     db->io_addr = ioremap(db->addr_res->start, iosize);                    //将地址信息重映射

    19.     if (db->io_addr == NULL) {
    20.         dev_err(db->dev, "failed to ioremap address reg ");
    21.         ret = -EINVAL;
    22.         goto out;
    23.     }

    24.     iosize = res_size(db->data_res);
    25.     db->data_req = request_mem_region(db->data_res->start, iosize,
    26.                      pdev->name);

    27.     if (db->data_req == NULL) {
    28.         dev_err(db->dev, "cannot claim data reg area ");
    29.         ret = -EIO;
    30.         goto out;
    31.     }

    32.     db->io_data = ioremap(db->data_res->start, iosize);               //将数据信息重映射

    33.     if (db->io_data == NULL) {
    34.         dev_err(db->dev, "failed to ioremap data reg ");
    35.         ret = -EINVAL;
    36.         goto out;
    37.     }

    38.     .........................

    39.     id_val = ior(db, DM9000_CHIPR);                                    //读取芯片信息
    40. //    dev_dbg(db->dev, "dm9000 revision 0x%02x io_mode %02x ", id_val, db->io_mode);
    41.     printk(KERN_INFO "dm9000 revision 0x%02x io_mode %02x ", id_val, db->io_mode);

    42.     switch (id_val) {
    43.     case CHIPR_DM9000A:
    44.         db->type = TYPE_DM9000A;
    45.         break;
    46.     case CHIPR_DM9000B:
    47.         db->type = TYPE_DM9000B;
    48.         break;
    49.     case CHIPR_DM9000C:
    50.         db->type = TYPE_DM9000C;
    51.         break;
    52.     default:
    53.         dev_dbg(db->dev, "ID %02x => defaulting to DM9000E ", id_val);
    54.         db->type = TYPE_DM9000E;
    55.     }

    56.     /* from this point we assume that we have found a DM9000 */

    57.     /* driver system function */                                                //下面在设置dm9000的操作函数集了
    58.     ether_setup(ndev);

    59.     ndev->open         = &dm9000_open;
    60.     ndev->hard_start_xmit = &dm9000_start_xmit;
    61.     ndev->tx_timeout = &dm9000_timeout;
    62.     ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
    63.     ndev->stop         = &dm9000_stop;
    64.     ndev->set_multicast_list = &dm9000_hash_table;
    65.     ndev->ethtool_ops     = &dm9000_ethtool_ops;
    66.     ndev->do_ioctl         = &dm9000_ioctl;

    67. #ifdef CONFIG_NET_POLL_CONTROLLER
    68.     ndev->poll_controller     = &dm9000_poll_controller;
    69. #endif

    70.     db->msg_enable = NETIF_MSG_LINK;
    71.     db->mii.phy_id_mask = 0x1f;
    72.     db->mii.reg_num_mask = 0x1f;
    73.     db->mii.force_media = 0;
    74.     db->mii.full_duplex = 0;
    75.     db->mii.dev     = ndev;
    76.     db->mii.mdio_read = dm9000_phy_read;
    77.     db->mii.mdio_write = dm9000_phy_write;

    78. #if defined(CONFIG_ARCH_S3C2410)
    79.     printk("Now use the default MAC address: 10:23:45:67:89:ab ");
    80.     mac_src = "EmbedSky";
    81.     ndev->dev_addr[0] = 0x10;
    82.     ndev->dev_addr[1] = 0x23;
    83.     ndev->dev_addr[2] = 0x45;
    84.     ndev->dev_addr[3] = 0x67;
    85.     ndev->dev_addr[4] = 0x89;
    86.     ndev->dev_addr[5] = 0xab;
    87. #else
    88.     mac_src = "eeprom";

    89.     /* try reading the node address from the attached EEPROM */         //读取MAC地址,从EEPROM中
    90.     for (i = 0; i < 6; i += 2)
    91.         dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);

    92.     if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
    93.         mac_src = "platform data";
    94.         memcpy(ndev->dev_addr, pdata->dev_addr, 6);
    95.     }

    96.     if (!is_valid_ether_addr(ndev->dev_addr)) {
    97.         /* try reading from mac */
    98.         
    99.         mac_src = "chip";
    100.         for (i = 0; i < 6; i++)
    101.             ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
    102.     }

    103.     if (!is_valid_ether_addr(ndev->dev_addr))
    104.         dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
    105.              "set using ifconfig ", ndev->name);
    106. #endif

    107.     platform_set_drvdata(pdev, ndev);
    108.     ret = register_netdev(ndev);                                           //注册网卡驱动

    109.     if (ret == 0)
    110.         printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s) ",
    111.          ndev->name, dm9000_type_to_char(db->type),
    112.          db->io_addr, db->io_data, ndev->irq,
    113.          ndev->dev_addr, mac_src);
    114.     return 0;

    115. out:
    116. #if defined(CONFIG_ARCH_S3C2410)
    117.     *(volatile unsigned int *)S3C2410_BWSCON = oldval_bwscon;
    118.     *(volatile unsigned int *)S3C2410_BANKCON4 = oldval_bankcon4;
    119. #endif
    120.     dev_err(db->dev, "not found (%d). ", ret);

    121.     dm9000_release_board(pdev, db);
    122.     free_netdev(ndev);

    123.     return ret;
    124. }
    二、DM9000_OPEN函数分析
    在probe中没有太多的dm9000的初始化代码,都写在了open中(这个open函数在ifconfig eth0 192.168.1.1时调用):
    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.     if (netif_msg_ifup(db))
    11.         dev_dbg(db->dev, "enabling %s ", dev->name);

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

    14.     if (irqflags == IRQF_TRIGGER_NONE)
    15.         dev_warn(db->dev, "WARNING: no IRQ resource flags set. ");

    16.     irqflags |= IRQF_SHARED;

    17.     if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))                      //注册网卡驱动的中断处理函数
    18.         return -EAGAIN;

    19.     /* Initialize DM9000 board */
    20. //    dm9000_reset(db);
    21.     dm9000_init_dm9000(dev);                                                                     //网卡初始化在这里

    22.     /* Init driver variable */
    23.     db->dbug_cnt = 0;

    24.     mii_check_media(&db->mii, netif_msg_link(db), 1);
    25.     netif_start_queue(dev);                                                                      //启动发送队列
    26.     
    27.     dm9000_schedule_poll(db);

    28.     return 0;
    29. }
    DM9000初始化:
    ①分配net_device结构
    ②从platform_device中获取地址,中断号
    ③把获取到的地址映射为虚拟地址
    ④读取芯片类型
    ⑤设置操作函数集
    ⑥注册网卡驱动

    三、dm9000_start_xmit发送函数分析

    dm9000_start_xmit:
    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.     int save_mwr, check_mwr, calc_mwr;    

    11.     dm9000_dbg(db, 3, "%s: ", __func__);

    12.     if ((db->tx_pkt_cnt > 0) || !netif_carrier_ok(dev))
    13.         return 1;

    14.     spin_lock_irqsave(&db->lock, flags);
    15.     
    16.     netif_stop_queue(dev);                                                                                     //通知协议栈,暂停向驱动传送数据
    17.     db->tx_pkt_cnt++;
    18.     dev->stats.tx_bytes += skb->len;
    19.     dev->stats.tx_packets++;
    20.     
    21.     save_mwr = (ior(db, 0xfb) << 8) | ior(db, 0xfa);
    22.     calc_mwr = save_mwr + skb->len;
    23.     if(skb->len & 0x01) calc_mwr++;
    24.     if(calc_mwr > 0x0bff ) calc_mwr -= 0x0c00;

    25.     /* Set TX length to DM9000 */                                                                              //获取发送长度
    26.     iow(db, DM9000_TXPLL, skb->len);
    27.     iow(db, DM9000_TXPLH, skb->len >> 8);
    28.     
    29.     /* Move data to DM9000 TX RAM */                                                                           //将要发送的数据发送入缓存
    30.     writeb(DM9000_MWCMD, db->io_addr);
    31.     (db->outblk)(db->io_data, skb->data, skb->len);                                                            //skb->data,skb->len分别指向结构体数据的头和尾

    32.     /* Issue TX polling command */
    33.     iow(db, DM9000_TCR, TCR_TXREQ);    /* Cleared after TX complete */                                         //清除发送位

    34.     dev->trans_start = jiffies;    /* save the time stamp */
    35.     
    36.     check_mwr = (ior(db, 0xfb) << 8) | ior(db, 0xfa);
    37.     if(calc_mwr != check_mwr)
    38.     {
    39.         printk(KERN_INFO "TX: fifo error %04x %04x %04x %04x ", save_mwr, skb->len, calc_mwr, check_mwr);
    40.         iow(db, 0xfb, (calc_mwr >> 8) & 0xff);
    41.         iow(db, 0xfa, calc_mwr & 0xff);
    42.     }            

    43.     spin_unlock_irqrestore(&db->lock, flags);

    44.     /* free this SKB */
    45.     dev_kfree_skb(skb);                                                                                          //释放SKB结构

    46.     return 0;
    47. }
    发送完成产生中断(dm9000_interrupt):
    1. static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
    2. {
    3.     struct net_device *dev = dev_id;
    4.     board_info_t *db = netdev_priv(dev);
    5.     int int_status;
    6.     unsigned long flags;
    7.     u8 reg_save;

    8.     dm9000_dbg(db, 3, "entering %s ", __func__);

    9.     /* A real interrupt coming */

    10.     /* holders of db->lock must always block IRQs */
    11.     spin_lock_irqsave(&db->lock, flags);

    12.     /* Save previous register address */
    13.     reg_save = readb(db->io_addr);

    14.     /* Disable all interrupts */
    15.     iow(db, DM9000_IMR, IMR_PAR);

    16.     /* Got DM9000 interrupt status */
    17.     int_status = ior(db, DM9000_ISR);    /* Got ISR */
    18.     iow(db, DM9000_ISR, int_status);    /* Clear ISR status */

    19.     if (netif_msg_intr(db))
    20.         dev_dbg(db->dev, "interrupt status %02x ", int_status);

    21.     /* Received the coming packet */
    22.     if (int_status & ISR_PRS)
    23.         dm9000_rx(dev);                                                               //接收中断
    24.     
    25.     int_status |= ior(db, DM9000_ISR);    /* Got ISR */

    26.     /* Trnasmit Interrupt check */
    27.     if (int_status & ISR_PTS)
    28.     {
    29.         iow(db, DM9000_ISR, ISR_PTS);
    30.         dm9000_tx_done(dev, db);                                                      //发送中断
    31.     }

    32.     if (db->type != TYPE_DM9000E) {
    33.         if (int_status & ISR_LNKCHNG) {
    34.             /* fire a link-change request */
    35.             schedule_delayed_work(&db->phy_poll, 1);
    36.         }
    37.     }

    38.     /* Re-enable interrupt mask */
    39.     iow(db, DM9000_IMR, db->imr_all);

    40.     /* Restore previous register address */
    41.     writeb(reg_save, db->io_addr);

    42.     spin_unlock_irqrestore(&db->lock, flags);

    43.     return IRQ_HANDLED;
    44. }
    发送函数完成后进入中断dm9000_tx_done:
    1. /*
    2.  * DM9000 interrupt handler
    3.  * receive the packet to upper layer, free the transmitted packet
    4.  */

    5. static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
    6. {
    7.     int tx_status = ior(db, DM9000_TCR);    /* Got TX status */                           //获取中断状态
    8.     
    9.     if(tx_status & TCR_TXREQ)                                                             //查看发送是否出错    
    10.     {
    11.         dev->stats.rx_fifo_errors++;                                                      //错误计数加1
    12.     }
    13.     else
    14.     {
    15.         db->tx_pkt_cnt = 0;
    16.         dev->trans_start = 0;
    17.         netif_wake_queue(dev);                                                            //调用netif_wake_queue(),通知协议栈发送数据
    18.     }
    19. }
    dm9000_rx():
    1. /*
    2.  * Received a packet and pass to upper layer
    3.  */
    4. static void
    5. dm9000_rx(struct net_device *dev)
    6. {
    7.     board_info_t *db = netdev_priv(dev);
    8.     struct dm9000_rxhdr rxhdr;
    9.     struct sk_buff *skb;
    10.     u8 rxbyte, *rdptr;
    11.     bool GoodPacket;
    12.     int RxLen;
    13.     int save_mrr, check_mrr, calc_mrr;

    14.     /* Check packet ready or not */
    15.     do {
    16.         ior(db, DM9000_MRCMDX);    /* Dummy read */                                                     //空读
    17.         save_mrr = (ior(db, 0xf5) << 8) | ior(db, 0xf4);
    18.         /* Get most updated data */
    19.         rxbyte = ior(db, DM9000_MRCMDX);                                                                //查看接收状态
    20.         
    21.         if(DM9000_PKT_RDY != rxbyte)                                                                    //是否已经ready
    22.         {
    23.             /* Status check: this byte must be 0 or 1 */
    24.             if (rxbyte) {
    25. //                dev_warn(db->dev, "status check fail: %d ", rxbyte);
    26.                 printk(KERN_INFO "status check fail: %d ", rxbyte);
    27.                 iow(db, DM9000_RCR, 0x00);    /* Stop Device */
    28.                 iow(db, DM9000_IMR, IMR_PAR);    /* Stop INT request */
    29.                 
    30.                 dm9000_init_dm9000(dev);
    31.             }
    32.             return;
    33.         }

    34.         /* A packet ready now & Get status/length */
    35.         GoodPacket = true;                                                           
    36.         writeb(DM9000_MRCMD, db->io_addr);                                                                //
    37.         (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));                                                  //dm9000_rxhdr结构中有rx_len,接收长度

    38.         calc_mrr = save_mrr + 4;
    39.         if(calc_mrr > 0x3fff) calc_mrr -= 0x3400;
    40.         
    41.         check_mrr = (ior(db, 0xf5) << 8) | ior(db, 0xf4);
    42.         if(calc_mrr != check_mrr)
    43.         {
    44.             printk(KERN_INFO "RX: 4 byte error %04x %04x %04x ", save_mrr, calc_mrr, check_mrr);
    45.             iow(db, 0xf5, (save_mrr >> 8) & 0xff);
    46.             iow(db, 0xf4, save_mrr & 0xff);
    47.             continue;
    48.         }
    49.         
    50.         writeb(DM9000_MRCMD, db->io_addr);
    51.         
    52.         RxLen = le16_to_cpu(rxhdr.RxLen);
    53.         
    54.         calc_mrr = save_mrr + 4 + RxLen;
    55.         if(RxLen & 0x01) calc_mrr++;
    56.         if(calc_mrr > 0x3fff) calc_mrr -= 0x3400;

    57.         if (netif_msg_rx_status(db))
    58.             dev_dbg(db->dev, "RX: status %02x, length %04x ",
    59.                 rxhdr.RxStatus, RxLen);

    60.         /* Packet Status check */                                                                     //判断长度
    61.         if (RxLen < 0x40) {
    62.             GoodPacket = false;
    63.             if (netif_msg_rx_err(db))
    64.                 dev_dbg(db->dev, "RX: Bad Packet (runt) ");
    65.         }

    66.         if (RxLen > DM9000_PKT_MAX) {
    67.             dev_dbg(db->dev, "RST: RX Len:%x ", RxLen);
    68.         }

    69.         /* rxhdr.RxStatus is identical to RSR register. */                                             //读取状态看有没有出错
    70.         if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
    71.                  RSR_PLE | RSR_RWTO |
    72.                  RSR_LCS | RSR_RF)) {
    73.             GoodPacket = false;
    74.             if (rxhdr.RxStatus & RSR_FOE) {
    75.                 if (netif_msg_rx_err(db))
    76.                     dev_dbg(db->dev, "fifo error ");
    77.                 dev->stats.rx_fifo_errors++;
    78.             }
    79.             if (rxhdr.RxStatus & RSR_CE) {
    80.                 if (netif_msg_rx_err(db))
    81.                     dev_dbg(db->dev, "crc error ");
    82.                 dev->stats.rx_crc_errors++;
    83.             }
    84.             if (rxhdr.RxStatus & RSR_RF) {
    85.                 if (netif_msg_rx_err(db))
    86.                     dev_dbg(db->dev, "length error ");
    87.                 dev->stats.rx_length_errors++;
    88.             }
    89.         }

    90.         /* Move data from DM9000 */                                                                       
    91.         if (GoodPacket
    92.          && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {                                                    //分配skb=接收到的数据长度+4
    93.             skb_reserve(skb, 2);                                                                             //skb中的ip包需要4字节对齐,所以skb要保留多2个字节。(以太网包格式)
    94.             rdptr = (u8 *) skb_put(skb, RxLen - 4);                                                          //skb的tail指针,数据包长度减4

    95.             /* Read received packet from RX SRAM */

    96.             (db->inblk)(db->io_data, rdptr, RxLen);                                                          //读取io_data地址到rdptr中
    97.             dev->stats.rx_bytes += RxLen;

    98.             /* Pass to upper layer */
    99.             skb->protocol = eth_type_trans(skb, dev);
    100.             netif_rx(skb);                                                                                   //把准备好的skb提交给上层协议
    101.             dev->stats.rx_packets++;
    102.             
    103.             check_mrr = (ior(db, 0xf5) << 8) | ior(db, 0xf4);
    104.             if(calc_mrr != check_mrr)
    105.             {
    106. //                dev_dbg(db->dev, "RX: fifo error %04x %04x %04x %04x ", save_mrr, RxLen, calc_mrr, check_mrr);
    107.                 printk(KERN_INFO "RX: fifo error %04x %04x %04x %04x ", save_mrr, RxLen, calc_mrr, check_mrr);
    108.                 iow(db, 0xf5, (calc_mrr >> 8) & 0xff);
    109.                 iow(db, 0xf4, calc_mrr & 0xff);
    110.             }            

    111.         } else {
    112.             /* need to dump the packet's data */
    113.             iow(db, 0xf5, (calc_mrr >> 8) & 0xff);
    114.             iow(db, 0xf4, calc_mrr & 0xff);
    115.         }
    116.         
    117.     } while (rxbyte == DM9000_PKT_RDY);
    118. }









    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    USACO提交方法
    洛谷 P1967 【货车运输】
    一本通 P1386 【打击犯罪】
    洛谷 P5767 【最优乘车】
    洛谷 P5658 【括号树】
    洛谷 P5657 【格雷码】
    洛谷 P2272 【最大半连通子图】
    二分图匈牙利算法
    最小生成树Kruskal算法
    觉得写出了抽象类和接口,以及概括了设计模式的宗旨
  • 原文地址:https://www.cnblogs.com/ch122633/p/7363302.html
Copyright © 2011-2022 走看看