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