net: wireless: bcmdhd: Update to version 5.90.125.78

- Add BT-Coex support to cfg80211
- Add private event logic to cfg80211 when FW hangs
- Reduce passive dwell time to 130 ms
- Fix proptx initialize fail issue
- Implement codes for WPS2.0 using cfg80211
- Clean any left virtual interfaces in primary dhd_stop context
- Skip waiting for rtnl_lock in cfg80211 callback if already taken
- Skip writing to file FW trap info

Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
This commit is contained in:
Dmitry Shmidt 2011-09-07 10:30:45 -07:00
parent 95cf7a199c
commit 4bc71443e4
14 changed files with 1269 additions and 319 deletions

View File

@ -202,7 +202,7 @@ typedef struct dhd_pub {
void* wlfc_state;
#endif
bool dongle_isolation;
int hang_was_sent;
#ifdef WLMEDIA_HTSF
uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */
#endif
@ -389,7 +389,7 @@ 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 int dhd_custom_get_mac_address(unsigned char *buf);
extern int dhd_custom_get_mac_address(unsigned char *buf);
extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub);
extern void dhd_os_sdlock_eventq(dhd_pub_t * pub);
extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub);

View File

@ -57,6 +57,17 @@
* round off at the end of buffer
*/
#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */
#ifdef PROP_TXSTATUS
typedef struct dhd_wlfc_commit_info {
uint8 needs_hdr;
uint8 ac_fifo_credit_spent;
ewlfc_packet_state_t pkt_type;
wlfc_mac_descriptor_t* mac_entry;
void* p;
} dhd_wlfc_commit_info_t;
#endif /* PROP_TXSTATUS */
typedef struct dhd_prot {
uint16 reqid;
uint8 pending;
@ -152,7 +163,8 @@ dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uin
memcpy(prot->buf, buf, len);
if ((ret = dhdcdc_msg(dhd)) < 0) {
DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
if (!dhd->hang_was_sent)
DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
goto done;
}
@ -206,6 +218,17 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
if (dhd->busstate == DHD_BUS_DOWN) {
DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
return -EIO;
}
/* don't talk to the dongle if fw is about to be reloaded */
if (dhd->hang_was_sent) {
DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n",
__FUNCTION__));
return -EIO;
}
memset(msg, 0, sizeof(cdc_ioctl_t));
@ -629,8 +652,8 @@ dhd_wlfc_hanger_get_free_slot(void* hanger)
if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE)
return (uint16)i;
}
h->failed_slotfind++;
}
h->failed_slotfind++;
return WLFC_HANGER_MAXITEMS;
}
@ -1286,6 +1309,30 @@ _dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t*
return rc;
}
int
_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, uint8 available_credit_map, int borrower_ac)
{
int lender_ac;
int rc = BCME_ERROR;
if (ctx == NULL || available_credit_map == 0) {
WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
return BCME_BADARG;
}
/* Borrow from lowest priority available AC (including BC/MC credits) */
for (lender_ac = 0; lender_ac <= AC_COUNT; lender_ac++) {
if ((available_credit_map && (1 << lender_ac)) &&
(ctx->FIFO_credit[lender_ac] > 0)) {
ctx->credits_borrowed[borrower_ac][lender_ac]++;
ctx->FIFO_credit[lender_ac]--;
rc = BCME_OK;
break;
}
}
return rc;
}
int
dhd_wlfc_interface_entry_update(void* state,
ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea)
@ -1313,6 +1360,7 @@ dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits)
/* credit for bc/mc packets */
ctx->FIFO_credit[4] = credits[4];
/* credit for ATIM FIFO is not used yet. */
ctx->FIFO_credit[5] = 0;
return BCME_OK;
}
@ -1344,18 +1392,69 @@ dhd_wlfc_enque_sendq(void* state, int prec, void* p)
return BCME_OK;
}
int
_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac,
dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx)
{
uint32 hslot;
int rc;
/*
if ac_fifo_credit_spent = 0
This packet will not count against the FIFO credit.
To ensure the txstatus corresponding to this packet
does not provide an implied credit (default behavior)
mark the packet accordingly.
if ac_fifo_credit_spent = 1
This is a normal packet and it counts against the FIFO
credit count.
*/
DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent);
rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p,
commit_info->needs_hdr, &hslot);
if (rc == BCME_OK)
rc = fcommit(commit_ctx, commit_info->p);
else
ctx->stats.generic_error++;
if (rc == BCME_OK) {
ctx->stats.pkt2bus++;
if (commit_info->ac_fifo_credit_spent) {
ctx->stats.sendq_pkts[ac]++;
WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac);
}
}
else {
/*
bus commit has failed, rollback.
- remove wl-header for a delayed packet
- save wl-header header for suppressed packets
*/
rc = _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p,
(commit_info->pkt_type), hslot);
if (rc != BCME_OK)
ctx->stats.rollback_failed++;
rc = BCME_ERROR;
}
return rc;
}
int
dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx)
{
int ac;
int credit;
uint8 ac_fifo_credit_spent;
uint8 needs_hdr;
uint32 hslot;
void* p;
int rc;
dhd_wlfc_commit_info_t commit_info;
athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state;
wlfc_mac_descriptor_t* mac_entry;
int credit_count = 0;
int bus_retry_count = 0;
uint8 ac_available = 0; /* Bitmask for 4 ACs + BC/MC */
if ((state == NULL) ||
(fcommit == NULL)) {
@ -1363,8 +1462,12 @@ dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx)
return BCME_BADARG;
}
/*
memset(&commit_info, 0, sizeof(commit_info));
/*
Commit packets for regular AC traffic. Higher priority first.
First, use up FIFO credits available to each AC. Based on distribution
and credits left, borrow from other ACs as applicable
-NOTE:
If the bus between the host and firmware is overwhelmed by the
@ -1373,96 +1476,189 @@ dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx)
have to employ weighted round-robin or ucode scheme to avoid
low priority packet starvation.
*/
for (ac = AC_COUNT; ac >= 0; ac--) {
int initial_credit_count = ctx->FIFO_credit[ac];
for (credit = 0; credit < ctx->FIFO_credit[ac];) {
p = _dhd_wlfc_deque_delayedq(ctx, ac, &ac_fifo_credit_spent, &needs_hdr,
&mac_entry);
if (p == NULL)
commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac,
&(commit_info.ac_fifo_credit_spent),
&(commit_info.needs_hdr),
&(commit_info.mac_entry));
if (commit_info.p == NULL)
break;
/*
if ac_fifo_credit_spent = 0
This packet will not count against the FIFO credit.
To ensure the txstatus corresponding to this packet
does not provide an implied credit (default behavior)
mark the packet accordingly.
commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED :
eWLFC_PKTTYPE_SUPPRESSED;
if ac_fifo_credit_spent = 1
This is a normal packet and it counts against the FIFO
credit count.
*/
DHD_PKTTAG_SETCREDITCHECK(PKTTAG(p), ac_fifo_credit_spent);
rc = _dhd_wlfc_pretx_pktprocess(ctx, mac_entry, p, needs_hdr, &hslot);
if (rc == BCME_OK)
rc = fcommit(commit_ctx, p);
else
ctx->stats.generic_error++;
rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info,
fcommit, commit_ctx);
/* Bus commits may fail (e.g. flow control); abort after retries */
if (rc == BCME_OK) {
ctx->stats.pkt2bus++;
if (ac_fifo_credit_spent) {
ctx->stats.sendq_pkts[ac]++;
WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac);
/*
1 FIFO credit has been spent by sending this packet
to the device.
*/
if (commit_info.ac_fifo_credit_spent) {
credit++;
}
}
else {
/* bus commit has failed, rollback. */
rc = _dhd_wlfc_rollback_packet_toq(ctx,
p,
/*
- remove wl-header for a delayed packet
- save wl-header header for suppressed packets
*/
(needs_hdr ? eWLFC_PKTTYPE_DELAYED :
eWLFC_PKTTYPE_SUPPRESSED),
hslot);
if (rc != BCME_OK)
ctx->stats.rollback_failed++;
bus_retry_count++;
if (bus_retry_count >= BUS_RETRIES) {
DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n"));
ctx->FIFO_credit[ac] -= credit;
return rc;
}
}
}
ctx->FIFO_credit[ac] -= credit;
/* packets from SENDQ are fresh and they'd need header */
needs_hdr = 1;
/* packets from SENDQ are fresh and they'd need header and have no MAC entry */
commit_info.needs_hdr = 1;
commit_info.mac_entry = NULL;
commit_info.pkt_type = eWLFC_PKTTYPE_NEW;
for (credit = 0; credit < ctx->FIFO_credit[ac];) {
p = _dhd_wlfc_deque_sendq(ctx, ac, &ac_fifo_credit_spent);
if (p == NULL)
commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac,
&(commit_info.ac_fifo_credit_spent));
if (commit_info.p == NULL)
break;
DHD_PKTTAG_SETCREDITCHECK(PKTTAG(p), ac_fifo_credit_spent);
rc = _dhd_wlfc_pretx_pktprocess(ctx, NULL, p, needs_hdr, &hslot);
if (rc == BCME_OK)
rc = fcommit(commit_ctx, p);
else
ctx->stats.generic_error++;
rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info,
fcommit, commit_ctx);
/* Bus commits may fail (e.g. flow control); abort after retries */
if (rc == BCME_OK) {
ctx->stats.pkt2bus++;
if (ac_fifo_credit_spent) {
WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac);
ctx->stats.sendq_pkts[ac]++;
if (commit_info.ac_fifo_credit_spent) {
credit++;
}
}
else {
/* bus commit has failed, rollback. */
rc = _dhd_wlfc_rollback_packet_toq(ctx,
p,
/* remove wl-header while rolling back */
eWLFC_PKTTYPE_NEW,
hslot);
if (rc != BCME_OK)
ctx->stats.rollback_failed++;
bus_retry_count++;
if (bus_retry_count >= BUS_RETRIES) {
DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n"));
ctx->FIFO_credit[ac] -= credit;
return rc;
}
}
}
ctx->FIFO_credit[ac] -= credit;
/* If no credits were used, the queue is idle and can be re-used
Note that resv credits cannot be borrowed
*/
if (initial_credit_count == ctx->FIFO_credit[ac]) {
ac_available |= (1 << ac);
credit_count += ctx->FIFO_credit[ac];
}
}
/* We borrow only for AC_BE and only if no other traffic seen for DEFER_PERIOD
Note that (ac_available & WLFC_AC_BE_TRAFFIC_ONLY) is done to:
a) ignore BC/MC for deferring borrow
b) ignore AC_BE being available along with other ACs
(this should happen only for pure BC/MC traffic)
i.e. AC_VI, AC_VO, AC_BK all MUST be available (i.e. no traffic) and
we do not care if AC_BE and BC/MC are available or not
*/
if ((ac_available & WLFC_AC_BE_TRAFFIC_ONLY) == WLFC_AC_BE_TRAFFIC_ONLY) {
if (ctx->allow_credit_borrow) {
ac = 1; /* Set ac to AC_BE and borrow credits */
}
else {
int delta;
int curr_t = OSL_SYSUPTIME();
if (curr_t > ctx->borrow_defer_timestamp)
delta = curr_t - ctx->borrow_defer_timestamp;
else
delta = 0xffffffff + curr_t - ctx->borrow_defer_timestamp;
if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) {
/* Reset borrow but defer to next iteration (defensive borrowing) */
ctx->allow_credit_borrow = TRUE;
ctx->borrow_defer_timestamp = 0;
}
return BCME_OK;
}
}
else {
/* If we have multiple AC traffic, turn off borrowing, mark time and bail out */
ctx->allow_credit_borrow = FALSE;
ctx->borrow_defer_timestamp = OSL_SYSUPTIME();
return BCME_OK;
}
/* At this point, borrow all credits only for "ac" (which should be set above to AC_BE)
Generically use "ac" only in case we extend to all ACs in future
*/
for (; (credit_count > 0);) {
commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac,
&(commit_info.ac_fifo_credit_spent),
&(commit_info.needs_hdr),
&(commit_info.mac_entry));
if (commit_info.p == NULL)
break;
commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED :
eWLFC_PKTTYPE_SUPPRESSED;
rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info,
fcommit, commit_ctx);
/* Bus commits may fail (e.g. flow control); abort after retries */
if (rc == BCME_OK) {
if (commit_info.ac_fifo_credit_spent) {
(void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac);
credit_count--;
}
}
else {
bus_retry_count++;
if (bus_retry_count >= BUS_RETRIES) {
DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n"));
return rc;
}
}
}
/* packets from SENDQ are fresh and they'd need header and have no MAC entry */
commit_info.needs_hdr = 1;
commit_info.mac_entry = NULL;
commit_info.pkt_type = eWLFC_PKTTYPE_NEW;
for (; (credit_count > 0);) {
commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac,
&(commit_info.ac_fifo_credit_spent));
if (commit_info.p == NULL)
break;
rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info,
fcommit, commit_ctx);
/* Bus commits may fail (e.g. flow control); abort after retries */
if (rc == BCME_OK) {
if (commit_info.ac_fifo_credit_spent) {
(void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac);
credit_count--;
}
}
else {
bus_retry_count++;
if (bus_retry_count >= BUS_RETRIES) {
DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n"));
return rc;
}
}
}
return BCME_OK;
}
@ -1489,6 +1685,7 @@ dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success)
athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
dhd->wlfc_state;
void* p;
int fifo_id;
if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) {
#ifdef PROP_TXSTATUS_DEBUG
@ -1506,11 +1703,29 @@ dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success)
/* indicate failure and free the packet */
dhd_txcomplete(dhd, txp, FALSE);
PKTFREE(wlfc->osh, txp, TRUE);
/* return the credit, if necessary */
if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp)))
wlfc->FIFO_credit[DHD_PKTTAG_FIFO(PKTTAG(txp))]++;
if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp))) {
int lender, credit_returned = 0; /* Note that borrower is fifo_id */
fifo_id = DHD_PKTTAG_FIFO(PKTTAG(txp));
/* Return credits to highest priority lender first */
for (lender = AC_COUNT; lender >= 0; lender--) {
if (wlfc->credits_borrowed[fifo_id][lender] > 0) {
wlfc->FIFO_credit[lender]++;
wlfc->credits_borrowed[fifo_id][lender]--;
credit_returned = 1;
break;
}
}
if (!credit_returned) {
wlfc->FIFO_credit[fifo_id]++;
}
}
PKTFREE(wlfc->osh, txp, TRUE);
}
return;
}
@ -1593,7 +1808,21 @@ dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info)
/* pick up the implicit credit from this packet */
if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) {
if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) {
wlfc->FIFO_credit[fifo_id]++;
int lender, credit_returned = 0; /* Note that borrower is fifo_id */
/* Return credits to highest priority lender first */
for (lender = AC_COUNT; lender >= 0; lender--) {
if (wlfc->credits_borrowed[fifo_id][lender] > 0) {
wlfc->FIFO_credit[lender]++;
wlfc->credits_borrowed[fifo_id][lender]--;
credit_returned = 1;
break;
}
}
if (!credit_returned) {
wlfc->FIFO_credit[fifo_id]++;
}
}
}
else {
@ -1644,8 +1873,33 @@ dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits)
#endif
/* update FIFO credits */
if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT)
wlfc->FIFO_credit[i] += credits[i];
{
int lender; /* Note that borrower is i */
/* Return credits to highest priority lender first */
for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) {
if (wlfc->credits_borrowed[i][lender] > 0) {
if (credits[i] >= wlfc->credits_borrowed[i][lender]) {
credits[i] -= wlfc->credits_borrowed[i][lender];
wlfc->FIFO_credit[lender] +=
wlfc->credits_borrowed[i][lender];
wlfc->credits_borrowed[i][lender] = 0;
}
else {
wlfc->credits_borrowed[i][lender] -= credits[i];
wlfc->FIFO_credit[lender] += credits[i];
credits[i] = 0;
}
}
}
/* If we have more credits left over, these must belong to the AC */
if (credits[i] > 0) {
wlfc->FIFO_credit[i] += credits[i];
}
}
}
return BCME_OK;
}
@ -1986,6 +2240,9 @@ dhd_wlfc_enable(dhd_pub_t *dhd)
wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT;
wlfc->allow_credit_borrow = TRUE;
wlfc->borrow_defer_timestamp = 0;
return BCME_OK;
}
@ -2165,7 +2422,7 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf)
dhd_wlfc_parse_header_info(dhd, pktbuf, (h->dataOffset << 2));
((athost_wl_status_info_t*)dhd->wlfc_state)->stats.dhd_hdrpulls++;
dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata,
dhd->bus);
(void *)dhd->bus);
dhd_os_wlfc_unblock(dhd);
}
#endif /* PROP_TXSTATUS */
@ -2232,7 +2489,6 @@ dhd_prot_dstats(dhd_pub_t *dhd)
return;
}
int
dhd_prot_init(dhd_pub_t *dhd)
{

View File

@ -1970,7 +1970,7 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY);
pfn_element.wsec = htod32(0);
pfn_element.infra = htod32(1);
pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT);
memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len);
pfn_element.ssid.SSID_len = ssids_local[i].SSID_len;

View File

@ -132,7 +132,11 @@ MODULE_LICENSE("GPL v2");
#include <dhd_bus.h>
#ifndef PROP_TXSTATUS
#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen)
#else
#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128)
#endif
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
const char *
@ -218,7 +222,7 @@ typedef struct dhd_info {
struct semaphore proto_sem;
#ifdef PROP_TXSTATUS
spinlock_t wlfc_spinlock;
#endif
#endif /* PROP_TXSTATUS */
#ifdef WLMEDIA_HTSF
htsf_t htsf;
#endif
@ -258,8 +262,6 @@ typedef struct dhd_info {
int wakelock_counter;
int wakelock_timeout_enable;
int hang_was_sent;
/* Thread to issue ioctl for multicast */
bool set_macaddress;
struct ether_addr macvalue;
@ -498,7 +500,6 @@ static struct notifier_block dhd_sleep_pm_notifier = {
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) */
/* && defined(DHD_GPL) */
static void dhd_set_packet_filter(int value, dhd_pub_t *dhd)
{
@ -976,10 +977,8 @@ dhd_op_if(dhd_if_t *ifp)
dhd_net_attach)) {
ifp->state = 0;
return;
}
}
#endif
if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) {
DHD_ERROR(("%s: dhd_net_attach failed, err %d\n",
__FUNCTION__, err));
@ -1037,7 +1036,7 @@ dhd_op_if(dhd_if_t *ifp)
ap_net_dev = NULL; /* NULL SOFTAP global wl0.1 as well */
dhd_os_spin_unlock(&dhd->pub, flags);
#endif /* SOFTAP */
MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
}
}
@ -1413,6 +1412,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
continue;
}
pnext = PKTNEXT(dhdp->osh, pktbuf);
PKTSETNEXT(wl->sh.osh, pktbuf, NULL);
@ -2078,6 +2078,14 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
goto done;
}
/* send to dongle only if we are not waiting for reload already */
if (dhd->pub.hang_was_sent) {
DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n",
__FUNCTION__));
bcmerror = BCME_DONGLE_DOWN;
goto done;
}
/* check for local dhd ioctl and handle it */
if (driver == DHD_IOCTL_MAGIC) {
bcmerror = dhd_ioctl((void *)&dhd->pub, &ioc, buf, buflen);
@ -2184,6 +2192,41 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
return OSL_ERROR(bcmerror);
}
static int
dhd_cleanup_virt_ifaces(dhd_info_t *dhd)
{
int i = 1; /* Leave ifidx 0 [Primary Interface] */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
int rollback_lock = FALSE;
#endif
DHD_TRACE(("%s: Enter \n", __func__));
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
/* release lock for unregister_netdev */
if (rtnl_is_locked()) {
rtnl_unlock();
rollback_lock = TRUE;
}
#endif
for (i = 1; i < DHD_MAX_IFS; i++) {
if (dhd->iflist[i]) {
DHD_TRACE(("Deleting IF: %d \n", i));
dhd->iflist[i]->state = WLC_E_IF_DEL;
dhd->iflist[i]->idx = i;
dhd_op_if(dhd->iflist[i]);
}
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
if (rollback_lock)
rtnl_lock();
#endif
return 0;
}
static int
dhd_stop(struct net_device *net)
{
@ -2197,8 +2240,17 @@ dhd_stop(struct net_device *net)
ifidx = dhd_net2idx(dhd, net);
#ifdef WL_CFG80211
if (ifidx == 0)
if (ifidx == 0) {
wl_cfg80211_down();
/** For CFG80211: Clean up all the left over virtual interfaces
* when the primary Interface is brought down. [ifconfig wlan0 down]
*/
if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) &&
(dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
dhd_cleanup_virt_ifaces(dhd);
}
}
#endif
#ifdef PROP_TXSTATUS
@ -2238,6 +2290,7 @@ dhd_open(struct net_device *net)
strcpy(fw_path, firmware_path);
firmware_path[0] = '\0';
}
#if !defined(WL_CFG80211)
/** Force start if ifconfig_up gets called before START command
* We keep WEXT's wl_control_wl_start to provide backward compatibility
@ -2262,7 +2315,9 @@ dhd_open(struct net_device *net)
if (ifidx == 0) {
atomic_set(&dhd->pend_8021x_cnt, 0);
#if defined(WL_CFG80211)
DHD_ERROR(("\n%s\n", dhd_version));
wl_android_wifi_on(net);
dhd->pub.hang_was_sent = 0;
#endif
if (dhd->pub.busstate != DHD_BUS_DATA) {
@ -2610,7 +2665,7 @@ dhd_bus_start(dhd_pub_t *dhdp)
ASSERT(dhd);
DHD_TRACE(("%s: \n", __FUNCTION__));
DHD_TRACE(("Enter %s:\n", __FUNCTION__));
dhd_os_sdlock(dhdp);
@ -2706,6 +2761,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#endif
int scan_assoc_time = 40;
int scan_unassoc_time = 40;
int scan_passive_time = 130;
char buf[WLC_IOCTL_SMLEN];
char *ptr;
uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
@ -2946,14 +3002,16 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
sizeof(scan_assoc_time), TRUE, 0);
dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
sizeof(scan_unassoc_time), TRUE, 0);
dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time,
sizeof(scan_passive_time), TRUE, 0);
#ifdef ARP_OFFLOAD_SUPPORT
/* Set and enable ARP offload feature for STA only */
if (arpoe
#if defined(SOFTAP)
&& (!ap_fw_loaded)
#endif /* (OEM_ANDROID) && defined(SOFTAP) */
) {
if (arpoe && !ap_fw_loaded) {
#else
if (arpoe) {
#endif
dhd_arp_offload_set(dhd, dhd_arp_mode);
dhd_arp_offload_enable(dhd, arpoe);
} else {
@ -2970,7 +3028,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
dhd->pktfilter[1] = NULL;
dhd->pktfilter[2] = NULL;
dhd->pktfilter[3] = NULL;
#if defined(SOFTAP)
if (ap_fw_loaded) {
int i;
@ -2979,13 +3036,12 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
0, dhd_master_mode);
}
}
#endif /* (SOFTAP) */
#endif /* defined(SOFTAP) */
#endif /* PKT_FILTER_SUPPORT */
/* Force STA UP */
ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0);
if (ret < 0)
goto done;
if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0)
DHD_ERROR(("%s Setting WL UP failed %d\n", __FUNCTION__, ret));
done:
@ -3065,7 +3121,8 @@ int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
#ifdef ARP_OFFLOAD_SUPPORT
/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */
void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
void
aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
{
u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */
int i;
@ -3088,14 +3145,11 @@ void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
}
for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
if (add && (ipv4_buf[i] == 0)) {
ipv4_buf[i] = ipa;
ipv4_buf[i] = ipa;
add = FALSE; /* added ipa to local table */
DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n",
__FUNCTION__, i));
} else if (ipv4_buf[i] == ipa) {
ipv4_buf[i] = 0;
DHD_ARPOE(("%s: removed IP:%x from temp table %d\n",
@ -3160,14 +3214,14 @@ static int dhd_device_event(struct notifier_block *this,
#ifdef AOE_IP_ALIAS_SUPPORT
if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) {
DHD_ARPOE(("%s: primary interface is down, AOE clr all\n",
__FUNCTION__));
__FUNCTION__));
dhd_aoe_hostip_clr(&dhd->pub);
dhd_aoe_arp_clr(&dhd->pub);
} else
aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE);
#else
dhd_aoe_hostip_clr(&dhd->pub);
dhd_aoe_arp_clr(&dhd->pub);
dhd_aoe_hostip_clr(&dhd->pub);
dhd_aoe_arp_clr(&dhd->pub);
#endif
break;
@ -3221,9 +3275,9 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
net->netdev_ops = &dhd_ops_pri;
#endif
} else {
/*
* We have to use the primary MAC for virtual interfaces
*/
/*
* We have to use the primary MAC for virtual interfaces
*/
memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN);
/*
* Android sets the locally administered bit to indicate that this is a
@ -3362,15 +3416,10 @@ void dhd_detach(dhd_pub_t *dhdp)
/* delete all interfaces, start with virtual */
if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) {
int i = 1;
dhd_if_t *ifp;
for (i = 1; i < DHD_MAX_IFS; i++)
if (dhd->iflist[i]) {
dhd->iflist[i]->state = WLC_E_IF_DEL;
dhd->iflist[i]->idx = i;
dhd_op_if(dhd->iflist[i]);
}
/* Cleanup all virtual Interfaces */
dhd_cleanup_virt_ifaces(dhd);
/* delete primary interface 0 */
ifp = dhd->iflist[0];
@ -3428,8 +3477,8 @@ void dhd_detach(dhd_pub_t *dhdp)
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
unregister_pm_notifier(&dhd_sleep_pm_notifier);
#endif
unregister_pm_notifier(&dhd_sleep_pm_notifier);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
#ifdef CONFIG_HAS_WAKELOCK
@ -3437,7 +3486,6 @@ void dhd_detach(dhd_pub_t *dhdp)
wake_lock_destroy(&dhd->wl_rxwake);
#endif
}
}
@ -3509,7 +3557,6 @@ dhd_module_init(void)
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
error = dhd_bus_register();
if (!error)
printf("\n%s\n", dhd_version);
else {
@ -4156,10 +4203,13 @@ int net_os_send_hang_message(struct net_device *dev)
int ret = 0;
if (dhd) {
if (!dhd->hang_was_sent) {
dhd->hang_was_sent = 1;
if (!dhd->pub.hang_was_sent) {
dhd->pub.hang_was_sent = 1;
#if defined(CONFIG_WIRELESS_EXT)
ret = wl_iw_send_priv_event(dev, "HANG");
#endif
#if defined(WL_CFG80211)
ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
#endif
}
}

View File

@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <typedefs.h>
#include <linuxver.h>
int setScheduler(struct task_struct *p, int policy, struct sched_param *param)

View File

@ -147,6 +147,8 @@ extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
#ifdef DHD_DEBUG
/* Device console log buffer state */
#define CONSOLE_LINE_MAX 192
#define CONSOLE_BUFFER_MAX 2024
typedef struct dhd_console {
uint count; /* Poll interval msec counter */
uint log_addr; /* Log struct address (fixed) */
@ -429,7 +431,7 @@ do { \
* Mode 0: Dongle writes the software host mailbox and host is interrupted.
* Mode 1: (sdiod core rev >= 4)
* Device sets a new bit in the intstatus whenever there is a packet
* available in fifo. Host can't clear this specific status bit until all the
* available in fifo. Host can't clear this specific status bit until all the
* packets are read from the FIFO. No need to ack dongle intstatus.
* Mode 2: (sdiod core rev >= 4)
* Device sets a bit in the intstatus, and host acks this by writing
@ -463,9 +465,9 @@ static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count);
#ifdef DHD_DEBUG
static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size);
static int dhdsdio_mem_dump(dhd_bus_t *bus);
static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
#endif /* DHD_DEBUG */
static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
@ -1374,7 +1376,8 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
ret = 0;
} else {
DHD_ERROR(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__));
if (!bus->dhd->hang_was_sent)
DHD_ERROR(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__));
ret = -1;
bus->ctrl_frame_stat = FALSE;
goto done;
@ -1528,9 +1531,9 @@ enum {
IOV_SD1IDLE,
IOV_SLEEP,
IOV_DONGLEISOLATION,
IOV_VARS
IOV_VARS,
#ifdef SOFTAP
, IOV_FWPATH
IOV_FWPATH
#endif
};
@ -1836,6 +1839,7 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
return BCME_OK;
if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
"is different than sdpcm_shared version %d in dongle\n",
@ -1847,7 +1851,6 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
return BCME_OK;
}
#define CONSOLE_LINE_MAX 192
static int
dhdsdio_readconsole(dhd_bus_t *bus)
@ -1925,11 +1928,16 @@ dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size)
int bcmerror = 0;
uint msize = 512;
char *mbuffer = NULL;
char *console_buffer = NULL;
uint maxstrlen = 256;
char *str = NULL;
trap_t tr;
sdpcm_shared_t sdpcm_shared;
struct bcmstrbuf strbuf;
uint32 console_ptr, console_size, console_index;
uint8 line[CONSOLE_LINE_MAX], ch;
uint32 n, i, addr;
int rv;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
@ -2013,86 +2021,76 @@ dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size)
bcm_bprintf(&strbuf,
"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",
"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\n",
ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
ltoh32(sdpcm_shared.trap_addr),
ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log);
if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
goto printbuf;
addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size);
if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&console_size, sizeof(console_size))) < 0)
goto printbuf;
addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx);
if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&console_index, sizeof(console_index))) < 0)
goto printbuf;
console_ptr = ltoh32(console_ptr);
console_size = ltoh32(console_size);
console_index = ltoh32(console_index);
if (console_size > CONSOLE_BUFFER_MAX || !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
goto printbuf;
if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr, (uint8 *)console_buffer, console_size)) < 0)
goto printbuf;
for ( i = 0, n = 0; i < console_size; i += n + 1 ) {
for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
ch = console_buffer[ (console_index + i + n) % console_size];
if (ch == '\n')
break;
line[n] = ch;
}
if (n > 0) {
if (line[n - 1] == '\r')
n--;
line[n] = 0;
/* Don't use DHD_ERROR macro since we print a lot of information quickly */
/* The macro will truncate a lot of the printfs */
if (dhd_msg_level & DHD_ERROR_VAL)
printf("CONSOLE: %s\n", line);
}
}
}
}
printbuf:
if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
}
#ifdef DHD_DEBUG
if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
/* Mem dump to a file on device */
dhdsdio_mem_dump(bus);
}
#endif /* DHD_DEBUG */
done:
if (mbuffer)
MFREE(bus->dhd->osh, mbuffer, msize);
if (str)
MFREE(bus->dhd->osh, str, maxstrlen);
if (console_buffer)
MFREE(bus->dhd->osh, console_buffer, console_size);
return bcmerror;
}
#endif /* #ifdef DHD_DEBUG */
static int
dhdsdio_mem_dump(dhd_bus_t *bus)
{
int ret = 0;
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");
/* 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 */
return 0;
}
#endif /* defined(DHD_DEBUG) */
int
dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
@ -3040,6 +3038,7 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
dhd_os_sdunlock(bus->dhd);
}
int
dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
{
@ -4352,6 +4351,13 @@ dhdsdio_hostmail(dhd_bus_t *bus)
bus->flowcontrol = fcbits;
}
#ifdef DHD_DEBUG
/* At least print a message if FW halted */
if (hmb_data & HMB_DATA_FWHALT) {
DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED\n"));
dhdsdio_checkdied(bus, NULL, 0);
}
#endif /* DHD_DEBUG */
/* Shouldn't be any others */
if (hmb_data & ~(HMB_DATA_DEVREADY |
@ -5176,6 +5182,9 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
#ifdef GET_CUSTOM_MAC_ENABLE
struct ether_addr ea_addr;
#endif /* GET_CUSTOM_MAC_ENABLE */
#ifdef PROP_TXSTATUS
uint up = 0;
#endif
/* Init global variables at run-time, not as part of the declaration.
* This is required to support init/de-init of the driver. Initialization
@ -5342,6 +5351,10 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
goto fail;
}
#ifdef PROP_TXSTATUS
if (dhd_download_fw_on_driverload)
dhd_wl_ioctl_cmd(bus->dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0);
#endif
return bus;
fail:
@ -5916,7 +5929,7 @@ dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
return bcmerror;
}
/*
/*
EXAMPLE: nvram_array
nvram_arry format:
name=value
@ -6190,16 +6203,16 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
dhd_enable_oob_intr(bus, TRUE);
#endif /* defined(OOB_INTR_ONLY) */
bus->dhd->dongle_reset = FALSE;
bus->dhd->up = TRUE;
bus->dhd->dongle_reset = FALSE;
bus->dhd->up = TRUE;
#if !defined(IGNORE_ETH0_DOWN)
/* Restore flow control */
dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
/* Restore flow control */
dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
#endif
dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
} else {
dhd_bus_stop(bus, FALSE);
dhdsdio_release_dongle(bus, bus->dhd->osh,

View File

@ -201,6 +201,14 @@ typedef struct athost_wl_stat_counters {
#define WLFC_FCMODE_IMPLIED_CREDIT 1
#define WLFC_FCMODE_EXPLICIT_CREDIT 2
#define WLFC_BORROW_DEFER_PERIOD_MS 100
/* Mask to represent available ACs (note: BC/MC is ignored */
#define WLFC_AC_MASK 0xF
/* Mask to check for only on-going AC_BE traffic */
#define WLFC_AC_BE_TRAFFIC_ONLY 0xD
typedef struct athost_wl_status_info {
uint8 last_seqid_to_wlc;
@ -213,7 +221,11 @@ typedef struct athost_wl_status_info {
athost_wl_stat_counters_t stats;
/* the additional ones are for bc/mc and ATIM FIFO */
int FIFO_credit[AC_COUNT + 2];
int FIFO_credit[AC_COUNT + 2];
/* Credit borrow counts for each FIFO from each of the other FIFOs */
int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2];
struct pktq SENDQ;
/* packet hanger and MAC->handle lookup table */
@ -228,7 +240,7 @@ typedef struct athost_wl_status_info {
wlfc_mac_descriptor_t other;
} destination_entries;
/* token position for different priority packets */
uint8 token_pos[AC_COUNT];
uint8 token_pos[AC_COUNT+1];
/* ON/OFF state for flow control to the host network interface */
uint8 hostif_flow_state[WLFC_MAX_IFNUM];
uint8 host_ifidx;
@ -243,6 +255,12 @@ typedef struct athost_wl_status_info {
2 - Use explicit credit
*/
uint8 proptxstatus_mode;
/* To borrow credits */
uint8 allow_credit_borrow;
/* Timestamp to compute how long to defer borrowing for */
uint32 borrow_defer_timestamp;
} athost_wl_status_info_t;
#endif /* __wlfc_host_driver_definitions_h__ */

View File

@ -33,17 +33,17 @@
#define EPI_RC_NUMBER 125
#define EPI_INCREMENTAL_NUMBER 74
#define EPI_INCREMENTAL_NUMBER 78
#define EPI_BUILD_NUMBER 0
#define EPI_VERSION 5, 90, 125, 74
#define EPI_VERSION 5, 90, 125, 78
#define EPI_VERSION_NUM 0x055a7d4a
#define EPI_VERSION_NUM 0x055a7d4e
#define EPI_VERSION_DEV 5.90.125
#define EPI_VERSION_STR "5.90.125.74"
#define EPI_VERSION_STR "5.90.125.78"
#endif

View File

@ -48,23 +48,25 @@
#define BCM_MEM_FILENAME_LEN 24
#ifdef DHD_USE_STATIC_BUF
#define MAX_STATIC_BUF_NUM 16
#define STATIC_BUF_SIZE (PAGE_SIZE*2)
#define STATIC_BUF_TOTAL_LEN (MAX_STATIC_BUF_NUM*STATIC_BUF_SIZE)
#define STATIC_BUF_MAX_NUM 16
#define STATIC_BUF_SIZE (PAGE_SIZE * 2)
#define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE)
typedef struct bcm_static_buf {
struct semaphore static_sem;
unsigned char *buf_ptr;
unsigned char buf_use[MAX_STATIC_BUF_NUM];
unsigned char buf_use[STATIC_BUF_MAX_NUM];
} bcm_static_buf_t;
static bcm_static_buf_t *bcm_static_buf = 0;
#define MAX_STATIC_PKT_NUM 8
#define STATIC_PKT_MAX_NUM 8
typedef struct bcm_static_pkt {
struct sk_buff *skb_4k[MAX_STATIC_PKT_NUM];
struct sk_buff *skb_8k[MAX_STATIC_PKT_NUM];
struct sk_buff *skb_4k[STATIC_PKT_MAX_NUM];
struct sk_buff *skb_8k[STATIC_PKT_MAX_NUM];
struct semaphore osl_pkt_sem;
unsigned char pkt_use[MAX_STATIC_PKT_NUM*2];
unsigned char pkt_use[STATIC_PKT_MAX_NUM * 2];
} bcm_static_pkt_t;
static bcm_static_pkt_t *bcm_static_skb = 0;
#endif
@ -228,8 +230,8 @@ osl_attach(void *pdev, uint bustype, bool pkttag)
bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048);
skb_buff_ptr = dhd_os_prealloc(osh, 4, 0);
bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)*16);
for (i = 0; i < MAX_STATIC_PKT_NUM*2; i++)
bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * 16);
for (i = 0; i < STATIC_PKT_MAX_NUM * 2; i++)
bcm_static_skb->pkt_use[i] = 0;
sema_init(&bcm_static_skb->osl_pkt_sem, 1);
@ -548,84 +550,69 @@ osl_pktget_static(osl_t *osh, uint len)
struct sk_buff *skb;
if (len > (PAGE_SIZE*2))
{
if (len > (PAGE_SIZE * 2)) {
printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len);
printk("Do we really need this big skb??\n");
return osl_pktget(osh, len);
}
down(&bcm_static_skb->osl_pkt_sem);
if (len <= PAGE_SIZE)
{
for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
{
if (len <= PAGE_SIZE) {
for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
if (bcm_static_skb->pkt_use[i] == 0)
break;
}
if (i != MAX_STATIC_PKT_NUM)
{
if (i != STATIC_PKT_MAX_NUM) {
bcm_static_skb->pkt_use[i] = 1;
up(&bcm_static_skb->osl_pkt_sem);
skb = bcm_static_skb->skb_4k[i];
skb->tail = skb->data + len;
skb->len = len;
return skb;
}
}
for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
{
if (bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] == 0)
for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
if (bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] == 0)
break;
}
if (i != MAX_STATIC_PKT_NUM)
{
bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] = 1;
if (i != STATIC_PKT_MAX_NUM) {
bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] = 1;
up(&bcm_static_skb->osl_pkt_sem);
skb = bcm_static_skb->skb_8k[i];
skb->tail = skb->data + len;
skb->len = len;
return skb;
}
up(&bcm_static_skb->osl_pkt_sem);
printk("all static pkt in use!\n");
printk("%s: all static pkt in use!\n", __FUNCTION__);
return osl_pktget(osh, len);
}
void
osl_pktfree_static(osl_t *osh, void *p, bool send)
{
int i;
for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
{
if (p == bcm_static_skb->skb_4k[i])
{
for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
if (p == bcm_static_skb->skb_4k[i]) {
down(&bcm_static_skb->osl_pkt_sem);
bcm_static_skb->pkt_use[i] = 0;
up(&bcm_static_skb->osl_pkt_sem);
return;
}
}
for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
{
if (p == bcm_static_skb->skb_8k[i])
{
for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
if (p == bcm_static_skb->skb_8k[i]) {
down(&bcm_static_skb->osl_pkt_sem);
bcm_static_skb->pkt_use[i + MAX_STATIC_PKT_NUM] = 0;
bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0;
up(&bcm_static_skb->osl_pkt_sem);
return;

View File

@ -108,6 +108,7 @@ uint dhd_dev_reset(struct net_device *dev, uint8 flag);
void dhd_dev_init_ioctl(struct net_device *dev);
#ifdef WL_CFG80211
int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command);
#else
int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) { return 0; }
#endif
@ -454,6 +455,9 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
net_os_set_packet_filter(net, 0); /* DHCP starts */
else
net_os_set_packet_filter(net, 1); /* DHCP ends */
#ifdef WL_CFG80211
bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
#endif
}
else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);

View File

@ -123,6 +123,32 @@ static ctl_table wl_sysctl_table[] = {
static struct ctl_table_header *wl_sysctl_hdr;
#endif /* CONFIG_SYSCTL */
#define COEX_DHCP
#if defined(COEX_DHCP)
#define BT_DHCP_eSCO_FIX /* use New SCO/eSCO smart YG
* suppression
*/
#define BT_DHCP_USE_FLAGS /* this flag boost wifi pkt priority
* to max, caution: -not fair to sco
*/
#define BT_DHCP_OPPR_WIN_TIME 2500 /* T1 start SCO/ESCo priority
* suppression
*/
#define BT_DHCP_FLAG_FORCE_TIME 5500 /* T2 turn off SCO/SCO supperesion
* is (timeout)
*/
enum wl_cfg80211_btcoex_status {
BT_DHCP_IDLE,
BT_DHCP_START,
BT_DHCP_OPPR_WIN,
BT_DHCP_FLAG_FORCE_TIMEOUT
};
static int wl_cfg80211_btcoex_init(struct wl_priv *wl);
static void wl_cfg80211_btcoex_deinit(struct wl_priv *wl);
#endif
/* This is to override regulatory domains defined in cfg80211 module (reg.c)
* By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
* and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
@ -909,7 +935,6 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
return ERR_PTR(-ENODEV);
}
static s32
wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
{
@ -944,7 +969,6 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
(wl->scan_request == false),
msecs_to_jiffies(MAX_WAIT_TIME));
if (timeout > 0 && (!wl->scan_request)) {
WL_DBG(("IFDEL Operations Done"));
} else {
@ -1063,6 +1087,7 @@ s32
wl_cfg80211_ifdel_ops(struct net_device *net)
{
struct wl_priv *wl = wlcfg_drv_priv;
int rollback_lock = FALSE;
if (!net || !net->name) {
WL_DBG(("net is NULL\n"));
@ -1073,10 +1098,15 @@ wl_cfg80211_ifdel_ops(struct net_device *net)
/* Abort any pending scan requests */
wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
rtnl_lock();
if (!rtnl_is_locked()) {
rtnl_lock();
rollback_lock = TRUE;
}
WL_INFO(("ESCAN COMPLETED\n"));
wl_notify_escan_complete(wl, true);
rtnl_unlock();
if (rollback_lock)
rtnl_unlock();
}
/* Wake up any waiting thread */
@ -1093,7 +1123,6 @@ wl_cfg80211_notify_ifdel(struct net_device *net)
if (wl->p2p->vif_created) {
s32 index = 0;
WL_DBG(("IF_DEL event called from dongle, net %x, vif name: %s\n",
(unsigned int)net, wl->p2p->vir_ifname));
@ -1459,6 +1488,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
struct wl_priv *wl = wiphy_priv(wiphy);
struct cfg80211_ssid *ssids;
struct wl_scan_req *sr = wl_to_sr(wl);
wpa_ie_fixed_t *wps_ie;
s32 passive_scan;
bool iscan_req;
bool escan_req;
@ -1466,7 +1496,8 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
bool p2p_ssid;
s32 err = 0;
s32 i;
u32 wpsie_len = 0;
u8 wpsie[IE_MAX_LEN];
if (unlikely(wl_get_drv_status(wl, SCANNING))) {
WL_ERR(("Scanning already : status (%d)\n", (int)wl->status));
return -EAGAIN;
@ -1531,6 +1562,26 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
}
}
}
if (!wl->p2p_supported || !p2p_scan(wl)) {
if (ndev == wl_to_prmry_ndev(wl)) {
/* find the WPSIE */
memset(wpsie, 0, sizeof(wpsie));
if ((wps_ie = wl_cfgp2p_find_wpsie(
(u8 *)request->ie,
request->ie_len)) != NULL) {
wpsie_len =
wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
memcpy(wpsie, wps_ie, wpsie_len);
} else {
wpsie_len = 0;
}
err = wl_cfgp2p_set_management_ie(wl, ndev, -1,
VNDR_IE_PRBREQ_FLAG, wpsie, wpsie_len);
if (unlikely(err)) {
goto scan_out;
}
}
}
}
}
} else { /* scan in ibss */
@ -1615,6 +1666,7 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
WL_DBG(("Enter \n"));
CHECK_SYS_UP(wl);
err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
if (unlikely(err)) {
WL_ERR(("scan error (%d)\n", err));
@ -2100,9 +2152,12 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
size_t join_params_size;
s32 err = 0;
wpa_ie_fixed_t *wpa_ie;
wpa_ie_fixed_t *wps_ie;
bcm_tlv_t *wpa2_ie;
u8* wpaie = 0;
u32 wpaie_len = 0;
u32 wpsie_len = 0;
u8 wpsie[IE_MAX_LEN];
WL_DBG(("In\n"));
CHECK_SYS_UP(wl);
@ -2126,7 +2181,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
} else if (p2p_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
/* This is the connect req after WPS is done [credentials exchanged]
/* This is the connect req after WPS is done [credentials exchanged]
* currently identified with WPA_VERSION_2 .
* Update the previously set IEs with
* the newly received IEs from Supplicant. This will remove the WPS IE from
@ -2158,8 +2213,21 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
ioctlbuf, sizeof(ioctlbuf));
}
/* find the WPSIE */
memset(wpsie, 0, sizeof(wpsie));
if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)sme->ie,
sme->ie_len)) != NULL) {
wpsie_len = wps_ie->length +WPA_RSN_IE_TAG_FIXED_LEN;
memcpy(wpsie, wps_ie, wpsie_len);
} else {
wpsie_len = 0;
}
err = wl_cfgp2p_set_management_ie(wl, dev, -1,
VNDR_IE_ASSOCREQ_FLAG, wpsie, wpsie_len);
if (unlikely(err)) {
return err;
}
}
if (unlikely(!sme->ssid)) {
WL_ERR(("Invalid ssid\n"));
return -EOPNOTSUPP;
@ -2594,17 +2662,6 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
}
return err;
}
#ifdef NOT_YET
/* TODO: Removed in P2P twig, check later --lin */
val = 0; /* assume open key. otherwise 1 */
val = htod32(val);
err = wldev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val), false);
if (unlikely(err)) {
WL_ERR(("WLC_SET_AUTH error (%d)\n", err));
return err;
}
#endif
return err;
}
@ -3145,9 +3202,6 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
wl_cfgp2p_set_management_ie(wl, dev, bssidx,
VNDR_IE_PRBRSP_FLAG,
(u8 *)wps_ie, wpsie_len + p2pie_len);
/* remove WLC_E_PROBREQ_MSG event to prevent HOSTAPD
* from responding many probe request
*/
}
}
cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL);
@ -3198,7 +3252,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
wifi_p2p_pub_act_frame_t *act_frm =
(wifi_p2p_pub_act_frame_t *) (action_frame->data);
/*
* To make sure to send successfully action frame, we have to turn off mpc
* To make sure to send successfully action frame, we have to turn off mpc
*/
if ((act_frm->subtype == P2P_PAF_GON_REQ)||
(act_frm->subtype == P2P_PAF_GON_RSP)) {
@ -3702,8 +3756,11 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
} else {
WL_DBG(("No WPSIE in beacon \n"));
}
wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), false);
err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), false);
if (unlikely(err)) {
WL_ERR(("WLC_UP error (%d)\n", err));
return err;
}
memset(&join_params, 0, sizeof(join_params));
/* join parameters starts with ssid */
join_params_size = sizeof(join_params.ssid);
@ -4222,7 +4279,7 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
} else {
WL_DBG(("wl_notify_connect_status : event %d status : %d \n",
ntoh32(e->event_type), ntoh32(e->status)));
ntoh32(e->event_type), ntoh32(e->status)));
if (wl_is_linkup(wl, e, ndev)) {
wl_link_up(wl);
act = true;
@ -4859,7 +4916,11 @@ static s32 wl_init_priv_mem(struct wl_priv *wl)
WL_ERR(("pmk list alloc failed\n"));
goto init_priv_mem_out;
}
wl->sta_info = (void *)kzalloc(sizeof(*wl->sta_info), GFP_KERNEL);
if (unlikely(!wl->sta_info)) {
WL_ERR(("sta info alloc failed\n"));
goto init_priv_mem_out;
}
return 0;
init_priv_mem_out:
@ -4892,6 +4953,8 @@ static void wl_deinit_priv_mem(struct wl_priv *wl)
wl->fw = NULL;
kfree(wl->pmk_list);
wl->pmk_list = NULL;
kfree(wl->sta_info);
wl->sta_info = NULL;
if (wl->ap_info) {
kfree(wl->ap_info->wpa_ie);
kfree(wl->ap_info->rsn_ie);
@ -5428,6 +5491,11 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
goto cfg80211_attach_out;
}
#endif
#if defined(COEX_DHCP)
if (wl_cfg80211_btcoex_init(wl))
goto cfg80211_attach_out;
#endif /* COEX_DHCP */
wlcfg_drv_priv = wl;
return err;
@ -5444,6 +5512,11 @@ void wl_cfg80211_detach(void)
wl = wlcfg_drv_priv;
WL_TRACE(("In\n"));
#if defined(COEX_DHCP)
wl_cfg80211_btcoex_deinit(wl);
#endif /* COEX_DHCP */
#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
if (wl_sysctl_hdr)
unregister_sysctl_table(wl_sysctl_hdr);
@ -6120,6 +6193,20 @@ s32 wl_cfg80211_up(void)
return err;
}
/* Private Event to Supplicant with indication that FW hangs */
int wl_cfg80211_hang(struct net_device *dev, u16 reason)
{
struct wl_priv *wl;
wl = wlcfg_drv_priv;
WL_ERR(("In : FW crash Eventing\n"));
cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL);
if (wl != NULL) {
wl_link_down(wl);
}
return 0;
}
s32 wl_cfg80211_down(void)
{
struct wl_priv *wl;
@ -6547,3 +6634,480 @@ static int wl_setup_rfkill(struct wl_priv *wl, bool setup)
err_out:
return err;
}
#if defined(COEX_DHCP)
/*
* get named driver variable to uint register value and return error indication
* calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
*/
static int
dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
uint reg, int *retval)
{
union {
char buf[WLC_IOCTL_SMLEN];
int val;
} var;
int error;
bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
(char *)(&var), sizeof(var.buf));
error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
*retval = dtoh32(var.val);
return (error);
}
static int
dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
char ioctlbuf[1024];
#else
static char ioctlbuf[1024];
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf, sizeof(ioctlbuf), false));
}
/*
get named driver variable to uint register value and return error indication
calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
*/
static int
dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
{
char reg_addr[8];
memset(reg_addr, 0, sizeof(reg_addr));
memcpy((char *)&reg_addr[0], (char *)addr, 4);
memcpy((char *)&reg_addr[4], (char *)val, 4);
return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
}
static bool btcoex_is_sco_active(struct net_device *dev)
{
int ioc_res = 0;
bool res = FALSE;
int sco_id_cnt = 0;
int param27;
int i;
for (i = 0; i < 12; i++) {
ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
WL_INFO(("%s, sample[%d], btc params: 27:%x\n",
__FUNCTION__, i, param27));
if (ioc_res < 0) {
WL_ERR(("%s ioc read btc params error\n", __FUNCTION__));
break;
}
if ((param27 & 0x6) == 2) { /* count both sco & esco */
sco_id_cnt++;
}
if (sco_id_cnt > 2) {
WL_INFO(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n",
__FUNCTION__, sco_id_cnt, i));
res = TRUE;
break;
}
msleep(5);
}
return res;
}
#if defined(BT_DHCP_eSCO_FIX)
/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
{
static bool saved_status = FALSE;
char buf_reg50va_dhcp_on[8] =
{ 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
char buf_reg51va_dhcp_on[8] =
{ 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
char buf_reg64va_dhcp_on[8] =
{ 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
char buf_reg65va_dhcp_on[8] =
{ 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
char buf_reg71va_dhcp_on[8] =
{ 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
uint32 regaddr;
static uint32 saved_reg50;
static uint32 saved_reg51;
static uint32 saved_reg64;
static uint32 saved_reg65;
static uint32 saved_reg71;
if (trump_sco) {
/* this should reduce eSCO agressive retransmit
* w/o breaking it
*/
/* 1st save current */
WL_INFO(("Do new SCO/eSCO coex algo {save &"
"override}\n"));
if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
(!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
(!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
(!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
(!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
saved_status = TRUE;
WL_INFO(("%s saved bt_params[50,51,64,65,71]:"
"0x%x 0x%x 0x%x 0x%x 0x%x\n",
__FUNCTION__, saved_reg50, saved_reg51,
saved_reg64, saved_reg65, saved_reg71));
} else {
WL_ERR((":%s: save btc_params failed\n",
__FUNCTION__));
saved_status = FALSE;
return -1;
}
WL_INFO(("override with [50,51,64,65,71]:"
"0x%x 0x%x 0x%x 0x%x 0x%x\n",
*(u32 *)(buf_reg50va_dhcp_on+4),
*(u32 *)(buf_reg51va_dhcp_on+4),
*(u32 *)(buf_reg64va_dhcp_on+4),
*(u32 *)(buf_reg65va_dhcp_on+4),
*(u32 *)(buf_reg71va_dhcp_on+4)));
dev_wlc_bufvar_set(dev, "btc_params",
(char *)&buf_reg50va_dhcp_on[0], 8);
dev_wlc_bufvar_set(dev, "btc_params",
(char *)&buf_reg51va_dhcp_on[0], 8);
dev_wlc_bufvar_set(dev, "btc_params",
(char *)&buf_reg64va_dhcp_on[0], 8);
dev_wlc_bufvar_set(dev, "btc_params",
(char *)&buf_reg65va_dhcp_on[0], 8);
dev_wlc_bufvar_set(dev, "btc_params",
(char *)&buf_reg71va_dhcp_on[0], 8);
saved_status = TRUE;
} else if (saved_status) {
/* restore previously saved bt params */
WL_INFO(("Do new SCO/eSCO coex algo {save &"
"override}\n"));
regaddr = 50;
dev_wlc_intvar_set_reg(dev, "btc_params",
(char *)&regaddr, (char *)&saved_reg50);
regaddr = 51;
dev_wlc_intvar_set_reg(dev, "btc_params",
(char *)&regaddr, (char *)&saved_reg51);
regaddr = 64;
dev_wlc_intvar_set_reg(dev, "btc_params",
(char *)&regaddr, (char *)&saved_reg64);
regaddr = 65;
dev_wlc_intvar_set_reg(dev, "btc_params",
(char *)&regaddr, (char *)&saved_reg65);
regaddr = 71;
dev_wlc_intvar_set_reg(dev, "btc_params",
(char *)&regaddr, (char *)&saved_reg71);
WL_INFO(("restore bt_params[50,51,64,65,71]:"
"0x%x 0x%x 0x%x 0x%x 0x%x\n",
saved_reg50, saved_reg51, saved_reg64,
saved_reg65, saved_reg71));
saved_status = FALSE;
} else {
WL_ERR((":%s att to restore not saved BTCOEX params\n",
__FUNCTION__));
return -1;
}
return 0;
}
#endif /* BT_DHCP_eSCO_FIX */
static void
wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
{
#if defined(BT_DHCP_USE_FLAGS)
char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
rtnl_lock();
#endif
#if defined(BT_DHCP_eSCO_FIX)
/* set = 1, save & turn on 0 - off & restore prev settings */
set_btc_esco_params(dev, set);
#endif
#if defined(BT_DHCP_USE_FLAGS)
WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
if (set == TRUE)
/* Forcing bt_flag7 */
dev_wlc_bufvar_set(dev, "btc_flags",
(char *)&buf_flag7_dhcp_on[0],
sizeof(buf_flag7_dhcp_on));
else
/* Restoring default bt flag7 */
dev_wlc_bufvar_set(dev, "btc_flags",
(char *)&buf_flag7_default[0],
sizeof(buf_flag7_default));
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
rtnl_unlock();
#endif
}
static void wl_cfg80211_bt_timerfunc(ulong data)
{
struct btcoex_info *bt_local = (struct btcoex_info *)data;
WL_TRACE(("%s\n", __FUNCTION__));
bt_local->timer_on = 0;
schedule_work(&bt_local->work);
}
static void wl_cfg80211_bt_handler(struct work_struct *work)
{
struct btcoex_info *btcx_inf;
btcx_inf = container_of(work, struct btcoex_info, work);
if (btcx_inf->timer_on) {
btcx_inf->timer_on = 0;
del_timer_sync(&btcx_inf->timer);
}
switch (btcx_inf->bt_state) {
case BT_DHCP_START:
/* DHCP started
* provide OPPORTUNITY window to get DHCP address
*/
WL_TRACE(("%s bt_dhcp stm: started \n",
__FUNCTION__));
btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
mod_timer(&btcx_inf->timer,
jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000);
btcx_inf->timer_on = 1;
break;
case BT_DHCP_OPPR_WIN:
if (btcx_inf->dhcp_done) {
WL_TRACE(("%s DHCP Done before T1 expiration\n",
__FUNCTION__));
goto btc_coex_idle;
}
/* DHCP is not over yet, start lowering BT priority
* enforce btc_params + flags if necessary
*/
WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__,
BT_DHCP_OPPR_WIN_TIME));
if (btcx_inf->dev)
wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
mod_timer(&btcx_inf->timer,
jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
btcx_inf->timer_on = 1;
break;
case BT_DHCP_FLAG_FORCE_TIMEOUT:
if (btcx_inf->dhcp_done) {
WL_TRACE(("%s DHCP Done before T2 expiration\n",
__FUNCTION__));
} else {
/* Noo dhcp during T1+T2, restore BT priority */
WL_TRACE(("%s DHCP wait interval T2:%d"
"msec expired\n", __FUNCTION__,
BT_DHCP_FLAG_FORCE_TIME));
}
/* Restoring default bt priority */
if (btcx_inf->dev)
wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
btc_coex_idle:
btcx_inf->bt_state = BT_DHCP_IDLE;
btcx_inf->timer_on = 0;
break;
default:
WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__,
btcx_inf->bt_state));
if (btcx_inf->dev)
wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
btcx_inf->bt_state = BT_DHCP_IDLE;
btcx_inf->timer_on = 0;
break;
}
net_os_wake_unlock(btcx_inf->dev);
}
static int wl_cfg80211_btcoex_init(struct wl_priv *wl)
{
struct btcoex_info *btco_inf = NULL;
btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
if (!btco_inf)
return -ENOMEM;
btco_inf->bt_state = BT_DHCP_IDLE;
btco_inf->ts_dhcp_start = 0;
btco_inf->ts_dhcp_ok = 0;
/* Set up timer for BT */
btco_inf->timer_ms = 10;
init_timer(&btco_inf->timer);
btco_inf->timer.data = (ulong)btco_inf;
btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
btco_inf->dev = wl->wdev->netdev;
INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
wl->btcoex_info = btco_inf;
return 0;
}
static void
wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
{
if (!wl->btcoex_info)
return;
if (!wl->btcoex_info->timer_on) {
wl->btcoex_info->timer_on = 0;
del_timer_sync(&wl->btcoex_info->timer);
}
cancel_work_sync(&wl->btcoex_info->work);
kfree(wl->btcoex_info);
wl->btcoex_info = NULL;
}
#endif /* OEM_ANDROID */
int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
{
char powermode_val = 0;
char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
uint32 regaddr;
static uint32 saved_reg66;
static uint32 saved_reg41;
static uint32 saved_reg68;
static bool saved_status = FALSE;
#ifdef COEX_DHCP
char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
struct btcoex_info *btco_inf = wlcfg_drv_priv->btcoex_info;
#endif /* COEX_DHCP */
/* Figure out powermode 1 or o command */
strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
/* Retrieve and saved orig regs value */
if ((saved_status == FALSE) &&
(!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
(!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
(!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
saved_status = TRUE;
WL_INFO(("Saved 0x%x 0x%x 0x%x\n",
saved_reg66, saved_reg41, saved_reg68));
/* Disable PM mode during dhpc session */
/* Disable PM mode during dhpc session */
#ifdef COEX_DHCP
/* Start BT timer only for SCO connection */
if (btcoex_is_sco_active(dev)) {
/* btc_params 66 */
dev_wlc_bufvar_set(dev, "btc_params",
(char *)&buf_reg66va_dhcp_on[0],
sizeof(buf_reg66va_dhcp_on));
/* btc_params 41 0x33 */
dev_wlc_bufvar_set(dev, "btc_params",
(char *)&buf_reg41va_dhcp_on[0],
sizeof(buf_reg41va_dhcp_on));
/* btc_params 68 0x190 */
dev_wlc_bufvar_set(dev, "btc_params",
(char *)&buf_reg68va_dhcp_on[0],
sizeof(buf_reg68va_dhcp_on));
saved_status = TRUE;
btco_inf->bt_state = BT_DHCP_START;
btco_inf->timer_on = 1;
mod_timer(&btco_inf->timer, btco_inf->timer.expires);
WL_INFO(("%s enable BT DHCP Timer\n",
__FUNCTION__));
}
#endif /* COEX_DHCP */
}
else if (saved_status == TRUE) {
WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
}
}
else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
/* Restoring PM mode */
#ifdef COEX_DHCP
/* Stop any bt timer because DHCP session is done */
WL_INFO(("%s disable BT DHCP Timer\n", __FUNCTION__));
if (btco_inf->timer_on) {
btco_inf->timer_on = 0;
del_timer_sync(&btco_inf->timer);
if (btco_inf->bt_state != BT_DHCP_IDLE) {
/* need to restore original btc flags & extra btc params */
WL_INFO(("%s bt->bt_state:%d\n",
__FUNCTION__, btco_inf->bt_state));
/* wake up btcoex thread to restore btlags+params */
schedule_work(&btco_inf->work);
}
}
/* Restoring btc_flag paramter anyway */
if (saved_status == TRUE)
dev_wlc_bufvar_set(dev, "btc_flags",
(char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
#endif /* COEX_DHCP */
/* Restore original values */
if (saved_status == TRUE) {
regaddr = 66;
dev_wlc_intvar_set_reg(dev, "btc_params",
(char *)&regaddr, (char *)&saved_reg66);
regaddr = 41;
dev_wlc_intvar_set_reg(dev, "btc_params",
(char *)&regaddr, (char *)&saved_reg41);
regaddr = 68;
dev_wlc_intvar_set_reg(dev, "btc_params",
(char *)&regaddr, (char *)&saved_reg68);
WL_INFO(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
saved_reg66, saved_reg41, saved_reg68));
}
saved_status = FALSE;
}
else {
WL_ERR(("%s Unkwown yet power setting, ignored\n",
__FUNCTION__));
}
snprintf(command, 3, "OK");
return (strlen("OK"));
}

View File

@ -323,6 +323,27 @@ struct ap_info {
u8 *wps_ie;
bool security_mode;
};
struct btcoex_info {
struct timer_list timer;
uint32 timer_ms;
uint32 timer_on;
uint32 ts_dhcp_start; /* ms ts ecord time stats */
uint32 ts_dhcp_ok; /* ms ts ecord time stats */
bool dhcp_done; /* flag, indicates that host done with
* dhcp before t1/t2 expiration
*/
int bt_state;
struct work_struct work;
struct net_device *dev;
};
struct sta_info {
/* Structure to hold WPS IE for a STA */
u8 probe_req_ie[IE_MAX_LEN];
u8 assoc_req_ie[IE_MAX_LEN];
u32 probe_req_ie_len;
u32 assoc_req_ie_len;
};
/* dongle private data of cfg80211 interface */
struct wl_priv {
struct wireless_dev *wdev; /* representing wl cfg80211 device */
@ -343,8 +364,6 @@ struct wl_priv {
struct wl_cfg80211_bss_info *bss_info;
/* information element object for internal purpose */
struct wl_ie ie;
u8 scan_ie_buf[2048];
int scan_ie_len;
struct ether_addr bssid; /* bssid of currently engaged network */
/* for synchronization of main event thread */
@ -357,7 +376,7 @@ struct wl_priv {
/* control firwmare and nvram paramter downloading */
struct wl_fw_ctrl *fw;
struct wl_pmk_list *pmk_list; /* wpa2 pmk list */
tsk_ctl_t event_tsk; /* task of main event handler thread */
tsk_ctl_t event_tsk; /* task of main event handler thread */
unsigned long status; /* current dongle status */
void *pub;
u32 channel; /* current channel */
@ -385,9 +404,10 @@ struct wl_priv {
u64 cache_cookie;
wait_queue_head_t dongle_event_wait;
struct ap_info *ap_info;
struct sta_info *sta_info;
struct p2p_info *p2p;
bool p2p_supported;
s8 last_eventmask[WL_EVENTING_MASK_LEN];
struct btcoex_info *btcoex_info;
};
#define wl_to_wiphy(w) (w->wdev->wiphy)
@ -507,6 +527,7 @@ extern void wl_cfg80211_release_fw(void);
extern s8 *wl_cfg80211_get_fwname(void);
extern s8 *wl_cfg80211_get_nvramname(void);
extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
extern int wl_cfg80211_hang(struct net_device *dev, u16 reason);
#ifdef CONFIG_SYSCTL
extern s32 wl_cfg80211_sysctl_export_devaddr(void *data);
#endif

View File

@ -627,16 +627,14 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
s32 ret = BCME_OK;
u32 pos;
u8 *ie_buf;
u8 *mgmt_ie_buf;
u32 mgmt_ie_buf_len;
u32 *mgmt_ie_len;
u8 *mgmt_ie_buf = NULL;
u32 mgmt_ie_buf_len = 0;
u32 *mgmt_ie_len = 0;
u8 ie_id, ie_len;
u8 delete = 0;
#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie)
#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len)
if (bssidx == -1)
return BCME_BADARG;
if (wl->p2p_supported && p2p_on(wl)) {
if (wl->p2p_supported && p2p_on(wl) && bssidx != -1) {
if (bssidx == P2PAPI_BSSCFG_PRIMARY)
bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
switch (pktflag) {
@ -671,7 +669,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
CFGP2P_ERR(("not suitable type\n"));
return -1;
}
} else {
} else if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
switch (pktflag) {
case VNDR_IE_PRBRSP_FLAG :
mgmt_ie_buf = wl->ap_info->probe_res_ie;
@ -689,37 +687,63 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
CFGP2P_ERR(("not suitable type\n"));
return -1;
}
bssidx = 0;
} else if (bssidx == -1 && get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) {
switch (pktflag) {
case VNDR_IE_PRBREQ_FLAG :
mgmt_ie_buf = wl->sta_info->probe_req_ie;
mgmt_ie_len = &wl->sta_info->probe_req_ie_len;
mgmt_ie_buf_len = sizeof(wl->sta_info->probe_req_ie);
break;
case VNDR_IE_ASSOCREQ_FLAG :
mgmt_ie_buf = wl->sta_info->assoc_req_ie;
mgmt_ie_len = &wl->sta_info->assoc_req_ie_len;
mgmt_ie_buf_len = sizeof(wl->sta_info->assoc_req_ie);
break;
default:
mgmt_ie_buf = NULL;
mgmt_ie_len = NULL;
CFGP2P_ERR(("not suitable type\n"));
return -1;
}
bssidx = 0;
} else {
CFGP2P_ERR(("not suitable type\n"));
return -1;
}
/* Add if there is any extra IE */
if (vndr_ie && vndr_ie_len) {
CFGP2P_INFO(("Request has extra IE"));
if (vndr_ie_len > mgmt_ie_buf_len) {
CFGP2P_ERR(("extra IE size too big\n"));
ret = -ENOMEM;
} else {
if (mgmt_ie_buf != NULL) {
if ((vndr_ie_len == *mgmt_ie_len) &&
(memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) {
CFGP2P_INFO(("Previous mgmt IE is equals to current IE"));
goto exit;
}
pos = 0;
delete = 1;
ie_buf = (u8 *) mgmt_ie_buf;
while (pos < *mgmt_ie_len) {
ie_id = ie_buf[pos++];
ie_len = ie_buf[pos++];
CFGP2P_INFO(("DELELED ID(%d), Len(%d),"
"OUI(%02x:%02x:%02x)\n",
ie_id, ie_len, ie_buf[pos],
ie_buf[pos+1], ie_buf[pos+2]));
ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag,
ie_buf+pos, VNDR_SPEC_ELEMENT_ID,
ie_buf+pos+3, ie_len-3, delete);
pos += ie_len;
}
if (vndr_ie_len > mgmt_ie_buf_len) {
CFGP2P_ERR(("extra IE size too big\n"));
ret = -ENOMEM;
} else {
if (mgmt_ie_buf != NULL) {
if (vndr_ie_len && (vndr_ie_len == *mgmt_ie_len) &&
(memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) {
CFGP2P_INFO(("Previous mgmt IE is equals to current IE"));
goto exit;
}
pos = 0;
delete = 1;
ie_buf = (u8 *) mgmt_ie_buf;
while (pos < *mgmt_ie_len) {
ie_id = ie_buf[pos++];
ie_len = ie_buf[pos++];
if ((ie_id == DOT11_MNG_VS_ID) &&
(wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) ||
wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
CFGP2P_INFO(("DELELED ID : %d, Len : %d , OUI :"
"%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
ie_buf[pos+1], ie_buf[pos+2]));
ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
}
pos += ie_len;
}
}
*mgmt_ie_len = 0;
/* Add if there is any extra IE */
if (vndr_ie && vndr_ie_len) {
/* save the current IE in wl struct */
memcpy(mgmt_ie_buf, vndr_ie, vndr_ie_len);
*mgmt_ie_len = vndr_ie_len;
@ -741,7 +765,6 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
pos += ie_len;
}
}
}
#undef IE_TYPE
#undef IE_TYPE_LEN

View File

@ -1266,6 +1266,7 @@ wl_iw_set_dtim_skip(
&iovbuf, sizeof(iovbuf))) >= 0) {
p += snprintf(p, MAX_WX_STRING, "OK");
net_os_set_dtim_skip(dev, bcn_li_dtim);
WL_TRACE(("%s: set dtim_skip %d OK\n", __FUNCTION__,
@ -1737,6 +1738,7 @@ wl_iw_control_wl_off(
sdioh_stop(NULL);
#endif
net_os_set_dtim_skip(dev, 0);
dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
@ -2415,7 +2417,7 @@ wl_iw_get_range(
list = (wl_uint32_list_t *)channels;
dwrq->length = sizeof(struct iw_range);
memset(range, 0, sizeof(range));
memset(range, 0, sizeof(*range));
range->min_nwid = range->max_nwid = 0;
@ -4472,7 +4474,7 @@ wl_iw_set_essid(
g_ssid.SSID_len = htod32(g_ssid.SSID_len);
memset(join_params, 0, sizeof(join_params));
memset(join_params, 0, sizeof(*join_params));
join_params_size = sizeof(join_params->ssid);
memcpy(join_params->ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
@ -6297,6 +6299,8 @@ wl_iw_add_wps_probe_req_ie(
str_ptr += WPS_PROBE_REQ_IE_CMD_LENGTH;
datalen = wrqu->data.length - WPS_PROBE_REQ_IE_CMD_LENGTH;
buflen = sizeof(vndr_ie_setbuf_t) + datalen - sizeof(vndr_ie_t);
ie_setbuf = (vndr_ie_setbuf_t *)kmalloc(buflen, GFP_KERNEL);
if (!ie_setbuf) {
@ -6306,16 +6310,21 @@ wl_iw_add_wps_probe_req_ie(
memset(ie_setbuf, 0x00, buflen);
strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1);
ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
iecount = htod32(1);
memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int));
pktflag = 0x10;
memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag, sizeof(uint32));
memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag,
&pktflag, sizeof(uint32));
memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data, str_ptr, datalen);
memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data,
str_ptr, datalen);
total_len = strlen("vndr_ie ") + buflen;
bufptr = (char *)kmalloc(total_len, GFP_KERNEL);
@ -7528,11 +7537,15 @@ wl_iw_set_priv(
ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra);
#endif
#ifdef CONFIG_WPS2
else if (strnicmp(extra, WPS_ADD_PROBE_REQ_IE_CMD, strlen(WPS_ADD_PROBE_REQ_IE_CMD)) == 0)
ret = wl_iw_add_wps_probe_req_ie(dev, info, (union iwreq_data *)dwrq, extra);
else if (strnicmp(extra, WPS_DEL_PROBE_REQ_IE_CMD, strlen(WPS_DEL_PROBE_REQ_IE_CMD)) == 0)
ret = wl_iw_del_wps_probe_req_ie(dev, info, (union iwreq_data *)dwrq, extra);
#endif
else if (strnicmp(extra, WPS_ADD_PROBE_REQ_IE_CMD,
strlen(WPS_ADD_PROBE_REQ_IE_CMD)) == 0)
ret = wl_iw_add_wps_probe_req_ie(dev, info,
(union iwreq_data *)dwrq, extra);
else if (strnicmp(extra, WPS_DEL_PROBE_REQ_IE_CMD,
strlen(WPS_DEL_PROBE_REQ_IE_CMD)) == 0)
ret = wl_iw_del_wps_probe_req_ie(dev, info,
(union iwreq_data *)dwrq, extra);
#endif
else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0)
@ -7761,8 +7774,8 @@ static const struct iw_priv_args wl_iw_priv_args[] =
{
WL_AP_STA_LIST,
0,
IW_PRIV_TYPE_CHAR | 0,
IW_PRIV_TYPE_CHAR | 0,
IW_PRIV_TYPE_CHAR | 1024,
"AP_GET_STA_LIST"
},