Broadcom softmac WLAN 驱动解析(2)

现在我们来看看driver是如何从WLAN chipset那里接收数据的

在上一篇文章中提到,数据过来时会产生中断,而在brcms_attach()函数体中,虚拟主机,注册的interrupt handler是brcms_isr(),所以数据过来触发的第一个函数就是brcms_isr()。

1. 触发brcms_isr()

static irqreturn_t brcms_isr(int irq, void *dev_id){struct brcms_info *wl;irqreturn_t ret = IRQ_NONE;wl = (struct brcms_info *) dev_id;spin_lock(&wl->isr_lock);(brcms_c_isr(wl->wlc)) {tasklet_schedule(&wl->tasklet);ret = IRQ_HANDLED;}spin_unlock(&wl->isr_lock);return ret;}

这里通过tasklet_schedule()来运行tasklet。在brcms_attach()中,香港虚拟主机,已经用tasklet_init()指定了底半部的handler是brcms_dpc.

2. 触发brcms_dpc()

void brcms_dpc(unsigned long data){  …(wl->pub->up) {if (wl->resched) {unsigned long flags;spin_lock_irqsave(&wl->isr_lock, flags);brcms_c_intrsupd(wl->wlc);spin_unlock_irqrestore(&wl->isr_lock, flags);}wl->resched = brcms_c_dpc(wl->wlc, true);}  …}

3. 调用brcms_c_dpc()

/* second-level interrupt processing * Return true if another dpc needs to be re-scheduled. false otherwise. * Param ‘bounded’ indicates if applicable loops should be bounded. */bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded){…/** received data or control frame, MI_DMAINT is* indication of RX_FIFO interrupt*/if (macintstatus & MI_DMAINT)if (brcms_b_recv(wlc_hw, RX_FIFO, bounded))wlc->macintstatus |= MI_DMAINT;…}

4. 调用brcms_b_recv()

brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound){…skb_queue_head_init(&recv_frames); {(n >= bound_limit)break;morepending = dma_rx(wlc_hw->di[fifo], &recv_frames);n++;} while (morepending);dma_rxfill(wlc_hw->di[fifo]);skb_queue_walk_safe(&recv_frames, p, next) {struct d11rxhdr_le *rxh_le;struct d11rxhdr *rxh;skb_unlink(p, &recv_frames);rxh_le = (struct d11rxhdr_le *)p->data;rxh = (struct d11rxhdr *)p->data;…brcms_c_recv(wlc_hw->wlc, p);}return morepending;}

5. 调用brcms_c_recv()

* Return true if more frames need to be processed. false otherwise. * Param ‘bound’ indicates max. # frames to process before break out. brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p){…is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK;if (is_amsdu)goto toss;brcms_c_recvctl(wlc, rxh, p);return;toss:brcmu_pkt_buf_free_skb(p);}

6. 调用brcms_c_recvctl()

static voidbrcms_c_recvctl(struct brcms_c_info *wlc, struct d11rxhdr *rxh,struct sk_buff *p){int len_mpdu;struct ieee80211_rx_status rx_status;struct ieee80211_hdr *hdr;memset(&rx_status, 0, sizeof(rx_status));prep_mac80211_status(wlc, rxh, p, &rx_status);len_mpdu = p->len – D11_PHY_HDR_LEN – FCS_LEN;skb_pull(p, D11_PHY_HDR_LEN);__skb_trim(p, len_mpdu);(wlc->hw->suspended_fifos) {hdr = (struct ieee80211_hdr *)p->data;if (ieee80211_is_beacon(hdr->frame_control))brcms_b_mute(wlc->hw, false);}memcpy(IEEE80211_SKB_RXCB(p), &rx_status, sizeof(rx_status));ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p);}

这里我们暂时只需要关注最后一行,也就是ieee80211_rx_irqsafe()

7. 调用ieee80211_rx_irqsafe()

/* This is a version of the rx handler that can be called from hard irq * context. Post the skb on the queue and schedule the tasklet */void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb){struct ieee80211_local *local = hw_to_local(hw);BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));skb->pkt_type = IEEE80211_RX_MSG;skb_queue_tail(&local->skb_queue, skb);tasklet_schedule(&local->tasklet);}

关键的一行代码是tasklet_schedule(), 回忆一下我们在分析ieee80211_alloc_hw()时提到的这句代码:

tasklet_init(&local->tasklet,ieee80211_tasklet_handler,(unsigned long) local);

这里终于派上了用场,ieee80211_tasklet_handler被触发了。

8. 调用ieee80211_tasklet_handler()

其实,每个人都是幸福的。只是,你的幸福,常常在别人眼里。

Broadcom softmac WLAN 驱动解析(2)

相关文章:

  • 【算法】直接插入排序C语言实现
  • 嵌入式 FAAC1.28 在海思HI3518C/HI3518A平台linux中的编译优化
  • 你感兴趣的文章:

    标签云:

    亚洲高清电影在线, 免费高清电影, 八戒影院夜间, 八戒电影最新大片, 出轨在线电影, 午夜电影院, 在线影院a1166, 在线电影院, 在线观看美剧下载, 日本爱情电影, 日韩高清电影在线, 电影天堂网, 直播盒子app, 聚合直播, 高清美剧, 高清美剧在线观看 EhViewer-E站, E站, E站绿色版, qqmulu.com, qq目录网, qq网站目录,