Commit 19d337df authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

rfkill: rewrite

This patch completely rewrites the rfkill core to address
the following deficiencies:

 * all rfkill drivers need to implement polling where necessary
   rather than having one central implementation

 * updating the rfkill state cannot be done from arbitrary
   contexts, forcing drivers to use schedule_work and requiring
   lots of code

 * rfkill drivers need to keep track of soft/hard blocked
   internally -- the core should do this

 * the rfkill API has many unexpected quirks, for example being
   asymmetric wrt. alloc/free and register/unregister

 * rfkill can call back into a driver from within a function the
   driver called -- this is prone to deadlocks and generally
   should be avoided

 * rfkill-input pointlessly is a separate module

 * drivers need to #ifdef rfkill functions (unless they want to
   depend on or select RFKILL) -- rfkill should provide inlines
   that do nothing if it isn't compiled in

 * the rfkill structure is not opaque -- drivers need to initialise
   it correctly (lots of sanity checking code required) -- instead
   force drivers to pass the right variables to rfkill_alloc()

 * the documentation is hard to read because it always assumes the
   reader is completely clueless and contains way TOO MANY CAPS

 * the rfkill code needlessly uses a lot of locks and atomic
   operations in locked sections

 * fix LED trigger to actually change the LED when the radio state
   changes -- this wasn't done before
Tested-by: default avatarAlan Jenkins <alan-jenkins@tuffmail.co.uk>
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> [thinkpad]
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 0f6399c4
This diff is collapsed.
...@@ -4753,9 +4753,9 @@ S: Supported ...@@ -4753,9 +4753,9 @@ S: Supported
F: fs/reiserfs/ F: fs/reiserfs/
RFKILL RFKILL
P: Ivo van Doorn P: Johannes Berg
M: IvDoorn@gmail.com M: johannes@sipsolutions.net
L: netdev@vger.kernel.org L: linux-wireless@vger.kernel.org
S: Maintained S: Maintained
F Documentation/rfkill.txt F Documentation/rfkill.txt
F: net/rfkill/ F: net/rfkill/
......
...@@ -35,21 +35,25 @@ static void tosa_bt_off(struct tosa_bt_data *data) ...@@ -35,21 +35,25 @@ static void tosa_bt_off(struct tosa_bt_data *data)
gpio_set_value(data->gpio_reset, 0); gpio_set_value(data->gpio_reset, 0);
} }
static int tosa_bt_toggle_radio(void *data, enum rfkill_state state) static int tosa_bt_set_block(void *data, bool blocked)
{ {
pr_info("BT_RADIO going: %s\n", pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on");
state == RFKILL_STATE_UNBLOCKED ? "on" : "off");
if (state == RFKILL_STATE_UNBLOCKED) { if (!blocked) {
pr_info("TOSA_BT: going ON\n"); pr_info("TOSA_BT: going ON\n");
tosa_bt_on(data); tosa_bt_on(data);
} else { } else {
pr_info("TOSA_BT: going OFF\n"); pr_info("TOSA_BT: going OFF\n");
tosa_bt_off(data); tosa_bt_off(data);
} }
return 0; return 0;
} }
static const struct rfkill_ops tosa_bt_rfkill_ops = {
.set_block = tosa_bt_set_block,
};
static int tosa_bt_probe(struct platform_device *dev) static int tosa_bt_probe(struct platform_device *dev)
{ {
int rc; int rc;
...@@ -70,18 +74,14 @@ static int tosa_bt_probe(struct platform_device *dev) ...@@ -70,18 +74,14 @@ static int tosa_bt_probe(struct platform_device *dev)
if (rc) if (rc)
goto err_pwr_dir; goto err_pwr_dir;
rfk = rfkill_allocate(&dev->dev, RFKILL_TYPE_BLUETOOTH); rfk = rfkill_alloc("tosa-bt", &dev->dev, RFKILL_TYPE_BLUETOOTH,
&tosa_bt_rfkill_ops, data);
if (!rfk) { if (!rfk) {
rc = -ENOMEM; rc = -ENOMEM;
goto err_rfk_alloc; goto err_rfk_alloc;
} }
rfk->name = "tosa-bt"; rfkill_set_led_trigger_name(rfk, "tosa-bt");
rfk->toggle_radio = tosa_bt_toggle_radio;
rfk->data = data;
#ifdef CONFIG_RFKILL_LEDS
rfk->led_trigger.name = "tosa-bt";
#endif
rc = rfkill_register(rfk); rc = rfkill_register(rfk);
if (rc) if (rc)
...@@ -92,9 +92,7 @@ static int tosa_bt_probe(struct platform_device *dev) ...@@ -92,9 +92,7 @@ static int tosa_bt_probe(struct platform_device *dev)
return 0; return 0;
err_rfkill: err_rfkill:
if (rfk) rfkill_destroy(rfk);
rfkill_free(rfk);
rfk = NULL;
err_rfk_alloc: err_rfk_alloc:
tosa_bt_off(data); tosa_bt_off(data);
err_pwr_dir: err_pwr_dir:
...@@ -113,8 +111,10 @@ static int __devexit tosa_bt_remove(struct platform_device *dev) ...@@ -113,8 +111,10 @@ static int __devexit tosa_bt_remove(struct platform_device *dev)
platform_set_drvdata(dev, NULL); platform_set_drvdata(dev, NULL);
if (rfk) if (rfk) {
rfkill_unregister(rfk); rfkill_unregister(rfk);
rfkill_destroy(rfk);
}
rfk = NULL; rfk = NULL;
tosa_bt_off(data); tosa_bt_off(data);
......
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/pda_power.h> #include <linux/pda_power.h>
#include <linux/rfkill.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <asm/setup.h> #include <asm/setup.h>
......
...@@ -2481,10 +2481,10 @@ static int add_net_device(struct hso_device *hso_dev) ...@@ -2481,10 +2481,10 @@ static int add_net_device(struct hso_device *hso_dev)
return 0; return 0;
} }
static int hso_radio_toggle(void *data, enum rfkill_state state) static int hso_rfkill_set_block(void *data, bool blocked)
{ {
struct hso_device *hso_dev = data; struct hso_device *hso_dev = data;
int enabled = (state == RFKILL_STATE_UNBLOCKED); int enabled = !blocked;
int rv; int rv;
mutex_lock(&hso_dev->mutex); mutex_lock(&hso_dev->mutex);
...@@ -2498,6 +2498,10 @@ static int hso_radio_toggle(void *data, enum rfkill_state state) ...@@ -2498,6 +2498,10 @@ static int hso_radio_toggle(void *data, enum rfkill_state state)
return rv; return rv;
} }
static const struct rfkill_ops hso_rfkill_ops = {
.set_block = hso_rfkill_set_block,
};
/* Creates and sets up everything for rfkill */ /* Creates and sets up everything for rfkill */
static void hso_create_rfkill(struct hso_device *hso_dev, static void hso_create_rfkill(struct hso_device *hso_dev,
struct usb_interface *interface) struct usb_interface *interface)
...@@ -2506,29 +2510,25 @@ static void hso_create_rfkill(struct hso_device *hso_dev, ...@@ -2506,29 +2510,25 @@ static void hso_create_rfkill(struct hso_device *hso_dev,
struct device *dev = &hso_net->net->dev; struct device *dev = &hso_net->net->dev;
char *rfkn; char *rfkn;
hso_net->rfkill = rfkill_allocate(&interface_to_usbdev(interface)->dev,
RFKILL_TYPE_WWAN);
if (!hso_net->rfkill) {
dev_err(dev, "%s - Out of memory\n", __func__);
return;
}
rfkn = kzalloc(20, GFP_KERNEL); rfkn = kzalloc(20, GFP_KERNEL);
if (!rfkn) { if (!rfkn)
rfkill_free(hso_net->rfkill);
hso_net->rfkill = NULL;
dev_err(dev, "%s - Out of memory\n", __func__); dev_err(dev, "%s - Out of memory\n", __func__);
return;
}
snprintf(rfkn, 20, "hso-%d", snprintf(rfkn, 20, "hso-%d",
interface->altsetting->desc.bInterfaceNumber); interface->altsetting->desc.bInterfaceNumber);
hso_net->rfkill->name = rfkn;
hso_net->rfkill->state = RFKILL_STATE_UNBLOCKED; hso_net->rfkill = rfkill_alloc(rfkn,
hso_net->rfkill->data = hso_dev; &interface_to_usbdev(interface)->dev,
hso_net->rfkill->toggle_radio = hso_radio_toggle; RFKILL_TYPE_WWAN,
&hso_rfkill_ops, hso_dev);
if (!hso_net->rfkill) {
dev_err(dev, "%s - Out of memory\n", __func__);
kfree(rfkn);
return;
}
if (rfkill_register(hso_net->rfkill) < 0) { if (rfkill_register(hso_net->rfkill) < 0) {
rfkill_destroy(hso_net->rfkill);
kfree(rfkn); kfree(rfkn);
hso_net->rfkill->name = NULL;
rfkill_free(hso_net->rfkill);
hso_net->rfkill = NULL; hso_net->rfkill = NULL;
dev_err(dev, "%s - Failed to register rfkill\n", __func__); dev_err(dev, "%s - Failed to register rfkill\n", __func__);
return; return;
...@@ -3165,8 +3165,10 @@ static void hso_free_interface(struct usb_interface *interface) ...@@ -3165,8 +3165,10 @@ static void hso_free_interface(struct usb_interface *interface)
hso_stop_net_device(network_table[i]); hso_stop_net_device(network_table[i]);
cancel_work_sync(&network_table[i]->async_put_intf); cancel_work_sync(&network_table[i]->async_put_intf);
cancel_work_sync(&network_table[i]->async_get_intf); cancel_work_sync(&network_table[i]->async_get_intf);
if (rfk) if (rfk) {
rfkill_unregister(rfk); rfkill_unregister(rfk);
rfkill_destroy(rfk);
}
hso_free_net_device(network_table[i]); hso_free_net_device(network_table[i]);
} }
} }
......
...@@ -460,12 +460,9 @@ struct ath_led { ...@@ -460,12 +460,9 @@ struct ath_led {
bool registered; bool registered;
}; };
/* Rfkill */
#define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */
struct ath_rfkill { struct ath_rfkill {
struct rfkill *rfkill; struct rfkill *rfkill;
struct delayed_work rfkill_poll; struct rfkill_ops ops;
char rfkill_name[32]; char rfkill_name[32];
}; };
...@@ -509,8 +506,6 @@ struct ath_rfkill { ...@@ -509,8 +506,6 @@ struct ath_rfkill {
#define SC_OP_RXFLUSH BIT(7) #define SC_OP_RXFLUSH BIT(7)
#define SC_OP_LED_ASSOCIATED BIT(8) #define SC_OP_LED_ASSOCIATED BIT(8)
#define SC_OP_RFKILL_REGISTERED BIT(9) #define SC_OP_RFKILL_REGISTERED BIT(9)
#define SC_OP_RFKILL_SW_BLOCKED BIT(10)
#define SC_OP_RFKILL_HW_BLOCKED BIT(11)
#define SC_OP_WAIT_FOR_BEACON BIT(12) #define SC_OP_WAIT_FOR_BEACON BIT(12)
#define SC_OP_LED_ON BIT(13) #define SC_OP_LED_ON BIT(13)
#define SC_OP_SCANNING BIT(14) #define SC_OP_SCANNING BIT(14)
......
...@@ -1192,120 +1192,69 @@ static bool ath_is_rfkill_set(struct ath_softc *sc) ...@@ -1192,120 +1192,69 @@ static bool ath_is_rfkill_set(struct ath_softc *sc)
ah->rfkill_polarity; ah->rfkill_polarity;
} }
/* h/w rfkill poll function */ /* s/w rfkill handlers */
static void ath_rfkill_poll(struct work_struct *work) static int ath_rfkill_set_block(void *data, bool blocked)
{ {
struct ath_softc *sc = container_of(work, struct ath_softc, struct ath_softc *sc = data;
rf_kill.rfkill_poll.work);
bool radio_on;
if (sc->sc_flags & SC_OP_INVALID)
return;
radio_on = !ath_is_rfkill_set(sc);
/*
* enable/disable radio only when there is a
* state change in RF switch
*/
if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) {
enum rfkill_state state;
if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) {
state = radio_on ? RFKILL_STATE_SOFT_BLOCKED
: RFKILL_STATE_HARD_BLOCKED;
} else if (radio_on) {
ath_radio_enable(sc);
state = RFKILL_STATE_UNBLOCKED;
} else {
ath_radio_disable(sc);
state = RFKILL_STATE_HARD_BLOCKED;
}
if (state == RFKILL_STATE_HARD_BLOCKED)
sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED;
else
sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED;
rfkill_force_state(sc->rf_kill.rfkill, state); if (blocked)
} ath_radio_disable(sc);
else
ath_radio_enable(sc);
queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll, return 0;
msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL));
} }
/* s/w rfkill handler */ static void ath_rfkill_poll_state(struct rfkill *rfkill, void *data)
static int ath_sw_toggle_radio(void *data, enum rfkill_state state)
{ {
struct ath_softc *sc = data; struct ath_softc *sc = data;
bool blocked = !!ath_is_rfkill_set(sc);
switch (state) { if (rfkill_set_hw_state(rfkill, blocked))
case RFKILL_STATE_SOFT_BLOCKED: ath_radio_disable(sc);
if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED | else
SC_OP_RFKILL_SW_BLOCKED))) ath_radio_enable(sc);
ath_radio_disable(sc);
sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED;
return 0;
case RFKILL_STATE_UNBLOCKED:
if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) {
sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED;
if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) {
DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the"
"radio as it is disabled by h/w\n");
return -EPERM;
}
ath_radio_enable(sc);
}
return 0;
default:
return -EINVAL;
}
} }
/* Init s/w rfkill */ /* Init s/w rfkill */
static int ath_init_sw_rfkill(struct ath_softc *sc) static int ath_init_sw_rfkill(struct ath_softc *sc)
{ {
sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy), sc->rf_kill.ops.set_block = ath_rfkill_set_block;
RFKILL_TYPE_WLAN); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
sc->rf_kill.ops.poll = ath_rfkill_poll_state;
snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name),
"ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy));
sc->rf_kill.rfkill = rfkill_alloc(sc->rf_kill.rfkill_name,
wiphy_dev(sc->hw->wiphy),
RFKILL_TYPE_WLAN,
&sc->rf_kill.ops, sc);
if (!sc->rf_kill.rfkill) { if (!sc->rf_kill.rfkill) {
DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n"); DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n");
return -ENOMEM; return -ENOMEM;
} }
snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name),
"ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy));
sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name;
sc->rf_kill.rfkill->data = sc;
sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio;
sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED;
return 0; return 0;
} }
/* Deinitialize rfkill */ /* Deinitialize rfkill */
static void ath_deinit_rfkill(struct ath_softc *sc) static void ath_deinit_rfkill(struct ath_softc *sc)
{ {
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) { if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) {
rfkill_unregister(sc->rf_kill.rfkill); rfkill_unregister(sc->rf_kill.rfkill);
rfkill_destroy(sc->rf_kill.rfkill);
sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED; sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED;
sc->rf_kill.rfkill = NULL;
} }
} }
static int ath_start_rfkill_poll(struct ath_softc *sc) static int ath_start_rfkill_poll(struct ath_softc *sc)
{ {
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
queue_delayed_work(sc->hw->workqueue,
&sc->rf_kill.rfkill_poll, 0);
if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
if (rfkill_register(sc->rf_kill.rfkill)) { if (rfkill_register(sc->rf_kill.rfkill)) {
DPRINTF(sc, ATH_DBG_FATAL, DPRINTF(sc, ATH_DBG_FATAL,
"Unable to register rfkill\n"); "Unable to register rfkill\n");
rfkill_free(sc->rf_kill.rfkill); rfkill_destroy(sc->rf_kill.rfkill);
/* Deinitialize the device */ /* Deinitialize the device */
ath_cleanup(sc); ath_cleanup(sc);
...@@ -1678,10 +1627,6 @@ int ath_attach(u16 devid, struct ath_softc *sc) ...@@ -1678,10 +1627,6 @@ int ath_attach(u16 devid, struct ath_softc *sc)
goto error_attach; goto error_attach;
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
/* Initialze h/w Rfkill */
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll);
/* Initialize s/w rfkill */ /* Initialize s/w rfkill */
error = ath_init_sw_rfkill(sc); error = ath_init_sw_rfkill(sc);
if (error) if (error)
...@@ -2214,10 +2159,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) ...@@ -2214,10 +2159,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
} else } else
sc->rx.rxlink = NULL; sc->rx.rxlink = NULL;
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) rfkill_pause_polling(sc->rf_kill.rfkill);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
#endif
/* disable HAL and put h/w to sleep */ /* disable HAL and put h/w to sleep */
ath9k_hw_disable(sc->sc_ah); ath9k_hw_disable(sc->sc_ah);
ath9k_hw_configpcipowersave(sc->sc_ah, 1); ath9k_hw_configpcipowersave(sc->sc_ah, 1);
......
...@@ -227,11 +227,6 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) ...@@ -227,11 +227,6 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
#endif
pci_save_state(pdev); pci_save_state(pdev);
pci_disable_device(pdev); pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot); pci_set_power_state(pdev, PCI_D3hot);
...@@ -256,16 +251,6 @@ static int ath_pci_resume(struct pci_dev *pdev) ...@@ -256,16 +251,6 @@ static int ath_pci_resume(struct pci_dev *pdev)
AR_GPIO_OUTPUT_MUX_AS_OUTPUT); AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
/*
* check the h/w rfkill state on resume
* and start the rfkill poll timer
*/
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
queue_delayed_work(sc->hw->workqueue,
&sc->rf_kill.rfkill_poll, 0);
#endif
return 0; return 0;
} }
......
...@@ -102,7 +102,7 @@ config B43_LEDS ...@@ -102,7 +102,7 @@ config B43_LEDS
# if it's possible. # if it's possible.
config B43_RFKILL config B43_RFKILL
bool bool
depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43) depends on B43 && (RFKILL = y || RFKILL = B43)
default y default y
# This config option automatically enables b43 HW-RNG support, # This config option automatically enables b43 HW-RNG support,
......
...@@ -87,7 +87,7 @@ static void b43_led_brightness_set(struct led_classdev *led_dev, ...@@ -87,7 +87,7 @@ static void b43_led_brightness_set(struct led_classdev *led_dev,
} }
static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
const char *name, char *default_trigger, const char *name, const char *default_trigger,
u8 led_index, bool activelow) u8 led_index, bool activelow)
{ {
int err; int err;
......
...@@ -3470,7 +3470,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) ...@@ -3470,7 +3470,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
if (!!conf->radio_enabled != phy->radio_on) { if (!!conf->radio_enabled != phy->radio_on) {
if (conf->radio_enabled) { if (conf->radio_enabled) {
b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED); b43_software_rfkill(dev, false);
b43info(dev->wl, "Radio turned on by software\n"); b43info(dev->wl, "Radio turned on by software\n");
if (!dev->radio_hw_enable) { if (!dev->radio_hw_enable) {
b43info(dev->wl, "The hardware RF-kill button " b43info(dev->wl, "The hardware RF-kill button "
...@@ -3478,7 +3478,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) ...@@ -3478,7 +3478,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
"Press the button to turn it on.\n"); "Press the button to turn it on.\n");
} }
} else { } else {
b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); b43_software_rfkill(dev, true);
b43info(dev->wl, "Radio turned off by software\n"); b43info(dev->wl, "Radio turned off by software\n");
} }
} }
......
...@@ -480,11 +480,11 @@ static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev) ...@@ -480,11 +480,11 @@ static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev)
} }
static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, static void b43_aphy_op_software_rfkill(struct b43_wldev *dev,
enum rfkill_state state) bool blocked)
{ {
struct b43_phy *phy = &dev->phy; struct b43_phy *phy = &dev->phy;
if (state == RFKILL_STATE_UNBLOCKED) { if (!blocked) {
if (phy->radio_on) if (phy->radio_on)
return; return;
b43_radio_write16(dev, 0x0004, 0x00C0); b43_radio_write16(dev, 0x0004, 0x00C0);
......
...@@ -84,7 +84,7 @@ int b43_phy_init(struct b43_wldev *dev) ...@@ -84,7 +84,7 @@ int b43_phy_init(struct b43_wldev *dev)
phy->channel = ops->get_default_chan(dev); phy->channel = ops->get_default_chan(dev);
ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED); ops->software_rfkill(dev, false);
err = ops->init(dev); err = ops->init(dev);
if (err) { if (err) {
b43err(dev->wl, "PHY init failed\n"); b43err(dev->wl, "PHY init failed\n");
...@@ -104,7 +104,7 @@ int b43_phy_init(struct b43_wldev *dev) ...@@ -104,7 +104,7 @@ int b43_phy_init(struct b43_wldev *dev)
if (ops->exit) if (ops->exit)
ops->exit(dev); ops->exit(dev);
err_block_rf: err_block_rf:
ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); ops->software_rfkill(dev, true);
return err; return err;
} }
...@@ -113,7 +113,7 @@ void b43_phy_exit(struct b43_wldev *dev) ...@@ -113,7 +113,7 @@ void b43_phy_exit(struct b43_wldev *dev)
{ {
const struct b43_phy_operations *ops = dev->phy.ops; const struct b43_phy_operations *ops = dev->phy.ops;
ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); ops->software_rfkill(dev, true);
if (ops->exit) if (ops->exit)
ops->exit(dev); ops->exit(dev);
} }
...@@ -295,18 +295,13 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel) ...@@ -295,18 +295,13 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
return err; return err;
} }
void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) void b43_software_rfkill(struct b43_wldev *dev, bool blocked)
{ {
struct b43_phy *phy = &dev->phy; struct b43_phy *phy = &dev->phy;
if (state == RFKILL_STATE_HARD_BLOCKED) {
/* We cannot hardware-block the device */
state = RFKILL_STATE_SOFT_BLOCKED;
}
b43_mac_suspend(dev); b43_mac_suspend(dev);
phy->ops->software_rfkill(dev, state); phy->ops->software_rfkill(dev, blocked);
phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); phy->radio_on = !blocked;
b43_mac_enable(dev); b43_mac_enable(dev);
} }
......
...@@ -159,7 +159,7 @@ struct b43_phy_operations { ...@@ -159,7 +159,7 @@ struct b43_phy_operations {
/* Radio */ /* Radio */
bool (*supports_hwpctl)(struct b43_wldev *dev); bool (*supports_hwpctl)(struct b43_wldev *dev);
void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state); void (*software_rfkill)(struct b43_wldev *dev, bool blocked);
void (*switch_analog)(struct b43_wldev *dev, bool on); void (*switch_analog)(struct b43_wldev *dev, bool on);
int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel); int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel);
unsigned int (*get_default_chan)(struct b43_wldev *dev); unsigned int (*get_default_chan)(struct b43_wldev *dev);
...@@ -364,7 +364,7 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel); ...@@ -364,7 +364,7 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel);
/** /**
* b43_software_rfkill - Turn the radio ON or OFF in software. * b43_software_rfkill - Turn the radio ON or OFF in software.
*/ */
void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); void b43_software_rfkill(struct b43_wldev *dev, bool blocked);
/** /**
* b43_phy_txpower_check - Check TX power output. * b43_phy_txpower_check - Check TX power output.
......
...@@ -2592,7 +2592,7 @@ static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev) ...@@ -2592,7 +2592,7 @@ static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev)
} }
static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, static void b43_gphy_op_software_rfkill(struct b43_wldev *dev,
enum rfkill_state state) bool blocked)
{ {
struct b43_phy *phy = &dev->phy; struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g; struct b43_phy_g *gphy = phy->g;
...@@ -2600,7 +2600,7 @@ static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, ...@@ -2600,7 +2600,7 @@ static void b43_gphy_op_software_rfkill(struct b43_wldev *dev,
might_sleep(); might_sleep();
if (state == RFKILL_STATE_UNBLOCKED) { if (!blocked) {
/* Turn radio ON */ /* Turn radio ON */
if (phy->radio_on) if (phy->radio_on)
return; return;
......
...@@ -488,7 +488,7 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) ...@@ -488,7 +488,7 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
} }
static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev, static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
enum rfkill_state state) bool blocked)
{ {
//TODO //TODO
} }
......
...@@ -579,7 +579,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) ...@@ -579,7 +579,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
} }
static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
enum rfkill_state state) bool blocked)
{//TODO {//TODO
} }
......
...@@ -45,12 +45,11 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) ...@@ -45,12 +45,11 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
} }
/* The poll callback for the hardware button. */ /* The poll callback for the hardware button. */
static void b43_rfkill_poll(struct input_polled_dev *poll_dev) static void b43_rfkill_poll(struct rfkill *rfkill, void *data)
{ {
struct b43_wldev *dev = poll_dev->private; struct b43_wldev *dev = data;
struct b43_wl *wl = dev->wl; struct b43_wl *wl = dev->wl;
bool enabled; bool enabled;
bool report_change = 0;
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) { if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) {
...@@ -60,68 +59,55 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) ...@@ -60,68 +59,55 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
enabled = b43_is_hw_radio_enabled(dev); enabled = b43_is_hw_radio_enabled(dev);
if (unlikely(enabled != dev->radio_hw_enable)) { if (unlikely(enabled != dev->radio_hw_enable)) {
dev->radio_hw_enable = enabled; dev->radio_hw_enable = enabled;
report_change = 1;
b43info(wl, "Radio hardware status changed to %s\n", b43info(wl, "Radio hardware status changed to %s\n",
enabled ? "ENABLED" : "DISABLED"); enabled ? "ENABLED" : "DISABLED");
enabled = !rfkill_set_hw_state(rfkill, !enabled);
if (enabled != dev->phy.radio_on)
b43_software_rfkill(dev, !enabled);
} }
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
/* send the radio switch event to the system - note both a key press
* and a release are required */
if (unlikely(report_change)) {
input_report_key(poll_dev->input, KEY_WLAN, 1);
input_report_key(poll_dev->input, KEY_WLAN, 0);
}
} }
/* Called when the RFKILL toggled in software. */ /* Called when the RFKILL toggled in software. */
static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) static int b43_rfkill_soft_set(void *data, bool blocked)
{ {
struct b43_wldev *dev = data; struct b43_wldev *dev = data;
struct b43_wl *wl = dev->wl; struct b43_wl *wl = dev->wl;
int err = -EBUSY; int err = -EINVAL;
if (!wl->rfkill.registered) if (WARN_ON(!wl->rfkill.registered))
return 0; return -EINVAL;
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (b43_status(dev) < B43_STAT_INITIALIZED) if (b43_status(dev) < B43_STAT_INITIALIZED)
goto out_unlock; goto out_unlock;
if (!dev->radio_hw_enable)
goto out_unlock;
if (!blocked != dev->phy.radio_on)
b43_software_rfkill(dev, blocked);
err = 0; err = 0;
switch (state) {
case RFKILL_STATE_UNBLOCKED:
if (!dev->radio_hw_enable) {
/* No luck. We can't toggle the hardware RF-kill
* button from software. */
err = -EBUSY;
goto out_unlock;
}
if (!dev->phy.radio_on)
b43_software_rfkill(dev, state);
break;
case RFKILL_STATE_SOFT_BLOCKED:
if (dev->phy.radio_on)
b43_software_rfkill(dev, state);
break;
default:
b43warn(wl, "Received unexpected rfkill state %d.\n", state);
break;
}
out_unlock: out_unlock:
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
return err; return err;
} }
char *b43_rfkill_led_name(struct b43_wldev *dev) const char *b43_rfkill_led_name(struct b43_wldev *dev)
{ {
struct b43_rfkill *rfk = &(dev->wl->rfkill); struct b43_rfkill *rfk = &(dev->wl->rfkill);
if (!rfk->registered) if (!rfk->registered)
return NULL; return NULL;
return rfkill_get_led_name(rfk->rfkill); return rfkill_get_led_trigger_name(rfk->rfkill);
} }
static const struct rfkill_ops b43_rfkill_ops = {
.set_block = b43_rfkill_soft_set,
.poll = b43_rfkill_poll,
};
void b43_rfkill_init(struct b43_wldev *dev) void b43_rfkill_init(struct b43_wldev *dev)
{ {
struct b43_wl *wl = dev->wl; struct b43_wl *wl = dev->wl;
...@@ -130,65 +116,26 @@ void b43_rfkill_init(struct b43_wldev *dev) ...@@ -130,65 +116,26 @@ void b43_rfkill_init(struct b43_wldev *dev)
rfk->registered = 0; rfk->registered = 0;
rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
if (!rfk->rfkill)
goto out_error;
snprintf(rfk->name, sizeof(rfk->name), snprintf(rfk->name, sizeof(rfk->name),
"b43-%s", wiphy_name(wl->hw->wiphy)); "b43-%s", wiphy_name(wl->hw->wiphy));
rfk->rfkill->name = rfk->name;
rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
rfk->rfkill->data = dev;
rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle;
rfk->poll_dev = input_allocate_polled_device();
if (!rfk->poll_dev) {
rfkill_free(rfk->rfkill);
goto err_freed_rfk;
}
rfk->poll_dev->private = dev;
rfk->poll_dev->poll = b43_rfkill_poll;
rfk->poll_dev->poll_interval = 1000; /* msecs */
rfk->poll_dev->input->name = rfk->name; rfk->rfkill = rfkill_alloc(rfk->name,
rfk->poll_dev->input->id.bustype = BUS_HOST; dev->dev->dev,
rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; RFKILL_TYPE_WLAN,
rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); &b43_rfkill_ops, dev);
set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); if (!rfk->rfkill)
goto out_error;
err = rfkill_register(rfk->rfkill); err = rfkill_register(rfk->rfkill);
if (err) if (err)
goto err_free_polldev; goto err_free;
#ifdef CONFIG_RFKILL_INPUT_MODULE
/* B43 RF-kill isn't useful without the rfkill-input subsystem.
* Try to load the module. */
err = request_module("rfkill-input");
if (err)
b43warn(wl, "Failed to load the rfkill-input module. "
"The built-in radio LED will not work.\n");
#endif /* CONFIG_RFKILL_INPUT */
#if !defined(CONFIG_RFKILL_INPUT) && !defined(CONFIG_RFKILL_INPUT_MODULE)
b43warn(wl, "The rfkill-input subsystem is not available. "
"The built-in radio LED will not work.\n");
#endif
err = input_register_polled_device(rfk->poll_dev);
if (err)
goto err_unreg_rfk;
rfk->registered = 1; rfk->registered = 1;
return; return;
err_unreg_rfk: err_free:
rfkill_unregister(rfk->rfkill); rfkill_destroy(rfk->rfkill);
err_free_polldev: out_error:
input_free_polled_device(rfk->poll_dev);
rfk->poll_dev = NULL;
err_freed_rfk:
rfk->rfkill = NULL;
out_error:
rfk->registered = 0; rfk->registered = 0;
b43warn(wl, "RF-kill button init failed\n"); b43warn(wl, "RF-kill button init failed\n");
} }
...@@ -201,9 +148,7 @@ void b43_rfkill_exit(struct b43_wldev *dev) ...@@ -201,9 +148,7 @@ void b43_rfkill_exit(struct b43_wldev *dev)
return; return;
rfk->registered = 0; rfk->registered = 0;
input_unregister_polled_device(rfk->poll_dev);
rfkill_unregister(rfk->rfkill); rfkill_unregister(rfk->rfkill);
input_free_polled_device(rfk->poll_dev); rfkill_destroy(rfk->rfkill);
rfk->poll_dev = NULL;
rfk->rfkill = NULL; rfk->rfkill = NULL;
} }
...@@ -7,14 +7,11 @@ struct b43_wldev; ...@@ -7,14 +7,11 @@ struct b43_wldev;
#ifdef CONFIG_B43_RFKILL #ifdef CONFIG_B43_RFKILL
#include <linux/rfkill.h> #include <linux/rfkill.h>
#include <linux/input-polldev.h>
struct b43_rfkill { struct b43_rfkill {
/* The RFKILL subsystem data structure */ /* The RFKILL subsystem data structure */
struct rfkill *rfkill; struct rfkill *rfkill;
/* The poll device for the RFKILL input button */
struct input_polled_dev *poll_dev;
/* Did initialization succeed? Used for freeing. */ /* Did initialization succeed? Used for freeing. */
bool registered; bool registered;
/* The unique name of this rfkill switch */ /* The unique name of this rfkill switch */
...@@ -26,7 +23,7 @@ struct b43_rfkill { ...@@ -26,7 +23,7 @@ struct b43_rfkill {
void b43_rfkill_init(struct b43_wldev *dev); void b43_rfkill_init(struct b43_wldev *dev);
void b43_rfkill_exit(struct b43_wldev *dev); void b43_rfkill_exit(struct b43_wldev *dev);
char * b43_rfkill_led_name(struct b43_wldev *dev); const char *b43_rfkill_led_name(struct b43_wldev *dev);
#else /* CONFIG_B43_RFKILL */ #else /* CONFIG_B43_RFKILL */
......
...@@ -47,7 +47,7 @@ config B43LEGACY_LEDS ...@@ -47,7 +47,7 @@ config B43LEGACY_LEDS
# if it's possible. # if it's possible.
config B43LEGACY_RFKILL config B43LEGACY_RFKILL
bool bool
depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY) depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY)
default y default y
# This config option automatically enables b43 HW-RNG support, # This config option automatically enables b43 HW-RNG support,
......
...@@ -86,7 +86,8 @@ static void b43legacy_led_brightness_set(struct led_classdev *led_dev, ...@@ -86,7 +86,8 @@ static void b43legacy_led_brightness_set(struct led_classdev *led_dev,
static int b43legacy_register_led(struct b43legacy_wldev *dev, static int b43legacy_register_led(struct b43legacy_wldev *dev,
struct b43legacy_led *led, struct b43legacy_led *led,
const char *name, char *default_trigger, const char *name,
const char *default_trigger,
u8 led_index, bool activelow) u8 led_index, bool activelow)
{ {
int err; int err;
......
...@@ -45,12 +45,11 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) ...@@ -45,12 +45,11 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
} }
/* The poll callback for the hardware button. */ /* The poll callback for the hardware button. */
static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) static void b43legacy_rfkill_poll(struct rfkill *rfkill, void *data)
{ {
struct b43legacy_wldev *dev = poll_dev->private; struct b43legacy_wldev *dev = data;
struct b43legacy_wl *wl = dev->wl; struct b43legacy_wl *wl = dev->wl;
bool enabled; bool enabled;
bool report_change = 0;
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) {
...@@ -60,71 +59,64 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) ...@@ -60,71 +59,64 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
enabled = b43legacy_is_hw_radio_enabled(dev); enabled = b43legacy_is_hw_radio_enabled(dev);
if (unlikely(enabled != dev->radio_hw_enable)) { if (unlikely(enabled != dev->radio_hw_enable)) {
dev->radio_hw_enable = enabled; dev->radio_hw_enable = enabled;
report_change = 1;
b43legacyinfo(wl, "Radio hardware status changed to %s\n", b43legacyinfo(wl, "Radio hardware status changed to %s\n",
enabled ? "ENABLED" : "DISABLED"); enabled ? "ENABLED" : "DISABLED");
enabled = !rfkill_set_hw_state(rfkill, !enabled);
if (enabled != dev->phy.radio_on) {
if (enabled)
b43legacy_radio_turn_on(dev);
else
b43legacy_radio_turn_off(dev, 0);
}
} }
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
/* send the radio switch event to the system - note both a key press
* and a release are required */
if (unlikely(report_change)) {
input_report_key(poll_dev->input, KEY_WLAN, 1);
input_report_key(poll_dev->input, KEY_WLAN, 0);
}
} }
/* Called when the RFKILL toggled in software. /* Called when the RFKILL toggled in software.
* This is called without locking. */ * This is called without locking. */
static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state) static int b43legacy_rfkill_soft_set(void *data, bool blocked)
{ {
struct b43legacy_wldev *dev = data; struct b43legacy_wldev *dev = data;
struct b43legacy_wl *wl = dev->wl; struct b43legacy_wl *wl = dev->wl;
int err = -EBUSY; int ret = -EINVAL;
if (!wl->rfkill.registered) if (!wl->rfkill.registered)
return 0; return -EINVAL;
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
goto out_unlock; goto out_unlock;
err = 0;
switch (state) { if (!dev->radio_hw_enable)
case RFKILL_STATE_UNBLOCKED: goto out_unlock;
if (!dev->radio_hw_enable) {
/* No luck. We can't toggle the hardware RF-kill if (!blocked != dev->phy.radio_on) {
* button from software. */ if (!blocked)
err = -EBUSY;
goto out_unlock;
}
if (!dev->phy.radio_on)
b43legacy_radio_turn_on(dev); b43legacy_radio_turn_on(dev);
break; else
case RFKILL_STATE_SOFT_BLOCKED:
if (dev->phy.radio_on)
b43legacy_radio_turn_off(dev, 0); b43legacy_radio_turn_off(dev, 0);
break;
default:
b43legacywarn(wl, "Received unexpected rfkill state %d.\n",
state);
break;
} }
ret = 0;
out_unlock: out_unlock:
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
return ret;
return err;
} }
char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev)
{ {
struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
if (!rfk->registered) if (!rfk->registered)
return NULL; return NULL;
return rfkill_get_led_name(rfk->rfkill); return rfkill_get_led_trigger_name(rfk->rfkill);
} }
static const struct rfkill_ops b43legacy_rfkill_ops = {
.set_block = b43legacy_rfkill_soft_set,
.poll = b43legacy_rfkill_poll,
};
void b43legacy_rfkill_init(struct b43legacy_wldev *dev) void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
{ {
struct b43legacy_wl *wl = dev->wl; struct b43legacy_wl *wl = dev->wl;
...@@ -133,60 +125,25 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev) ...@@ -133,60 +125,25 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
rfk->registered = 0; rfk->registered = 0;
rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
if (!rfk->rfkill)
goto out_error;
snprintf(rfk->name, sizeof(rfk->name), snprintf(rfk->name, sizeof(rfk->name),
"b43legacy-%s", wiphy_name(wl->hw->wiphy)); "b43legacy-%s", wiphy_name(wl->hw->wiphy));
rfk->rfkill->name = rfk->name; rfk->rfkill = rfkill_alloc(rfk->name,
rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; dev->dev->dev,
rfk->rfkill->data = dev; RFKILL_TYPE_WLAN,
rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; &b43legacy_rfkill_ops, dev);
if (!rfk->rfkill)
rfk->poll_dev = input_allocate_polled_device(); goto out_error;
if (!rfk->poll_dev) {
rfkill_free(rfk->rfkill);
goto err_freed_rfk;
}
rfk->poll_dev->private = dev;
rfk->poll_dev->poll = b43legacy_rfkill_poll;
rfk->poll_dev->poll_interval = 1000; /* msecs */
rfk->poll_dev->input->name = rfk->name;
rfk->poll_dev->input->id.bustype = BUS_HOST;
rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor;
rfk->poll_dev->input->evbit[0] = BIT(EV_KEY);
set_bit(KEY_WLAN, rfk->poll_dev->input->keybit);
err = rfkill_register(rfk->rfkill); err = rfkill_register(rfk->rfkill);
if (err) if (err)
goto err_free_polldev; goto err_free;
#ifdef CONFIG_RFKILL_INPUT_MODULE
/* B43legacy RF-kill isn't useful without the rfkill-input subsystem.
* Try to load the module. */
err = request_module("rfkill-input");
if (err)
b43legacywarn(wl, "Failed to load the rfkill-input module."
"The built-in radio LED will not work.\n");
#endif /* CONFIG_RFKILL_INPUT */
err = input_register_polled_device(rfk->poll_dev);
if (err)
goto err_unreg_rfk;
rfk->registered = 1; rfk->registered = 1;
return; return;
err_unreg_rfk: err_free:
rfkill_unregister(rfk->rfkill); rfkill_destroy(rfk->rfkill);
err_free_polldev: out_error:
input_free_polled_device(rfk->poll_dev);
rfk->poll_dev = NULL;
err_freed_rfk:
rfk->rfkill = NULL;
out_error:
rfk->registered = 0; rfk->registered = 0;
b43legacywarn(wl, "RF-kill button init failed\n"); b43legacywarn(wl, "RF-kill button init failed\n");
} }
...@@ -199,10 +156,8 @@ void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) ...@@ -199,10 +156,8 @@ void b43legacy_rfkill_exit(struct b43legacy_wldev *dev)
return; return;
rfk->registered = 0; rfk->registered = 0;
input_unregister_polled_device(rfk->poll_dev);
rfkill_unregister(rfk->rfkill); rfkill_unregister(rfk->rfkill);
input_free_polled_device(rfk->poll_dev); rfkill_destroy(rfk->rfkill);
rfk->poll_dev = NULL;
rfk->rfkill = NULL; rfk->rfkill = NULL;
} }
...@@ -6,16 +6,12 @@ struct b43legacy_wldev; ...@@ -6,16 +6,12 @@ struct b43legacy_wldev;
#ifdef CONFIG_B43LEGACY_RFKILL #ifdef CONFIG_B43LEGACY_RFKILL
#include <linux/rfkill.h> #include <linux/rfkill.h>
#include <linux/workqueue.h>
#include <linux/input-polldev.h>
struct b43legacy_rfkill { struct b43legacy_rfkill {
/* The RFKILL subsystem data structure */ /* The RFKILL subsystem data structure */
struct rfkill *rfkill; struct rfkill *rfkill;
/* The poll device for the RFKILL input button */
struct input_polled_dev *poll_dev;
/* Did initialization succeed? Used for freeing. */ /* Did initialization succeed? Used for freeing. */
bool registered; bool registered;
/* The unique name of this rfkill switch */ /* The unique name of this rfkill switch */
...@@ -27,7 +23,7 @@ struct b43legacy_rfkill { ...@@ -27,7 +23,7 @@ struct b43legacy_rfkill {
void b43legacy_rfkill_init(struct b43legacy_wldev *dev); void b43legacy_rfkill_init(struct b43legacy_wldev *dev);
void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); void b43legacy_rfkill_exit(struct b43legacy_wldev *dev);
char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev);
#else /* CONFIG_B43LEGACY_RFKILL */ #else /* CONFIG_B43LEGACY_RFKILL */
......
...@@ -5,15 +5,14 @@ config IWLWIFI ...@@ -5,15 +5,14 @@ config IWLWIFI
select FW_LOADER select FW_LOADER
select MAC80211_LEDS if IWLWIFI_LEDS select MAC80211_LEDS if IWLWIFI_LEDS
select LEDS_CLASS if IWLWIFI_LEDS select LEDS_CLASS if IWLWIFI_LEDS
select RFKILL if IWLWIFI_RFKILL
config IWLWIFI_LEDS config IWLWIFI_LEDS
bool "Enable LED support in iwlagn and iwl3945 drivers" bool "Enable LED support in iwlagn and iwl3945 drivers"
depends on IWLWIFI depends on IWLWIFI
config IWLWIFI_RFKILL config IWLWIFI_RFKILL
bool "Enable RF kill support in iwlagn and iwl3945 drivers" def_bool y
depends on IWLWIFI depends on IWLWIFI && RFKILL
config IWLWIFI_SPECTRUM_MEASUREMENT config IWLWIFI_SPECTRUM_MEASUREMENT
bool "Enable Spectrum Measurement in iwlagn driver" bool "Enable Spectrum Measurement in iwlagn driver"
......
...@@ -36,42 +36,37 @@ ...@@ -36,42 +36,37 @@
#include "iwl-core.h" #include "iwl-core.h"
/* software rf-kill from user */ /* software rf-kill from user */
static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) static int iwl_rfkill_soft_rf_kill(void *data, bool blocked)
{ {
struct iwl_priv *priv = data; struct iwl_priv *priv = data;
int err = 0;
if (!priv->rfkill) if (!priv->rfkill)
return 0; return -EINVAL;
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return 0; return 0;
IWL_DEBUG_RF_KILL(priv, "we received soft RFKILL set to state %d\n", state); IWL_DEBUG_RF_KILL(priv, "received soft RFKILL: block=%d\n", blocked);
mutex_lock(&priv->mutex); mutex_lock(&priv->mutex);
switch (state) { if (iwl_is_rfkill_hw(priv))
case RFKILL_STATE_UNBLOCKED: goto out_unlock;
if (iwl_is_rfkill_hw(priv)) {
err = -EBUSY; if (!blocked)
goto out_unlock;
}
iwl_radio_kill_sw_enable_radio(priv); iwl_radio_kill_sw_enable_radio(priv);
break; else
case RFKILL_STATE_SOFT_BLOCKED:
iwl_radio_kill_sw_disable_radio(priv); iwl_radio_kill_sw_disable_radio(priv);
break;
default:
IWL_WARN(priv, "we received unexpected RFKILL state %d\n",
state);
break;
}
out_unlock: out_unlock:
mutex_unlock(&priv->mutex); mutex_unlock(&priv->mutex);
return 0;
return err;
} }
static const struct rfkill_ops iwl_rfkill_ops = {
.set_block = iwl_rfkill_soft_rf_kill,
};
int iwl_rfkill_init(struct iwl_priv *priv) int iwl_rfkill_init(struct iwl_priv *priv)
{ {
struct device *device = wiphy_dev(priv->hw->wiphy); struct device *device = wiphy_dev(priv->hw->wiphy);
...@@ -80,21 +75,16 @@ int iwl_rfkill_init(struct iwl_priv *priv) ...@@ -80,21 +75,16 @@ int iwl_rfkill_init(struct iwl_priv *priv)
BUG_ON(device == NULL); BUG_ON(device == NULL);
IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n"); IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n");
priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); priv->rfkill = rfkill_alloc(priv->cfg->name,
device,
RFKILL_TYPE_WLAN,
&iwl_rfkill_ops, priv);
if (!priv->rfkill) { if (!priv->rfkill) {
IWL_ERR(priv, "Unable to allocate RFKILL device.\n"); IWL_ERR(priv, "Unable to allocate RFKILL device.\n");
ret = -ENOMEM; ret = -ENOMEM;
goto error; goto error;
} }
priv->rfkill->name = priv->cfg->name;
priv->rfkill->data = priv;
priv->rfkill->state = RFKILL_STATE_UNBLOCKED;
priv->rfkill->toggle_radio = iwl_rfkill_soft_rf_kill;
priv->rfkill->dev.class->suspend = NULL;
priv->rfkill->dev.class->resume = NULL;
ret = rfkill_register(priv->rfkill); ret = rfkill_register(priv->rfkill);
if (ret) { if (ret) {
IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret); IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret);
...@@ -102,11 +92,10 @@ int iwl_rfkill_init(struct iwl_priv *priv) ...@@ -102,11 +92,10 @@ int iwl_rfkill_init(struct iwl_priv *priv)
} }
IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n"); IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n");
return ret; return 0;
free_rfkill: free_rfkill:
if (priv->rfkill != NULL) rfkill_destroy(priv->rfkill);
rfkill_free(priv->rfkill);
priv->rfkill = NULL; priv->rfkill = NULL;
error: error:
...@@ -118,8 +107,10 @@ EXPORT_SYMBOL(iwl_rfkill_init); ...@@ -118,8 +107,10 @@ EXPORT_SYMBOL(iwl_rfkill_init);
void iwl_rfkill_unregister(struct iwl_priv *priv) void iwl_rfkill_unregister(struct iwl_priv *priv)
{ {
if (priv->rfkill) if (priv->rfkill) {
rfkill_unregister(priv->rfkill); rfkill_unregister(priv->rfkill);
rfkill_destroy(priv->rfkill);
}
priv->rfkill = NULL; priv->rfkill = NULL;
} }
...@@ -131,14 +122,10 @@ void iwl_rfkill_set_hw_state(struct iwl_priv *priv) ...@@ -131,14 +122,10 @@ void iwl_rfkill_set_hw_state(struct iwl_priv *priv)
if (!priv->rfkill) if (!priv->rfkill)
return; return;
if (iwl_is_rfkill_hw(priv)) { if (rfkill_set_hw_state(priv->rfkill,
rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED); !!iwl_is_rfkill_hw(priv)))
return; iwl_radio_kill_sw_disable_radio(priv);
}
if (!iwl_is_rfkill_sw(priv))
rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED);
else else
rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED); iwl_radio_kill_sw_enable_radio(priv);
} }
EXPORT_SYMBOL(iwl_rfkill_set_hw_state); EXPORT_SYMBOL(iwl_rfkill_set_hw_state);
...@@ -25,47 +25,42 @@ ...@@ -25,47 +25,42 @@
#include "iwm.h" #include "iwm.h"
static int iwm_rfkill_soft_toggle(void *data, enum rfkill_state state) static int iwm_rfkill_set_block(void *data, bool blocked)
{ {
struct iwm_priv *iwm = data; struct iwm_priv *iwm = data;
switch (state) { if (!blocked) {
case RFKILL_STATE_UNBLOCKED:
if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio)) if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio))
return -EBUSY; return -EBUSY;
if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) && if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) &&
(iwm_to_ndev(iwm)->flags & IFF_UP)) (iwm_to_ndev(iwm)->flags & IFF_UP))
iwm_up(iwm); return iwm_up(iwm);
} else {
break;
case RFKILL_STATE_SOFT_BLOCKED:
if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
iwm_down(iwm); return iwm_down(iwm);
break;
default:
break;
} }
return 0; return 0;
} }
static const struct rfkill_ops iwm_rfkill_ops = {
.set_block = iwm_rfkill_set_block,
};
int iwm_rfkill_init(struct iwm_priv *iwm) int iwm_rfkill_init(struct iwm_priv *iwm)
{ {
int ret; int ret;
iwm->rfkill = rfkill_allocate(iwm_to_dev(iwm), RFKILL_TYPE_WLAN); iwm->rfkill = rfkill_alloc(KBUILD_MODNAME,
iwm_to_dev(iwm),
RFKILL_TYPE_WLAN,
&iwm_rfkill_ops, iwm);
if (!iwm->rfkill) { if (!iwm->rfkill) {
IWM_ERR(iwm, "Unable to allocate rfkill device\n"); IWM_ERR(iwm, "Unable to allocate rfkill device\n");
return -ENOMEM; return -ENOMEM;
} }
iwm->rfkill->name = KBUILD_MODNAME;
iwm->rfkill->data = iwm;
iwm->rfkill->state = RFKILL_STATE_UNBLOCKED;
iwm->rfkill->toggle_radio = iwm_rfkill_soft_toggle;
ret = rfkill_register(iwm->rfkill); ret = rfkill_register(iwm->rfkill);
if (ret) { if (ret) {
IWM_ERR(iwm, "Failed to register rfkill device\n"); IWM_ERR(iwm, "Failed to register rfkill device\n");
...@@ -74,15 +69,15 @@ int iwm_rfkill_init(struct iwm_priv *iwm) ...@@ -74,15 +69,15 @@ int iwm_rfkill_init(struct iwm_priv *iwm)
return 0; return 0;
fail: fail:
rfkill_free(iwm->rfkill); rfkill_destroy(iwm->rfkill);
return ret; return ret;
} }
void iwm_rfkill_exit(struct iwm_priv *iwm) void iwm_rfkill_exit(struct iwm_priv *iwm)
{ {
if (iwm->rfkill) if (iwm->rfkill) {
rfkill_unregister(iwm->rfkill); rfkill_unregister(iwm->rfkill);
rfkill_destroy(iwm->rfkill);
rfkill_free(iwm->rfkill); }
iwm->rfkill = NULL; iwm->rfkill = NULL;
} }
...@@ -21,7 +21,7 @@ config ACER_WMI ...@@ -21,7 +21,7 @@ config ACER_WMI
depends on NEW_LEDS depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE depends on BACKLIGHT_CLASS_DEVICE
depends on SERIO_I8042 depends on SERIO_I8042
depends on RFKILL depends on RFKILL || RFKILL = n
select ACPI_WMI select ACPI_WMI
---help--- ---help---
This is a driver for newer Acer (and Wistron) laptops. It adds This is a driver for newer Acer (and Wistron) laptops. It adds
...@@ -60,7 +60,7 @@ config DELL_LAPTOP ...@@ -60,7 +60,7 @@ config DELL_LAPTOP
depends on DCDBAS depends on DCDBAS
depends on EXPERIMENTAL depends on EXPERIMENTAL
depends on BACKLIGHT_CLASS_DEVICE depends on BACKLIGHT_CLASS_DEVICE
depends on RFKILL depends on RFKILL || RFKILL = n
depends on POWER_SUPPLY depends on POWER_SUPPLY
default n default n
---help--- ---help---
...@@ -117,7 +117,7 @@ config HP_WMI ...@@ -117,7 +117,7 @@ config HP_WMI
tristate "HP WMI extras" tristate "HP WMI extras"
depends on ACPI_WMI depends on ACPI_WMI
depends on INPUT depends on INPUT
depends on RFKILL depends on RFKILL || RFKILL = n
help help
Say Y here if you want to support WMI-based hotkeys on HP laptops and Say Y here if you want to support WMI-based hotkeys on HP laptops and
to read data from WMI such as docking or ambient light sensor state. to read data from WMI such as docking or ambient light sensor state.
...@@ -196,14 +196,13 @@ config THINKPAD_ACPI ...@@ -196,14 +196,13 @@ config THINKPAD_ACPI
tristate "ThinkPad ACPI Laptop Extras" tristate "ThinkPad ACPI Laptop Extras"
depends on ACPI depends on ACPI
depends on INPUT depends on INPUT
depends on RFKILL || RFKILL = n
select BACKLIGHT_LCD_SUPPORT select BACKLIGHT_LCD_SUPPORT
select BACKLIGHT_CLASS_DEVICE select BACKLIGHT_CLASS_DEVICE
select HWMON select HWMON
select NVRAM select NVRAM
select NEW_LEDS select NEW_LEDS
select LEDS_CLASS select LEDS_CLASS
select NET
select RFKILL
---help--- ---help---
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video support for Fn-Fx key combinations, Bluetooth control, video
...@@ -338,9 +337,9 @@ config EEEPC_LAPTOP ...@@ -338,9 +337,9 @@ config EEEPC_LAPTOP
depends on ACPI depends on ACPI
depends on INPUT depends on INPUT
depends on EXPERIMENTAL depends on EXPERIMENTAL
depends on RFKILL || RFKILL = n
select BACKLIGHT_CLASS_DEVICE select BACKLIGHT_CLASS_DEVICE
select HWMON select HWMON
select RFKILL
---help--- ---help---
This driver supports the Fn-Fx keys on Eee PC laptops. This driver supports the Fn-Fx keys on Eee PC laptops.
It also adds the ability to switch camera/wlan on/off. It also adds the ability to switch camera/wlan on/off.
...@@ -405,9 +404,8 @@ config ACPI_TOSHIBA ...@@ -405,9 +404,8 @@ config ACPI_TOSHIBA
tristate "Toshiba Laptop Extras" tristate "Toshiba Laptop Extras"
depends on ACPI depends on ACPI
depends on INPUT depends on INPUT
depends on RFKILL || RFKILL = n
select INPUT_POLLDEV select INPUT_POLLDEV
select NET
select RFKILL
select BACKLIGHT_CLASS_DEVICE select BACKLIGHT_CLASS_DEVICE
---help--- ---help---
This driver adds support for access to certain system settings This driver adds support for access to certain system settings
......
...@@ -958,58 +958,50 @@ static void acer_rfkill_update(struct work_struct *ignored) ...@@ -958,58 +958,50 @@ static void acer_rfkill_update(struct work_struct *ignored)
status = get_u32(&state, ACER_CAP_WIRELESS); status = get_u32(&state, ACER_CAP_WIRELESS);
if (ACPI_SUCCESS(status)) if (ACPI_SUCCESS(status))
rfkill_force_state(wireless_rfkill, state ? rfkill_set_sw_state(wireless_rfkill, !!state);
RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
if (has_cap(ACER_CAP_BLUETOOTH)) { if (has_cap(ACER_CAP_BLUETOOTH)) {
status = get_u32(&state, ACER_CAP_BLUETOOTH); status = get_u32(&state, ACER_CAP_BLUETOOTH);
if (ACPI_SUCCESS(status)) if (ACPI_SUCCESS(status))
rfkill_force_state(bluetooth_rfkill, state ? rfkill_set_sw_state(bluetooth_rfkill, !!state);
RFKILL_STATE_UNBLOCKED :
RFKILL_STATE_SOFT_BLOCKED);
} }
schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
} }
static int acer_rfkill_set(void *data, enum rfkill_state state) static int acer_rfkill_set(void *data, bool blocked)
{ {
acpi_status status; acpi_status status;
u32 *cap = data; u32 cap = (unsigned long)data;
status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap); status = set_u32(!!blocked, cap);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; return -ENODEV;
return 0; return 0;
} }
static struct rfkill * acer_rfkill_register(struct device *dev, static const struct rfkill_ops acer_rfkill_ops = {
enum rfkill_type type, char *name, u32 cap) .set_block = acer_rfkill_set,
};
static struct rfkill *acer_rfkill_register(struct device *dev,
enum rfkill_type type,
char *name, u32 cap)
{ {
int err; int err;
u32 state; u32 state;
u32 *data;
struct rfkill *rfkill_dev; struct rfkill *rfkill_dev;
rfkill_dev = rfkill_allocate(dev, type); rfkill_dev = rfkill_alloc(name, dev, type,
&acer_rfkill_ops,
(void *)(unsigned long)cap);
if (!rfkill_dev) if (!rfkill_dev)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
rfkill_dev->name = name;
get_u32(&state, cap); get_u32(&state, cap);
rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED : rfkill_set_sw_state(rfkill_dev, !state);
RFKILL_STATE_SOFT_BLOCKED;
data = kzalloc(sizeof(u32), GFP_KERNEL);
if (!data) {
rfkill_free(rfkill_dev);
return ERR_PTR(-ENOMEM);
}
*data = cap;
rfkill_dev->data = data;
rfkill_dev->toggle_radio = acer_rfkill_set;
err = rfkill_register(rfkill_dev); err = rfkill_register(rfkill_dev);
if (err) { if (err) {
kfree(rfkill_dev->data); rfkill_destroy(rfkill_dev);
rfkill_free(rfkill_dev);
return ERR_PTR(err); return ERR_PTR(err);
} }
return rfkill_dev; return rfkill_dev;
...@@ -1027,8 +1019,8 @@ static int acer_rfkill_init(struct device *dev) ...@@ -1027,8 +1019,8 @@ static int acer_rfkill_init(struct device *dev)
RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
ACER_CAP_BLUETOOTH); ACER_CAP_BLUETOOTH);
if (IS_ERR(bluetooth_rfkill)) { if (IS_ERR(bluetooth_rfkill)) {
kfree(wireless_rfkill->data);
rfkill_unregister(wireless_rfkill); rfkill_unregister(wireless_rfkill);
rfkill_destroy(wireless_rfkill);
return PTR_ERR(bluetooth_rfkill); return PTR_ERR(bluetooth_rfkill);
} }
} }
...@@ -1041,11 +1033,13 @@ static int acer_rfkill_init(struct device *dev) ...@@ -1041,11 +1033,13 @@ static int acer_rfkill_init(struct device *dev)
static void acer_rfkill_exit(void) static void acer_rfkill_exit(void)
{ {
cancel_delayed_work_sync(&acer_rfkill_work); cancel_delayed_work_sync(&acer_rfkill_work);
kfree(wireless_rfkill->data);
rfkill_unregister(wireless_rfkill); rfkill_unregister(wireless_rfkill);
rfkill_destroy(wireless_rfkill);
if (has_cap(ACER_CAP_BLUETOOTH)) { if (has_cap(ACER_CAP_BLUETOOTH)) {
kfree(bluetooth_rfkill->data);
rfkill_unregister(bluetooth_rfkill); rfkill_unregister(bluetooth_rfkill);
rfkill_destroy(bluetooth_rfkill);
} }
return; return;
} }
......
...@@ -174,10 +174,11 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, ...@@ -174,10 +174,11 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
result[3]: NVRAM format version number result[3]: NVRAM format version number
*/ */
static int dell_rfkill_set(int radio, enum rfkill_state state) static int dell_rfkill_set(void *data, bool blocked)
{ {
struct calling_interface_buffer buffer; struct calling_interface_buffer buffer;
int disable = (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1; int disable = blocked ? 0 : 1;
unsigned long radio = (unsigned long)data;
memset(&buffer, 0, sizeof(struct calling_interface_buffer)); memset(&buffer, 0, sizeof(struct calling_interface_buffer));
buffer.input[0] = (1 | (radio<<8) | (disable << 16)); buffer.input[0] = (1 | (radio<<8) | (disable << 16));
...@@ -186,56 +187,24 @@ static int dell_rfkill_set(int radio, enum rfkill_state state) ...@@ -186,56 +187,24 @@ static int dell_rfkill_set(int radio, enum rfkill_state state)
return 0; return 0;
} }
static int dell_wifi_set(void *data, enum rfkill_state state) static void dell_rfkill_query(struct rfkill *rfkill, void *data)
{
return dell_rfkill_set(1, state);
}
static int dell_bluetooth_set(void *data, enum rfkill_state state)
{
return dell_rfkill_set(2, state);
}
static int dell_wwan_set(void *data, enum rfkill_state state)
{
return dell_rfkill_set(3, state);
}
static int dell_rfkill_get(int bit, enum rfkill_state *state)
{ {
struct calling_interface_buffer buffer; struct calling_interface_buffer buffer;
int status; int status;
int new_state = RFKILL_STATE_HARD_BLOCKED; int bit = (unsigned long)data + 16;
memset(&buffer, 0, sizeof(struct calling_interface_buffer)); memset(&buffer, 0, sizeof(struct calling_interface_buffer));
dell_send_request(&buffer, 17, 11); dell_send_request(&buffer, 17, 11);
status = buffer.output[1]; status = buffer.output[1];
if (status & (1<<16)) if (status & BIT(bit))
new_state = RFKILL_STATE_SOFT_BLOCKED; rfkill_set_hw_state(rfkill, !!(status & BIT(16)));
if (status & (1<<bit))
*state = new_state;
else
*state = RFKILL_STATE_UNBLOCKED;
return 0;
}
static int dell_wifi_get(void *data, enum rfkill_state *state)
{
return dell_rfkill_get(17, state);
}
static int dell_bluetooth_get(void *data, enum rfkill_state *state)
{
return dell_rfkill_get(18, state);
} }
static int dell_wwan_get(void *data, enum rfkill_state *state) static const struct rfkill_ops dell_rfkill_ops = {
{ .set_block = dell_rfkill_set,
return dell_rfkill_get(19, state); .query = dell_rfkill_query,
} };
static int dell_setup_rfkill(void) static int dell_setup_rfkill(void)
{ {
...@@ -248,36 +217,37 @@ static int dell_setup_rfkill(void) ...@@ -248,36 +217,37 @@ static int dell_setup_rfkill(void)
status = buffer.output[1]; status = buffer.output[1];
if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
wifi_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WLAN); wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN,
if (!wifi_rfkill) &dell_rfkill_ops, (void *) 1);
if (!wifi_rfkill) {
ret = -ENOMEM;
goto err_wifi; goto err_wifi;
wifi_rfkill->name = "dell-wifi"; }
wifi_rfkill->toggle_radio = dell_wifi_set;
wifi_rfkill->get_state = dell_wifi_get;
ret = rfkill_register(wifi_rfkill); ret = rfkill_register(wifi_rfkill);
if (ret) if (ret)
goto err_wifi; goto err_wifi;
} }
if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) {
bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH); bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL,
if (!bluetooth_rfkill) RFKILL_TYPE_BLUETOOTH,
&dell_rfkill_ops, (void *) 2);
if (!bluetooth_rfkill) {
ret = -ENOMEM;
goto err_bluetooth; goto err_bluetooth;
bluetooth_rfkill->name = "dell-bluetooth"; }
bluetooth_rfkill->toggle_radio = dell_bluetooth_set;
bluetooth_rfkill->get_state = dell_bluetooth_get;
ret = rfkill_register(bluetooth_rfkill); ret = rfkill_register(bluetooth_rfkill);
if (ret) if (ret)
goto err_bluetooth; goto err_bluetooth;
} }
if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) {
wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN); wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN,
if (!wwan_rfkill) &dell_rfkill_ops, (void *) 3);
if (!wwan_rfkill) {
ret = -ENOMEM;
goto err_wwan; goto err_wwan;
wwan_rfkill->name = "dell-wwan"; }
wwan_rfkill->toggle_radio = dell_wwan_set;
wwan_rfkill->get_state = dell_wwan_get;
ret = rfkill_register(wwan_rfkill); ret = rfkill_register(wwan_rfkill);
if (ret) if (ret)
goto err_wwan; goto err_wwan;
...@@ -285,22 +255,15 @@ static int dell_setup_rfkill(void) ...@@ -285,22 +255,15 @@ static int dell_setup_rfkill(void)
return 0; return 0;
err_wwan: err_wwan:
if (wwan_rfkill) rfkill_destroy(wwan_rfkill);
rfkill_free(wwan_rfkill); if (bluetooth_rfkill)
if (bluetooth_rfkill) {
rfkill_unregister(bluetooth_rfkill); rfkill_unregister(bluetooth_rfkill);
bluetooth_rfkill = NULL;
}
err_bluetooth: err_bluetooth:
if (bluetooth_rfkill) rfkill_destroy(bluetooth_rfkill);
rfkill_free(bluetooth_rfkill); if (wifi_rfkill)
if (wifi_rfkill) {
rfkill_unregister(wifi_rfkill); rfkill_unregister(wifi_rfkill);
wifi_rfkill = NULL;
}
err_wifi: err_wifi:
if (wifi_rfkill) rfkill_destroy(wifi_rfkill);
rfkill_free(wifi_rfkill);
return ret; return ret;
} }
......
...@@ -299,39 +299,22 @@ static int update_bl_status(struct backlight_device *bd) ...@@ -299,39 +299,22 @@ static int update_bl_status(struct backlight_device *bd)
* Rfkill helpers * Rfkill helpers
*/ */
static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state) static bool eeepc_wlan_rfkill_blocked(void)
{
if (state == RFKILL_STATE_SOFT_BLOCKED)
return set_acpi(CM_ASL_WLAN, 0);
else
return set_acpi(CM_ASL_WLAN, 1);
}
static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state)
{ {
if (get_acpi(CM_ASL_WLAN) == 1) if (get_acpi(CM_ASL_WLAN) == 1)
*state = RFKILL_STATE_UNBLOCKED; return false;
else return true;
*state = RFKILL_STATE_SOFT_BLOCKED;
return 0;
} }
static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state) static int eeepc_rfkill_set(void *data, bool blocked)
{ {
if (state == RFKILL_STATE_SOFT_BLOCKED) unsigned long asl = (unsigned long)data;
return set_acpi(CM_ASL_BLUETOOTH, 0); return set_acpi(asl, !blocked);
else
return set_acpi(CM_ASL_BLUETOOTH, 1);
} }
static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state) static const struct rfkill_ops eeepc_rfkill_ops = {
{ .set_block = eeepc_rfkill_set,
if (get_acpi(CM_ASL_BLUETOOTH) == 1) };
*state = RFKILL_STATE_UNBLOCKED;
else
*state = RFKILL_STATE_SOFT_BLOCKED;
return 0;
}
/* /*
* Sys helpers * Sys helpers
...@@ -531,9 +514,9 @@ static int notify_brn(void) ...@@ -531,9 +514,9 @@ static int notify_brn(void)
static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
{ {
enum rfkill_state state;
struct pci_dev *dev; struct pci_dev *dev;
struct pci_bus *bus = pci_find_bus(0, 1); struct pci_bus *bus = pci_find_bus(0, 1);
bool blocked;
if (event != ACPI_NOTIFY_BUS_CHECK) if (event != ACPI_NOTIFY_BUS_CHECK)
return; return;
...@@ -543,9 +526,8 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) ...@@ -543,9 +526,8 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
return; return;
} }
eeepc_wlan_rfkill_state(ehotk->eeepc_wlan_rfkill, &state); blocked = eeepc_wlan_rfkill_blocked();
if (!blocked) {
if (state == RFKILL_STATE_UNBLOCKED) {
dev = pci_get_slot(bus, 0); dev = pci_get_slot(bus, 0);
if (dev) { if (dev) {
/* Device already present */ /* Device already present */
...@@ -566,7 +548,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) ...@@ -566,7 +548,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
} }
} }
rfkill_force_state(ehotk->eeepc_wlan_rfkill, state); rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked);
} }
static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
...@@ -684,26 +666,17 @@ static int eeepc_hotk_add(struct acpi_device *device) ...@@ -684,26 +666,17 @@ static int eeepc_hotk_add(struct acpi_device *device)
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
if (get_acpi(CM_ASL_WLAN) != -1) { if (get_acpi(CM_ASL_WLAN) != -1) {
ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev, ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan",
RFKILL_TYPE_WLAN); &device->dev,
RFKILL_TYPE_WLAN,
&eeepc_rfkill_ops,
(void *)CM_ASL_WLAN);
if (!ehotk->eeepc_wlan_rfkill) if (!ehotk->eeepc_wlan_rfkill)
goto wlan_fail; goto wlan_fail;
ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan"; rfkill_set_global_sw_state(RFKILL_TYPE_WLAN,
ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set; get_acpi(CM_ASL_WLAN) != 1);
ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state;
if (get_acpi(CM_ASL_WLAN) == 1) {
ehotk->eeepc_wlan_rfkill->state =
RFKILL_STATE_UNBLOCKED;
rfkill_set_default(RFKILL_TYPE_WLAN,
RFKILL_STATE_UNBLOCKED);
} else {
ehotk->eeepc_wlan_rfkill->state =
RFKILL_STATE_SOFT_BLOCKED;
rfkill_set_default(RFKILL_TYPE_WLAN,
RFKILL_STATE_SOFT_BLOCKED);
}
result = rfkill_register(ehotk->eeepc_wlan_rfkill); result = rfkill_register(ehotk->eeepc_wlan_rfkill);
if (result) if (result)
goto wlan_fail; goto wlan_fail;
...@@ -711,28 +684,17 @@ static int eeepc_hotk_add(struct acpi_device *device) ...@@ -711,28 +684,17 @@ static int eeepc_hotk_add(struct acpi_device *device)
if (get_acpi(CM_ASL_BLUETOOTH) != -1) { if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
ehotk->eeepc_bluetooth_rfkill = ehotk->eeepc_bluetooth_rfkill =
rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH); rfkill_alloc("eeepc-bluetooth",
&device->dev,
RFKILL_TYPE_BLUETOOTH,
&eeepc_rfkill_ops,
(void *)CM_ASL_BLUETOOTH);
if (!ehotk->eeepc_bluetooth_rfkill) if (!ehotk->eeepc_bluetooth_rfkill)
goto bluetooth_fail; goto bluetooth_fail;
ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth"; rfkill_set_global_sw_state(RFKILL_TYPE_BLUETOOTH,
ehotk->eeepc_bluetooth_rfkill->toggle_radio = get_acpi(CM_ASL_BLUETOOTH) != 1);
eeepc_bluetooth_rfkill_set;
ehotk->eeepc_bluetooth_rfkill->get_state =
eeepc_bluetooth_rfkill_state;
if (get_acpi(CM_ASL_BLUETOOTH) == 1) {
ehotk->eeepc_bluetooth_rfkill->state =
RFKILL_STATE_UNBLOCKED;
rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
RFKILL_STATE_UNBLOCKED);
} else {
ehotk->eeepc_bluetooth_rfkill->state =
RFKILL_STATE_SOFT_BLOCKED;
rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
RFKILL_STATE_SOFT_BLOCKED);
}
result = rfkill_register(ehotk->eeepc_bluetooth_rfkill); result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
if (result) if (result)
goto bluetooth_fail; goto bluetooth_fail;
...@@ -741,13 +703,10 @@ static int eeepc_hotk_add(struct acpi_device *device) ...@@ -741,13 +703,10 @@ static int eeepc_hotk_add(struct acpi_device *device)
return 0; return 0;
bluetooth_fail: bluetooth_fail:
if (ehotk->eeepc_bluetooth_rfkill) rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
rfkill_free(ehotk->eeepc_bluetooth_rfkill);
rfkill_unregister(ehotk->eeepc_wlan_rfkill); rfkill_unregister(ehotk->eeepc_wlan_rfkill);
ehotk->eeepc_wlan_rfkill = NULL;
wlan_fail: wlan_fail:
if (ehotk->eeepc_wlan_rfkill) rfkill_destroy(ehotk->eeepc_wlan_rfkill);
rfkill_free(ehotk->eeepc_wlan_rfkill);
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
ehotk_fail: ehotk_fail:
......
...@@ -154,58 +154,46 @@ static int hp_wmi_dock_state(void) ...@@ -154,58 +154,46 @@ static int hp_wmi_dock_state(void)
return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0); return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0);
} }
static int hp_wmi_wifi_set(void *data, enum rfkill_state state) static int hp_wmi_set_block(void *data, bool blocked)
{ {
if (state) unsigned long b = (unsigned long) data;
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101); int query = BIT(b + 8) | ((!!blocked) << b);
else
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100);
}
static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state) return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
{
if (state)
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202);
else
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200);
} }
static int hp_wmi_wwan_set(void *data, enum rfkill_state state) static const struct rfkill_ops hp_wmi_rfkill_ops = {
{ .set_block = hp_wmi_set_block,
if (state) };
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404);
else
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400);
}
static int hp_wmi_wifi_state(void) static bool hp_wmi_wifi_state(void)
{ {
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
if (wireless & 0x100) if (wireless & 0x100)
return RFKILL_STATE_UNBLOCKED; return false;
else else
return RFKILL_STATE_SOFT_BLOCKED; return true;
} }
static int hp_wmi_bluetooth_state(void) static bool hp_wmi_bluetooth_state(void)
{ {
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
if (wireless & 0x10000) if (wireless & 0x10000)
return RFKILL_STATE_UNBLOCKED; return false;
else else
return RFKILL_STATE_SOFT_BLOCKED; return true;
} }
static int hp_wmi_wwan_state(void) static bool hp_wmi_wwan_state(void)
{ {
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
if (wireless & 0x1000000) if (wireless & 0x1000000)
return RFKILL_STATE_UNBLOCKED; return false;
else else
return RFKILL_STATE_SOFT_BLOCKED; return true;
} }
static ssize_t show_display(struct device *dev, struct device_attribute *attr, static ssize_t show_display(struct device *dev, struct device_attribute *attr,
...@@ -347,14 +335,14 @@ static void hp_wmi_notify(u32 value, void *context) ...@@ -347,14 +335,14 @@ static void hp_wmi_notify(u32 value, void *context)
} }
} else if (eventcode == 0x5) { } else if (eventcode == 0x5) {
if (wifi_rfkill) if (wifi_rfkill)
rfkill_force_state(wifi_rfkill, rfkill_set_sw_state(wifi_rfkill,
hp_wmi_wifi_state()); hp_wmi_wifi_state());
if (bluetooth_rfkill) if (bluetooth_rfkill)
rfkill_force_state(bluetooth_rfkill, rfkill_set_sw_state(bluetooth_rfkill,
hp_wmi_bluetooth_state()); hp_wmi_bluetooth_state());
if (wwan_rfkill) if (wwan_rfkill)
rfkill_force_state(wwan_rfkill, rfkill_set_sw_state(wwan_rfkill,
hp_wmi_wwan_state()); hp_wmi_wwan_state());
} else } else
printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
eventcode); eventcode);
...@@ -430,31 +418,34 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) ...@@ -430,31 +418,34 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
goto add_sysfs_error; goto add_sysfs_error;
if (wireless & 0x1) { if (wireless & 0x1) {
wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
wifi_rfkill->name = "hp-wifi"; RFKILL_TYPE_WLAN,
wifi_rfkill->state = hp_wmi_wifi_state(); &hp_wmi_rfkill_ops,
wifi_rfkill->toggle_radio = hp_wmi_wifi_set; (void *) 0);
rfkill_set_sw_state(wifi_rfkill, hp_wmi_wifi_state());
err = rfkill_register(wifi_rfkill); err = rfkill_register(wifi_rfkill);
if (err) if (err)
goto add_sysfs_error; goto register_wifi_error;
} }
if (wireless & 0x2) { if (wireless & 0x2) {
bluetooth_rfkill = rfkill_allocate(&device->dev, bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
RFKILL_TYPE_BLUETOOTH); RFKILL_TYPE_BLUETOOTH,
bluetooth_rfkill->name = "hp-bluetooth"; &hp_wmi_rfkill_ops,
bluetooth_rfkill->state = hp_wmi_bluetooth_state(); (void *) 1);
bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set; rfkill_set_sw_state(bluetooth_rfkill,
hp_wmi_bluetooth_state());
err = rfkill_register(bluetooth_rfkill); err = rfkill_register(bluetooth_rfkill);
if (err) if (err)
goto register_bluetooth_error; goto register_bluetooth_error;
} }
if (wireless & 0x4) { if (wireless & 0x4) {
wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
wwan_rfkill->name = "hp-wwan"; RFKILL_TYPE_WWAN,
wwan_rfkill->state = hp_wmi_wwan_state(); &hp_wmi_rfkill_ops,
wwan_rfkill->toggle_radio = hp_wmi_wwan_set; (void *) 2);
rfkill_set_sw_state(wwan_rfkill, hp_wmi_wwan_state());
err = rfkill_register(wwan_rfkill); err = rfkill_register(wwan_rfkill);
if (err) if (err)
goto register_wwan_err; goto register_wwan_err;
...@@ -462,11 +453,15 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) ...@@ -462,11 +453,15 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
return 0; return 0;
register_wwan_err: register_wwan_err:
rfkill_destroy(wwan_rfkill);
if (bluetooth_rfkill) if (bluetooth_rfkill)
rfkill_unregister(bluetooth_rfkill); rfkill_unregister(bluetooth_rfkill);
register_bluetooth_error: register_bluetooth_error:
rfkill_destroy(bluetooth_rfkill);
if (wifi_rfkill) if (wifi_rfkill)
rfkill_unregister(wifi_rfkill); rfkill_unregister(wifi_rfkill);
register_wifi_error:
rfkill_destroy(wifi_rfkill);
add_sysfs_error: add_sysfs_error:
cleanup_sysfs(device); cleanup_sysfs(device);
return err; return err;
...@@ -476,12 +471,18 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) ...@@ -476,12 +471,18 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
{ {
cleanup_sysfs(device); cleanup_sysfs(device);
if (wifi_rfkill) if (wifi_rfkill) {
rfkill_unregister(wifi_rfkill); rfkill_unregister(wifi_rfkill);
if (bluetooth_rfkill) rfkill_destroy(wifi_rfkill);
}
if (bluetooth_rfkill) {
rfkill_unregister(bluetooth_rfkill); rfkill_unregister(bluetooth_rfkill);
if (wwan_rfkill) rfkill_destroy(wifi_rfkill);
}
if (wwan_rfkill) {
rfkill_unregister(wwan_rfkill); rfkill_unregister(wwan_rfkill);
rfkill_destroy(wwan_rfkill);
}
return 0; return 0;
} }
......
...@@ -128,11 +128,11 @@ enum sony_nc_rfkill { ...@@ -128,11 +128,11 @@ enum sony_nc_rfkill {
SONY_BLUETOOTH, SONY_BLUETOOTH,
SONY_WWAN, SONY_WWAN,
SONY_WIMAX, SONY_WIMAX,
SONY_RFKILL_MAX, N_SONY_RFKILL,
}; };
static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX]; static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900}; static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
static void sony_nc_rfkill_update(void); static void sony_nc_rfkill_update(void);
/*********** Input Devices ***********/ /*********** Input Devices ***********/
...@@ -1051,147 +1051,98 @@ static void sony_nc_rfkill_cleanup(void) ...@@ -1051,147 +1051,98 @@ static void sony_nc_rfkill_cleanup(void)
{ {
int i; int i;
for (i = 0; i < SONY_RFKILL_MAX; i++) { for (i = 0; i < N_SONY_RFKILL; i++) {
if (sony_rfkill_devices[i]) if (sony_rfkill_devices[i]) {
rfkill_unregister(sony_rfkill_devices[i]); rfkill_unregister(sony_rfkill_devices[i]);
rfkill_destroy(sony_rfkill_devices[i]);
}
} }
} }
static int sony_nc_rfkill_get(void *data, enum rfkill_state *state) static int sony_nc_rfkill_set(void *data, bool blocked)
{
int result;
int argument = sony_rfkill_address[(long) data];
sony_call_snc_handle(0x124, 0x200, &result);
if (result & 0x1) {
sony_call_snc_handle(0x124, argument, &result);
if (result & 0xf)
*state = RFKILL_STATE_UNBLOCKED;
else
*state = RFKILL_STATE_SOFT_BLOCKED;
} else {
*state = RFKILL_STATE_HARD_BLOCKED;
}
return 0;
}
static int sony_nc_rfkill_set(void *data, enum rfkill_state state)
{ {
int result; int result;
int argument = sony_rfkill_address[(long) data] + 0x100; int argument = sony_rfkill_address[(long) data] + 0x100;
if (state == RFKILL_STATE_UNBLOCKED) if (!blocked)
argument |= 0xff0000; argument |= 0xff0000;
return sony_call_snc_handle(0x124, argument, &result); return sony_call_snc_handle(0x124, argument, &result);
} }
static int sony_nc_setup_wifi_rfkill(struct acpi_device *device) static const struct rfkill_ops sony_rfkill_ops = {
{ .set_block = sony_nc_rfkill_set,
int err = 0; };
struct rfkill *sony_wifi_rfkill;
sony_wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
if (!sony_wifi_rfkill)
return -1;
sony_wifi_rfkill->name = "sony-wifi";
sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set;
sony_wifi_rfkill->get_state = sony_nc_rfkill_get;
sony_wifi_rfkill->data = (void *)SONY_WIFI;
err = rfkill_register(sony_wifi_rfkill);
if (err)
rfkill_free(sony_wifi_rfkill);
else {
sony_rfkill_devices[SONY_WIFI] = sony_wifi_rfkill;
sony_nc_rfkill_set(sony_wifi_rfkill->data,
RFKILL_STATE_UNBLOCKED);
}
return err;
}
static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device) static int sony_nc_setup_rfkill(struct acpi_device *device,
enum sony_nc_rfkill nc_type)
{ {
int err = 0; int err = 0;
struct rfkill *sony_bluetooth_rfkill; struct rfkill *rfk;
enum rfkill_type type;
sony_bluetooth_rfkill = rfkill_allocate(&device->dev, const char *name;
RFKILL_TYPE_BLUETOOTH);
if (!sony_bluetooth_rfkill) switch (nc_type) {
return -1; case SONY_WIFI:
sony_bluetooth_rfkill->name = "sony-bluetooth"; type = RFKILL_TYPE_WLAN;
sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set; name = "sony-wifi";
sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get; break;
sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH; case SONY_BLUETOOTH:
err = rfkill_register(sony_bluetooth_rfkill); type = RFKILL_TYPE_BLUETOOTH;
if (err) name = "sony-bluetooth";
rfkill_free(sony_bluetooth_rfkill); break;
else { case SONY_WWAN:
sony_rfkill_devices[SONY_BLUETOOTH] = sony_bluetooth_rfkill; type = RFKILL_TYPE_WWAN;
sony_nc_rfkill_set(sony_bluetooth_rfkill->data, name = "sony-wwan";
RFKILL_STATE_UNBLOCKED); break;
case SONY_WIMAX:
type = RFKILL_TYPE_WIMAX;
name = "sony-wimax";
break;
default:
return -EINVAL;
} }
return err;
}
static int sony_nc_setup_wwan_rfkill(struct acpi_device *device) rfk = rfkill_alloc(name, &device->dev, type,
{ &sony_rfkill_ops, (void *)nc_type);
int err = 0; if (!rfk)
struct rfkill *sony_wwan_rfkill; return -ENOMEM;
sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); err = rfkill_register(rfk);
if (!sony_wwan_rfkill) if (err) {
return -1; rfkill_destroy(rfk);
sony_wwan_rfkill->name = "sony-wwan"; return err;
sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set;
sony_wwan_rfkill->get_state = sony_nc_rfkill_get;
sony_wwan_rfkill->data = (void *)SONY_WWAN;
err = rfkill_register(sony_wwan_rfkill);
if (err)
rfkill_free(sony_wwan_rfkill);
else {
sony_rfkill_devices[SONY_WWAN] = sony_wwan_rfkill;
sony_nc_rfkill_set(sony_wwan_rfkill->data,
RFKILL_STATE_UNBLOCKED);
} }
sony_rfkill_devices[nc_type] = rfk;
sony_nc_rfkill_set((void *)nc_type, false);
return err; return err;
} }
static int sony_nc_setup_wimax_rfkill(struct acpi_device *device) static void sony_nc_rfkill_update()
{ {
int err = 0; enum sony_nc_rfkill i;
struct rfkill *sony_wimax_rfkill; int result;
bool hwblock;
sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX); sony_call_snc_handle(0x124, 0x200, &result);
if (!sony_wimax_rfkill) hwblock = !(result & 0x1);
return -1;
sony_wimax_rfkill->name = "sony-wimax";
sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set;
sony_wimax_rfkill->get_state = sony_nc_rfkill_get;
sony_wimax_rfkill->data = (void *)SONY_WIMAX;
err = rfkill_register(sony_wimax_rfkill);
if (err)
rfkill_free(sony_wimax_rfkill);
else {
sony_rfkill_devices[SONY_WIMAX] = sony_wimax_rfkill;
sony_nc_rfkill_set(sony_wimax_rfkill->data,
RFKILL_STATE_UNBLOCKED);
}
return err;
}
static void sony_nc_rfkill_update() for (i = 0; i < N_SONY_RFKILL; i++) {
{ int argument = sony_rfkill_address[i];
int i;
enum rfkill_state state;
for (i = 0; i < SONY_RFKILL_MAX; i++) { if (!sony_rfkill_devices[i])
if (sony_rfkill_devices[i]) { continue;
sony_rfkill_devices[i]->
get_state(sony_rfkill_devices[i]->data, if (hwblock) {
&state); if (rfkill_set_hw_state(sony_rfkill_devices[i], true))
rfkill_force_state(sony_rfkill_devices[i], state); sony_nc_rfkill_set(sony_rfkill_devices[i],
true);
continue;
} }
sony_call_snc_handle(0x124, argument, &result);
rfkill_set_states(sony_rfkill_devices[i],
!(result & 0xf), false);
} }
} }
...@@ -1210,13 +1161,13 @@ static int sony_nc_rfkill_setup(struct acpi_device *device) ...@@ -1210,13 +1161,13 @@ static int sony_nc_rfkill_setup(struct acpi_device *device)
} }
if (result & 0x1) if (result & 0x1)
sony_nc_setup_wifi_rfkill(device); sony_nc_setup_rfkill(device, SONY_WIFI);
if (result & 0x2) if (result & 0x2)
sony_nc_setup_bluetooth_rfkill(device); sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
if (result & 0x1c) if (result & 0x1c)
sony_nc_setup_wwan_rfkill(device); sony_nc_setup_rfkill(device, SONY_WWAN);
if (result & 0x20) if (result & 0x20)
sony_nc_setup_wimax_rfkill(device); sony_nc_setup_rfkill(device, SONY_WIMAX);
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -45,7 +45,6 @@ ...@@ -45,7 +45,6 @@
#include <linux/backlight.h> #include <linux/backlight.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/rfkill.h> #include <linux/rfkill.h>
#include <linux/input-polldev.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -250,21 +249,15 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result) ...@@ -250,21 +249,15 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
struct toshiba_acpi_dev { struct toshiba_acpi_dev {
struct platform_device *p_dev; struct platform_device *p_dev;
struct rfkill *rfk_dev; struct rfkill *bt_rfk;
struct input_polled_dev *poll_dev;
const char *bt_name; const char *bt_name;
const char *rfk_name;
bool last_rfk_state;
struct mutex mutex; struct mutex mutex;
}; };
static struct toshiba_acpi_dev toshiba_acpi = { static struct toshiba_acpi_dev toshiba_acpi = {
.bt_name = "Toshiba Bluetooth", .bt_name = "Toshiba Bluetooth",
.rfk_name = "Toshiba RFKill Switch",
.last_rfk_state = false,
}; };
/* Bluetooth rfkill handlers */ /* Bluetooth rfkill handlers */
...@@ -283,21 +276,6 @@ static u32 hci_get_bt_present(bool *present) ...@@ -283,21 +276,6 @@ static u32 hci_get_bt_present(bool *present)
return hci_result; return hci_result;
} }
static u32 hci_get_bt_on(bool *on)
{
u32 hci_result;
u32 value, value2;
value = 0;
value2 = 0x0001;
hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
if (hci_result == HCI_SUCCESS)
*on = (value & HCI_WIRELESS_BT_POWER) &&
(value & HCI_WIRELESS_BT_ATTACH);
return hci_result;
}
static u32 hci_get_radio_state(bool *radio_state) static u32 hci_get_radio_state(bool *radio_state)
{ {
u32 hci_result; u32 hci_result;
...@@ -311,70 +289,67 @@ static u32 hci_get_radio_state(bool *radio_state) ...@@ -311,70 +289,67 @@ static u32 hci_get_radio_state(bool *radio_state)
return hci_result; return hci_result;
} }
static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state) static int bt_rfkill_set_block(void *data, bool blocked)
{ {
struct toshiba_acpi_dev *dev = data;
u32 result1, result2; u32 result1, result2;
u32 value; u32 value;
int err;
bool radio_state; bool radio_state;
struct toshiba_acpi_dev *dev = data;
value = (state == RFKILL_STATE_UNBLOCKED); value = (blocked == false);
if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) mutex_lock(&dev->mutex);
return -EFAULT; if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) {
err = -EBUSY;
goto out;
}
switch (state) { if (!radio_state) {
case RFKILL_STATE_UNBLOCKED: err = 0;
if (!radio_state) goto out;
return -EPERM;
break;
case RFKILL_STATE_SOFT_BLOCKED:
break;
default:
return -EINVAL;
} }
mutex_lock(&dev->mutex);
hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1); hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2); hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
mutex_unlock(&dev->mutex);
if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS) if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
return -EFAULT; err = -EBUSY;
else
return 0; err = 0;
out:
mutex_unlock(&dev->mutex);
return err;
} }
static void bt_poll_rfkill(struct input_polled_dev *poll_dev) static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
{ {
bool state_changed;
bool new_rfk_state; bool new_rfk_state;
bool value; bool value;
u32 hci_result; u32 hci_result;
struct toshiba_acpi_dev *dev = poll_dev->private; struct toshiba_acpi_dev *dev = data;
mutex_lock(&dev->mutex);
hci_result = hci_get_radio_state(&value); hci_result = hci_get_radio_state(&value);
if (hci_result != HCI_SUCCESS) if (hci_result != HCI_SUCCESS) {
return; /* Can't do anything useful */ /* Can't do anything useful */
mutex_unlock(&dev->mutex);
}
new_rfk_state = value; new_rfk_state = value;
mutex_lock(&dev->mutex);
state_changed = new_rfk_state != dev->last_rfk_state;
dev->last_rfk_state = new_rfk_state;
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
if (unlikely(state_changed)) { if (rfkill_set_hw_state(rfkill, !new_rfk_state))
rfkill_force_state(dev->rfk_dev, bt_rfkill_set_block(data, true);
new_rfk_state ?
RFKILL_STATE_SOFT_BLOCKED :
RFKILL_STATE_HARD_BLOCKED);
input_report_switch(poll_dev->input, SW_RFKILL_ALL,
new_rfk_state);
input_sync(poll_dev->input);
}
} }
static const struct rfkill_ops toshiba_rfk_ops = {
.set_block = bt_rfkill_set_block,
.poll = bt_rfkill_poll,
};
static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
static struct backlight_device *toshiba_backlight_device; static struct backlight_device *toshiba_backlight_device;
static int force_fan; static int force_fan;
...@@ -702,14 +677,11 @@ static struct backlight_ops toshiba_backlight_data = { ...@@ -702,14 +677,11 @@ static struct backlight_ops toshiba_backlight_data = {
static void toshiba_acpi_exit(void) static void toshiba_acpi_exit(void)
{ {
if (toshiba_acpi.poll_dev) { if (toshiba_acpi.bt_rfk) {
input_unregister_polled_device(toshiba_acpi.poll_dev); rfkill_unregister(toshiba_acpi.bt_rfk);
input_free_polled_device(toshiba_acpi.poll_dev); rfkill_destroy(toshiba_acpi.bt_rfk);
} }
if (toshiba_acpi.rfk_dev)
rfkill_unregister(toshiba_acpi.rfk_dev);
if (toshiba_backlight_device) if (toshiba_backlight_device)
backlight_device_unregister(toshiba_backlight_device); backlight_device_unregister(toshiba_backlight_device);
...@@ -728,8 +700,6 @@ static int __init toshiba_acpi_init(void) ...@@ -728,8 +700,6 @@ static int __init toshiba_acpi_init(void)
acpi_status status = AE_OK; acpi_status status = AE_OK;
u32 hci_result; u32 hci_result;
bool bt_present; bool bt_present;
bool bt_on;
bool radio_on;
int ret = 0; int ret = 0;
if (acpi_disabled) if (acpi_disabled)
...@@ -793,60 +763,21 @@ static int __init toshiba_acpi_init(void) ...@@ -793,60 +763,21 @@ static int __init toshiba_acpi_init(void)
/* Register rfkill switch for Bluetooth */ /* Register rfkill switch for Bluetooth */
if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) { if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev, toshiba_acpi.bt_rfk = rfkill_alloc(toshiba_acpi.bt_name,
RFKILL_TYPE_BLUETOOTH); &toshiba_acpi.p_dev->dev,
if (!toshiba_acpi.rfk_dev) { RFKILL_TYPE_BLUETOOTH,
&toshiba_rfk_ops,
&toshiba_acpi);
if (!toshiba_acpi.bt_rfk) {
printk(MY_ERR "unable to allocate rfkill device\n"); printk(MY_ERR "unable to allocate rfkill device\n");
toshiba_acpi_exit(); toshiba_acpi_exit();
return -ENOMEM; return -ENOMEM;
} }
toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name; ret = rfkill_register(toshiba_acpi.bt_rfk);
toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio;
toshiba_acpi.rfk_dev->data = &toshiba_acpi;
if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) {
toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED;
} else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS &&
radio_on) {
toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED;
} else {
toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED;
}
ret = rfkill_register(toshiba_acpi.rfk_dev);
if (ret) { if (ret) {
printk(MY_ERR "unable to register rfkill device\n"); printk(MY_ERR "unable to register rfkill device\n");
toshiba_acpi_exit(); rfkill_destroy(toshiba_acpi.bt_rfk);
return -ENOMEM;
}
/* Register input device for kill switch */
toshiba_acpi.poll_dev = input_allocate_polled_device();
if (!toshiba_acpi.poll_dev) {
printk(MY_ERR
"unable to allocate kill-switch input device\n");
toshiba_acpi_exit();
return -ENOMEM;
}
toshiba_acpi.poll_dev->private = &toshiba_acpi;
toshiba_acpi.poll_dev->poll = bt_poll_rfkill;
toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */
toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name;
toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST;
/* Toshiba USB ID */
toshiba_acpi.poll_dev->input->id.vendor = 0x0930;
set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit);
set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit);
input_report_switch(toshiba_acpi.poll_dev->input,
SW_RFKILL_ALL, TRUE);
input_sync(toshiba_acpi.poll_dev->input);
ret = input_register_polled_device(toshiba_acpi.poll_dev);
if (ret) {
printk(MY_ERR
"unable to register kill-switch input device\n");
toshiba_acpi_exit(); toshiba_acpi_exit();
return ret; return ret;
} }
......
...@@ -311,6 +311,7 @@ unifdef-y += ptrace.h ...@@ -311,6 +311,7 @@ unifdef-y += ptrace.h
unifdef-y += qnx4_fs.h unifdef-y += qnx4_fs.h
unifdef-y += quota.h unifdef-y += quota.h
unifdef-y += random.h unifdef-y += random.h
unifdef-y += rfkill.h
unifdef-y += irqnr.h unifdef-y += irqnr.h
unifdef-y += reboot.h unifdef-y += reboot.h
unifdef-y += reiserfs_fs.h unifdef-y += reiserfs_fs.h
......
This diff is collapsed.
...@@ -253,7 +253,6 @@ ...@@ -253,7 +253,6 @@
struct net_device; struct net_device;
struct genl_info; struct genl_info;
struct wimax_dev; struct wimax_dev;
struct input_dev;
/** /**
* struct wimax_dev - Generic WiMAX device * struct wimax_dev - Generic WiMAX device
...@@ -293,8 +292,8 @@ struct input_dev; ...@@ -293,8 +292,8 @@ struct input_dev;
* See wimax_reset()'s documentation. * See wimax_reset()'s documentation.
* *
* @name: [fill] A way to identify this device. We need to register a * @name: [fill] A way to identify this device. We need to register a
* name with many subsystems (input for RFKILL, workqueue * name with many subsystems (rfkill, workqueue creation, etc).
* creation, etc). We can't use the network device name as that * We can't use the network device name as that
* might change and in some instances we don't know it yet (until * might change and in some instances we don't know it yet (until
* we don't call register_netdev()). So we generate an unique one * we don't call register_netdev()). So we generate an unique one
* using the driver name and device bus id, place it here and use * using the driver name and device bus id, place it here and use
...@@ -316,9 +315,6 @@ struct input_dev; ...@@ -316,9 +315,6 @@ struct input_dev;
* *
* @rfkill: [private] integration into the RF-Kill infrastructure. * @rfkill: [private] integration into the RF-Kill infrastructure.
* *
* @rfkill_input: [private] virtual input device to process the
* hardware RF Kill switches.
*
* @rf_sw: [private] State of the software radio switch (OFF/ON) * @rf_sw: [private] State of the software radio switch (OFF/ON)
* *
* @rf_hw: [private] State of the hardware radio switch (OFF/ON) * @rf_hw: [private] State of the hardware radio switch (OFF/ON)
......
...@@ -10,22 +10,15 @@ menuconfig RFKILL ...@@ -10,22 +10,15 @@ menuconfig RFKILL
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called rfkill. module will be called rfkill.
config RFKILL_INPUT
tristate "Input layer to RF switch connector"
depends on RFKILL && INPUT
help
Say Y here if you want kernel automatically toggle state
of RF switches on and off when user presses appropriate
button or a key on the keyboard. Without this module you
need a some kind of userspace application to control
state of the switches.
To compile this driver as a module, choose M here: the
module will be called rfkill-input.
# LED trigger support # LED trigger support
config RFKILL_LEDS config RFKILL_LEDS
bool bool
depends on RFKILL && LEDS_TRIGGERS depends on RFKILL
depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS
default y default y
config RFKILL_INPUT
bool
depends on RFKILL
depends on INPUT = y || RFKILL = INPUT
default y
...@@ -2,5 +2,6 @@ ...@@ -2,5 +2,6 @@
# Makefile for the RF switch subsystem. # Makefile for the RF switch subsystem.
# #
obj-$(CONFIG_RFKILL) += rfkill.o rfkill-y += core.o
obj-$(CONFIG_RFKILL_INPUT) += rfkill-input.o rfkill-$(CONFIG_RFKILL_INPUT) += input.o
obj-$(CONFIG_RFKILL) += rfkill.o
This diff is collapsed.
/* /*
* Copyright (C) 2007 Ivo van Doorn * Copyright (C) 2007 Ivo van Doorn
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
*/ */
/* /*
...@@ -11,11 +12,16 @@ ...@@ -11,11 +12,16 @@
#ifndef __RFKILL_INPUT_H #ifndef __RFKILL_INPUT_H
#define __RFKILL_INPUT_H #define __RFKILL_INPUT_H
void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state); /* core code */
void rfkill_switch_all(const enum rfkill_type type, bool blocked);
void rfkill_epo(void); void rfkill_epo(void);
void rfkill_restore_states(void); void rfkill_restore_states(void);
void rfkill_remove_epo_lock(void); void rfkill_remove_epo_lock(void);
bool rfkill_is_epo_lock_active(void); bool rfkill_is_epo_lock_active(void);
enum rfkill_state rfkill_get_global_state(const enum rfkill_type type); bool rfkill_get_global_sw_state(const enum rfkill_type type);
/* input handler */
int rfkill_handler_init(void);
void rfkill_handler_exit(void);
#endif /* __RFKILL_INPUT_H */ #endif /* __RFKILL_INPUT_H */
# #
# WiMAX LAN device configuration # WiMAX LAN device configuration
# #
# Note the ugly 'depends on' on WIMAX: that disallows RFKILL to be a
# module if WIMAX is to be linked in. The WiMAX code is done in such a
# way that it doesn't require and explicit dependency on RFKILL in
# case an embedded system wants to rip it out.
#
# As well, enablement of the RFKILL code means we need the INPUT layer
# support to inject events coming from hw rfkill switches. That
# dependency could be killed if input.h provided appropriate means to
# work when input is disabled.
comment "WiMAX Wireless Broadband support requires CONFIG_INPUT enabled"
depends on INPUT = n && RFKILL != n
menuconfig WIMAX menuconfig WIMAX
tristate "WiMAX Wireless Broadband support" tristate "WiMAX Wireless Broadband support"
depends on (y && RFKILL != m) || m
depends on (INPUT && RFKILL != n) || RFKILL = n
help help
Select to configure support for devices that provide Select to configure support for devices that provide
......
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
* A non-polled generic rfkill device is embedded into the WiMAX * A non-polled generic rfkill device is embedded into the WiMAX
* subsystem's representation of a device. * subsystem's representation of a device.
* *
* FIXME: Need polled support? use a timer or add the implementation * FIXME: Need polled support? Let drivers provide a poll routine
* to the stack. * and hand it to rfkill ops then?
* *
* All device drivers have to do is after wimax_dev_init(), call * All device drivers have to do is after wimax_dev_init(), call
* wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update * wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
* wimax_rfkill() Kernel calling wimax_rfkill() * wimax_rfkill() Kernel calling wimax_rfkill()
* __wimax_rf_toggle_radio() * __wimax_rf_toggle_radio()
* *
* wimax_rfkill_toggle_radio() RF-Kill subsytem calling * wimax_rfkill_set_radio_block() RF-Kill subsytem calling
* __wimax_rf_toggle_radio() * __wimax_rf_toggle_radio()
* *
* __wimax_rf_toggle_radio() * __wimax_rf_toggle_radio()
...@@ -65,15 +65,11 @@ ...@@ -65,15 +65,11 @@
#include <linux/wimax.h> #include <linux/wimax.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/rfkill.h> #include <linux/rfkill.h>
#include <linux/input.h>
#include "wimax-internal.h" #include "wimax-internal.h"
#define D_SUBMODULE op_rfkill #define D_SUBMODULE op_rfkill
#include "debug-levels.h" #include "debug-levels.h"
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
/** /**
* wimax_report_rfkill_hw - Reports changes in the hardware RF switch * wimax_report_rfkill_hw - Reports changes in the hardware RF switch
* *
...@@ -99,7 +95,6 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, ...@@ -99,7 +95,6 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
int result; int result;
struct device *dev = wimax_dev_to_dev(wimax_dev); struct device *dev = wimax_dev_to_dev(wimax_dev);
enum wimax_st wimax_state; enum wimax_st wimax_state;
enum rfkill_state rfkill_state;
d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
BUG_ON(state == WIMAX_RF_QUERY); BUG_ON(state == WIMAX_RF_QUERY);
...@@ -112,16 +107,15 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev, ...@@ -112,16 +107,15 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
if (state != wimax_dev->rf_hw) { if (state != wimax_dev->rf_hw) {
wimax_dev->rf_hw = state; wimax_dev->rf_hw = state;
rfkill_state = state == WIMAX_RF_ON ?
RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
if (wimax_dev->rf_hw == WIMAX_RF_ON if (wimax_dev->rf_hw == WIMAX_RF_ON
&& wimax_dev->rf_sw == WIMAX_RF_ON) && wimax_dev->rf_sw == WIMAX_RF_ON)
wimax_state = WIMAX_ST_READY; wimax_state = WIMAX_ST_READY;
else else
wimax_state = WIMAX_ST_RADIO_OFF; wimax_state = WIMAX_ST_RADIO_OFF;
rfkill_set_hw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF);
__wimax_state_change(wimax_dev, wimax_state); __wimax_state_change(wimax_dev, wimax_state);
input_report_key(wimax_dev->rfkill_input, KEY_WIMAX,
rfkill_state);
} }
error_not_ready: error_not_ready:
mutex_unlock(&wimax_dev->mutex); mutex_unlock(&wimax_dev->mutex);
...@@ -174,6 +168,7 @@ void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev, ...@@ -174,6 +168,7 @@ void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev,
else else
wimax_state = WIMAX_ST_RADIO_OFF; wimax_state = WIMAX_ST_RADIO_OFF;
__wimax_state_change(wimax_dev, wimax_state); __wimax_state_change(wimax_dev, wimax_state);
rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF);
} }
error_not_ready: error_not_ready:
mutex_unlock(&wimax_dev->mutex); mutex_unlock(&wimax_dev->mutex);
...@@ -249,36 +244,31 @@ int __wimax_rf_toggle_radio(struct wimax_dev *wimax_dev, ...@@ -249,36 +244,31 @@ int __wimax_rf_toggle_radio(struct wimax_dev *wimax_dev,
* *
* NOTE: This call will block until the operation is completed. * NOTE: This call will block until the operation is completed.
*/ */
static static int wimax_rfkill_set_radio_block(void *data, bool blocked)
int wimax_rfkill_toggle_radio(void *data, enum rfkill_state state)
{ {
int result; int result;
struct wimax_dev *wimax_dev = data; struct wimax_dev *wimax_dev = data;
struct device *dev = wimax_dev_to_dev(wimax_dev); struct device *dev = wimax_dev_to_dev(wimax_dev);
enum wimax_rf_state rf_state; enum wimax_rf_state rf_state;
d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state); d_fnstart(3, dev, "(wimax_dev %p blocked %u)\n", wimax_dev, blocked);
switch (state) { rf_state = WIMAX_RF_ON;
case RFKILL_STATE_SOFT_BLOCKED: if (blocked)
rf_state = WIMAX_RF_OFF; rf_state = WIMAX_RF_OFF;
break;
case RFKILL_STATE_UNBLOCKED:
rf_state = WIMAX_RF_ON;
break;
default:
BUG();
}
mutex_lock(&wimax_dev->mutex); mutex_lock(&wimax_dev->mutex);
if (wimax_dev->state <= __WIMAX_ST_QUIESCING) if (wimax_dev->state <= __WIMAX_ST_QUIESCING)
result = 0; /* just pretend it didn't happen */ result = 0;
else else
result = __wimax_rf_toggle_radio(wimax_dev, rf_state); result = __wimax_rf_toggle_radio(wimax_dev, rf_state);
mutex_unlock(&wimax_dev->mutex); mutex_unlock(&wimax_dev->mutex);
d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n", d_fnend(3, dev, "(wimax_dev %p blocked %u) = %d\n",
wimax_dev, state, result); wimax_dev, blocked, result);
return result; return result;
} }
static const struct rfkill_ops wimax_rfkill_ops = {
.set_block = wimax_rfkill_set_radio_block,
};
/** /**
* wimax_rfkill - Set the software RF switch state for a WiMAX device * wimax_rfkill - Set the software RF switch state for a WiMAX device
...@@ -322,6 +312,7 @@ int wimax_rfkill(struct wimax_dev *wimax_dev, enum wimax_rf_state state) ...@@ -322,6 +312,7 @@ int wimax_rfkill(struct wimax_dev *wimax_dev, enum wimax_rf_state state)
result = __wimax_rf_toggle_radio(wimax_dev, state); result = __wimax_rf_toggle_radio(wimax_dev, state);
if (result < 0) if (result < 0)
goto error; goto error;
rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF);
break; break;
case WIMAX_RF_QUERY: case WIMAX_RF_QUERY:
break; break;
...@@ -349,40 +340,20 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) ...@@ -349,40 +340,20 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev)
{ {
int result; int result;
struct rfkill *rfkill; struct rfkill *rfkill;
struct input_dev *input_dev;
struct device *dev = wimax_dev_to_dev(wimax_dev); struct device *dev = wimax_dev_to_dev(wimax_dev);
d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
/* Initialize RF Kill */ /* Initialize RF Kill */
result = -ENOMEM; result = -ENOMEM;
rfkill = rfkill_allocate(dev, RFKILL_TYPE_WIMAX); rfkill = rfkill_alloc(wimax_dev->name, dev, RFKILL_TYPE_WIMAX,
&wimax_rfkill_ops, wimax_dev);
if (rfkill == NULL) if (rfkill == NULL)
goto error_rfkill_allocate; goto error_rfkill_allocate;
d_printf(1, dev, "rfkill %p\n", rfkill);
wimax_dev->rfkill = rfkill; wimax_dev->rfkill = rfkill;
rfkill->name = wimax_dev->name;
rfkill->state = RFKILL_STATE_UNBLOCKED;
rfkill->data = wimax_dev;
rfkill->toggle_radio = wimax_rfkill_toggle_radio;
/* Initialize the input device for the hw key */
input_dev = input_allocate_device();
if (input_dev == NULL)
goto error_input_allocate;
wimax_dev->rfkill_input = input_dev;
d_printf(1, dev, "rfkill %p input %p\n", rfkill, input_dev);
input_dev->name = wimax_dev->name;
/* FIXME: get a real device bus ID and stuff? do we care? */
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0xffff;
input_dev->evbit[0] = BIT(EV_KEY);
set_bit(KEY_WIMAX, input_dev->keybit);
/* Register both */
result = input_register_device(wimax_dev->rfkill_input);
if (result < 0)
goto error_input_register;
result = rfkill_register(wimax_dev->rfkill); result = rfkill_register(wimax_dev->rfkill);
if (result < 0) if (result < 0)
goto error_rfkill_register; goto error_rfkill_register;
...@@ -394,17 +365,8 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev) ...@@ -394,17 +365,8 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev)
d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev); d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev);
return 0; return 0;
/* if rfkill_register() suceeds, can't use rfkill_free() any
* more, only rfkill_unregister() [it owns the refcount]; with
* the input device we have the same issue--hence the if. */
error_rfkill_register: error_rfkill_register:
input_unregister_device(wimax_dev->rfkill_input); rfkill_destroy(wimax_dev->rfkill);
wimax_dev->rfkill_input = NULL;
error_input_register:
if (wimax_dev->rfkill_input)
input_free_device(wimax_dev->rfkill_input);
error_input_allocate:
rfkill_free(wimax_dev->rfkill);
error_rfkill_allocate: error_rfkill_allocate:
d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result); d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result);
return result; return result;
...@@ -423,45 +385,12 @@ void wimax_rfkill_rm(struct wimax_dev *wimax_dev) ...@@ -423,45 +385,12 @@ void wimax_rfkill_rm(struct wimax_dev *wimax_dev)
{ {
struct device *dev = wimax_dev_to_dev(wimax_dev); struct device *dev = wimax_dev_to_dev(wimax_dev);
d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev); d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
rfkill_unregister(wimax_dev->rfkill); /* frees */ rfkill_unregister(wimax_dev->rfkill);
input_unregister_device(wimax_dev->rfkill_input); rfkill_destroy(wimax_dev->rfkill);
d_fnend(3, dev, "(wimax_dev %p)\n", wimax_dev); d_fnend(3, dev, "(wimax_dev %p)\n", wimax_dev);
} }
#else /* #ifdef CONFIG_RFKILL */
void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
enum wimax_rf_state state)
{
}
EXPORT_SYMBOL_GPL(wimax_report_rfkill_hw);
void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev,
enum wimax_rf_state state)
{
}
EXPORT_SYMBOL_GPL(wimax_report_rfkill_sw);
int wimax_rfkill(struct wimax_dev *wimax_dev,
enum wimax_rf_state state)
{
return WIMAX_RF_ON << 1 | WIMAX_RF_ON;
}
EXPORT_SYMBOL_GPL(wimax_rfkill);
int wimax_rfkill_add(struct wimax_dev *wimax_dev)
{
return 0;
}
void wimax_rfkill_rm(struct wimax_dev *wimax_dev)
{
}
#endif /* #ifdef CONFIG_RFKILL */
/* /*
* Exporting to user space over generic netlink * Exporting to user space over generic netlink
* *
......
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