SDIO_WIFI分析


static int __init dhd_module_init(void)
  err = dhd_wifi_platform_register_drv();
      err = wifi_ctrlfunc_register_drv();
      adapter = kzalloc(sizeof(wifi_adapter_info_t), GFP_KERNEL);
            adapter->name = "DHD generic adapter";
            adapter->bus_type = -1;
            adapter->bus_num = -1;
            adapter->slot_num = -1;
            adapter->irq_num = -1;
            is_power_on = FALSE;
            wifi_plat_dev_probe_ret = 0;
            dhd_wifi_platdata = kzalloc(sizeof(bcmdhd_wifi_platdata_t), GFP_KERNEL);
            dhd_wifi_platdata->num_adapters = 1;
            dhd_wifi_platdata->adapters = adapter;
            
            //硬件相关的
            adapter->wifi_plat_data = (void *)&dhd_wlan_control;
            bcm_wlan_set_plat_data(); ***********************************************************************(1)

            adapter->irq_num = bcm_wlan_get_oob_irq();         
            adapter->intr_flags = bcm_wlan_get_oob_irq_flags();
            
       wifi_plat_dev_probe_ret = dhd_wifi_platform_load();  ***********************************************(2)
         
       dhd_wifi_platform_load_sdio() *********************************************************************** (3)
           err = dhd_bus_register();                                                                                                                                   
                 bcmsdh_register(&dhd_sdio);                                                                                                                    
                     drvinfo = *driver;******************************************************************************** (4)
                     error = bcmsdh_register_client_driver();                                                                                         
                      sdio_register_driver(&bcmsdh_sdmmc_driver); *********************************************(5)
                          drv->drv.name = drv->name;                                                                                         
                          drv->drv.bus = &sdio_bus_type;                                                                                   
                                                    driver_register(&drv->drv);                                                                    
                                                        bus_add_driver(drv);                                                                                      
                                                                bus = bus_get(drv->bus);                                                          
                                                            priv->driver = drv;                                                                              
                                                            driver_attach(drv);                                                                            
                                                                bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);    
                                                                    static int __driver_attach(struct device *dev, void *data)       
                                                                        driver_probe_device(drv, dev);                                              
                                                                             really_probe(dev, drv);                                                        
                                                                                 dev->bus->probe(dev);  *************************************(6)                                                 
                                                                                                                                                                       
                                                                                                 
                     

第(6)调用sdio_bus_type结构体的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,            
};     

static int sdio_bus_probe(struct device *dev)                                                                                            

    drv->probe(func, id);******************************************************************************************(7)

第(7)调用(5)结构体的probe

static struct sdio_driver bcmsdh_sdmmc_driver = {                                                                             
     .probe        = bcmsdh_sdmmc_probe,                                                                                                          
     .remove        = bcmsdh_sdmmc_remove,                                                                                                   
     .name        = "bcmsdh_sdmmc",                                                                                                                      
     .id_table    = bcmsdh_sdmmc_ids,                                                                                                                 
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)        
     .drv = {                                                                                                                                                                                   
     .pm    = &bcmsdh_sdmmc_pm_ops,                                                                                                                            
     },                                                                                                                                                                                            
 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ *                       
 };                                                                              

                                                                                                                                                                                                  
static int bcmsdh_sdmmc_probe(struct sdio_func *func, const struct sdio_device_id *id)                                         
    sdioh_probe(func);                                                                                                                                                       
         sdioh->bcmsdh = bcmsdh_probe(osh, &func->dev, sdioh, adapter, SDIO_BUS, host_idx, rca);*******(8)
                                                                                                                                                                                                    
  第(8)调用(4)结构体的probe ,与网络相关联                                                                                                                                                                                           
 static bcmsdh_driver_t dhd_sdio = { 
   dhdsdio_probe,                    
   dhdsdio_disconnect,                 
   dhdsdio_suspend,             
   dhdsdio_resume,              
 };     
                                                                                                                                              
static void *dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
     uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)  
  网络相关的    
                                                                                                                                                                                                             
                                                                                                                                                                                                                         
第(2)初始化探测SDIO函数                                                                                                                              
static int dhd_wifi_platform_load_sdio(void)
    wifi_platform_bus_enumerate(adapter, TRUE);
        plat_data = adapter->wifi_plat_data;
        device_present = TRUE;

      plat_data->set_carddetect(device_present);******************************************************(9)

      


第(2)调用(10)

dhd_wlan_control.set_carddetect = bcm_wlan_set_carddetect; ************************************(10)

int bcm_wlan_set_carddetect(bool present)
    force_presence_change(NULL, present);
        sw_mci_rescan_card(state);
            slot = mci_slot[CFG_WIFI_SDIO_ID]; // CFG_WIFI_SDIO_ID sd 1口
            mmc_detect_change(slot->mmc, 0);
                mmc_schedule_delayed_work(&host->detect, delay);
                        ==>host->detect就是mmc_rescan
                        INIT_DELAYED_WORK(&host->detect, mmc_rescan);
                        ==>mmc_rescan
                        ==>host->bus_ops->detect(host);//就是mmc_sdio_detect

                        ==>static const struct mmc_bus_ops mmc_sdio_ops.detect = mmc_sdio_detect;****(11)


第(11)调用(9)SDIO探测函数枚举SDIO,与SDIO相关联

                       

    
参考:http://blog.csdn.net/fenzhi1988/article/details/44809779

调试驱动之前,首先先看看驱动代码,了解代码大致工作流程,再根据硬件配置驱动,比如硬件上面没有

中断脚,就不要在驱动里面配置中断方式。
bcmdhd驱动代码分析:

一. dhd_linux.c
dhd_module_init为驱动模块初始化函数。
初始化函数调用dhd_linux_platdev.c中dhd_wifi_platform_register_drv查找设备,注册驱动等。

 

二.   dhd_linux_platdev.c
        cfg_multichip=FALSE,所以dhd_wifi_platform_register_drv直接调用wifi_ctrlfunc_register_drv。

       wifi_ctrlfunc_register_drv中先调用bus_find_device寻找平台设备,如果寻找到,接下来就会调用
platform_driver_register来注册平台设备驱动。注册完,就会调用平台驱动的probe函数进行驱动后
续初始化,但是这两个平台设备都没有注册。
        初始化wifi_adapter_info_t,把这个adapter传递给全局变量dhd_wifi_platdata,供其他函数使用。
使用dhd_wlan_control全局变量初始化adapter中的wifi_plat_data成员,而dhd_wlan_control全局变量
在下面调用dhd_gpio.c中的bcm_wlan_set_plat_data()初始化,dhd_wlan_control全局变量保存
set_power/set_carddetect/mem_prealloc这些底层控制接口。
       最后调用dhd_wifi_platform_load()->dhd_wifi_platform_load_sdio()
     dhd_wifi_platform_load_sdio()中,开始进行sdio设备枚举,adapter只有一个。尝试3次枚举,dhd_bus_reg_sdio_notify()
注册一个 dummy_sdmmc 驱动,其probe函数释放一个信号量,再调用wifi_platform_set_power()。
wifi_platform_set_power()函数调用adapter成员wifi_plat_data中的set_power开启模块电源,set_power已
经初始化为dhd_gpio.c的bcm_wlan_set_power(),bcm_wlan_set_power()只是设置引脚电平。
wifi_platform_set_power()函数调用成功,调用wifi_platform_bus_enumerate(adapter, TRUE);这个函
数调用adapter成员wifi_plat_data中的set_carddetect,真正调用的是dhd_gpio.c的bcm_wlan_set_carddetect()

三.    Linux-3.4\drivers\net\wireless\bcmdhd\dhd_gpio.c
bcm_wlan_set_carddetect()调用sunxi_mci_rescan_card(sdc_id, 1);

四.   linux-3.4\drivers\mmc\host\sunxi-mci.c
sunxi_mci_rescan_card()函数软设置指定host的sdio卡可见,再调用mmc_detect_change()触发mmc探测历程。
如果发现总线上有设备,会调用上面的dummy驱动的probe函数释放信号量,在dhd_wifi_platform_load_sdio()中
等待的信号量就会成功唤醒,并跳出循环。

五.    linux-3.4\drivers\net\wireless\bcmdhd\dhd_linux_platdev.c
dhd_wifi_platform_load_sdio()跳出循环之后,继续调用dhd_bus_register()->bcmsdh_register()->bcmsdh_register_client_driver()
->sdio_register_driver()
sdio_register_driver()注册名为bcmsdh_sdmmc的驱动,此驱动注册注册完成,即进入bcmsdh_sdmmc_probe()。最后调用
sdioh_probe()进行真正的驱动初始化。sdioh_probe()->bcmsdh_probe()->drvinfo.probe()
drvinfo在bcmsdh_register()初始化。bcmsdh_register()调用处为dhd_bus_register()函数,设置为dhd_sdio变量,所以
drvinfo.probe()调用的是dhdsdio_probe()函数。

六.    linux-3.4\drivers\net\wireless\bcmdhd\dhd_sdio.c
dhdsdio_probe()函数继续深入初始化。这个函数里面有个变量dhd_download_fw_on_driverload,决定函数初始化流程,需要
修改为TRUE。

后面的代码越来越接近真正网络注册,基本上,到这里都比较正常,驱动差不多就可以顺利加载了,至于加载后出错的问题,很大原因是驱动没有

配置好,一般调试成熟的驱动代码或是其他代码的时候,首先要怀疑自己是不是正确的进行了配置。

 

驱动要加载固件,需要文件系统,所以驱动最好是做成ko。
硬件上,模块没有中断脚,所以需要设置为poll方式。
linux-3.4\drivers\net\wireless\bcmdhd\dhd_linux.c中修改dhd_poll,dhd_intr

 

开始调试

* 没有在系统配置文件里面声明sdio1有效,导致驱动不执行sdio相关probe函数
 在sys_config.fex声明sdio1有效。
* wifi_pm模块初始化太迟导致wifi模块不能正确获取电源相关操作资源。
 在wifi模块初始化之前直接调用wifi_pm模块初始化函数进行初始化。
* 修改module_num为8,在wifi_pm.c的函数wifi_pm_power里面case 7:后面增加case 8:
* module_pm模块初始化太迟,导致wifi模块不能正确获取电源相关操作资源。
 使用fs_initcall_sync提前初始化。
* 去掉wifi驱动Mafile中的-DOOB_INTR_ONLY
            
                                                
                                                

                     
              
       


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值