Linux 下wifi 驱动开发 SDIO接口WiFi驱动浅析.docx

上传人:b****7 文档编号:10136317 上传时间:2023-02-08 格式:DOCX 页数:23 大小:203.38KB
下载 相关 举报
Linux 下wifi 驱动开发 SDIO接口WiFi驱动浅析.docx_第1页
第1页 / 共23页
Linux 下wifi 驱动开发 SDIO接口WiFi驱动浅析.docx_第2页
第2页 / 共23页
Linux 下wifi 驱动开发 SDIO接口WiFi驱动浅析.docx_第3页
第3页 / 共23页
Linux 下wifi 驱动开发 SDIO接口WiFi驱动浅析.docx_第4页
第4页 / 共23页
Linux 下wifi 驱动开发 SDIO接口WiFi驱动浅析.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

Linux 下wifi 驱动开发 SDIO接口WiFi驱动浅析.docx

《Linux 下wifi 驱动开发 SDIO接口WiFi驱动浅析.docx》由会员分享,可在线阅读,更多相关《Linux 下wifi 驱动开发 SDIO接口WiFi驱动浅析.docx(23页珍藏版)》请在冰豆网上搜索。

Linux 下wifi 驱动开发 SDIO接口WiFi驱动浅析.docx

Linux下wifi驱动开发SDIO接口WiFi驱动浅析

Linux下wifi驱动开发(三)——SDIO接口WiFi驱动浅析

    SDIO-Wifi模块是基于SDIO接口的符合wifi无线网络标准的嵌入式模块,内置无线网络协议IEEE802.11协议栈以及TCP/IP协议栈,能够实现用户主平台数据通过SDIO口到无线网络之间的转换。

SDIO具有传输数据快,兼容SD、MMC接口等特点。

   对于SDIO接口的wifi,首先,它是一个sdio的卡的设备,然后具备了wifi的功能,所以,注册的时候还是先以sdio的卡的设备去注册的。

然后检测到卡之后就要驱动他的wifi功能了,显然,他是用sdio的协议,通过发命令和数据来控制的。

下面先简单回顾一下SDIO的相关知识:

一、SDIO相关基础知识解析

1、SDIO接口

     SDIO 故名思义,就是 SD的I/O接口(interface)的意思,不过这样解释可能还有点抽像。

更具体的说明,SD本来是记忆卡的标准,但是现在也可以把SD拿来插上一些外围接口使用,这样的技术便是SDIO。

    所以SDIO本身是一种相当单纯的技术,透过SD的I/O接脚来连接外部外围,并且透过SD上的I/O数据接位与这些外围传输数据,而且SD协会会员也推出很完整的SDIOstack驱动程序,使得SDIO外围(我们称为SDIO卡)的开发与应用变得相当热门。

    现在已经有非常多的手机或是手持装置都支持SDIO的功能(SD标准原本就是针对mobiledevice而制定),而且许多SDIO外围也都被开发出来,让手机外接外围更加容易,并且开发上更有弹性(不需要内建外围)。

目前常见的SDIO外围(SDIO卡)有:

·Wi-Ficard(无线网络卡) 

·CMOSsensorcard(照相模块) 

·GPScard 

·GSM/GPRSmodemcard 

·Bluetoothcard 

   SDIO的应用将是未来嵌入式系统最重要的接口技术之一,并且也会取代目前GPIO式的SPI接口。

2、SDIO总线

   SDIO总线和USB总线类似,SDIO也有两端,其中一端是HOST端,另一端是device端。

所有的通信都是由HOST端发送命令开始的,Device端只要能解析命令,就可以相互通信。

CLK信号:

HOST给DEVICE的时钟信号,每个时钟周期传输一个命令。

CMD信号:

双向的信号,用于传送命令和反应。

DAT0-DAT3信号:

四条用于传送的数据线。

VDD信号:

电源信号。

VSS1,VSS2:

电源地信号。

3、SDIO热插拔原理

方法:

设置一个 定时器检查 或 插拔中断检测

硬件:

假如GPG10(EINT18)用于SD卡检测

GPG10为高电平即没有插入SD卡

GPG10为低电平 即插入了SD卡

4、SDIO命令

   SDIO总线上都是HOST端发起请求,然后DEVICE端回应请求。

sdio命令由6个字节组成。

a--Command:

用于开始传输的命令,是由HOST端发往DEVICE端的。

其中命令是通过CMD信号线传送的。

b--Response:

回应是DEVICE返回的HOST的命令,作为Command的回应。

也是通过CMD线传送的。

c--Data:

数据是双向的传送的。

可以设置为1线模式,也可以设置为4线模式。

数据是通过DAT0-DAT3信号线传输的。

   SDIO的每次操作都是由HOST在CMD线上发起一个CMD,对于有的CMD,DEVICE需要返回Response,有的则不需要。

   对于读命令,首先HOST会向DEVICE发送命令,紧接着DEVICE会返回一个握手信号,此时,当HOST收到回应的握手信号后,会将数据放在4位的数据线上,在传送数据的同时会跟随着CRC校验码。

当整个读传送完毕后,HOST会再次发送一个命令,通知DEVICE操作完毕,DEVICE同时会返回一个响应。

  对于写命令,首先HOST会向DEVICE发送命令,紧接着DEVICE会返回一个握手信号,此时,当HOST收到回应的握手信号后,会将数据放在4位的数据线上,在传送数据的同时会跟随着CRC校验码。

当整个写传送完毕后,HOST会再次发送一个命令,通知DEVICE操作完毕,DEVICE同时会返回一个响应。

二、SDIO接口驱动

    前面讲到,SDIO接口的wifi,首先,它是一个sdio的卡的设备,然后具备了wifi的功能,所以SDIO接口的WiFi驱动就是在wifi驱动外面套上了一个SDIO驱动的外壳,SDIO驱动仍然符合设备驱动的分层与分离思想:

   设备驱动层(wifi设备)

           |

核心层(向上向下提供接口)

           |

主机驱动层(实现SDIO驱动)

    下面先分析SDIO接口驱动的实现,看几个重要的数据结构(用于核心层与主机驱动层的数据交换处理)。

[/include/linux/mmc/host.h]

structmmc_host  用来描述卡控制器

structmmc_card  用来描述卡

structmmc_driver 用来描述mmc卡驱动

structsdio_func   用来描述功能设备

structmmc_host_ops 用来描述卡控制器操作接口函数功能,用于从主机控制器层向core层注册操作函数,从而将core层与具体的主机控制器隔离。

也就是说core要操作主机控制器,就用这个ops当中给的函数指针操作,不能直接调用具体主控制器的函数。

   HOST层驱动分析在前面的系列文章中 LinuxSD卡驱动开发

(二)——SD卡驱动分析HOST篇 有详细阐述,下面只简单回顾一下一些重要函数处理

1、编写Host层驱动

   这里参考的是S3C24XX的HOST驱动程序 /drivers/mmc/host/s3cmci.c 

[cpp] viewplain copy

1.static struct platform_driver s3cmci_driver = {  

2.     .driver  = {  

3.         .name    = "s3c-sdi",  //名称和平台设备定义中的对应  

4.         .owner   = THIS_MODULE,  

5.         .pm  = s3cmci_pm_ops,  

6.     },  

7.     .id_table = s3cmci_driver_ids,  

8.     .probe        = s3cmci_probe,  //平台设备探测接口函数  

9.     .remove       = __devexit_p(s3cmci_remove),  

10.     .shutdown = s3cmci_shutdown,  

11.};  

12.  

13.s3cmci_probe(struct platform_device *pdev)  

14.{  

15.    //....  

16.    struct mmc_host *mmc;  

17.    mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev);  //分配mmc_host结构体  

18.  

19.    //.....  

20.}  

21.  

22./*注册中断处理函数s3cmci_irq,来处理数据收发过程引起的各种中断*/  

23.request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host) //注册中断处理函数s3cmci_irq  

24.  

25./*注册中断处理s3cmci_irq_cd函数,来处理热拨插引起的中断,中断触发的形式为上升沿、下降沿触发*/  

26.request_irq(host->irq_cd, s3cmci_irq_cd,IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING, DRIVER_NAME, host)  

27.  

28.mmc_add_host(mmc);  //initialise host hardware //向MMC core注册host驱动  

29.----> device_add(&host->class_dev); //添加设备到mmc_bus_type总线上的设备链表中  

30.----> mmc_start_host(host); //启动mmc host  

31.  

32./*MMC drivers should call this when they detect a card has been inserted or removed.检测sd卡是否插上或移除*/  

33. ---->mmc_detect_change(host, 0);  

34.  

35./*Schedule delayed work in the MMC work queue.调度延时工作队列*/  

36. mmc_schedule_delayed_work(&host->detect, delay);  

搜索host->detected得到以下信息:

[/drivers/mmc/core/host.c]

[cpp] viewplain copy

1.NIT_DELAYED_WORK(&host->detect, mmc_rescan);  

2.  

3.mmc_rescan(struct work_struct *work)  

4.---->mmc_bus_put(host);//card 从bus上移除时,释放它占有的总线空间  

5.  

6./*判断当前mmc host控制器是否被占用,当前mmc控制器如果被占用,那么  host->claimed = 1;否则为0 

7. *如果为1,那么会在while

(1)循环中调用schedule切换出自己,当占用mmc控制器的操作完成之后,执行 *mmc_release_host()的时候,会激活登记到等待队列&host->wq中的其他 程序获得mmc主控制器的使用权 

8. */  

9.mmc_claim_host(host);  

10.     mmc_rescan_try_freq(host, max(freqs[i], host->f_min);  

11.  

12.static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)  

13.{  

14.     …  

15.     /* Order's important:

 probe SDIO, then SD, then MMC */  

16.     if (!

mmc_attach_sdio(host))  

17.          return 0;  

18.     if (!

mmc_attach_sd(host))  

19.         return 0;  

20.     if (!

mmc_attach_mmc(host))  

21.         return 0;  

22.        ….  

23.}  

24.  

25.mmc_attach_sdio(struct mmc_host *host)  //匹配sdio接口卡  

26.     --->mmc_attach_bus(host, &mmc_sdio_ops);  

27.  

28./*当card与总线上的驱动匹配,就初始化card*/  

29.mmc_sdio_init_card(host, host->ocr, NULL, 0);   

30.    --->card = mmc_alloc_card(host, NULL);//分配一个card结构体  

31.          mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); //设置mmc_bus的工作模式  

32.  

33.struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; //SDIO functions (devices)  

34.  

35.sdio_init_func(host->card, i + 1);  

36.    --->func = sdio_alloc_func(card); //分配struct sdio_fun(sdio功能设备)结构体  

37.          mmc_io_rw_direct();  

38.          card->sdio_func[fn - 1] = func;  

39.  

40.mmc_add_card(host->card);  //将具体的sdio设备挂载到mmc_bus_types 总线  

41.sdio_add_func(host->card->sdio_func[i]); //将sdio功能设备挂载到sdio_bus_types总线  

这里一系列函数调用在前面的SD驱动蚊帐中已经阐述过了,不再详细阐述

2、SDIO设备的热插拔

   当插拔SDIO设备,会触发中断通知到CPU,然后执行卡检测中断处理函数在这个中断服务函数中,mmc_detect_change->mmc_schedule_delayed_work(&host->detect,delay),INIT_DELAYED_WORK(&host->detect,mmc_rescan)会调度mmc_rescan函数延时调度工作队列,这样也会触发SDIO设备的初始化流程,检测到有效的SDIO设备后,会将它注册到系统中去。

[cpp] viewplain copy

1.static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id)  

2.{  

3.     struct s3cmci_host *host = (struct s3cmci_host *)dev_id;  

4.     ........  

5.     mmc_detect_change(host->mmc, msecs_to_jiffies(500));  

6.  

7.     return IRQ_HANDLED;  

8.}  

三、wifi驱动部分解析

wifi驱动的通用的软件架构

1.分为两部分,上面为主机端驱动,下面是我们之前所说的firmware

2.其中固件部分的主要工作是:

因为天线接受和发送回来的都是802.11帧的帧,而主机接受和传送出来的数据都必须是802.3的帧,所以必须由firmware来负责802.3的帧和802.11帧之间的转换

3.当天线收到数据,并被firmware处理好后会放在一个buffer里,并产生一个中断,主机在收到中断后就去读这个buffer。

    

   SDIO设备的驱动由sdio_driver结构体定义,sdio_driver其实是driver的封装。

通过sdio_register_driver函数将SDIO设备驱动加载进内核,其实就是挂载到sdio_bus_type总线上去。

1、设备驱动的注册与匹配

[Drivers/net/wireless/libertas/if_sdio.c]

[cpp] viewplain copy

1./* SDIO function device driver*/  

2.  

3.struct sdio_driver {  

4.     char *name;  //设备名  

5.     const struct sdio_device_id *id_table; //设备驱动ID  

6.     int (*probe)(struct sdio_func *, const struct sdio_device_id *);//匹配函数  

7.     void (*remove)(struct sdio_func *);  

8.     struct device_driver drv;  

9.};  

下面是具体函数的填充:

[cpp] viewplain copy

1./*if_sdio.c*/  

2.  

3.static struct sdio_driver if_sdio_driver = {  

4.     .name         = "libertas_sdio",  

5.     .id_table = if_sdio_ids,  //用于设备与驱动的匹配  

6.     .probe        = if_sdio_probe,  

7.     .remove       = if_sdio_remove,  

8.     .drv = {  

9.         .pm = &if_sdio_pm_ops,  

10.         }  

11.};  

设备注册函数

[cpp] viewplain copy

1./** 

2. *   sdio_register_driver - register a function driver 

3. *   @drv:

 SDIO function driver 

4. */  

5.  

6.int sdio_register_driver(struct sdio_driver *drv)  

7.{  

8.     drv->drv.name = drv->name;  

9.     drv->drv.bus = &sdio_bus_type;  //设置driver的bus为sdio_bus_type  

10.     return driver_register(&drv->drv);  

11.}  

总线函数

[cpp] viewplain copy

1.static struct bus_type sdio_bus_type = {  

2.     .name         = "sdio",  

3.     .dev_attrs    = sdio_dev_attrs,  

4.     .match        = sdio_bus_match,  

5.     .uevent       = sdio_bus_uevent,  

6.     .probe        = sdio_bus_probe,  

7.     .remove       = sdio_bus_remove,  

8.     .pm      = SDIO_PM_OPS_PTR,  

9.};  

注意:

设备或者驱动注册到系统中的过程中,都会调用相应bus上的匹配函数来进行匹配合适的驱动或者设备,对于sdio设备的匹配是由sdio_bus_match和sdio_bus_probe函数来完成。

[cpp] viewplain copy

1.static int sdio_bus_match(struct device *dev, struct device_driver *drv)  

2.{  

3.     struct sdio_func *func = dev_to_sdio_func(dev);  

4.     struct sdio_driver *sdrv = to_sdio_driver(drv);   

5.     if (sdio_match_device(func, sdrv))  

6.         return 1;   

7.  

8.     return 0;  

9.}  

10.  

11.static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,  

12.     struct sdio_driver *sdrv)  

13.{  

14.     const struct sdio_device_id *ids;  

15.     ids = sdrv->id_table;             

16.  

17.    if (sdio_match_one(func, ids))  

18.                   return ids;  

19.}  

由以上匹配过程来看,通过匹配id_table和sdio_driver设备驱动中id,来匹配合适的驱动或设备。

最终会调用.probe函数,来完成相关操作。

2、If_sdio_probe函数

  当检测到sdio卡插入了之后就会调用If_sdio_probe,而当卡被移除后就会调用If_sdio_remove。

下面先看下If_sdio_probet函数,if_sdio_prob函数主要做了两件事 

[cpp] viewplain copy

1.static struct sdio_driver if_sdio_driver = {  

2. .name  = "libertas_sdio",  

3. .id_table = if_sdio_ids,   //用于设备和驱动的匹配  

4. .probe  = if_sdio_probe,  

5. .remove  = if_sdio_remove,  

6. .drv = {  

7.  .pm = &if_sdio_pm_ops,  

8. },  

9.};  

10.   

11.  

12.1 //定义一个 if_sdio  card的结构体  

13. struct if_sdio_card *card;  

14. struct if_sdio_packet *packet;  //sdio 包的结构体   

15. struct mmc_host *host = func->card->host;  

16.  

17. // 查询是否有指定的功能寄存器在mmc  

18.   //_sdio_card中  

19. for (i = 0;i < func->card->num_info;i++) {  

20.  if (sscanf(func->card->info[i],  

21.    "802.11 SDIO ID:

 %x", &model) == 1)  

22.   

23.//在这里进行片选  选择到我们使用的marvell 8686 的设备  

24.case MODEL_8686:

  

25.  ca

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1