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 谢谢!
浙公网安备 33010602011771号