Commit 5abb04a6 authored by Arend van Spriel's avatar Arend van Spriel Committed by Greg Kroah-Hartman

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: default avatarBrett Rudley <brudley@broadcom.com>
Reviewed-by: default avatarHenry Ptasinski <henryp@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 698a9dce
...@@ -34,6 +34,7 @@ extern void wl_down(struct wl_info *wl); ...@@ -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, extern void wl_txflowcontrol(struct wl_info *wl, struct wl_if *wlif, bool state,
int prio); int prio);
extern bool wl_alloc_dma_resources(struct wl_info *wl, uint dmaddrwidth); 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 */ /* timer functions */
struct wl_timer; struct wl_timer;
......
...@@ -142,6 +142,7 @@ static int wl_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ...@@ -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, static int wl_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action, enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn); 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) 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) ...@@ -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) static int wl_ops_start(struct ieee80211_hw *hw)
{ {
struct wl_info *wl = hw->priv; struct wl_info *wl = hw->priv;
bool blocked;
/* /*
struct ieee80211_channel *curchan = hw->conf.channel; struct ieee80211_channel *curchan = hw->conf.channel;
WL_NONE("%s : Initial channel: %d\n", __func__, curchan->hw_value); WL_NONE("%s : Initial channel: %d\n", __func__, curchan->hw_value);
...@@ -170,6 +172,9 @@ static int wl_ops_start(struct ieee80211_hw *hw) ...@@ -170,6 +172,9 @@ static int wl_ops_start(struct ieee80211_hw *hw)
WL_LOCK(wl); WL_LOCK(wl);
ieee80211_wake_queues(hw); ieee80211_wake_queues(hw);
WL_UNLOCK(wl); WL_UNLOCK(wl);
blocked = wl_rfkill_set_hw_state(wl);
if (!blocked)
wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
return 0; return 0;
} }
...@@ -205,8 +210,9 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) ...@@ -205,8 +210,9 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
err = wl_up(wl); err = wl_up(wl);
WL_UNLOCK(wl); WL_UNLOCK(wl);
if (err != 0) if (err != 0) {
WL_ERROR("%s: wl_up() returned %d\n", __func__, err); WL_ERROR("%s: wl_up() returned %d\n", __func__, err);
}
return err; return err;
} }
...@@ -583,6 +589,19 @@ wl_ampdu_action(struct ieee80211_hw *hw, ...@@ -583,6 +589,19 @@ wl_ampdu_action(struct ieee80211_hw *hw,
return 0; 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 = { static const struct ieee80211_ops wl_ops = {
.tx = wl_ops_tx, .tx = wl_ops_tx,
.start = wl_ops_start, .start = wl_ops_start,
...@@ -604,6 +623,7 @@ static const struct ieee80211_ops wl_ops = { ...@@ -604,6 +623,7 @@ static const struct ieee80211_ops wl_ops = {
.sta_add = wl_sta_add, .sta_add = wl_sta_add,
.sta_remove = wl_sta_remove, .sta_remove = wl_sta_remove,
.ampdu_action = wl_ampdu_action, .ampdu_action = wl_ampdu_action,
.rfkill_poll = wl_ops_rfkill_poll,
}; };
static int wl_set_hint(struct wl_info *wl, char *abbrev) static int wl_set_hint(struct wl_info *wl, char *abbrev)
...@@ -1137,6 +1157,11 @@ static void wl_remove(struct pci_dev *pdev) ...@@ -1137,6 +1157,11 @@ static void wl_remove(struct pci_dev *pdev)
WL_ERROR("wl: wl_remove: pci_get_drvdata failed\n"); WL_ERROR("wl: wl_remove: pci_get_drvdata failed\n");
return; 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)) { if (!wlc_chipmatch(pdev->vendor, pdev->device)) {
WL_ERROR("wl: wl_remove: wlc_chipmatch failed\n"); WL_ERROR("wl: wl_remove: wlc_chipmatch failed\n");
return; return;
...@@ -1815,3 +1840,13 @@ int wl_check_firmwares(struct wl_info *wl) ...@@ -1815,3 +1840,13 @@ int wl_check_firmwares(struct wl_info *wl)
return rc; 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;
}
...@@ -428,14 +428,10 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded) ...@@ -428,14 +428,10 @@ bool BCMFASTPATH wlc_dpc(struct wlc_info *wlc, bool bounded)
} }
if (macintstatus & MI_RFDISABLE) { if (macintstatus & MI_RFDISABLE) {
#if defined(BCMDBG) WL_TRACE("wl%d: BMAC Detected a change on the RF Disable Input\n", wlc_hw->unit);
u32 rfd = R_REG(wlc_hw->osh, &regs->phydebug) & PDBG_RFD;
#endif
WL_ERROR("wl%d: MAC Detected a change on the RF Disable Input 0x%x\n",
wlc_hw->unit, rfd);
WLCNTINCR(wlc->pub->_cnt->rfdisable); 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 */ /* send any enq'd tx packets. Just makes sure to jump start tx */
......
...@@ -2304,10 +2304,6 @@ void wlc_radio_mpc_upd(struct wlc_info *wlc) ...@@ -2304,10 +2304,6 @@ void wlc_radio_mpc_upd(struct wlc_info *wlc)
*/ */
static void wlc_radio_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 */ /* maintain LED behavior in down state */
...@@ -2324,6 +2320,14 @@ static void wlc_down_led_upd(struct wlc_info *wlc) ...@@ -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) void wlc_radio_disable(struct wlc_info *wlc)
{ {
if (!wlc->pub->up) { if (!wlc->pub->up) {
......
...@@ -598,6 +598,7 @@ extern void wlc_getrand(struct wlc_info *wlc, u8 *buf, int len); ...@@ -598,6 +598,7 @@ extern void wlc_getrand(struct wlc_info *wlc, u8 *buf, int len);
struct scb; struct scb;
extern void wlc_ps_on(struct wlc_info *wlc, struct scb *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 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); extern bool wlc_radio_monitor_stop(struct wlc_info *wlc);
#if defined(BCMDBG) #if defined(BCMDBG)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment