diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/dhd_linux.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_linux.c | 742 |
1 files changed, 497 insertions, 245 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 80a75699e270..6ba7df1cac32 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -22,7 +22,7 @@ * 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: dhd_linux.c 291449 2011-10-22 12:16:26Z $ + * $Id: dhd_linux.c 329682 2012-04-26 09:20:38Z $ */ #include <typedefs.h> @@ -50,6 +50,7 @@ #include <epivers.h> #include <bcmutils.h> #include <bcmendian.h> +#include <bcmdevs.h> #include <proto/ethernet.h> #include <dngl_stats.h> @@ -110,6 +111,7 @@ extern bool ap_fw_loaded; #include <wl_android.h> #ifdef ARP_OFFLOAD_SUPPORT +void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add); static int dhd_device_event(struct notifier_block *this, unsigned long event, void *ptr); @@ -128,6 +130,9 @@ DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); #if defined(OOB_INTR_ONLY) extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); #endif /* defined(OOB_INTR_ONLY) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +static void dhd_hang_process(struct work_struct *work); +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) MODULE_LICENSE("GPL v2"); #endif /* LinuxVer */ @@ -154,11 +159,10 @@ print_tainted() extern wl_iw_extra_params_t g_wl_iw_params; #endif /* defined(CONFIG_BCMDHD_WEXT) */ -#if defined(CONFIG_HAS_EARLYSUSPEND) +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) #include <linux/earlysuspend.h> -extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); -extern int dhd_get_dtim_skip(dhd_pub_t *dhd); #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ +extern int dhd_get_dtim_skip(dhd_pub_t *dhd); #ifdef PKT_FILTER_SUPPORT extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); @@ -247,11 +251,15 @@ typedef struct dhd_info { bool dhd_tasklet_create; #endif /* DHDTHREAD */ tsk_ctl_t thr_sysioc_ctl; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + struct work_struct work_hang; +#endif /* Wakelocks */ #if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) struct wake_lock wl_wifi; /* Wifi wakelock */ struct wake_lock wl_rxwake; /* Wifi rx wakelock */ + struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */ #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) @@ -259,10 +267,12 @@ typedef struct dhd_info { * calls and wifi_on or wifi_off */ struct mutex dhd_net_if_mutex; + struct mutex dhd_suspend_mutex; #endif spinlock_t wakelock_spinlock; int wakelock_counter; - int wakelock_timeout_enable; + int wakelock_rx_timeout_enable; + int wakelock_ctrl_timeout_enable; /* Thread to issue ioctl for multicast */ bool set_macaddress; @@ -271,9 +281,13 @@ typedef struct dhd_info { atomic_t pend_8021x_cnt; dhd_attach_states_t dhd_state; -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) struct early_suspend early_suspend; #endif /* CONFIG_HAS_EARLYSUSPEND */ + +#ifdef ARP_OFFLOAD_SUPPORT + u32 pend_ipaddr; +#endif /* ARP_OFFLOAD_SUPPORT */ } dhd_info_t; /* Definitions to provide path to the firmware and nvram @@ -282,6 +296,8 @@ typedef struct dhd_info { char firmware_path[MOD_PARAM_PATHLEN]; char nvram_path[MOD_PARAM_PATHLEN]; +int op_mode = 0; +module_param(op_mode, int, 0644); extern int wl_control_wl_start(struct net_device *dev); extern int net_os_send_hang_message(struct net_device *dev); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) @@ -353,25 +369,6 @@ uint dhd_radio_up = 1; char iface_name[IFNAMSIZ] = {'\0'}; module_param_string(iface_name, iface_name, IFNAMSIZ, 0); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define DAEMONIZE(a) daemonize(a); \ - allow_signal(SIGKILL); \ - allow_signal(SIGTERM); -#else /* Linux 2.4 (w/o preemption patch) */ -#define RAISE_RX_SOFTIRQ() \ - cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) -#define DAEMONIZE(a) daemonize(); \ - do { if (a) \ - strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \ - } while (0); -#endif /* LINUX_VERSION_CODE */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define BLOCKABLE() (!in_atomic()) -#else -#define BLOCKABLE() (!in_interrupt()) -#endif - /* The following are specific to the SDIO dongle */ /* IOCTL response timeout */ @@ -437,6 +434,11 @@ static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR ; static void dhd_net_if_lock_local(dhd_info_t *dhd); static void dhd_net_if_unlock_local(dhd_info_t *dhd); +static void dhd_suspend_lock(dhd_pub_t *dhdp); +static void dhd_suspend_unlock(dhd_pub_t *dhdp); +#if !defined(AP) && defined(WLP2P) && defined(WL_ENABLE_P2P_IF) +static u32 dhd_concurrent_fw(dhd_pub_t *dhd); +#endif #ifdef WLMEDIA_HTSF void htsf_update(dhd_info_t *dhd, void *data); @@ -479,7 +481,7 @@ static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long actio { int ret = NOTIFY_DONE; -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) switch (action) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: @@ -499,7 +501,7 @@ static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long actio static struct notifier_block dhd_sleep_pm_notifier = { .notifier_call = dhd_sleep_pm_callback, - .priority = 0 + .priority = 10 }; extern int register_pm_notifier(struct notifier_block *nb); extern int unregister_pm_notifier(struct notifier_block *nb); @@ -511,7 +513,8 @@ static void dhd_set_packet_filter(int value, dhd_pub_t *dhd) DHD_TRACE(("%s: %d\n", __FUNCTION__, value)); /* 1 - Enable packet filter, only allow unicast packet to send up */ /* 0 - Disable packet filter */ - if (dhd_pkt_filter_enable) { + if (dhd_pkt_filter_enable && (!value || + (dhd_check_ap_wfd_mode_set(dhd) == FALSE))) { int i; for (i = 0; i < dhd->pktfilter_count; i++) { @@ -523,7 +526,6 @@ static void dhd_set_packet_filter(int value, dhd_pub_t *dhd) #endif } -#if defined(CONFIG_HAS_EARLYSUSPEND) static int dhd_set_suspend(int value, dhd_pub_t *dhd) { int power_mode = PM_MAX; @@ -535,70 +537,76 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n", __FUNCTION__, value, dhd->in_suspend)); + dhd_suspend_lock(dhd); if (dhd && dhd->up) { if (value && dhd->in_suspend) { - /* Kernel suspended */ - DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); - - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); + /* Kernel suspended */ + DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); - /* Enable packet filter, only allow unicast packet to send up */ - dhd_set_packet_filter(1, dhd); + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, + sizeof(power_mode), TRUE, 0); - /* If DTIM skip is set up as default, force it to wake - * each third DTIM for better power savings. Note that - * one side effect is a chance to miss BC/MC packet. - */ - bcn_li_dtim = dhd_get_dtim_skip(dhd); - bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, - 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + /* Enable packet filter, only allow unicast packet to send up */ + dhd_set_packet_filter(1, dhd); - /* Disable firmware roaming during suspend */ - bcm_mkiovar("roam_off", (char *)&roamvar, 4, - iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - } else { + /* If DTIM skip is set up as default, force it to wake + * each third DTIM for better power savings. Note that + * one side effect is a chance to miss BC/MC packet. + */ + bcn_li_dtim = dhd_get_dtim_skip(dhd); + bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, + 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + + /* Disable firmware roaming during suspend */ + bcm_mkiovar("roam_off", (char *)&roamvar, 4, + iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + } else { - /* Kernel resumed */ - DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__)); + /* Kernel resumed */ + DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__)); - power_mode = PM_FAST; - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); + power_mode = PM_FAST; + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, + sizeof(power_mode), TRUE, 0); - /* disable pkt filter */ - dhd_set_packet_filter(0, dhd); + /* disable pkt filter */ + dhd_set_packet_filter(0, dhd); - /* restore pre-suspend setting for dtim_skip */ - bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip, - 4, iovbuf, sizeof(iovbuf)); + /* restore pre-suspend setting for dtim_skip */ + bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip, + 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - roamvar = dhd_roam_disable; - bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, - sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - } + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + roamvar = dhd_roam_disable; + bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, + sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + } } - + dhd_suspend_unlock(dhd); return 0; } -static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val) +static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) { dhd_pub_t *dhdp = &dhd->pub; + int ret = 0; DHD_OS_WAKE_LOCK(dhdp); /* Set flag when early suspend was called */ dhdp->in_suspend = val; - if ((!dhdp->suspend_disable_flag) && (dhd_check_ap_wfd_mode_set(dhdp) == FALSE)) - dhd_set_suspend(val, dhdp); + if ((force || !dhdp->suspend_disable_flag) && + (dhd_check_ap_wfd_mode_set(dhdp) == FALSE)) { + ret = dhd_set_suspend(val, dhdp); + } DHD_OS_WAKE_UNLOCK(dhdp); + return ret; } +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) static void dhd_early_suspend(struct early_suspend *h) { struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); @@ -606,7 +614,7 @@ static void dhd_early_suspend(struct early_suspend *h) DHD_TRACE(("%s: enter\n", __FUNCTION__)); if (dhd) - dhd_suspend_resume_helper(dhd, 1); + dhd_suspend_resume_helper(dhd, 1, 0); } static void dhd_late_resume(struct early_suspend *h) @@ -616,7 +624,7 @@ static void dhd_late_resume(struct early_suspend *h) DHD_TRACE(("%s: enter\n", __FUNCTION__)); if (dhd) - dhd_suspend_resume_helper(dhd, 0); + dhd_suspend_resume_helper(dhd, 0, 0); } #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ @@ -664,16 +672,12 @@ dhd_timeout_expired(dhd_timeout_t *tmo) } else { wait_queue_head_t delay_wait; DECLARE_WAITQUEUE(wait, current); - int pending; init_waitqueue_head(&delay_wait); add_wait_queue(&delay_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); - pending = signal_pending(current); remove_wait_queue(&delay_wait, &wait); set_current_state(TASK_RUNNING); - if (pending) - return 1; /* Interrupted */ } return 0; @@ -694,8 +698,9 @@ dhd_net2idx(dhd_info_t *dhd, struct net_device *net) return DHD_BAD_IF; } -struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx) +struct net_device * dhd_idx2net(void *pub, int ifidx) { + struct dhd_pub *dhd_pub = (struct dhd_pub *)pub; struct dhd_info *dhd_info; if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS) @@ -923,6 +928,7 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); } else { memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); + memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); } return ret; @@ -942,8 +948,9 @@ dhd_op_if(dhd_if_t *ifp) unsigned long flags; #endif + if (!ifp || !ifp->info || !ifp->idx) + return; ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */ - dhd = ifp->info; DHD_TRACE(("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state)); @@ -978,7 +985,7 @@ dhd_op_if(dhd_if_t *ifp) #ifdef WL_CFG80211 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx, - dhd_net_attach)) { + (void*)dhd_net_attach)) { ifp->state = DHD_IF_NONE; return; } @@ -1014,12 +1021,18 @@ dhd_op_if(dhd_if_t *ifp) DHD_TRACE(("\n%s: got 'DHD_IF_DEL' state\n", __FUNCTION__)); #ifdef WL_CFG80211 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { - wl_cfg80211_notify_ifdel(ifp->net); + wl_cfg80211_ifdel_ops(ifp->net); } #endif netif_stop_queue(ifp->net); unregister_netdev(ifp->net); - ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */ + ret = DHD_DEL_IF; + +#ifdef WL_CFG80211 + if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { + wl_cfg80211_notify_ifdel(); + } +#endif } break; case DHD_IF_DELETING: @@ -1034,6 +1047,7 @@ dhd_op_if(dhd_if_t *ifp) ifp->set_multicast = FALSE; if (ifp->net) { free_netdev(ifp->net); + ifp->net = NULL; } dhd->iflist[ifp->idx] = NULL; #ifdef SOFTAP @@ -1135,7 +1149,7 @@ dhd_set_mac_address(struct net_device *dev, void *addr) if (ifidx == DHD_BAD_IF) return -1; - ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN); dhd->set_macaddress = TRUE; up(&dhd->thr_sysioc_ctl.sema); @@ -1153,7 +1167,7 @@ dhd_set_multicast_list(struct net_device *dev) if (ifidx == DHD_BAD_IF) return; - ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); dhd->iflist[ifidx]->set_multicast = TRUE; up(&dhd->thr_sysioc_ctl.sema); } @@ -1164,6 +1178,7 @@ dhd_os_wlfc_block(dhd_pub_t *pub) { dhd_info_t *di = (dhd_info_t *)(pub->info); ASSERT(di != NULL); + spin_lock_bh(&di->wlfc_spinlock); return 1; } @@ -1197,7 +1212,7 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) } /* Update multicast statistic */ - if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_ADDR_LEN) { + if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); eh = (struct ether_header *)pktdata; @@ -1205,6 +1220,9 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) dhdp->tx_multicast++; if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) atomic_inc(&dhd->pend_8021x_cnt); + } else { + PKTFREE(dhd->pub.osh, pktbuf, TRUE); + return BCME_ERROR; } /* Look into the packet and update the packet priority */ @@ -1280,11 +1298,13 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); netif_stop_queue(net); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) /* Send Event when bus down detected during data session */ if (dhd->pub.busstate == DHD_BUS_DOWN) { DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); net_os_send_hang_message(net); } +#endif DHD_OS_WAKE_UNLOCK(&dhd->pub); return -ENODEV; } @@ -1398,7 +1418,8 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) int i; dhd_if_t *ifp; wl_event_msg_t event; - int tout = DHD_PACKET_TIMEOUT; + int tout_rx = 0; + int tout_ctrl = 0; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -1415,7 +1436,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) PKTFREE(dhdp->osh, pktbuf, TRUE); continue; } - +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) /* Dropping packets before registering net device to avoid kernel panic */ if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) { @@ -1424,6 +1445,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) PKTFREE(dhdp->osh, pktbuf, TRUE); continue; } +#endif pnext = PKTNEXT(dhdp->osh, pktbuf); PKTSETNEXT(wl->sh.osh, pktbuf, NULL); @@ -1448,6 +1470,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) */ ((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++; PKTFREE(dhdp->osh, pktbuf, TRUE); + DHD_TRACE(("RX: wlfc header \n")); continue; } #endif @@ -1499,10 +1522,15 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) &data); wl_event_to_host_order(&event); + if (!tout_ctrl) + tout_ctrl = DHD_PACKET_TIMEOUT_MS; if (event.event_type == WLC_E_BTA_HCI_EVENT) { dhd_bta_doevt(dhdp, data, event.datalen); + } else if (event.event_type == WLC_E_PFN_NET_FOUND) { + tout_ctrl *= 2; } - tout = DHD_EVENT_TIMEOUT; + } else { + tout_rx = DHD_PACKET_TIMEOUT_MS; } ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); @@ -1535,7 +1563,8 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ } } - DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(dhdp, tout); + DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); } void @@ -1589,8 +1618,10 @@ dhd_get_stats(struct net_device *net) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__)); return NULL; + } ifp = dhd->iflist[ifidx]; ASSERT(dhd && ifp); @@ -2001,6 +2032,7 @@ dhd_ethtool(dhd_info_t *dhd, void *uaddr) static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) if (!dhdp) return FALSE; if ((error == -ETIMEDOUT) || ((dhdp->busstate == DHD_BUS_DOWN) && @@ -2010,6 +2042,7 @@ static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) net_os_send_hang_message(net); return TRUE; } +#endif return FALSE; } @@ -2030,7 +2063,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) /* send to dongle only if we are not waiting for reload already */ if (dhd->pub.hang_was_sent) { DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__)); - DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); DHD_OS_WAKE_UNLOCK(&dhd->pub); return OSL_ERROR(BCME_DONGLE_DOWN); } @@ -2039,6 +2072,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s: BAD IF\n", __FUNCTION__)); DHD_OS_WAKE_UNLOCK(&dhd->pub); return -1; } @@ -2236,6 +2270,7 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd) #endif for (i = 1; i < DHD_MAX_IFS; i++) { + dhd_net_if_lock_local(dhd); if (dhd->iflist[i]) { DHD_TRACE(("Deleting IF: %d \n", i)); if ((dhd->iflist[i]->state != DHD_IF_DEL) && @@ -2245,6 +2280,7 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd) dhd_op_if(dhd->iflist[i]); } } + dhd_net_if_unlock_local(dhd); } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) @@ -2259,10 +2295,10 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd) static int dhd_stop(struct net_device *net) { - int ifidx; + int ifidx = 0; dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net)); if (dhd->pub.up == 0) { goto exit; } @@ -2270,7 +2306,7 @@ dhd_stop(struct net_device *net) #ifdef WL_CFG80211 if (ifidx == 0) { - wl_cfg80211_down(); + wl_cfg80211_down(NULL); /* * For CFG80211: Clean up all the left over virtual interfaces @@ -2293,15 +2329,15 @@ dhd_stop(struct net_device *net) /* Stop the protocol module */ dhd_prot_stop(&dhd->pub); + OLD_MOD_DEC_USE_COUNT; +exit: #if defined(WL_CFG80211) if (ifidx == 0 && !dhd_download_fw_on_driverload) wl_android_wifi_off(net); #endif - dhd->pub.hang_was_sent = 0; dhd->pub.rxcnt_timeout = 0; dhd->pub.txcnt_timeout = 0; - OLD_MOD_DEC_USE_COUNT; -exit: + DHD_OS_WAKE_UNLOCK(&dhd->pub); return 0; } @@ -2326,13 +2362,19 @@ dhd_open(struct net_device *net) firmware_path[0] = '\0'; } + dhd->pub.hang_was_sent = 0; #if !defined(WL_CFG80211) /* * 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); + ret = wl_control_wl_start(net); + if (ret != 0) { + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + ret = -1; + goto exit; + } #endif ifidx = dhd_net2idx(dhd, net); @@ -2354,12 +2396,17 @@ dhd_open(struct net_device *net) atomic_set(&dhd->pend_8021x_cnt, 0); #if defined(WL_CFG80211) DHD_ERROR(("\n%s\n", dhd_version)); - if (!dhd_download_fw_on_driverload) - wl_android_wifi_on(net); + if (!dhd_download_fw_on_driverload) { + ret = wl_android_wifi_on(net); + if (ret != 0) { + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + ret = -1; + goto exit; + } + } #endif /* defined(WL_CFG80211) */ if (dhd->pub.busstate != DHD_BUS_DATA) { - int ret; /* try to bring up bus */ if ((ret = dhd_bus_start(&dhd->pub)) != 0) { @@ -2382,7 +2429,7 @@ dhd_open(struct net_device *net) #endif /* TOE */ #if defined(WL_CFG80211) - if (unlikely(wl_cfg80211_up())) { + if (unlikely(wl_cfg80211_up(NULL))) { DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__)); ret = -1; goto exit; @@ -2400,10 +2447,39 @@ dhd_open(struct net_device *net) OLD_MOD_INC_USE_COUNT; exit: + if (ret) + dhd_stop(net); + DHD_OS_WAKE_UNLOCK(&dhd->pub); return ret; } +int dhd_do_driver_init(struct net_device *net) +{ + dhd_info_t *dhd = NULL; + + if (!net) { + DHD_ERROR(("Primary Interface not initialized \n")); + return -EINVAL; + } + + dhd = *(dhd_info_t **)netdev_priv(net); + + /* If driver is already initialized, do nothing + */ + if (dhd->pub.busstate == DHD_BUS_DATA) { + DHD_TRACE(("Driver already Inititalized. Nothing to do")); + return 0; + } + + if (dhd_open(net) < 0) { + DHD_ERROR(("Driver Init Failed \n")); + return -1; + } + + return 0; +} + osl_t * dhd_osl_attach(void *pdev, uint bustype) { @@ -2457,7 +2533,7 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, ifp->state = DHD_IF_ADD; ifp->idx = ifidx; ifp->bssidx = bssidx; - ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); up(&dhd->thr_sysioc_ctl.sema); } else ifp->net = (struct net_device *)handle; @@ -2481,10 +2557,30 @@ dhd_del_if(dhd_info_t *dhd, int ifidx) ifp->state = DHD_IF_DEL; ifp->idx = ifidx; - ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); up(&dhd->thr_sysioc_ctl.sema); } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) +static struct net_device_ops dhd_ops_pri = { + .ndo_open = dhd_open, + .ndo_stop = dhd_stop, + .ndo_get_stats = dhd_get_stats, + .ndo_do_ioctl = dhd_ioctl_entry, + .ndo_start_xmit = dhd_start_xmit, + .ndo_set_mac_address = dhd_set_mac_address, + .ndo_set_multicast_list = dhd_set_multicast_list, +}; + +static struct net_device_ops dhd_ops_virt = { + .ndo_get_stats = dhd_get_stats, + .ndo_do_ioctl = dhd_ioctl_entry, + .ndo_start_xmit = dhd_start_xmit, + .ndo_set_mac_address = dhd_set_mac_address, + .ndo_set_multicast_list = dhd_set_multicast_list, +}; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ + dhd_pub_t * dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev) { @@ -2577,13 +2673,16 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev) /* Initialize Wakelock stuff */ spin_lock_init(&dhd->wakelock_spinlock); dhd->wakelock_counter = 0; - dhd->wakelock_timeout_enable = 0; + dhd->wakelock_rx_timeout_enable = 0; + dhd->wakelock_ctrl_timeout_enable = 0; #ifdef CONFIG_HAS_WAKELOCK wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); + wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake"); #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) mutex_init(&dhd->dhd_net_if_mutex); + mutex_init(&dhd->dhd_suspend_mutex); #endif dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; @@ -2659,7 +2758,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev) dhd->thr_sysioc_ctl.thr_pid = -1; } dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + INIT_WORK(&dhd->work_hang, dhd_hang_process); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ /* * Save the dhd_info into the priv */ @@ -2669,7 +2770,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev) register_pm_notifier(&dhd_sleep_pm_notifier); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; dhd->early_suspend.suspend = dhd_early_suspend; dhd->early_suspend.resume = dhd_late_resume; @@ -2678,6 +2779,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev) #endif #ifdef ARP_OFFLOAD_SUPPORT + dhd->pend_ipaddr = 0; register_inetaddr_notifier(&dhd_notifier); #endif /* ARP_OFFLOAD_SUPPORT */ @@ -2711,7 +2813,8 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_TRACE(("Enter %s:\n", __FUNCTION__)); #ifdef DHDTHREAD - dhd_os_sdlock(dhdp); + if (dhd->threads_only) + dhd_os_sdlock(dhdp); #endif /* DHDTHREAD */ /* try to download image and nvram to the dongle */ @@ -2724,14 +2827,16 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", __FUNCTION__, fw_path, nv_path)); #ifdef DHDTHREAD - dhd_os_sdunlock(dhdp); + if (dhd->threads_only) + dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ return -1; } } if (dhd->pub.busstate != DHD_BUS_LOAD) { #ifdef DHDTHREAD - dhd_os_sdunlock(dhdp); + if (dhd->threads_only) + dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ return -ENETDOWN; } @@ -2745,7 +2850,8 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); #ifdef DHDTHREAD - dhd_os_sdunlock(dhdp); + if (dhd->threads_only) + dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ return ret; } @@ -2761,7 +2867,8 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__)); #ifdef DHDTHREAD - dhd_os_sdunlock(dhdp); + if (dhd->threads_only) + dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ return -ENODEV; } @@ -2778,13 +2885,15 @@ dhd_bus_start(dhd_pub_t *dhdp) del_timer_sync(&dhd->timer); DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); #ifdef DHDTHREAD - dhd_os_sdunlock(dhdp); + if (dhd->threads_only) + dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ return -ENODEV; } #ifdef DHDTHREAD - dhd_os_sdunlock(dhdp); + if (dhd->threads_only) + dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ #ifdef READ_MACADDR @@ -2799,45 +2908,89 @@ dhd_bus_start(dhd_pub_t *dhdp) dhd_write_macaddr(dhd->pub.mac.octet); #endif +#ifdef ARP_OFFLOAD_SUPPORT + if (dhd->pend_ipaddr) { +#ifdef AOE_IP_ALIAS_SUPPORT + aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE); +#endif /* AOE_IP_ALIAS_SUPPORT */ + dhd->pend_ipaddr = 0; + } +#endif /* ARP_OFFLOAD_SUPPORT */ + return 0; } +#if !defined(AP) && defined(WLP2P) && defined(WL_ENABLE_P2P_IF) +/* For Android ICS MR2 release, the concurrent mode is enabled by default and the firmware + * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA + * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware + * would still be named as fw_bcmdhd_apsta. + */ +static u32 +dhd_concurrent_fw(dhd_pub_t *dhd) +{ + int ret = 0; + char buf[WLC_IOCTL_SMLEN]; + + if ((!op_mode) && (strstr(fw_path, "_p2p") == NULL) && + (strstr(fw_path, "_apsta") == NULL)) { + /* Given path is for the STA firmware. Check whether P2P support is present in + * the firmware. If so, set mode as P2P (concurrent support). + */ + memset(buf, 0, sizeof(buf)); + bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), + FALSE, 0)) < 0) { + DHD_TRACE(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); + } else if (buf[0] == 1) { + DHD_TRACE(("%s: P2P is supported\n", __FUNCTION__)); + return 1; + } + } + return 0; +} +#endif + int dhd_preinit_ioctls(dhd_pub_t *dhd) { int ret = 0; char eventmask[WL_EVENTING_MASK_LEN]; char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ - +#if !defined(WL_CFG80211) uint up = 0; +#endif uint power_mode = PM_FAST; uint32 dongle_align = DHD_SDALIGN; uint32 glom = 0; - uint bcn_timeout = 4; + uint bcn_timeout = DHD_BEACON_TIMEOUT_NORMAL; + uint retry_max = 3; #if defined(ARP_OFFLOAD_SUPPORT) int arpoe = 1; #endif - int scan_assoc_time = 40; +#if defined(KEEP_ALIVE) + int res; +#endif /* defined(KEEP_ALIVE) */ + int scan_assoc_time = DHD_SCAN_ACTIVE_TIME; int scan_unassoc_time = 40; - int scan_passive_time = 130; + int scan_passive_time = DHD_SCAN_PASSIVE_TIME; char buf[WLC_IOCTL_SMLEN]; char *ptr; uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ + uint16 chipID; #if defined(SOFTAP) uint dtim = 1; #endif #if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ #endif - #if defined(AP) || defined(WLP2P) uint32 apsta = 1; /* Enable APSTA mode */ #endif /* defined(AP) || defined(WLP2P) */ #ifdef GET_CUSTOM_MAC_ENABLE struct ether_addr ea_addr; #endif /* GET_CUSTOM_MAC_ENABLE */ - DHD_TRACE(("Enter %s\n", __FUNCTION__)); dhd->op_mode = 0; #ifdef GET_CUSTOM_MAC_ENABLE @@ -2847,9 +3000,10 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf)); ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); if (ret < 0) { - DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); + DHD_ERROR(("%s: can't set custom MAC address , error=%d\n", __FUNCTION__, ret)); return BCME_NOTUP; } + memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN); } else { #endif /* GET_CUSTOM_MAC_ENABLE */ /* Get the default device MAC address directly from firmware */ @@ -2867,7 +3021,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* GET_CUSTOM_MAC_ENABLE */ #ifdef SET_RANDOM_MAC_SOFTAP - if (strstr(fw_path, "_apsta") != NULL) { + if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == HOSTAPD_MASK)) { uint rand_mac; srandom32((uint)jiffies); @@ -2889,26 +3043,53 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* SET_RANDOM_MAC_SOFTAP */ DHD_TRACE(("Firmware = %s\n", fw_path)); -#if !defined(AP) && defined(WLP2P) +#if !defined(AP) && defined(WLP2P) /* Check if firmware with WFD support used */ - if (strstr(fw_path, "_p2p") != NULL) { + if ((!op_mode && strstr(fw_path, "_p2p") != NULL) +#if defined(WL_ENABLE_P2P_IF) + || (op_mode == 0x04) ||(dhd_concurrent_fw(dhd)) +#endif + ) { bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret)); } else { dhd->op_mode |= WFD_MASK; -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 0; -#endif /* (ARP_OFFLOAD_SUPPORT) */ - dhd_pkt_filter_enable = FALSE; } } #endif #if !defined(AP) && defined(WL_CFG80211) /* Check if firmware with HostAPD support used */ - if (strstr(fw_path, "_apsta") != NULL) { + if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == HOSTAPD_MASK)) { + /* Disable A-band for HostAPD */ + uint band = WLC_BAND_2G; + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_BAND, (char *)&band, sizeof(band), + TRUE, 0)) < 0) { + DHD_ERROR(("%s:set band failed error (%d)\n", __FUNCTION__, ret)); + } + + /* Turn off wme if we are having only g ONLY firmware */ + bcm_mkiovar("nmode", 0, 0, buf, sizeof(buf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), + FALSE, 0)) < 0) { + DHD_ERROR(("%s:get nmode failed error (%d)\n", __FUNCTION__, ret)); + } + else { + DHD_TRACE(("%s:get nmode returned %d\n", __FUNCTION__,buf[0])); + } + if (buf[0] == 0) { + int wme = 0; + bcm_mkiovar("wme", (char *)&wme, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s set wme for HostAPD failed %d\n", __FUNCTION__, ret)); + } + else { + DHD_TRACE(("%s set wme succeeded for g ONLY firmware\n", __FUNCTION__)); + } + } /* Turn off MPC in AP mode */ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, @@ -2957,9 +3138,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - /* disable glom option per default */ - bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + /* disable glom option for some chips */ + chipID = (uint16)dhd_bus_chip_id(dhd); + if ((chipID == BCM4330_CHIP_ID) || (chipID == BCM4329_CHIP_ID)) { + DHD_INFO(("%s disable glom for chipID=0x%X\n", __FUNCTION__, chipID)); + bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + } /* Setup timeout if Beacons are lost and roam is off to report link down */ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); @@ -2967,6 +3152,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) /* Setup assoc_retry_max count to reconnect target AP in dongle */ bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + #if defined(AP) && !defined(WLP2P) /* Turn off MPC in AP mode */ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); @@ -2982,17 +3168,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif #if defined(KEEP_ALIVE) - { /* Set Keep Alive : be sure to use FW with -keepalive */ - int res; - #if defined(SOFTAP) if (ap_fw_loaded == FALSE) #endif if ((res = dhd_keep_alive_onoff(dhd)) < 0) DHD_ERROR(("%s set keeplive failed %d\n", __FUNCTION__, res)); - } #endif /* defined(KEEP_ALIVE) */ /* Read event_msgs mask */ @@ -3019,6 +3201,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) setbit(eventmask, WLC_E_LINK); setbit(eventmask, WLC_E_NDIS_LINK); setbit(eventmask, WLC_E_MIC_ERROR); + setbit(eventmask, WLC_E_ASSOC_REQ_IE); + setbit(eventmask, WLC_E_ASSOC_RESP_IE); setbit(eventmask, WLC_E_PMKID_CACHE); setbit(eventmask, WLC_E_JOIN_START); setbit(eventmask, WLC_E_SCAN_COMPLETE); @@ -3072,12 +3256,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef PKT_FILTER_SUPPORT /* Setup defintions for pktfilter , enable in suspend */ - dhd->pktfilter_count = 4; + dhd->pktfilter_count = 5; /* Setup filter to allow only unicast */ dhd->pktfilter[0] = "100 0 0 0 0x01 0x00"; dhd->pktfilter[1] = NULL; dhd->pktfilter[2] = NULL; dhd->pktfilter[3] = NULL; + dhd->pktfilter[4] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; #if defined(SOFTAP) if (ap_fw_loaded) { int i; @@ -3089,12 +3274,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* defined(SOFTAP) */ #endif /* PKT_FILTER_SUPPORT */ +#if !defined(WL_CFG80211) /* Force STA UP */ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0) { DHD_ERROR(("%s Setting WL UP failed %d\n", __FUNCTION__, ret)); goto done; } - +#endif /* query for 'ver' to get version info from firmware */ memset(buf, 0, sizeof(buf)); ptr = buf; @@ -3105,8 +3291,15 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcmstrtok(&ptr, "\n", 0); /* Print fw version info */ DHD_ERROR(("Firmware version = %s\n", buf)); + DHD_BLOG(buf, strlen(buf) + 1); DHD_BLOG(dhd_version, strlen(dhd_version) + 1); + + /* Check and adjust IOCTL response timeout for Manufactring firmware */ + if (strstr(buf, MANUFACTRING_FW) != NULL) { + dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT * 10); + DHD_ERROR(("%s : adjust IOCTL response time for Manufactring Firmware\n", __FUNCTION__)); + } } done: @@ -3138,26 +3331,6 @@ dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, in return ret; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) -static struct net_device_ops dhd_ops_pri = { - .ndo_open = dhd_open, - .ndo_stop = dhd_stop, - .ndo_get_stats = dhd_get_stats, - .ndo_do_ioctl = dhd_ioctl_entry, - .ndo_start_xmit = dhd_start_xmit, - .ndo_set_mac_address = dhd_set_mac_address, - .ndo_set_multicast_list = dhd_set_multicast_list, -}; - -static struct net_device_ops dhd_ops_virt = { - .ndo_get_stats = dhd_get_stats, - .ndo_do_ioctl = dhd_ioctl_entry, - .ndo_start_xmit = dhd_start_xmit, - .ndo_set_mac_address = dhd_set_mac_address, - .ndo_set_multicast_list = dhd_set_multicast_list, -}; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ - int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) { struct dhd_info *dhd = dhdp->info; @@ -3261,9 +3434,13 @@ static int dhd_device_event(struct notifier_block *this, DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n", __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - /* firmware not downloaded, do nothing */ - if (dhd->pub.busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: bus is down, exit\n", __FUNCTION__)); + if (dhd->pub.busstate != DHD_BUS_DATA) { + DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__)); + if (dhd->pend_ipaddr) { + DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n", + __FUNCTION__, dhd->pend_ipaddr)); + } + dhd->pend_ipaddr = ifa->ifa_address; break; } @@ -3281,7 +3458,7 @@ static int dhd_device_event(struct notifier_block *this, case NETDEV_DOWN: DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n", __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - + dhd->pend_ipaddr = 0; #ifdef AOE_IP_ALIAS_SUPPORT if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) { DHD_ARPOE(("%s: primary interface is down, AOE clr all\n", @@ -3355,7 +3532,8 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) * portable hotspot. This will not work in simultaneous AP/STA mode, * nor with P2P. Need to set the Donlge's MAC address, and then use that. */ - if (ifidx > 0) { + if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr, + ETHER_ADDR_LEN)) { DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n", __func__, net->name)); temp_addr[0] |= 0x02; @@ -3468,13 +3646,17 @@ void dhd_detach(dhd_pub_t *dhdp) unregister_inetaddr_notifier(&dhd_notifier); #endif /* ARP_OFFLOAD_SUPPORT */ -#if defined(CONFIG_HAS_EARLYSUSPEND) +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { if (dhd->early_suspend.suspend) unregister_early_suspend(&dhd->early_suspend); } #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + cancel_work_sync(&dhd->work_hang); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ + #if defined(CONFIG_BCMDHD_WEXT) if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { /* Detatch and unlink in the iw */ @@ -3482,7 +3664,7 @@ void dhd_detach(dhd_pub_t *dhdp) } #endif /* defined(CONFIG_BCMDHD_WEXT) */ - if (&dhd->thr_sysioc_ctl.thr_pid >= 0) { + if (dhd->thr_sysioc_ctl.thr_pid >= 0) { PROC_STOP(&dhd->thr_sysioc_ctl); } @@ -3492,13 +3674,15 @@ void dhd_detach(dhd_pub_t *dhdp) dhd_if_t *ifp; /* Cleanup virtual interfaces */ - for (i = 1; i < DHD_MAX_IFS; i++) + for (i = 1; i < DHD_MAX_IFS; i++) { + dhd_net_if_lock_local(dhd); if (dhd->iflist[i]) { dhd->iflist[i]->state = DHD_IF_DEL; dhd->iflist[i]->idx = i; dhd_op_if(dhd->iflist[i]); } - + dhd_net_if_unlock_local(dhd); + } /* delete primary interface 0 */ ifp = dhd->iflist[0]; ASSERT(ifp); @@ -3549,7 +3733,7 @@ void dhd_detach(dhd_pub_t *dhdp) #ifdef WL_CFG80211 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { - wl_cfg80211_detach(); + wl_cfg80211_detach(NULL); dhd_monitor_uninit(); } #endif @@ -3562,6 +3746,7 @@ void dhd_detach(dhd_pub_t *dhdp) #ifdef CONFIG_HAS_WAKELOCK wake_lock_destroy(&dhd->wl_wifi); wake_lock_destroy(&dhd->wl_rxwake); + wake_lock_destroy(&dhd->wl_ctrlwake); #endif } } @@ -3596,7 +3781,6 @@ dhd_module_cleanup(void) dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); } - static int __init dhd_module_init(void) { @@ -3643,26 +3827,26 @@ dhd_module_init(void) } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - /* - * Wait till MMC sdio_register_driver callback called and made driver attach. - * It's needed to make sync up exit from dhd insmod and - * Kernel MMC sdio device callback registration - */ + /* + * Wait till MMC sdio_register_driver callback called and made driver attach. + * It's needed to make sync up exit from dhd insmod and + * Kernel MMC sdio device callback registration + */ if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) { - error = -EINVAL; + error = -ENODEV; DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__)); goto fail_2; - } + } #endif #if defined(WL_CFG80211) - error = wl_android_post_init(); -#endif + wl_android_post_init(); +#endif /* defined(WL_CFG80211) */ return error; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) fail_2: dhd_bus_unregister(); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +#endif fail_1: #if defined(CONFIG_WIFI_CONTROL_FUNC) wl_android_wifictrl_func_del(); @@ -3674,7 +3858,11 @@ fail_1: return error; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) late_initcall(dhd_module_init); +#else +module_init(dhd_module_init); +#endif module_exit(dhd_module_cleanup); /* @@ -3722,7 +3910,6 @@ int dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) { dhd_info_t * dhd = (dhd_info_t *)(pub->info); - DECLARE_WAITQUEUE(wait, current); int timeout = dhd_ioctl_timeout_msec; /* Convert timeout in millsecond to jiffies */ @@ -3732,26 +3919,7 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) timeout = timeout * HZ / 1000; #endif - /* Wait until control frame is available */ - add_wait_queue(&dhd->ioctl_resp_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - /* Memory barrier to support multi-processing - * As the variable "condition", which points to dhd->rxlen (dhd_bus_rxctl[dhd_sdio.c]) - * Can be changed by another processor. - */ - smp_mb(); - while (!(*condition) && (!signal_pending(current) && timeout)) { - timeout = schedule_timeout(timeout); - smp_mb(); - } - - if (signal_pending(current)) - *pending = TRUE; - - set_current_state(TASK_RUNNING); - remove_wait_queue(&dhd->ioctl_resp_wait, &wait); - + timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); return timeout; } @@ -3761,7 +3929,7 @@ dhd_os_ioctl_resp_wake(dhd_pub_t *pub) dhd_info_t *dhd = (dhd_info_t *)(pub->info); if (waitqueue_active(&dhd->ioctl_resp_wait)) { - wake_up_interruptible(&dhd->ioctl_resp_wait); + wake_up(&dhd->ioctl_resp_wait); } return 0; @@ -3917,7 +4085,7 @@ dhd_os_sdtxunlock(dhd_pub_t *pub) dhd_os_sdunlock(pub); } -#if defined(DHD_USE_STATIC_BUF) +#if defined(CONFIG_DHD_USE_STATIC_BUF) uint8* dhd_os_prealloc(void *osh, int section, uint size) { return (uint8*)wl_android_prealloc(section, size); @@ -3926,7 +4094,7 @@ uint8* dhd_os_prealloc(void *osh, int section, uint size) void dhd_os_prefree(void *osh, void *addr, uint size) { } -#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ +#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ #if defined(CONFIG_BCMDHD_WEXT) struct iw_statistics * @@ -3975,7 +4143,13 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, #endif /* defined(CONFIG_BCMDHD_WEXT) */ #ifdef WL_CFG80211 - + if ((ntoh32(event->event_type) == WLC_E_IF) && + (((dhd_if_event_t *)*data)->action == WLC_E_IF_ADD)) + /* If ADD_IF has been called directly by wl utility then we + * should not report this. In case if ADD_IF was called from + * CFG stack, then too this event need not be reported back + */ + return (BCME_OK); if ((wl_cfg80211_is_progress_ifchange() || wl_cfg80211_is_progress_ifadd()) && (*ifidx != 0)) { /* @@ -4104,8 +4278,13 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) struct dhd_info *dhdinfo = dhd->info; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + int timeout = msecs_to_jiffies(2000); +#else + int timeout = 2 * HZ; +#endif dhd_os_sdunlock(dhd); - wait_event_interruptible_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), HZ * 2); + wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout); dhd_os_sdlock(dhd); #endif return; @@ -4116,7 +4295,7 @@ void dhd_wait_event_wakeup(dhd_pub_t *dhd) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) struct dhd_info *dhdinfo = dhd->info; if (waitqueue_active(&dhdinfo->ctrl_wait)) - wake_up_interruptible(&dhdinfo->ctrl_wait); + wake_up(&dhdinfo->ctrl_wait); #endif return; } @@ -4149,16 +4328,18 @@ int net_os_set_suspend_disable(struct net_device *dev, int val) return ret; } -int net_os_set_suspend(struct net_device *dev, int val) +int net_os_set_suspend(struct net_device *dev, int val, int force) { int ret = 0; -#if defined(CONFIG_HAS_EARLYSUSPEND) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); if (dhd) { +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ret = dhd_set_suspend(val, &dhd->pub); +#else + ret = dhd_suspend_resume_helper(dhd, val, force); +#endif } -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ return ret; } @@ -4178,7 +4359,8 @@ int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) char *filterp = NULL; int ret = 0; - if (!dhd || (num == DHD_UNICAST_FILTER_NUM)) + if (!dhd || (num == DHD_UNICAST_FILTER_NUM) || + (num == DHD_MDNS_FILTER_NUM)) return ret; if (num >= dhd->pub.pktfilter_count) return -EINVAL; @@ -4201,9 +4383,8 @@ int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) return ret; } -int net_os_set_packet_filter(struct net_device *dev, int val) +int dhd_os_set_packet_filter(dhd_pub_t *dhdp, int val) { - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); int ret = 0; /* Packet filtering is set only if we still in early-suspend and @@ -4211,22 +4392,29 @@ int net_os_set_packet_filter(struct net_device *dev, int val) * We can always turn it OFF in case of early-suspend, but we turn it * back ON only if suspend_disable_flag was not set */ - if (dhd && dhd->pub.up) { - if (dhd->pub.in_suspend) { - if (!val || (val && !dhd->pub.suspend_disable_flag)) - dhd_set_packet_filter(val, &dhd->pub); + if (dhdp && dhdp->up) { + if (dhdp->in_suspend) { + if (!val || (val && !dhdp->suspend_disable_flag)) + dhd_set_packet_filter(val, dhdp); } } return ret; + } +int net_os_set_packet_filter(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); -void + return dhd_os_set_packet_filter(&dhd->pub, val); +} + +int dhd_dev_init_ioctl(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - dhd_preinit_ioctls(&dhd->pub); + return dhd_preinit_ioctls(&dhd->pub); } #ifdef PNO_SUPPORT @@ -4271,6 +4459,28 @@ dhd_dev_get_pno_status(struct net_device *dev) #endif /* PNO_SUPPORT */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) +static void dhd_hang_process(struct work_struct *work) +{ + dhd_info_t *dhd; + struct net_device *dev; + + dhd = (dhd_info_t *)container_of(work, dhd_info_t, work_hang); + dev = dhd->iflist[0]->net; + + if (dev) { + rtnl_lock(); + dev_close(dev); + rtnl_unlock(); +#if defined(WL_WIRELESS_EXT) + wl_iw_send_priv_event(dev, "HANG"); +#endif +#if defined(WL_CFG80211) + wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); +#endif + } +} + int net_os_send_hang_message(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -4279,26 +4489,21 @@ int net_os_send_hang_message(struct net_device *dev) if (dhd) { if (!dhd->pub.hang_was_sent) { dhd->pub.hang_was_sent = 1; -#if defined(CONFIG_BCMDHD_WEXT) - ret = wl_iw_send_priv_event(dev, "HANG"); -#endif -#if defined(WL_CFG80211) - ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); -#endif + schedule_work(&dhd->work_hang); } } return ret; } +#endif void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); if (dhd && dhd->pub.up) - memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); + memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); } - void dhd_net_if_lock(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -4327,6 +4532,24 @@ static void dhd_net_if_unlock_local(dhd_info_t *dhd) #endif } +static void dhd_suspend_lock(dhd_pub_t *pub) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + if (dhd) + mutex_lock(&dhd->dhd_suspend_mutex); +#endif +} + +static void dhd_suspend_unlock(dhd_pub_t *pub) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + if (dhd) + mutex_unlock(&dhd->dhd_suspend_mutex); +#endif +} + unsigned long dhd_os_spin_lock(dhd_pub_t *pub) { dhd_info_t *dhd = (dhd_info_t *)(pub->info); @@ -4419,13 +4642,18 @@ int dhd_os_wake_lock_timeout(dhd_pub_t *pub) if (dhd) { spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - ret = dhd->wakelock_timeout_enable; + ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ? + dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable; #ifdef CONFIG_HAS_WAKELOCK - if (dhd->wakelock_timeout_enable) + if (dhd->wakelock_rx_timeout_enable) wake_lock_timeout(&dhd->wl_rxwake, - dhd->wakelock_timeout_enable * HZ); + msecs_to_jiffies(dhd->wakelock_rx_timeout_enable)); + if (dhd->wakelock_ctrl_timeout_enable) + wake_lock_timeout(&dhd->wl_ctrlwake, + msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable)); #endif - dhd->wakelock_timeout_enable = 0; + dhd->wakelock_rx_timeout_enable = 0; + dhd->wakelock_ctrl_timeout_enable = 0; spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); } return ret; @@ -4441,27 +4669,51 @@ int net_os_wake_lock_timeout(struct net_device *dev) return ret; } -int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val) +int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) { dhd_info_t *dhd = (dhd_info_t *)(pub->info); unsigned long flags; if (dhd) { spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (val > dhd->wakelock_timeout_enable) - dhd->wakelock_timeout_enable = val; + if (val > dhd->wakelock_rx_timeout_enable) + dhd->wakelock_rx_timeout_enable = val; spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); } return 0; } -int net_os_wake_lock_timeout_enable(struct net_device *dev, int val) +int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + if (val > dhd->wakelock_ctrl_timeout_enable) + dhd->wakelock_ctrl_timeout_enable = val; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return 0; +} + +int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); int ret = 0; if (dhd) - ret = dhd_os_wake_lock_timeout_enable(&dhd->pub, val); + ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val); + return ret; +} + +int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val); return ret; } @@ -4532,15 +4784,6 @@ int dhd_os_check_wakelock(void *dhdp) return 0; } -int dhd_os_check_if_up(void *dhdp) -{ - dhd_pub_t *pub = (dhd_pub_t *)dhdp; - - if (!pub) - return 0; - return pub->up; -} - int net_os_wake_unlock(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -4551,6 +4794,15 @@ int net_os_wake_unlock(struct net_device *dev) return ret; } +int dhd_os_check_if_up(void *dhdp) +{ + dhd_pub_t *pub = (dhd_pub_t *)dhdp; + + if (!pub) + return 0; + return pub->up; +} + int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) { int ifidx; @@ -4590,8 +4842,8 @@ extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t uint8 iftype, uint8* ea); extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits); -int dhd_wlfc_interface_event(struct dhd_info *dhd, uint8 action, uint8 ifid, uint8 iftype, - uint8* ea) +int dhd_wlfc_interface_event(struct dhd_info *dhd, + ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) { if (dhd->pub.wlfc_state == NULL) return BCME_OK; |