Update to 5.90.125.32:
Lin Ma [Tue, 28 Jun 2011 01:53:59 +0000 (18:53 -0700)]
* 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 <hharte@broadcom.com>
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>

16 files changed:
drivers/net/wireless/bcmdhd/bcmsdh_linux.c
drivers/net/wireless/bcmdhd/dhd.h
drivers/net/wireless/bcmdhd/dhd_cdc.c
drivers/net/wireless/bcmdhd/dhd_common.c
drivers/net/wireless/bcmdhd/dhd_custom_gpio.c
drivers/net/wireless/bcmdhd/dhd_linux.c
drivers/net/wireless/bcmdhd/dhd_sdio.c
drivers/net/wireless/bcmdhd/include/epivers.h
drivers/net/wireless/bcmdhd/linux_osl.c
drivers/net/wireless/bcmdhd/wl_android.c
drivers/net/wireless/bcmdhd/wl_android.h [new file with mode: 0644]
drivers/net/wireless/bcmdhd/wl_cfg80211.c
drivers/net/wireless/bcmdhd/wl_cfgp2p.c
drivers/net/wireless/bcmdhd/wl_iw.c
drivers/net/wireless/bcmdhd/wldev_common.c
drivers/net/wireless/bcmdhd/wldev_common.h

index 37bb990..6fa4737 100644 (file)
@@ -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;
        }
index f7a103a..4a7f571 100644 (file)
@@ -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
index 44a431b..91c461f 100644 (file)
@@ -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 */
index 1bfca85..39ded01 100644 (file)
@@ -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 */
 
 
index 9958513..b7d78d1 100644 (file)
@@ -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; }
index 57f38ee..c4b5539 100644 (file)
@@ -100,174 +100,8 @@ extern bool ap_cfg_running;
 #include <wlfc_proto.h>
 #include <dhd_wlfc.h>
 #endif
-#if defined(CONFIG_WIFI_CONTROL_FUNC)
-#include <linux/platform_device.h>
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
-#include <linux/wlan_plat.h>
-#else
-#include <linux/wifi_tiwlan.h>
-#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 <wl_android.h>
 
 #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
 }
 
index 30a1cc2..6d7d57e 100644 (file)
@@ -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)
index 9ef7703..32ada84 100644 (file)
 
 #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 
index eda5ddf..4c4a76d 100644 (file)
@@ -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++)
index 6dfdd6b..11abb95 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Linux cfg80211 driver - Android private commands
+ * Linux cfg80211 driver - Android related functions
  *
  * Copyright (C) 1999-2011, Broadcom Corporation
  *
 
 #include <linux/module.h>
 #include <linux/netdevice.h>
-#include <wlioctl.h>
+
+#include <wl_android.h>
 #include <wldev_common.h>
+#include <wlioctl.h>
 #include <bcmutils.h>
+#include <linux_osl.h>
 #include <dhd_dbg.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <bcmsdbus.h>
 
+#if defined(CONFIG_WIFI_CONTROL_FUNC)
+#include <linux/platform_device.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+#include <linux/wlan_plat.h>
+#else
+#include <linux/wifi_tiwlan.h>
+#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 (file)
index 0000000..3c75bfb
--- /dev/null
@@ -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 <linux/module.h>
+#include <linux/netdevice.h>
+#include <wldev_common.h>
+
+/**
+ * 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
index 7181f2c..2ef3347 100644 (file)
@@ -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;
 }
 
index e2780df..0a5a8a8 100644 (file)
@@ -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;
index a438cf6..1f811a9 100644 (file)
@@ -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__));
 
index 82d305a..a39bdaa 100644 (file)
  * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $
  */
 
-#include <wlioctl.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include <wldev_common.h>
 #include <bcmutils.h>
 #include <dhd_dbg.h>
 
@@ -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)
 {
index 12476af..344875b 100644 (file)
@@ -26,6 +26,8 @@
 #ifndef __WLDEV_COMMON_H__
 #define __WLDEV_COMMON_H__
 
+#include <wlioctl.h>
+
 /** 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
  */