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 <[email protected]>
---
 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
[email protected]
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel

Reply via email to