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