diff options
Diffstat (limited to 'bcm4329/src/dhd/sys')
-rw-r--r-- | bcm4329/src/dhd/sys/dhd.h | 136 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_cdc.c | 232 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_common.c | 80 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_custom_gpio.c | 239 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_dbg.h | 1 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_linux.c | 594 | ||||
-rw-r--r-- | bcm4329/src/dhd/sys/dhd_sdio.c | 167 |
7 files changed, 1000 insertions, 449 deletions
diff --git a/bcm4329/src/dhd/sys/dhd.h b/bcm4329/src/dhd/sys/dhd.h index 8f15106..004f7a3 100644 --- a/bcm4329/src/dhd/sys/dhd.h +++ b/bcm4329/src/dhd/sys/dhd.h @@ -24,7 +24,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.h,v 1.32.4.7.2.4.14.22 2009/06/04 23:07:40 Exp $ + * $Id: dhd.h,v 1.32.4.7.2.4.14.25 2009/10/27 04:41:56 Exp $ */ /**************** @@ -46,6 +46,9 @@ #include <linux/ethtool.h> #include <asm/uaccess.h> #include <asm/unaligned.h> +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) +#include <linux/wakelock.h> +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ /* The kernel threading is sdio-specific */ #else /* LINUX */ #define ENOMEM 1 @@ -75,6 +78,26 @@ enum dhd_bus_state { DHD_BUS_DATA /* Ready for frame transfers */ }; +enum dhd_bus_wake_state { + WAKE_LOCK_OFF, + WAKE_LOCK_PRIV, + WAKE_LOCK_DPC, + WAKE_LOCK_IOCTL, + WAKE_LOCK_DOWNLOAD, + WAKE_LOCK_TMOUT, + WAKE_LOCK_WATCHDOG, + WAKE_LOCK_LINK_DOWN_TMOUT, + WAKE_LOCK_MAX +}; +enum dhd_prealloc_index { + DHD_PREALLOC_PROT = 0, + DHD_PREALLOC_RXBUF, + DHD_PREALLOC_DATABUF, + DHD_PREALLOC_OSL_BUF +}; +#ifdef DHD_USE_STATIC_BUF +extern void * dhd_os_prealloc(int section, unsigned long size); +#endif /* Common structure for module and instance linkage */ typedef struct dhd_pub { /* Linkage ponters */ @@ -126,6 +149,9 @@ typedef struct dhd_pub { int dongle_error; uint8 country_code[WLC_CNTRY_BUF_SZ]; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) + struct wake_lock wakelock[WAKE_LOCK_MAX]; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ } dhd_pub_t; #ifdef NDIS60 @@ -139,9 +165,90 @@ WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(wdf_device_info_t, dhd_get_wdf_device_info) #endif /* NDIS60 */ + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) + + #define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); + #define _DHD_PM_RESUME_WAIT(a, b) do {\ + int retry = 0; \ + while (dhd_mmc_suspend && retry++ != b) { \ + wait_event_timeout(a, FALSE, HZ/100); \ + } \ + } while (0) + #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 30) + #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) + #define DHD_PM_RESUME_RETURN_ERROR(a) do { if (dhd_mmc_suspend) return a; } while (0) + #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) + + #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); + #define SPINWAIT_SLEEP(a, exp, us) do { \ + uint countdown = (us) + 9; \ + while ((exp) && (countdown >= 10)) { \ + wait_event_timeout(a, FALSE, HZ/100); \ + countdown -= 10; \ + } \ + } while (0) + + #else + + #define DHD_PM_RESUME_WAIT_INIT(a) + #define DHD_PM_RESUME_WAIT(a) + #define DHD_PM_RESUME_WAIT_FOREVER(a) + #define DHD_PM_RESUME_RETURN_ERROR(a) + #define DHD_PM_RESUME_RETURN + + #define DHD_SPINWAIT_SLEEP_INIT(a) + #define SPINWAIT_SLEEP(a, exp, us) do { \ + uint countdown = (us) + 9; \ + while ((exp) && (countdown >= 10)) { \ + OSL_DELAY(10); \ + countdown -= 10; \ + } \ + } while (0) + + #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ +#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ + +inline static void WAKE_LOCK_INIT(dhd_pub_t * dhdp, int index, char * y) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) + wake_lock_init(&dhdp->wakelock[index], WAKE_LOCK_SUSPEND, y); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ +} + +inline static void WAKE_LOCK(dhd_pub_t * dhdp, int index) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) + wake_lock(&dhdp->wakelock[index]); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ +} + +inline static void WAKE_UNLOCK(dhd_pub_t * dhdp, int index) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) + wake_unlock(&dhdp->wakelock[index]); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ +} + +inline static void WAKE_LOCK_TIMEOUT(dhd_pub_t * dhdp, int index, long time) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) + wake_lock_timeout(&dhdp->wakelock[index], time); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ +} + +inline static void WAKE_LOCK_DESTROY(dhd_pub_t * dhdp, int index) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) + wake_lock_destroy(&dhdp->wakelock[index]); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ +} + + typedef struct dhd_if_event { uint8 ifidx; uint8 action; + uint8 flags; + uint8 bssidx; } dhd_if_event_t; /* @@ -201,15 +308,13 @@ extern void dhd_os_sdunlock_txq(dhd_pub_t * pub); extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); +extern void dhd_customer_gpio_wlan_ctrl(int onoff); extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); +#if defined(OOB_INTR_ONLY) +extern int dhd_customer_oob_irq_map(void); +#endif /* defined(OOB_INTR_ONLY) */ extern void dhd_os_sdtxlock(dhd_pub_t * pub); extern void dhd_os_sdtxunlock(dhd_pub_t * pub); -extern void dhd_os_set_irq(unsigned int irq, dhd_pub_t *pub); -extern void dhd_os_enable_irq(dhd_pub_t *pub); -extern void dhd_os_disable_irq(dhd_pub_t *pub); -extern int dhd_os_wake_lock(dhd_pub_t *pub); -extern int dhd_os_wake_unlock(dhd_pub_t *pub); -extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); int setScheduler(struct task_struct *p, int policy, struct sched_param *param); @@ -224,15 +329,24 @@ extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); extern int dhd_timeout_expired(dhd_timeout_t *tmo); extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); +extern uint8 *dhd_bssidx2bssid(dhd_pub_t *dhd, int idx); extern int wl_host_event(struct dhd_info *dhd, int *idx, void *pktdata, wl_event_msg_t *, void **data_ptr); extern void wl_event_to_host_order(wl_event_msg_t * evt); extern void dhd_common_init(void); -extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle, char *name, uint8 *mac_addr); +extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle, + char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx); extern void dhd_del_if(struct dhd_info *dhd, int ifidx); +extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name); +extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); + +extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx); +extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); + + /* Send packet to dongle via data channel */ extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); @@ -244,6 +358,12 @@ extern int dhd_bus_start(dhd_pub_t *dhdp); +typedef enum cust_gpio_modes { + WLAN_RESET_ON, + WLAN_RESET_OFF, + WLAN_POWER_ON, + WLAN_POWER_OFF +} cust_gpio_modes_t; /* * Insmod parameters for debug/test */ diff --git a/bcm4329/src/dhd/sys/dhd_cdc.c b/bcm4329/src/dhd/sys/dhd_cdc.c index b28d455..e503b50 100644 --- a/bcm4329/src/dhd/sys/dhd_cdc.c +++ b/bcm4329/src/dhd/sys/dhd_cdc.c @@ -21,7 +21,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_cdc.c,v 1.22.4.2.4.7.2.18 2009/06/26 07:03:26 Exp $ + * $Id: dhd_cdc.c,v 1.22.4.2.4.7.2.30 2009/10/28 21:38:04 Exp $ * * BDC is like CDC, except it includes a header for data packets to convey * packet priority over the bus, and flags (e.g. to indicate checksum status @@ -41,11 +41,6 @@ #include <dhd_bus.h> #include <dhd_dbg.h> -#ifdef EXT_STA -#include <siutils.h> -#include <wlc_cfg.h> -#include <wlc_pub.h> -#endif /* EXT_STA */ /* Packet alignment for most efficient SDIO (can change based on platform) */ #ifndef DHD_SDALIGN @@ -78,12 +73,9 @@ dhdcdc_msg(dhd_pub_t *dhd) { dhd_prot_t *prot = dhd->prot; int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); - int ret; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - dhd_os_wake_lock(dhd); - /* NOTE : cdc->msg.len holds the desired length of the buffer to be * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area * is actually sent to the dongle @@ -92,10 +84,7 @@ dhdcdc_msg(dhd_pub_t *dhd) len = CDC_MAX_MSG_SIZE; /* Send request */ - ret = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); - - dhd_os_wake_unlock(dhd); - return ret; + return dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); } static int @@ -129,7 +118,7 @@ dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len) /* Respond "bcmerror" and "bcmerrorstr" with local cache */ - if (cmd == WLC_GET_VAR) + if (cmd == WLC_GET_VAR && buf) { if (!strcmp((char *)buf, "bcmerrorstr")) { @@ -152,7 +141,7 @@ dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len) CDC_SET_IF_IDX(msg, ifidx); if (buf) - memcpy((void *)(&msg[1]), buf, len); + memcpy(prot->buf, buf, len); if ((ret = dhdcdc_msg(dhd)) < 0) { DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret)); @@ -219,7 +208,7 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len) CDC_SET_IF_IDX(msg, ifidx); if (buf) - memcpy((void *)(&msg[1]), buf, len); + memcpy(prot->buf, buf, len); if ((ret = dhdcdc_msg(dhd)) < 0) goto done; @@ -256,6 +245,10 @@ dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) dhd_prot_t *prot = dhd->prot; int ret = -1; + if (dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); + return ret; + } dhd_os_proto_block(dhd); DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -361,11 +354,6 @@ dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) if (PKTSUMNEEDED(pktbuf)) h->flags |= BDC_FLAG_SUM_NEEDED; -#ifdef EXT_STA - /* save pkt encryption exemption info for dongle */ - h->flags &= ~BDC_FLAG_EXEMPT; - h->flags |= (WLPKTFLAG_EXEMPT_GET(WLPKTTAG(pktbuf)) & BDC_FLAG_EXEMPT); -#endif /* EXT_STA */ h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK); h->flags2 = 0; @@ -461,10 +449,17 @@ 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)))) { + 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 */ @@ -481,8 +476,10 @@ dhd_prot_attach(dhd_pub_t *dhd) return 0; fail: +#ifndef DHD_USE_STATIC_BUF if (cdc != NULL) MFREE(dhd->osh, cdc, sizeof(dhd_prot_t)); +#endif return BCME_NOMEM; } @@ -490,7 +487,9 @@ fail: void dhd_prot_detach(dhd_pub_t *dhd) { +#ifndef DHD_USE_STATIC_BUF MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t)); +#endif dhd->prot = NULL; } @@ -507,17 +506,120 @@ dhd_prot_dstats(dhd_pub_t *dhd) return; } +int dhd_set_suspend(int value, dhd_pub_t *dhd) +{ + int power_mode = PM_MAX; + wl_pkt_filter_enable_t enable_parm; + char iovbuf[32]; + int bcn_li_dtim = 3; +#ifdef CUSTOMER_HW2 + uint roamvar = 1; +#endif /* CUSTOMER_HW2 */ + +#define htod32(i) i + + if (dhd && dhd->up) { + if (value) { + dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, + (char *)&power_mode, sizeof(power_mode)); + /* Enable packet filter, only allow unicast packet to send up */ + enable_parm.id = htod32(100); + enable_parm.enable = htod32(1); + bcm_mkiovar("pkt_filter_enable", (char *)&enable_parm, + sizeof(wl_pkt_filter_enable_t), iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + /* set bcn_li_dtim */ + bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, + 4, iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); +#ifdef CUSTOMER_HW2 + /* Disable build-in roaming to allowed ext supplicant to take of romaing */ + bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); +#endif /* CUSTOMER_HW2 */ + } else { + power_mode = PM_FAST; + dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, + sizeof(power_mode)); + /* disable pkt filter */ + enable_parm.id = htod32(100); + enable_parm.enable = htod32(0); + bcm_mkiovar("pkt_filter_enable", (char *)&enable_parm, + sizeof(wl_pkt_filter_enable_t), iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + /* set bcn_li_dtim */ + bcn_li_dtim = 0; + bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, + 4, iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); +#ifdef CUSTOMER_HW2 + roamvar = 0; + bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); +#endif /* CUSTOMER_HW2 */ + } + } + + return 0; +} + +#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) + +/* Convert user's input in hex pattern to byte-size mask */ +static int +wl_pattern_atoh(char *src, char *dst) +{ + int i; + if (strncmp(src, "0x", 2) != 0 && + strncmp(src, "0X", 2) != 0) { + printf("Mask invalid format. Needs to start with 0x\n"); + return -1; + } + src = src + 2; /* Skip past 0x */ + if (strlen(src) % 2 != 0) { + printf("Mask invalid format. Needs to be of even length\n"); + return -1; + } + for (i = 0; *src != '\0'; i++) { + char num[3]; + strncpy(num, src, 2); + num[2] = '\0'; + dst[i] = (uint8)strtoul(num, NULL, 16); + src += 2; + } + return i; +} + int dhd_preinit_ioctls(dhd_pub_t *dhd) { char eventmask[WL_EVENTING_MASK_LEN]; char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ - + int ret; uint up = 0; +#ifdef CUSTOMER_HW2 + uint roamvar = 0; +#else uint roamvar = 1; +#endif uint power_mode = PM_FAST; uint32 dongle_align = DHD_SDALIGN; - int ret; + uint32 glom = 0; + + uint bcn_timeout = 3; + int arpoe = 1; + int arp_ol = 0xf; + int scan_assoc_time = 40; + int scan_unassoc_time = 80; + const char *str; + wl_pkt_filter_t pkt_filter; + wl_pkt_filter_t *pkt_filterp; + int buf_len; + int str_len; + uint32 mask_size; + uint32 pattern_size; + char buf[256]; + uint filter_mode = 1; /* Get the device MAC address */ strcpy(iovbuf, "cur_etheraddr"); @@ -542,19 +644,27 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); - /* Force STA UP */ - dhdcdc_set_ioctl(dhd, 0, WLC_UP, (char *)&up, sizeof(up)); + /* disable glom option per default */ + bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + /* Setup timeout if Beacons are lost and roam is off to report link down */ + if (roamvar) { + bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + } - /* Disable build-in roaming to allowed ext supplicant to take of romaing */ + /* Enable/Disable build-in roaming to allowed ext supplicant to take of romaing */ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + /* Force STA UP */ + dhdcdc_set_ioctl(dhd, 0, WLC_UP, (char *)&up, sizeof(up)); + /* Setup event_msgs */ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf)); bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); - /* Setup event_msgs */ setbit(eventmask, WLC_E_SET_SSID); setbit(eventmask, WLC_E_PRUNE); setbit(eventmask, WLC_E_AUTH); @@ -576,6 +686,69 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + + dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, + sizeof(scan_assoc_time)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, + sizeof(scan_unassoc_time)); + + /* Set ARP offload */ + bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + + /* add a default packet filter pattern */ + str = "pkt_filter_add"; + str_len = strlen(str); + strncpy(buf, str, str_len); + buf[ str_len ] = '\0'; + buf_len = str_len + 1; + + pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); + + /* Parse packet filter id. */ + pkt_filter.id = htod32(100); + + /* Parse filter polarity. */ + pkt_filter.negate_match = htod32(0); + + /* Parse filter type. */ + pkt_filter.type = htod32(0); + + /* Parse pattern filter offset. */ + pkt_filter.u.pattern.offset = htod32(0); + + /* Parse pattern filter mask. */ + mask_size = htod32(wl_pattern_atoh("0xff", + (char *) pkt_filterp->u.pattern.mask_and_pattern)); + + /* Parse pattern filter pattern. */ + pattern_size = htod32(wl_pattern_atoh("0x00", + (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); + + if (mask_size != pattern_size) { + printk("Mask and pattern not the same size\n"); + return -1; + } + + pkt_filter.u.pattern.size_bytes = mask_size; + buf_len += WL_PKT_FILTER_FIXED_LEN; + buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); + + /* Keep-alive attributes are set in local variable (keep_alive_pkt), and + ** then memcpy'ed into buffer (keep_alive_pktp) since there is no + ** guarantee that the buffer is properly aligned. + */ + memcpy((char *)pkt_filterp, &pkt_filter, + WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); + + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len); + + /* set mode to allow pattern */ + bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, sizeof(iovbuf)); + dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); + return 0; } @@ -583,13 +756,8 @@ int dhd_prot_init(dhd_pub_t *dhd) { int ret = 0; - char buf[128]; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - /* Get the device MAC address */ - strcpy(buf, "cur_etheraddr"); - dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf)); - memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); ret = dhd_preinit_ioctls(dhd); diff --git a/bcm4329/src/dhd/sys/dhd_common.c b/bcm4329/src/dhd/sys/dhd_common.c index c96a0ac..eff07f2 100644 --- a/bcm4329/src/dhd/sys/dhd_common.c +++ b/bcm4329/src/dhd/sys/dhd_common.c @@ -21,7 +21,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_common.c,v 1.5.6.8.2.6.6.32 2009/06/04 23:07:41 Exp $ + * $Id: dhd_common.c,v 1.5.6.8.2.6.6.37 2009/10/22 14:47:18 Exp $ */ #include <typedefs.h> #include <osl.h> @@ -90,6 +90,7 @@ const bcm_iovar_t dhd_iovars[] = { {NULL, 0, 0, 0, 0 } }; + void dhd_common_init(void) { @@ -100,16 +101,8 @@ dhd_common_init(void) * first time that the driver is initialized vs subsequent initializations. */ dhd_msg_level = DHD_ERROR_VAL; -#ifdef CONFIG_BCM4329_FW_PATH - strncpy(fw_path, CONFIG_BCM4329_FW_PATH, MOD_PARAM_PATHLEN-1); -#else fw_path[0] = '\0'; -#endif -#ifdef CONFIG_BCM4329_NVRAM_PATH - strncpy(nv_path, CONFIG_BCM4329_NVRAM_PATH, MOD_PARAM_PATHLEN-1); -#else nv_path[0] = '\0'; -#endif } static int @@ -312,14 +305,21 @@ dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) return FALSE; /* refuse newer (incoming) packet */ /* Evict packet according to discard policy */ p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); - ASSERT(p); + if (p == NULL) { + DHD_ERROR(("%s: pktq_penq() failed, oldest %d.", + __FUNCTION__, discard_oldest)); + ASSERT(p); + } PKTFREE(dhdp->osh, p, TRUE); } /* Enqueue */ p = pktq_penq(q, prec, pkt); - ASSERT(p); + if (p == NULL) { + DHD_ERROR(("%s: pktq_penq() failed.", __FUNCTION__)); + ASSERT(p); + } return TRUE; } @@ -382,6 +382,8 @@ dhd_ioctl(dhd_pub_t *dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + if (!buf) return BCME_BADARG; + switch (ioc->cmd) { case DHD_GET_MAGIC: if (buflen < sizeof(int)) @@ -451,7 +453,7 @@ dhd_ioctl(dhd_pub_t *dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen) } #ifdef APSTA_PINGTEST -struct ether_addr guest_eas[MAX_GUEST] = {}; +struct ether_addr guest_eas[MAX_GUEST]; #endif #ifdef SHOW_EVENTS @@ -774,13 +776,18 @@ wl_host_event(struct dhd_info *dhd, int *ifidx, void *pktdata, char *event_data; uint32 type, status; uint16 flags; + int evlen; - if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) + if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) { + DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__)); return (BCME_ERROR); + } /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ - if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) + if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) { + DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__)); return (BCME_ERROR); + } *data_ptr = &pvt_data[1]; event_data = *data_ptr; @@ -791,17 +798,21 @@ wl_host_event(struct dhd_info *dhd, int *ifidx, void *pktdata, type = ntoh32_ua((void *)&event->event_type); flags = ntoh16_ua((void *)&event->flags); status = ntoh32_ua((void *)&event->status); + evlen = ntoh32_ua((void *)&event->datalen) + sizeof(bcm_event_t); switch (type) { case WLC_E_IF: { dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data; + DHD_TRACE(("%s: if event\n", __FUNCTION__)); if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { if (ifevent->action == WLC_E_IF_ADD) dhd_add_if(dhd, ifevent->ifidx, - NULL, event->ifname, pvt_data->eth.ether_dhost); + NULL, event->ifname, + pvt_data->eth.ether_dhost, + ifevent->flags, ifevent->bssidx); else dhd_del_if(dhd, ifevent->ifidx); } else { @@ -809,17 +820,44 @@ wl_host_event(struct dhd_info *dhd, int *ifidx, void *pktdata, __FUNCTION__, ifevent->ifidx, event->ifname)); } } + /* send up the if event: btamp user needs it */ + *ifidx = dhd_ifname2idx(dhd, event->ifname); + /* push up to external supp/auth */ + dhd_event(dhd, (char *)pvt_data, evlen, *ifidx); + break; + + +#ifdef P2P + case WLC_E_NDIS_LINK: break; +#endif + /* fall through */ + /* These are what external supplicant/authenticator wants */ case WLC_E_LINK: - case WLC_E_DEAUTH: - case WLC_E_DEAUTH_IND: - case WLC_E_DISASSOC: + case WLC_E_ASSOC_IND: + case WLC_E_REASSOC_IND: case WLC_E_DISASSOC_IND: - DHD_EVENT(("%s: Link event %d, flags %x, status %x\n", - __FUNCTION__, type, flags, status)); + case WLC_E_MIC_ERROR: default: + /* Fall through: this should get _everything_ */ + *ifidx = dhd_ifname2idx(dhd, event->ifname); - DHD_EVENT(("%s: event %d, idx %d\n", __FUNCTION__, type, *ifidx)); + /* push up to external supp/auth */ + dhd_event(dhd, (char *)pvt_data, evlen, *ifidx); + DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", + __FUNCTION__, type, flags, status)); + + /* put it back to WLC_E_NDIS_LINK */ + if (type == WLC_E_NDIS_LINK) { + uint32 temp; + + temp = ntoh32_ua((void *)&event->event_type); + DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp)); + + temp = ntoh32(WLC_E_NDIS_LINK); + memcpy((void *)(&pvt_data->event.event_type), &temp, + sizeof(pvt_data->event.event_type)); + } break; } diff --git a/bcm4329/src/dhd/sys/dhd_custom_gpio.c b/bcm4329/src/dhd/sys/dhd_custom_gpio.c index d0dc970..4da20ab 100644 --- a/bcm4329/src/dhd/sys/dhd_custom_gpio.c +++ b/bcm4329/src/dhd/sys/dhd_custom_gpio.c @@ -20,7 +20,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_custom_gpio.c,v 1.1.4.2 2009/04/13 06:09:38 Exp $ +* $Id: dhd_custom_gpio.c,v 1.1.4.3 2009/10/14 04:29:34 Exp $ */ @@ -28,193 +28,96 @@ #include <linuxver.h> #include <osl.h> #include <bcmutils.h> + #include <dngl_stats.h> #include <dhd.h> #include <wlioctl.h> #include <wl_iw.h> -#include <linux/platform_device.h> -#include <linux/wifi_tiwlan.h> - -#include <linux/gpio.h> -#ifdef CONFIG_HAS_WAKELOCK -#include <linux/wakelock.h> -#endif - -static struct wifi_platform_data *wifi_control_data = NULL; -static struct resource *wifi_irqres = NULL; -static dhd_pub_t *wifi_dhd_pub = NULL; -#ifdef MODULE -DECLARE_COMPLETION(sdio_wait); -#endif - -static int wifi_set_carddetect( int on ) -{ - printk("%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_set_power( int on, unsigned long msec ) -{ - printk("%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; -} - -static int wifi_set_reset( int on, unsigned long msec ) -{ - printk("%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; -} - -irqreturn_t dhd_ext_irq_handler( int irq, void *pub, struct pt_regs *cpu_regs ) -{ - printk("%s\n", __FUNCTION__); - dhd_os_disable_irq(pub); - return IRQ_HANDLED; -} - -static int wifi_probe( struct platform_device *pdev ) -{ - struct wifi_platform_data *wifi_ctrl = (struct wifi_platform_data *)(pdev->dev.platform_data); - - printk("%s\n", __FUNCTION__); - wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); - if (wifi_irqres) { - printk("wifi_irqres->start = %lu\n", (unsigned long)(wifi_irqres->start)); - printk("wifi_irqres->flags = %lx\n", wifi_irqres->flags); - } - wifi_control_data = wifi_ctrl; - wifi_set_power(1, 0); - wifi_set_reset(0, 0); - wifi_set_carddetect(1); - return 0; -} +#define WL_ERROR(x) printf x +#define WL_TRACE(x) -int dhdsdio_bussleep(struct dhd_bus *bus, bool sleep); +#ifdef CUSTOMER_HW +extern void bcm_wlan_power_off(int); +extern void bcm_wlan_power_on(int); +#endif /* CUSTOMER_HW */ -static int wifi_suspend( struct platform_device *pdev, pm_message_t state ) -{ - int rc = 0; +#if defined(OOB_INTR_ONLY) - printk("%s\n", __FUNCTION__); - if (wifi_dhd_pub && !wifi_dhd_pub->dongle_reset) { - rc = dhdsdio_bussleep(wifi_dhd_pub->bus, 1); - if (!rc) - dhd_os_enable_irq(wifi_dhd_pub); - } - return rc; -} +#if defined(BCMLXSDMMC) +extern int sdioh_mmc_irq(int irq); +#endif /* (BCMLXSDMMC) */ -static int wifi_resume( struct platform_device *pdev ) -{ - int rc = 0; +/* Customer specific Host GPIO defintion */ +static int dhd_oob_gpio_num = -1; /* GG 19 */ - printk("%s\n", __FUNCTION__); - if (wifi_dhd_pub && !wifi_dhd_pub->dongle_reset) { - rc = dhdsdio_bussleep(wifi_dhd_pub->bus, 0); - if (!rc) - dhd_sched_dpc(wifi_dhd_pub); - } - return rc; -} - -static int wifi_remove( struct platform_device *pdev ) -{ - struct wifi_platform_data *wifi_ctrl = (struct wifi_platform_data *)(pdev->dev.platform_data); - - printk("%s\n", __FUNCTION__); - wifi_control_data = wifi_ctrl; - wifi_set_carddetect(0); - wifi_set_reset(1, 0); - wifi_set_power(0, 0); - return 0; -} +module_param(dhd_oob_gpio_num, int, 0644); +MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); -static struct platform_driver bcm4329_wlan_device = { - .probe = wifi_probe, - .remove = wifi_remove, - .suspend = wifi_suspend, - .resume = wifi_resume, - .driver = { - .name = "bcm4329_wlan", - }, -}; - -int dhd_customer_wifi_complete( void *pub ) +int dhd_customer_oob_irq_map(void) { - int rc = -ENODEV; - - printk("%s\n", __FUNCTION__); - if (!pub) { - printk(KERN_WARNING "%s: No network device\n", __FUNCTION__); - goto end; - } - if (!wifi_irqres || !(wifi_irqres->start)) { - printk(KERN_WARNING "%s: No platform resources\n", __FUNCTION__); - goto end; +int host_oob_irq; +#if defined(CUSTOM_OOB_GPIO_NUM) + if (dhd_oob_gpio_num < 0) { + dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; } - wifi_dhd_pub = pub; - if ((rc = request_irq(wifi_irqres->start, (irq_handler_t)dhd_ext_irq_handler, wifi_irqres->flags & IRQF_TRIGGER_MASK, wifi_irqres->name, pub))) { - printk(KERN_ERR "%s: Failed to register interrupt handler\n", __FUNCTION__); - goto end; - } - set_irq_wake(wifi_irqres->start, 1); - dhd_os_set_irq(wifi_irqres->start, pub); -end: -#ifdef MODULE - complete(&sdio_wait); #endif - return rc; -} -int dhd_customer_wifi_add_dev( void ) -{ - printk("%s\n", __FUNCTION__); - - if (platform_driver_register(&bcm4329_wlan_device)) - return -ENODEV; -#ifdef MODULE - if (!wait_for_completion_timeout(&sdio_wait, msecs_to_jiffies(10000))) { - printk(KERN_ERR "%s: Timed out waiting for device detect\n", __FUNCTION__); - return -ENODEV; + if (dhd_oob_gpio_num < 0) { + WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", \ + __FUNCTION__)); + return (dhd_oob_gpio_num); } -#endif - return 0; -} -void dhd_customer_wifi_del_dev( void ) -{ - printk("%s\n", __FUNCTION__); - set_irq_wake(wifi_irqres->start, 0); - free_irq(wifi_irqres->start, wifi_dhd_pub); - platform_driver_unregister( &bcm4329_wlan_device ); + WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", \ + __FUNCTION__, dhd_oob_gpio_num)); + + /* TODO : move it mmc specific code */ + host_oob_irq = sdioh_mmc_irq(dhd_oob_gpio_num); + return (host_oob_irq); } +#endif /* defined(OOB_INTR_ONLY) */ -/* Customer specific function to insert/remove wlan reset gpio pin */ -void dhd_customer_gpio_wlan_reset( bool onoff ) +/* Customer function to control hw specific wlan gpios */ +void +dhd_customer_gpio_wlan_ctrl(int onoff) { - if (onoff == G_WLAN_SET_OFF) { - printk("%s: assert WLAN RESET\n", __FUNCTION__); - wifi_set_reset(1, 0); - wifi_set_power(0, 0); - } - else { - printk("%s: remove WLAN RESET\n", __FUNCTION__); - wifi_set_power(1, 0); - wifi_set_reset(0, 0); + switch (onoff) { + case WLAN_RESET_OFF: + WL_TRACE(("%s: call customer specific GPIO to insert WLAN RESET\n", + __FUNCTION__)); +#ifdef CUSTOMER_HW + bcm_wlan_power_off(2); +#endif /* CUSTOMER_HW */ + WL_ERROR(("=========== WLAN placed in RESET ========\n")); + break; + + case WLAN_RESET_ON: + WL_TRACE(("%s: callc customer specific GPIO to remove WLAN RESET\n", + __FUNCTION__)); +#ifdef CUSTOMER_HW + bcm_wlan_power_on(2); +#endif /* CUSTOMER_HW */ + WL_ERROR(("=========== WLAN going back to live ========\n")); + break; + + case WLAN_POWER_OFF: + WL_TRACE(("%s: call customer specific GPIO to turn off WL_REG_ON\n", + __FUNCTION__)); +#ifdef CUSTOMER_HW + bcm_wlan_power_off(1); +#endif /* CUSTOMER_HW */ + break; + + case WLAN_POWER_ON: + WL_TRACE(("%s: call customer specific GPIO to turn on WL_REG_ON\n", + __FUNCTION__)); +#ifdef CUSTOMER_HW + bcm_wlan_power_on(1); +#endif /* CUSTOMER_HW */ + /* Lets customer power to get stable */ + OSL_DELAY(500); + break; } } diff --git a/bcm4329/src/dhd/sys/dhd_dbg.h b/bcm4329/src/dhd/sys/dhd_dbg.h index 8ec6d33..581b17d 100644 --- a/bcm4329/src/dhd/sys/dhd_dbg.h +++ b/bcm4329/src/dhd/sys/dhd_dbg.h @@ -1,6 +1,5 @@ /* * Debug/trace/assert driver definitions for Dongle Host Driver. - * basically copied from WL driver. * * Copyright (C) 1999-2009, Broadcom Corporation * diff --git a/bcm4329/src/dhd/sys/dhd_linux.c b/bcm4329/src/dhd/sys/dhd_linux.c index aacc4fb..e5f84c0 100644 --- a/bcm4329/src/dhd/sys/dhd_linux.c +++ b/bcm4329/src/dhd/sys/dhd_linux.c @@ -22,9 +22,12 @@ * 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,v 1.65.4.9.2.12.2.32 2009/06/26 07:03:26 Exp $ + * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.46 2009/10/28 10:35:11 Exp $ */ +#ifdef CONFIG_WIFI_CONTROL_FUNC +#include <linux/platform_device.h> +#endif #include <typedefs.h> #include <linuxver.h> #include <osl.h> @@ -54,12 +57,99 @@ #include <dhd_bus.h> #include <dhd_proto.h> #include <dhd_dbg.h> +#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) +/* To make sdio host driver ignore card insert/remove information */ +struct wifi_platform_data { + char *name; + int (*set_power)(int val); + int (*set_reset)(int val); + int (*set_carddetect)(int val); + void *(*mem_prealloc)(int section, unsigned long size); +}; -#ifdef CONFIG_HAS_WAKELOCK -#include <linux/wakelock.h> -#endif -#include <linux/freezer.h> +struct semaphore wifi_control_sem; + +struct dhd_bus *g_bus; + +static struct wifi_platform_data *wifi_control_data = NULL; + +static int wifi_probe(struct platform_device *pdev) +{ + struct wifi_platform_data *wifi_ctrl = + (struct wifi_platform_data *)(pdev->dev.platform_data); + + DHD_TRACE(("## %s\n", __FUNCTION__)); + if (wifi_ctrl) { + wifi_control_data = wifi_ctrl; + if (wifi_ctrl->set_power) + wifi_ctrl->set_power(1); /* Power On */ + if (wifi_ctrl->set_carddetect) + wifi_ctrl->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_TRACE(("## %s\n", __FUNCTION__)); + if (wifi_ctrl) { + if (wifi_ctrl->set_carddetect) + wifi_ctrl->set_carddetect(0); /* CardDetect (1->0) */ + if (wifi_ctrl->set_power) + wifi_ctrl->set_power(0); /* Power Off */ + } + up(&wifi_control_sem); + return 0; +} +static int wifi_suspend(struct platform_device *pdev, pm_message_t state) +{ + DHD_TRACE(("##> %s\n", __FUNCTION__)); + return 0; +} +static int wifi_resume(struct platform_device *pdev) +{ + DHD_TRACE(("##> %s\n", __FUNCTION__)); + return 0; +} +static struct platform_driver wifi_device = { + .probe = wifi_probe, + .remove = wifi_remove, + .suspend = wifi_suspend, + .resume = wifi_resume, + .driver = { + .name = "msm_wifi", + } +}; + +int wifi_add_dev(void) +{ + DHD_TRACE(("## Calling platform_driver_register\n")); + return platform_driver_register(&wifi_device); +} + +void wifi_del_dev(void) +{ + DHD_TRACE(("## Unregister platform_driver_register\n")); + platform_driver_unregister(&wifi_device); +} +#endif /* defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */ + + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) +#include <linux/suspend.h> +volatile bool dhd_mmc_suspend = FALSE; +DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ + +#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, 0)) MODULE_LICENSE("GPL v2"); #endif /* LinuxVer */ @@ -77,6 +167,10 @@ print_tainted() #include <wl_iw.h> #endif /* CONFIG_WIRELESS_EXT */ +#if defined(CONFIG_HAS_EARLYSUSPEND) +#include <linux/earlysuspend.h> +#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ + /* Interface control information */ typedef struct dhd_if { struct dhd_info *info; /* back pointer to dhd_info */ @@ -120,17 +214,6 @@ typedef struct dhd_info { struct semaphore dpc_sem; struct completion dpc_exited; - /* Wakelocks */ -#ifdef CONFIG_HAS_WAKELOCK - struct wake_lock wl_wifi; /* Wifi wakelock */ - struct wake_lock wl_rxwake; /* Wifi rx wakelock */ -#endif - spinlock_t wl_lock; - int wl_count; - int wl_packet; - unsigned int oob_irq; - int oob_irq_flag; - /* Thread to issue ioctl for multicast */ long sysioc_pid; struct semaphore sysioc_sem; @@ -139,6 +222,11 @@ typedef struct dhd_info { bool set_macaddress; struct ether_addr macvalue; wait_queue_head_t ctrl_wait; + atomic_t pend_8021x_cnt; + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif /* CONFIG_HAS_EARLYSUSPEND */ } dhd_info_t; /* Definitions to provide path to the firmware and nvram @@ -147,6 +235,9 @@ typedef struct dhd_info { char firmware_path[MOD_PARAM_PATHLEN]; char nvram_path[MOD_PARAM_PATHLEN]; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 +struct semaphore dhd_registration_sem; +#endif /* load firmware and/or nvram values from the filesystem */ module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0); module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); @@ -159,7 +250,7 @@ uint dhd_sysioc = TRUE; module_param(dhd_sysioc, uint, 0); /* Watchdog interval */ -uint dhd_watchdog_ms = 1000; +uint dhd_watchdog_ms = 10; module_param(dhd_watchdog_ms, uint, 0); @@ -256,6 +347,8 @@ struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); #endif /* CONFIG_WIRELESS_EXT */ static void dhd_dpc(ulong data); +/* forward decl */ +extern int dhd_wait_pend8021x(struct net_device *dev); #ifdef TOE #ifndef BDC @@ -268,6 +361,55 @@ static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, wl_event_msg_t *event_ptr, void **data_ptr); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) +static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) +{ + switch (action) + { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + dhd_mmc_suspend = TRUE; + return NOTIFY_OK; + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + dhd_mmc_suspend = FALSE; + return NOTIFY_OK; + } + return 0; +} + +static struct notifier_block dhd_sleep_pm_notifier = { + .notifier_call = dhd_sleep_pm_callback, + .priority = 0 +}; +extern int register_pm_notifier(struct notifier_block *nb); +extern int unregister_pm_notifier(struct notifier_block *nb); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ + + +#if defined(CONFIG_HAS_EARLYSUSPEND) +extern int dhd_set_suspend(int value, dhd_pub_t *dhd); + +static void dhd_early_suspend(struct early_suspend *h) +{ + struct dhd_info *dhdp; + dhdp = container_of(h, struct dhd_info, early_suspend); + + DHD_TRACE(("%s: enter\n", __FUNCTION__)); + + dhd_set_suspend(1, &dhdp->pub); +} + +static void dhd_late_resume(struct early_suspend *h) +{ + struct dhd_info *dhdp; + dhdp = container_of(h, struct dhd_info, early_suspend); + + DHD_TRACE(("%s: enter\n", __FUNCTION__)); + + dhd_set_suspend(0, &dhdp->pub); +} +#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ /* * Generalized timeout mechanism. Uses spin sleep with exponential back-off until @@ -647,6 +789,7 @@ int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) { int ret; + dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); /* Reject if down */ if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { @@ -660,6 +803,8 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) if (ETHER_ISMULTI(eh->ether_dhost)) dhdp->tx_multicast++; + if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) + atomic_inc(&dhd->pend_8021x_cnt); } /* Look into the packet and update the packet priority */ @@ -670,7 +815,12 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) dhd_prot_hdrpush(dhdp, ifidx, pktbuf); /* Use bus module to send data frame */ +#ifdef BCMDBUS + ret = dbus_send_pkt(dhdp->dbus, pktbuf, NULL /* pktinfo */); +#else + WAKE_LOCK_TIMEOUT(dhdp, WAKE_LOCK_TMOUT, 25); ret = dhd_bus_txdata(dhdp->bus, pktbuf); +#endif /* BCMDBUS */ return ret; } @@ -687,6 +837,7 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) /* Reject if down */ if (!dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) { + DHD_ERROR(("%s: xmit rejected due to dhd bus down status \n", __FUNCTION__)); return -ENODEV; } @@ -763,7 +914,6 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt) int i; dhd_if_t *ifp; wl_event_msg_t event; - unsigned long flags; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -819,10 +969,12 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt) &data); ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); - if (dhd->iflist[ifidx]) + if (dhd->iflist[ifidx] && !dhd->iflist[ifidx]->state) ifp = dhd->iflist[ifidx]; - ifp->net->last_rx = jiffies; + if (ifp->net) + ifp->net->last_rx = jiffies; + dhdp->dstats.rx_bytes += skb->len; dhdp->rx_packets++; /* Local count */ @@ -846,15 +998,20 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt) #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ } } - spin_lock_irqsave(&dhd->wl_lock, flags); - dhd->wl_packet = 1; - spin_unlock_irqrestore(&dhd->wl_lock, flags); +} + +void +dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) +{ + /* Linux version has nothing to do */ + return; } void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) { - int ifidx; + uint ifidx; + dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); struct ether_header *eh; uint16 type; @@ -863,6 +1020,9 @@ dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); type = ntoh16(eh->ether_type); + if (type == ETHER_TYPE_802_1X) + atomic_dec(&dhd->pend_8021x_cnt); + } static struct net_device_stats * @@ -904,6 +1064,7 @@ static int dhd_watchdog_thread(void *data) { dhd_info_t *dhd = (dhd_info_t *)data; + WAKE_LOCK_INIT(&dhd->pub, WAKE_LOCK_WATCHDOG, "dhd_watchdog_thread"); /* This thread doesn't need any user-level access, * so get rid of all our resources @@ -917,15 +1078,15 @@ dhd_watchdog_thread(void *data) } #endif /* DHD_SCHED */ - set_freezable(); - DAEMONIZE("dhd_watchdog"); /* Run until signal received */ while (1) { if (down_interruptible (&dhd->watchdog_sem) == 0) { + WAKE_LOCK(&dhd->pub, WAKE_LOCK_WATCHDOG); /* Call the bus module watchdog */ dhd_bus_watchdog(&dhd->pub); + WAKE_UNLOCK(&dhd->pub, WAKE_LOCK_WATCHDOG); /* Count the tick for reference */ dhd->pub.tickcnt++; @@ -939,6 +1100,7 @@ dhd_watchdog_thread(void *data) break; } + WAKE_LOCK_DESTROY(&dhd->pub, WAKE_LOCK_WATCHDOG); complete_and_exit(&dhd->watchdog_exited, 0); } @@ -968,6 +1130,7 @@ dhd_dpc_thread(void *data) { dhd_info_t *dhd = (dhd_info_t *)data; + WAKE_LOCK_INIT(&dhd->pub, WAKE_LOCK_DPC, "dhd_dpc_thread"); /* This thread doesn't need any user-level access, * so get rid of all our resources */ @@ -980,8 +1143,6 @@ dhd_dpc_thread(void *data) } #endif /* DHD_SCHED */ - set_freezable(); - DAEMONIZE("dhd_dpc"); /* Run until signal received */ @@ -989,19 +1150,22 @@ dhd_dpc_thread(void *data) if (down_interruptible(&dhd->dpc_sem) == 0) { /* Call bus dpc unless it indicated down (then clean stop) */ if (dhd->pub.busstate != DHD_BUS_DOWN) { - if (dhd_bus_dpc(dhd->pub.bus)) + WAKE_LOCK(&dhd->pub, WAKE_LOCK_DPC); + if (dhd_bus_dpc(dhd->pub.bus)) { up(&dhd->dpc_sem); - else - dhd_os_wake_unlock(&dhd->pub); + WAKE_LOCK_TIMEOUT(&dhd->pub, WAKE_LOCK_TMOUT, 25); + } + WAKE_UNLOCK(&dhd->pub, WAKE_LOCK_DPC); } else { dhd_bus_stop(dhd->pub.bus, TRUE); - dhd_os_wake_unlock(&dhd->pub); } } else break; } + WAKE_LOCK_DESTROY(&dhd->pub, WAKE_LOCK_DPC); + complete_and_exit(&dhd->dpc_exited, 0); } @@ -1026,7 +1190,6 @@ dhd_sched_dpc(dhd_pub_t *dhdp) { dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - dhd_os_wake_lock(dhdp); if (dhd->dpc_pid >= 0) { up(&dhd->dpc_sem); return; @@ -1151,6 +1314,7 @@ dhd_ethtool(dhd_info_t *dhd, void *uaddr) if (copy_from_user(&info, uaddr, sizeof(info))) return -EFAULT; strncpy(drvname, info.driver, sizeof(info.driver)); + drvname[sizeof(info.driver)-1] = '\0'; /* clear struct for return */ memset(&info, 0, sizeof(info)); @@ -1163,8 +1327,10 @@ dhd_ethtool(dhd_info_t *dhd, void *uaddr) } /* otherwise, require dongle to be up */ - else if (!dhd->pub.up) + else if (!dhd->pub.up) { + DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__)); return -ENODEV; + } /* finally, report dongle driver type */ else if (dhd->pub.iswl) @@ -1244,6 +1410,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) void *buf = NULL; uint driver = 0; int ifidx; + bool is_set_key_cmd; ifidx = dhd_net2idx(dhd, net); DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); @@ -1327,10 +1494,26 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) goto done; } + /* Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to + * prevent M4 encryption. + */ + is_set_key_cmd = ((ioc.cmd == WLC_SET_KEY) || + ((ioc.cmd == WLC_SET_VAR) && + !(strncmp("wsec_key", ioc.buf, 9))) || + ((ioc.cmd == WLC_SET_VAR) && + !(strncmp("bsscfg:wsec_key", ioc.buf, 15)))); + if (is_set_key_cmd) { + dhd_wait_pend8021x(net); + } + WAKE_LOCK_INIT(&dhd->pub, WAKE_LOCK_IOCTL, "dhd_ioctl_entry"); + WAKE_LOCK(&dhd->pub, WAKE_LOCK_IOCTL); + bcmerror = dhd_prot_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); + WAKE_UNLOCK(&dhd->pub, WAKE_LOCK_IOCTL); + WAKE_LOCK_DESTROY(&dhd->pub, WAKE_LOCK_IOCTL); done: - if (!bcmerror && ioc.buf) { + if (!bcmerror && buf && ioc.buf) { if (copy_to_user(ioc.buf, buf, buflen)) bcmerror = -EFAULT; } @@ -1344,13 +1527,21 @@ done: static int dhd_stop(struct net_device *net) { +#if !defined(IGNORE_ETH0_DOWN) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + if (dhd->pub.up == 0) { + return 0; + } + /* Set state and stop OS transmissions */ dhd->pub.up = 0; netif_stop_queue(net); +#else + DHD_ERROR(("BYPASS %s:due to BRCM compilation : under investigation ...\n", __FUNCTION__)); +#endif /* !defined(IGNORE_ETH0_DOWN) */ OLD_MOD_DEC_USE_COUNT; return 0; @@ -1364,18 +1555,13 @@ dhd_open(struct net_device *net) uint32 toe_ol; #endif int ifidx; - int ret; ifidx = dhd_net2idx(dhd, net); DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); ASSERT(ifidx == 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; - } + atomic_set(&dhd->pend_8021x_cnt, 0); memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); @@ -1408,10 +1594,14 @@ dhd_osl_detach(osl_t *osh) DHD_ERROR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh))); } osl_detach(osh); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 + up(&dhd_registration_sem); +#endif } int -dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, uint8 *mac_addr) +dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, + uint8 *mac_addr, uint32 flags, uint8 bssidx) { dhd_if_t *ifp; @@ -1491,9 +1681,13 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) memset(dhd, 0, sizeof(dhd_info_t)); + /* + * Save the dhd_info into the priv + */ + memcpy(netdev_priv(net), &dhd, sizeof(dhd)); dhd->pub.osh = osh; - if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL) == DHD_BAD_IF) + if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL, 0, 0) == DHD_BAD_IF) goto fail; net->open = NULL; @@ -1507,15 +1701,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) spin_lock_init(&dhd->sdlock); spin_lock_init(&dhd->txqlock); - /* Initialize Wakelock stuff */ - spin_lock_init(&dhd->wl_lock); - dhd->wl_count = 0; - dhd->wl_packet = 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"); -#endif - /* Link to info module */ dhd->pub.info = dhd; @@ -1530,7 +1715,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) } #ifdef CONFIG_WIRELESS_EXT /* Attach and link in the iw */ - if (wl_iw_attach(net) != 0) { + if (wl_iw_attach(net, (void *)&dhd->pub) != 0) { DHD_ERROR(("wl_iw_attach failed\n")); goto fail; } @@ -1583,6 +1768,23 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) */ memcpy(netdev_priv(net), &dhd, sizeof(dhd)); +#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) + g_bus = bus; +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) + register_pm_notifier(&dhd_sleep_pm_notifier); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ + /* Init lock suspend to prevent kernel going to suspend */ + WAKE_LOCK_INIT(&dhd->pub, WAKE_LOCK_TMOUT, "dhd_wake_lock"); + WAKE_LOCK_INIT(&dhd->pub, WAKE_LOCK_LINK_DOWN_TMOUT, "dhd_wake_lock_link_dw_event"); + +#ifdef CONFIG_HAS_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; + register_early_suspend(&dhd->early_suspend); +#endif + return &dhd->pub; fail: @@ -1607,12 +1809,19 @@ dhd_bus_start(dhd_pub_t *dhdp) /* try to download image and nvram to the dongle */ if (dhd->pub.busstate == DHD_BUS_DOWN) { + WAKE_LOCK_INIT(dhdp, WAKE_LOCK_DOWNLOAD, "dhd_bus_start"); + WAKE_LOCK(dhdp, WAKE_LOCK_DOWNLOAD); if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, fw_path, nv_path))) { DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", __FUNCTION__, fw_path, nv_path)); + WAKE_UNLOCK(dhdp, WAKE_LOCK_DOWNLOAD); + WAKE_LOCK_DESTROY(dhdp, WAKE_LOCK_DOWNLOAD); return -1; } + + WAKE_UNLOCK(dhdp, WAKE_LOCK_DOWNLOAD); + WAKE_LOCK_DESTROY(dhdp, WAKE_LOCK_DOWNLOAD); } /* Start the watchdog timer */ @@ -1624,6 +1833,18 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); return ret; } +#if defined(OOB_INTR_ONLY) + /* Host registration for OOB interrupt */ + if (bcmsdh_register_oob_intr(dhdp)) { + del_timer(&dhd->timer); + dhd->wd_timer_valid = FALSE; + DHD_ERROR(("%s Host failed to resgister for OOB\n", __FUNCTION__)); + return -ENODEV; + } + + /* Enable oob at firmware */ + dhd_enable_oob_intr(dhd->pub.bus, TRUE); +#endif /* defined(OOB_INTR_ONLY) */ /* If bus is not ready, can't come up */ if (dhd->pub.busstate != DHD_BUS_DATA) { @@ -1634,7 +1855,8 @@ dhd_bus_start(dhd_pub_t *dhdp) } /* Bus is ready, do any protocol initialization */ - dhd_prot_init(&dhd->pub); + if ((ret = dhd_prot_init(&dhd->pub)) < 0) + return ret; return 0; } @@ -1719,8 +1941,13 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) goto fail; } - printf("%s: Broadcom Dongle Host Driver\n", net->name); + 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], + dhd->pub.mac.octet[3], dhd->pub.mac.octet[4], dhd->pub.mac.octet[5]); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 + up(&dhd_registration_sem); +#endif return 0; fail: @@ -1731,42 +1958,56 @@ fail: void dhd_bus_detach(dhd_pub_t *dhdp) { - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + dhd_info_t *dhd; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - /* Stop the protocol module */ - dhd_prot_stop(&dhd->pub); - - /* Stop the bus module */ - dhd_bus_stop(dhd->pub.bus, TRUE); - - /* Clear the watchdog timer */ - del_timer(&dhd->timer); - dhd->wd_timer_valid = FALSE; + 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); +#if defined(OOB_INTR_ONLY) + bcmsdh_unregister_oob_intr(); +#endif /* defined(OOB_INTR_ONLY) */ + + /* Clear the watchdog timer */ + del_timer(&dhd->timer); + dhd->wd_timer_valid = FALSE; + } + } } void dhd_detach(dhd_pub_t *dhdp) { - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + dhd_info_t *dhd; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - if (dhd) { - dhd_if_t *ifp; - int i; + if (dhdp) { + dhd = (dhd_info_t *)dhdp->info; + if (dhd) { + dhd_if_t *ifp; + int i; - for (i = 1; i < DHD_MAX_IFS; i++) - if (dhd->iflist[i]) - dhd_del_if(dhd, i); +#if defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(&dhd->early_suspend); +#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ - ifp = dhd->iflist[0]; - ASSERT(ifp); - if (ifp->net->open) { - dhd_stop(ifp->net); - unregister_netdev(ifp->net); - } + for (i = 1; i < DHD_MAX_IFS; i++) + if (dhd->iflist[i]) + dhd_del_if(dhd, i); + + ifp = dhd->iflist[0]; + ASSERT(ifp); + if (ifp->net->open) { + dhd_stop(ifp->net); + unregister_netdev(ifp->net); + } if (dhd->watchdog_pid >= 0) @@ -1798,18 +2039,17 @@ dhd_detach(dhd_pub_t *dhdp) wl_iw_detach(); #endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) + unregister_pm_notifier(&dhd_sleep_pm_notifier); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ + WAKE_LOCK_DESTROY(dhdp, WAKE_LOCK_TMOUT); + WAKE_LOCK_DESTROY(dhdp, WAKE_LOCK_LINK_DOWN_TMOUT); free_netdev(ifp->net); -#ifdef CONFIG_HAS_WAKELOCK - wake_lock_destroy(&dhd->wl_wifi); - wake_lock_destroy(&dhd->wl_rxwake); -#endif MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); } } - -int dhd_customer_wifi_add_dev(void); -void dhd_customer_wifi_del_dev(void); +} static int __init dhd_module_init(void) @@ -1828,21 +2068,50 @@ dhd_module_init(void) if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0) && dhd_deferred_tx) break; - printk("Invalid module parameters.\n"); + DHD_ERROR(("Invalid module parameters.\n")); return -EINVAL; } while (0); +#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) + sema_init(&wifi_control_sem, 0); + wifi_add_dev(); + + /* Waiting callback after platform_driver_register is done or exit with error */ + if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) { + error = 1; + DHD_ERROR(("%s: platform_driver_register callback timeout\n", __FUNCTION__)); + goto fail; + } +#endif /* #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */ + + /* Call customer gpio to turn on power with WL_REG_ON signal */ + dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 + sema_init(&dhd_registration_sem, 0); +#endif + error = dhd_bus_register(); - if (error) - return error; - - error = dhd_customer_wifi_add_dev(); - if (error) { - printk(KERN_ERR "%s: Fail to add wifi device\n", __func__); - dhd_bus_unregister(); - } - else + + if (!error) printf("\n%s\n", dhd_version); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 + /* + * 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(3000)) != 0) { + error = 1; + DHD_ERROR(("%s: sdio_register_driver failed \n", __FUNCTION__)); + } +#endif + +#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) +fail: +#endif /* defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */ + return error; } @@ -1850,10 +2119,16 @@ static void __exit dhd_module_cleanup(void) { DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + dhd_bus_unregister(); - dhd_customer_wifi_del_dev(); +#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) + wifi_del_dev(); +#endif + /* Call customer gpio to turn off power with WL_REG_ON signal */ + dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); } + module_init(dhd_module_init); module_exit(dhd_module_cleanup); @@ -2007,7 +2282,7 @@ dhd_os_sdlock(dhd_pub_t *pub) if (dhd->threads_only) down(&dhd->sdsem); else - spin_lock_bh(&dhd->sdlock); + spin_lock_bh(&dhd->sdlock); } void @@ -2020,7 +2295,7 @@ dhd_os_sdunlock(dhd_pub_t *pub) if (dhd->threads_only) up(&dhd->sdsem); else - spin_unlock_bh(&dhd->sdlock); + spin_unlock_bh(&dhd->sdlock); } void @@ -2061,6 +2336,29 @@ 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(CUSTOMER_HW2) && 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) + { + DHD_INFO(("success alloc section %d\n", section)); + bzero(alloc_ptr, size); + return alloc_ptr; + } + } + + DHD_ERROR(("can't alloc section %d\n", section)); + return 0; +#else +return MALLOC(0, size); +#endif /* #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */ +} +#endif /* DHD_USE_STATIC_BUF */ #ifdef CONFIG_WIRELESS_EXT struct iw_statistics * dhd_get_wireless_stats(struct net_device *dev) @@ -2148,90 +2446,30 @@ dhd_dev_init_ioctl(struct net_device *dev) dhd_preinit_ioctls(&dhd->pub); } -int dhd_os_wake_lock_timeout(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&dhd->wl_lock, flags); - if (dhd) { -#ifdef CONFIG_HAS_WAKELOCK - if (dhd->wl_packet) - wake_lock_timeout(&dhd->wl_rxwake, (HZ >> 1)); -#endif - dhd->wl_packet = 0; - } - ret = dhd->wl_packet; - spin_unlock_irqrestore(&dhd->wl_lock, flags); - /* printk("%s: %d\n", __FUNCTION__, ret); */ - return ret; -} - -int dhd_os_wake_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&dhd->wl_lock, flags); - if (dhd) { -#ifdef CONFIG_HAS_WAKELOCK - if (!dhd->wl_count) - wake_lock(&dhd->wl_wifi); -#endif - dhd->wl_count++; - ret = dhd->wl_count; - } - spin_unlock_irqrestore(&dhd->wl_lock, flags); - if (ret > 2) - printk("%s: Warning: %d\n", __FUNCTION__, ret); - return ret; -} - -int dhd_os_wake_unlock(dhd_pub_t *pub) +static int +dhd_get_pend_8021x_cnt(dhd_info_t *dhd) { - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&dhd->wl_lock, flags); - if (dhd && dhd->wl_count) { - dhd->wl_count--; -#ifdef CONFIG_HAS_WAKELOCK - if (!dhd->wl_count) - wake_unlock(&dhd->wl_wifi); -#endif - ret = dhd->wl_count; - } - spin_unlock_irqrestore(&dhd->wl_lock, flags); - /* printk("%s: %d\n", __FUNCTION__, ret); */ - return ret; + return (atomic_read(&dhd->pend_8021x_cnt)); } -void dhd_os_set_irq(unsigned int irq, dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); +#define MAX_WAIT_FOR_8021X_TX 10 - dhd->oob_irq = irq; - disable_irq(irq); - dhd->oob_irq_flag = 0; -} - -void dhd_os_disable_irq(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - disable_irq_nosync(dhd->oob_irq); - dhd->oob_irq_flag = 0; -} - -void dhd_os_enable_irq(dhd_pub_t *pub) +int +dhd_wait_pend8021x(struct net_device *dev) { - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (!(dhd->oob_irq_flag)) { - dhd->oob_irq_flag = 1; - enable_irq(dhd->oob_irq); + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int timeout = 10 * HZ / 1000; + int ntimes = MAX_WAIT_FOR_8021X_TX; + int pend = dhd_get_pend_8021x_cnt(dhd); + + while (ntimes && pend) { + if (pend) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(timeout); + set_current_state(TASK_RUNNING); + ntimes--; + } + pend = dhd_get_pend_8021x_cnt(dhd); } + return pend; } diff --git a/bcm4329/src/dhd/sys/dhd_sdio.c b/bcm4329/src/dhd/sys/dhd_sdio.c index ec4a9fa..6e43e43 100644 --- a/bcm4329/src/dhd/sys/dhd_sdio.c +++ b/bcm4329/src/dhd/sys/dhd_sdio.c @@ -21,7 +21,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_sdio.c,v 1.157.2.27.2.33.2.77 2009/06/27 00:46:37 Exp $ + * $Id: dhd_sdio.c,v 1.157.2.27.2.33.2.89 2009/10/28 05:49:40 Exp $ */ #include <typedefs.h> @@ -60,8 +60,6 @@ #include <dhdioctl.h> #include <sdiovar.h> -#include <linux/gpio.h> - #define QLEN 256 /* bulk rx and tx queue lengths */ #define FCHI (QLEN - 10) #define FCLOW (FCHI / 2) @@ -140,6 +138,8 @@ */ #define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ PKTFREE(bus->dhd->osh, pkt, FALSE); +DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); +extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); /* Private data for SDIO bus interaction */ @@ -323,6 +323,13 @@ static bool forcealign; #define ALIGNMENT 4 +#if defined(OOB_INTR_ONLY) && defined(HW_OOB) +extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); +#endif + +#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) +#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD +#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */ #define PKTALIGN(osh, p, len, align) \ do { \ uint datalign; \ @@ -425,6 +432,7 @@ static int dhdsdio_download_nvram(struct dhd_bus *bus); static int dhdsdio_download_code_array(struct dhd_bus *bus); #endif + static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size) { @@ -463,6 +471,9 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); +#if defined(OOB_INTR_ONLY) + pendok = FALSE; +#endif clkctl = 0; sdh = bus->sdh; @@ -521,7 +532,8 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) /* Otherwise, wait here (polling) for HT Avail */ if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { - SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, + SPINWAIT_SLEEP(sdioh_spinwait_sleep, + ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err)), !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY); } @@ -716,16 +728,8 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) return BCME_OK; } -int dhdsdio_oob(dhd_bus_t *bus) -{ - sdpcmd_regs_t *regs = bus->regs; - uint retries = 0; - - W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); - return 0; -} - -int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) +int +dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) { bcmsdh_info_t *sdh = bus->sdh; sdpcmd_regs_t *regs = bus->regs; @@ -745,6 +749,7 @@ int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) return BCME_BUSY; + /* Disable SDIO interrupts (no longer interested) */ bcmsdh_intr_disable(bus->sdh); @@ -763,21 +768,25 @@ int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); /* Isolate the bus */ -#if 0 - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, - SBSDIO_DEVCTL_PADS_ISO, NULL); -#endif + if (bus->sih->chip != BCM4329_CHIP_ID && bus->sih->chip != BCM4319_CHIP_ID) { + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, + SBSDIO_DEVCTL_PADS_ISO, NULL); + } + /* Change state */ bus->sleeping = TRUE; } else { /* Waking up: bus power up is ok, set local state */ + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); + /* Force pad isolation off if possible (in case power never toggled) */ if ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev >= 10)) bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL); + /* Make sure the controller has the bus up */ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); @@ -785,7 +794,8 @@ int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) W_SDREG(0, ®s->tosbmailboxdata, retries); if (retries <= retry_limit) W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); - else + + if (retries > retry_limit) DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); /* Make sure we have SD bus access */ @@ -800,8 +810,39 @@ int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) bcmsdh_intr_enable(bus->sdh); } } + return BCME_OK; } +#if defined(OOB_INTR_ONLY) +void +dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) +{ +#if defined(HW_OOB) + bcmsdh_enable_hw_oob_intr(bus->sdh, enable); +#else + sdpcmd_regs_t *regs = bus->regs; + uint retries = 0; + + dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); + if (enable == TRUE) { + + /* Tell device to start using OOB wakeup */ + W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); + if (retries > retry_limit) + DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); + + } else { + /* Send misc interrupt to indicate OOB not needed */ + W_SDREG(0, ®s->tosbmailboxdata, retries); + if (retries <= retry_limit) + W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); + } + + /* Turn off our contribution to the HT clock request */ + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); +#endif /* defined(HW_OOB) */ +} +#endif /* defined(OOB_INTR_ONLY) */ #define BUS_WAKE(bus) \ do { \ @@ -1466,7 +1507,7 @@ dhd_bus_clearcounts(dhd_pub_t *dhdp) dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus; bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0; - bus->rxrtx = bus->rx_toolong = bus->rx_toolong = bus->rxc_errors = 0; + bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0; bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0; bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0; bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0; @@ -1538,6 +1579,11 @@ dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint s uint32 sdaddr; uint dsize; + if (size % 4) { + size += 3; + size &= 0xFFFFFFFC; + } + /* Determine initial transfer parameters */ sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK) @@ -1910,11 +1956,11 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch *(char *)arg = 0; bcmstrcat(arg, "\nFunc 0\n"); - bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), 49 * 32); + bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); bcmstrcat(arg, "\nFunc 1\n"); - bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), 49 * 32); + bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); bcmstrcat(arg, "\nFunc 2\n"); - bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), 49 * 32); + bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); break; } @@ -2064,7 +2110,6 @@ dhdsdio_write_vars(dhd_bus_t *bus) /* Compare the org NVRAM with the one read from RAM */ if (memcmp(vbuffer, nvram_ularray, varsize)) { DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__)); - ASSERT(0); } else DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n", __FUNCTION__)); @@ -3674,7 +3719,7 @@ dhdsdio_hostmail(dhd_bus_t *bus) return intstatus; } -static bool +bool dhdsdio_dpc(dhd_bus_t *bus) { bcmsdh_info_t *sdh = bus->sdh; @@ -3892,16 +3937,17 @@ clkwait: resched = TRUE; } - dhd_os_sdunlock(bus->dhd); bus->dpc_sched = resched; /* If we're done for now, turn off clock request. */ - if (bus->idletime == DHD_IDLE_IMMEDIATE) { + if ((bus->clkstate != CLK_PENDING) && bus->idletime == DHD_IDLE_IMMEDIATE) { bus->activity = FALSE; dhdsdio_clkctl(bus, CLK_NONE, FALSE); } - dhd_os_wake_lock_timeout(bus->dhd); /* Keep wake lock for rx */ + + dhd_os_sdunlock(bus->dhd); + return resched; } @@ -3927,6 +3973,11 @@ dhdsdio_isr(void *arg) dhd_bus_t *bus = (dhd_bus_t*)arg; bcmsdh_info_t *sdh = bus->sdh; + if (bus->dhd->busstate == DHD_BUS_DOWN) { + DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); + return; + } + DHD_TRACE(("%s: Enter\n", __FUNCTION__)); /* Count the interrupt call */ @@ -3950,13 +4001,13 @@ dhdsdio_isr(void *arg) bus->intdis = TRUE; #if defined(SDIO_ISR_THREAD) - dhd_os_wake_lock(bus->dhd); + DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); while (dhdsdio_dpc(bus)); - dhd_os_wake_unlock(bus->dhd); #else bus->dpc_sched = TRUE; dhd_sched_dpc(bus->dhd); #endif + } #ifdef SDTEST @@ -4326,8 +4377,6 @@ dhdsdio_chipmatch(uint16 chipid) return FALSE; } -int dhd_customer_wifi_complete(void *); - static void * dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh) @@ -4480,11 +4529,9 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__)); goto fail; } - if (dhd_customer_wifi_complete(bus->dhd)) { - DHD_ERROR(("%s: Platform resorce!!\n", __FUNCTION__)); - goto fail; - } + return bus; + fail: dhdsdio_release(bus, osh); return NULL; @@ -4645,6 +4692,7 @@ 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))) { @@ -4662,6 +4710,22 @@ dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) 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)); + goto fail; + } +#endif /* DHD_USE_STATIC_BUF */ /* Align the buffer */ if ((uintptr)bus->databuf % DHD_SDALIGN) @@ -4759,6 +4823,7 @@ dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, ret = dhdsdio_download_firmware(bus, osh, bus->sdh); + return ret; } @@ -4769,12 +4834,12 @@ dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) /* Download the firmware */ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - dhd_os_wake_lock(bus->dhd); - ret = _dhdsdio_download_firmware(bus); - dhd_os_wake_unlock(bus->dhd); + + ret = _dhdsdio_download_firmware(bus) == 0; + dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - return !ret; + return ret; } /* Detach and free everything */ @@ -4818,13 +4883,17 @@ dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) return; if (bus->rxbuf) { +#ifndef DHD_USE_STATIC_BUF MFREE(osh, bus->rxbuf, bus->rxblen); +#endif bus->rxctl = bus->rxbuf = NULL; bus->rxlen = 0; } if (bus->databuf) { +#ifndef DHD_USE_STATIC_BUF MFREE(osh, bus->databuf, MAX_DATA_BUF); +#endif bus->databuf = NULL; } } @@ -5066,7 +5135,7 @@ process_nvram_vars(char *varbuf, uint len) return buf_len; } -/* +/* EXAMPLE: nvram_array nvram_arry format: name=value @@ -5123,6 +5192,8 @@ dhdsdio_download_nvram(struct dhd_bus *bus) else { len = strlen(bus->nvram_params); ASSERT(len <= MEMBLOCK); + if (len > MEMBLOCK) + len = MEMBLOCK; memcpy(memblock, bus->nvram_params, len); } @@ -5283,6 +5354,10 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) if (flag == TRUE) { if (!bus->dhd->dongle_reset) { +#if !defined(IGNORE_ETH0_DOWN) + /* Force flow control as protection when stop come before ifconfig_down */ + dhd_txflowcontrol(bus->dhd, 0, ON); +#endif /* !defined(IGNORE_ETH0_DOWN) */ /* save country settinng if was pre-setup with priv ioctl */ dhdcdc_query_ioctl(bus->dhd, 0, WLC_GET_COUNTRY, bus->dhd->country_code, sizeof(bus->dhd->country_code)); @@ -5321,8 +5396,18 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) /* Re-init bus, enable F2 transfer */ dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); +#if defined(OOB_INTR_ONLY) + dhd_enable_oob_intr(bus, TRUE); +#endif /* defined(OOB_INTR_ONLY) */ + bus->dhd->dongle_reset = FALSE; bus->dhd->up = TRUE; + +#if !defined(IGNORE_ETH0_DOWN) + /* Restore flow control */ + dhd_txflowcontrol(bus->dhd, 0, OFF); +#endif + DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); } else bcmerror = BCME_SDIO_ERROR; |