Add rfkill interface. This interface will collaborate with wi-fi off or airplane mode on event from user space. This feature is essential in fullmac wi-fi model because it needs to control power tightly. Signed-off-by: Nohee Ko <noheek@xxxxxxxxxxxx> --- drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c | 62 ++++++++++++++++++++++ drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h | 3 + 2 files changed, 65 insertions(+), 0 deletions(-) diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c index 792cffb..014300d 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c @@ -342,6 +342,12 @@ static void wl_set_mpc(struct net_device *ndev, int mpc); static int wl_debugfs_add_netdev_params(struct wl_priv *wl); static void wl_debugfs_remove_netdev(struct wl_priv *wl); +/* +* rfkill support +*/ +static int wl_setup_rfkill(struct wl_priv *wl); +static int wl_rfkill_set(void *data, bool blocked); + #define WL_PRIV_GET() \ ({ \ struct wl_iface *ci; \ @@ -3160,6 +3166,7 @@ static s32 wl_init_priv(struct wl_priv *wl) wl->active_scan = true; /* we do active scan for specific scan per default */ wl->dongle_up = false; /* dongle is not up yet */ + wl->rf_blocked = false; wl_init_eq(wl); err = wl_init_priv_mem(wl); if (unlikely(err)) @@ -3224,6 +3231,12 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) WL_ERR(("Failed to init iwm_priv (%d)\n", err)); goto cfg80211_attach_out; } + err = wl_setup_rfkill(wl); + if (unlikely(err)) { + WL_ERR(("Failed to setup rfkill %d\n", err)); + goto cfg80211_attach_out; + } + wl_set_drvdata(wl_cfg80211_dev, ci); set_bit(WL_STATUS_READY, &wl->status); @@ -3240,6 +3253,9 @@ void wl_cfg80211_detach(void) wl = WL_PRIV_GET(); + rfkill_unregister(wl->rfkill); + rfkill_destroy(wl->rfkill); + wl_deinit_priv(wl); wl_free_wdev(wl); wl_set_drvdata(wl_cfg80211_dev, NULL); @@ -4264,3 +4280,49 @@ static __used void wl_dongle_poweroff(struct wl_priv *wl) net_os_set_dtim_skip(ndev, 0); dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); } + +static const struct rfkill_ops wl_rfkill_ops = { + .set_block = wl_rfkill_set, +}; + +static int wl_rfkill_set(void *data, bool blocked) +{ + struct wl_priv *wl = (struct wl_priv *)data; + + WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked")); + + if (blocked) { + if (!wl->rf_blocked) + wl_dongle_poweroff(wl); + } else { + if (wl->rf_blocked) + wl_dongle_poweron(wl); + } + + wl->rf_blocked = blocked; + + return 0; +} + +static int wl_setup_rfkill(struct wl_priv *wl) +{ + s32 err; + + wl->rfkill = rfkill_alloc("brcmfmac-wifi", + &wl_cfg80211_get_sdio_func()->dev, + RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)wl); + + if (!wl->rfkill) { + err = -ENOMEM; + goto err_out; + } + + err = rfkill_register(wl->rfkill); + + if (err) + rfkill_destroy(wl->rfkill); + +err_out: + return err; + +} diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h index f90ecae..d5c6fe8 100644 --- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h @@ -23,6 +23,7 @@ #include <wlioctl.h> #include <linux/wireless.h> #include <net/cfg80211.h> +#include <linux/rfkill.h> struct wl_conf; struct wl_iface; @@ -342,6 +343,8 @@ struct wl_priv { u8 *ioctl_buf; /* ioctl buffer */ u8 *extra_buf; /* maily to grab assoc information */ struct dentry *debugfsdir; + struct rfkill *rfkill; + bool rf_blocked; u8 ci[0] __attribute__ ((__aligned__(NETDEV_ALIGN))); }; -- 1.7.0.4 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/devel