转载请注明出处: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 谢谢!