高通無線接收流程

http://blog.csdn.net/suiyuan19840208/article/details/17562465


1:數據處理函數tasklet,workqueue

在之前的初始化代碼中的函數__ath_attach()中,有如下的代碼:

#ifndef ATH_SUPPORT_HTC
#ifdef ADF_SUPPORT
    ATH_INIT_TQUEUE(&osdev->intr_tq, (adf_os_defer_fn_t)ath_tasklet, (void*)dev);
#else
   ATH_INIT_TQUEUE(&osdev->intr_tq, ath_tasklet, dev);
#endif
#endif

首先開看看 ATH_INIT_TQUEUE()是怎麼定義的:
#ifdef DECLARE_TASKLET          /* native tasklets */
#define tq_struct tasklet_struct
#define ATH_INIT_TQUEUE(a,b,c)      tasklet_init((a),(b),(unsigned long)(c))
#define ATH_SCHEDULE_TQUEUE(a,b)    tasklet_schedule((a))
typedef unsigned long TQUEUE_ARG;
#define mark_bh(a)
#else                   /* immediate work queue */
#define ATH_INIT_TQUEUE(a,b,c)      INIT_TQUEUE(a,b,c)
#define ATH_SCHEDULE_TQUEUE(a,b) do {       \
    *(b) |= queue_task((a), &tq_immediate); \
} while(0)
typedef void *TQUEUE_ARG;
#define tasklet_disable(t)  do { (void) t; local_bh_disable(); } while (0)
#define tasklet_enable(t)   do { (void) t; local_bh_enable(); } while (0)
#endif /* !DECLARE_TASKLET */
有上面的定義可以知道:次數定義的是中斷處理函數的下半部,其實現採用倆種方式:tasklet和work_queue。
在中斷處理函數中將會調用task或者queue的調度函數即上面定義的:ATH_SCHEDULE_TQUEUE
函數ath_tasklet()定義如下:
static void ath_tasklet(TQUEUE_ARG data)
{
    struct net_device *dev = (struct net_device *)data;
    struct ath_softc_net80211 *scn = ath_netdev_priv(dev);
    do_ath_handle_intr(scn->sc_dev);
}
#define do_ath_handle_intr(_dev) do{ ath_handle_intr_generic(_dev);}while(0)
#define ath_handle_intr_generic(_dev)   scn->sc_ops->handle_intr(_dev) 

static const struct ath_ops ath_ar_ops = {
    ath_handle_intr,            /* handle_intr */
    ath_rx_tasklet,             /* rx_proc */

}
2:中斷的申請
在__ath_attach()有如下中斷申請代碼
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
    if (request_irq(dev->irq, ath_isr, SA_SHIRQ, dev->name, dev)) {
#else
#ifdef ATH_AHB
    if (request_irq(dev->irq, ath_isr, IRQF_DISABLED, dev->name, dev)) {
#else
    if (request_irq(dev->irq, ath_isr, IRQF_SHARED, dev->name, dev)) {
#endif
#endif
        printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
        error = -EIO;
        goto bad3;
    }  由此可知,中斷處理函數爲:
ath_isr(int irq, void *dev_id, struct pt_regs *regs)
{
    do_ath_isr(irq,dev_id,regs);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
#define do_ath_isr(_irq,_dev_id) do{ return ath_isr_generic(_irq,_dev_id);}while(0)
#else
#define do_ath_isr(_irq,_dev_id,_regs) do{ return ath_isr_generic(_irq,_dev_id,_regs);}while(0)
#endif //if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)


irqreturn_t ath_isr_generic(int irq, void *dev_id, struct pt_regs *regs)
#endif
{
    struct net_device *dev = dev_id;
    struct ath_softc_net80211 *scn = ath_netdev_priv(dev);
    int sched, needmark = 0;
    /* always acknowledge the interrupt */
    sched = scn->sc_ops->isr(scn->sc_dev);
    switch(sched)
    {
    case ATH_ISR_NOSCHED:
        return  IRQ_HANDLED;
        
    case ATH_ISR_NOTMINE:
        return IRQ_NONE;
        
    default:
        if ((dev->flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP))
        {
            DPRINTF_INTSAFE(scn, ATH_DEBUG_INTR, "%s: flags 0x%x\n", __func__, dev->flags);
            scn->sc_ops->disable_interrupt(scn->sc_dev);     /* disable further intr's */
            return IRQ_HANDLED;
        }
    }
    
    /*
    ** See if the transmit queue processing needs to be scheduled
    */
    
    ATH_SCHEDULE_TQUEUE(&scn->sc_osdev->intr_tq, &needmark);
    if (needmark)
        mark_bh(IMMEDIATE_BH);
    return IRQ_HANDLED;
}上面已經說明了在中斷處理函數中對tasklet或者workqueue的調度。
3:代碼執行流程

其代碼執行過程如下:




當數據數據之後,會交給函數ieee80211_input(),在測函數中會處理80211的三大數據包類似,數據幀,管理幀和控制幀。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章