summaryrefslogtreecommitdiffstats
path: root/bcm4329/src/dhd/sys
diff options
context:
space:
mode:
Diffstat (limited to 'bcm4329/src/dhd/sys')
-rw-r--r--bcm4329/src/dhd/sys/dhd.h136
-rw-r--r--bcm4329/src/dhd/sys/dhd_cdc.c232
-rw-r--r--bcm4329/src/dhd/sys/dhd_common.c80
-rw-r--r--bcm4329/src/dhd/sys/dhd_custom_gpio.c239
-rw-r--r--bcm4329/src/dhd/sys/dhd_dbg.h1
-rw-r--r--bcm4329/src/dhd/sys/dhd_linux.c594
-rw-r--r--bcm4329/src/dhd/sys/dhd_sdio.c167
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, &regs->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, &regs->tosbmailboxdata, retries);
if (retries <= retry_limit)
W_SDREG(SMB_DEV_INT, &regs->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, &regs->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, &regs->tosbmailboxdata, retries);
+ if (retries <= retry_limit)
+ W_SDREG(SMB_DEV_INT, &regs->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;