summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLin Ma <linm@broadcom.com>2011-06-27 18:53:59 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:38:45 -0800
commit2ef3ac71571a6eff99f19bca73ccfa94bdd20810 (patch)
tree2773e999443db330d14507d3414045ea25b0df4d /drivers
parentbddf7ce9361d534ba7e8900c7f302bd27f1cac2d (diff)
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 <hharte@broadcom.com> Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_linux.c9
-rw-r--r--drivers/net/wireless/bcmdhd/dhd.h28
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_cdc.c10
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_common.c39
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_custom_gpio.c2
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.c351
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_sdio.c35
-rw-r--r--drivers/net/wireless/bcmdhd/include/epivers.h8
-rw-r--r--drivers/net/wireless/bcmdhd/linux_osl.c9
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.c411
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.h39
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c52
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.c2
-rw-r--r--drivers/net/wireless/bcmdhd/wl_iw.c8
-rw-r--r--drivers/net/wireless/bcmdhd/wldev_common.c7
-rw-r--r--drivers/net/wireless/bcmdhd/wldev_common.h8
16 files changed, 588 insertions, 430 deletions
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 <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
}
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 <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
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 <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
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 <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)
{
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 <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
*/