注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

TCP/IP驱动八——中断处理函数  

2013-07-12 11:31:33|  分类: TCPIP驱动 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

TCP/IP驱动八——中断处理函数

 

   其实最核心的东西就在这里,中断。DM9000的驱动的中断(有些人会问为什么不用轮询,这个真是无语了)触发的时机有两种情况,一种是在接收到一个包后,一种是在发送完成一个包后。

  在前面说过,中断处理函数在open的时候被注册进内核。所以如果有不清楚的可以回头去看看。

static int  dm9000_open(struct net_device *dev)

{

…….

         if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))

…..

}

下面是中断的处理函数:

static irqreturn_t dm9000_interrupt(int irq, void *dev_id)   

{   

    struct net_device *dev = dev_id;   

    board_info_t *db = netdev_priv(dev);   

    int int_status;   

    unsigned long flags;   

    u8 reg_save;   

  

    dm9000_dbg(db, 3, "entering %s\n", __func__);   

  

    /* A real interrupt coming */  

  

    /* holders of db->lock must always block IRQs */  

    spin_lock_irqsave(&db->lock, flags);   

  

    /* Save previous register address */  

    reg_save = readb(db->io_addr);   

  

    /* Disable all interrupts */  

    iow(db, DM9000_IMR, IMR_PAR);   

  

    /* Got DM9000 interrupt status */  

    int_status = ior(db, DM9000_ISR);   /* Got ISR */  

    iow(db, DM9000_ISR, int_status);    /* Clear ISR status */  

  

    if (netif_msg_intr(db))   

        dev_dbg(db->dev, "interrupt status %02x\n", int_status);   

  

    /* Received the coming packet */  

        /*如果是由于收到数据而触发的中断,显然调用dm9000_rx()把数据取走,传递给上层*/  

    if (int_status & ISR_PRS)   

        dm9000_rx(dev);   

  

    /* Trnasmit Interrupt check */  

        /*如果是由于发送完了数据而触发的中断,则调用dm9000_tx_done()函数,下面具体分析这个函数*/  

    if (int_status & ISR_PTS)   

        dm9000_tx_done(dev, db);   

  

    if (db->type != TYPE_DM9000E) {    

        if (int_status & ISR_LNKCHNG) {   

            /* fire a link-change request */  

            schedule_delayed_work(&db->phy_poll, 1);   

        }   

    }   

  

    /* Re-enable interrupt mask */  

    iow(db, DM9000_IMR, db->imr_all);   

    /* Restore previous register address */  

    writeb(reg_save, db->io_addr);     

    spin_unlock_irqrestore(&db->lock, flags);     

    return IRQ_HANDLED;   

}  

   需要说明的是:dm9000可以发送两个数据包,当发送一个数据包产生中断后,要确认一下队列中有没有第2个包需要发送。

 

    1、读取dm9000寄存器NSRNetwork Status Register)获取发送的状态,存在变量tx_status中;

    2、如果发送状态为NSR_TX2END(第2个包发送完毕)或者NSR_TX1END(第1个包发送完毕),则将待发送的数据包数量(db-> tx_pkt_cnt )减1,已发送的数据包数量(dev->stats.tx_packets)加1

   3、检查变量db-> tx_pkt_cnt(待发送的数据包)是否大于0(表明还有数据包要发送),则调用函数dm9000_send_packet发送队列中的数据包;

  4、调用函数netif_wake_queue (dev)通知内核可以将待发送的数据包进入发送队列。

 

/*  

 * DM9000 interrupt handler  

 * receive the packet to upper layer, free the transmitted packet  

 */  

  

static void dm9000_tx_done(struct net_device *dev, board_info_t *db)   

{   

    int tx_status = ior(db, DM9000_NSR);    /* Got TX status */  

  

    if (tx_status & (NSR_TX2END | NSR_TX1END)) {   

        /* One packet sent complete */  

        db->tx_pkt_cnt--;   

        dev->stats.tx_packets++;   

  

        if (netif_msg_tx_done(db))   

            dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);   

  

        /* Queue packet check & send */  

        if (db->tx_pkt_cnt > 0) {   

            iow(db, DM9000_TXPLL, db->queue_pkt_len);   

            iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8);   

            iow(db, DM9000_TCR, TCR_TXREQ);   

            dev->trans_start = jiffies;   

        }   

        netif_wake_queue(dev);   

    }   

}

这样基本上整个DM9000的网卡的接收流程就差不多了。下来还有一些具体的细节函数,也没有多复杂了。上面的其实好多内核中的注释都是非常清楚的,再参考一下别人在网上的资料,基本就可以明白了。

总算可以松一口气了。

  评论这张
 
阅读(788)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017