From 5abb04a63b890dc3f4abdf7d34e8ee1943546bd7 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 21 Jan 2011 15:44:12 +0100 Subject: staging: brcm80211: implementation of RFKILL functionality Resubmitted the patch to align with staging-next tree. This change depends on suspend/resume patch as sent on Wed, Jan 12, 2011. Only hardware switch state needs to be handled by driver. RFKILL is informed when hardware switch is activated. MAC80211 rfkill_poll callback is used to check hardware switch deactivation. Reviewed-by: Brett Rudley Reviewed-by: Henry Ptasinski Signed-off-by: Arend van Spriel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmsmac/wl_export.h | 1 + drivers/staging/brcm80211/brcmsmac/wl_mac80211.c | 37 ++++++++++++++++++++++- drivers/staging/brcm80211/brcmsmac/wlc_bmac.c | 8 ++--- drivers/staging/brcm80211/brcmsmac/wlc_mac80211.c | 12 +++++--- drivers/staging/brcm80211/brcmsmac/wlc_pub.h | 1 + 5 files changed, 48 insertions(+), 11 deletions(-) diff --git a/drivers/staging/brcm80211/brcmsmac/wl_export.h b/drivers/staging/brcm80211/brcmsmac/wl_export.h index aa8b5a3ed633..16c626a8458c 100644 --- a/drivers/staging/brcm80211/brcmsmac/wl_export.h +++ b/drivers/staging/brcm80211/brcmsmac/wl_export.h @@ -34,6 +34,7 @@ extern void wl_down(struct wl_info *wl); extern void wl_txflowcontrol(struct wl_info *wl, struct wl_if *wlif, bool state, int prio); extern bool wl_alloc_dma_resources(struct wl_info *wl, uint dmaddrwidth); +extern bool wl_rfkill_set_hw_state(struct wl_info *wl); /* timer functions */ struct wl_timer; diff --git a/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c b/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c index add00462bc52..5ce0f0701d0e 100644 --- a/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c +++ b/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c @@ -142,6 +142,7 @@ static int wl_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static int wl_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn); +static void wl_ops_rfkill_poll(struct ieee80211_hw *hw); static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { @@ -162,6 +163,7 @@ static int wl_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) static int wl_ops_start(struct ieee80211_hw *hw) { struct wl_info *wl = hw->priv; + bool blocked; /* struct ieee80211_channel *curchan = hw->conf.channel; WL_NONE("%s : Initial channel: %d\n", __func__, curchan->hw_value); @@ -170,6 +172,9 @@ static int wl_ops_start(struct ieee80211_hw *hw) WL_LOCK(wl); ieee80211_wake_queues(hw); WL_UNLOCK(wl); + blocked = wl_rfkill_set_hw_state(wl); + if (!blocked) + wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); return 0; } @@ -205,8 +210,9 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) err = wl_up(wl); WL_UNLOCK(wl); - if (err != 0) + if (err != 0) { WL_ERROR("%s: wl_up() returned %d\n", __func__, err); + } return err; } @@ -583,6 +589,19 @@ wl_ampdu_action(struct ieee80211_hw *hw, return 0; } +static void wl_ops_rfkill_poll(struct ieee80211_hw *hw) +{ + struct wl_info *wl = HW_TO_WL(hw); + bool blocked; + + WL_LOCK(wl); + blocked = wlc_check_radio_disabled(wl->wlc); + WL_UNLOCK(wl); + + WL_ERROR("wl: rfkill_poll: %d\n", blocked); + wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); +} + static const struct ieee80211_ops wl_ops = { .tx = wl_ops_tx, .start = wl_ops_start, @@ -604,6 +623,7 @@ static const struct ieee80211_ops wl_ops = { .sta_add = wl_sta_add, .sta_remove = wl_sta_remove, .ampdu_action = wl_ampdu_action, + .rfkill_poll = wl_ops_rfkill_poll, }; static int wl_set_hint(struct wl_info *wl, char *abbrev) @@ -1137,6 +1157,11 @@ static void wl_remove(struct pci_dev *pdev) WL_ERROR("wl: wl_remove: pci_get_drvdata failed\n"); return; } + + /* make sure rfkill is not using driver */ + wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false); + wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); + if (!wlc_chipmatch(pdev->vendor, pdev->device)) { WL_ERROR("wl: wl_remove: wlc_chipmatch failed\n"); return; @@ -1815,3 +1840,13 @@ int wl_check_firmwares(struct wl_info *wl) return rc; } +bool wl_rfkill_set_hw_state(struct wl_info *wl) +{ + bool blocked = wlc_check_radio_disabled(wl->wlc); + + WL_ERROR("%s: update hw state: blocked=%s\n", __func__, blocked ? "true" : "false"); + wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); + if (blocked) + wiphy_rfkill_start_polling(wl->pub->ieee_hw->wiphy); + return blocked; +} diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_bmac.c b/drivers/staging/brcm80211/brcmsmac/wlc_bmac.c index 80716c544781..631ee733b9f5 100644 --- a/drivers/staging/brcm80211/brcmsmac/wlc_bmac.c +++ b/drivers/staging/brcm80211/brcmsmac/wlc_bmac.c @@ -428,14 +428,10 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded) } if (macintstatus & MI_RFDISABLE) { -#if defined(BCMDBG) - u32 rfd = R_REG(wlc_hw->osh, ®s->phydebug) & PDBG_RFD; -#endif - - WL_ERROR("wl%d: MAC Detected a change on the RF Disable Input 0x%x\n", - wlc_hw->unit, rfd); + WL_TRACE("wl%d: BMAC Detected a change on the RF Disable Input\n", wlc_hw->unit); WLCNTINCR(wlc->pub->_cnt->rfdisable); + wl_rfkill_set_hw_state(wlc->wl); } /* send any enq'd tx packets. Just makes sure to jump start tx */ diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_mac80211.c b/drivers/staging/brcm80211/brcmsmac/wlc_mac80211.c index 683bc5fd55ea..bba84ebe4d5b 100644 --- a/drivers/staging/brcm80211/brcmsmac/wlc_mac80211.c +++ b/drivers/staging/brcm80211/brcmsmac/wlc_mac80211.c @@ -2304,10 +2304,6 @@ void wlc_radio_mpc_upd(struct wlc_info *wlc) */ static void wlc_radio_upd(struct wlc_info *wlc) { - if (wlc->pub->radio_disabled) - wlc_radio_disable(wlc); - else - wlc_radio_enable(wlc); } /* maintain LED behavior in down state */ @@ -2324,6 +2320,14 @@ static void wlc_down_led_upd(struct wlc_info *wlc) } } +/* update hwradio status and return it */ +bool wlc_check_radio_disabled(struct wlc_info *wlc) +{ + wlc_radio_hwdisable_upd(wlc); + + return mboolisset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE) ? true : false; +} + void wlc_radio_disable(struct wlc_info *wlc) { if (!wlc->pub->up) { diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_pub.h b/drivers/staging/brcm80211/brcmsmac/wlc_pub.h index e8b252a699f8..0e39414d5e54 100644 --- a/drivers/staging/brcm80211/brcmsmac/wlc_pub.h +++ b/drivers/staging/brcm80211/brcmsmac/wlc_pub.h @@ -598,6 +598,7 @@ extern void wlc_getrand(struct wlc_info *wlc, u8 *buf, int len); struct scb; extern void wlc_ps_on(struct wlc_info *wlc, struct scb *scb); extern void wlc_ps_off(struct wlc_info *wlc, struct scb *scb, bool discard); +extern bool wlc_check_radio_disabled(struct wlc_info *wlc); extern bool wlc_radio_monitor_stop(struct wlc_info *wlc); #if defined(BCMDBG) -- cgit v1.2.1