rtl8187: Implement rfkill support
Herton Ronaldo Krzesinski [Wed, 26 Aug 2009 16:54:09 +0000 (13:54 -0300)]
This change implements rfkill support for RTL8187B and RTL8187L devices,
using new cfg80211 rfkill API.

Acked-by: Larry Finger <Larry.Finger@lwfinger.net>
Tested-by: Hin-Tak Leung <htl10@users.sourceforge.net>
Signed-off-by: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

drivers/net/wireless/rtl818x/Makefile
drivers/net/wireless/rtl818x/rtl8187.h
drivers/net/wireless/rtl818x/rtl8187_dev.c
drivers/net/wireless/rtl818x/rtl8187_leds.c
drivers/net/wireless/rtl818x/rtl8187_rfkill.c [new file with mode: 0644]
drivers/net/wireless/rtl818x/rtl8187_rfkill.h [new file with mode: 0644]
drivers/net/wireless/rtl818x/rtl818x.h

index 37e3d4d..93cbfbe 100644 (file)
@@ -1,5 +1,5 @@
 rtl8180-objs           := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
-rtl8187-objs           := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o
+rtl8187-objs           := rtl8187_dev.o rtl8187_rtl8225.o rtl8187_leds.o rtl8187_rfkill.o
 
 obj-$(CONFIG_RTL8180)  += rtl8180.o
 obj-$(CONFIG_RTL8187)  += rtl8187.o
index c09bfef..bf9175a 100644 (file)
@@ -133,6 +133,7 @@ struct rtl8187_priv {
                __le16 bits16;
                __le32 bits32;
        } *io_dmabuf;
+       bool rfkill_off;
 };
 
 void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
index 5573e34..9679b29 100644 (file)
@@ -32,6 +32,7 @@
 #ifdef CONFIG_RTL8187_LEDS
 #include "rtl8187_leds.h"
 #endif
+#include "rtl8187_rfkill.h"
 
 MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
 MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
@@ -648,10 +649,10 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
 
        /* setup card */
        rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0);
-       rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
+       rtl818x_iowrite8(priv, &priv->map->GPIO0, 0);
 
        rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8));
-       rtl818x_iowrite8(priv, &priv->map->GPIO, 1);
+       rtl818x_iowrite8(priv, &priv->map->GPIO0, 1);
        rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
 
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
@@ -674,11 +675,11 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
 
        /* host_usb_init */
        rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0);
-       rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
+       rtl818x_iowrite8(priv, &priv->map->GPIO0, 0);
        reg = rtl818x_ioread8(priv, (u8 *)0xFE53);
        rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7));
        rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8));
-       rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20);
+       rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x20);
        rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
        rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80);
        rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80);
@@ -907,12 +908,12 @@ static int rtl8187_start(struct ieee80211_hw *dev)
        u32 reg;
        int ret;
 
+       mutex_lock(&priv->conf_mutex);
+
        ret = (!priv->is_rtl8187b) ? rtl8187_init_hw(dev) :
                                     rtl8187b_init_hw(dev);
        if (ret)
-               return ret;
-
-       mutex_lock(&priv->conf_mutex);
+               goto rtl8187_start_exit;
 
        init_usb_anchor(&priv->anchored);
        priv->dev = dev;
@@ -939,8 +940,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
                                  (7 << 21 /* MAX TX DMA */));
                rtl8187_init_urbs(dev);
                rtl8187b_init_status_urb(dev);
-               mutex_unlock(&priv->conf_mutex);
-               return 0;
+               goto rtl8187_start_exit;
        }
 
        rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
@@ -984,9 +984,10 @@ static int rtl8187_start(struct ieee80211_hw *dev)
        reg |= RTL818X_CMD_RX_ENABLE;
        rtl818x_iowrite8(priv, &priv->map->CMD, reg);
        INIT_DELAYED_WORK(&priv->work, rtl8187_work);
-       mutex_unlock(&priv->conf_mutex);
 
-       return 0;
+rtl8187_start_exit:
+       mutex_unlock(&priv->conf_mutex);
+       return ret;
 }
 
 static void rtl8187_stop(struct ieee80211_hw *dev)
@@ -1277,7 +1278,8 @@ static const struct ieee80211_ops rtl8187_ops = {
        .bss_info_changed       = rtl8187_bss_info_changed,
        .prepare_multicast      = rtl8187_prepare_multicast,
        .configure_filter       = rtl8187_configure_filter,
-       .conf_tx                = rtl8187_conf_tx
+       .conf_tx                = rtl8187_conf_tx,
+       .rfkill_poll            = rtl8187_rfkill_poll
 };
 
 static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -1517,6 +1519,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
        reg &= 0xFF;
        rtl8187_leds_init(dev, reg);
 #endif
+       rtl8187_rfkill_init(dev);
 
        return 0;
 
@@ -1540,6 +1543,7 @@ static void __devexit rtl8187_disconnect(struct usb_interface *intf)
 #ifdef CONFIG_RTL8187_LEDS
        rtl8187_leds_exit(dev);
 #endif
+       rtl8187_rfkill_exit(dev);
        ieee80211_unregister_hw(dev);
 
        priv = dev->priv;
index a6cfb7e..a1c670f 100644 (file)
@@ -42,7 +42,7 @@ static void led_turn_on(struct work_struct *work)
        mutex_lock(&priv->conf_mutex);
        switch (led->ledpin) {
        case LED_PIN_GPIO0:
-               rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01);
+               rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01);
                rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x00);
                break;
        case LED_PIN_LED0:
@@ -80,7 +80,7 @@ static void led_turn_off(struct work_struct *work)
        mutex_lock(&priv->conf_mutex);
        switch (led->ledpin) {
        case LED_PIN_GPIO0:
-               rtl818x_iowrite8(priv, &priv->map->GPIO, 0x01);
+               rtl818x_iowrite8(priv, &priv->map->GPIO0, 0x01);
                rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0x01);
                break;
        case LED_PIN_LED0:
diff --git a/drivers/net/wireless/rtl818x/rtl8187_rfkill.c b/drivers/net/wireless/rtl818x/rtl8187_rfkill.c
new file mode 100644 (file)
index 0000000..9fab13e
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Linux RFKILL support for RTL8187
+ *
+ * Copyright (c) 2009 Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ *
+ * Based on the RFKILL handling in the r8187 driver, which is:
+ * Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+ *
+ * Thanks to Realtek for their support!
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <net/mac80211.h>
+
+#include "rtl8187.h"
+
+static bool rtl8187_is_radio_enabled(struct rtl8187_priv *priv)
+{
+       u8 gpio;
+
+       gpio = rtl818x_ioread8(priv, &priv->map->GPIO0);
+       rtl818x_iowrite8(priv, &priv->map->GPIO0, gpio & ~0x02);
+       gpio = rtl818x_ioread8(priv, &priv->map->GPIO1);
+
+       return gpio & 0x02;
+}
+
+void rtl8187_rfkill_init(struct ieee80211_hw *hw)
+{
+       struct rtl8187_priv *priv = hw->priv;
+
+       priv->rfkill_off = rtl8187_is_radio_enabled(priv);
+       printk(KERN_INFO "rtl8187: wireless switch is %s\n",
+              priv->rfkill_off ? "on" : "off");
+       wiphy_rfkill_set_hw_state(hw->wiphy, !priv->rfkill_off);
+       wiphy_rfkill_start_polling(hw->wiphy);
+}
+
+void rtl8187_rfkill_poll(struct ieee80211_hw *hw)
+{
+       bool enabled;
+       struct rtl8187_priv *priv = hw->priv;
+
+       mutex_lock(&priv->conf_mutex);
+       enabled = rtl8187_is_radio_enabled(priv);
+       if (unlikely(enabled != priv->rfkill_off)) {
+               priv->rfkill_off = enabled;
+               printk(KERN_INFO "rtl8187: wireless radio switch turned %s\n",
+                      enabled ? "on" : "off");
+               wiphy_rfkill_set_hw_state(hw->wiphy, !enabled);
+       }
+       mutex_unlock(&priv->conf_mutex);
+}
+
+void rtl8187_rfkill_exit(struct ieee80211_hw *hw)
+{
+       wiphy_rfkill_stop_polling(hw->wiphy);
+}
diff --git a/drivers/net/wireless/rtl818x/rtl8187_rfkill.h b/drivers/net/wireless/rtl818x/rtl8187_rfkill.h
new file mode 100644 (file)
index 0000000..e12575e
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef RTL8187_RFKILL_H
+#define RTL8187_RFKILL_H
+
+void rtl8187_rfkill_init(struct ieee80211_hw *hw);
+void rtl8187_rfkill_poll(struct ieee80211_hw *hw);
+void rtl8187_rfkill_exit(struct ieee80211_hw *hw);
+
+#endif /* RTL8187_RFKILL_H */
index 562222e..8522490 100644 (file)
@@ -138,8 +138,9 @@ struct rtl818x_csr {
        __le32  RF_PARA;
        __le32  RF_TIMING;
        u8      GP_ENABLE;
-       u8      GPIO;
-       u8      reserved_12[2];
+       u8      GPIO0;
+       u8      GPIO1;
+       u8      reserved_12;
        __le32  HSSI_PARA;
        u8      reserved_13[4];
        u8      TX_AGC_CTL;