轉自: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