天天看點

博通wifi驅動

很早之前自己的筆記,想想還是記錄到網上吧

注冊

7611 static int __init
 7612 dhd_module_init(void)
 7613 {
 7614     int err;
 7615     int retry = POWERUP_MAX_RETRY;
 7616 
 7617     printk("%s: in\n", __FUNCTION__);
 7618 
 7619     DHD_PERIM_RADIO_INIT();
 7620 
 7621     if (firmware_path[0] != '\0') {
 7622         strncpy(fw_bak_path, firmware_path, MOD_PARAM_PATHLEN);
 7623         fw_bak_path[MOD_PARAM_PATHLEN-1] = '\0';
 7624     }
 7625 
 7626     if (nvram_path[0] != '\0') {
 7627         strncpy(nv_bak_path, nvram_path, MOD_PARAM_PATHLEN);
 7628         nv_bak_path[MOD_PARAM_PATHLEN-1] = '\0';
 7629     }
 7630 
 7631     do {
 7632         err = dhd_wifi_platform_register_drv();
 7633         if (!err) {
 7634             register_reboot_notifier(&dhd_reboot_notifier);
 7635             break;
 7636         }
 7637         else {
 7638             DHD_ERROR(("%s: Failed to load the driver, try cnt %d\n",
 7639                 __FUNCTION__, retry));
 7640             strncpy(firmware_path, fw_bak_path, MOD_PARAM_PATHLEN);
 7641             firmware_path[MOD_PARAM_PATHLEN-1] = '\0';
  7642             strncpy(nvram_path, nv_bak_path, MOD_PARAM_PATHLEN);
 7643             nvram_path[MOD_PARAM_PATHLEN-1] = '\0';
 7644         }
 7645     } while (retry--);
 7646 
 7647     if (err)
 7648         DHD_ERROR(("%s: Failed to load driver max retry reached**\n", __FUNCTION__));
 7649 
 7650     printk("%s: Exit err=%d\n", __FUNCTION__, err);
 7651     return err;
 7652 }                                                                             
           

該數是博通wifi驅動注冊的起始函數,7621~7629獲得固件的路徑,固件路徑在makemenuconfig可以指定。

7632行注冊wifi的平台驅動。如果注冊成功,則7634行注冊一個wifi重新開機的通知鍊。

543 int dhd_wifi_platform_register_drv(void) 
544 { 
545     int err = 0; 
...
565     { 
566         err = wifi_ctrlfunc_register_drv(); 
567 
568         /* no wifi ctrl func either, load bus directly and ignore this error */ 
569         if (err) { 
570             if (err == -ENXIO) { 
571                 /* wifi ctrl function does not exist */ 
572                 err = dhd_wifi_platform_load(); 
573             } else { 
574                 /* unregister driver due to initialization failure */ 
575                 wifi_ctrlfunc_unregister_drv(); 
576             } 
577         } 
578     } 
579 
580     return err; 
581 } 
           

566行注冊wifi的相關控制函數。

381 static int wifi_ctrlfunc_register_drv(void) 
382 { 
383     wifi_adapter_info_t *adapter; 
384 
385 #ifndef CUSTOMER_HW 
386     int err = 0; 
387     struct device *dev1, *dev2; 
388     dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match); 
389     dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); 
390 #endif 
391 
392 #if !defined(CONFIG_DTS) && !defined(CUSTOMER_HW) 
393     if (!dts_enabled) { 
394         if (dev1 == NULL && dev2 == NULL) { 
395             DHD_ERROR(("no wifi platform data, skip\n")); 
396             return -ENXIO; 
397         } 
398     } 
399 #endif /* !defined(CONFIG_DTS) */ 
400 
401     /* multi-chip support not enabled, build one adapter information for 
402      * DHD (either SDIO, USB or PCIe) 
403      */ 
404     adapter = kzalloc(sizeof(wifi_adapter_info_t), GFP_KERNEL); 
405     adapter->name = "DHD generic adapter"; 
406     adapter->bus_type = -1; 
407     adapter->bus_num = -1; 
408     adapter->slot_num = -1; 
409     adapter->irq_num = -1; 
410     is_power_on = FALSE; 
411     wifi_plat_dev_probe_ret = 0; 
412     dhd_wifi_platdata = kzalloc(sizeof(bcmdhd_wifi_platdata_t), GFP_KERNEL); 
413     dhd_wifi_platdata->num_adapters = 1; 
414     dhd_wifi_platdata->adapters = adapter; 
...
435 #if !defined(CONFIG_DTS) 
436     if (dts_enabled) { 
437 #ifdef CUSTOMER_HW 
438         adapter->wifi_plat_data = (void *)&dhd_wlan_control; 
439         bcm_wlan_set_plat_data(); 
440 #ifdef CUSTOMER_OOB 
441         adapter->irq_num = bcm_wlan_get_oob_irq(); 
442         adapter->intr_flags = bcm_wlan_get_oob_irq_flags(); 
443 #endif 
444 #else 
445         struct resource *resource; 
446         resource = &dhd_wlan_resources; 
447         adapter->irq_num = resource->start; 
448         adapter->intr_flags = resource->flags & IRQF_TRIGGER_MASK; 
449 #endif 
450         wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); 
451     } 
452 #endif /* !defined(CONFIG_DTS) */ 
453 
454 
455 #if defined(CONFIG_DTS) && !defined(CUSTOMER_HW) 
456     wifi_plat_dev_probe_ret = platform_driver_register(&wifi_platform_dev_driver); 
457 #endif /* CONFIG_DTS */ 
458 
459     /* return probe function's return value if registeration succeeded */ 
460     return wifi_plat_dev_probe_ret; 
461 } 
           

385~390行,CUSTOMER_HW在makefile中定義了,該宏的意義是使用的使用者定制的硬體情況下的驅動注冊。392~399行同樣略過。

我們使用的wifi模組是sdio接口方式,401~415初始化一個wifiadapter的相關資料結構,在i2c裝置驅動中也有adapter的概念。

435~437行,這三行的條件都滿足。

438行為adapter的wifi_plat_data成員先占坑。

439行的函數在dmesg出來的啟動資訊的2.685895秒有顯示。其是為438行占坑的指針指派成員初始化。指派的這三個成員是平台相關的,如下:

dhd_wlan_control.set_power = bcm_wlan_set_power;
	dhd_wlan_control.set_carddetect = bcm_wlan_set_carddetect;
	dhd_wlan_control.get_mac_addr = bcm_wlan_get_mac_address;
           

441行獲得wifi的中斷号,對應于2.686263秒列印出的資訊,該中斷号是ap6335的13腳(WL_HOST_WAKE)輸出信号,該腳的作用是WLAN喚醒AP(應用處理器)。

442行設定該中斷的标志為中斷,高電平觸發,中斷資源可以共享。

444~449行是else分支,并沒有得到執行。

450行加載wifi的sdio驅動,2.687878列印的資訊即進入該函數。其sdio加載函數是

dhd_wifi_platform_load_sdio()。

685 #ifdef BCMSDIO 
686 static int dhd_wifi_platform_load_sdio(void) 
687 { 
688     int i; 
689     int err = 0; 
690     wifi_adapter_info_t *adapter; 
           

//去除沒用使用的變量帶來的警告,處理編譯上的,和功能上沒有什麼關系。

692     BCM_REFERENCE(i); 
693     BCM_REFERENCE(adapter); 
           

//參數安全性檢查

694     /* Sanity check on the module parameters 
695      * - Both watchdog and DPC as tasklets are ok 
696      * - If both watchdog and DPC are threads, TX must be deferred 
697      */ 
698     if (!(dhd_watchdog_prio < 0 && dhd_dpc_prio < 0) && 
699         !(dhd_watchdog_prio >= 0 && dhd_dpc_prio >= 0 && dhd_deferred_tx)) 
700         return -EINVAL; 
           

//702行同樣在makefile中定義,dhd_wifi_platdata在上面紅色那行已經被指派。

702 #if defined(BCMLXSDMMC) 
703     if (dhd_wifi_platdata == NULL) { 
704         DHD_ERROR(("DHD wifi platform data is required for Android build\n")); 
705         return -EINVAL; 
706     } 
           

//将dhd_registration_sem這個信号量初始化為0.

708     sema_init(&dhd_registration_sem, 0); 
           

//adapter的個數實際上就是1,是以該循環隻執行一次

710     for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { 
711         bool chip_up = FALSE; 
712         int retry = POWERUP_MAX_RETRY; 
713         struct semaphore dhd_chipup_sem; 
714 
715         adapter = &dhd_wifi_platdata->adapters[i]; 
           

//對應于2.688490時刻列印的資訊。

717         DHD_ERROR(("Power-up adapter '%s'\n", adapter->name)); 
718         DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", 
719             adapter->irq_num, adapter->intr_flags, adapter->fw_path, adapter->nv_path)); 
720         DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", 
721             adapter->bus_type, adapter->bus_num, adapter->slot_num)); 
722 
723         do { 
           

//同樣是信号量初始化

724             sema_init(&dhd_chipup_sem, 0); 
//Register a dummy SDIO client driver in order to be notified of new SDIO device
725             err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem); 
726             if (err) { 
727                 DHD_ERROR(("%s dhd_bus_reg_sdio_notify fail(%d)\n\n", 
728                     __FUNCTION__, err)); 
729                 return err; 
730             } 
           

//調用bcm_wlan_set_power,将ap6335的12腳拉低,讓其内部電源穩壓器工作。上電完成傳回TRUE。上電正常傳回值err=0。

731             err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY); 
732             if (err) { 
733                 /* WL_REG_ON state unknown, Power off forcely */ 
734                 wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); 
735                 continue; 
736             } else { 
           

//上電成功,則需要枚舉裝置,3.099935時刻列印的資訊。bcm_wlan_set_carddetect

737                 wifi_platform_bus_enumerate(adapter, TRUE); 
738                 err = 0; 
739             } 
           

//如果成功擷取到dhd_chipup_sem,則表示wifi晶片成功powerup,這時表sdio的notify登出掉并跳出這個循環。

741             if (down_timeout(&dhd_chipup_sem, msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { 
742                 dhd_bus_unreg_sdio_notify(); 
743                 chip_up = TRUE; 
744                 break; 
745             }
           

//出錯處理,省略

...
751         } while (retry--); 
...
753         if (!chip_up) { 
754             DHD_ERROR(("failed to power up %s, max retry reached**\n", adapter->name)); 
755             return -ENODEV; 
756         } 
757 
758     } 
           

//dhd總線注冊

760     err = dhd_bus_register(); 
761 
762     if (err) { 
763         DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); 
764         goto fail; 
765     } 
766 
767 
768     /* 
769      * Wait till MMC sdio_register_driver callback called and made driver attach. 
770      * It's needed to make sync up exit from dhd insmod  and 
771      * Kernel MMC sdio device callback registration 
772      */ 
773     err = down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)); 
774     if (err) { 
775         DHD_ERROR(("%s: sdio_register_driver timeout or error \n", __FUNCTION__)); 
776         dhd_bus_unregister(); 
777         goto fail; 
778     } 
779 
780     return err; 
781 
782 fail: 
783     /* power down all adapters */ 
784     for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { 
785         adapter = &dhd_wifi_platdata->adapters[i]; 
786         wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); 
787         wifi_platform_bus_enumerate(adapter, FALSE); 
788     } 
789 #else 
790 
791     /* x86 bring-up PC needs no power-up operations */ 
792     err = dhd_bus_register(); 
793 
794 #endif 
795 
796     return err; 
797 } 
           

sdio裝置探測函數如下,對應3.100247時刻的輸出資訊就是下面88行的輸出。

82 extern void exynos_dwmci1_notify_change(int state); 
 83 int bcm_wlan_set_carddetect(bool present) 
 84 { 
 85     int err = 0; 
 86 
 87     if (present) { 
 88         printk("======== Card detection to detect SDIO card! ========\n"); 
 89 #ifdef CONFIG_MACH_ODROID_4210 
 90         exynos_dwmci1_notify_change(1); 
 91 #endif 
 92     } else { 
 93         printk("======== Card detection to remove SDIO card! ========\n"); 
 94 #ifdef CONFIG_MACH_ODROID_4210 
 95         exynos_dwmci1_notify_change(0); 
 96 #endif 
 97     } 
 98 
 99     return err; 
100 } 
           

由于exynos_dwmci1_notify_change屬于mmc的範疇,

157 static void (*_exynos_dwmci1_notify_func)(struct platform_device *, int); 
158 void exynos_dwmci1_notify_change(int state) 
159 { 
160     if (_exynos_dwmci1_notify_func) 
161         _exynos_dwmci1_notify_func(&exynos5_device_dwmci1, state); 
162 } 
163 EXPORT_SYMBOL(exynos_dwmci1_notify_change); 
164 
           

_exynos_dwmci1_notify_func是一個函數指針,實際上就是函數dw_mci_notify_change。

307 void __init exynos5_tf4_mmc_init(void) 
308 { 
309 #ifdef CONFIG_MMC_DW 
310     if (samsung_rev() < EXYNOS5410_REV_1_0) 
311         smdk5410_dwmci0_pdata.caps &= 
312             ~(MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR); 
313 #ifndef CONFIG_EXYNOS_EMMC_HS200 
314     smdk5410_dwmci0_pdata.caps2 &= 
315         ~MMC_CAP2_HS200_1_8V_SDR; 
316 #endif 
317     exynos_dwmci_set_platdata(&smdk5410_dwmci0_pdata, 0); 
318     exynos_dwmci_set_platdata(&smdk5410_dwmci1_pdata, 1); 
319     exynos_dwmci_set_platdata(&smdk5410_dwmci2_pdata, 2); 
320 #endif 
321     platform_add_devices(smdk5410_mmc_devices, 
322             ARRAY_SIZE(smdk5410_mmc_devices)); 
323 } 
           

資料接收

drivers/net/wireless/bcmdhd/dhd_linux.c

drivers/net/wireless/bcmdhd/dhd_sdio.c

 關鍵函數流程

dhdsdio_probe
	dhd_attach
6054  dhd_bus_dpc
5788  dhdsdio_dpc  ---
5053  dhdsdio_readframes
           

接收處理函數,經過該函數後,見基于以太網的接收流程

drivers/net/wireless/bcmdhd/dhd_linux.c
2855 void
 2856 dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
 2857 {
 2858     dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
 2859     struct sk_buff *skb;
 2860     uchar *eth;
 2861     uint len;
 2862     void *data, *pnext = NULL;
….
3123         if (in_interrupt()) {
 3124             netif_rx(skb);
 3125         } else {
 3126             if (dhd->rxthread_enabled) {
 3127                 if (!skbhead)
 3128                     skbhead = skb;
 3129                 else
 3130                     PKTSETNEXT(dhdp->osh, skbprev, skb);
 3131                 skbprev = skb;
 3132             } else {
 3133 
 3134                 /* If the receive is not processed inside an ISR,
 3135                  * the softirqd must be woken explicitly to service
 3136                  * the NET_RX_SOFTIRQ.  In 2.6 kernels, this is handled
 3137                  * by netif_rx_ni(), but in earlier kernels, we need
 3138                  * to do it manually.
 3139                  */
 3140 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
 3141                 netif_rx_ni(skb);
 3142 #else
 3143                 ulong flags;
 3144                 netif_rx(skb);
           

繼續閱讀