wifi驅動的理解(3)——usb介面在wifi模組中的角色
轉載請註明出處:http://blog.csdn.net/Righthek 謝謝!
上一篇文章已經提到USB介面在wifi模組中的最重要兩個函式是usb_read_port()和usb_write_port()。那它們是怎麼和wifi扯上關係的呢?我們可以從以下三個方面去分析:
1、首先需要明確wifi模組是USB裝置,主控(CPU)端是USB主機;
2、USB主機若需要對wifi模組進行資料的讀寫時,就必須經過USB介面;
3、既然涉及到資料的讀寫操作,必然要用相應的讀寫函式,那麼usb_read_port()和usb_write_port()即是它們的讀寫函式。
我們先從讀資料開始進行分析,在分析之前,我們必須瞭解USB裝置驅動的讀資料過程。USB讀取資料操作流程如下:
(1)通過usb_alloc_urb()函式建立並分配一個URB,作為傳輸USB資料的載體;
(2)建立並分配DMA緩衝區,以DMA方式快速傳輸資料;
(3)初始化URB,根據wifi的傳輸資料量,我們需要初始化為批量URB,相應操作函式為usb_fill_bulk_urb();
(4)將URB提交到USB核心;
(5)提交成功後,URB的完成函式將被USB核心呼叫。
現在我們一步步地詳細分析整個過程,所謂的建立和分配,實質上是對記憶體的分配。作為一名Linux驅動開發程式設計師,必須瞭解Linux記憶體管理相關知識及合理使用記憶體。
那麼我們應該怎樣合理地建立和分配URB和DMA緩衝區呢?很明顯,我們應該在用的時候分配,在不用的時候釋放。
那麼問題來了……什麼時候在用,又什麼時候不用呢?問題很簡單,就是主控端讀資料時分配,讀完後釋放,而只有當wifi模組有資料可讀時,主控端才能成功地讀取資料。那麼wifi模組什麼時候有資料可讀呢?——下面重點來了!wifi模組通過RF端接收到無線網路資料,然後快取到wifi晶片的RAM中,此時,wifi模組就有資料可讀了。
經過上面的分析,我們找到了一條USB介面與wifi模組扯上關係的線索,就是wifi模組的接收資料,會引發USB介面的讀資料;
現在,我們轉到wifi模組的接收函式中,看看是不是真的這樣?
在wifi接收函式初始化中,我們可以看到usb_alloc_urb()建立一箇中斷URB。虛擬碼如下:
[cpp] view plain copy print ?- int xxxwifi_init_recv(_adapter *padapter)
- {
- struct recv_priv *precvpriv = &padapter->recvpriv;
- int i, res = _SUCCESS;
- struct recv_buf *precvbuf;
- tasklet_init(&precvpriv->recv_tasklet, (void(*)(unsigned long))rtl8188eu_recv_tasklet, (unsigned long)padapter);
- precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); //建立一箇中斷URB
- precvpriv->int_in_buf = rtw_zmalloc(INTERRUPT_MSG_FORMAT_LEN);
- //init recv_buf
- _rtw_init_queue(&precvpriv->free_recv_buf_queue);
- _rtw_init_queue(&precvpriv->recv_buf_pending_queue);
- precvpriv -> pallocated_recv_buf = rtw_zmalloc(NR_RECVBUFF *sizeof(struct recv_buf) + 4);
- precvbuf = (struct recv_buf*)precvpriv->precv_buf;
- for(i=0; i < NR_RECVBUFF ; i++)
- {
- _rtw_init_listhead(&precvbuf->list);
- _rtw_spinlock_init(&precvbuf->recvbuf_lock);
- precvbuf->alloc_sz = MAX_RECVBUF_SZ;
- res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf);
- precvbuf->ref_cnt = 0;
- precvbuf->adapter =padapter;
- precvbuf++;
- }
- precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF;
- skb_queue_head_init(&precvpriv->rx_skb_queue);
- #ifdef CONFIG_PREALLOC_RECV_SKB
- {
- int i;
- SIZE_PTR tmpaddr=0;
- SIZE_PTR alignment=0;
- struct sk_buff *pskb=NULL;
- skb_queue_head_init(&precvpriv->free_recv_skb_queue);
- for(i=0; i<NR_PREALLOC_RECV_SKB; i++)
- {
- pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
- if(pskb)
- {
- pskb->dev = padapter->pnetdev;
- tmpaddr = (SIZE_PTR)pskb->data;
- alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
- skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));
- skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
- }
- pskb=NULL;
- }
- }
- #endif
- return res;
- }
int xxxwifi_init_recv(_adapter *padapter)
{
struct recv_priv *precvpriv = &padapter->recvpriv;
int i, res = _SUCCESS;
struct recv_buf *precvbuf;
tasklet_init(&precvpriv->recv_tasklet, (void(*)(unsigned long))rtl8188eu_recv_tasklet, (unsigned long)padapter);
precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); //建立一箇中斷URB
precvpriv->int_in_buf = rtw_zmalloc(INTERRUPT_MSG_FORMAT_LEN);
//init recv_buf
_rtw_init_queue(&precvpriv->free_recv_buf_queue);
_rtw_init_queue(&precvpriv->recv_buf_pending_queue);
precvpriv -> pallocated_recv_buf = rtw_zmalloc(NR_RECVBUFF *sizeof(struct recv_buf) + 4);
precvbuf = (struct recv_buf*)precvpriv->precv_buf;
for(i=0; i < NR_RECVBUFF ; i++)
{
_rtw_init_listhead(&precvbuf->list);
_rtw_spinlock_init(&precvbuf->recvbuf_lock);
precvbuf->alloc_sz = MAX_RECVBUF_SZ;
res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf);
precvbuf->ref_cnt = 0;
precvbuf->adapter =padapter;
precvbuf++;
}
precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF;
skb_queue_head_init(&precvpriv->rx_skb_queue);
#ifdef CONFIG_PREALLOC_RECV_SKB
{
int i;
SIZE_PTR tmpaddr=0;
SIZE_PTR alignment=0;
struct sk_buff *pskb=NULL;
skb_queue_head_init(&precvpriv->free_recv_skb_queue);
for(i=0; i<NR_PREALLOC_RECV_SKB; i++)
{
pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
if(pskb)
{
pskb->dev = padapter->pnetdev;
tmpaddr = (SIZE_PTR)pskb->data;
alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));
skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
}
pskb=NULL;
}
}
#endif
return res;
}
在rtw_os_recvbuf_resource_alloc函式中,建立一個批量URB和一個DMA緩衝區。虛擬碼如下:
[cpp] view plain copy print ?- int rtw_os_recvbuf_resource_alloc(_adapter *padapter, struct recv_buf *precvbuf)
- {
- int res=_SUCCESS;
- struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
- struct usb_device *pusbd = pdvobjpriv->pusbdev;
- precvbuf->irp_pending = _FALSE;
- precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); //建立一個批量URB
- precvbuf->pskb = NULL;
- precvbuf->reuse = _FALSE;
- precvbuf->pallocated_buf = precvbuf->pbuf = NULL;
- precvbuf->pdata = precvbuf->phead = precvbuf->ptail = precvbuf->pend = NULL;
- precvbuf->transfer_len = 0;
- precvbuf->len = 0;
- #ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX
- precvbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)precvbuf->alloc_sz, &precvbuf->dma_transfer_addr); //建立一個DMA緩衝區
- precvbuf->pbuf = precvbuf->pallocated_buf;
- if(precvbuf->pallocated_buf == NULL)
- return _FAIL;
- #endif //CONFIG_USE_USB_BUFFER_ALLOC_RX
- return res;
- }
int rtw_os_recvbuf_resource_alloc(_adapter *padapter, struct recv_buf *precvbuf)
{
int res=_SUCCESS;
struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
struct usb_device *pusbd = pdvobjpriv->pusbdev;
precvbuf->irp_pending = _FALSE;
precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); //建立一個批量URB
precvbuf->pskb = NULL;
precvbuf->reuse = _FALSE;
precvbuf->pallocated_buf = precvbuf->pbuf = NULL;
precvbuf->pdata = precvbuf->phead = precvbuf->ptail = precvbuf->pend = NULL;
precvbuf->transfer_len = 0;
precvbuf->len = 0;
#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX
precvbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)precvbuf->alloc_sz, &precvbuf->dma_transfer_addr); //建立一個DMA緩衝區
precvbuf->pbuf = precvbuf->pallocated_buf;
if(precvbuf->pallocated_buf == NULL)
return _FAIL;
#endif //CONFIG_USE_USB_BUFFER_ALLOC_RX
return res;
}
在usb_read_port()函式中,通過usb_fill_bulk_urb()初始化批量URB,並且提交給USB核心,也即USB讀取資料操作流程的第3、4步。在usb_fill_bulk_urb()函式中,初始化URB的完成函式usb_read_port_complete(),只有當URB提交完成後,函式usb_read_port_complete()將被呼叫。虛擬碼如下:
[cpp] view plain copy print ?- static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
- {
- struct recv_buf *precvbuf = (struct recv_buf *)rmem;
- _adapter *adapter = pintfhdl->padapter;
- struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter);
- struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobj);
- struct recv_priv *precvpriv = &adapter->recvpriv;
- struct usb_device *pusbd = pdvobj->pusbdev;
- rtl8188eu_init_recvbuf(adapter, precvbuf);
- precvpriv->rx_pending_cnt++;
- purb = precvbuf->purb;
- //translate DMA FIFO addr to pipehandle
- pipe = ffaddr2pipehdl(pdvobj, addr);
- usb_fill_bulk_urb(purb, pusbd, pipe,
- precvbuf->pbuf,
- MAX_RECVBUF_SZ,
- usb_read_port_complete,
- precvbuf);//context is precvbuf
- err = usb_submit_urb(purb, GFP_ATOMIC);
- return ret;
- }
static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
{
struct recv_buf *precvbuf = (struct recv_buf *)rmem;
_adapter *adapter = pintfhdl->padapter;
struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter);
struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobj);
struct recv_priv *precvpriv = &adapter->recvpriv;
struct usb_device *pusbd = pdvobj->pusbdev;
rtl8188eu_init_recvbuf(adapter, precvbuf);
precvpriv->rx_pending_cnt++;
purb = precvbuf->purb;
//translate DMA FIFO addr to pipehandle
pipe = ffaddr2pipehdl(pdvobj, addr);
usb_fill_bulk_urb(purb, pusbd, pipe,
precvbuf->pbuf,
MAX_RECVBUF_SZ,
usb_read_port_complete,
precvbuf);//context is precvbuf
err = usb_submit_urb(purb, GFP_ATOMIC);
return ret;
}
通過上面的程式碼,我們可以得知在wifi模組為接收資料做初始化準備時,分配了URB和DMA緩衝區。而在usb_read_port()函式中初始化URB和提交URB。
它為什麼要這樣做呢?目的是什麼?
接下來,我們將在下一篇文章中為大家揭曉。
轉載請註明出處:http://blog.csdn.net/Righthek 謝謝!轉載請註明出處:http://blog.csdn.net/Righthek 謝謝!
上一篇文章已經提到USB介面在wifi模組中的最重要兩個函式是usb_read_port()和usb_write_port()。那它們是怎麼和wifi扯上關係的呢?我們可以從以下三個方面去分析:
1、首先需要明確wifi模組是USB裝置,主控(CPU)端是USB主機;
2、USB主機若需要對wifi模組進行資料的讀寫時,就必須經過USB介面;
3、既然涉及到資料的讀寫操作,必然要用相應的讀寫函式,那麼usb_read_port()和usb_write_port()即是它們的讀寫函式。
我們先從讀資料開始進行分析,在分析之前,我們必須瞭解USB裝置驅動的讀資料過程。USB讀取資料操作流程如下:
(1)通過usb_alloc_urb()函式建立並分配一個URB,作為傳輸USB資料的載體;
(2)建立並分配DMA緩衝區,以DMA方式快速傳輸資料;
(3)初始化URB,根據wifi的傳輸資料量,我們需要初始化為批量URB,相應操作函式為usb_fill_bulk_urb();
(4)將URB提交到USB核心;
(5)提交成功後,URB的完成函式將被USB核心呼叫。
現在我們一步步地詳細分析整個過程,所謂的建立和分配,實質上是對記憶體的分配。作為一名Linux驅動開發程式設計師,必須瞭解Linux記憶體管理相關知識及合理使用記憶體。
那麼我們應該怎樣合理地建立和分配URB和DMA緩衝區呢?很明顯,我們應該在用的時候分配,在不用的時候釋放。
那麼問題來了……什麼時候在用,又什麼時候不用呢?問題很簡單,就是主控端讀資料時分配,讀完後釋放,而只有當wifi模組有資料可讀時,主控端才能成功地讀取資料。那麼wifi模組什麼時候有資料可讀呢?——下面重點來了!wifi模組通過RF端接收到無線網路資料,然後快取到wifi晶片的RAM中,此時,wifi模組就有資料可讀了。
經過上面的分析,我們找到了一條USB介面與wifi模組扯上關係的線索,就是wifi模組的接收資料,會引發USB介面的讀資料;
現在,我們轉到wifi模組的接收函式中,看看是不是真的這樣?
在wifi接收函式初始化中,我們可以看到usb_alloc_urb()建立一箇中斷URB。虛擬碼如下:
[cpp] view plain copy print ?- int xxxwifi_init_recv(_adapter *padapter)
- {
- struct recv_priv *precvpriv = &padapter->recvpriv;
- int i, res = _SUCCESS;
- struct recv_buf *precvbuf;
- tasklet_init(&precvpriv->recv_tasklet, (void(*)(unsigned long))rtl8188eu_recv_tasklet, (unsigned long)padapter);
- precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); //建立一箇中斷URB
- precvpriv->int_in_buf = rtw_zmalloc(INTERRUPT_MSG_FORMAT_LEN);
- //init recv_buf
- _rtw_init_queue(&precvpriv->free_recv_buf_queue);
- _rtw_init_queue(&precvpriv->recv_buf_pending_queue);
- precvpriv -> pallocated_recv_buf = rtw_zmalloc(NR_RECVBUFF *sizeof(struct recv_buf) + 4);
- precvbuf = (struct recv_buf*)precvpriv->precv_buf;
- for(i=0; i < NR_RECVBUFF ; i++)
- {
- _rtw_init_listhead(&precvbuf->list);
- _rtw_spinlock_init(&precvbuf->recvbuf_lock);
- precvbuf->alloc_sz = MAX_RECVBUF_SZ;
- res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf);
- precvbuf->ref_cnt = 0;
- precvbuf->adapter =padapter;
- precvbuf++;
- }
- precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF;
- skb_queue_head_init(&precvpriv->rx_skb_queue);
- #ifdef CONFIG_PREALLOC_RECV_SKB
- {
- int i;
- SIZE_PTR tmpaddr=0;
- SIZE_PTR alignment=0;
- struct sk_buff *pskb=NULL;
- skb_queue_head_init(&precvpriv->free_recv_skb_queue);
- for(i=0; i<NR_PREALLOC_RECV_SKB; i++)
- {
- pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
- if(pskb)
- {
- pskb->dev = padapter->pnetdev;
- tmpaddr = (SIZE_PTR)pskb->data;
- alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
- skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));
- skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
- }
- pskb=NULL;
- }
- }
- #endif
- return res;
- }
int xxxwifi_init_recv(_adapter *padapter)
{
struct recv_priv *precvpriv = &padapter->recvpriv;
int i, res = _SUCCESS;
struct recv_buf *precvbuf;
tasklet_init(&precvpriv->recv_tasklet, (void(*)(unsigned long))rtl8188eu_recv_tasklet, (unsigned long)padapter);
precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); //建立一箇中斷URB
precvpriv->int_in_buf = rtw_zmalloc(INTERRUPT_MSG_FORMAT_LEN);
//init recv_buf
_rtw_init_queue(&precvpriv->free_recv_buf_queue);
_rtw_init_queue(&precvpriv->recv_buf_pending_queue);
precvpriv -> pallocated_recv_buf = rtw_zmalloc(NR_RECVBUFF *sizeof(struct recv_buf) + 4);
precvbuf = (struct recv_buf*)precvpriv->precv_buf;
for(i=0; i < NR_RECVBUFF ; i++)
{
_rtw_init_listhead(&precvbuf->list);
_rtw_spinlock_init(&precvbuf->recvbuf_lock);
precvbuf->alloc_sz = MAX_RECVBUF_SZ;
res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf);
precvbuf->ref_cnt = 0;
precvbuf->adapter =padapter;
precvbuf++;
}
precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF;
skb_queue_head_init(&precvpriv->rx_skb_queue);
#ifdef CONFIG_PREALLOC_RECV_SKB
{
int i;
SIZE_PTR tmpaddr=0;
SIZE_PTR alignment=0;
struct sk_buff *pskb=NULL;
skb_queue_head_init(&precvpriv->free_recv_skb_queue);
for(i=0; i<NR_PREALLOC_RECV_SKB; i++)
{
pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
if(pskb)
{
pskb->dev = padapter->pnetdev;
tmpaddr = (SIZE_PTR)pskb->data;
alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));
skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
}
pskb=NULL;
}
}
#endif
return res;
}
在rtw_os_recvbuf_resource_alloc函式中,建立一個批量URB和一個DMA緩衝區。虛擬碼如下:
[cpp] view plain copy print ?- int rtw_os_recvbuf_resource_alloc(_adapter *padapter, struct recv_buf *precvbuf)
- {
- int res=_SUCCESS;
- struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
- struct usb_device *pusbd = pdvobjpriv->pusbdev;
- precvbuf->irp_pending = _FALSE;
- precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); //建立一個批量URB
- precvbuf->pskb = NULL;
- precvbuf->reuse = _FALSE;
- precvbuf->pallocated_buf = precvbuf->pbuf = NULL;
- precvbuf->pdata = precvbuf->phead = precvbuf->ptail = precvbuf->pend = NULL;
- precvbuf->transfer_len = 0;
- precvbuf->len = 0;
- #ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX
- precvbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)precvbuf->alloc_sz, &precvbuf->dma_transfer_addr); //建立一個DMA緩衝區
- precvbuf->pbuf = precvbuf->pallocated_buf;
- if(precvbuf->pallocated_buf == NULL)
- return _FAIL;
- #endif //CONFIG_USE_USB_BUFFER_ALLOC_RX
- return res;
- }
int rtw_os_recvbuf_resource_alloc(_adapter *padapter, struct recv_buf *precvbuf)
{
int res=_SUCCESS;
struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
struct usb_device *pusbd = pdvobjpriv->pusbdev;
precvbuf->irp_pending = _FALSE;
precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); //建立一個批量URB
precvbuf->pskb = NULL;
precvbuf->reuse = _FALSE;
precvbuf->pallocated_buf = precvbuf->pbuf = NULL;
precvbuf->pdata = precvbuf->phead = precvbuf->ptail = precvbuf->pend = NULL;
precvbuf->transfer_len = 0;
precvbuf->len = 0;
#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX
precvbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)precvbuf->alloc_sz, &precvbuf->dma_transfer_addr); //建立一個DMA緩衝區
precvbuf->pbuf = precvbuf->pallocated_buf;
if(precvbuf->pallocated_buf == NULL)
return _FAIL;
#endif //CONFIG_USE_USB_BUFFER_ALLOC_RX
return res;
}
在usb_read_port()函式中,通過usb_fill_bulk_urb()初始化批量URB,並且提交給USB核心,也即USB讀取資料操作流程的第3、4步。在usb_fill_bulk_urb()函式中,初始化URB的完成函式usb_read_port_complete(),只有當URB提交完成後,函式usb_read_port_complete()將被呼叫。虛擬碼如下:
[cpp] view plain copy print ?- static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
- {
- struct recv_buf *precvbuf = (struct recv_buf *)rmem;
- _adapter *adapter = pintfhdl->padapter;
- struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter);
- struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobj);
- struct recv_priv *precvpriv = &adapter->recvpriv;
- struct usb_device *pusbd = pdvobj->pusbdev;
- rtl8188eu_init_recvbuf(adapter, precvbuf);
- precvpriv->rx_pending_cnt++;
- purb = precvbuf->purb;
- //translate DMA FIFO addr to pipehandle
- pipe = ffaddr2pipehdl(pdvobj, addr);
- usb_fill_bulk_urb(purb, pusbd, pipe,
- precvbuf->pbuf,
- MAX_RECVBUF_SZ,
- usb_read_port_complete,
- precvbuf);//context is precvbuf
- err = usb_submit_urb(purb, GFP_ATOMIC);
- return ret;
- }
static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
{
struct recv_buf *precvbuf = (struct recv_buf *)rmem;
_adapter *adapter = pintfhdl->padapter;
struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter);
struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobj);
struct recv_priv *precvpriv = &adapter->recvpriv;
struct usb_device *pusbd = pdvobj->pusbdev;
rtl8188eu_init_recvbuf(adapter, precvbuf);
precvpriv->rx_pending_cnt++;
purb = precvbuf->purb;
//translate DMA FIFO addr to pipehandle
pipe = ffaddr2pipehdl(pdvobj, addr);
usb_fill_bulk_urb(purb, pusbd, pipe,
precvbuf->pbuf,
MAX_RECVBUF_SZ,
usb_read_port_complete,
precvbuf);//context is precvbuf
err = usb_submit_urb(purb, GFP_ATOMIC);
return ret;
}
通過上面的程式碼,我們可以得知在wifi模組為接收資料做初始化準備時,分配了URB和DMA緩衝區。而在usb_read_port()函式中初始化URB和提交URB。
它為什麼要這樣做呢?目的是什麼?
接下來,我們將在下一篇文章中為大家揭曉。
轉載請註明出處:http://blog.csdn.net/Righthek 謝謝!