From 3f409b9c1f6300114f8de2f52f518decafdeb451 Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Mon, 27 Jun 2011 18:53:59 -0700 Subject: [PATCH] Update to 5.90.125.32: * Move Android specific functions to wl_android (wifi control functions, wifi device, pre-alloc buffer.) * Link Android start/stop commands to interface up/down (download firmware when primary interfacde is up.) * Fix a issue in driver unload, the same IRQ can not be disabled twice (set_irq_wake) Change-Id: Id49c4f746f69371323c9a34834c3b628b78ff713 Signed-off-by: Howard M. Harte Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/bcmsdh_linux.c | 9 +- drivers/net/wireless/bcmdhd/dhd.h | 28 +- drivers/net/wireless/bcmdhd/dhd_cdc.c | 10 +- drivers/net/wireless/bcmdhd/dhd_common.c | 39 +- drivers/net/wireless/bcmdhd/dhd_custom_gpio.c | 2 - drivers/net/wireless/bcmdhd/dhd_linux.c | 351 +++++---------- drivers/net/wireless/bcmdhd/dhd_sdio.c | 35 +- drivers/net/wireless/bcmdhd/include/epivers.h | 8 +- drivers/net/wireless/bcmdhd/linux_osl.c | 9 +- drivers/net/wireless/bcmdhd/wl_android.c | 411 +++++++++++++++--- drivers/net/wireless/bcmdhd/wl_android.h | 39 ++ drivers/net/wireless/bcmdhd/wl_cfg80211.c | 52 +-- drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 2 +- drivers/net/wireless/bcmdhd/wl_iw.c | 8 +- drivers/net/wireless/bcmdhd/wldev_common.c | 7 +- drivers/net/wireless/bcmdhd/wldev_common.h | 8 +- 16 files changed, 588 insertions(+), 430 deletions(-) create mode 100644 drivers/net/wireless/bcmdhd/wl_android.h diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c index 37bb990bec5a..6fa47378cfe9 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c @@ -77,6 +77,7 @@ struct bcmsdh_hc { unsigned int oob_irq; unsigned long oob_flags; /* OOB Host specifiction as edge and etc */ bool oob_irq_registered; + bool oob_irq_enable_flag; #if defined(OOB_INTR_ONLY) spinlock_t irq_lock; #endif @@ -238,6 +239,7 @@ int bcmsdh_probe(struct device *dev) sdhc->oob_irq = irq; sdhc->oob_flags = irq_flags; sdhc->oob_irq_registered = FALSE; /* to make sure.. */ + sdhc->oob_irq_enable_flag = FALSE; #if defined(OOB_INTR_ONLY) spin_lock_init(&sdhc->irq_lock); #endif @@ -639,6 +641,7 @@ int bcmsdh_register_oob_intr(void * dhdp) enable_irq_wake(sdhcinfo->oob_irq); sdhcinfo->oob_irq_registered = TRUE; + sdhcinfo->oob_irq_enable_flag = TRUE; } return 0; @@ -646,8 +649,9 @@ int bcmsdh_register_oob_intr(void * dhdp) void bcmsdh_set_irq(int flag) { - if (sdhcinfo->oob_irq_registered) { + if (sdhcinfo->oob_irq_registered && sdhcinfo->oob_irq_enable_flag != flag) { SDLX_MSG(("%s Flag = %d", __FUNCTION__, flag)); + sdhcinfo->oob_irq_enable_flag = flag; if (flag) { enable_irq(sdhcinfo->oob_irq); enable_irq_wake(sdhcinfo->oob_irq); @@ -663,8 +667,7 @@ void bcmsdh_unregister_oob_intr(void) SDLX_MSG(("%s: Enter\n", __FUNCTION__)); if (sdhcinfo->oob_irq_registered == TRUE) { - disable_irq_wake(sdhcinfo->oob_irq); - disable_irq(sdhcinfo->oob_irq); /* just in case.. */ + bcmsdh_set_irq(FALSE); free_irq(sdhcinfo->oob_irq, NULL); sdhcinfo->oob_irq_registered = FALSE; } diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index f7a103acc44f..4a7f571c766a 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -93,9 +93,21 @@ enum dhd_prealloc_index { DHD_PREALLOC_DATABUF, DHD_PREALLOC_OSL_BUF }; -#ifdef DHD_USE_STATIC_BUF -extern void * dhd_os_prealloc(int section, unsigned long size); -#endif + +#if defined(DHD_USE_STATIC_BUF) + +uint8* dhd_os_prealloc(void *osh, int section, uint size); +void dhd_os_prefree(void *osh, void *addr, uint size); +#define DHD_OS_PREALLOC(osh, section, size) dhd_os_prealloc(osh, section, size) +#define DHD_OS_PREFREE(osh, addr, size) dhd_os_prefree(osh, addr, size) + +#else + +#define DHD_OS_PREALLOC(osh, section, size) MALLOC(osh, size) +#define DHD_OS_PREFREE(osh, addr, size) MFREE(osh, addr, size) + +#endif /* defined(DHD_USE_STATIC_BUF) */ + /* Common structure for module and instance linkage */ typedef struct dhd_pub { /* Linkage ponters */ @@ -272,8 +284,11 @@ extern unsigned long dhd_os_spin_lock(dhd_pub_t *pub); extern void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags); -extern void dhd_os_start_lock(dhd_pub_t *pub); -extern void dhd_os_start_unlock(dhd_pub_t *pub); +/* interface operations (register, remove) should be atomic, use this lock to prevent race + * condition among wifi on/off and interface operation functions + */ +void dhd_net_if_lock(struct net_device *dev); +void dhd_net_if_unlock(struct net_device *dev); typedef struct dhd_if_event { uint8 ifidx; @@ -519,6 +534,9 @@ extern char nv_path[MOD_PARAM_PATHLEN]; extern char fw_path2[MOD_PARAM_PATHLEN]; #endif +/* Flag to indicate if we should download firmware on driver load */ +extern uint dhd_download_fw_on_driverload; + /* For supporting multiple interfaces */ #define DHD_MAX_IFS 16 #define DHD_DEL_IF -0xe diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c index 44a431b58ffd..91c461f7bbe0 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cdc.c +++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c @@ -2183,17 +2183,11 @@ dhd_prot_attach(dhd_pub_t *dhd) { dhd_prot_t *cdc; -#ifndef DHD_USE_STATIC_BUF - if (!(cdc = (dhd_prot_t *)MALLOC(dhd->osh, sizeof(dhd_prot_t)))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - goto fail; - } -#else - if (!(cdc = (dhd_prot_t *)dhd_os_prealloc(DHD_PREALLOC_PROT, sizeof(dhd_prot_t)))) { + if (!(cdc = (dhd_prot_t *)DHD_OS_PREALLOC(dhd->osh, DHD_PREALLOC_PROT, + sizeof(dhd_prot_t)))) { DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); goto fail; } -#endif /* DHD_USE_STATIC_BUF */ memset(cdc, 0, sizeof(dhd_prot_t)); /* ensure that the msg buf directly follows the cdc msg struct */ diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index 1bfca858b11f..39ded0107e81 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -87,10 +87,10 @@ extern int dhd_iscan_in_progress(void *h); void dhd_iscan_lock(void); void dhd_iscan_unlock(void); extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); -#if defined(SOFTAP) + bool ap_cfg_running = FALSE; bool ap_fw_loaded = FALSE; -#endif + #if defined(KEEP_ALIVE) int dhd_keep_alive_onoff(dhd_pub_t *dhd, int ka_on); @@ -194,7 +194,6 @@ dhd_common_init(osl_t *osh) * behavior since the value of the globals may be different on the * first time that the driver is initialized vs subsequent initializations. */ - dhd_msg_level = DHD_ERROR_VAL; /* Allocate private bus interface state */ if (!(cmn = MALLOC(osh, sizeof(dhd_cmn_t)))) { DHD_ERROR(("%s: MALLOC failed\n", __FUNCTION__)); @@ -1574,13 +1573,14 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) memcpy(dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN); } else { #endif /* GET_CUSTOM_MAC_ENABLE */ - /* Get the default device MAC address directly from firmware */ - strcpy(iovbuf, "cur_etheraddr"); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) { - DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); - return BCME_NOTUP; - } - memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); + /* Get the default device MAC address directly from firmware */ + strcpy(iovbuf, "cur_etheraddr"); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), + FALSE, 0)) < 0) { + DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); + return BCME_NOTUP; + } + memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); #ifdef GET_CUSTOM_MAC_ENABLE } #endif /* GET_CUSTOM_MAC_ENABLE */ @@ -1598,9 +1598,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) iovbuf[4] = (unsigned char)(rand_mac >> 8); iovbuf[5] = (unsigned char)(rand_mac >> 16); - printk("Broadcom Dongle Host Driver mac=%02x:%02x:%02x:%02x:%02x:%02x\n", - iovbuf[0], iovbuf[1], iovbuf[2], iovbuf[3], iovbuf[4], iovbuf[5]); - bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf)); ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); if (ret < 0) { @@ -1610,6 +1607,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } #endif /* SET_RANDOM_MAC_SOFTAP */ + DHD_ERROR(("Broadcom Dongle Host Driver mac=%02x:%02x:%02x:%02x:%02x:%02x\n", + iovbuf[0], iovbuf[1], iovbuf[2], iovbuf[3], iovbuf[4], iovbuf[5])); + /* Set Country code */ if (dhd->dhd_cspec.ccode[0] != 0) { bcm_mkiovar("country", (char *)&dhd->dhd_cspec, @@ -1675,7 +1675,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) DHD_ERROR(("%s set keeplive failed %d\n", __FUNCTION__, res)); } -#endif +#endif /* defined(KEEP_ALIVE) */ /* Force STA UP */ ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0); @@ -1775,11 +1775,16 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) /* set mode to allow pattern */ bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + #ifdef ARP_OFFLOAD_SUPPORT - /* Set and enable ARP offload feature */ - if (dhd_arp_enable) + /* Set and enable ARP offload feature for STA only */ + if (dhd_arp_enable && !ap_fw_loaded) { dhd_arp_offload_set(dhd, dhd_arp_mode); - dhd_arp_offload_enable(dhd, dhd_arp_enable); + dhd_arp_offload_enable(dhd, dhd_arp_enable); + } else { + dhd_arp_offload_set(dhd, 0); + dhd_arp_offload_enable(dhd, FALSE); + } #endif /* ARP_OFFLOAD_SUPPORT */ diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c index 9958513cfefe..b7d78d1cdc42 100644 --- a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c @@ -43,13 +43,11 @@ extern void bcm_wlan_power_on(int); #endif /* CUSTOMER_HW */ #if defined(CUSTOMER_HW2) #ifdef CONFIG_WIFI_CONTROL_FUNC -int wifi_set_carddetect(int on); int wifi_set_power(int on, unsigned long msec); int wifi_get_irq_number(unsigned long *irq_flags_ptr); int wifi_get_mac_addr(unsigned char *buf); void *wifi_get_country_code(char *ccode); #else -int wifi_set_carddetect(int on) { return -1; } int wifi_set_power(int on, unsigned long msec) { return -1; } int wifi_get_irq_number(unsigned long *irq_flags_ptr) { return -1; } int wifi_get_mac_addr(unsigned char *buf) { return -1; } diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 57f38ee40fa8..c4b55399cc64 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -100,174 +100,8 @@ extern bool ap_cfg_running; #include #include #endif -#if defined(CONFIG_WIFI_CONTROL_FUNC) -#include - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) -#include -#else -#include -#endif - -struct semaphore wifi_control_sem; - -static struct wifi_platform_data *wifi_control_data = NULL; -static struct resource *wifi_irqres = NULL; - -int wifi_get_irq_number(unsigned long *irq_flags_ptr) -{ - if (wifi_irqres) { - *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK; - return (int)wifi_irqres->start; - } -#ifdef CUSTOM_OOB_GPIO_NUM - return CUSTOM_OOB_GPIO_NUM; -#else - return -1; -#endif -} - -int wifi_set_carddetect(int on) -{ - DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); - if (wifi_control_data && wifi_control_data->set_carddetect) { - wifi_control_data->set_carddetect(on); - } - return 0; -} - -int wifi_set_power(int on, unsigned long msec) -{ - DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); - if (wifi_control_data && wifi_control_data->set_power) { - wifi_control_data->set_power(on); - } - if (msec) - mdelay(msec); - return 0; -} - -int wifi_set_reset(int on, unsigned long msec) -{ - DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); - if (wifi_control_data && wifi_control_data->set_reset) { - wifi_control_data->set_reset(on); - } - if (msec) - mdelay(msec); - return 0; -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) -int wifi_get_mac_addr(unsigned char *buf) -{ - DHD_ERROR(("%s\n", __FUNCTION__)); - if (!buf) - return -EINVAL; - if (wifi_control_data && wifi_control_data->get_mac_addr) { - return wifi_control_data->get_mac_addr(buf); - } - return -EOPNOTSUPP; -} -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) -void *wifi_get_country_code(char *ccode) -{ - DHD_TRACE(("%s\n", __FUNCTION__)); - if (!ccode) - return NULL; - if (wifi_control_data && wifi_control_data->get_country_code) { - return wifi_control_data->get_country_code(ccode); - } - return NULL; -} -#endif - -static int wifi_probe(struct platform_device *pdev) -{ - struct wifi_platform_data *wifi_ctrl = - (struct wifi_platform_data *)(pdev->dev.platform_data); - - DHD_ERROR(("## %s\n", __FUNCTION__)); - wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); - if (wifi_irqres == NULL) - wifi_irqres = platform_get_resource_byname(pdev, - IORESOURCE_IRQ, "bcm4329_wlan_irq"); - wifi_control_data = wifi_ctrl; - - wifi_set_power(1, 0); /* Power On */ - wifi_set_carddetect(1); /* CardDetect (0->1) */ - - up(&wifi_control_sem); - return 0; -} - -static int wifi_remove(struct platform_device *pdev) -{ - struct wifi_platform_data *wifi_ctrl = - (struct wifi_platform_data *)(pdev->dev.platform_data); - - DHD_ERROR(("## %s\n", __FUNCTION__)); - wifi_control_data = wifi_ctrl; - - wifi_set_power(0, 0); /* Power Off */ - wifi_set_carddetect(0); /* CardDetect (1->0) */ - - up(&wifi_control_sem); - return 0; -} -static int wifi_suspend(struct platform_device *pdev, pm_message_t state) -{ - DHD_TRACE(("##> %s\n", __FUNCTION__)); -#if defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_set(0); -#endif /* (OOB_INTR_ONLY) */ - return 0; -} -static int wifi_resume(struct platform_device *pdev) -{ - DHD_TRACE(("##> %s\n", __FUNCTION__)); -#if defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_set(1); -#endif /* (OOB_INTR_ONLY) */ - return 0; -} -static struct platform_driver wifi_device = { - .probe = wifi_probe, - .remove = wifi_remove, - .suspend = wifi_suspend, - .resume = wifi_resume, - .driver = { - .name = "bcmdhd_wlan", - } -}; -static struct platform_driver wifi_device_legacy = { - .probe = wifi_probe, - .remove = wifi_remove, - .suspend = wifi_suspend, - .resume = wifi_resume, - .driver = { - .name = "bcm4329_wlan", - } -}; - -int wifi_add_dev(void) -{ - DHD_TRACE(("## Calling platform_driver_register\n")); - platform_driver_register(&wifi_device); - platform_driver_register(&wifi_device_legacy); - return 0; -} - -void wifi_del_dev(void) -{ - DHD_TRACE(("## Unregister platform_driver_register\n")); - platform_driver_unregister(&wifi_device); - platform_driver_unregister(&wifi_device_legacy); -} -#endif +#include #ifdef ARP_OFFLOAD_SUPPORT static int dhd_device_event(struct notifier_block *this, @@ -410,7 +244,10 @@ typedef struct dhd_info { #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - struct mutex wl_start_lock; /* mutex when START called to prevent any other Linux calls */ + /* net_device interface lock, prevent race conditions among net_dev interface + * calls and wifi_on or wifi_off + */ + struct mutex dhd_net_if_mutex; #endif spinlock_t wakelock_spinlock; int wakelock_counter; @@ -439,7 +276,6 @@ char nvram_path[MOD_PARAM_PATHLEN]; extern int wl_control_wl_start(struct net_device *dev); extern int net_os_send_hang_message(struct net_device *dev); -extern int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) struct semaphore dhd_registration_sem; #define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ @@ -591,6 +427,8 @@ static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled in " SRCBASE " on " __DATE__ " at " __TIME__ #endif ; +static void dhd_net_if_lock_local(dhd_info_t *dhd); +static void dhd_net_if_unlock_local(dhd_info_t *dhd); #ifdef WLMEDIA_HTSF void htsf_update(dhd_info_t *dhd, void *data); @@ -1208,7 +1046,7 @@ _dhd_sysioc_thread(void *data) break; } - dhd_os_start_lock(&dhd->pub); + dhd_net_if_lock_local(dhd); DHD_OS_WAKE_LOCK(&dhd->pub); for (i = 0; i < DHD_MAX_IFS; i++) { @@ -1254,7 +1092,7 @@ _dhd_sysioc_thread(void *data) } DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_os_start_unlock(&dhd->pub); + dhd_net_if_unlock_local(dhd); } DHD_TRACE(("%s: stopped\n", __FUNCTION__)); complete_and_exit(&tsk->completed, 0); @@ -2317,14 +2155,18 @@ done: static int dhd_stop(struct net_device *net) { + int ifidx; dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); DHD_TRACE(("%s: Enter\n", __FUNCTION__)); if (dhd->pub.up == 0) { return 0; } + ifidx = dhd_net2idx(dhd, net); + #ifdef WL_CFG80211 - wl_cfg80211_down(); + if (ifidx == 0) + wl_cfg80211_down(); #endif #ifdef PROP_TXSTATUS @@ -2337,6 +2179,11 @@ dhd_stop(struct net_device *net) /* Stop the protocol module */ dhd_prot_stop(&dhd->pub); +#if defined(WL_CFG80211) + if (ifidx == 0) + wl_android_wifi_off(net); +#endif + OLD_MOD_DEC_USE_COUNT; return 0; } @@ -2353,44 +2200,60 @@ dhd_open(struct net_device *net) int32 ret = 0; #if !defined(WL_CFG80211) - /* Force start if ifconfig_up gets called before START command */ + /** Force start if ifconfig_up gets called before START command + * We keep WEXT's wl_control_wl_start to provide backward compatibility + * This should be removed in the future + */ wl_control_wl_start(net); #endif ifidx = dhd_net2idx(dhd, net); DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); - if ((dhd->iflist[ifidx]) && (dhd->iflist[ifidx]->state == WLC_E_IF_DEL)) { + if (!dhd->iflist[ifidx] || dhd->iflist[ifidx]->state == WLC_E_IF_DEL) { DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__)); return -1; } + if (ifidx == 0) { + atomic_set(&dhd->pend_8021x_cnt, 0); +#if defined(WL_CFG80211) + wl_android_wifi_on(net); +#endif - if (ifidx == 0) { /* do it only for primary eth0 */ - + if (dhd->pub.busstate != DHD_BUS_DATA) { + int ret; - atomic_set(&dhd->pend_8021x_cnt, 0); + /* try to bring up bus */ + if ((ret = dhd_bus_start(&dhd->pub)) != 0) { + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + return -1; + } + } - memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); + /* dhd_prot_init has been called in dhd_bus_start or wl_android_wifi_on */ + memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); #ifdef TOE - /* Get current TOE mode from dongle */ - if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) - dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM; - else - dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; -#endif + /* Get current TOE mode from dongle */ + if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) + dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM; + else + dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; +#endif /* TOE */ + +#if defined(WL_CFG80211) + if (unlikely(wl_cfg80211_up())) { + DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__)); + return -1; + } +#endif /* WL_CFG80211 */ } + /* Allow transmit calls */ netif_start_queue(net); dhd->pub.up = 1; -#ifdef WL_CFG80211 - if (unlikely(wl_cfg80211_up())) { - DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__)); - return -1; - } -#endif /* WL_CFG80211 */ #ifdef BCMDBGFS dhd_dbg_init(&dhd->pub); @@ -2578,7 +2441,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_init(&dhd->wl_start_lock); + mutex_init(&dhd->dhd_net_if_mutex); #endif dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; @@ -3069,10 +2932,6 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) DHD_ERROR(("couldn't register the net device, err %d\n", err)); goto fail; } -#if defined(WL_CFG80211) - if (ifidx == 0) - wl_cfg80211_attach_post(net); -#endif printf("%s: Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", net->name, dhd->pub.mac.octet[0], dhd->pub.mac.octet[1], dhd->pub.mac.octet[2], @@ -3109,11 +2968,17 @@ dhd_bus_detach(dhd_pub_t *dhdp) if (dhdp) { dhd = (dhd_info_t *)dhdp->info; if (dhd) { - /* Stop the protocol module */ - dhd_prot_stop(&dhd->pub); - /* Stop the bus module */ - dhd_bus_stop(dhd->pub.bus, TRUE); + /** In case of Android cfg80211 driver, the bus is down in dhd_stop, + * calling stop again will cuase SD read/write errors. + */ + if (dhd->pub.busstate != DHD_BUS_DOWN) { + /* Stop the protocol module */ + dhd_prot_stop(&dhd->pub); + + /* Stop the bus module */ + dhd_bus_stop(dhd->pub.bus, TRUE); + } #if defined(OOB_INTR_ONLY) bcmsdh_unregister_oob_intr(); @@ -3173,9 +3038,9 @@ void dhd_detach(dhd_pub_t *dhdp) for (i = 1; i < DHD_MAX_IFS; i++) if (dhd->iflist[i]) { - dhd->iflist[i]->state = WLC_E_IF_DEL; - dhd->iflist[i]->idx = i; - dhd_op_if(dhd->iflist[i]); + dhd->iflist[i]->state = WLC_E_IF_DEL; + dhd->iflist[i]->idx = i; + dhd_op_if(dhd->iflist[i]); } /* delete primary interface 0 */ @@ -3188,7 +3053,6 @@ void dhd_detach(dhd_pub_t *dhdp) if (ifp->net->netdev_ops == &dhd_ops_pri) #endif { - dhd_stop(ifp->net); unregister_netdev(ifp->net); MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); @@ -3218,6 +3082,7 @@ void dhd_detach(dhd_pub_t *dhdp) if (dhdp->prot) dhd_prot_detach(dhdp); } + #ifdef WL_CFG80211 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) wl_cfg80211_detach(); @@ -3256,9 +3121,12 @@ dhd_module_cleanup(void) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); dhd_bus_unregister(); + #if defined(CONFIG_WIFI_CONTROL_FUNC) - wifi_del_dev(); -#endif + wl_android_wifictrl_func_del(); +#endif /* CONFIG_WIFI_CONTROL_FUNC */ + wl_android_exit(); + /* Call customer gpio to turn off power with WL_REG_ON signal */ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); } @@ -3267,10 +3135,12 @@ dhd_module_cleanup(void) static int __init dhd_module_init(void) { - int error; + int error = 0; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + wl_android_init(); + #ifdef DHDTHREAD /* Sanity check on the module parameters */ do { @@ -3291,21 +3161,8 @@ dhd_module_init(void) dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); #if defined(CONFIG_WIFI_CONTROL_FUNC) - sema_init(&wifi_control_sem, 0); - - /* Added fail_0, fail_1 to do the right clean-up for failure case */ - error = wifi_add_dev(); - if (error) { - DHD_ERROR(("%s: platform_driver_register failed\n", __FUNCTION__)); - goto fail_0; - } - - /* Waiting callback after platform_driver_register is done or exit with error */ - if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) { - error = -EINVAL; - DHD_ERROR(("%s: platform_driver_register timeout\n", __FUNCTION__)); + if (wl_android_wifictrl_func_add() < 0) goto fail_1; - } #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) @@ -3341,8 +3198,7 @@ fail_2: #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ fail_1: #if defined(CONFIG_WIFI_CONTROL_FUNC) - wifi_del_dev(); -fail_0: + wl_android_wifictrl_func_del(); #endif /* Call customer gpio to turn off power with WL_REG_ON signal */ @@ -3598,29 +3454,17 @@ dhd_os_sdtxunlock(dhd_pub_t *pub) dhd_os_sdunlock(pub); } -#ifdef DHD_USE_STATIC_BUF -void * dhd_os_prealloc(int section, unsigned long size) -{ -#if defined(CONFIG_WIFI_CONTROL_FUNC) - void *alloc_ptr = NULL; - if (wifi_control_data && wifi_control_data->mem_prealloc) - { - alloc_ptr = wifi_control_data->mem_prealloc(section, size); - if (alloc_ptr) +#if defined(DHD_USE_STATIC_BUF) +uint8* dhd_os_prealloc(void *osh, int section, uint size) { - DHD_INFO(("success alloc section %d\n", section)); - bzero(alloc_ptr, size); - return alloc_ptr; - } + return (uint8*)wl_android_prealloc(section, size); } - DHD_ERROR(("can't alloc section %d\n", section)); - return 0; -#else -return MALLOC(0, size); -#endif +void dhd_os_prefree(void *osh, void *addr, uint size) +{ } -#endif /* DHD_USE_STATIC_BUF */ +#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ + #if defined(CONFIG_WIRELESS_EXT) struct iw_statistics * dhd_get_wireless_stats(struct net_device *dev) @@ -3826,7 +3670,6 @@ dhd_dev_reset(struct net_device *dev, uint8 flag) DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); return ret; } - DHD_ERROR(("%s: WLAN %s DONE\n", __FUNCTION__, flag ? "OFF" : "ON")); return ret; } @@ -3961,23 +3804,31 @@ void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) } -void dhd_os_start_lock(dhd_pub_t *pub) +void dhd_net_if_lock(struct net_device *dev) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - dhd_info_t *dhd = (dhd_info_t *)(pub->info); + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + dhd_net_if_lock_local(dhd); +} + +void dhd_net_if_unlock(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + dhd_net_if_unlock_local(dhd); +} +static void dhd_net_if_lock_local(dhd_info_t *dhd) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) if (dhd) - mutex_lock(&dhd->wl_start_lock); + mutex_lock(&dhd->dhd_net_if_mutex); #endif } -void dhd_os_start_unlock(dhd_pub_t *pub) +static void dhd_net_if_unlock_local(dhd_info_t *dhd) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - if (dhd) - mutex_unlock(&dhd->wl_start_lock); + mutex_unlock(&dhd->dhd_net_if_mutex); #endif } diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 30a1cc22b26c..6d7d57ed96c4 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -359,6 +359,9 @@ static const uint retry_limit = 2; /* Force even SD lengths (some host controllers mess up on odd bytes) */ static bool forcealign; +/* Flag to indicate if we should download firmware on driver load */ +uint dhd_download_fw_on_driverload = 1; + #define ALIGNMENT 4 #if defined(OOB_INTR_ONLY) && defined(HW_OOB) @@ -5298,9 +5301,10 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, /* if firmware path present try to download and bring up bus */ - if ((ret = dhd_bus_start(bus->dhd)) != 0) { - DHD_ERROR(("%s: failed\n", __FUNCTION__)); - goto fail; + if (dhd_download_fw_on_driverload && (ret = dhd_bus_start(bus->dhd)) != 0) { + DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__)); + if (ret == BCME_NOTUP) + goto fail; } /* Ok, have the per-port tell the stack we're open for business */ if (dhd_net_attach(bus->dhd, 0) != 0) { @@ -5484,40 +5488,23 @@ dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) { DHD_TRACE(("%s: Enter\n", __FUNCTION__)); -#ifndef DHD_USE_STATIC_BUF if (bus->dhd->maxctl) { bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN; - if (!(bus->rxbuf = MALLOC(osh, bus->rxblen))) { + if (!(bus->rxbuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_RXBUF, bus->rxblen))) { DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n", __FUNCTION__, bus->rxblen)); goto fail; } } - /* Allocate buffer to receive glomed packet */ - if (!(bus->databuf = MALLOC(osh, MAX_DATA_BUF))) { + if (!(bus->databuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) { DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n", __FUNCTION__, MAX_DATA_BUF)); /* release rxbuf which was already located as above */ - if (!bus->rxblen) MFREE(osh, bus->rxbuf, bus->rxblen); - goto fail; - } -#else - if (bus->dhd->maxctl) { - bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN; - if (!(bus->rxbuf = dhd_os_prealloc(DHD_PREALLOC_RXBUF, bus->rxblen))) { - DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n", - __FUNCTION__, bus->rxblen)); - goto fail; - } - } - /* Allocate buffer to receive glomed packet */ - if (!(bus->databuf = dhd_os_prealloc(DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) { - DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n", - __FUNCTION__, MAX_DATA_BUF)); + if (!bus->rxblen) + DHD_OS_PREFREE(osh, bus->rxbuf, bus->rxblen); goto fail; } -#endif /* DHD_USE_STATIC_BUF */ /* Align the buffer */ if ((uintptr)bus->databuf % DHD_SDALIGN) diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index 9ef7703ef603..32ada84248a4 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -33,17 +33,17 @@ #define EPI_RC_NUMBER 125 -#define EPI_INCREMENTAL_NUMBER 27 +#define EPI_INCREMENTAL_NUMBER 32 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 125, 27 +#define EPI_VERSION 5, 90, 125, 32 -#define EPI_VERSION_NUM 0x055a7d1b +#define EPI_VERSION_NUM 0x055a7d20 #define EPI_VERSION_DEV 5.90.125 -#define EPI_VERSION_STR "5.90.125.27" +#define EPI_VERSION_STR "5.90.125.32" #endif diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c index eda5ddffd328..4c4a76d60cfe 100644 --- a/drivers/net/wireless/bcmdhd/linux_osl.c +++ b/drivers/net/wireless/bcmdhd/linux_osl.c @@ -161,7 +161,8 @@ osl_error(int bcmerror) return linuxbcmerrormap[-bcmerror]; } -void * dhd_os_prealloc(int section, unsigned long size); +extern uint8* dhd_os_prealloc(void *osh, int section, int size); + osl_t * osl_attach(void *pdev, uint bustype, bool pkttag) { @@ -201,9 +202,9 @@ osl_attach(void *pdev, uint bustype, bool pkttag) break; } -#ifdef DHD_USE_STATIC_BUF +#if defined(DHD_USE_STATIC_BUF) if (!bcm_static_buf) { - if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(3, STATIC_BUF_SIZE+ + if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(osh, 3, STATIC_BUF_SIZE+ STATIC_BUF_TOTAL_LEN))) { printk("can not alloc static buf!\n"); } @@ -223,7 +224,7 @@ osl_attach(void *pdev, uint bustype, bool pkttag) int i; void *skb_buff_ptr = 0; bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); - skb_buff_ptr = dhd_os_prealloc(4, 0); + skb_buff_ptr = dhd_os_prealloc(osh, 4, 0); bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)*16); for (i = 0; i < MAX_STATIC_PKT_NUM*2; i++) diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 6dfdd6bdc59e..11abb958d7e3 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -1,5 +1,5 @@ /* - * Linux cfg80211 driver - Android private commands + * Linux cfg80211 driver - Android related functions * * Copyright (C) 1999-2011, Broadcom Corporation * @@ -26,11 +26,25 @@ #include #include -#include + +#include #include +#include #include +#include #include +#include +#include +#include +#if defined(CONFIG_WIFI_CONTROL_FUNC) +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) +#include +#else +#include +#endif +#endif /* CONFIG_WIFI_CONTROL_FUNC */ /* * Android private command strings, PLEASE define new private commands here @@ -56,14 +70,145 @@ typedef struct android_wifi_priv_cmd { int total_len; } android_wifi_priv_cmd; +/** + * Extern funciton declarations (TODO: move them to dhd_linux.h) + */ +void dhd_customer_gpio_wlan_ctrl(int onoff); +uint dhd_dev_reset(struct net_device *dev, uint8 flag); +void dhd_dev_init_ioctl(struct net_device *dev); +int net_os_set_dtim_skip(struct net_device *dev, int val); int net_os_set_suspend_disable(struct net_device *dev, int val); int net_os_set_suspend(struct net_device *dev, int val); -static int g_wifi_on = 0; +/** + * Local (static) functions and variables + */ + +/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first + * time (only) in dhd_open, subsequential wifi on will be handled by + * wl_android_wifi_on + */ +static int g_wifi_on = 1; + static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len); static int wl_android_get_rssi(struct net_device *net, char *command, int total_len); static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len); +/** + * Local (static) function definitions + */ +static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len) +{ + int link_speed; + int bytes_written; + int error; + + error = wldev_get_link_speed(net, &link_speed); + if (error) + return -1; + + /* Convert Kbps to Android Mbps */ + link_speed = link_speed / 1000; + bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed); + DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command)); + return bytes_written; +} + +static int wl_android_get_rssi(struct net_device *net, char *command, int total_len) +{ + wlc_ssid_t ssid; + int rssi; + int bytes_written; + int error; + + error = wldev_get_rssi(net, &rssi); + if (error) + return -1; + + error = wldev_get_ssid(net, &ssid); + if (error) + return -1; + memcpy(command, ssid.SSID, ssid.SSID_len); + bytes_written = ssid.SSID_len; + bytes_written += snprintf(&command[bytes_written], total_len, " rssi %d", rssi); + DHD_INFO(("%s: command result is %s \n", __FUNCTION__, command)); + return bytes_written; +} + +static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len) +{ + int suspend_flag; + int ret_now; + int ret = 0; + + suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0'; + + if (suspend_flag != 0) + suspend_flag = 1; + ret_now = net_os_set_suspend_disable(dev, suspend_flag); + + if (ret_now != suspend_flag) { + if (!(ret = net_os_set_suspend(dev, ret_now))) + DHD_INFO(("%s: Suspend Flag %d -> %d\n", + __FUNCTION__, ret_now, suspend_flag)); + else + DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); + } + return ret; +} + +/** + * Global function definitions (declared in wl_android.h) + */ + +int wl_android_wifi_on(struct net_device *dev) +{ + int ret = 0; + + printk("%s in\n", __FUNCTION__); + if (!dev) { + DHD_ERROR(("%s: dev is null\n", __FUNCTION__)); + return -EINVAL; + } + + dhd_net_if_lock(dev); + if (!g_wifi_on) { + dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); + sdioh_start(NULL, 0); + ret = dhd_dev_reset(dev, FALSE); + sdioh_start(NULL, 1); + dhd_dev_init_ioctl(dev); + g_wifi_on = 1; + } + dhd_net_if_unlock(dev); + + return ret; +} + +int wl_android_wifi_off(struct net_device *dev) +{ + int ret = 0; + + printk("%s in\n", __FUNCTION__); + if (!dev) { + DHD_TRACE(("%s: dev is null\n", __FUNCTION__)); + return -EINVAL; + } + + dhd_net_if_lock(dev); + if (g_wifi_on) { + dhd_dev_reset(dev, 1); + dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); + sdioh_stop(NULL); + /* clean up dtim_skip setting */ + net_os_set_dtim_skip(dev, TRUE); + g_wifi_on = 0; + } + dhd_net_if_unlock(dev); + + return ret; +} + int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) { int ret = 0; @@ -91,19 +236,14 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) goto exit; } - DHD_TRACE(("%s: Android private command \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name)); + DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name)); if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) { - /* TBD: START */ DHD_INFO(("%s, Received regular START command\n", __FUNCTION__)); g_wifi_on = 1; } if (!g_wifi_on) { - /* - printk("%s START command has to be called first\n", __FUNCTION__); - ret = -EFAULT; - goto exit; - */ + } if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) { /* TBD: STOP */ @@ -137,8 +277,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) } else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) { bytes_written = wl_android_set_suspendopt(net, command, priv_cmd->total_len); - } - else { + } else { DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); snprintf(command, 3, "OK"); bytes_written = strlen("OK") + 1; @@ -162,63 +301,225 @@ exit: return ret; } +int wl_android_init(void) +{ + int ret = 0; -static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len) + dhd_msg_level = DHD_ERROR_VAL; + dhd_download_fw_on_driverload = 0; + return ret; +} + +int wl_android_exit(void) { - int link_speed; - int bytes_written; - int error; + int ret = 0; - error = wldev_get_link_speed(net, &link_speed); - if (error) - return -1; + return ret; +} - /* Convert Kbps to Android Mbps */ - link_speed = link_speed / 1000; - bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed); - DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command)); - return bytes_written; + +/** + * Functions for Android WiFi card detection + */ +#if defined(CONFIG_WIFI_CONTROL_FUNC) + +static int g_wifidev_registered = 0; +static struct semaphore wifi_control_sem; +static struct wifi_platform_data *wifi_control_data = NULL; +static struct resource *wifi_irqres = NULL; + +static int wifi_add_dev(void); +static void wifi_del_dev(void); + +int wl_android_wifictrl_func_add(void) +{ + int ret = 0; + sema_init(&wifi_control_sem, 0); + + ret = wifi_add_dev(); + if (ret) { + DHD_ERROR(("%s: platform_driver_register failed\n", __FUNCTION__)); + return ret; + } + g_wifidev_registered = 1; + + /* Waiting callback after platform_driver_register is done or exit with error */ + if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) { + ret = -EINVAL; + DHD_ERROR(("%s: platform_driver_register timeout\n", __FUNCTION__)); + } + + return ret; } -static int wl_android_get_rssi(struct net_device *net, char *command, int total_len) +void wl_android_wifictrl_func_del(void) { - wlc_ssid_t ssid; - int rssi; - int bytes_written; - int error; + if (g_wifidev_registered) + { + wifi_del_dev(); + g_wifidev_registered = 0; + } +} - error = wldev_get_rssi(net, &rssi); - if (error) - return -1; +void* wl_android_prealloc(int section, unsigned long size) +{ + void *alloc_ptr = NULL; + if (wifi_control_data && wifi_control_data->mem_prealloc) { + alloc_ptr = wifi_control_data->mem_prealloc(section, size); + if (alloc_ptr) { + DHD_INFO(("success alloc section %d\n", section)); + bzero(alloc_ptr, size); + return alloc_ptr; + } + } - error = wldev_get_ssid(net, &ssid); - if (error) - return -1; - memcpy(command, ssid.SSID, ssid.SSID_len); - bytes_written = ssid.SSID_len; - bytes_written += snprintf(&command[bytes_written], total_len, " rssi %d", rssi); - DHD_INFO(("%s: command result is %s \n", __FUNCTION__, command)); - return bytes_written; + DHD_ERROR(("can't alloc section %d\n", section)); + return 0; } -static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len) +int wifi_get_irq_number(unsigned long *irq_flags_ptr) { - int suspend_flag; - int ret_now; - int ret = 0; + if (wifi_irqres) { + *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK; + return (int)wifi_irqres->start; + } +#ifdef CUSTOM_OOB_GPIO_NUM + return CUSTOM_OOB_GPIO_NUM; +#else + return -1; +#endif +} - suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0'; +int wifi_set_power(int on, unsigned long msec) +{ + DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); + if (wifi_control_data && wifi_control_data->set_power) { + wifi_control_data->set_power(on); + } + if (msec) + mdelay(msec); + return 0; +} - if (suspend_flag != 0) - suspend_flag = 1; - ret_now = net_os_set_suspend_disable(dev, suspend_flag); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) +int wifi_get_mac_addr(unsigned char *buf) +{ + DHD_ERROR(("%s\n", __FUNCTION__)); + if (!buf) + return -EINVAL; + if (wifi_control_data && wifi_control_data->get_mac_addr) { + return wifi_control_data->get_mac_addr(buf); + } + return -EOPNOTSUPP; +} +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */ - if (ret_now != suspend_flag) { - if (!(ret = net_os_set_suspend(dev, ret_now))) - DHD_INFO(("%s: Suspend Flag %d -> %d\n", - __FUNCTION__, ret_now, suspend_flag)); - else - DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) +void *wifi_get_country_code(char *ccode) +{ + DHD_TRACE(("%s\n", __FUNCTION__)); + if (!ccode) + return NULL; + if (wifi_control_data && wifi_control_data->get_country_code) { + return wifi_control_data->get_country_code(ccode); } - return ret; + return NULL; +} +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ + +static int wifi_set_carddetect(int on) +{ + DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); + if (wifi_control_data && wifi_control_data->set_carddetect) { + wifi_control_data->set_carddetect(on); + } + return 0; +} + +static int wifi_probe(struct platform_device *pdev) +{ + struct wifi_platform_data *wifi_ctrl = + (struct wifi_platform_data *)(pdev->dev.platform_data); + + DHD_ERROR(("## %s\n", __FUNCTION__)); + wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); + if (wifi_irqres == NULL) + wifi_irqres = platform_get_resource_byname(pdev, + IORESOURCE_IRQ, "bcm4329_wlan_irq"); + wifi_control_data = wifi_ctrl; + + wifi_set_power(1, 0); /* Power On */ + wifi_set_carddetect(1); /* CardDetect (0->1) */ + + up(&wifi_control_sem); + return 0; +} + +static int wifi_remove(struct platform_device *pdev) +{ + struct wifi_platform_data *wifi_ctrl = + (struct wifi_platform_data *)(pdev->dev.platform_data); + + DHD_ERROR(("## %s\n", __FUNCTION__)); + wifi_control_data = wifi_ctrl; + + wifi_set_power(0, 0); /* Power Off */ + wifi_set_carddetect(0); /* CardDetect (1->0) */ + + up(&wifi_control_sem); + return 0; +} + +static int wifi_suspend(struct platform_device *pdev, pm_message_t state) +{ + DHD_TRACE(("##> %s\n", __FUNCTION__)); +#if defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_set(0); +#endif /* (OOB_INTR_ONLY) */ + return 0; +} + +static int wifi_resume(struct platform_device *pdev) +{ + DHD_TRACE(("##> %s\n", __FUNCTION__)); +#if defined(OOB_INTR_ONLY) + bcmsdh_oob_intr_set(1); +#endif /* (OOB_INTR_ONLY) */ + return 0; +} + +static struct platform_driver wifi_device = { + .probe = wifi_probe, + .remove = wifi_remove, + .suspend = wifi_suspend, + .resume = wifi_resume, + .driver = { + .name = "bcmdhd_wlan", + } +}; + +static struct platform_driver wifi_device_legacy = { + .probe = wifi_probe, + .remove = wifi_remove, + .suspend = wifi_suspend, + .resume = wifi_resume, + .driver = { + .name = "bcm4329_wlan", + } +}; + +static int wifi_add_dev(void) +{ + DHD_TRACE(("## Calling platform_driver_register\n")); + platform_driver_register(&wifi_device); + platform_driver_register(&wifi_device_legacy); + return 0; +} + +static void wifi_del_dev(void) +{ + DHD_TRACE(("## Unregister platform_driver_register\n")); + platform_driver_unregister(&wifi_device); + platform_driver_unregister(&wifi_device_legacy); } +#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ diff --git a/drivers/net/wireless/bcmdhd/wl_android.h b/drivers/net/wireless/bcmdhd/wl_android.h new file mode 100644 index 000000000000..3c75bfb820d5 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/wl_android.h @@ -0,0 +1,39 @@ +/* + * Linux cfg80211 driver - Android related functions + * + * $Copyright Open Broadcom Corporation$ + * + * $Id: wl_android.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 linm Exp $ + */ + +#include +#include +#include + +/** + * Android platform dependent functions, feel free to add Android specific functions here + * (save the macros in dhd). Please do NOT declare functions that are NOT exposed to dhd + * or cfg, define them as static in wl_android.c + */ + +/** + * wl_android_init will be called from module init function (dhd_module_init now), similarly + * wl_android_exit will be called from module exit function (dhd_module_cleanup now) + */ +int wl_android_init(void); +int wl_android_exit(void); + +int wl_android_wifi_on(struct net_device *dev); +int wl_android_wifi_off(struct net_device *dev); +int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd); + +#if defined(CONFIG_WIFI_CONTROL_FUNC) +int wl_android_wifictrl_func_add(void); +void wl_android_wifictrl_func_del(void); +void* wl_android_prealloc(int section, unsigned long size); + +int wifi_get_irq_number(unsigned long *irq_flags_ptr); +int wifi_set_power(int on, unsigned long msec); +int wifi_get_mac_addr(unsigned char *buf); +void *wifi_get_country_code(char *ccode); +#endif /* CONFIG_WIFI_CONTROL_FUNC */ \ No newline at end of file diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 7181f2cb50b2..2ef334746dd1 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -353,8 +353,6 @@ static s32 wl_pattern_atoh(s8 *src, s8 *dst); static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode); static s32 wl_update_wiphybands(struct wl_priv *wl); #endif /* !EMBEDDED_PLATFORM */ -static __used void wl_dongle_poweron(struct wl_priv *wl); -static __used void wl_dongle_poweroff(struct wl_priv *wl); static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock); /* @@ -893,7 +891,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, } else { wl_clr_p2p_status(wl, IF_ADD); - WL_ERR((" virtual interface(%s) is not created \n", wl->p2p.vir_ifname)); + WL_ERR((" virtual interface(%s) is not created timeout=%d\n", + wl->p2p.vir_ifname, timeout)); memset(wl->p2p.vir_ifname, '\0', IFNAMSIZ); wl->p2p.vif_created = FALSE; } @@ -1423,7 +1422,7 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, CHECK_SYS_UP(); err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); if (unlikely(err)) { - WL_DBG(("scan error (%d)\n", err)); + WL_ERR(("scan error (%d)\n", err)); return err; } @@ -5487,8 +5486,10 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status); clear_bit(WL_STATUS_CONNECTED, &wl->status); + wl->dongle_up = false; + wl_flush_eq(wl); + wl_link_down(wl); wl_cfgp2p_down(wl); - wl_debugfs_remove_netdev(wl); return err; @@ -5502,6 +5503,7 @@ s32 wl_cfg80211_up(void) WL_TRACE(("In\n")); wl = WL_PRIV_GET(); mutex_lock(&wl->usr_sync); + wl_cfg80211_attach_post(wl_to_prmry_ndev(wl)); err = __wl_cfg80211_up(wl); mutex_unlock(&wl->usr_sync); @@ -5852,52 +5854,12 @@ static void wl_debugfs_remove_netdev(struct wl_priv *wl) WL_DBG(("Enter \n")); } -static __used void wl_dongle_poweron(struct wl_priv *wl) -{ - - WL_DBG(("Enter \n")); - dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); - -#if defined(BCMLXSDMMC) - sdioh_start(NULL, 0); -#endif -#if defined(BCMLXSDMMC) - sdioh_start(NULL, 1); -#endif - wl_cfg80211_resume(wl_to_wiphy(wl)); -} - -static __used void wl_dongle_poweroff(struct wl_priv *wl) -{ - - - WL_DBG(("Enter \n")); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) - wl_cfg80211_suspend(wl_to_wiphy(wl), NULL); -#else - wl_cfg80211_suspend(wl_to_wiphy(wl)); -#endif - -#if defined(BCMLXSDMMC) - sdioh_stop(NULL); -#endif - /* clean up dtim_skip setting */ - dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); -} - static const struct rfkill_ops wl_rfkill_ops = { .set_block = wl_rfkill_set }; static int wl_rfkill_set(void *data, bool blocked) { - struct wl_priv *wl = (struct wl_priv *)data; - - WL_DBG(("Enter \n")); - WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked")); - - wl->rf_blocked = blocked; - return 0; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index e2780dfde0ef..0a5a8a8f1097 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -637,7 +637,7 @@ wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssi } /* Add if there is any extra IE */ if (p2p_ie && p2p_ie_len) { - CFGP2P_ERR(("Request has extra IE")); + CFGP2P_INFO(("Request has extra IE")); if (p2p_ie_len > mgmt_ie_buf_len) { CFGP2P_ERR(("extra IE size too big\n")); ret = -ENOMEM; diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index a438cf6f1e7a..1f811a90ae56 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -1648,7 +1648,7 @@ wl_control_wl_start(struct net_device *dev) return -1; } - dhd_os_start_lock(iw->pub); + dhd_net_if_lock(dev); if (g_onoff == G_WLAN_SET_OFF) { dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); @@ -1669,7 +1669,7 @@ wl_control_wl_start(struct net_device *dev) } WL_TRACE(("Exited %s\n", __FUNCTION__)); - dhd_os_start_unlock(iw->pub); + dhd_net_if_unlock(dev); return ret; } @@ -1697,7 +1697,7 @@ wl_iw_control_wl_off( return -1; } - dhd_os_start_lock(iw->pub); + dhd_net_if_lock(dev); #ifdef SOFTAP ap_cfg_running = FALSE; @@ -1740,7 +1740,7 @@ wl_iw_control_wl_off( wl_iw_send_priv_event(dev, "STOP"); } - dhd_os_start_unlock(iw->pub); + dhd_net_if_unlock(dev); WL_TRACE(("Exited %s\n", __FUNCTION__)); diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c index 82d305a660bb..a39bdaacb8cf 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.c +++ b/drivers/net/wireless/bcmdhd/wldev_common.c @@ -24,7 +24,10 @@ * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $ */ -#include +#include +#include + +#include #include #include @@ -68,7 +71,7 @@ s32 wldev_ioctl( * taken care of in dhd_ioctl_entry. Internal use only, not exposed to * wl_iw, wl_cfg80211 and wl_cfgp2p */ -s32 wldev_mkiovar( +static s32 wldev_mkiovar( s8 *iovar_name, s8 *param, s32 paramlen, s8 *iovar_buf, u32 buflen) { diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h index 12476af61733..344875b72d8e 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.h +++ b/drivers/net/wireless/bcmdhd/wldev_common.h @@ -26,6 +26,8 @@ #ifndef __WLDEV_COMMON_H__ #define __WLDEV_COMMON_H__ +#include + /** wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or * netdev_ops->ndo_do_ioctl in new kernels) * @dev: the net_device handle @@ -53,12 +55,6 @@ s32 wldev_iovar_setint( s32 wldev_iovar_getint( struct net_device *dev, s8 *iovar, s32 *pval); - -s32 wldev_mkiovar( - s8 *iovar_name, s8 *param, s32 paramlen, - s8 *iovar_buf, u32 buflen); - - /** The following function can be implemented if there is a need for bsscfg * indexed IOVARs */ -- 2.34.1