summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorGreg Goldman <ggoldman@broadcom.com>2010-06-03 10:58:51 -0700
committerColin Cross <ccross@android.com>2010-09-29 17:49:36 -0700
commit7c82d4484a9dab67b0372b97975deba23d252e66 (patch)
treea059b993dcce3c518f6b00db94f88465b595db72 /drivers/net
parent18cde38642ce0bea1a7d2dec84b62fbcc50b9f24 (diff)
network: wireless: bcm4329: Update to Version 4.218.238
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/bcm4329/Makefile1
-rw-r--r--drivers/net/wireless/bcm4329/dhd.h41
-rw-r--r--drivers/net/wireless/bcm4329/dhd_bus.h8
-rw-r--r--drivers/net/wireless/bcm4329/dhd_cdc.c282
-rw-r--r--drivers/net/wireless/bcm4329/dhd_common.c803
-rw-r--r--drivers/net/wireless/bcm4329/dhd_dbg.h7
-rw-r--r--drivers/net/wireless/bcm4329/dhd_linux.c244
-rw-r--r--drivers/net/wireless/bcm4329/dhd_proto.h8
-rw-r--r--drivers/net/wireless/bcm4329/dhd_sdio.c315
-rw-r--r--drivers/net/wireless/bcm4329/include/dhdioctl.h5
-rw-r--r--drivers/net/wireless/bcm4329/include/epivers.h12
-rw-r--r--drivers/net/wireless/bcm4329/include/hndrte_cons.h35
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/802.11.h3
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/ethernet.h5
-rw-r--r--drivers/net/wireless/bcm4329/include/wlioctl.h5
-rw-r--r--drivers/net/wireless/bcm4329/linux_osl.c4
-rw-r--r--drivers/net/wireless/bcm4329/wl_iw.c174
17 files changed, 1516 insertions, 436 deletions
diff --git a/drivers/net/wireless/bcm4329/Makefile b/drivers/net/wireless/bcm4329/Makefile
index 6d71341d3c35..a7c0267dfcfc 100644
--- a/drivers/net/wireless/bcm4329/Makefile
+++ b/drivers/net/wireless/bcm4329/Makefile
@@ -5,6 +5,7 @@ DHDCFLAGS = -DLINUX -DBCMDRIVER -DBCMDONGLEHOST -DDHDTHREAD -DBCMWPA2 \
-DSHOW_EVENTS -DBCMSDIO -DDHD_GPL -DBCMLXSDMMC -DBCMPLATFORM_BUS \
-Wall -Wstrict-prototypes -Werror -DOOB_INTR_ONLY -DCUSTOMER_HW2 \
-DDHD_USE_STATIC_BUF -DMMC_SDIO_ABORT -DDHD_DEBUG_TRAP -DSOFTAP \
+ -DEMBEDDED_PLATFORM -DARP_OFFLOAD_SUPPORT -DPKT_FILTER_SUPPORT \
-Idrivers/net/wireless/bcm4329 -Idrivers/net/wireless/bcm4329/include
DHDOFILES = dhd_linux.o linux_osl.o bcmutils.o dhd_common.o dhd_custom_gpio.o \
diff --git a/drivers/net/wireless/bcm4329/dhd.h b/drivers/net/wireless/bcm4329/dhd.h
index 845a31624081..a6c9ba3d6683 100644
--- a/drivers/net/wireless/bcm4329/dhd.h
+++ b/drivers/net/wireless/bcm4329/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.29 2010/02/23 06:58:21 Exp $
+ * $Id: dhd.h,v 1.32.4.7.2.4.14.43 2010/05/18 05:48:53 Exp $
*/
/****************
@@ -150,7 +150,13 @@ typedef struct dhd_pub {
/* Last error from dongle */
int dongle_error;
+ /* Pkt filter defination */
+ char * pktfilter[100];
+ int pktfilter_count;
+
uint8 country_code[WLC_CNTRY_BUF_SZ];
+ char eventmask[WL_EVENTING_MASK_LEN];
+
} dhd_pub_t;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
@@ -169,10 +175,10 @@ typedef struct dhd_pub {
#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)) { \
+ uint countdown = (us) + 9999; \
+ while ((exp) && (countdown >= 10000)) { \
wait_event_interruptible_timeout(a, FALSE, HZ/100); \
- countdown -= 10; \
+ countdown -= 10000; \
} \
} while (0)
@@ -270,6 +276,9 @@ extern void dhd_customer_gpio_wlan_ctrl(int onoff);
extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub);
extern void dhd_os_sdlock_eventq(dhd_pub_t * pub);
extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub);
+#ifdef DHD_DEBUG
+extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size);
+#endif /* DHD_DEBUG */
#if defined(OOB_INTR_ONLY)
extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr);
#endif /* defined(OOB_INTR_ONLY) */
@@ -316,6 +325,7 @@ extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag);
extern uint dhd_bus_status(dhd_pub_t *dhdp);
extern int dhd_bus_start(dhd_pub_t *dhdp);
+extern void print_buf(void *pbuf, int len, int bytes_per_line);
typedef enum cust_gpio_modes {
@@ -336,7 +346,7 @@ extern uint dhd_watchdog_ms;
#if defined(DHD_DEBUG)
/* Console output poll interval */
extern uint dhd_console_ms;
-#endif
+#endif /* defined(DHD_DEBUG) */
/* Use interrupts */
extern uint dhd_intr;
@@ -344,6 +354,27 @@ extern uint dhd_intr;
/* Use polling */
extern uint dhd_poll;
+/* ARP offload agent mode */
+extern uint dhd_arp_mode;
+
+/* ARP offload enable */
+extern uint dhd_arp_enable;
+
+/* Pkt filte enable control */
+extern uint dhd_pkt_filter_enable;
+
+/* Pkt filter init setup */
+extern uint dhd_pkt_filter_init;
+
+/* Pkt filter mode control */
+extern uint dhd_master_mode;
+
+/* Roaming mode control */
+extern uint dhd_roam;
+
+/* Roaming mode control */
+extern uint dhd_radio_up;
+
/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */
extern int dhd_idletime;
#define DHD_IDLETIME_TICKS 1
diff --git a/drivers/net/wireless/bcm4329/dhd_bus.h b/drivers/net/wireless/bcm4329/dhd_bus.h
index 93392f98348c..9e29fb955444 100644
--- a/drivers/net/wireless/bcm4329/dhd_bus.h
+++ b/drivers/net/wireless/bcm4329/dhd_bus.h
@@ -4,7 +4,7 @@
* Provides type definitions and function prototypes used to link the
* DHD OS, bus, and protocol modules.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -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_bus.h,v 1.4.6.3.2.3.6.5 2009/06/02 21:56:30 Exp $
+ * $Id: dhd_bus.h,v 1.4.6.3.2.3.6.6 2010/05/17 18:18:13 Exp $
*/
#ifndef _dhd_bus_h_
@@ -60,6 +60,10 @@ extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen);
/* Watchdog timer function */
extern bool dhd_bus_watchdog(dhd_pub_t *dhd);
+#ifdef DHD_DEBUG
+/* Device console input function */
+extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen);
+#endif
/* Deferred processing for the bus, return TRUE requests reschedule */
extern bool dhd_bus_dpc(struct dhd_bus *bus);
diff --git a/drivers/net/wireless/bcm4329/dhd_cdc.c b/drivers/net/wireless/bcm4329/dhd_cdc.c
index 43b21c389926..835b30a9f8f3 100644
--- a/drivers/net/wireless/bcm4329/dhd_cdc.c
+++ b/drivers/net/wireless/bcm4329/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.34 2010/01/21 22:08:34 Exp $
+ * $Id: dhd_cdc.c,v 1.22.4.2.4.7.2.36 2010/04/14 12:09:11 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,6 +41,11 @@
#include <dhd_bus.h>
#include <dhd_dbg.h>
+#ifdef CUSTOMER_HW2
+int wifi_get_mac_addr(unsigned char *buf);
+#endif
+
+extern int dhd_preinit_ioctls(dhd_pub_t *dhd);
/* Packet alignment for most efficient SDIO (can change based on platform) */
#ifndef DHD_SDALIGN
@@ -193,7 +198,7 @@ done:
return ret;
}
-static int
+int
dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len)
{
dhd_prot_t *prot = dhd->prot;
@@ -510,270 +515,49 @@ 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) {
- dhd_os_proto_block(dhd);
- 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 */
- }
- dhd_os_proto_unblock(dhd);
- }
-
- 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)
+dhd_prot_init(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;
+ int ret = 0;
+ char buf[128];
#ifdef CUSTOMER_HW2
- uint roamvar = 0;
-#else
- uint roamvar = 1;
+ struct ether_addr ea_addr;
#endif
- uint power_mode = PM_FAST;
- uint32 dongle_align = DHD_SDALIGN;
- 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;
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
dhd_os_proto_block(dhd);
- /* Get the device MAC address */
- strcpy(iovbuf, "cur_etheraddr");
- if ((ret = dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf))) < 0) {
- DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
- dhd_os_proto_unblock(dhd);
- return BCME_NOTUP;
- }
- memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
- /* Set Country code */
- if (dhd->country_code[0] != 0) {
- if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_COUNTRY,
- dhd->country_code, sizeof(dhd->country_code)) < 0) {
- DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
+#ifdef CUSTOMER_HW2
+ /* Set the device MAC address if applicable */
+ ret = wifi_get_mac_addr(ea_addr.octet);
+ if (!ret) {
+ bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
+ ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf));
+ if (ret < 0) {
+ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
+ goto fail;
}
}
+#endif
- /* Set PowerSave mode */
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode));
-
- /* Match Host and Dongle rx alignment */
- bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
-
- /* 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));
- }
-
- /* 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);
-
- setbit(eventmask, WLC_E_SET_SSID);
- setbit(eventmask, WLC_E_PRUNE);
- setbit(eventmask, WLC_E_AUTH);
- setbit(eventmask, WLC_E_REASSOC);
- setbit(eventmask, WLC_E_REASSOC_IND);
- setbit(eventmask, WLC_E_DEAUTH_IND);
- setbit(eventmask, WLC_E_DISASSOC_IND);
- setbit(eventmask, WLC_E_DISASSOC);
- setbit(eventmask, WLC_E_JOIN);
- setbit(eventmask, WLC_E_ASSOC_IND);
- setbit(eventmask, WLC_E_PSK_SUP);
- setbit(eventmask, WLC_E_LINK);
- setbit(eventmask, WLC_E_NDIS_LINK);
- setbit(eventmask, WLC_E_MIC_ERROR);
- setbit(eventmask, WLC_E_PMKID_CACHE);
- setbit(eventmask, WLC_E_TXFAIL);
- setbit(eventmask, WLC_E_JOIN_START);
- setbit(eventmask, WLC_E_SCAN_COMPLETE);
-
- 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) {
- DHD_ERROR(("Mask and pattern not the same size\n"));
- dhd_os_proto_unblock(dhd);
- return -EINVAL;
+ /* Get the device MAC address */
+ strcpy(buf, "cur_etheraddr");
+ ret = dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf));
+ if (ret < 0) {
+ goto fail;
}
+ memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
- 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));
-
- dhd_os_proto_unblock(dhd);
- return 0;
-}
-
-int
-dhd_prot_init(dhd_pub_t *dhd)
-{
- int ret = 0;
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
-
+#ifdef EMBEDDED_PLATFORM
ret = dhd_preinit_ioctls(dhd);
+#endif /* EMBEDDED_PLATFORM */
/* Always assumes wl for now */
dhd->iswl = TRUE;
+fail:
+ dhd_os_proto_unblock(dhd);
+
return ret;
}
diff --git a/drivers/net/wireless/bcm4329/dhd_common.c b/drivers/net/wireless/bcm4329/dhd_common.c
index a0e6a7370d5d..1fd07215fe9b 100644
--- a/drivers/net/wireless/bcm4329/dhd_common.c
+++ b/drivers/net/wireless/bcm4329/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.41 2010/02/24 01:52:41 Exp $
+ * $Id: dhd_common.c,v 1.5.6.8.2.6.6.60 2010/05/26 03:36:55 Exp $
*/
#include <typedefs.h>
#include <osl.h>
@@ -38,6 +38,8 @@
#include <msgtrace.h>
+#include <wlioctl.h>
+
int dhd_msg_level;
char fw_path[MOD_PARAM_PATHLEN];
@@ -48,6 +50,25 @@ uint32 dhd_conn_event;
uint32 dhd_conn_status;
uint32 dhd_conn_reason;
+#define htod32(i) i
+#define htod16(i) i
+#define dtoh32(i) i
+#define dtoh16(i) i
+
+extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
+extern void dhd_ind_scan_confirm(void *h, bool status);
+extern int dhd_wl_ioctl(dhd_pub_t *dhd, uint cmd, char *buf, uint buflen);
+void dhd_iscan_lock(void);
+void dhd_iscan_unlock(void);
+
+/* Packet alignment for most efficient SDIO (can change based on platform) */
+#ifndef DHD_SDALIGN
+#define DHD_SDALIGN 32
+#endif
+#if !ISPOWEROF2(DHD_SDALIGN)
+#error DHD_SDALIGN is not a power of 2!
+#endif
+
#ifdef DHD_DEBUG
const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on "
__DATE__ " at " __TIME__;
@@ -57,7 +78,6 @@ const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR;
void dhd_set_timer(void *bus, uint wdtick);
-
/* IOVar table */
enum {
IOV_VERSION = 1,
@@ -66,6 +86,10 @@ enum {
IOV_BCMERROR,
IOV_WDTICK,
IOV_DUMP,
+#ifdef DHD_DEBUG
+ IOV_CONS,
+ IOV_DCONSOLE_POLL,
+#endif
IOV_CLEARCOUNTS,
IOV_LOGDUMP,
IOV_LOGCAL,
@@ -84,6 +108,10 @@ const bcm_iovar_t dhd_iovars[] = {
{"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 },
{"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 },
{"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
+#ifdef DHD_DEBUG
+ {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 },
+ {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 },
+#endif
{"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 },
{"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 },
{"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 },
@@ -223,6 +251,21 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
bcmerror = dhd_dump(dhd_pub, arg, len);
break;
+#ifdef DHD_DEBUG
+ case IOV_GVAL(IOV_DCONSOLE_POLL):
+ int_val = (int32)dhd_console_ms;
+ bcopy(&int_val, arg, val_size);
+ break;
+
+ case IOV_SVAL(IOV_DCONSOLE_POLL):
+ dhd_console_ms = (uint)int_val;
+ break;
+
+ case IOV_SVAL(IOV_CONS):
+ if (len > 0)
+ bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
+ break;
+#endif
case IOV_SVAL(IOV_CLEARCOUNTS):
dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
@@ -892,3 +935,759 @@ wl_event_to_host_order(wl_event_msg_t *evt)
evt->datalen = ntoh32(evt->datalen);
evt->version = ntoh16(evt->version);
}
+
+void print_buf(void *pbuf, int len, int bytes_per_line)
+{
+ int i, j = 0;
+ unsigned char *buf = pbuf;
+
+ if (bytes_per_line == 0) {
+ bytes_per_line = len;
+ }
+
+ for (i = 0; i < len; i++) {
+ printf("%2.2x", *buf++);
+ j++;
+ if (j == bytes_per_line) {
+ printf("\n");
+ j = 0;
+ } else {
+ printf(":");
+ }
+ }
+ printf("\n");
+}
+
+#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) {
+ DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
+ return -1;
+ }
+ src = src + 2; /* Skip past 0x */
+ if (strlen(src) % 2 != 0) {
+ DHD_ERROR(("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;
+}
+
+void
+dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode)
+{
+ char *argv[8];
+ int i = 0;
+ const char *str;
+ int buf_len;
+ int str_len;
+ char *arg_save = 0, *arg_org = 0;
+ int rc;
+ char buf[128];
+ wl_pkt_filter_enable_t enable_parm;
+ wl_pkt_filter_enable_t * pkt_filterp;
+
+ if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
+ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+ goto fail;
+ }
+ arg_org = arg_save;
+ memcpy(arg_save, arg, strlen(arg) + 1);
+
+ argv[i] = bcmstrtok(&arg_save, " ", 0);
+
+ i = 0;
+ if (NULL == argv[i]) {
+ DHD_ERROR(("No args provided\n"));
+ goto fail;
+ }
+
+ str = "pkt_filter_enable";
+ str_len = strlen(str);
+ strncpy(buf, str, str_len);
+ buf[str_len] = '\0';
+ buf_len = str_len + 1;
+
+ pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1);
+
+ /* Parse packet filter id. */
+ enable_parm.id = htod32(strtoul(argv[i], NULL, 0));
+
+ /* Parse enable/disable value. */
+ enable_parm.enable = htod32(enable);
+
+ buf_len += sizeof(enable_parm);
+ memcpy((char *)pkt_filterp,
+ &enable_parm,
+ sizeof(enable_parm));
+
+ /* Enable/disable the specified filter. */
+ rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len);
+ rc = rc >= 0 ? 0 : rc;
+ if (rc)
+ DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
+ __FUNCTION__, arg, rc));
+ else
+ DHD_TRACE(("%s: successfully added pktfilter %s\n",
+ __FUNCTION__, arg));
+
+ /* Contorl the master mode */
+ bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf));
+ rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf));
+ rc = rc >= 0 ? 0 : rc;
+ if (rc)
+ DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
+ __FUNCTION__, arg, rc));
+
+fail:
+ if (arg_org)
+ MFREE(dhd->osh, arg_org, strlen(arg) + 1);
+}
+
+void
+dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg)
+{
+ const char *str;
+ wl_pkt_filter_t pkt_filter;
+ wl_pkt_filter_t *pkt_filterp;
+ int buf_len;
+ int str_len;
+ int rc;
+ uint32 mask_size;
+ uint32 pattern_size;
+ char *argv[8], * buf = 0;
+ int i = 0;
+ char *arg_save = 0, *arg_org = 0;
+#define BUF_SIZE 2048
+
+ if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
+ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+ goto fail;
+ }
+
+ arg_org = arg_save;
+
+ if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) {
+ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+ goto fail;
+ }
+
+ memcpy(arg_save, arg, strlen(arg) + 1);
+
+ if (strlen(arg) > BUF_SIZE) {
+ DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf)));
+ goto fail;
+ }
+
+ argv[i] = bcmstrtok(&arg_save, " ", 0);
+ while (argv[i++])
+ argv[i] = bcmstrtok(&arg_save, " ", 0);
+
+ i = 0;
+ if (NULL == argv[i]) {
+ DHD_ERROR(("No args provided\n"));
+ goto fail;
+ }
+
+ 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(strtoul(argv[i], NULL, 0));
+
+ if (NULL == argv[++i]) {
+ DHD_ERROR(("Polarity not provided\n"));
+ goto fail;
+ }
+
+ /* Parse filter polarity. */
+ pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0));
+
+ if (NULL == argv[++i]) {
+ DHD_ERROR(("Filter type not provided\n"));
+ goto fail;
+ }
+
+ /* Parse filter type. */
+ pkt_filter.type = htod32(strtoul(argv[i], NULL, 0));
+
+ if (NULL == argv[++i]) {
+ DHD_ERROR(("Offset not provided\n"));
+ goto fail;
+ }
+
+ /* Parse pattern filter offset. */
+ pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0));
+
+ if (NULL == argv[++i]) {
+ DHD_ERROR(("Bitmask not provided\n"));
+ goto fail;
+ }
+
+ /* Parse pattern filter mask. */
+ mask_size =
+ htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern));
+
+ if (NULL == argv[++i]) {
+ DHD_ERROR(("Pattern not provided\n"));
+ goto fail;
+ }
+
+ /* Parse pattern filter pattern. */
+ pattern_size =
+ htod32(wl_pattern_atoh(argv[i],
+ (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
+
+ if (mask_size != pattern_size) {
+ DHD_ERROR(("Mask and pattern not the same size\n"));
+ goto fail;
+ }
+
+ 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);
+
+ rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len);
+ rc = rc >= 0 ? 0 : rc;
+
+ if (rc)
+ DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
+ __FUNCTION__, arg, rc));
+ else
+ DHD_TRACE(("%s: successfully added pktfilter %s\n",
+ __FUNCTION__, arg));
+
+fail:
+ if (arg_org)
+ MFREE(dhd->osh, arg_org, strlen(arg) + 1);
+
+ if (buf)
+ MFREE(dhd->osh, buf, BUF_SIZE);
+}
+
+void
+dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode)
+{
+ char iovbuf[32];
+ int retcode;
+
+ bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
+ retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+ retcode = retcode >= 0 ? 0 : retcode;
+ if (retcode)
+ DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
+ __FUNCTION__, arp_mode, retcode));
+ else
+ DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
+ __FUNCTION__, arp_mode));
+}
+
+void
+dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable)
+{
+ char iovbuf[32];
+ int retcode;
+
+ bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
+ retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+ retcode = retcode >= 0 ? 0 : retcode;
+ if (retcode)
+ DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
+ __FUNCTION__, arp_enable, retcode));
+ else
+ DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
+ __FUNCTION__, arp_enable));
+}
+
+int
+dhd_preinit_ioctls(dhd_pub_t *dhd)
+{
+ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+ uint up = 0;
+ char buf[128], *ptr;
+ uint power_mode = PM_FAST;
+ uint32 dongle_align = DHD_SDALIGN;
+ uint32 glom = 0;
+ uint bcn_timeout = 3;
+ int scan_assoc_time = 40;
+ int scan_unassoc_time = 80;
+
+ /* Set Country code */
+ if (dhd->country_code[0] != 0) {
+ if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_COUNTRY,
+ dhd->country_code, sizeof(dhd->country_code)) < 0) {
+ DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
+ }
+ }
+
+ /* query for 'ver' to get version info from firmware */
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ bcm_mkiovar("ver", 0, 0, buf, sizeof(buf));
+ dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf));
+ bcmstrtok(&ptr, "\n", 0);
+ /* Print fw version info */
+ DHD_ERROR(("Firmware version = %s\n", buf));
+
+ /* Set PowerSave mode */
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode));
+
+ /* Match Host and Dongle rx alignment */
+ bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+
+ /* 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 */
+ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+
+ /* Enable/Disable build-in roaming to allowed ext supplicant to take of romaing */
+ bcm_mkiovar("roam_off", (char *)&dhd_roam, 4, iovbuf, sizeof(iovbuf));
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+
+ /* Force STA UP */
+ if (dhd_radio_up)
+ dhdcdc_set_ioctl(dhd, 0, WLC_UP, (char *)&up, sizeof(up));
+
+ /* Setup event_msgs */
+ bcm_mkiovar("event_msgs", dhd->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));
+
+#ifdef ARP_OFFLOAD_SUPPORT
+ /* Set and enable ARP offload feature */
+ if (dhd_arp_enable)
+ dhd_arp_offload_set(dhd, dhd_arp_mode);
+ dhd_arp_offload_enable(dhd, dhd_arp_enable);
+#endif /* ARP_OFFLOAD_SUPPORT */
+
+#ifdef PKT_FILTER_SUPPORT
+ {
+ int i;
+ /* Set up pkt filter */
+ if (dhd_pkt_filter_enable) {
+ for (i = 0; i < dhd->pktfilter_count; i++) {
+ dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
+ dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
+ dhd_pkt_filter_init, dhd_master_mode);
+ }
+ }
+ }
+#endif /* PKT_FILTER_SUPPORT */
+
+ return 0;
+}
+
+#ifdef SIMPLE_ISCAN
+
+uint iscan_thread_id;
+iscan_buf_t * iscan_chain = 0;
+
+iscan_buf_t *
+dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf)
+{
+ iscan_buf_t *iscanbuf_alloc = 0;
+ iscan_buf_t *iscanbuf_head;
+
+ dhd_iscan_lock();
+
+ iscanbuf_alloc = (iscan_buf_t*)MALLOC(dhd->osh, sizeof(iscan_buf_t));
+ if (iscanbuf_alloc == NULL)
+ goto fail;
+
+ iscanbuf_alloc->next = NULL;
+ iscanbuf_head = *iscanbuf;
+
+ DHD_ISCAN(("%s: addr of allocated node = 0x%X, addr of iscanbuf_head \
+ = 0x%X dhd = 0x%X\n", __FUNCTION__, iscanbuf_alloc,
+ iscanbuf_head, dhd));
+
+ if (iscanbuf_head == NULL) {
+ *iscanbuf = iscanbuf_alloc;
+ DHD_ISCAN(("%s: Head is allocated\n", __FUNCTION__));
+ goto fail;
+ }
+
+ while (iscanbuf_head->next)
+ iscanbuf_head = iscanbuf_head->next;
+
+ iscanbuf_head->next = iscanbuf_alloc;
+
+fail:
+ dhd_iscan_unlock();
+ return iscanbuf_alloc;
+}
+
+void
+dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete)
+{
+ iscan_buf_t *iscanbuf_free = 0;
+ iscan_buf_t *iscanbuf_prv = 0;
+ iscan_buf_t *iscanbuf_cur = iscan_chain;
+ dhd_pub_t *dhd = dhd_bus_pub(dhdp);
+
+ dhd_iscan_lock();
+ /* If iscan_delete is null then delete the entire
+ * chain or else delete specific one provided
+ */
+ if (!iscan_delete) {
+ while (iscanbuf_cur) {
+ iscanbuf_free = iscanbuf_cur;
+ iscanbuf_cur = iscanbuf_cur->next;
+ iscanbuf_free->next = 0;
+ MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t));
+ }
+ iscan_chain = 0;
+ } else {
+ while (iscanbuf_cur) {
+ if (iscanbuf_cur == iscan_delete)
+ break;
+ iscanbuf_prv = iscanbuf_cur;
+ iscanbuf_cur = iscanbuf_cur->next;
+ }
+ if (iscanbuf_prv)
+ iscanbuf_prv->next = iscan_delete->next;
+
+ iscan_delete->next = 0;
+ MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t));
+
+ if (!iscanbuf_prv)
+ iscan_chain = 0;
+ }
+ dhd_iscan_unlock();
+}
+
+iscan_buf_t *
+dhd_iscan_result_buf(void)
+{
+ return iscan_chain;
+}
+
+
+
+/*
+* print scan cache
+* print partial iscan_skip list differently
+*/
+int
+dhd_iscan_print_cache(iscan_buf_t *iscan_skip)
+{
+ int i = 0, l = 0;
+ iscan_buf_t *iscan_cur;
+ wl_iscan_results_t *list;
+ wl_scan_results_t *results;
+ wl_bss_info_t UNALIGNED *bi;
+
+ dhd_iscan_lock();
+
+ iscan_cur = dhd_iscan_result_buf();
+
+ while (iscan_cur) {
+ list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
+ if (!list)
+ break;
+
+ results = (wl_scan_results_t *)&list->results;
+ if (!results)
+ break;
+
+ if (results->version != WL_BSS_INFO_VERSION) {
+ DHD_ISCAN(("%s: results->version %d != WL_BSS_INFO_VERSION\n",
+ __FUNCTION__, results->version));
+ goto done;
+ }
+
+ bi = results->bss_info;
+ for (i = 0; i < results->count; i++) {
+ if (!bi)
+ break;
+
+ DHD_ISCAN(("%s[%2.2d:%2.2d] %X:%X:%X:%X:%X:%X\n",
+ iscan_cur != iscan_skip?"BSS":"bss", l, i,
+ bi->BSSID.octet[0], bi->BSSID.octet[1], bi->BSSID.octet[2],
+ bi->BSSID.octet[3], bi->BSSID.octet[4], bi->BSSID.octet[5]));
+
+ bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
+ }
+ iscan_cur = iscan_cur->next;
+ l++;
+ }
+
+done:
+ dhd_iscan_unlock();
+ return 0;
+}
+
+/*
+* delete disappeared AP from specific scan cache but skip partial list in iscan_skip
+*/
+int
+dhd_iscan_delete_bss(void *dhdp, void *addr, iscan_buf_t *iscan_skip)
+{
+ int i = 0, j = 0, l = 0;
+ iscan_buf_t *iscan_cur;
+ wl_iscan_results_t *list;
+ wl_scan_results_t *results;
+ wl_bss_info_t UNALIGNED *bi, *bi_new, *bi_next;
+
+ uchar *s_addr = addr;
+
+ dhd_iscan_lock();
+ DHD_ISCAN(("%s: BSS to remove %X:%X:%X:%X:%X:%X\n",
+ __FUNCTION__, s_addr[0], s_addr[1], s_addr[2],
+ s_addr[3], s_addr[4], s_addr[5]));
+
+ iscan_cur = dhd_iscan_result_buf();
+
+ while (iscan_cur) {
+ if (iscan_cur != iscan_skip) {
+ list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
+ if (!list)
+ break;
+
+ results = (wl_scan_results_t *)&list->results;
+ if (!results)
+ break;
+
+ if (results->version != WL_BSS_INFO_VERSION) {
+ DHD_ERROR(("%s: results->version %d != WL_BSS_INFO_VERSION\n",
+ __FUNCTION__, results->version));
+ goto done;
+ }
+
+ bi = results->bss_info;
+ for (i = 0; i < results->count; i++) {
+ if (!bi)
+ break;
+
+ if (!memcmp(bi->BSSID.octet, addr, ETHER_ADDR_LEN)) {
+ DHD_ISCAN(("%s: Del BSS[%2.2d:%2.2d] %X:%X:%X:%X:%X:%X\n", \
+ __FUNCTION__, l, i, bi->BSSID.octet[0], \
+ bi->BSSID.octet[1], bi->BSSID.octet[2], \
+ bi->BSSID.octet[3], bi->BSSID.octet[4], \
+ bi->BSSID.octet[5]));
+
+ bi_new = bi;
+ bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
+/*
+ if(bi && bi_new) {
+ bcopy(bi, bi_new, results->buflen -
+ dtoh32(bi_new->length));
+ results->buflen -= dtoh32(bi_new->length);
+ }
+*/
+ results->buflen -= dtoh32(bi_new->length);
+ results->count--;
+
+ for (j = i; j < results->count; j++) {
+ if (bi && bi_new) {
+ DHD_ISCAN(("%s: Moved up BSS[%2.2d:%2.2d] \
+ %X:%X:%X:%X:%X:%X\n",
+ __FUNCTION__, l, j, bi->BSSID.octet[0],
+ bi->BSSID.octet[1], bi->BSSID.octet[2],
+ bi->BSSID.octet[3], bi->BSSID.octet[4],
+ bi->BSSID.octet[5]));
+
+ bi_next = (wl_bss_info_t *)((uintptr)bi +
+ dtoh32(bi->length));
+ bcopy(bi, bi_new, dtoh32(bi->length));
+ bi_new = (wl_bss_info_t *)((uintptr)bi_new +
+ dtoh32(bi_new->length));
+ bi = bi_next;
+ }
+ }
+
+ if (results->count == 0) {
+ /* Prune now empty partial scan list */
+ dhd_iscan_free_buf(dhdp, iscan_cur);
+ goto done;
+ }
+ break;
+ }
+ bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
+ }
+ }
+ iscan_cur = iscan_cur->next;
+ l++;
+ }
+
+done:
+ dhd_iscan_unlock();
+ return 0;
+}
+
+int
+dhd_iscan_remove_duplicates(void * dhdp, iscan_buf_t *iscan_cur)
+{
+ int i = 0;
+ wl_iscan_results_t *list;
+ wl_scan_results_t *results;
+ wl_bss_info_t UNALIGNED *bi, *bi_new, *bi_next;
+
+ dhd_iscan_lock();
+
+ DHD_ISCAN(("%s: Scan cache before delete\n",
+ __FUNCTION__));
+ dhd_iscan_print_cache(iscan_cur);
+
+ if (!iscan_cur)
+ goto done;
+
+ list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
+ if (!list)
+ goto done;
+
+ results = (wl_scan_results_t *)&list->results;
+ if (!results)
+ goto done;
+
+ if (results->version != WL_BSS_INFO_VERSION) {
+ DHD_ERROR(("%s: results->version %d != WL_BSS_INFO_VERSION\n",
+ __FUNCTION__, results->version));
+ goto done;
+ }
+
+ bi = results->bss_info;
+ for (i = 0; i < results->count; i++) {
+ if (!bi)
+ break;
+
+ DHD_ISCAN(("%s: Find dups for BSS[%2.2d] %X:%X:%X:%X:%X:%X\n",
+ __FUNCTION__, i, bi->BSSID.octet[0], bi->BSSID.octet[1], bi->BSSID.octet[2],
+ bi->BSSID.octet[3], bi->BSSID.octet[4], bi->BSSID.octet[5]));
+
+ dhd_iscan_delete_bss(dhdp, bi->BSSID.octet, iscan_cur);
+
+ bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
+ }
+
+done:
+ DHD_ISCAN(("%s: Scan cache after delete\n", __FUNCTION__));
+ dhd_iscan_print_cache(iscan_cur);
+ dhd_iscan_unlock();
+ return 0;
+}
+
+void
+dhd_iscan_ind_scan_confirm(void *dhdp, bool status)
+{
+
+ dhd_ind_scan_confirm(dhdp, status);
+}
+
+int
+dhd_iscan_request(void * dhdp, uint16 action)
+{
+ int rc;
+ wl_iscan_params_t params;
+ dhd_pub_t *dhd = dhd_bus_pub(dhdp);
+ char buf[WLC_IOCTL_SMLEN];
+
+
+ memset(&params, 0, sizeof(wl_iscan_params_t));
+ memcpy(&params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
+
+ params.params.bss_type = DOT11_BSSTYPE_ANY;
+ params.params.scan_type = DOT11_SCANTYPE_ACTIVE;
+
+ params.params.nprobes = htod32(-1);
+ params.params.active_time = htod32(-1);
+ params.params.passive_time = htod32(-1);
+ params.params.home_time = htod32(-1);
+ params.params.channel_num = htod32(0);
+
+ params.version = htod32(ISCAN_REQ_VERSION);
+ params.action = htod16(action);
+ params.scan_duration = htod16(0);
+
+ bcm_mkiovar("iscan", (char *)&params, sizeof(wl_iscan_params_t), buf, WLC_IOCTL_SMLEN);
+ rc = dhd_wl_ioctl(dhdp, WLC_SET_VAR, buf, WLC_IOCTL_SMLEN);
+
+ return rc;
+}
+
+static int
+dhd_iscan_get_partial_result(void *dhdp, uint *scan_count)
+{
+ wl_iscan_results_t *list_buf;
+ wl_iscan_results_t list;
+ wl_scan_results_t *results;
+ iscan_buf_t *iscan_cur;
+ int status = -1;
+ dhd_pub_t *dhd = dhd_bus_pub(dhdp);
+ int rc;
+
+
+ iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain);
+ if (!iscan_cur) {
+ DHD_ERROR(("%s: Failed to allocate node\n", __FUNCTION__));
+ dhd_iscan_free_buf(dhdp, 0);
+ dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT);
+ goto fail;
+ }
+
+ dhd_iscan_lock();
+
+ memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
+ list_buf = (wl_iscan_results_t*)iscan_cur->iscan_buf;
+ results = &list_buf->results;
+ results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
+ results->version = 0;
+ results->count = 0;
+
+ memset(&list, 0, sizeof(list));
+ list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
+ bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE,
+ iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
+ rc = dhd_wl_ioctl(dhdp, WLC_GET_VAR, iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
+
+ results->buflen = dtoh32(results->buflen);
+ results->version = dtoh32(results->version);
+ *scan_count = results->count = dtoh32(results->count);
+ status = dtoh32(list_buf->status);
+
+ dhd_iscan_unlock();
+
+ if (!(*scan_count))
+ dhd_iscan_free_buf(dhdp, iscan_cur);
+ else
+ dhd_iscan_remove_duplicates(dhdp, iscan_cur);
+
+
+fail:
+ return status;
+}
+
+#endif
diff --git a/drivers/net/wireless/bcm4329/dhd_dbg.h b/drivers/net/wireless/bcm4329/dhd_dbg.h
index e6d18f7abfb1..b48c1d70f144 100644
--- a/drivers/net/wireless/bcm4329/dhd_dbg.h
+++ b/drivers/net/wireless/bcm4329/dhd_dbg.h
@@ -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_dbg.h,v 1.5.6.2.4.2.14.4 2009/12/11 01:13:49 Exp $
+ * $Id: dhd_dbg.h,v 1.5.6.2.4.2.14.10 2010/05/21 21:49:38 Exp $
*/
#ifndef _dhd_dbg_
@@ -42,6 +42,7 @@
#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0)
#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0)
#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0)
+#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0)
#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL)
#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL)
@@ -55,6 +56,7 @@
#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL)
#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL)
#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL)
+#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL)
#else /* DHD_DEBUG */
@@ -70,6 +72,7 @@
#define DHD_GLOM(args)
#define DHD_EVENT(args)
#define DHD_BTA(args)
+#define DHD_ISCAN(args)
#define DHD_ERROR_ON() 0
#define DHD_TRACE_ON() 0
@@ -83,7 +86,7 @@
#define DHD_GLOM_ON() 0
#define DHD_EVENT_ON() 0
#define DHD_BTA_ON() 0
-
+#define DHD_ISCAN_ON() 0
#endif /* DHD_DEBUG */
#define DHD_LOG(args)
diff --git a/drivers/net/wireless/bcm4329/dhd_linux.c b/drivers/net/wireless/bcm4329/dhd_linux.c
index a9dcb3ba3192..5a0a8892cd19 100644
--- a/drivers/net/wireless/bcm4329/dhd_linux.c
+++ b/drivers/net/wireless/bcm4329/dhd_linux.c
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.66 2010/04/01 17:01:25 Exp $
+ * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.86 2010/05/18 05:48:53 Exp $
*/
#ifdef CONFIG_WIFI_CONTROL_FUNC
@@ -115,6 +115,17 @@ int wifi_set_reset(int on, unsigned long msec)
return 0;
}
+int wifi_get_mac_addr(unsigned char *buf)
+{
+ printk("%s\n", __FUNCTION__);
+ if (!buf)
+ return -EINVAL;
+ if (wifi_control_data && wifi_control_data->get_mac_addr) {
+ return wifi_control_data->get_mac_addr(buf);
+ }
+ return -EOPNOTSUPP;
+}
+
static int wifi_probe(struct platform_device *pdev)
{
struct wifi_platform_data *wifi_ctrl =
@@ -204,10 +215,13 @@ print_tainted()
/* Linux wireless extension support */
#if defined(CONFIG_WIRELESS_EXT)
#include <wl_iw.h>
-#endif
+#endif /* defined(CONFIG_WIRELESS_EXT) */
#if defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
+extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
+extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
+extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
/* Interface control information */
@@ -229,7 +243,7 @@ typedef struct dhd_if {
typedef struct dhd_info {
#if defined(CONFIG_WIRELESS_EXT)
wl_iw_t iw; /* wireless extensions state (must be first) */
-#endif
+#endif /* defined(CONFIG_WIRELESS_EXT) */
dhd_pub_t pub;
@@ -285,7 +299,8 @@ char nvram_path[MOD_PARAM_PATHLEN];
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
struct semaphore dhd_registration_sem;
-#endif
+#define DHD_REGISTRATION_TIMEOUT 8000 /* msec : allowed time to finished dhd registration */
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
/* 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);
@@ -305,7 +320,27 @@ module_param(dhd_watchdog_ms, uint, 0);
/* Console poll interval */
uint dhd_console_ms = 0;
module_param(dhd_console_ms, uint, 0);
-#endif
+#endif /* DHD_DEBUG */
+
+/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */
+uint dhd_arp_mode = 0xb;
+module_param(dhd_arp_mode, uint, 0);
+
+/* ARP offload enable */
+uint dhd_arp_enable = TRUE;
+module_param(dhd_arp_enable, uint, 0);
+
+/* Global Pkt filter enable control */
+uint dhd_pkt_filter_enable = TRUE;
+module_param(dhd_pkt_filter_enable, uint, 0);
+
+/* Pkt filter init setup */
+uint dhd_pkt_filter_init = 0;
+module_param(dhd_pkt_filter_init, uint, 0);
+
+/* Pkt filter mode control */
+uint dhd_master_mode = TRUE;
+module_param(dhd_master_mode, uint, 1);
/* Watchdog thread priority, -1 to use kernel timer */
int dhd_watchdog_prio = 97;
@@ -319,6 +354,16 @@ module_param(dhd_dpc_prio, int, 0);
extern int dhd_dongle_memsize;
module_param(dhd_dongle_memsize, int, 0);
+/* Contorl fw roaming */
+#ifdef CUSTOMER_HW2
+uint dhd_roam = 0;
+#else
+uint dhd_roam = 1;
+#endif
+
+/* Control radio state */
+uint dhd_radio_up = 1;
+
/* Network inteface name */
char iface_name[IFNAMSIZ];
module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
@@ -404,7 +449,7 @@ static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
#if defined(CONFIG_WIRELESS_EXT)
struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
-#endif
+#endif /* defined(CONFIG_WIRELESS_EXT) */
static void dhd_dpc(ulong data);
/* forward decl */
@@ -448,7 +493,78 @@ extern int unregister_pm_notifier(struct notifier_block *nb);
#if defined(CONFIG_HAS_EARLYSUSPEND)
-extern int dhd_set_suspend(int value, dhd_pub_t *dhd);
+
+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 */
+ int i;
+
+#define htod32(i) i
+
+ if (dhd && dhd->up) {
+ dhd_os_proto_block(dhd);
+ if (value) {
+
+ /* Kernel suspended */
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM,
+ (char *)&power_mode, sizeof(power_mode));
+
+ /* Enable packet filter, only allow unicast packet to send up */
+ if (dhd_pkt_filter_enable) {
+ for (i = 0; i < dhd->pktfilter_count; i++) {
+ dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
+ dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
+ 1, dhd_master_mode);
+ }
+ }
+
+ /* 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 {
+
+ /* Kernel resumed */
+ power_mode = PM_FAST;
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode,
+ sizeof(power_mode));
+
+ /* disable pkt filter */
+ if (dhd_pkt_filter_enable) {
+ for (i = 0; i < dhd->pktfilter_count; i++) {
+ dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
+ dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
+ 0, dhd_master_mode);
+ }
+ }
+
+ /* 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 */
+ }
+ dhd_os_proto_unblock(dhd);
+ }
+
+ return 0;
+}
static void dhd_early_suspend(struct early_suspend *h)
{
@@ -1203,9 +1319,11 @@ dhd_watchdog_thread(void *data)
while (1) {
if (down_interruptible (&dhd->watchdog_sem) == 0) {
dhd_os_wake_lock(&dhd->pub);
- /* Call the bus module watchdog */
- dhd_bus_watchdog(&dhd->pub);
+ if (dhd->pub.dongle_reset == FALSE) {
+ /* Call the bus module watchdog */
+ dhd_bus_watchdog(&dhd->pub);
+ }
/* Count the tick for reference */
dhd->pub.tickcnt++;
@@ -1239,12 +1357,8 @@ dhd_watchdog(ulong data)
dhd->pub.tickcnt++;
/* Reschedule the watchdog */
-#if defined(CONTINUOUS_WATCHDOG)
- mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
-#else
if (dhd->wd_timer_valid)
mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
-#endif /* defined(CONTINUOUS_WATCHDOG) */
}
static int
@@ -1545,7 +1659,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
/* may recurse, do NOT lock */
return wl_iw_ioctl(net, ifr, cmd);
}
-#endif
+#endif /* defined(CONFIG_WIRELESS_EXT) */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
if (cmd == SIOCETHTOOL)
@@ -1721,7 +1835,7 @@ dhd_osl_detach(osl_t *osh)
osl_detach(osh);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1
up(&dhd_registration_sem);
-#endif
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
}
int
@@ -1869,7 +1983,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
DHD_ERROR(("wl_iw_attach failed\n"));
goto fail;
}
-#endif
+#endif /* defined(CONFIG_WIRELESS_EXT) */
/* Set up the watchdog timer */
init_timer(&dhd->timer);
@@ -1949,6 +2063,9 @@ dhd_bus_start(dhd_pub_t *dhdp)
{
int ret = -1;
dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
+#ifdef EMBEDDED_PLATFORM
+ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+#endif /* EMBEDDED_PLATFORM */
ASSERT(dhd);
@@ -1994,6 +2111,35 @@ dhd_bus_start(dhd_pub_t *dhdp)
return -ENODEV;
}
+#ifdef EMBEDDED_PLATFORM
+ bcm_mkiovar("event_msgs", dhdp->eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
+ dhdcdc_query_ioctl(dhdp, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf));
+ bcopy(iovbuf, dhdp->eventmask, WL_EVENTING_MASK_LEN);
+
+ setbit(dhdp->eventmask, WLC_E_SET_SSID);
+ setbit(dhdp->eventmask, WLC_E_PRUNE);
+ setbit(dhdp->eventmask, WLC_E_AUTH);
+ setbit(dhdp->eventmask, WLC_E_REASSOC);
+ setbit(dhdp->eventmask, WLC_E_REASSOC_IND);
+ setbit(dhdp->eventmask, WLC_E_DEAUTH_IND);
+ setbit(dhdp->eventmask, WLC_E_DISASSOC_IND);
+ setbit(dhdp->eventmask, WLC_E_DISASSOC);
+ setbit(dhdp->eventmask, WLC_E_JOIN);
+ setbit(dhdp->eventmask, WLC_E_ASSOC_IND);
+ setbit(dhdp->eventmask, WLC_E_PSK_SUP);
+ setbit(dhdp->eventmask, WLC_E_LINK);
+ setbit(dhdp->eventmask, WLC_E_NDIS_LINK);
+ setbit(dhdp->eventmask, WLC_E_MIC_ERROR);
+ setbit(dhdp->eventmask, WLC_E_PMKID_CACHE);
+ setbit(dhdp->eventmask, WLC_E_TXFAIL);
+ setbit(dhdp->eventmask, WLC_E_JOIN_START);
+ setbit(dhdp->eventmask, WLC_E_SCAN_COMPLETE);
+
+ dhdp->pktfilter_count = 1;
+ /* Setup filter to allow only unicast */
+ dhdp->pktfilter[0] = "100 0 0 0 0xff 0x00";
+#endif /* EMBEDDED_PLATFORM */
+
/* Bus is ready, do any protocol initialization */
if ((ret = dhd_prot_init(&dhd->pub)) < 0)
return ret;
@@ -2242,6 +2388,19 @@ dhd_detach(dhd_pub_t *dhdp)
}
}
+static void __exit
+dhd_module_cleanup(void)
+{
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ dhd_bus_unregister();
+#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);
+}
+
static int __init
dhd_module_init(void)
{
@@ -2301,7 +2460,7 @@ dhd_module_init(void)
* 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(10000)) != 0) {
+ if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) {
error = -EINVAL;
DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__));
goto fail_2;
@@ -2324,20 +2483,6 @@ fail_0:
return error;
}
-static void __exit
-dhd_module_cleanup(void)
-{
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- dhd_bus_unregister();
-#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);
@@ -2703,6 +2848,43 @@ dhd_wait_pend8021x(struct net_device *dev)
return pend;
}
+#ifdef DHD_DEBUG
+int
+write_to_file(dhd_pub_t *dhd, uint8 *buf, int size)
+{
+ int ret = 0;
+ struct file *fp;
+ mm_segment_t old_fs;
+ loff_t pos = 0;
+
+ /* change to KERNEL_DS address limit */
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ /* open file to write */
+ fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640);
+ if (!fp) {
+ printf("%s: open file error\n", __FUNCTION__);
+ ret = -1;
+ goto exit;
+ }
+
+ /* Write buf to file */
+ fp->f_op->write(fp, buf, size, &pos);
+
+exit:
+ /* free buf before return */
+ MFREE(dhd->osh, buf, size);
+ /* close file before return */
+ if (fp)
+ filp_close(fp, current->files);
+ /* restore previous address limit */
+ set_fs(old_fs);
+
+ return ret;
+}
+#endif /* DHD_DEBUG */
+
int dhd_os_wake_lock_timeout(dhd_pub_t *pub)
{
dhd_info_t *dhd = (dhd_info_t *)(pub->info);
diff --git a/drivers/net/wireless/bcm4329/dhd_proto.h b/drivers/net/wireless/bcm4329/dhd_proto.h
index 1e2401acd403..382785a1ff6b 100644
--- a/drivers/net/wireless/bcm4329/dhd_proto.h
+++ b/drivers/net/wireless/bcm4329/dhd_proto.h
@@ -4,7 +4,7 @@
* Provides type definitions and function prototypes used to link the
* DHD OS, bus, and protocol modules.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -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_proto.h,v 1.2.82.1.4.1.16.6 2009/06/17 01:01:55 Exp $
+ * $Id: dhd_proto.h,v 1.2.82.1.4.1.16.7 2010/05/10 12:54:59 Exp $
*/
#ifndef _dhd_proto_h_
@@ -37,6 +37,10 @@
#define IOCTL_RESP_TIMEOUT 2000 /* In milli second */
#endif
+#ifndef IOCTL_CHIP_ACTIVE_TIMEOUT
+#define IOCTL_CHIP_ACTIVE_TIMEOUT 10 /* In milli second */
+#endif
+
/*
* Exported from the dhd protocol module (dhd_cdc, dhd_rndis)
*/
diff --git a/drivers/net/wireless/bcm4329/dhd_sdio.c b/drivers/net/wireless/bcm4329/dhd_sdio.c
index d94c70a7b47b..e41c8ef8d7f8 100644
--- a/drivers/net/wireless/bcm4329/dhd_sdio.c
+++ b/drivers/net/wireless/bcm4329/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.109.2.2 2010/05/18 01:13:11 Exp $
+ * $Id: dhd_sdio.c,v 1.157.2.27.2.33.2.123 2010/05/18 05:48:53 Exp $
*/
#include <typedefs.h>
@@ -953,7 +953,6 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
(((pad + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
#ifdef DHD_DEBUG
tx_packets[PKTPRIO(pkt)]++;
@@ -1019,6 +1018,9 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
}
}
+ if (ret == 0) {
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+ }
} while ((ret < 0) && retrydata && retries++ < TXRETRIES);
done:
@@ -1106,7 +1108,8 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
/* Otherwise, send it now */
BUS_WAKE(bus);
- dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
+ /* Make sure back plane ht clk is on, no pending allowed */
+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
#ifndef SDTEST
DHD_TRACE(("%s: calling txpkt\n", __FUNCTION__));
@@ -1260,6 +1263,8 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
if (!DATAOK(bus)) {
+ DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
+ __FUNCTION__, bus->tx_max, bus->tx_seq));
bus->ctrl_frame_stat = TRUE;
/* Send from dpc */
bus->ctrl_frame_buf = frame;
@@ -1267,15 +1272,16 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
- if (bus->ctrl_frame_stat == FALSE)
+ if (bus->ctrl_frame_stat == FALSE) {
+ DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
ret = 0;
- else
+ } else {
+ DHD_INFO(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__));
ret = -1;
+ }
}
if (ret == -1) {
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
-
#ifdef DHD_DEBUG
if (DHD_BYTES_ON() && DHD_CTL_ON()) {
prhex("Tx Frame", frame, len);
@@ -1285,6 +1291,7 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
#endif
do {
+ bus->ctrl_frame_stat = FALSE;
ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
frame, len, NULL, NULL, NULL);
ASSERT(ret != BCME_PENDING);
@@ -1313,6 +1320,9 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
}
}
+ if (ret == 0) {
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+ }
} while ((ret < 0) && retries++ < TXRETRIES);
}
@@ -1723,83 +1733,7 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
return BCME_OK;
}
-#endif
-
-#define CONSOLE_LINE_MAX 192
-#ifdef DHD_DEBUG
-static int
-dhdsdio_readconsole(dhd_bus_t *bus)
-{
- dhd_console_t *c = &bus->console;
- uint8 line[CONSOLE_LINE_MAX], ch;
- uint32 n, idx, addr;
- int rv;
-
- /* Don't do anything until FWREADY updates console address */
- if (bus->console_addr == 0)
- return 0;
-
- /* Read console log struct */
- addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
- if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
- return rv;
-
- /* Allocate console buffer (one time only) */
- if (c->buf == NULL) {
- c->bufsize = ltoh32(c->log.buf_size);
- if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
- return BCME_NOMEM;
- }
-
- idx = ltoh32(c->log.idx);
-
- /* Protect against corrupt value */
- if (idx > c->bufsize)
- return BCME_ERROR;
-
- /* Skip reading the console buffer if the index pointer has not moved */
- if (idx == c->last)
- return BCME_OK;
-
- /* Read the console buffer */
- addr = ltoh32(c->log.buf);
- if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
- return rv;
-
- while (c->last != idx) {
- for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
- if (c->last == idx) {
- /* This would output a partial line. Instead, back up
- * the buffer pointer and output this line next time around.
- */
- if (c->last >= n)
- c->last -= n;
- else
- c->last = c->bufsize - n;
- goto break2;
- }
- ch = c->buf[c->last];
- c->last = (c->last + 1) % c->bufsize;
- if (ch == '\n')
- break;
- line[n] = ch;
- }
-
- if (n > 0) {
- if (line[n - 1] == '\r')
- n--;
- line[n] = 0;
- printf("CONSOLE: %s\n", line);
- }
- }
-break2:
-
- return BCME_OK;
-}
-#endif
-
-#ifdef DHD_DEBUG_TRAP
static int
dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size)
{
@@ -1892,7 +1826,7 @@ dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size)
goto done;
bcm_bprintf(&strbuf,
- "Dongle trap type 0x%x @ pc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
+ "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
"lp 0x%x, rpc 0x%x Trap offset 0x%x, "
"r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n",
tr.type, tr.epc, tr.cpsr, tr.spsr, tr.r13, tr.r14, tr.pc,
@@ -1923,10 +1857,131 @@ static int
dhdsdio_mem_dump(dhd_bus_t *bus)
{
int ret = 0;
- return ret;
+ int size; /* Full mem size */
+ int start = 0; /* Start address */
+ int read_size = 0; /* Read size of each iteration */
+ uint8 *buf = NULL, *databuf = NULL;
+
+ /* Get full mem size */
+ size = bus->ramsize;
+ buf = MALLOC(bus->dhd->osh, size);
+ if (!buf) {
+ printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size);
+ return -1;
+ }
+
+ /* Read mem content */
+ printf("Dump dongle memory");
+ databuf = buf;
+ while (size)
+ {
+ read_size = MIN(MEMBLOCK, size);
+ if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size)))
+ {
+ printf("%s: Error membytes %d\n", __FUNCTION__, ret);
+ if (buf) {
+ MFREE(bus->dhd->osh, buf, size);
+ }
+ return -1;
+ }
+ printf(".");
+
+ /* Decrement size and increment start address */
+ size -= read_size;
+ start += read_size;
+ databuf += read_size;
+ }
+ printf("Done\n");
+
+#ifdef DHD_DEBUG
+ /* free buf before return !!! */
+ if (write_to_file(bus->dhd, buf, bus->ramsize))
+ {
+ printf("%s: Error writing to files\n", __FUNCTION__);
+ return -1;
+ }
+ /* buf free handled in write_to_file, not here */
+#else
+ MFREE(bus->dhd->osh, buf, size);
+#endif
+ return 0;
}
#endif /* DHD_DEBUG_TRAP */
+#ifdef DHD_DEBUG
+#define CONSOLE_LINE_MAX 192
+
+static int
+dhdsdio_readconsole(dhd_bus_t *bus)
+{
+ dhd_console_t *c = &bus->console;
+ uint8 line[CONSOLE_LINE_MAX], ch;
+ uint32 n, idx, addr;
+ int rv;
+
+ /* Don't do anything until FWREADY updates console address */
+ if (bus->console_addr == 0)
+ return 0;
+
+ /* Read console log struct */
+ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
+ if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
+ return rv;
+
+ /* Allocate console buffer (one time only) */
+ if (c->buf == NULL) {
+ c->bufsize = ltoh32(c->log.buf_size);
+ if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
+ return BCME_NOMEM;
+ }
+
+ idx = ltoh32(c->log.idx);
+
+ /* Protect against corrupt value */
+ if (idx > c->bufsize)
+ return BCME_ERROR;
+
+ /* Skip reading the console buffer if the index pointer has not moved */
+ if (idx == c->last)
+ return BCME_OK;
+
+ /* Read the console buffer */
+ addr = ltoh32(c->log.buf);
+ if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
+ return rv;
+
+ while (c->last != idx) {
+ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
+ if (c->last == idx) {
+ /* This would output a partial line. Instead, back up
+ * the buffer pointer and output this line next time around.
+ */
+ if (c->last >= n)
+ c->last -= n;
+ else
+ c->last = c->bufsize - n;
+ goto break2;
+ }
+ ch = c->buf[c->last];
+ c->last = (c->last + 1) % c->bufsize;
+ if (ch == '\n')
+ break;
+ line[n] = ch;
+ }
+
+ if (n > 0) {
+ if (line[n - 1] == '\r')
+ n--;
+ line[n] = 0;
+ printf("CONSOLE: %s\n", line);
+ }
+ }
+break2:
+
+ return BCME_OK;
+}
+#endif /* DHD_DEBUG */
+
int
dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
{
@@ -4082,8 +4137,10 @@ dhdsdio_dpc(dhd_bus_t *bus)
BUS_WAKE(bus);
- /* Make sure backplane clock is on */
- dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
+ /* Make sure backplane clock is on, no pending,
+ * waste of cycle to wait for the next schedule to send
+ */
+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
if (bus->clkstate == CLK_PENDING)
goto clkwait;
@@ -4174,7 +4231,7 @@ clkwait:
bcmsdh_intr_enable(sdh);
}
- if (DATAOK(bus) && bus->ctrl_frame_stat) {
+ if (DATAOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
int ret, i;
ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
@@ -4206,13 +4263,16 @@ clkwait:
}
}
+ if (ret == 0) {
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+ }
+
printf("Return_dpc value is : %d\n", ret);
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
bus->ctrl_frame_stat = FALSE;
dhd_wait_event_wakeup(bus->dhd);
}
/* Send queued frames (limit 1 if rx may still be pending) */
- else if ((bus->clkstate != CLK_PENDING) && !bus->fcstate &&
+ else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
framecnt = dhdsdio_sendfromq(bus, framecnt);
@@ -4227,7 +4287,8 @@ clkwait:
bus->dhd->busstate = DHD_BUS_DOWN;
bus->intstatus = 0;
} else if (bus->clkstate == CLK_PENDING) {
- /* Awaiting I_CHIPACTIVE; don't resched */
+ DHD_INFO(("%s: rescheduled due to CLK_PENDING awaiting \
+ I_CHIPACTIVE interrupt", __FUNCTION__));
} else if (bus->intstatus || bus->ipend ||
(!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
PKT_AVAILABLE()) { /* Read multiple frames */
@@ -4251,7 +4312,6 @@ clkwait:
bool
dhd_bus_dpc(struct dhd_bus *bus)
{
-#ifdef SDIO_ISR_THREAD
bool resched;
/* Call the DPC directly. */
@@ -4259,9 +4319,6 @@ dhd_bus_dpc(struct dhd_bus *bus)
resched = dhdsdio_dpc(bus);
return resched;
-#else
- return dhdsdio_dpc(bus);
-#endif /* SDIO_ISR_THREAD */
}
void
@@ -4270,6 +4327,8 @@ dhdsdio_isr(void *arg)
dhd_bus_t *bus = (dhd_bus_t*)arg;
bcmsdh_info_t *sdh;
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
if (!bus) {
DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
return;
@@ -4280,9 +4339,6 @@ dhdsdio_isr(void *arg)
DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
return;
}
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
/* Count the interrupt call */
bus->intrcount++;
bus->ipend = TRUE;
@@ -4639,7 +4695,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
bus->idlecount = 0;
if (bus->activity) {
bus->activity = FALSE;
- } else {
dhdsdio_clkctl(bus, CLK_NONE, FALSE);
}
}
@@ -4650,6 +4705,68 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
return bus->ipend;
}
+#ifdef DHD_DEBUG
+extern int
+dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
+{
+ dhd_bus_t *bus = dhdp->bus;
+ uint32 addr, val;
+ int rv;
+ void *pkt;
+
+ /* Address could be zero if CONSOLE := 0 in dongle Makefile */
+ if (bus->console_addr == 0)
+ return BCME_UNSUPPORTED;
+
+ /* Exclusive bus access */
+ dhd_os_sdlock(bus->dhd);
+
+ /* Don't allow input if dongle is in reset */
+ if (bus->dhd->dongle_reset) {
+ dhd_os_sdunlock(bus->dhd);
+ return BCME_NOTREADY;
+ }
+
+ /* Request clock to allow SDIO accesses */
+ BUS_WAKE(bus);
+ /* No pend allowed since txpkt is called later, ht clk has to be on */
+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
+
+ /* Zero cbuf_index */
+ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx);
+ val = htol32(0);
+ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
+ goto done;
+
+ /* Write message into cbuf */
+ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf);
+ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
+ goto done;
+
+ /* Write length into vcons_in */
+ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in);
+ val = htol32(msglen);
+ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
+ goto done;
+
+ /* Bump dongle by sending an empty event pkt.
+ * sdpcm_sendup (RX) checks for virtual console input.
+ */
+ if (((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) &&
+ bus->clkstate == CLK_AVAIL)
+ dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE);
+
+done:
+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+ }
+
+ dhd_os_sdunlock(bus->dhd);
+
+ return rv;
+}
+#endif /* DHD_DEBUG */
#ifdef DHD_DEBUG
static void
diff --git a/drivers/net/wireless/bcm4329/include/dhdioctl.h b/drivers/net/wireless/bcm4329/include/dhdioctl.h
index ee78c3d1949e..980a14301003 100644
--- a/drivers/net/wireless/bcm4329/include/dhdioctl.h
+++ b/drivers/net/wireless/bcm4329/include/dhdioctl.h
@@ -5,7 +5,7 @@
*
* Definitions subject to change without notice.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -25,7 +25,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: dhdioctl.h,v 13.7.8.1.4.1.16.4 2009/09/05 16:50:35 Exp $
+ * $Id: dhdioctl.h,v 13.7.8.1.4.1.16.5 2010/05/21 21:49:38 Exp $
*/
#ifndef _dhdioctl_h_
@@ -79,6 +79,7 @@ typedef struct dhd_ioctl {
#define DHD_GLOM_VAL 0x0400
#define DHD_EVENT_VAL 0x0800
#define DHD_BTA_VAL 0x1000
+#define DHD_ISCAN_VAL 0x2000
#ifdef SDTEST
/* For pktgen iovar */
diff --git a/drivers/net/wireless/bcm4329/include/epivers.h b/drivers/net/wireless/bcm4329/include/epivers.h
index a76ea3f85d6e..f27fcc5832b6 100644
--- a/drivers/net/wireless/bcm4329/include/epivers.h
+++ b/drivers/net/wireless/bcm4329/include/epivers.h
@@ -31,18 +31,18 @@
#define EPI_MINOR_VERSION 218
-#define EPI_RC_NUMBER 223
+#define EPI_RC_NUMBER 238
-#define EPI_INCREMENTAL_NUMBER 1
+#define EPI_INCREMENTAL_NUMBER 0
#define EPI_BUILD_NUMBER 0
-#define EPI_VERSION 4, 218, 223, 1
+#define EPI_VERSION 4, 218, 238, 0
-#define EPI_VERSION_NUM 0x04dadf01
+#define EPI_VERSION_NUM 0x04daee00
-#define EPI_VERSION_STR "4.218.223.1"
-#define EPI_ROUTER_VERSION_STR "4.219.223.1"
+#define EPI_VERSION_STR "4.218.238.0"
+#define EPI_ROUTER_VERSION_STR "4.219.238.0"
#endif
diff --git a/drivers/net/wireless/bcm4329/include/hndrte_cons.h b/drivers/net/wireless/bcm4329/include/hndrte_cons.h
index f2334a0a3394..dccafdb55d1f 100644
--- a/drivers/net/wireless/bcm4329/include/hndrte_cons.h
+++ b/drivers/net/wireless/bcm4329/include/hndrte_cons.h
@@ -24,20 +24,51 @@
#include <typedefs.h>
+#ifdef RWL_DONGLE
+/* For Dongle uart tranport max cmd len is 256 bytes + header length (16 bytes)
+ * In case of ASD commands we are not sure about how much is the command size
+ * To be on the safe side, input buf len CBUF_LEN is increased to max (512) bytes.
+ */
+#define RWL_MAX_DATA_LEN (512 + 8) /* allow some extra bytes for '/n' termination */
+#define CBUF_LEN (RWL_MAX_DATA_LEN + 64) /* allow 64 bytes for header ("rwl...") */
+#else
#define CBUF_LEN (128)
+#endif
+
+#ifdef WLLMAC
+#define LOG_BUF_LEN 2048
+#else /* WLLMAC */
#define LOG_BUF_LEN 1024
+#endif /* WLLMAC */
typedef struct {
- uint32 buf;
+ uint32 buf; /* Can't be pointer on (64-bit) hosts */
uint buf_size;
uint idx;
- char *_buf_compat;
+ char *_buf_compat; /* Redundant pointer for backward compat. */
} hndrte_log_t;
typedef struct {
+ /* Virtual UART
+ * When there is no UART (e.g. Quickturn), the host should write a complete
+ * input line directly into cbuf and then write the length into vcons_in.
+ * This may also be used when there is a real UART (at risk of conflicting with
+ * the real UART). vcons_out is currently unused.
+ */
volatile uint vcons_in;
volatile uint vcons_out;
+
+ /* Output (logging) buffer
+ * Console output is written to a ring buffer log_buf at index log_idx.
+ * The host may read the output when it sees log_idx advance.
+ * Output will be lost if the output wraps around faster than the host polls.
+ */
hndrte_log_t log;
+
+ /* Console input line buffer
+ * Characters are read one at a time into cbuf until <CR> is received, then
+ * the buffer is processed as a command line. Also used for virtual UART.
+ */
uint cbuf_idx;
char cbuf[CBUF_LEN];
} hndrte_cons_t;
diff --git a/drivers/net/wireless/bcm4329/include/proto/802.11.h b/drivers/net/wireless/bcm4329/include/proto/802.11.h
index 3ef7de2f20e2..fd26317361da 100644
--- a/drivers/net/wireless/bcm4329/include/proto/802.11.h
+++ b/drivers/net/wireless/bcm4329/include/proto/802.11.h
@@ -976,6 +976,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification {
#define DOT11_MNG_EXT_CSA_ID 60
#define DOT11_MNG_HT_ADD 61
#define DOT11_MNG_EXT_CHANNEL_OFFSET 62
+#define DOT11_MNG_WAPI_ID 68
#define DOT11_MNG_HT_BSS_COEXINFO_ID 72
#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73
#define DOT11_MNG_HT_OBSS_ID 74
@@ -1422,6 +1423,8 @@ typedef struct vndr_ie vndr_ie_t;
#define AES_KEY_SIZE 16
#define AES_MIC_SIZE 8
+#define SMS4_KEY_LEN 16
+#define SMS4_WPI_CBC_MAC_LEN 16
#include <packed_section_end.h>
diff --git a/drivers/net/wireless/bcm4329/include/proto/ethernet.h b/drivers/net/wireless/bcm4329/include/proto/ethernet.h
index 05530d51b176..9ad2ea0c70fd 100644
--- a/drivers/net/wireless/bcm4329/include/proto/ethernet.h
+++ b/drivers/net/wireless/bcm4329/include/proto/ethernet.h
@@ -1,7 +1,7 @@
/*
* From FreeBSD 2.2.7: Fundamental constants relating to ethernet.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -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: ethernet.h,v 9.45.56.3 2009/08/15 00:51:27 Exp $
+ * $Id: ethernet.h,v 9.45.56.5 2010/02/22 22:04:36 Exp $
*/
@@ -67,6 +67,7 @@
#define ETHER_TYPE_8021Q 0x8100
#define ETHER_TYPE_BRCM 0x886c
#define ETHER_TYPE_802_1X 0x888e
+#define ETHER_TYPE_WAI 0x88b4
#ifdef BCMWPA2
#define ETHER_TYPE_802_1X_PREAUTH 0x88c7
#endif
diff --git a/drivers/net/wireless/bcm4329/include/wlioctl.h b/drivers/net/wireless/bcm4329/include/wlioctl.h
index 58a2f6c0ff1e..a1507ebe598d 100644
--- a/drivers/net/wireless/bcm4329/include/wlioctl.h
+++ b/drivers/net/wireless/bcm4329/include/wlioctl.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: wlioctl.h,v 1.601.4.15.2.14.2.60 2010/04/12 05:33:02 Exp $
+ * $Id: wlioctl.h,v 1.601.4.15.2.14.2.61 2010/05/04 20:26:25 Exp $
*/
@@ -288,6 +288,7 @@ typedef enum sup_auth_status {
#define CRYPTO_ALGO_AES_OCB_MSDU 5
#define CRYPTO_ALGO_AES_OCB_MPDU 6
#define CRYPTO_ALGO_NALG 7
+#define CRYPTO_ALGO_SMS4 11
#define WSEC_GEN_MIC_ERROR 0x0001
#define WSEC_GEN_REPLAY 0x0002
@@ -338,6 +339,7 @@ typedef struct {
#define AES_ENABLED 0x0004
#define WSEC_SWFLAG 0x0008
#define SES_OW_ENABLED 0x0040
+#define SMS4_ENABLED 0x0100
#define WPA_AUTH_DISABLED 0x0000
@@ -349,6 +351,7 @@ typedef struct {
#define WPA2_AUTH_PSK 0x0080
#define BRCM_AUTH_PSK 0x0100
#define BRCM_AUTH_DPT 0x0200
+#define WPA_AUTH_WAPI 0x0400
#define WPA_AUTH_PFN_ANY 0xffffffff
diff --git a/drivers/net/wireless/bcm4329/linux_osl.c b/drivers/net/wireless/bcm4329/linux_osl.c
index 6383e00498f1..d00bd1ca291b 100644
--- a/drivers/net/wireless/bcm4329/linux_osl.c
+++ b/drivers/net/wireless/bcm4329/linux_osl.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: linux_osl.c,v 1.125.12.3.8.6 2009/12/09 01:29:03 Exp $
+ * $Id: linux_osl.c,v 1.125.12.3.8.7 2010/05/04 21:10:04 Exp $
*/
@@ -511,7 +511,7 @@ osl_mfree(osl_t *osh, void *addr, uint size)
#ifdef DHD_USE_STATIC_BUF
if (bcm_static_buf)
{
- if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr \
+ if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr
<= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN)))
{
int buf_idx = 0;
diff --git a/drivers/net/wireless/bcm4329/wl_iw.c b/drivers/net/wireless/bcm4329/wl_iw.c
index 8fb396385475..7ccee377fe01 100644
--- a/drivers/net/wireless/bcm4329/wl_iw.c
+++ b/drivers/net/wireless/bcm4329/wl_iw.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: wl_iw.c,v 1.51.4.9.2.6.4.104 2010/04/21 23:21:00 Exp $
+ * $Id: wl_iw.c,v 1.51.4.9.2.6.4.108 2010/05/18 00:09:41 Exp $
*/
@@ -57,7 +57,32 @@ typedef const struct si_pub si_t;
#include <wl_iw.h>
-#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
+#ifndef IW_ENCODE_ALG_SM4
+#define IW_ENCODE_ALG_SM4 0x20
+#endif
+
+#ifndef IW_AUTH_WAPI_ENABLED
+#define IW_AUTH_WAPI_ENABLED 0x20
+#endif
+
+#ifndef IW_AUTH_WAPI_VERSION_1
+#define IW_AUTH_WAPI_VERSION_1 0x00000008
+#endif
+
+#ifndef IW_AUTH_CIPHER_SMS4
+#define IW_AUTH_CIPHER_SMS4 0x00000020
+#endif
+
+#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK
+#define IW_AUTH_KEY_MGMT_WAPI_PSK 4
+#endif
+
+#ifndef IW_AUTH_KEY_MGMT_WAPI_CERT
+#define IW_AUTH_KEY_MGMT_WAPI_CERT 8
+#endif
+
+
+#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED))
#include <linux/rtnetlink.h>
#include <linux/mutex.h>
@@ -1182,28 +1207,6 @@ static int iwpriv_set_ap_config(struct net_device *dev,
#ifdef SOFTAP
-void print_buf(void *pbuf, int len, int bytes_per_line)
-{
- int i, j = 0;
- unsigned char *buf = pbuf;
-
- if (bytes_per_line == 0) {
- bytes_per_line = len;
- }
-
- for (i = 0; i < len; i++) {
- WL_SOFTAP(("%2.2x", *buf++));
- j++;
- if (j == bytes_per_line) {
- WL_SOFTAP(("\n"));
- j = 0;
- } else {
- WL_SOFTAP((":"));
- }
- }
- WL_SOFTAP(("\n"));
-}
-
static int iwpriv_get_assoc_list(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *p_iwrq,
@@ -1554,9 +1557,9 @@ wl_iw_get_range(
)
{
struct iw_range *range = (struct iw_range *) extra;
- int channels[MAXCHANNEL+1];
- wl_uint32_list_t *list = (wl_uint32_list_t *) channels;
+ wl_uint32_list_t *list;
wl_rateset_t rateset;
+ int8 *channels;
int error, i, k;
uint sf, ch;
@@ -1574,14 +1577,23 @@ wl_iw_get_range(
if (!extra)
return -EINVAL;
+ channels = kmalloc((MAXCHANNEL+1)*4, GFP_KERNEL);
+ if (!channels) {
+ WL_ERROR(("Could not alloc channels\n"));
+ return -ENOMEM;
+ }
+ list = (wl_uint32_list_t *)channels;
+
dwrq->length = sizeof(struct iw_range);
memset(range, 0, sizeof(range));
range->min_nwid = range->max_nwid = 0;
list->count = htod32(MAXCHANNEL);
- if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, sizeof(channels))))
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, (MAXCHANNEL+1)*4))) {
+ kfree(channels);
return error;
+ }
for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) {
range->freq[i].i = dtoh32(list->element[i]);
@@ -1613,8 +1625,10 @@ wl_iw_get_range(
range->avg_qual.noise = 0x100 - 75;
#endif
- if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset))))
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) {
+ kfree(channels);
return error;
+ }
rateset.count = dtoh32(rateset.count);
range->num_bitrates = rateset.count;
for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++)
@@ -1649,8 +1663,10 @@ wl_iw_get_range(
}
}
- if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i))))
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) {
+ kfree(channels);
return error;
+ }
i = dtoh32(i);
if (i == WLC_PHY_TYPE_A)
range->throughput = 24000000;
@@ -1719,6 +1735,8 @@ wl_iw_get_range(
#endif
#endif
+ kfree(channels);
+
return 0;
}
@@ -2795,6 +2813,32 @@ ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len)
}
#endif
+static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
+ size_t len, int uppercase)
+{
+ size_t i;
+ char *pos = buf, *end = buf + buf_size;
+ int ret;
+ if (buf_size == 0)
+ return 0;
+ for (i = 0; i < len; i++) {
+ ret = snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
+ data[i]);
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return pos - buf;
+ }
+ pos += ret;
+ }
+ end[-1] = '\0';
+ return pos - buf;
+}
+
+
+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
+{
+ return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
+}
static int
wl_iw_handle_scanresults_ies(char **event_p, char *end,
@@ -2803,6 +2847,8 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end,
#if WIRELESS_EXT > 17
struct iw_event iwe;
char *event;
+ char *buf;
+ int custom_event_len;
event = *event_p;
if (bi->ie_length) {
@@ -2841,6 +2887,35 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end,
}
}
+ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
+ ptr_len = bi->ie_length;
+
+ while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WAPI_ID))) {
+ WL_TRACE(("%s: found a WAPI IE...\n", __FUNCTION__));
+#ifdef WAPI_IE_USE_GENIE
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = ie->len + 2;
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
+#else
+ iwe.cmd = IWEVCUSTOM;
+ custom_event_len = strlen("wapi_ie=") + 2*(ie->len + 2);
+ iwe.u.data.length = custom_event_len;
+
+ buf = kmalloc(custom_event_len+1, GFP_KERNEL);
+ if (buf == NULL)
+ {
+ WL_ERROR(("malloc(%d) returned NULL...\n", custom_event_len));
+ break;
+ }
+
+ memcpy(buf, "wapi_ie=", 8);
+ wpa_snprintf_hex(buf + 8, 2+1, &(ie->id), 1);
+ wpa_snprintf_hex(buf + 10, 2+1, &(ie->len), 1);
+ wpa_snprintf_hex(buf + 12, 2*ie->len+1, ie->data, ie->len);
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, buf);
+#endif
+ break;
+ }
*event_p = event;
}
#endif
@@ -3918,11 +3993,21 @@ wl_iw_set_wpaie(
char *extra
)
{
+ uchar buf[WLC_IOCTL_SMLEN] = {0};
+ uchar *p = buf;
+ int wapi_ie_size;
WL_TRACE(("%s: SIOCSIWGENIE\n", dev->name));
CHECK_EXTRA_FOR_NULL(extra);
+ if (extra[0] == DOT11_MNG_WAPI_ID)
+ {
+ wapi_ie_size = iwp->length;
+ memcpy(p, extra, iwp->length);
+ dev_wlc_bufvar_set(dev, "wapiie", buf, wapi_ie_size);
+ }
+ else
dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
return 0;
@@ -4039,6 +4124,12 @@ wl_iw_set_encodeext(
case IW_ENCODE_ALG_CCMP:
key.algo = CRYPTO_ALGO_AES_CCM;
break;
+ case IW_ENCODE_ALG_SM4:
+ key.algo = CRYPTO_ALGO_SMS4;
+ if (iwe->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+ key.flags &= ~WL_PRIMARY_KEY;
+ }
+ break;
default:
break;
}
@@ -4222,6 +4313,8 @@ wl_iw_set_wpaauth(
else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
#endif
+ else if (paramval & IW_AUTH_WAPI_VERSION_1)
+ val = WPA_AUTH_WAPI;
WL_INFORM(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val));
if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
return error;
@@ -4236,6 +4329,8 @@ wl_iw_set_wpaauth(
val = TKIP_ENABLED;
if (paramval & IW_AUTH_CIPHER_CCMP)
val = AES_ENABLED;
+ if (paramval & IW_AUTH_CIPHER_SMS4)
+ val = SMS4_ENABLED;
if (paramid == IW_AUTH_CIPHER_PAIRWISE) {
iw->pwsec = val;
@@ -4283,9 +4378,12 @@ wl_iw_set_wpaauth(
val = WPA2_AUTH_UNSPECIFIED;
}
#endif
+ if (paramval & (IW_AUTH_KEY_MGMT_WAPI_PSK | IW_AUTH_KEY_MGMT_WAPI_CERT))
+ val = WPA_AUTH_WAPI;
WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
return error;
+
break;
case IW_AUTH_TKIP_COUNTERMEASURES:
dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)&paramval, 1);
@@ -4368,6 +4466,24 @@ wl_iw_set_wpaauth(
break;
}
#endif
+ case IW_AUTH_WAPI_ENABLED:
+ if ((error = dev_wlc_intvar_get(dev, "wsec", &val)))
+ return error;
+ if (paramval) {
+ val |= SMS4_ENABLED;
+ if ((error = dev_wlc_intvar_set(dev, "wsec", val))) {
+ WL_ERROR(("%s: setting wsec to 0x%0x returned error %d\n",
+ __FUNCTION__, val, error));
+ return error;
+ }
+ if ((error = dev_wlc_intvar_set(dev, "wpa_auth", WPA_AUTH_WAPI))) {
+ WL_ERROR(("%s: setting wpa_auth(WPA_AUTH_WAPI) returned %d\n",
+ __FUNCTION__, error));
+ return error;
+ }
+ }
+
+ break;
default:
break;
}