From 1d3e084e948f9ef55f1fbfc49e6ae12ca2ee4510 Mon Sep 17 00:00:00 2001 From: "Howard M. Harte" Date: Wed, 15 Jun 2011 18:52:15 -0700 Subject: [PATCH] net: wireless: bcmdhd: Combined patch from 4.218.248-31 bcmdhd: Allocate skb with GFP_KERNEL flag if possible: fix for older kernels. bcmdhd: Fix race conditions for sysioc_thread * Fix up formatting and #ifdefs. net: wireless: bcmdhd: Fix get_customized_country_code() for older kernels. net: wireless: bcmdhd: Move PNO function prototypes to dhd.h. Add private command support. net: wireless: bcmdhd: Set proper read barrier net: wireless: bcmdhd: Fix memory leak in case of dhd_bus_init() failure net: wireless: bcmdhd: Fix wake_lock symmetry net: wireless: bcmdhd: Ignore error if scan results are empty net: wireless: bcmdhd: Add sdlock to firmware loading net: wireless: bcmdhd: Fix watchdog syncronization during start/stop net: wireless: bcmdhd: Fix Makefile to allow WEXT compilation Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/Makefile | 7 +- drivers/net/wireless/bcmdhd/dhd.h | 18 ++- drivers/net/wireless/bcmdhd/dhd_custom_gpio.c | 10 +- drivers/net/wireless/bcmdhd/dhd_linux.c | 99 +++++++-------- drivers/net/wireless/bcmdhd/dhd_sdio.c | 18 ++- drivers/net/wireless/bcmdhd/include/linuxver.h | 4 - drivers/net/wireless/bcmdhd/linux_osl.c | 4 + drivers/net/wireless/bcmdhd/wl_android.c | 160 +++++++++++++++++++++++++ drivers/net/wireless/bcmdhd/wl_iw.c | 13 +- drivers/net/wireless/bcmdhd/wl_iw.h | 14 +-- drivers/net/wireless/bcmdhd/wldev_common.c | 16 +++ drivers/net/wireless/bcmdhd/wldev_common.h | 14 ++- 12 files changed, 268 insertions(+), 109 deletions(-) create mode 100644 drivers/net/wireless/bcmdhd/wl_android.c diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index b476372..fc5a02f 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -6,13 +6,14 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Werror -Dlinux -DBCMDRIVER \ -DCUSTOMER_HW2 -DCUSTOM_OOB_GPIO_NUM=2 -DOOB_INTR_ONLY -DHW_OOB \ -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DBCMPLATFORM_BUS -DWLP2P \ -DNEW_COMPAT_WIRELESS -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ - -DKEEP_ALIVE -DCSCAN -DGET_CUSTOM_MAC_ENABLE \ + -DKEEP_ALIVE -DCSCAN -DGET_CUSTOM_MAC_ENABLE -DPKT_FILTER_SUPPORT \ + -DEMBEDDED_PLATFORM \ -Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \ dhd_linux_sched.o bcmwifi.o dhd_sdio.o bcmevent.o dhd_bta.o hndpmu.o \ bcmsdh.o dhd_cdc.o bcmsdh_linux.o dhd_common.o linux_osl.o \ - bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o + bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o obj-$(CONFIG_BCMDHD) += bcmdhd.o bcmdhd-objs += $(DHDOFILES) @@ -21,7 +22,7 @@ bcmdhd-objs += wl_iw.o DHDCFLAGS += -DSOFTAP endif ifneq ($(CONFIG_CFG80211),) -bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wldev_common.o +bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o DHDCFLAGS += -DWL_CFG80211 endif EXTRA_CFLAGS = $(DHDCFLAGS) diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index 9033da9..f7a103a 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -268,13 +268,13 @@ inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) #define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub) #define DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(pub) dhd_os_wake_lock_timeout_enable(pub) -extern void dhd_os_start_lock(dhd_pub_t *pub); -extern void dhd_os_start_unlock(dhd_pub_t *pub); - 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); + typedef struct dhd_if_event { uint8 ifidx; uint8 action; @@ -363,6 +363,18 @@ extern int dhd_custom_get_mac_address(unsigned char *buf); extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); +extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); +extern int dhd_pno_clean(dhd_pub_t *dhd); +extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, + ushort scan_fr, int pno_repeat, int pno_freq_expo_max); +extern int dhd_pno_get_status(dhd_pub_t *dhd); +extern int dhd_dev_pno_reset(struct net_device *dev); +extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, + int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max); +extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); +extern int dhd_dev_get_pno_status(struct net_device *dev); +extern int dhd_get_dtim_skip(dhd_pub_t *dhd); + #ifdef DHD_DEBUG extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); #endif /* DHD_DEBUG */ diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c index 76587a1..9958513 100644 --- a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c +++ b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c @@ -41,7 +41,7 @@ extern void bcm_wlan_power_off(int); extern void bcm_wlan_power_on(int); #endif /* CUSTOMER_HW */ -#if defined(CUSTOMER_HW2) +#if defined(CUSTOMER_HW2) #ifdef CONFIG_WIFI_CONTROL_FUNC int wifi_set_carddetect(int on); int wifi_set_power(int on, unsigned long msec); @@ -54,8 +54,8 @@ 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; } void *wifi_get_country_code(char *ccode) { return NULL; } -#endif -#endif +#endif /* CONFIG_WIFI_CONTROL_FUNC */ +#endif /* CUSTOMER_HW2 */ #if defined(OOB_INTR_ONLY) @@ -253,7 +253,7 @@ const struct cntry_locales_custom translate_custom_table[] = { */ void get_customized_country_code(char *country_iso_code, wl_country_t *cspec) { -#ifdef CUSTOMER_HW2 +#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) struct cntry_locales_custom *cloc_ptr; if (!cspec) @@ -290,5 +290,5 @@ void get_customized_country_code(char *country_iso_code, wl_country_t *cspec) cspec->rev = translate_custom_table[0].custom_locale_rev; #endif /* EXMAPLE_TABLE */ return; -#endif +#endif /* defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ } diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 7d78bae..57f38ee 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -90,7 +90,7 @@ static histo_t vi_d1, vi_d2, vi_d3, vi_d4; #endif /* WLMEDIA_HTSF */ #if defined(SOFTAP) -extern bool ap_cfg_running; +extern bool ap_cfg_running; #endif /* enable HOSTIP cache update from the host side when an eth0:N is up */ @@ -171,6 +171,7 @@ int wifi_get_mac_addr(unsigned char *buf) } #endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) void *wifi_get_country_code(char *ccode) { DHD_TRACE(("%s\n", __FUNCTION__)); @@ -181,6 +182,7 @@ void *wifi_get_country_code(char *ccode) } return NULL; } +#endif static int wifi_probe(struct platform_device *pdev) { @@ -437,6 +439,7 @@ 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 */ @@ -459,7 +462,7 @@ module_param(dhd_watchdog_ms, uint, 0); #if defined(DHD_DEBUG) /* Console poll interval */ -uint dhd_console_ms = 250; +uint dhd_console_ms = 0; module_param(dhd_console_ms, uint, 0); #endif /* defined(DHD_DEBUG) */ @@ -1206,6 +1209,7 @@ _dhd_sysioc_thread(void *data) } dhd_os_start_lock(&dhd->pub); + DHD_OS_WAKE_LOCK(&dhd->pub); for (i = 0; i < DHD_MAX_IFS; i++) { if (dhd->iflist[i]) { @@ -1251,7 +1255,6 @@ _dhd_sysioc_thread(void *data) DHD_OS_WAKE_UNLOCK(&dhd->pub); dhd_os_start_unlock(&dhd->pub); - } DHD_TRACE(("%s: stopped\n", __FUNCTION__)); complete_and_exit(&tsk->completed, 0); @@ -1762,11 +1765,10 @@ dhd_watchdog_thread(void *data) break; } + dhd_os_sdlock(&dhd->pub); if (dhd->pub.dongle_reset == FALSE) { DHD_TIMER(("%s:\n", __FUNCTION__)); - DHD_OS_WAKE_LOCK(&dhd->pub); - /* Call the bus module watchdog */ dhd_bus_watchdog(&dhd->pub); @@ -1776,11 +1778,12 @@ dhd_watchdog_thread(void *data) if (dhd->wd_timer_valid) mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); - DHD_OS_WAKE_UNLOCK(&dhd->pub); } + dhd_os_sdunlock(&dhd->pub); + DHD_OS_WAKE_UNLOCK(&dhd->pub); } else { break; - } + } complete_and_exit(&tsk->completed, 0); } @@ -1790,11 +1793,12 @@ static void dhd_watchdog(ulong data) { dhd_info_t *dhd = (dhd_info_t *)data; + DHD_OS_WAKE_LOCK(&dhd->pub); if (dhd->pub.dongle_reset) { + DHD_OS_WAKE_UNLOCK(&dhd->pub); return; } - DHD_OS_WAKE_LOCK(&dhd->pub); #ifdef DHDTHREAD if (dhd->thr_wdt_ctl.thr_pid >= 0) { up(&dhd->thr_wdt_ctl.sema); @@ -1802,6 +1806,7 @@ static void dhd_watchdog(ulong data) } #endif /* DHDTHREAD */ + dhd_os_sdlock(&dhd->pub); /* Call the bus module watchdog */ dhd_bus_watchdog(&dhd->pub); @@ -1811,6 +1816,7 @@ static void dhd_watchdog(ulong data) /* Reschedule the watchdog */ if (dhd->wd_timer_valid) mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + dhd_os_sdunlock(&dhd->pub); DHD_OS_WAKE_UNLOCK(&dhd->pub); } @@ -1852,7 +1858,6 @@ dhd_dpc_thread(void *data) if (dhd->pub.busstate != DHD_BUS_DOWN) { if (dhd_bus_dpc(dhd->pub.bus)) { up(&tsk->sema); - DHD_OS_WAKE_LOCK_TIMEOUT(&dhd->pub); } else { DHD_OS_WAKE_UNLOCK(&dhd->pub); @@ -2151,6 +2156,12 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) } #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ + if (cmd == SIOCDEVPRIVATE+1) { + ret = wl_android_priv_cmd(net, ifr, cmd); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return ret; + } + if (cmd != SIOCDEVPRIVATE) { DHD_OS_WAKE_UNLOCK(&dhd->pub); return -EOPNOTSUPP; @@ -2695,6 +2706,8 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_TRACE(("%s: \n", __FUNCTION__)); + dhd_os_sdlock(dhdp); + /* try to download image and nvram to the dongle */ if ((dhd->pub.busstate == DHD_BUS_DOWN) && (fw_path != NULL) && (fw_path[0] != '\0') && @@ -2704,24 +2717,23 @@ dhd_bus_start(dhd_pub_t *dhdp) fw_path, nv_path))) { DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", __FUNCTION__, fw_path, nv_path)); + dhd_os_sdunlock(dhdp); return -1; } } - if (dhd->pub.busstate != DHD_BUS_LOAD) + if (dhd->pub.busstate != DHD_BUS_LOAD) { + dhd_os_sdunlock(dhdp); return -ENETDOWN; + } /* Start the watchdog timer */ dhd->pub.tickcnt = 0; dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); /* Bring up the bus */ -#ifdef DHDTHREAD - if ((ret = dhd_bus_init(&dhd->pub, TRUE)) != 0) { -#else if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { -#endif - DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); + dhd_os_sdunlock(dhdp); return ret; } #if defined(OOB_INTR_ONLY) @@ -2732,6 +2744,7 @@ dhd_bus_start(dhd_pub_t *dhdp) del_timer_sync(&dhd->timer); DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__)); + dhd_os_sdunlock(dhdp); return -ENODEV; } @@ -2744,9 +2757,12 @@ dhd_bus_start(dhd_pub_t *dhdp) del_timer_sync(&dhd->timer); dhd->wd_timer_valid = FALSE; DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); + dhd_os_sdunlock(dhdp); return -ENODEV; } + dhd_os_sdunlock(dhdp); + #ifdef EMBEDDED_PLATFORM bcm_mkiovar("event_msgs", dhdp->eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); @@ -3432,53 +3448,38 @@ void dhd_os_wd_timer(void *bus, uint wdtick) { dhd_pub_t *pub = bus; - static uint save_dhd_watchdog_ms = 0; dhd_info_t *dhd = (dhd_info_t *)pub->info; + unsigned long flags; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + flags = dhd_os_spin_lock(pub); + /* don't start the wd until fw is loaded */ - if (pub->busstate == DHD_BUS_DOWN) + if (pub->busstate == DHD_BUS_DOWN) { + dhd_os_spin_unlock(pub, flags); return; + } /* Totally stop the timer */ if (!wdtick && dhd->wd_timer_valid == TRUE) { + dhd->wd_timer_valid = FALSE; + dhd_os_spin_unlock(pub, flags); #ifdef DHDTHREAD del_timer_sync(&dhd->timer); #else del_timer(&dhd->timer); #endif /* DHDTHREAD */ - dhd->wd_timer_valid = FALSE; - save_dhd_watchdog_ms = wdtick; return; } if (wdtick) { - dhd_watchdog_ms = (uint)wdtick; - if (save_dhd_watchdog_ms != dhd_watchdog_ms) { - - if (dhd->wd_timer_valid == TRUE) - /* Stop timer and restart at new value */ -#ifdef DHDTHREAD - del_timer_sync(&dhd->timer); -#else - del_timer(&dhd->timer); -#endif /* DHDTHREAD */ - - /* Create timer again when watchdog period is - dynamically changed or in the first instance - */ - dhd->timer.expires = jiffies + dhd_watchdog_ms * HZ / 1000; - add_timer(&dhd->timer); - } else { - /* Re arm the timer, at last watchdog period */ - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); - } - - dhd->wd_timer_valid = TRUE; - - save_dhd_watchdog_ms = wdtick; + dhd_watchdog_ms = (uint)wdtick; + /* Re arm the timer, at last watchdog period */ + mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + dhd->wd_timer_valid = TRUE; } + dhd_os_spin_unlock(pub, flags); } void * @@ -3820,19 +3821,12 @@ dhd_dev_reset(struct net_device *dev, uint8 flag) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - /* Turning off watchdog */ - if (flag) - dhd_os_wd_timer(&dhd->pub, 0); - ret = dhd_bus_devreset(&dhd->pub, flag); if (ret) { DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); return ret; } - /* Turning on watchdog back */ - if (!flag) - dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); - DHD_ERROR(("%s: WLAN OFF DONE\n", __FUNCTION__)); + DHD_ERROR(("%s: WLAN %s DONE\n", __FUNCTION__, flag ? "OFF" : "ON")); return ret; } @@ -3987,8 +3981,6 @@ void dhd_os_start_unlock(dhd_pub_t *pub) #endif } - -#ifdef SOFTAP unsigned long dhd_os_spin_lock(dhd_pub_t *pub) { dhd_info_t *dhd = (dhd_info_t *)(pub->info); @@ -4007,7 +3999,6 @@ void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags) if (dhd) spin_unlock_irqrestore(&dhd->dhd_lock, flags); } -#endif /* SOFTAP */ static int dhd_get_pend_8021x_cnt(dhd_info_t *dhd) diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index f3e53bf..30a1cc2 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -479,7 +479,7 @@ static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, void * regsva, uint16 devid); static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); -static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation); +static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag); static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size); static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, @@ -4961,8 +4961,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) if (dhdp->busstate == DHD_BUS_DOWN) return FALSE; - dhd_os_sdlock(bus->dhd); - /* Poll period: check device if appropriate. */ if (bus->poll && (++bus->polltick >= bus->pollrate)) { uint32 intstatus = 0; @@ -5032,8 +5030,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) } } - dhd_os_sdunlock(bus->dhd); - return bus->ipend; } @@ -5656,7 +5652,7 @@ dhdsdio_release(dhd_bus_t *bus, osl_t *osh) dhd_common_deinit(bus->dhd, NULL); dongle_isolation = bus->dhd->dongle_isolation; dhd_detach(bus->dhd); - dhdsdio_release_dongle(bus, osh, dongle_isolation); + dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE); dhd_free(bus->dhd); bus->dhd = NULL; } @@ -5709,12 +5705,12 @@ dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) static void -dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation) +dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) { DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, bus->dhd, bus->dhd->dongle_reset)); - if (bus->dhd && bus->dhd->dongle_reset) + if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) return; if (bus->sih) { @@ -6137,7 +6133,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) #endif /* defined(OOB_INTR_ONLY) */ /* Clean tx/rx buffer pointers, detach from the dongle */ - dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE); + dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE); bus->dhd->dongle_reset = TRUE; bus->dhd->up = FALSE; @@ -6182,12 +6178,12 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) /* Restore flow control */ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); #endif - dhd_os_wd_timer(dhdp, dhd_watchdog_ms); + dhd_os_wd_timer(dhdp, dhd_watchdog_ms); DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); } else { dhd_bus_stop(bus, FALSE); - dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE); + dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, FALSE); } } else bcmerror = BCME_SDIO_ERROR; diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h index fd399cb..b64d0bb 100644 --- a/drivers/net/wireless/bcmdhd/include/linuxver.h +++ b/drivers/net/wireless/bcmdhd/include/linuxver.h @@ -481,11 +481,7 @@ typedef struct { #define DBG_THR(x) #endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) -#else #define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x) -#endif #define PROC_START(thread_func, owner, tsk_ctl, flags) \ diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c index bfbfc88..eda5ddf 100644 --- a/drivers/net/wireless/bcmdhd/linux_osl.c +++ b/drivers/net/wireless/bcmdhd/linux_osl.c @@ -248,9 +248,13 @@ osl_detach(osl_t *osh) struct sk_buff *osl_alloc_skb(unsigned int len) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) gfp_t flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL; return __dev_alloc_skb(len, flags); +#else + return dev_alloc_skb(len); +#endif } #ifdef CTFPOOL diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c new file mode 100644 index 0000000..fbae30c --- /dev/null +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -0,0 +1,160 @@ +/* + * Linux cfg80211 driver - Android private commands + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_android.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ + */ + +#include +#include +#include + +/* + * Android private command strings, PLEASE define new private commands here + * so they can be updated easily in the future (if needed) + */ + +#define CMD_START "START" +#define CMD_STOP "STOP" +#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" +#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" +#define CMD_RSSI "RSSI" +#define CMD_LINKSPEED "LINKSPEED" +#define CMD_RXFILTER_START "RXFILTER-START" +#define CMD_RXFILTER_STOP "RXFILTER-STOP" +#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" +#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" +#define CMD_BTCOEXMODE "BTCOEXMODE" + +typedef struct android_wifi_priv_cmd { + char *buf; + int used_len; + int total_len; +} android_wifi_priv_cmd; + +static int g_wifi_on = 0; +static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len); + +int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) +{ + int ret = 0; + char *command = NULL; + int bytes_written = 0; + android_wifi_priv_cmd *priv_cmd; + + /* net_os_wake_lock(dev); */ + + priv_cmd = (android_wifi_priv_cmd*)ifr->ifr_data; + if (!priv_cmd) + { + ret = -EINVAL; + goto exit; + } + command = kmalloc(priv_cmd->total_len, GFP_KERNEL); + if (!command) + { + printk("%s: failed to allocate memory\n", __FUNCTION__); + ret = -ENOMEM; + goto exit; + } + if (copy_from_user(command, priv_cmd->buf, priv_cmd->total_len)) { + ret = -EFAULT; + goto exit; + } + + printk("%s: Android private command \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name); + + if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) { + /* TBD: START */ + printk("%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 */ + } + else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) { + /* TBD: SCAN-ACTIVE */ + } + else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) { + /* TBD: SCAN-PASSIVE */ + } + else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) { + /* TBD: RSSI */ + } + else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) { + bytes_written = wl_android_get_link_speed(net, command, priv_cmd->total_len); + } + else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) { + /* TBD: RXFILTER-START */ + } + else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) { + /* TBD: RXFILTER-STOP */ + } + else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) { + /* TBD: BTCOEXSCAN-START */ + } + else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) { + /* TBD: BTCOEXSCAN-STOP */ + } + else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) { + /* TBD: BTCOEXMODE */ + } + else { + printk("Unknown PRIVATE command %s - ignored\n", command); + snprintf(command, 3, "OK"); + bytes_written = strlen("OK") + 1; + } + + priv_cmd->used_len = bytes_written; + if (copy_to_user(priv_cmd->buf, command, bytes_written)) { + printk("%s: failed to copy data to user buffer\n", __FUNCTION__); + } + +exit: + /* net_os_wake_unlock(dev); */ + if (command) { + kfree(command); + } + + return ret; +} + +static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len) +{ + int link_speed; + int bytes_written; + + link_speed = wldev_get_link_speed(net); + + /* Convert Kbps to Android Mbps */ + link_speed = link_speed / 1000; + bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed); + printk("%s: command result is %s \n", __FUNCTION__, command); + return bytes_written; +} diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index 0af6073..a438cf6 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -1631,8 +1631,8 @@ wl_iw_send_priv_event( int wl_control_wl_start(struct net_device *dev) { - int ret = 0; wl_iw_t *iw; + int ret = 0; WL_TRACE(("Enter %s \n", __FUNCTION__)); @@ -1680,8 +1680,8 @@ wl_iw_control_wl_off( struct iw_request_info *info ) { - int ret = 0; wl_iw_t *iw; + int ret = 0; WL_TRACE(("Enter %s\n", __FUNCTION__)); @@ -1769,7 +1769,7 @@ wl_iw_control_wl_on( wl_iw_iscan_set_scan_broadcast_prep(dev, 0); #endif - WL_TRACE(("Exited %s \n", __FUNCTION__)); + WL_TRACE(("Exited %s\n", __FUNCTION__)); return ret; } @@ -1788,8 +1788,6 @@ static int set_ap_mac_list(struct net_device *dev, void *buf); static int get_parameter_from_string( char **str_ptr, const char *token, int param_type, void *dst, int param_max_len); -#endif - static int hex2num(char c) { @@ -1826,7 +1824,6 @@ hstr_2_buf(const char *txt, u8 *buf, int len) -#ifdef SOFTAP static int init_ap_profile_from_string(char *param_str, struct ap_profile *ap_cfg) { @@ -4323,10 +4320,6 @@ wl_iw_iscan_get_scan( WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter)); - - if (!dwrq->length) - return -EAGAIN; - return 0; } #endif diff --git a/drivers/net/wireless/bcmdhd/wl_iw.h b/drivers/net/wireless/bcmdhd/wl_iw.h index dbe30b2..4d36b8c 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.h +++ b/drivers/net/wireless/bcmdhd/wl_iw.h @@ -53,7 +53,7 @@ #define PNOSETUP_SET_CMD "PNOSETUP " #define PNOENABLE_SET_CMD "PNOFORCE" #define PNODEBUG_SET_CMD "PNODEBUG" -#define TXPOWER_SET_CMD "TXPOWER" +#define TXPOWER_SET_CMD "TXPOWER" #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" @@ -227,18 +227,6 @@ extern void get_customized_country_code(char *country_iso_code, wl_country_t *cs iwe_stream_add_point(stream, ends, iwe, extra) #endif -extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); -extern int dhd_pno_clean(dhd_pub_t *dhd); -extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, - ushort scan_fr, int pno_repeat, int pno_freq_expo_max); -extern int dhd_pno_get_status(dhd_pub_t *dhd); -extern int dhd_dev_pno_reset(struct net_device *dev); -extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, - int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max); -extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); -extern int dhd_dev_get_pno_status(struct net_device *dev); -extern int dhd_get_dtim_skip(dhd_pub_t *dhd); - void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec); #define PNO_TLV_PREFIX 'S' diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c index c81fcca..1afb54c 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.c +++ b/drivers/net/wireless/bcmdhd/wldev_common.c @@ -236,3 +236,19 @@ s32 wldev_iovar_getint_bsscfg( } return err; } + +int +wldev_get_link_speed( + struct net_device *dev) +{ + int error; + int link_speed; + + error = wldev_ioctl(dev, WLC_GET_RATE, &link_speed, sizeof(link_speed), 0); + if (error < 0) + return error; + /* Convert internal 500Kbps to Kbps */ + link_speed *= 500; + + return link_speed; +} diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h index eae7d24..bb3a12e 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.h +++ b/drivers/net/wireless/bcmdhd/wldev_common.h @@ -30,19 +30,18 @@ * netdev_ops->ndo_do_ioctl in new kernels) * @dev: the net_device handle */ - s32 wldev_ioctl( struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set); /** Retrieve named IOVARs, this function calls wl_dev_ioctl with - WLC_GET_VAR IOCTL code + * WLC_GET_VAR IOCTL code */ s32 wldev_iovar_getbuf( struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, void *buf, s32 buflen); /** Set named IOVARs, this function calls wl_dev_ioctl with - WLC_SET_VAR IOCTL code + * WLC_SET_VAR IOCTL code */ s32 wldev_iovar_setbuf( struct net_device *dev, s8 *iovar_name, @@ -61,7 +60,7 @@ s32 wldev_mkiovar( /** The following function can be implemented if there is a need for bsscfg - indexed IOVARs + * indexed IOVARs */ s32 wldev_mkiovar_bsscfg( @@ -69,14 +68,14 @@ s32 wldev_mkiovar_bsscfg( s8 *iovar_buf, s32 buflen, s32 bssidx); /** Retrieve named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with - WLC_GET_VAR IOCTL code + * WLC_GET_VAR IOCTL code */ s32 wldev_iovar_getbuf_bsscfg( struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx); /** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with - WLC_SET_VAR IOCTL code + * WLC_SET_VAR IOCTL code */ s32 wldev_iovar_setbuf_bsscfg( struct net_device *dev, s8 *iovar_name, @@ -88,4 +87,7 @@ s32 wldev_iovar_getint_bsscfg( s32 wldev_iovar_setint_bsscfg( struct net_device *dev, s8 *iovar, s32 val, s32 bssidx); +/* Get the link speed from dongle, a minus number indicating an error, speed is in kpbs */ +int wldev_get_link_speed(struct net_device *dev); + #endif /* __WLDEV_COMMON_H__ */ -- 2.7.4