平台说明:
s5p4418
sdio接口的wifi模块驱动:If_sdio.c (drivers\net\wireless\libertas)
linux 版本:3.4.29
MMC驱动子系统回顾:
在博客: 中通过跟踪代码的方式,大概了解了mmc控制器HOST的驱动:建立host mmc设备,等待卡的插入,如果有卡插入,卡的类型包括SDIO接口wifi模块,emmc,tf,sd卡等,则控制器驱动判断设备类型是SDIO,MMC还是SD,如下:
1. /* Order's important: probe SDIO, then SD, then MMC */  
2.     if (!mmc_attach_sdio(host))  
3.         return 0;  
4.     if (!mmc_attach_sd(host))  
5.         return 0;  
6.     if (!mmc_attach_mmc(host))  
7.         return 0;其结果就是创建不同类型的设备,如果是SDIO则创建的设备struct sdio_func,如下:
1. struct
2.     func = sdio_alloc_func(card);  
3. ----------------------------------------  
4. /*
5.  * Allocate and initialise a new SDIO function structure.
6.  */
7. struct sdio_func *sdio_alloc_func(struct
8. {  
9. struct
10.   
11. sizeof(struct
12. if
13. return
14.   
15.     func->card = card;  
16.   
17.     device_initialize(&func->dev);  
18.   
19.     func->dev.parent = &card->dev;  
20.     func->dev.bus = &sdio_bus_type;  
21.     func->dev.release = sdio_release_func;  
22.   
23. return
24. }  
 
err = sdio_add_func(host->card->sdio_func[i]);
 SDIO设备建立以后,sdio总线会遍历所有挂在总线上的驱动,然后执行,总线的probe函数,如下: 
static struct bus_type sdio_bus_type = {
     .name        = "sdio",
     .dev_attrs    = sdio_dev_attrs,
     .match        = sdio_bus_match,
     .uevent        = sdio_bus_uevent,
     .probe        = sdio_bus_probe,
     .remove        = sdio_bus_remove,
     .pm        = SDIO_PM_OPS_PTR,
 };---------
sdio_match_device(func, drv);
----------------
if (ids) {
         while (ids->class || ids->vendor || ids->device) {
             if (sdio_match_one(func, ids))
                 return ids;
             ids++;
         }
     }-----------------------
static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
     const struct sdio_device_id *id)
 {
     if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
         return NULL;
     if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
         return NULL;
     if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
         return NULL;
     return id;
 }-------------最终通过驱动和设备struct sdio_device_id进行匹配!如果找到驱动,则会执行驱动的probe,进行一系列设备的初始化。
sdio接口的wifi模块驱动分析:
SDIO接口的wifi的通信接口也是mmc系统,所以wifi驱动也要加上一层mmc驱动的外衣。
这里主要分析:If_sdio.c (drivers\net\wireless\libertas)
首先是sdio注册驱动:
sdio_register_driver(&if_sdio_driver);假设现在总线已经找到了设备对应的驱动,先面就是执行static int if_sdio_probe
probe关于wifi模块的操作主要是:
1、调用函数alloc_netdev()函数分配网络设备。 
 2、对网络设备dev进行初始化,操作函数绑定之后,接着调用了register_netdev(dev)函数,将网络设备注入到内核。 
 到这里可以在系统跑起来后用ifconfig命令来查看这个网络设备,还可以设置这个网络设备的ip地址,网关,子网掩码等。 
 在这个probe函数中还创建了一个内核线程,用来管理这个网络设备的数据发送、事件的处理(卡的拔出)和一些命令的处理。还申请了一个接收数据中断,只要这个wifi模块接收到数据,就会发送一个中断,告诉sdi host我接收到了数据,然后,host就会发送读取命令,对其进行读取,将读取到的数据放到skbuf中递交给ip层。 
 数据接收:  
 if_sdio_probe函数中我们已经申请了一个接收数据的中断
 if_sdio_interrupt(),当接收到数据,wifi模块通过产生中断来提醒host去读取数据,host通过发送cmd53命令将数据接收后放到skbuf中,然后调用ip层提供的接口(netif_rx())函数将数据递交到ip层。
 具体源码跟踪:
priv = lbs_add_card(card, &func->dev);-->
/* Allocate an Ethernet device and register it */
     wdev = lbs_cfg_alloc(dmdev);if (lbs_init_adapter(priv)) {
         pr_err("failed to initialize adapter structure\n");
         goto err_wdev;
     }dev = alloc_netdev(0, "wlan%d", ether_setup);
register_netdev(dev);ret = if_sdio_power_on(card);-->
ret = sdio_claim_irq(func, if_sdio_interrupt);
if (cause & IF_SDIO_H_INT_UPLD) {
         ret = if_sdio_card_to_host(card);
         if (ret)
             goto out;
     }case MVMS_DAT:
         ret = if_sdio_handle_data(card, card->buffer + 4, chunk - 4);
         if (ret)
             goto out;
         break;skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + NET_IP_ALIGN);
lbs_process_rxed_packet(card->priv, skb);
if (in_interrupt())
         netif_rx(skb);发送数据的过程: 
 ip层通过接口(dev_queue_xmit())将数据递交给网络设备协议接口层,网络设备借口层利用netdevice中的注册函数的数据发送函数(.ndo_start_xmit = lbs_hard_start_xmit,),唤醒主线程priv->main_thread,在主线程中回调(priv->hw_host_to_card = if_sdio_host_to_card;)if_sdio_host_to_card()函数。紧接着唤醒packet_work(包处理队列),最后通过sdio协议将数据发送到wifi模块的sram中,wifi模块会自动的将对数据进行处理(例如DA转换等)同无线电波的形式将数据发送到无线路由器。 
android的wifi延伸:

 
 
                     
            
        













 
                    

 
                 
                    