1. 程式人生 > >wifi驅動的理解(3)——usb介面在wifi模組中的角色

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 ? 在CODE上檢視程式碼片 派生到我的程式碼片
  1. int xxxwifi_init_recv(_adapter *padapter)  
  2. {  
  3.     struct recv_priv *precvpriv = &padapter->recvpriv;  
  4.     int i, res = _SUCCESS;  
  5.     struct recv_buf *precvbuf;  
  6.   
  7.     tasklet_init(&precvpriv->recv_tasklet, (void(*)(unsigned long))rtl8188eu_recv_tasklet, (unsigned long)padapter);  
  8.   
  9.     precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); //建立一箇中斷URB  
  10.   
  11.     precvpriv->int_in_buf = rtw_zmalloc(INTERRUPT_MSG_FORMAT_LEN);  
  12.     //init recv_buf  
  13.     _rtw_init_queue(&precvpriv->free_recv_buf_queue);  
  14.     _rtw_init_queue(&precvpriv->recv_buf_pending_queue);  
  15.   
  16.     precvpriv -> pallocated_recv_buf = rtw_zmalloc(NR_RECVBUFF *sizeof(struct recv_buf) + 4);  
  17.     precvbuf = (struct recv_buf*)precvpriv->precv_buf;  
  18.   
  19.     for(i=0; i < NR_RECVBUFF ; i++)  
  20.     {  
  21.         _rtw_init_listhead(&precvbuf->list);  
  22.         _rtw_spinlock_init(&precvbuf->recvbuf_lock);  
  23.         precvbuf->alloc_sz = MAX_RECVBUF_SZ;  
  24.   
  25.         res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf);  
  26.   
  27.         precvbuf->ref_cnt = 0;  
  28.         precvbuf->adapter =padapter;  
  29.         precvbuf++;  
  30.     }  
  31.     precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF;  
  32.   
  33.     skb_queue_head_init(&precvpriv->rx_skb_queue);  
  34.   
  35. #ifdef CONFIG_PREALLOC_RECV_SKB  
  36.     {  
  37.         int i;  
  38.         SIZE_PTR tmpaddr=0;  
  39.         SIZE_PTR alignment=0;  
  40.         struct sk_buff *pskb=NULL;  
  41.         skb_queue_head_init(&precvpriv->free_recv_skb_queue);  
  42.         for(i=0; i<NR_PREALLOC_RECV_SKB; i++)  
  43.         {  
  44.             pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);  
  45.             if(pskb)  
  46.             {  
  47.                 pskb->dev = padapter->pnetdev;  
  48.                 tmpaddr = (SIZE_PTR)pskb->data;  
  49.                 alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);  
  50.                 skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));  
  51.                 skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);  
  52.             }  
  53.             pskb=NULL;  
  54.         }  
  55.     }  
  56. #endif  
  57.     return res;  
  58. }  
save_snippets.png
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 ? 在CODE上檢視程式碼片 派生到我的程式碼片
  1. int rtw_os_recvbuf_resource_alloc(_adapter *padapter, struct recv_buf *precvbuf)  
  2. {  
  3.     int res=_SUCCESS;  
  4.     struct dvobj_priv   *pdvobjpriv = adapter_to_dvobj(padapter);  
  5.     struct usb_device   *pusbd = pdvobjpriv->pusbdev;  
  6.   
  7.     precvbuf->irp_pending = _FALSE;  
  8.     precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); //建立一個批量URB  
  9.   
  10.     precvbuf->pskb = NULL;  
  11.     precvbuf->reuse = _FALSE;  
  12.     precvbuf->pallocated_buf  = precvbuf->pbuf = NULL;  
  13.     precvbuf->pdata = precvbuf->phead = precvbuf->ptail = precvbuf->pend = NULL;  
  14.     precvbuf->transfer_len = 0;  
  15.     precvbuf->len = 0;  
  16.   
  17.     #ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX  
  18.     precvbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)precvbuf->alloc_sz, &precvbuf->dma_transfer_addr);  //建立一個DMA緩衝區  
  19.     precvbuf->pbuf = precvbuf->pallocated_buf;  
  20.     if(precvbuf->pallocated_buf == NULL)  
  21.         return _FAIL;  
  22.     #endif //CONFIG_USE_USB_BUFFER_ALLOC_RX  
  23.       
  24.     return res;  
  25. }  
save_snippets.png
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 ? 在CODE上檢視程式碼片 派生到我的程式碼片
  1. static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)  
  2. {     
  3.     struct recv_buf *precvbuf = (struct recv_buf *)rmem;  
  4.     _adapter        *adapter = pintfhdl->padapter;  
  5.     struct dvobj_priv   *pdvobj = adapter_to_dvobj(adapter);  
  6.     struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobj);  
  7.     struct recv_priv    *precvpriv = &adapter->recvpriv;  
  8.     struct usb_device   *pusbd = pdvobj->pusbdev;  
  9.   
  10.     rtl8188eu_init_recvbuf(adapter, precvbuf);        
  11.   
  12.     precvpriv->rx_pending_cnt++;  
  13.   
  14.     purb = precvbuf->purb;  
  15.   
  16.     //translate DMA FIFO addr to pipehandle  
  17.     pipe = ffaddr2pipehdl(pdvobj, addr);  
  18.   
  19.     usb_fill_bulk_urb(purb, pusbd, pipe,   
  20.                     precvbuf->pbuf,  
  21.                             MAX_RECVBUF_SZ,  
  22.                             usb_read_port_complete,  
  23.                             precvbuf);//context is precvbuf  
  24.   
  25.     err = usb_submit_urb(purb, GFP_ATOMIC);  
  26.   
  27.     return ret;  
  28. }  
save_snippets.png
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 ? 在CODE上檢視程式碼片 派生到我的程式碼片
  1. int xxxwifi_init_recv(_adapter *padapter)  
  2. {  
  3.     struct recv_priv *precvpriv = &padapter->recvpriv;  
  4.     int i, res = _SUCCESS;  
  5.     struct recv_buf *precvbuf;  
  6.   
  7.     tasklet_init(&precvpriv->recv_tasklet, (void(*)(unsigned long))rtl8188eu_recv_tasklet, (unsigned long)padapter);  
  8.   
  9.     precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); //建立一箇中斷URB  
  10.   
  11.     precvpriv->int_in_buf = rtw_zmalloc(INTERRUPT_MSG_FORMAT_LEN);  
  12.     //init recv_buf  
  13.     _rtw_init_queue(&precvpriv->free_recv_buf_queue);  
  14.     _rtw_init_queue(&precvpriv->recv_buf_pending_queue);  
  15.   
  16.     precvpriv -> pallocated_recv_buf = rtw_zmalloc(NR_RECVBUFF *sizeof(struct recv_buf) + 4);  
  17.     precvbuf = (struct recv_buf*)precvpriv->precv_buf;  
  18.   
  19.     for(i=0; i < NR_RECVBUFF ; i++)  
  20.     {  
  21.         _rtw_init_listhead(&precvbuf->list);  
  22.         _rtw_spinlock_init(&precvbuf->recvbuf_lock);  
  23.         precvbuf->alloc_sz = MAX_RECVBUF_SZ;  
  24.   
  25.         res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf);  
  26.   
  27.         precvbuf->ref_cnt = 0;  
  28.         precvbuf->adapter =padapter;  
  29.         precvbuf++;  
  30.     }  
  31.     precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF;  
  32.   
  33.     skb_queue_head_init(&precvpriv->rx_skb_queue);  
  34.   
  35. #ifdef CONFIG_PREALLOC_RECV_SKB  
  36.     {  
  37.         int i;  
  38.         SIZE_PTR tmpaddr=0;  
  39.         SIZE_PTR alignment=0;  
  40.         struct sk_buff *pskb=NULL;  
  41.         skb_queue_head_init(&precvpriv->free_recv_skb_queue);  
  42.         for(i=0; i<NR_PREALLOC_RECV_SKB; i++)  
  43.         {  
  44.             pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);  
  45.             if(pskb)  
  46.             {  
  47.                 pskb->dev = padapter->pnetdev;  
  48.                 tmpaddr = (SIZE_PTR)pskb->data;  
  49.                 alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);  
  50.                 skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));  
  51.                 skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);  
  52.             }  
  53.             pskb=NULL;  
  54.         }  
  55.     }  
  56. #endif  
  57.     return res;  
  58. }  
save_snippets.png
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 ? 在CODE上檢視程式碼片 派生到我的程式碼片
  1. int rtw_os_recvbuf_resource_alloc(_adapter *padapter, struct recv_buf *precvbuf)  
  2. {  
  3.     int res=_SUCCESS;  
  4.     struct dvobj_priv   *pdvobjpriv = adapter_to_dvobj(padapter);  
  5.     struct usb_device   *pusbd = pdvobjpriv->pusbdev;  
  6.   
  7.     precvbuf->irp_pending = _FALSE;  
  8.     precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); //建立一個批量URB  
  9.   
  10.     precvbuf->pskb = NULL;  
  11.     precvbuf->reuse = _FALSE;  
  12.     precvbuf->pallocated_buf  = precvbuf->pbuf = NULL;  
  13.     precvbuf->pdata = precvbuf->phead = precvbuf->ptail = precvbuf->pend = NULL;  
  14.     precvbuf->transfer_len = 0;  
  15.     precvbuf->len = 0;  
  16.   
  17.     #ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX  
  18.     precvbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)precvbuf->alloc_sz, &precvbuf->dma_transfer_addr);  //建立一個DMA緩衝區  
  19.     precvbuf->pbuf = precvbuf->pallocated_buf;  
  20.     if(precvbuf->pallocated_buf == NULL)  
  21.         return _FAIL;  
  22.     #endif //CONFIG_USE_USB_BUFFER_ALLOC_RX  
  23.       
  24.     return res;  
  25. }  
save_snippets.png
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 ? 在CODE上檢視程式碼片 派生到我的程式碼片
  1. static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)  
  2. {     
  3.     struct recv_buf *precvbuf = (struct recv_buf *)rmem;  
  4.     _adapter        *adapter = pintfhdl->padapter;  
  5.     struct dvobj_priv   *pdvobj = adapter_to_dvobj(adapter);  
  6.     struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobj);  
  7.     struct recv_priv    *precvpriv = &adapter->recvpriv;  
  8.     struct usb_device   *pusbd = pdvobj->pusbdev;  
  9.   
  10.     rtl8188eu_init_recvbuf(adapter, precvbuf);        
  11.   
  12.     precvpriv->rx_pending_cnt++;  
  13.   
  14.     purb = precvbuf->purb;  
  15.   
  16.     //translate DMA FIFO addr to pipehandle  
  17.     pipe = ffaddr2pipehdl(pdvobj, addr);  
  18.   
  19.     usb_fill_bulk_urb(purb, pusbd, pipe,   
  20.                     precvbuf->pbuf,  
  21.                             MAX_RECVBUF_SZ,  
  22.                             usb_read_port_complete,  
  23.                             precvbuf);//context is precvbuf  
  24.   
  25.     err = usb_submit_urb(purb, GFP_ATOMIC);  
  26.   
  27.     return ret;  
  28. }  
save_snippets.png
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 謝謝!