1. 程式人生 > >wifi驅動的理解(4)——usb介面在wifi模組中的角色

wifi驅動的理解(4)——usb介面在wifi模組中的角色

         轉載請註明出處:http://blog.csdn.net/Righthek 謝謝!

         還有1天就到2017年了,回顧整個2016年至此,都沒發表過一篇技術文章。做軟體開發已有5、6年,作為一名過往都有寫技術文章的開發者,實屬不妥。技術的創新和發展實質上是一種傳承、共享與拓展。而在我的理解中,技術文章就是一種傳承與共享。

         去年開的【智慧家居篇】專欄還沒完成,現在這篇文章繼續這個專欄的技術分析。

         在上一篇文章中,當wifi模組的接收初始化函式中,註冊了中斷URB。即當wifi模組接收到資料的時候,通過中斷URB產生中斷之後,就會呼叫usb_read_port()函式,實現USB的讀取。

         現在我們再來看看WIFI的傳送,首先我們先WIFI傳送處理函式註冊為tasklet,程式碼如下:

s32   rtl8192cu_init_xmit_priv(_adapter *padapter)

{

         struct xmit_priv       *pxmitpriv= &padapter->xmitpriv;

 

#ifdef PLATFORM_LINUX

         tasklet_init(&pxmitpriv->xmit_tasklet,

              (void(*)(unsignedlong))rtl8192cu_xmit_tasklet,

              (unsignedlong)padapter);

#endif

         return _SUCCESS;

}

         在tasklet_init()中註冊rtl8192cu_xmit_tasklet()回撥函式。

voidrtl8192cu_xmit_tasklet(void *priv)

{       

         int ret = _FALSE;

         _adapter *padapter = (_adapter*)priv;

         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;

 

         if(check_fwstate(&padapter->mlmepriv,_FW_UNDER_SURVEY) == _TRUE)

                   return;

 

         while(1)

         {

                   if ((padapter->bDriverStopped ==_TRUE)||(padapter->bSurpriseRemoved== _TRUE) ||(padapter->bWritePortCancel == _TRUE))

                   {

                            DBG_8192C("xmit_tasklet =>bDriverStopped or bSurpriseRemoved or bWritePortCancel\n");

                            break;

                   }

 

                   ret = rtl8192cu_xmitframe_complete(padapter,pxmitpriv, NULL);

 

                   if(ret==_FALSE)

                            break;

                  

         }

}

         回撥函式rtl8192cu_xmitframe_complete主要是打包資料,然後將資料上傳到USB FIFO,最後通過usb_write_port()傳送到WIFI模組上。

s32rtl8192cu_xmitframe_complete(_adapter *padapter, struct xmit_priv *pxmitpriv,struct xmit_buf *pxmitbuf)

{

         HAL_DATA_TYPE      *pHalData= GET_HAL_DATA(padapter);

         struct xmit_frame *pxmitframe = NULL;

         struct xmit_frame *pfirstframe = NULL;

 

         // aggregate variable

         struct hw_xmit *phwxmit;

         struct sta_info *psta = NULL;

         struct tx_servq *ptxservq = NULL;


         _irqL irqL;

         _list *xmitframe_plist = NULL, *xmitframe_phead = NULL;

 

         u32  pbuf;         // next pkt address

         u32  pbuf_tail; // last pkt tail

         u32  len;  // packet length, except TXDESC_SIZE andPKT_OFFSET

 

         u32  bulkSize =pHalData->UsbBulkOutSize;

         u8     descCount;

         u32  bulkPtr;

 

         // dump frame variable

         u32 ff_hwaddr;

 

#ifndef IDEA_CONDITION

         int res = _SUCCESS;

#endif

 

         RT_TRACE(_module_rtl8192c_xmit_c_, _drv_info_,("+xmitframe_complete\n"));


         // check xmitbuffer is ok

         if (pxmitbuf == NULL) {

                   pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);

                   if (pxmitbuf == NULL) return _FALSE;

         }


1、先將資料進行打包 

         //3 1. pick up first frame

         do {

                   rtw_free_xmitframe(pxmitpriv, pxmitframe);

                           

                   pxmitframe = rtw_dequeue_xframe(pxmitpriv,pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);

                   if (pxmitframe == NULL) {

                            // no more xmit frame, release xmitbuffer

                            rtw_free_xmitbuf(pxmitpriv,pxmitbuf);

                            return _FALSE;

                   }

 

#ifndef IDEA_CONDITION

                   if (pxmitframe->frame_tag != DATA_FRAMETAG) {

                            RT_TRACE(_module_rtl8192c_xmit_c_,_drv_err_,

                                      ("xmitframe_complete: frame tag(%d) isnot DATA_FRAMETAG(%d)!\n",

                                      pxmitframe->frame_tag, DATA_FRAMETAG));

//                         rtw_free_xmitframe(pxmitpriv,pxmitframe);

                            continue;

                   }

 

                   // TID 0~15

                   if ((pxmitframe->attrib.priority < 0) ||

                      (pxmitframe->attrib.priority > 15)) {

                            RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_,

                                      ("xmitframe_complete: TID(%d) should be0~15!\n",

                                      pxmitframe->attrib.priority));

//                         rtw_free_xmitframe(pxmitpriv,pxmitframe);

                            continue;

                   }

#endif

                   pxmitframe->pxmitbuf = pxmitbuf;

                   pxmitframe->buf_addr = pxmitbuf->pbuf;

                   pxmitbuf->priv_data = pxmitframe;

 

                   //pxmitframe->agg_num = 1; // alloc xmitframeshould assign to 1.

                   pxmitframe->pkt_offset = 1; // first frame ofaggregation, reserve offset

 

 

                   if (rtw_xmitframe_coalesce(padapter,pxmitframe->pkt, pxmitframe) == _FALSE) {

                            DBG_871X("%s coalesce 1st xmitframefailed \n",__FUNCTION__);

                            continue;

                   }

 

                   // always return ndis_packet afterrtw_xmitframe_coalesce

                   rtw_os_xmit_complete(padapter, pxmitframe);

 

                   break;

         } while (1);


 2、合併相同的優先順序和相同的資料(AP或者STA模式)幀。

         //3 2. aggregate same priority and same DA(AP or STA) frames

         pfirstframe = pxmitframe;

         len = xmitframe_need_length(pfirstframe) + TXDESC_OFFSET;

         pbuf_tail = len;

         pbuf = _RND8(pbuf_tail);

 

         // check pkt amount in one bluk

         descCount = 0;

         bulkPtr = bulkSize;

         if (pbuf < bulkPtr)

                   descCount++;

         else {

                   descCount = 0;

                   bulkPtr = ((pbuf / bulkSize) + 1) * bulkSize; //round to next bulkSize

         }

 

         // dequeue same priority packet from station tx queue

         psta = pfirstframe->attrib.psta;

         switch (pfirstframe->attrib.priority) {

                   case 1:

                   case 2:

                            ptxservq =&(psta->sta_xmitpriv.bk_q);

                            phwxmit = pxmitpriv->hwxmits + 3;

                            break;

 

                   case 4:

                   case 5:

                            ptxservq =&(psta->sta_xmitpriv.vi_q);

                            phwxmit = pxmitpriv->hwxmits + 1;

                            break;

 

                   case 6:

                   case 7:

                            ptxservq = &(psta->sta_xmitpriv.vo_q);

                            phwxmit = pxmitpriv->hwxmits;

                            break;

 

                   case 0:

                   case 3:

                   default:

                            ptxservq =&(psta->sta_xmitpriv.be_q);

                            phwxmit = pxmitpriv->hwxmits + 2;

                            break;

         }

 

         _enter_critical_bh(&pxmitpriv->lock, &irqL);

 

         xmitframe_phead = get_list_head(&ptxservq->sta_pending);

         xmitframe_plist = get_next(xmitframe_phead);

         while (rtw_end_of_queue_search(xmitframe_phead,xmitframe_plist) == _FALSE)

         {

                   pxmitframe = LIST_CONTAINOR(xmitframe_plist,struct xmit_frame, list);

                   xmitframe_plist = get_next(xmitframe_plist);

 

                   len = xmitframe_need_length(pxmitframe) +TXDESC_SIZE; // no offset

                   if (pbuf + len > MAX_XMITBUF_SZ) break;

 

                   rtw_list_delete(&pxmitframe->list);

                   ptxservq->qcnt--;

                   phwxmit->accnt--;

 

#ifndef IDEA_CONDITION

                   // suppose only data frames would be in queue

                   if (pxmitframe->frame_tag != DATA_FRAMETAG) {

                            RT_TRACE(_module_rtl8192c_xmit_c_,_drv_err_,

                                      ("xmitframe_complete: frame tag(%d) isnot DATA_FRAMETAG(%d)!\n",

                                      pxmitframe->frame_tag, DATA_FRAMETAG));

                            rtw_free_xmitframe(pxmitpriv,pxmitframe);

                            continue;

                   }

 

                   // TID 0~15

                   if ((pxmitframe->attrib.priority < 0) ||

                      (pxmitframe->attrib.priority > 15)) {

                            RT_TRACE(_module_rtl8192c_xmit_c_,_drv_err_,

                                      ("xmitframe_complete: TID(%d) should be 0~15!\n",

                                      pxmitframe->attrib.priority));

                            rtw_free_xmitframe(pxmitpriv,pxmitframe);

                            continue;

                   }

#endif

 

//               pxmitframe->pxmitbuf =pxmitbuf;

                   pxmitframe->buf_addr = pxmitbuf->pbuf +pbuf;

 

                   pxmitframe->agg_num = 0; // not first frame ofaggregation

                   pxmitframe->pkt_offset = 0; // not first frameof aggregation, no need to reserve offset

 

                   if (rtw_xmitframe_coalesce(padapter,pxmitframe->pkt, pxmitframe) == _FALSE) {

                            DBG_871X("%s coalesce failed\n",__FUNCTION__);

                            rtw_free_xmitframe(pxmitpriv,pxmitframe);

                            continue;

                   }

 

                   // always return ndis_packet afterrtw_xmitframe_coalesce

                   rtw_os_xmit_complete(padapter, pxmitframe);

 

                   // (len - TXDESC_SIZE) ==pxmitframe->attrib.last_txcmdsz

                   update_txdesc(pxmitframe, pxmitframe->buf_addr,pxmitframe->attrib.last_txcmdsz, _TRUE);

 

                   // don't need xmitframe any more

                   rtw_free_xmitframe(pxmitpriv, pxmitframe);

 

                   // handle pointer and stop condition

                   pbuf_tail = pbuf + len;

                   pbuf = _RND8(pbuf_tail);

 

                   pfirstframe->agg_num++;

                   if (MAX_TX_AGG_PACKET_NUMBER ==pfirstframe->agg_num)

                            break;

 

                   if (pbuf < bulkPtr) {

                            descCount++;

                            if (descCount ==pHalData->UsbTxAggDescNum)

                                     break;

                   } else {

                            descCount = 0;

                            bulkPtr = ((pbuf / bulkSize) + 1) *bulkSize;

                   }

         }

         if (_rtw_queue_empty(&ptxservq->sta_pending) ==_TRUE)

                   rtw_list_delete(&ptxservq->tx_pending);

 

         _exit_critical_bh(&pxmitpriv->lock, &irqL);

 

         if ((pfirstframe->attrib.ether_type != 0x0806) &&

            (pfirstframe->attrib.ether_type != 0x888e) &&

             (pfirstframe->attrib.dhcp_pkt!= 1))

         {

                   rtw_issue_addbareq_cmd(padapter, pfirstframe);

         }

 

#ifndefCONFIG_USE_USB_BUFFER_ALLOC_TX


3、更新第一幀資料幀。

         //3 3. update first frame txdesc

         if ((pbuf_tail % bulkSize) == 0) {

                   // remove pkt_offset

                   pbuf_tail -= PACKET_OFFSET_SZ;

                   pfirstframe->buf_addr += PACKET_OFFSET_SZ;

                   pfirstframe->pkt_offset = 0;

         }

#endif       // CONFIG_USE_USB_BUFFER_ALLOC_TX

         update_txdesc(pfirstframe, pfirstframe->buf_addr,pfirstframe->attrib.last_txcmdsz, _TRUE);

 

4、將要傳送的資料緩衝區寫到USB FIFO

         //3 4. write xmit buffer to USB FIFO

         ff_hwaddr = rtw_get_ff_hwaddr(pfirstframe);

 

         // xmit address ==((xmit_frame*)pxmitbuf->priv_data)->buf_addr

         rtw_write_port(padapter, ff_hwaddr, pbuf_tail,(u8*)pxmitbuf);

 

 5、更新狀態

         //3 5. update statisitc

         pbuf_tail -= (pfirstframe->agg_num * TXDESC_SIZE);

         if (pfirstframe->pkt_offset == 1) pbuf_tail -=PACKET_OFFSET_SZ;

        

         rtw_count_tx_stats(padapter, pfirstframe, pbuf_tail);

 

         rtw_free_xmitframe(pxmitpriv, pfirstframe);

 

         return _TRUE;

}


USB介面中的寫函式相當於主機要通過WIFI模組傳送資料到無線網路中,那麼USB介面就是它的傳輸通道。

轉載請註明出處:http://blog.csdn.net/Righthek 謝謝!

         轉載請註明出處:http://blog.csdn.net/Righthek 謝謝!

         還有1天就到2017年了,回顧整個2016年至此,都沒發表過一篇技術文章。做軟體開發已有5、6年,作為一名過往都有寫技術文章的開發者,實屬不妥。技術的創新和發展實質上是一種傳承、共享與拓展。而在我的理解中,技術文章就是一種傳承與共享。

         去年開的【智慧家居篇】專欄還沒完成,現在這篇文章繼續這個專欄的技術分析。

         在上一篇文章中,當wifi模組的接收初始化函式中,註冊了中斷URB。即當wifi模組接收到資料的時候,通過中斷URB產生中斷之後,就會呼叫usb_read_port()函式,實現USB的讀取。

         現在我們再來看看WIFI的傳送,首先我們先WIFI傳送處理函式註冊為tasklet,程式碼如下:

s32   rtl8192cu_init_xmit_priv(_adapter *padapter)

{

         struct xmit_priv       *pxmitpriv= &padapter->xmitpriv;

 

#ifdef PLATFORM_LINUX

         tasklet_init(&pxmitpriv->xmit_tasklet,

              (void(*)(unsignedlong))rtl8192cu_xmit_tasklet,

              (unsignedlong)padapter);

#endif

         return _SUCCESS;

}

         在tasklet_init()中註冊rtl8192cu_xmit_tasklet()回撥函式。

voidrtl8192cu_xmit_tasklet(void *priv)

{       

         int ret = _FALSE;

         _adapter *padapter = (_adapter*)priv;

         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;

 

         if(check_fwstate(&padapter->mlmepriv,_FW_UNDER_SURVEY) == _TRUE)

                   return;

 

         while(1)

         {

                   if ((padapter->bDriverStopped ==_TRUE)||(padapter->bSurpriseRemoved== _TRUE) ||(padapter->bWritePortCancel == _TRUE))

                   {

                            DBG_8192C("xmit_tasklet =>bDriverStopped or bSurpriseRemoved or bWritePortCancel\n");

                            break;

                   }

 

                   ret = rtl8192cu_xmitframe_complete(padapter,pxmitpriv, NULL);

 

                   if(ret==_FALSE)

                            break;

                  

         }

}

         回撥函式rtl8192cu_xmitframe_complete主要是打包資料,然後將資料上傳到USB FIFO,最後通過usb_write_port()傳送到WIFI模組上。

s32rtl8192cu_xmitframe_complete(_adapter *padapter, struct xmit_priv *pxmitpriv,struct xmit_buf *pxmitbuf)

{

         HAL_DATA_TYPE      *pHalData= GET_HAL_DATA(padapter);

         struct xmit_frame *pxmitframe = NULL;

         struct xmit_frame *pfirstframe = NULL;

 

         // aggregate variable

         struct hw_xmit *phwxmit;

         struct sta_info *psta = NULL;

         struct tx_servq *ptxservq = NULL;


         _irqL irqL;

         _list *xmitframe_plist = NULL, *xmitframe_phead = NULL;

 

         u32  pbuf;         // next pkt address

         u32  pbuf_tail; // last pkt tail

         u32  len;  // packet length, except TXDESC_SIZE andPKT_OFFSET

 

         u32  bulkSize =pHalData->UsbBulkOutSize;

         u8     descCount;

         u32  bulkPtr;

 

         // dump frame variable

         u32 ff_hwaddr;

 

#ifndef IDEA_CONDITION

         int res = _SUCCESS;

#endif

 

         RT_TRACE(_module_rtl8192c_xmit_c_, _drv_info_,("+xmitframe_complete\n"));


         // check xmitbuffer is ok

         if (pxmitbuf == NULL) {

                   pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);

                   if (pxmitbuf == NULL) return _FALSE;

         }


1、先將資料進行打包 

         //3 1. pick up first frame

         do {

                   rtw_free_xmitframe(pxmitpriv, pxmitframe);

                           

                   pxmitframe = rtw_dequeue_xframe(pxmitpriv,pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);

                   if (pxmitframe == NULL) {

                            // no more xmit frame, release xmitbuffer

                            rtw_free_xmitbuf(pxmitpriv,pxmitbuf);

                            return _FALSE;

                   }

 

#ifndef IDEA_CONDITION

                   if (pxmitframe->frame_tag != DATA_FRAMETAG) {

                            RT_TRACE(_module_rtl8192c_xmit_c_,_drv_err_,

                                      ("xmitframe_complete: frame tag(%d) isnot DATA_FRAMETAG(%d)!\n",

                                      pxmitframe->frame_tag, DATA_FRAMETAG));

//                         rtw_free_xmitframe(pxmitpriv,pxmitframe);

                            continue;

                   }

 

                   // TID 0~15

                   if ((pxmitframe->attrib.priority < 0) ||

                      (pxmitframe->attrib.priority > 15)) {

                            RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_,

                                      ("xmitframe_complete: TID(%d) should be0~15!\n",

                                      pxmitframe->attrib.priority));

//                         rtw_free_xmitframe(pxmitpriv,pxmitframe);

                            continue;

                   }

#endif

                   pxmitframe->pxmitbuf = pxmitbuf;

                   pxmitframe->buf_addr = pxmitbuf->pbuf;

                   pxmitbuf->priv_data = pxmitframe;

 

                   //pxmitframe->agg_num = 1; // alloc xmitframeshould assign to 1.

                   pxmitframe->pkt_offset = 1; // first frame ofaggregation, reserve offset

 

 

                   if (rtw_xmitframe_coalesce(padapter,pxmitframe->pkt, pxmitframe) == _FALSE) {

                            DBG_871X("%s coalesce 1st xmitframefailed \n",__FUNCTION__);

                            continue;

                   }

 

                   // always return ndis_packet afterrtw_xmitframe_coalesce

                   rtw_os_xmit_complete(padapter, pxmitframe);

 

                   break;

         } while (1);


 2、合併相同的優先順序和相同的資料(AP或者STA模式)幀。

         //3 2. aggregate same priority and same DA(AP or STA) frames

         pfirstframe = pxmitframe;

         len = xmitframe_need_length(pfirstframe) + TXDESC_OFFSET;

         pbuf_tail = len;

         pbuf = _RND8(pbuf_tail);

 

         // check pkt amount in one bluk

         descCount = 0;

         bulkPtr = bulkSize;

         if (pbuf < bulkPtr)

                   descCount++;

         else {

                   descCount = 0;

                   bulkPtr = ((pbuf / bulkSize) + 1) * bulkSize; //round to next bulkSize

         }

 

         // dequeue same priority packet from station tx queue

         psta = pfirstframe->attrib.psta;

         switch (pfirstframe->attrib.priority) {

                   case 1:

                   case 2:

                            ptxservq =&(psta->sta_xmitpriv.bk_q);

                            phwxmit = pxmitpriv->hwxmits + 3;

                            break;

 

                   case 4:

                   case 5:

                            ptxservq =&(psta->sta_xmitpriv.vi_q);

                            phwxmit = pxmitpriv->hwxmits + 1;

                            break;

 

                   case 6:

                   case 7:

                            ptxservq = &(psta->sta_xmitpriv.vo_q);

                            phwxmit = pxmitpriv->hwxmits;

                            break;

 

                   case 0:

                   case 3:

                   default:

                            ptxservq =&(psta->sta_xmitpriv.be_q);

                            phwxmit = pxmitpriv->hwxmits + 2;

                            break;

         }

 

         _enter_critical_bh(&pxmitpriv->lock, &irqL);

 

         xmitframe_phead = get_list_head(&ptxservq->sta_pending);

         xmitframe_plist = get_next(xmitframe_phead);

         while (rtw_end_of_queue_search(xmitframe_phead,xmitframe_plist) == _FALSE)

         {

                   pxmitframe = LIST_CONTAINOR(xmitframe_plist,struct xmit_frame, list);

                   xmitframe_plist = get_next(xmitframe_plist);

 

                   len = xmitframe_need_length(pxmitframe) +TXDESC_SIZE; // no offset

                   if (pbuf + len > MAX_XMITBUF_SZ) break;

 

                   rtw_list_delete(&pxmitframe->list);

                   ptxservq->qcnt--;

                   phwxmit->accnt--;

 

#ifndef IDEA_CONDITION

                   // suppose only data frames would be in queue

                   if (pxmitframe->frame_tag != DATA_FRAMETAG) {

                            RT_TRACE(_module_rtl8192c_xmit_c_,_drv_err_,

                                      ("xmitframe_complete: frame tag(%d) isnot DATA_FRAMETAG(%d)!\n",

                                      pxmitframe->frame_tag, DATA_FRAMETAG));

                            rtw_free_xmitframe(pxmitpriv,pxmitframe);

                            continue;

                   }

 

                   // TID 0~15

                   if ((pxmitframe->attrib.priority < 0) ||

                      (pxmitframe->attrib.priority > 15)) {

                            RT_TRACE(_module_rtl8192c_xmit_c_,_drv_err_,

  &n