【智能家居篇】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。伪代码如下:

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缓冲区。伪代码如下:

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()将被调用。伪代码如下:

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 谢谢!

时间: 2024-10-22 11:11:07

【智能家居篇】wifi驱动的理解(3)——usb接口在wifi模块中的角色的相关文章

【智能家居篇】wifi驱动的理解(1)——驱动架构

转载请注明出处:http://blog.csdn.net/Righthek 谢谢! 在分析WIFI驱动前,分享一下个人对Linux驱动的一些了解,其实纵观Linux众多的设备驱动,几乎都是以总线为载体,所有的数据传输都是基于总线形式的,即使设备没有所谓的总线接口,但是Linux还是会给它添加一条虚拟总线,如platform总线等:介于WIFI的驱动实在是太庞大了,同时又是基于比较复杂的USB总线,所以建议读者在看此文章之前,先了解一下USB设备驱动和网络设备驱动. 我们要看懂WIFI驱动,首先要

【智能家居篇】wifi驱动的理解(2)

转载请注明出处:http://blog.csdn.net/Righthek 谢谢! 上一篇文章我们已经通过三条线索简单地描述了wifi驱动的框架,现在我们开始深入到每条线索中.首先我们从USB设备这条线索开始.在分析之前,我们需要理解在整个wifi模块中,USB充当什么角色?它的作用是什么?实质上wifi模块上的数据传输有两端,一端是wifi芯片与wifi芯片之间,通过无线射频(RF)进行数据传输:另一端则是wifi芯片与CPU之间,通过USB进行数据传输. 了解Linux的USB驱动的读者都知

【智能家居篇】嵌入式WIFI与普通WIFI的区别

转载请注明出处:http://blog.csdn.net/Righthek 谢谢! 既然我们这系列的文章名称为<智能家居篇>,那么我们有必要提出一个与智能家居相关的概念.曾经一次在TI的无线研讨会上,提及这个概念.究竟是TI提出的,还是其他无线厂家提出的,这个就不去深究了.这个概念就是嵌入式WIFI,也有叫WIFI的IoT(全称:Internet of Things)解决方案,那么它和普通的WIFI又有什么区别呢?请继续阅读下文.         1.嵌入式WIFI的来源 我们都知道笔记本.手

【智能家居篇】wifi在智能家居中的应用

转载请注明出处:http://blog.csdn.net/Righthek 谢谢! 在设计智能家居系统方案时,一个非常关键的point就是组网方式.组网方式关系到整个智能家居系统的稳定性.可扩展性.实时性等:从安装及维护等各方面考虑,对于组网方式,本人觉得现在应该没人会去搭建一个有线的智能家居网络了吧,呵呵...... 所以,我们毫无疑问选择了无线的组网方式! 无线组网方式有很多种,有采用Zigbee.Wifi.Z-wave等等,当然一个完整的智能家居系统不可能只采用单纯的一种无线通信方式进行组

【智能家居篇】通信技术简介

转载请注明出处:http://blog.csdn.net/Righthek 谢谢! 在这个巴西世界杯火爆进行的炎热夏天,能够静下心来写一篇技术性的文章,不容易.2014年科技领域最备受关注之一的莫过于智能家居了.从年初的国际消费电子展(CES)的其中一大看点智能家居,到苹果发布智能家居平台homekit.世界各个科技公司都相继推出自己的智能家居产品. 什么是智能家居呢? 好吧,概念性的东西,我们在谷歌上百度一下吧! 智能家居是以住宅为平台,利用综合布线技术.网络通信技术.安全防范技术.自动控制技

【智能家居篇】wifi网络结构(上)

转载请注明出处:http://blog.csdn.net/Righthek 谢谢! WIFI是什么,相信大家都知道,这里就不作说明了.我们需要做的是深入了解其工作原理,包括软硬件.网络结构等.先说明一下WIFI是遵循IEEE802.11协议的,802.11是最早被国际标准组织认可的无线局域网协议,应该是1999年,到现在都有15年了.那时候哥还在读小学,连电脑都没摸过!太落后了...后来发展出很多以字母为后缀的802.11标准协议,如a.b.g.n.ac等. 本章节不作802.11协议的讲解,后

Android开发—智能家居系列】(二):用手机对WIFI模块进行配置

在实际开发中,我开发的这款APP是用来连接温控器,并对温控器进行控制的.有图为证,哈哈. 上一篇文章[Android开发-智能家居系列](一):智能家居原理的文末总结中写到: 手机APP控制智能温控器就两步:一是通过手机,让WIFI模块接入网络,而是通过网络,使用手机对模块发送指令.在这篇文章中,我们来介绍第一个步骤. [时序图] [概念] [两种模式]: AP:即无线接入点,是一个无线网络的中心节点.通常使用的无线路由器就是一个AP,其它无线终端可以通过AP相互连接. STA:即无线站点,是一

【智能家居篇】wifi网络接入原理(上)——扫描Scanning

转载请注明出处:http://blog.csdn.net/Righthek 谢谢! 对于低头党来说,在使用WIFI功能时,经常性的操作是打开手机上的WIFI设备,搜索到心目中的热点,输入密码,联网成功,各种低头上网...这个看似简单的过程,背后却是隐藏着大量的无线通信技术.用几个专业术语来表示这个过程,分别是:扫描(Scanning).认证(Authentication).关联(Association).下面用一张图来表示这个过程. 图1  WIFI接入网络过程 现在让我们来分析一下这个过程的工

【智能家居篇】wifi网络结构(下)

转载请注明出处:http://blog.csdn.net/Righthek 谢谢! 由于WIFI网络具有移动性,同时WIFI以无线电波作为传输媒介,这种媒介本质上是开放的,且容易被拦截,任何人都可以通过抓包工具截取无线网络的数据包.因此,在设计WIFI协议(其实就是802.11协议)时,需要提供一些传输数据和管理的服务.         1. 分布式(Distribution) 只要基础结构型网络里的移动式站点传送任何数据,就会使用这项服务.一旦基站接收到帧.就会使用分布式服务将帧送至目的地.任