还有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;

}