提交 19d337df 编写于 作者: J Johannes Berg 提交者: 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: NAlan Jenkins <alan-jenkins@tuffmail.co.uk>
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> [thinkpad]
Signed-off-by: NJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: NJohn W. Linville <linville@tuxdriver.com>
上级 0f6399c4
此差异已折叠。
......@@ -4753,9 +4753,9 @@ S: Supported
F: fs/reiserfs/
RFKILL
P: Ivo van Doorn
M: IvDoorn@gmail.com
L: netdev@vger.kernel.org
P: Johannes Berg
M: johannes@sipsolutions.net
L: linux-wireless@vger.kernel.org
S: Maintained
F Documentation/rfkill.txt
F: net/rfkill/
......
......@@ -35,21 +35,25 @@ static void tosa_bt_off(struct tosa_bt_data *data)
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",
state == RFKILL_STATE_UNBLOCKED ? "on" : "off");
pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on");
if (state == RFKILL_STATE_UNBLOCKED) {
if (!blocked) {
pr_info("TOSA_BT: going ON\n");
tosa_bt_on(data);
} else {
pr_info("TOSA_BT: going OFF\n");
tosa_bt_off(data);
}
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)
{
int rc;
......@@ -70,18 +74,14 @@ static int tosa_bt_probe(struct platform_device *dev)
if (rc)
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) {
rc = -ENOMEM;
goto err_rfk_alloc;
}
rfk->name = "tosa-bt";
rfk->toggle_radio = tosa_bt_toggle_radio;
rfk->data = data;
#ifdef CONFIG_RFKILL_LEDS
rfk->led_trigger.name = "tosa-bt";
#endif
rfkill_set_led_trigger_name(rfk, "tosa-bt");
rc = rfkill_register(rfk);
if (rc)
......@@ -92,9 +92,7 @@ static int tosa_bt_probe(struct platform_device *dev)
return 0;
err_rfkill:
if (rfk)
rfkill_free(rfk);
rfk = NULL;
rfkill_destroy(rfk);
err_rfk_alloc:
tosa_bt_off(data);
err_pwr_dir:
......@@ -113,8 +111,10 @@ static int __devexit tosa_bt_remove(struct platform_device *dev)
platform_set_drvdata(dev, NULL);
if (rfk)
if (rfk) {
rfkill_unregister(rfk);
rfkill_destroy(rfk);
}
rfk = NULL;
tosa_bt_off(data);
......
......@@ -31,7 +31,6 @@
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/pda_power.h>
#include <linux/rfkill.h>
#include <linux/spi/spi.h>
#include <asm/setup.h>
......
......@@ -2481,10 +2481,10 @@ static int add_net_device(struct hso_device *hso_dev)
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;
int enabled = (state == RFKILL_STATE_UNBLOCKED);
int enabled = !blocked;
int rv;
mutex_lock(&hso_dev->mutex);
......@@ -2498,6 +2498,10 @@ static int hso_radio_toggle(void *data, enum rfkill_state state)
return rv;
}
static const struct rfkill_ops hso_rfkill_ops = {
.set_block = hso_rfkill_set_block,
};
/* Creates and sets up everything for rfkill */
static void hso_create_rfkill(struct hso_device *hso_dev,
struct usb_interface *interface)
......@@ -2506,29 +2510,25 @@ static void hso_create_rfkill(struct hso_device *hso_dev,
struct device *dev = &hso_net->net->dev;
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);
if (!rfkn) {
rfkill_free(hso_net->rfkill);
hso_net->rfkill = NULL;
if (!rfkn)
dev_err(dev, "%s - Out of memory\n", __func__);
return;
}
snprintf(rfkn, 20, "hso-%d",
interface->altsetting->desc.bInterfaceNumber);
hso_net->rfkill->name = rfkn;
hso_net->rfkill->state = RFKILL_STATE_UNBLOCKED;
hso_net->rfkill->data = hso_dev;
hso_net->rfkill->toggle_radio = hso_radio_toggle;
hso_net->rfkill = rfkill_alloc(rfkn,
&interface_to_usbdev(interface)->dev,
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) {
rfkill_destroy(hso_net->rfkill);
kfree(rfkn);
hso_net->rfkill->name = NULL;
rfkill_free(hso_net->rfkill);
hso_net->rfkill = NULL;
dev_err(dev, "%s - Failed to register rfkill\n", __func__);
return;
......@@ -3165,8 +3165,10 @@ static void hso_free_interface(struct usb_interface *interface)
hso_stop_net_device(network_table[i]);
cancel_work_sync(&network_table[i]->async_put_intf);
cancel_work_sync(&network_table[i]->async_get_intf);
if (rfk)
if (rfk) {
rfkill_unregister(rfk);
rfkill_destroy(rfk);
}
hso_free_net_device(network_table[i]);
}
}
......
......@@ -460,12 +460,9 @@ struct ath_led {
bool registered;
};
/* Rfkill */
#define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */
struct ath_rfkill {
struct rfkill *rfkill;
struct delayed_work rfkill_poll;
struct rfkill_ops ops;
char rfkill_name[32];
};
......@@ -509,8 +506,6 @@ struct ath_rfkill {
#define SC_OP_RXFLUSH BIT(7)
#define SC_OP_LED_ASSOCIATED BIT(8)
#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_LED_ON BIT(13)
#define SC_OP_SCANNING BIT(14)
......
......@@ -1192,120 +1192,69 @@ static bool ath_is_rfkill_set(struct ath_softc *sc)
ah->rfkill_polarity;
}
/* h/w rfkill poll function */
static void ath_rfkill_poll(struct work_struct *work)
/* s/w rfkill handlers */
static int ath_rfkill_set_block(void *data, bool blocked)
{
struct ath_softc *sc = container_of(work, struct ath_softc,
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;
struct ath_softc *sc = data;
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,
msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL));
return 0;
}
/* s/w rfkill handler */
static int ath_sw_toggle_radio(void *data, enum rfkill_state state)
static void ath_rfkill_poll_state(struct rfkill *rfkill, void *data)
{
struct ath_softc *sc = data;
bool blocked = !!ath_is_rfkill_set(sc);
switch (state) {
case RFKILL_STATE_SOFT_BLOCKED:
if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED |
SC_OP_RFKILL_SW_BLOCKED)))
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;
}
if (rfkill_set_hw_state(rfkill, blocked))
ath_radio_disable(sc);
else
ath_radio_enable(sc);
}
/* Init s/w rfkill */
static int ath_init_sw_rfkill(struct ath_softc *sc)
{
sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy),
RFKILL_TYPE_WLAN);
sc->rf_kill.ops.set_block = ath_rfkill_set_block;
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) {
DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n");
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;
}
/* Deinitialize rfkill */
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) {
rfkill_unregister(sc->rf_kill.rfkill);
rfkill_destroy(sc->rf_kill.rfkill);
sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED;
sc->rf_kill.rfkill = NULL;
}
}
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 (rfkill_register(sc->rf_kill.rfkill)) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to register rfkill\n");
rfkill_free(sc->rf_kill.rfkill);
rfkill_destroy(sc->rf_kill.rfkill);
/* Deinitialize the device */
ath_cleanup(sc);
......@@ -1678,10 +1627,6 @@ int ath_attach(u16 devid, struct ath_softc *sc)
goto error_attach;
#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 */
error = ath_init_sw_rfkill(sc);
if (error)
......@@ -2214,10 +2159,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
} else
sc->rx.rxlink = NULL;
#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
rfkill_pause_polling(sc->rf_kill.rfkill);
/* disable HAL and put h/w to sleep */
ath9k_hw_disable(sc->sc_ah);
ath9k_hw_configpcipowersave(sc->sc_ah, 1);
......
......@@ -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);
#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_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
......@@ -256,16 +251,6 @@ static int ath_pci_resume(struct pci_dev *pdev)
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
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;
}
......
......@@ -102,7 +102,7 @@ config B43_LEDS
# if it's possible.
config B43_RFKILL
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
# This config option automatically enables b43 HW-RNG support,
......
......@@ -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,
const char *name, char *default_trigger,
const char *name, const char *default_trigger,
u8 led_index, bool activelow)
{
int err;
......
......@@ -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) {
b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
b43_software_rfkill(dev, false);
b43info(dev->wl, "Radio turned on by software\n");
if (!dev->radio_hw_enable) {
b43info(dev->wl, "The hardware RF-kill button "
......@@ -3478,7 +3478,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
"Press the button to turn it on.\n");
}
} else {
b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
b43_software_rfkill(dev, true);
b43info(dev->wl, "Radio turned off by software\n");
}
}
......
......@@ -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,
enum rfkill_state state)
bool blocked)
{
struct b43_phy *phy = &dev->phy;
if (state == RFKILL_STATE_UNBLOCKED) {
if (!blocked) {
if (phy->radio_on)
return;
b43_radio_write16(dev, 0x0004, 0x00C0);
......
......@@ -84,7 +84,7 @@ int b43_phy_init(struct b43_wldev *dev)
phy->channel = ops->get_default_chan(dev);
ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
ops->software_rfkill(dev, false);
err = ops->init(dev);
if (err) {
b43err(dev->wl, "PHY init failed\n");
......@@ -104,7 +104,7 @@ int b43_phy_init(struct b43_wldev *dev)
if (ops->exit)
ops->exit(dev);
err_block_rf:
ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
ops->software_rfkill(dev, true);
return err;
}
......@@ -113,7 +113,7 @@ void b43_phy_exit(struct b43_wldev *dev)
{
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)
ops->exit(dev);
}
......@@ -295,18 +295,13 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
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;
if (state == RFKILL_STATE_HARD_BLOCKED) {
/* We cannot hardware-block the device */
state = RFKILL_STATE_SOFT_BLOCKED;
}
b43_mac_suspend(dev);
phy->ops->software_rfkill(dev, state);
phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
phy->ops->software_rfkill(dev, blocked);
phy->radio_on = !blocked;
b43_mac_enable(dev);
}
......
......@@ -159,7 +159,7 @@ struct b43_phy_operations {
/* Radio */
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);
int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel);
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);
/**
* 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.
......
......@@ -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,
enum rfkill_state state)
bool blocked)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
......@@ -2600,7 +2600,7 @@ static void b43_gphy_op_software_rfkill(struct b43_wldev *dev,
might_sleep();
if (state == RFKILL_STATE_UNBLOCKED) {
if (!blocked) {
/* Turn radio ON */
if (phy->radio_on)
return;
......
......@@ -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,
enum rfkill_state state)
bool blocked)
{
//TODO
}
......
......@@ -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,
enum rfkill_state state)
bool blocked)
{//TODO
}
......
......@@ -45,12 +45,11 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
}
/* 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;
bool enabled;
bool report_change = 0;
mutex_lock(&wl->mutex);
if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) {
......@@ -60,68 +59,55 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
enabled = b43_is_hw_radio_enabled(dev);
if (unlikely(enabled != dev->radio_hw_enable)) {
dev->radio_hw_enable = enabled;
report_change = 1;
b43info(wl, "Radio hardware status changed to %s\n",
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);
/* 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. */
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_wl *wl = dev->wl;
int err = -EBUSY;
int err = -EINVAL;
if (!wl->rfkill.registered)
return 0;
if (WARN_ON(!wl->rfkill.registered))
return -EINVAL;
mutex_lock(&wl->mutex);
if (b43_status(dev) < B43_STAT_INITIALIZED)
goto out_unlock;
if (!dev->radio_hw_enable)
goto out_unlock;
if (!blocked != dev->phy.radio_on)
b43_software_rfkill(dev, blocked);
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:
mutex_unlock(&wl->mutex);
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);
if (!rfk->registered)
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)
{
struct b43_wl *wl = dev->wl;
......@@ -130,65 +116,26 @@ void b43_rfkill_init(struct b43_wldev *dev)
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),
"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->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);
rfk->rfkill = rfkill_alloc(rfk->name,
dev->dev->dev,
RFKILL_TYPE_WLAN,
&b43_rfkill_ops, dev);
if (!rfk->rfkill)
goto out_error;
err = rfkill_register(rfk->rfkill);
if (err)
goto err_free_polldev;
#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;
goto err_free;
rfk->registered = 1;
return;
err_unreg_rfk:
rfkill_unregister(rfk->rfkill);
err_free_polldev:
input_free_polled_device(rfk->poll_dev);
rfk->poll_dev = NULL;
err_freed_rfk:
rfk->rfkill = NULL;
out_error:
err_free:
rfkill_destroy(rfk->rfkill);
out_error:
rfk->registered = 0;
b43warn(wl, "RF-kill button init failed\n");
}
......@@ -201,9 +148,7 @@ void b43_rfkill_exit(struct b43_wldev *dev)
return;
rfk->registered = 0;
input_unregister_polled_device(rfk->poll_dev);
rfkill_unregister(rfk->rfkill);
input_free_polled_device(rfk->poll_dev);
rfk->poll_dev = NULL;
rfkill_destroy(rfk->rfkill);
rfk->rfkill = NULL;
}
......@@ -7,14 +7,11 @@ struct b43_wldev;
#ifdef CONFIG_B43_RFKILL
#include <linux/rfkill.h>
#include <linux/input-polldev.h>
struct b43_rfkill {
/* The RFKILL subsystem data structure */
struct rfkill *rfkill;
/* The poll device for the RFKILL input button */
struct input_polled_dev *poll_dev;
/* Did initialization succeed? Used for freeing. */
bool registered;
/* The unique name of this rfkill switch */
......@@ -26,7 +23,7 @@ struct b43_rfkill {
void b43_rfkill_init(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 */
......
......@@ -47,7 +47,7 @@ config B43LEGACY_LEDS
# if it's possible.
config B43LEGACY_RFKILL
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
# This config option automatically enables b43 HW-RNG support,
......
......@@ -86,7 +86,8 @@ static void b43legacy_led_brightness_set(struct led_classdev *led_dev,
static int b43legacy_register_led(struct b43legacy_wldev *dev,
struct b43legacy_led *led,
const char *name, char *default_trigger,
const char *name,
const char *default_trigger,
u8 led_index, bool activelow)
{
int err;
......
......@@ -45,12 +45,11 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
}
/* 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;
bool enabled;
bool report_change = 0;
mutex_lock(&wl->mutex);
if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) {
......@@ -60,71 +59,64 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
enabled = b43legacy_is_hw_radio_enabled(dev);
if (unlikely(enabled != dev->radio_hw_enable)) {
dev->radio_hw_enable = enabled;
report_change = 1;
b43legacyinfo(wl, "Radio hardware status changed to %s\n",
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);
/* 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.
* 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_wl *wl = dev->wl;
int err = -EBUSY;
int ret = -EINVAL;
if (!wl->rfkill.registered)
return 0;
return -EINVAL;
mutex_lock(&wl->mutex);
if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
goto out_unlock;
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)
if (!dev->radio_hw_enable)
goto out_unlock;
if (!blocked != dev->phy.radio_on) {
if (!blocked)
b43legacy_radio_turn_on(dev);
break;
case RFKILL_STATE_SOFT_BLOCKED:
if (dev->phy.radio_on)
else
b43legacy_radio_turn_off(dev, 0);
break;
default:
b43legacywarn(wl, "Received unexpected rfkill state %d.\n",
state);
break;
}
ret = 0;
out_unlock:
mutex_unlock(&wl->mutex);
return err;
return ret;
}
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);
if (!rfk->registered)
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)
{
struct b43legacy_wl *wl = dev->wl;
......@@ -133,60 +125,25 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
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),
"b43legacy-%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 = b43legacy_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 = 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);
rfk->rfkill = rfkill_alloc(rfk->name,
dev->dev->dev,
RFKILL_TYPE_WLAN,
&b43legacy_rfkill_ops, dev);
if (!rfk->rfkill)
goto out_error;
err = rfkill_register(rfk->rfkill);
if (err)
goto err_free_polldev;
#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;
goto err_free;
rfk->registered = 1;
return;
err_unreg_rfk:
rfkill_unregister(rfk->rfkill);
err_free_polldev:
input_free_polled_device(rfk->poll_dev);
rfk->poll_dev = NULL;
err_freed_rfk:
rfk->rfkill = NULL;
out_error:
err_free:
rfkill_destroy(rfk->rfkill);
out_error:
rfk->registered = 0;
b43legacywarn(wl, "RF-kill button init failed\n");
}
......@@ -199,10 +156,8 @@ void b43legacy_rfkill_exit(struct b43legacy_wldev *dev)
return;
rfk->registered = 0;
input_unregister_polled_device(rfk->poll_dev);
rfkill_unregister(rfk->rfkill);
input_free_polled_device(rfk->poll_dev);
rfk->poll_dev = NULL;
rfkill_destroy(rfk->rfkill);
rfk->rfkill = NULL;
}
......@@ -6,16 +6,12 @@ struct b43legacy_wldev;
#ifdef CONFIG_B43LEGACY_RFKILL
#include <linux/rfkill.h>
#include <linux/workqueue.h>
#include <linux/input-polldev.h>
struct b43legacy_rfkill {
/* The RFKILL subsystem data structure */
struct rfkill *rfkill;
/* The poll device for the RFKILL input button */
struct input_polled_dev *poll_dev;
/* Did initialization succeed? Used for freeing. */
bool registered;
/* The unique name of this rfkill switch */
......@@ -27,7 +23,7 @@ struct b43legacy_rfkill {
void b43legacy_rfkill_init(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 */
......
......@@ -5,15 +5,14 @@ config IWLWIFI
select FW_LOADER
select MAC80211_LEDS if IWLWIFI_LEDS
select LEDS_CLASS if IWLWIFI_LEDS
select RFKILL if IWLWIFI_RFKILL
config IWLWIFI_LEDS
bool "Enable LED support in iwlagn and iwl3945 drivers"
depends on IWLWIFI
config IWLWIFI_RFKILL
bool "Enable RF kill support in iwlagn and iwl3945 drivers"
depends on IWLWIFI
def_bool y
depends on IWLWIFI && RFKILL
config IWLWIFI_SPECTRUM_MEASUREMENT
bool "Enable Spectrum Measurement in iwlagn driver"
......
......@@ -36,42 +36,37 @@
#include "iwl-core.h"
/* 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;
int err = 0;
if (!priv->rfkill)
return 0;
return -EINVAL;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
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);
switch (state) {
case RFKILL_STATE_UNBLOCKED:
if (iwl_is_rfkill_hw(priv)) {
err = -EBUSY;
goto out_unlock;
}
if (iwl_is_rfkill_hw(priv))
goto out_unlock;
if (!blocked)
iwl_radio_kill_sw_enable_radio(priv);
break;
case RFKILL_STATE_SOFT_BLOCKED:
else
iwl_radio_kill_sw_disable_radio(priv);
break;
default:
IWL_WARN(priv, "we received unexpected RFKILL state %d\n",
state);
break;
}
out_unlock:
mutex_unlock(&priv->mutex);
return err;
return 0;
}
static const struct rfkill_ops iwl_rfkill_ops = {
.set_block = iwl_rfkill_soft_rf_kill,
};
int iwl_rfkill_init(struct iwl_priv *priv)
{
struct device *device = wiphy_dev(priv->hw->wiphy);
......@@ -80,21 +75,16 @@ int iwl_rfkill_init(struct iwl_priv *priv)
BUG_ON(device == NULL);
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) {
IWL_ERR(priv, "Unable to allocate RFKILL device.\n");
ret = -ENOMEM;
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);
if (ret) {
IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret);
......@@ -102,11 +92,10 @@ int iwl_rfkill_init(struct iwl_priv *priv)
}
IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n");
return ret;
return 0;
free_rfkill:
if (priv->rfkill != NULL)
rfkill_free(priv->rfkill);
rfkill_destroy(priv->rfkill);
priv->rfkill = NULL;
error:
......@@ -118,8 +107,10 @@ EXPORT_SYMBOL(iwl_rfkill_init);
void iwl_rfkill_unregister(struct iwl_priv *priv)
{
if (priv->rfkill)
if (priv->rfkill) {
rfkill_unregister(priv->rfkill);
rfkill_destroy(priv->rfkill);
}
priv->rfkill = NULL;
}
......@@ -131,14 +122,10 @@ void iwl_rfkill_set_hw_state(struct iwl_priv *priv)
if (!priv->rfkill)
return;
if (iwl_is_rfkill_hw(priv)) {
rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED);
return;
}
if (!iwl_is_rfkill_sw(priv))
rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED);
if (rfkill_set_hw_state(priv->rfkill,
!!iwl_is_rfkill_hw(priv)))
iwl_radio_kill_sw_disable_radio(priv);
else
rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED);
iwl_radio_kill_sw_enable_radio(priv);
}
EXPORT_SYMBOL(iwl_rfkill_set_hw_state);
......@@ -25,47 +25,42 @@
#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;
switch (state) {
case RFKILL_STATE_UNBLOCKED:
if (!blocked) {
if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio))
return -EBUSY;
if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) &&
(iwm_to_ndev(iwm)->flags & IFF_UP))
iwm_up(iwm);
break;
case RFKILL_STATE_SOFT_BLOCKED:
return iwm_up(iwm);
} else {
if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
iwm_down(iwm);
break;
default:
break;
return iwm_down(iwm);
}
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 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) {
IWM_ERR(iwm, "Unable to allocate rfkill device\n");
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);
if (ret) {
IWM_ERR(iwm, "Failed to register rfkill device\n");
......@@ -74,15 +69,15 @@ int iwm_rfkill_init(struct iwm_priv *iwm)
return 0;
fail:
rfkill_free(iwm->rfkill);
rfkill_destroy(iwm->rfkill);
return ret;
}
void iwm_rfkill_exit(struct iwm_priv *iwm)
{
if (iwm->rfkill)
if (iwm->rfkill) {
rfkill_unregister(iwm->rfkill);
rfkill_free(iwm->rfkill);
rfkill_destroy(iwm->rfkill);
}
iwm->rfkill = NULL;
}
......@@ -21,7 +21,7 @@ config ACER_WMI
depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
depends on SERIO_I8042
depends on RFKILL
depends on RFKILL || RFKILL = n
select ACPI_WMI
---help---
This is a driver for newer Acer (and Wistron) laptops. It adds
......@@ -60,7 +60,7 @@ config DELL_LAPTOP
depends on DCDBAS
depends on EXPERIMENTAL
depends on BACKLIGHT_CLASS_DEVICE
depends on RFKILL
depends on RFKILL || RFKILL = n
depends on POWER_SUPPLY
default n
---help---
......@@ -117,7 +117,7 @@ config HP_WMI
tristate "HP WMI extras"
depends on ACPI_WMI
depends on INPUT
depends on RFKILL
depends on RFKILL || RFKILL = n
help
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.
......@@ -196,14 +196,13 @@ config THINKPAD_ACPI
tristate "ThinkPad ACPI Laptop Extras"
depends on ACPI
depends on INPUT
depends on RFKILL || RFKILL = n
select BACKLIGHT_LCD_SUPPORT
select BACKLIGHT_CLASS_DEVICE
select HWMON
select NVRAM
select NEW_LEDS
select LEDS_CLASS
select NET
select RFKILL
---help---
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video
......@@ -338,9 +337,9 @@ config EEEPC_LAPTOP
depends on ACPI
depends on INPUT
depends on EXPERIMENTAL
depends on RFKILL || RFKILL = n
select BACKLIGHT_CLASS_DEVICE
select HWMON
select RFKILL
---help---
This driver supports the Fn-Fx keys on Eee PC laptops.
It also adds the ability to switch camera/wlan on/off.
......@@ -405,9 +404,8 @@ config ACPI_TOSHIBA
tristate "Toshiba Laptop Extras"
depends on ACPI
depends on INPUT
depends on RFKILL || RFKILL = n
select INPUT_POLLDEV
select NET
select RFKILL
select BACKLIGHT_CLASS_DEVICE
---help---
This driver adds support for access to certain system settings
......
......@@ -958,58 +958,50 @@ static void acer_rfkill_update(struct work_struct *ignored)
status = get_u32(&state, ACER_CAP_WIRELESS);
if (ACPI_SUCCESS(status))
rfkill_force_state(wireless_rfkill, state ?
RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
rfkill_set_sw_state(wireless_rfkill, !!state);
if (has_cap(ACER_CAP_BLUETOOTH)) {
status = get_u32(&state, ACER_CAP_BLUETOOTH);
if (ACPI_SUCCESS(status))
rfkill_force_state(bluetooth_rfkill, state ?
RFKILL_STATE_UNBLOCKED :
RFKILL_STATE_SOFT_BLOCKED);
rfkill_set_sw_state(bluetooth_rfkill, !!state);
}
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;
u32 *cap = data;
status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap);
u32 cap = (unsigned long)data;
status = set_u32(!!blocked, cap);
if (ACPI_FAILURE(status))
return -ENODEV;
return 0;
}
static struct rfkill * acer_rfkill_register(struct device *dev,
enum rfkill_type type, char *name, u32 cap)
static const struct rfkill_ops acer_rfkill_ops = {
.set_block = acer_rfkill_set,
};
static struct rfkill *acer_rfkill_register(struct device *dev,
enum rfkill_type type,
char *name, u32 cap)
{
int err;
u32 state;
u32 *data;
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)
return ERR_PTR(-ENOMEM);
rfkill_dev->name = name;
get_u32(&state, cap);
rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED :
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;
rfkill_set_sw_state(rfkill_dev, !state);
err = rfkill_register(rfkill_dev);
if (err) {
kfree(rfkill_dev->data);
rfkill_free(rfkill_dev);
rfkill_destroy(rfkill_dev);
return ERR_PTR(err);
}
return rfkill_dev;
......@@ -1027,8 +1019,8 @@ static int acer_rfkill_init(struct device *dev)
RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
ACER_CAP_BLUETOOTH);
if (IS_ERR(bluetooth_rfkill)) {
kfree(wireless_rfkill->data);
rfkill_unregister(wireless_rfkill);
rfkill_destroy(wireless_rfkill);
return PTR_ERR(bluetooth_rfkill);
}
}
......@@ -1041,11 +1033,13 @@ static int acer_rfkill_init(struct device *dev)
static void acer_rfkill_exit(void)
{
cancel_delayed_work_sync(&acer_rfkill_work);
kfree(wireless_rfkill->data);
rfkill_unregister(wireless_rfkill);
rfkill_destroy(wireless_rfkill);
if (has_cap(ACER_CAP_BLUETOOTH)) {
kfree(bluetooth_rfkill->data);
rfkill_unregister(bluetooth_rfkill);
rfkill_destroy(bluetooth_rfkill);
}
return;
}
......
......@@ -174,10 +174,11 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
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;
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));
buffer.input[0] = (1 | (radio<<8) | (disable << 16));
......@@ -186,56 +187,24 @@ static int dell_rfkill_set(int radio, enum rfkill_state state)
return 0;
}
static int dell_wifi_set(void *data, enum rfkill_state state)
{
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)
static void dell_rfkill_query(struct rfkill *rfkill, void *data)
{
struct calling_interface_buffer buffer;
int status;
int new_state = RFKILL_STATE_HARD_BLOCKED;
int bit = (unsigned long)data + 16;
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
dell_send_request(&buffer, 17, 11);
status = buffer.output[1];
if (status & (1<<16))
new_state = RFKILL_STATE_SOFT_BLOCKED;
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);
if (status & BIT(bit))
rfkill_set_hw_state(rfkill, !!(status & BIT(16)));
}
static int dell_wwan_get(void *data, enum rfkill_state *state)
{
return dell_rfkill_get(19, state);
}
static const struct rfkill_ops dell_rfkill_ops = {
.set_block = dell_rfkill_set,
.query = dell_rfkill_query,
};
static int dell_setup_rfkill(void)
{
......@@ -248,36 +217,37 @@ static int dell_setup_rfkill(void)
status = buffer.output[1];
if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
wifi_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WLAN);
if (!wifi_rfkill)
wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN,
&dell_rfkill_ops, (void *) 1);
if (!wifi_rfkill) {
ret = -ENOMEM;
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);
if (ret)
goto err_wifi;
}
if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) {
bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH);
if (!bluetooth_rfkill)
bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL,
RFKILL_TYPE_BLUETOOTH,
&dell_rfkill_ops, (void *) 2);
if (!bluetooth_rfkill) {
ret = -ENOMEM;
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);
if (ret)
goto err_bluetooth;
}
if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) {
wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN);
if (!wwan_rfkill)
wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN,
&dell_rfkill_ops, (void *) 3);
if (!wwan_rfkill) {
ret = -ENOMEM;
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);
if (ret)
goto err_wwan;
......@@ -285,22 +255,15 @@ static int dell_setup_rfkill(void)
return 0;
err_wwan:
if (wwan_rfkill)
rfkill_free(wwan_rfkill);
if (bluetooth_rfkill) {
rfkill_destroy(wwan_rfkill);
if (bluetooth_rfkill)
rfkill_unregister(bluetooth_rfkill);
bluetooth_rfkill = NULL;
}
err_bluetooth:
if (bluetooth_rfkill)
rfkill_free(bluetooth_rfkill);
if (wifi_rfkill) {
rfkill_destroy(bluetooth_rfkill);
if (wifi_rfkill)
rfkill_unregister(wifi_rfkill);
wifi_rfkill = NULL;
}
err_wifi:
if (wifi_rfkill)
rfkill_free(wifi_rfkill);
rfkill_destroy(wifi_rfkill);
return ret;
}
......
......@@ -299,39 +299,22 @@ static int update_bl_status(struct backlight_device *bd)
* Rfkill helpers
*/
static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state)
{
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)
static bool eeepc_wlan_rfkill_blocked(void)
{
if (get_acpi(CM_ASL_WLAN) == 1)
*state = RFKILL_STATE_UNBLOCKED;
else
*state = RFKILL_STATE_SOFT_BLOCKED;
return 0;
return false;
return true;
}
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)
return set_acpi(CM_ASL_BLUETOOTH, 0);
else
return set_acpi(CM_ASL_BLUETOOTH, 1);
unsigned long asl = (unsigned long)data;
return set_acpi(asl, !blocked);
}
static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state)
{
if (get_acpi(CM_ASL_BLUETOOTH) == 1)
*state = RFKILL_STATE_UNBLOCKED;
else
*state = RFKILL_STATE_SOFT_BLOCKED;
return 0;
}
static const struct rfkill_ops eeepc_rfkill_ops = {
.set_block = eeepc_rfkill_set,
};
/*
* Sys helpers
......@@ -531,9 +514,9 @@ static int notify_brn(void)
static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
{
enum rfkill_state state;
struct pci_dev *dev;
struct pci_bus *bus = pci_find_bus(0, 1);
bool blocked;
if (event != ACPI_NOTIFY_BUS_CHECK)
return;
......@@ -543,9 +526,8 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
return;
}
eeepc_wlan_rfkill_state(ehotk->eeepc_wlan_rfkill, &state);
if (state == RFKILL_STATE_UNBLOCKED) {
blocked = eeepc_wlan_rfkill_blocked();
if (!blocked) {
dev = pci_get_slot(bus, 0);
if (dev) {
/* Device already present */
......@@ -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)
......@@ -684,26 +666,17 @@ static int eeepc_hotk_add(struct acpi_device *device)
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
if (get_acpi(CM_ASL_WLAN) != -1) {
ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev,
RFKILL_TYPE_WLAN);
ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan",
&device->dev,
RFKILL_TYPE_WLAN,
&eeepc_rfkill_ops,
(void *)CM_ASL_WLAN);
if (!ehotk->eeepc_wlan_rfkill)
goto wlan_fail;
ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan";
ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set;
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);
}
rfkill_set_global_sw_state(RFKILL_TYPE_WLAN,
get_acpi(CM_ASL_WLAN) != 1);
result = rfkill_register(ehotk->eeepc_wlan_rfkill);
if (result)
goto wlan_fail;
......@@ -711,28 +684,17 @@ static int eeepc_hotk_add(struct acpi_device *device)
if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
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)
goto bluetooth_fail;
ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth";
ehotk->eeepc_bluetooth_rfkill->toggle_radio =
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);
}
rfkill_set_global_sw_state(RFKILL_TYPE_BLUETOOTH,
get_acpi(CM_ASL_BLUETOOTH) != 1);
result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
if (result)
goto bluetooth_fail;
......@@ -741,13 +703,10 @@ static int eeepc_hotk_add(struct acpi_device *device)
return 0;
bluetooth_fail:
if (ehotk->eeepc_bluetooth_rfkill)
rfkill_free(ehotk->eeepc_bluetooth_rfkill);
rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
rfkill_unregister(ehotk->eeepc_wlan_rfkill);
ehotk->eeepc_wlan_rfkill = NULL;
wlan_fail:
if (ehotk->eeepc_wlan_rfkill)
rfkill_free(ehotk->eeepc_wlan_rfkill);
rfkill_destroy(ehotk->eeepc_wlan_rfkill);
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
ehotk_fail:
......
......@@ -154,58 +154,46 @@ static int hp_wmi_dock_state(void)
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)
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101);
else
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100);
}
unsigned long b = (unsigned long) data;
int query = BIT(b + 8) | ((!!blocked) << b);
static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state)
{
if (state)
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202);
else
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200);
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
}
static int hp_wmi_wwan_set(void *data, enum rfkill_state state)
{
if (state)
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404);
else
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400);
}
static const struct rfkill_ops hp_wmi_rfkill_ops = {
.set_block = hp_wmi_set_block,
};
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);
if (wireless & 0x100)
return RFKILL_STATE_UNBLOCKED;
return false;
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);
if (wireless & 0x10000)
return RFKILL_STATE_UNBLOCKED;
return false;
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);
if (wireless & 0x1000000)
return RFKILL_STATE_UNBLOCKED;
return false;
else
return RFKILL_STATE_SOFT_BLOCKED;
return true;
}
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)
}
} else if (eventcode == 0x5) {
if (wifi_rfkill)
rfkill_force_state(wifi_rfkill,
hp_wmi_wifi_state());
rfkill_set_sw_state(wifi_rfkill,
hp_wmi_wifi_state());
if (bluetooth_rfkill)
rfkill_force_state(bluetooth_rfkill,
hp_wmi_bluetooth_state());
rfkill_set_sw_state(bluetooth_rfkill,
hp_wmi_bluetooth_state());
if (wwan_rfkill)
rfkill_force_state(wwan_rfkill,
hp_wmi_wwan_state());
rfkill_set_sw_state(wwan_rfkill,
hp_wmi_wwan_state());
} else
printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
eventcode);
......@@ -430,31 +418,34 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
goto add_sysfs_error;
if (wireless & 0x1) {
wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
wifi_rfkill->name = "hp-wifi";
wifi_rfkill->state = hp_wmi_wifi_state();
wifi_rfkill->toggle_radio = hp_wmi_wifi_set;
wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
RFKILL_TYPE_WLAN,
&hp_wmi_rfkill_ops,
(void *) 0);
rfkill_set_sw_state(wifi_rfkill, hp_wmi_wifi_state());
err = rfkill_register(wifi_rfkill);
if (err)
goto add_sysfs_error;
goto register_wifi_error;
}
if (wireless & 0x2) {
bluetooth_rfkill = rfkill_allocate(&device->dev,
RFKILL_TYPE_BLUETOOTH);
bluetooth_rfkill->name = "hp-bluetooth";
bluetooth_rfkill->state = hp_wmi_bluetooth_state();
bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set;
bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
RFKILL_TYPE_BLUETOOTH,
&hp_wmi_rfkill_ops,
(void *) 1);
rfkill_set_sw_state(bluetooth_rfkill,
hp_wmi_bluetooth_state());
err = rfkill_register(bluetooth_rfkill);
if (err)
goto register_bluetooth_error;
}
if (wireless & 0x4) {
wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
wwan_rfkill->name = "hp-wwan";
wwan_rfkill->state = hp_wmi_wwan_state();
wwan_rfkill->toggle_radio = hp_wmi_wwan_set;
wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
RFKILL_TYPE_WWAN,
&hp_wmi_rfkill_ops,
(void *) 2);
rfkill_set_sw_state(wwan_rfkill, hp_wmi_wwan_state());
err = rfkill_register(wwan_rfkill);
if (err)
goto register_wwan_err;
......@@ -462,11 +453,15 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
return 0;
register_wwan_err:
rfkill_destroy(wwan_rfkill);
if (bluetooth_rfkill)
rfkill_unregister(bluetooth_rfkill);
register_bluetooth_error:
rfkill_destroy(bluetooth_rfkill);
if (wifi_rfkill)
rfkill_unregister(wifi_rfkill);
register_wifi_error:
rfkill_destroy(wifi_rfkill);
add_sysfs_error:
cleanup_sysfs(device);
return err;
......@@ -476,12 +471,18 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
{
cleanup_sysfs(device);
if (wifi_rfkill)
if (wifi_rfkill) {
rfkill_unregister(wifi_rfkill);
if (bluetooth_rfkill)
rfkill_destroy(wifi_rfkill);
}
if (bluetooth_rfkill) {
rfkill_unregister(bluetooth_rfkill);
if (wwan_rfkill)
rfkill_destroy(wifi_rfkill);
}
if (wwan_rfkill) {
rfkill_unregister(wwan_rfkill);
rfkill_destroy(wwan_rfkill);
}
return 0;
}
......
......@@ -128,11 +128,11 @@ enum sony_nc_rfkill {
SONY_BLUETOOTH,
SONY_WWAN,
SONY_WIMAX,
SONY_RFKILL_MAX,
N_SONY_RFKILL,
};
static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX];
static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900};
static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
static void sony_nc_rfkill_update(void);
/*********** Input Devices ***********/
......@@ -1051,147 +1051,98 @@ static void sony_nc_rfkill_cleanup(void)
{
int i;
for (i = 0; i < SONY_RFKILL_MAX; i++) {
if (sony_rfkill_devices[i])
for (i = 0; i < N_SONY_RFKILL; i++) {
if (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)
{
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)
static int sony_nc_rfkill_set(void *data, bool blocked)
{
int result;
int argument = sony_rfkill_address[(long) data] + 0x100;
if (state == RFKILL_STATE_UNBLOCKED)
if (!blocked)
argument |= 0xff0000;
return sony_call_snc_handle(0x124, argument, &result);
}
static int sony_nc_setup_wifi_rfkill(struct acpi_device *device)
{
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 const struct rfkill_ops sony_rfkill_ops = {
.set_block = sony_nc_rfkill_set,
};
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;
struct rfkill *sony_bluetooth_rfkill;
sony_bluetooth_rfkill = rfkill_allocate(&device->dev,
RFKILL_TYPE_BLUETOOTH);
if (!sony_bluetooth_rfkill)
return -1;
sony_bluetooth_rfkill->name = "sony-bluetooth";
sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set;
sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get;
sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH;
err = rfkill_register(sony_bluetooth_rfkill);
if (err)
rfkill_free(sony_bluetooth_rfkill);
else {
sony_rfkill_devices[SONY_BLUETOOTH] = sony_bluetooth_rfkill;
sony_nc_rfkill_set(sony_bluetooth_rfkill->data,
RFKILL_STATE_UNBLOCKED);
struct rfkill *rfk;
enum rfkill_type type;
const char *name;
switch (nc_type) {
case SONY_WIFI:
type = RFKILL_TYPE_WLAN;
name = "sony-wifi";
break;
case SONY_BLUETOOTH:
type = RFKILL_TYPE_BLUETOOTH;
name = "sony-bluetooth";
break;
case SONY_WWAN:
type = RFKILL_TYPE_WWAN;
name = "sony-wwan";
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)
{
int err = 0;
struct rfkill *sony_wwan_rfkill;
rfk = rfkill_alloc(name, &device->dev, type,
&sony_rfkill_ops, (void *)nc_type);
if (!rfk)
return -ENOMEM;
sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
if (!sony_wwan_rfkill)
return -1;
sony_wwan_rfkill->name = "sony-wwan";
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);
err = rfkill_register(rfk);
if (err) {
rfkill_destroy(rfk);
return err;
}
sony_rfkill_devices[nc_type] = rfk;
sony_nc_rfkill_set((void *)nc_type, false);
return err;
}
static int sony_nc_setup_wimax_rfkill(struct acpi_device *device)
static void sony_nc_rfkill_update()
{
int err = 0;
struct rfkill *sony_wimax_rfkill;
enum sony_nc_rfkill i;
int result;
bool hwblock;
sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX);
if (!sony_wimax_rfkill)
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;
}
sony_call_snc_handle(0x124, 0x200, &result);
hwblock = !(result & 0x1);
static void sony_nc_rfkill_update()
{
int i;
enum rfkill_state state;
for (i = 0; i < N_SONY_RFKILL; i++) {
int argument = sony_rfkill_address[i];
for (i = 0; i < SONY_RFKILL_MAX; i++) {
if (sony_rfkill_devices[i]) {
sony_rfkill_devices[i]->
get_state(sony_rfkill_devices[i]->data,
&state);
rfkill_force_state(sony_rfkill_devices[i], state);
if (!sony_rfkill_devices[i])
continue;
if (hwblock) {
if (rfkill_set_hw_state(sony_rfkill_devices[i], true))
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)
}
if (result & 0x1)
sony_nc_setup_wifi_rfkill(device);
sony_nc_setup_rfkill(device, SONY_WIFI);
if (result & 0x2)
sony_nc_setup_bluetooth_rfkill(device);
sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
if (result & 0x1c)
sony_nc_setup_wwan_rfkill(device);
sony_nc_setup_rfkill(device, SONY_WWAN);
if (result & 0x20)
sony_nc_setup_wimax_rfkill(device);
sony_nc_setup_rfkill(device, SONY_WIMAX);
return 0;
}
......
......@@ -45,7 +45,6 @@
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>
#include <linux/input-polldev.h>
#include <asm/uaccess.h>
......@@ -250,21 +249,15 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
struct toshiba_acpi_dev {
struct platform_device *p_dev;
struct rfkill *rfk_dev;
struct input_polled_dev *poll_dev;
struct rfkill *bt_rfk;
const char *bt_name;
const char *rfk_name;
bool last_rfk_state;
struct mutex mutex;
};
static struct toshiba_acpi_dev toshiba_acpi = {
.bt_name = "Toshiba Bluetooth",
.rfk_name = "Toshiba RFKill Switch",
.last_rfk_state = false,
};
/* Bluetooth rfkill handlers */
......@@ -283,21 +276,6 @@ static u32 hci_get_bt_present(bool *present)
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)
{
u32 hci_result;
......@@ -311,70 +289,67 @@ static u32 hci_get_radio_state(bool *radio_state)
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 value;
int err;
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)
return -EFAULT;
mutex_lock(&dev->mutex);
if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) {
err = -EBUSY;
goto out;
}
switch (state) {
case RFKILL_STATE_UNBLOCKED:
if (!radio_state)
return -EPERM;
break;
case RFKILL_STATE_SOFT_BLOCKED:
break;
default:
return -EINVAL;
if (!radio_state) {
err = 0;
goto out;
}
mutex_lock(&dev->mutex);
hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
mutex_unlock(&dev->mutex);
if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
return -EFAULT;
return 0;
err = -EBUSY;
else
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 value;
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);
if (hci_result != HCI_SUCCESS)
return; /* Can't do anything useful */
if (hci_result != HCI_SUCCESS) {
/* Can't do anything useful */
mutex_unlock(&dev->mutex);
}
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);
if (unlikely(state_changed)) {
rfkill_force_state(dev->rfk_dev,
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);
}
if (rfkill_set_hw_state(rfkill, !new_rfk_state))
bt_rfkill_set_block(data, true);
}
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 backlight_device *toshiba_backlight_device;
static int force_fan;
......@@ -702,14 +677,11 @@ static struct backlight_ops toshiba_backlight_data = {
static void toshiba_acpi_exit(void)
{
if (toshiba_acpi.poll_dev) {
input_unregister_polled_device(toshiba_acpi.poll_dev);
input_free_polled_device(toshiba_acpi.poll_dev);
if (toshiba_acpi.bt_rfk) {
rfkill_unregister(toshiba_acpi.bt_rfk);
rfkill_destroy(toshiba_acpi.bt_rfk);
}
if (toshiba_acpi.rfk_dev)
rfkill_unregister(toshiba_acpi.rfk_dev);
if (toshiba_backlight_device)
backlight_device_unregister(toshiba_backlight_device);
......@@ -728,8 +700,6 @@ static int __init toshiba_acpi_init(void)
acpi_status status = AE_OK;
u32 hci_result;
bool bt_present;
bool bt_on;
bool radio_on;
int ret = 0;
if (acpi_disabled)
......@@ -793,60 +763,21 @@ static int __init toshiba_acpi_init(void)
/* Register rfkill switch for Bluetooth */
if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev,
RFKILL_TYPE_BLUETOOTH);
if (!toshiba_acpi.rfk_dev) {
toshiba_acpi.bt_rfk = rfkill_alloc(toshiba_acpi.bt_name,
&toshiba_acpi.p_dev->dev,
RFKILL_TYPE_BLUETOOTH,
&toshiba_rfk_ops,
&toshiba_acpi);
if (!toshiba_acpi.bt_rfk) {
printk(MY_ERR "unable to allocate rfkill device\n");
toshiba_acpi_exit();
return -ENOMEM;
}
toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name;
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);
ret = rfkill_register(toshiba_acpi.bt_rfk);
if (ret) {
printk(MY_ERR "unable to register rfkill device\n");
toshiba_acpi_exit();
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");
rfkill_destroy(toshiba_acpi.bt_rfk);
toshiba_acpi_exit();
return ret;
}
......
......@@ -311,6 +311,7 @@ unifdef-y += ptrace.h
unifdef-y += qnx4_fs.h
unifdef-y += quota.h
unifdef-y += random.h
unifdef-y += rfkill.h
unifdef-y += irqnr.h
unifdef-y += reboot.h
unifdef-y += reiserfs_fs.h
......
......@@ -4,6 +4,7 @@
/*
* Copyright (C) 2006 - 2007 Ivo van Doorn
* Copyright (C) 2007 Dmitry Torokhov
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -21,6 +22,24 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* define userspace visible states */
#define RFKILL_STATE_SOFT_BLOCKED 0
#define RFKILL_STATE_UNBLOCKED 1
#define RFKILL_STATE_HARD_BLOCKED 2
/* and that's all userspace gets */
#ifdef __KERNEL__
/* don't allow anyone to use these in the kernel */
enum rfkill_user_states {
RFKILL_USER_STATE_SOFT_BLOCKED = RFKILL_STATE_SOFT_BLOCKED,
RFKILL_USER_STATE_UNBLOCKED = RFKILL_STATE_UNBLOCKED,
RFKILL_USER_STATE_HARD_BLOCKED = RFKILL_STATE_HARD_BLOCKED,
};
#undef RFKILL_STATE_SOFT_BLOCKED
#undef RFKILL_STATE_UNBLOCKED
#undef RFKILL_STATE_HARD_BLOCKED
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/list.h>
......@@ -30,109 +49,267 @@
/**
* enum rfkill_type - type of rfkill switch.
* RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device.
* RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device.
* RFKILL_TYPE_UWB: switch is on a ultra wideband device.
* RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
* RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
*
* @RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device.
* @RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device.
* @RFKILL_TYPE_UWB: switch is on a ultra wideband device.
* @RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
* @RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
* @NUM_RFKILL_TYPES: number of defined rfkill types
*/
enum rfkill_type {
RFKILL_TYPE_WLAN ,
RFKILL_TYPE_WLAN,
RFKILL_TYPE_BLUETOOTH,
RFKILL_TYPE_UWB,
RFKILL_TYPE_WIMAX,
RFKILL_TYPE_WWAN,
RFKILL_TYPE_MAX,
NUM_RFKILL_TYPES,
};
enum rfkill_state {
RFKILL_STATE_SOFT_BLOCKED = 0, /* Radio output blocked */
RFKILL_STATE_UNBLOCKED = 1, /* Radio output allowed */
RFKILL_STATE_HARD_BLOCKED = 2, /* Output blocked, non-overrideable */
RFKILL_STATE_MAX, /* marker for last valid state */
/* this is opaque */
struct rfkill;
/**
* struct rfkill_ops - rfkill driver methods
*
* @poll: poll the rfkill block state(s) -- only assign this method
* when you need polling. When called, simply call one of the
* rfkill_set{,_hw,_sw}_state family of functions. If the hw
* is getting unblocked you need to take into account the return
* value of those functions to make sure the software block is
* properly used.
* @query: query the rfkill block state(s) and call exactly one of the
* rfkill_set{,_hw,_sw}_state family of functions. Assign this
* method if input events can cause hardware state changes to make
* the rfkill core query your driver before setting a requested
* block.
* @set_block: turn the transmitter on (blocked == false) or off
* (blocked == true) -- this is called only while the transmitter
* is not hard-blocked, but note that the core's view of whether
* the transmitter is hard-blocked might differ from your driver's
* view due to race conditions, so it is possible that it is still
* called at the same time as you are calling rfkill_set_hw_state().
* This callback must be assigned.
*/
struct rfkill_ops {
void (*poll)(struct rfkill *rfkill, void *data);
void (*query)(struct rfkill *rfkill, void *data);
int (*set_block)(void *data, bool blocked);
};
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
/**
* struct rfkill - rfkill control structure.
* @name: Name of the switch.
* @type: Radio type which the button controls, the value stored
* here should be a value from enum rfkill_type.
* @state: State of the switch, "UNBLOCKED" means radio can operate.
* @mutex: Guards switch state transitions. It serializes callbacks
* and also protects the state.
* @data: Pointer to the RF button drivers private data which will be
* passed along when toggling radio state.
* @toggle_radio(): Mandatory handler to control state of the radio.
* only RFKILL_STATE_SOFT_BLOCKED and RFKILL_STATE_UNBLOCKED are
* valid parameters.
* @get_state(): handler to read current radio state from hardware,
* may be called from atomic context, should return 0 on success.
* Either this handler OR judicious use of rfkill_force_state() is
* MANDATORY for any driver capable of RFKILL_STATE_HARD_BLOCKED.
* @led_trigger: A LED trigger for this button's LED.
* @dev: Device structure integrating the switch into device tree.
* @node: Used to place switch into list of all switches known to the
* the system.
*
* This structure represents a RF switch located on a network device.
* rfkill_alloc - allocate rfkill structure
* @name: name of the struct -- the string is not copied internally
* @parent: device that has rf switch on it
* @type: type of the switch (RFKILL_TYPE_*)
* @ops: rfkill methods
* @ops_data: data passed to each method
*
* This function should be called by the transmitter driver to allocate an
* rfkill structure. Returns %NULL on failure.
*/
struct rfkill {
const char *name;
enum rfkill_type type;
/* the mutex serializes callbacks and also protects
* the state */
struct mutex mutex;
enum rfkill_state state;
void *data;
int (*toggle_radio)(void *data, enum rfkill_state state);
int (*get_state)(void *data, enum rfkill_state *state);
struct rfkill * __must_check rfkill_alloc(const char *name,
struct device *parent,
const enum rfkill_type type,
const struct rfkill_ops *ops,
void *ops_data);
#ifdef CONFIG_RFKILL_LEDS
struct led_trigger led_trigger;
#endif
/**
* rfkill_register - Register a rfkill structure.
* @rfkill: rfkill structure to be registered
*
* This function should be called by the transmitter driver to register
* the rfkill structure needs to be registered. Before calling this function
* the driver needs to be ready to service method calls from rfkill.
*/
int __must_check rfkill_register(struct rfkill *rfkill);
struct device dev;
struct list_head node;
enum rfkill_state state_for_resume;
};
#define to_rfkill(d) container_of(d, struct rfkill, dev)
/**
* rfkill_pause_polling(struct rfkill *rfkill)
*
* Pause polling -- say transmitter is off for other reasons.
* NOTE: not necessary for suspend/resume -- in that case the
* core stops polling anyway
*/
void rfkill_pause_polling(struct rfkill *rfkill);
struct rfkill * __must_check rfkill_allocate(struct device *parent,
enum rfkill_type type);
void rfkill_free(struct rfkill *rfkill);
int __must_check rfkill_register(struct rfkill *rfkill);
/**
* rfkill_resume_polling(struct rfkill *rfkill)
*
* Pause polling -- say transmitter is off for other reasons.
* NOTE: not necessary for suspend/resume -- in that case the
* core stops polling anyway
*/
void rfkill_resume_polling(struct rfkill *rfkill);
/**
* rfkill_unregister - Unregister a rfkill structure.
* @rfkill: rfkill structure to be unregistered
*
* This function should be called by the network driver during device
* teardown to destroy rfkill structure. Until it returns, the driver
* needs to be able to service method calls.
*/
void rfkill_unregister(struct rfkill *rfkill);
int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state);
int rfkill_set_default(enum rfkill_type type, enum rfkill_state state);
/**
* rfkill_destroy - free rfkill structure
* @rfkill: rfkill structure to be destroyed
*
* Destroys the rfkill structure.
*/
void rfkill_destroy(struct rfkill *rfkill);
/**
* rfkill_set_hw_state - Set the internal rfkill hardware block state
* @rfkill: pointer to the rfkill class to modify.
* @state: the current hardware block state to set
*
* rfkill drivers that get events when the hard-blocked state changes
* use this function to notify the rfkill core (and through that also
* userspace) of the current state -- they should also use this after
* resume if the state could have changed.
*
* You need not (but may) call this function if poll_state is assigned.
*
* This function can be called in any context, even from within rfkill
* callbacks.
*
* The function returns the combined block state (true if transmitter
* should be blocked) so that drivers need not keep track of the soft
* block state -- which they might not be able to.
*/
bool __must_check rfkill_set_hw_state(struct rfkill *rfkill, bool blocked);
/**
* rfkill_set_sw_state - Set the internal rfkill software block state
* @rfkill: pointer to the rfkill class to modify.
* @state: the current software block state to set
*
* rfkill drivers that get events when the soft-blocked state changes
* (yes, some platforms directly act on input but allow changing again)
* use this function to notify the rfkill core (and through that also
* userspace) of the current state -- they should also use this after
* resume if the state could have changed.
*
* This function can be called in any context, even from within rfkill
* callbacks.
*
* The function returns the combined block state (true if transmitter
* should be blocked).
*/
bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked);
/**
* rfkill_set_states - Set the internal rfkill block states
* @rfkill: pointer to the rfkill class to modify.
* @sw: the current software block state to set
* @hw: the current hardware block state to set
*
* This function can be called in any context, even from within rfkill
* callbacks.
*/
void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw);
/**
* rfkill_state_complement - return complementar state
* @state: state to return the complement of
* rfkill_set_global_sw_state - set global sw block default
* @type: rfkill type to set default for
* @blocked: default to set
*
* Returns RFKILL_STATE_SOFT_BLOCKED if @state is RFKILL_STATE_UNBLOCKED,
* returns RFKILL_STATE_UNBLOCKED otherwise.
* This function sets the global default -- use at boot if your platform has
* an rfkill switch. If not early enough this call may be ignored.
*
* XXX: instead of ignoring -- how about just updating all currently
* registered drivers?
*/
static inline enum rfkill_state rfkill_state_complement(enum rfkill_state state)
void rfkill_set_global_sw_state(const enum rfkill_type type, bool blocked);
#else /* !RFKILL */
static inline struct rfkill * __must_check
rfkill_alloc(const char *name,
struct device *parent,
const enum rfkill_type type,
const struct rfkill_ops *ops,
void *ops_data)
{
return ERR_PTR(-ENODEV);
}
static inline int __must_check rfkill_register(struct rfkill *rfkill)
{
if (rfkill == ERR_PTR(-ENODEV))
return 0;
return -EINVAL;
}
static inline void rfkill_pause_polling(struct rfkill *rfkill)
{
}
static inline void rfkill_resume_polling(struct rfkill *rfkill)
{
}
static inline void rfkill_unregister(struct rfkill *rfkill)
{
}
static inline void rfkill_destroy(struct rfkill *rfkill)
{
}
static inline bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked)
{
return blocked;
}
static inline bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked)
{
return blocked;
}
static inline void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
{
}
static inline void rfkill_set_global_sw_state(const enum rfkill_type type,
bool blocked)
{
return (state == RFKILL_STATE_UNBLOCKED) ?
RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED;
}
#endif /* RFKILL || RFKILL_MODULE */
#ifdef CONFIG_RFKILL_LEDS
/**
* rfkill_get_led_name - Get the LED trigger name for the button's LED.
* rfkill_get_led_trigger_name - Get the LED trigger name for the button's LED.
* This function might return a NULL pointer if registering of the
* LED trigger failed.
* Use this as "default_trigger" for the LED.
* LED trigger failed. Use this as "default_trigger" for the LED.
*/
static inline char *rfkill_get_led_name(struct rfkill *rfkill)
{
#ifdef CONFIG_RFKILL_LEDS
return (char *)(rfkill->led_trigger.name);
const char *rfkill_get_led_trigger_name(struct rfkill *rfkill);
/**
* rfkill_set_led_trigger_name -- set the LED trigger name
* @rfkill: rfkill struct
* @name: LED trigger name
*
* This function sets the LED trigger name of the radio LED
* trigger that rfkill creates. It is optional, but if called
* must be called before rfkill_register() to be effective.
*/
void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name);
#else
static inline const char *rfkill_get_led_trigger_name(struct rfkill *rfkill)
{
return NULL;
#endif
}
static inline void
rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name)
{
}
#endif
#endif /* __KERNEL__ */
#endif /* RFKILL_H */
......@@ -253,7 +253,6 @@
struct net_device;
struct genl_info;
struct wimax_dev;
struct input_dev;
/**
* struct wimax_dev - Generic WiMAX device
......@@ -293,8 +292,8 @@ struct input_dev;
* See wimax_reset()'s documentation.
*
* @name: [fill] A way to identify this device. We need to register a
* name with many subsystems (input for RFKILL, workqueue
* creation, etc). We can't use the network device name as that
* name with many subsystems (rfkill, workqueue creation, etc).
* We can't use the network device name as that
* 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
* using the driver name and device bus id, place it here and use
......@@ -316,9 +315,6 @@ struct input_dev;
*
* @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_hw: [private] State of the hardware radio switch (OFF/ON)
......
......@@ -10,22 +10,15 @@ menuconfig RFKILL
To compile this driver as a module, choose M here: the
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
config RFKILL_LEDS
bool
depends on RFKILL && LEDS_TRIGGERS
depends on RFKILL
depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS
default y
config RFKILL_INPUT
bool
depends on RFKILL
depends on INPUT = y || RFKILL = INPUT
default y
......@@ -2,5 +2,6 @@
# Makefile for the RF switch subsystem.
#
obj-$(CONFIG_RFKILL) += rfkill.o
obj-$(CONFIG_RFKILL_INPUT) += rfkill-input.o
rfkill-y += core.o
rfkill-$(CONFIG_RFKILL_INPUT) += input.o
obj-$(CONFIG_RFKILL) += rfkill.o
/*
* Copyright (C) 2007 Ivo van Doorn
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
*/
/*
......@@ -11,11 +12,16 @@
#ifndef __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_restore_states(void);
void rfkill_remove_epo_lock(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 */
#
# 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
tristate "WiMAX Wireless Broadband support"
depends on (y && RFKILL != m) || m
depends on (INPUT && RFKILL != n) || RFKILL = n
help
Select to configure support for devices that provide
......
......@@ -29,8 +29,8 @@
* A non-polled generic rfkill device is embedded into the WiMAX
* subsystem's representation of a device.
*
* FIXME: Need polled support? use a timer or add the implementation
* to the stack.
* FIXME: Need polled support? Let drivers provide a poll routine
* and hand it to rfkill ops then?
*
* All device drivers have to do is after wimax_dev_init(), call
* wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update
......@@ -43,7 +43,7 @@
* wimax_rfkill() Kernel calling wimax_rfkill()
* __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()
......@@ -65,15 +65,11 @@
#include <linux/wimax.h>
#include <linux/security.h>
#include <linux/rfkill.h>
#include <linux/input.h>
#include "wimax-internal.h"
#define D_SUBMODULE op_rfkill
#include "debug-levels.h"
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
/**
* 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,
int result;
struct device *dev = wimax_dev_to_dev(wimax_dev);
enum wimax_st wimax_state;
enum rfkill_state rfkill_state;
d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
BUG_ON(state == WIMAX_RF_QUERY);
......@@ -112,16 +107,15 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
if (state != wimax_dev->rf_hw) {
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
&& wimax_dev->rf_sw == WIMAX_RF_ON)
wimax_state = WIMAX_ST_READY;
else
wimax_state = WIMAX_ST_RADIO_OFF;
rfkill_set_hw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF);
__wimax_state_change(wimax_dev, wimax_state);
input_report_key(wimax_dev->rfkill_input, KEY_WIMAX,
rfkill_state);
}
error_not_ready:
mutex_unlock(&wimax_dev->mutex);
......@@ -174,6 +168,7 @@ void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev,
else
wimax_state = WIMAX_ST_RADIO_OFF;
__wimax_state_change(wimax_dev, wimax_state);
rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF);
}
error_not_ready:
mutex_unlock(&wimax_dev->mutex);
......@@ -249,36 +244,31 @@ int __wimax_rf_toggle_radio(struct wimax_dev *wimax_dev,
*
* NOTE: This call will block until the operation is completed.
*/
static
int wimax_rfkill_toggle_radio(void *data, enum rfkill_state state)
static int wimax_rfkill_set_radio_block(void *data, bool blocked)
{
int result;
struct wimax_dev *wimax_dev = data;
struct device *dev = wimax_dev_to_dev(wimax_dev);
enum wimax_rf_state rf_state;
d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
switch (state) {
case RFKILL_STATE_SOFT_BLOCKED:
d_fnstart(3, dev, "(wimax_dev %p blocked %u)\n", wimax_dev, blocked);
rf_state = WIMAX_RF_ON;
if (blocked)
rf_state = WIMAX_RF_OFF;
break;
case RFKILL_STATE_UNBLOCKED:
rf_state = WIMAX_RF_ON;
break;
default:
BUG();
}
mutex_lock(&wimax_dev->mutex);
if (wimax_dev->state <= __WIMAX_ST_QUIESCING)
result = 0; /* just pretend it didn't happen */
result = 0;
else
result = __wimax_rf_toggle_radio(wimax_dev, rf_state);
mutex_unlock(&wimax_dev->mutex);
d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n",
wimax_dev, state, result);
d_fnend(3, dev, "(wimax_dev %p blocked %u) = %d\n",
wimax_dev, blocked, 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
......@@ -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);
if (result < 0)
goto error;
rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF);
break;
case WIMAX_RF_QUERY:
break;
......@@ -349,40 +340,20 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev)
{
int result;
struct rfkill *rfkill;
struct input_dev *input_dev;
struct device *dev = wimax_dev_to_dev(wimax_dev);
d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
/* Initialize RF Kill */
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)
goto error_rfkill_allocate;
d_printf(1, dev, "rfkill %p\n", 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);
if (result < 0)
goto error_rfkill_register;
......@@ -394,17 +365,8 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev)
d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev);
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:
input_unregister_device(wimax_dev->rfkill_input);
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);
rfkill_destroy(wimax_dev->rfkill);
error_rfkill_allocate:
d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result);
return result;
......@@ -423,45 +385,12 @@ void wimax_rfkill_rm(struct wimax_dev *wimax_dev)
{
struct device *dev = wimax_dev_to_dev(wimax_dev);
d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
rfkill_unregister(wimax_dev->rfkill); /* frees */
input_unregister_device(wimax_dev->rfkill_input);
rfkill_unregister(wimax_dev->rfkill);
rfkill_destroy(wimax_dev->rfkill);
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
*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册