Skip to content

Commit

Permalink
iwlwifi : Patch adds rfkill subsystem for 3945
Browse files Browse the repository at this point in the history
The patch removes the sysfs interface from iwl3945 and uses
the rfkill subsystem instead.

Original patch by Adel, I fixed the patch to work it properly.

Signed-off-by: Adel Gadllah <adel.gadllah@gmail.com>
Signed-off-by: Abhijeet Kolekar <abhijeet.kolekar@intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Abhijeet Kolekar authored and John W. Linville committed Jun 30, 2008
1 parent 2ff75b7 commit ebef200
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 35 deletions.
25 changes: 25 additions & 0 deletions drivers/net/wireless/iwlwifi/iwl-3945.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
#include <linux/kernel.h>
#include <net/ieee80211_radiotap.h>

/*used for rfkill*/
#include <linux/rfkill.h>
#include <linux/input.h>

/* Hardware specific file defines the PCI IDs table for that hardware module */
extern struct pci_device_id iwl3945_hw_card_ids[];

Expand Down Expand Up @@ -686,6 +690,23 @@ enum {

#endif

#ifdef CONFIG_IWLWIFI_RFKILL
struct iwl3945_priv;

struct iwl3945_rfkill_mngr {
struct rfkill *rfkill;
struct input_dev *input_dev;
};

void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv);
void iwl3945_rfkill_unregister(struct iwl3945_priv *priv);
int iwl3945_rfkill_init(struct iwl3945_priv *priv);
#else
static inline void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv) {}
static inline void iwl3945_rfkill_unregister(struct iwl3945_priv *priv) {}
static inline int iwl3945_rfkill_init(struct iwl3945_priv *priv) { return 0; }
#endif

#define IWL_MAX_NUM_QUEUES IWL39_MAX_NUM_QUEUES

struct iwl3945_priv {
Expand Down Expand Up @@ -779,6 +800,10 @@ struct iwl3945_priv {
struct iwl3945_init_alive_resp card_alive_init;
struct iwl3945_alive_resp card_alive;

#ifdef CONFIG_IWLWIFI_RFKILL
struct iwl3945_rfkill_mngr rfkill_mngr;
#endif

#ifdef CONFIG_IWL3945_LEDS
struct iwl3945_led led[IWL_LED_TRG_MAX];
unsigned long last_blink_time;
Expand Down
186 changes: 151 additions & 35 deletions drivers/net/wireless/iwlwifi/iwl3945-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -5921,7 +5921,9 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
STATUS_GEO_CONFIGURED |
test_bit(STATUS_IN_SUSPEND, &priv->status) <<
STATUS_IN_SUSPEND;
STATUS_IN_SUSPEND |
test_bit(STATUS_EXIT_PENDING, &priv->status) <<
STATUS_EXIT_PENDING;
goto exit;
}

Expand All @@ -5936,7 +5938,9 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
test_bit(STATUS_IN_SUSPEND, &priv->status) <<
STATUS_IN_SUSPEND |
test_bit(STATUS_FW_ERROR, &priv->status) <<
STATUS_FW_ERROR;
STATUS_FW_ERROR |
test_bit(STATUS_EXIT_PENDING, &priv->status) <<
STATUS_EXIT_PENDING;

spin_lock_irqsave(&priv->lock, flags);
iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
Expand Down Expand Up @@ -6008,11 +6012,12 @@ static int __iwl3945_up(struct iwl3945_priv *priv)
else {
set_bit(STATUS_RF_KILL_HW, &priv->status);
if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) {
iwl3945_rfkill_set_hw_state(priv);
IWL_WARNING("Radio disabled by HW RF Kill switch\n");
return -ENODEV;
}
}

iwl3945_rfkill_set_hw_state(priv);
iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF);

rc = iwl3945_hw_nic_init(priv);
Expand Down Expand Up @@ -6068,6 +6073,7 @@ static int __iwl3945_up(struct iwl3945_priv *priv)

set_bit(STATUS_EXIT_PENDING, &priv->status);
__iwl3945_down(priv);
clear_bit(STATUS_EXIT_PENDING, &priv->status);

/* tried to restart and config the device for as long as our
* patience could withstand */
Expand Down Expand Up @@ -6135,6 +6141,8 @@ static void iwl3945_bg_rf_kill(struct work_struct *work)
"Kill switch must be turned off for "
"wireless networking to work.\n");
}

iwl3945_rfkill_set_hw_state(priv);
mutex_unlock(&priv->mutex);
}

Expand Down Expand Up @@ -7412,37 +7420,6 @@ static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,

#endif /* CONFIG_IWL3945_DEBUG */

static ssize_t show_rf_kill(struct device *d,
struct device_attribute *attr, char *buf)
{
/*
* 0 - RF kill not enabled
* 1 - SW based RF kill active (sysfs)
* 2 - HW based RF kill active
* 3 - Both HW and SW based RF kill active
*/
struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
(test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);

return sprintf(buf, "%i\n", val);
}

static ssize_t store_rf_kill(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;

mutex_lock(&priv->mutex);
iwl3945_radio_kill_sw(priv, buf[0] == '1');
mutex_unlock(&priv->mutex);

return count;
}

static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);

static ssize_t show_temperature(struct device *d,
struct device_attribute *attr, char *buf)
{
Expand Down Expand Up @@ -7928,7 +7905,6 @@ static struct attribute *iwl3945_sysfs_entries[] = {
#endif
&dev_attr_power_level.attr,
&dev_attr_retry_rate.attr,
&dev_attr_rf_kill.attr,
&dev_attr_rs_window.attr,
&dev_attr_statistics.attr,
&dev_attr_status.attr,
Expand Down Expand Up @@ -8169,6 +8145,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
pci_save_state(pdev);
pci_disable_device(pdev);

err = iwl3945_rfkill_init(priv);
if (err)
IWL_ERROR("Unable to initialize RFKILL system. "
"Ignoring error: %d\n", err);

return 0;

out_free_geos:
Expand Down Expand Up @@ -8231,6 +8212,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)

sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);

iwl3945_rfkill_unregister(priv);
iwl3945_dealloc_ucode_pci(priv);

if (priv->rxq.bd)
Expand Down Expand Up @@ -8299,6 +8281,140 @@ static int iwl3945_pci_resume(struct pci_dev *pdev)

#endif /* CONFIG_PM */

/*************** RFKILL FUNCTIONS **********/
#ifdef CONFIG_IWLWIFI_RFKILL
/* software rf-kill from user */
static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
{
struct iwl3945_priv *priv = data;
int err = 0;

if (!priv->rfkill_mngr.rfkill)
return 0;

if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return 0;

IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state);
mutex_lock(&priv->mutex);

switch (state) {
case RFKILL_STATE_ON:
iwl3945_radio_kill_sw(priv, 0);
/* if HW rf-kill is set dont allow ON state */
if (iwl3945_is_rfkill(priv))
err = -EBUSY;
break;
case RFKILL_STATE_OFF:
iwl3945_radio_kill_sw(priv, 1);
if (!iwl3945_is_rfkill(priv))
err = -EBUSY;
break;
}
mutex_unlock(&priv->mutex);

return err;
}

int iwl3945_rfkill_init(struct iwl3945_priv *priv)
{
struct device *device = wiphy_dev(priv->hw->wiphy);
int ret = 0;

BUG_ON(device == NULL);

IWL_DEBUG_RF_KILL("Initializing RFKILL.\n");
priv->rfkill_mngr.rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
if (!priv->rfkill_mngr.rfkill) {
IWL_ERROR("Unable to allocate rfkill device.\n");
ret = -ENOMEM;
goto error;
}

priv->rfkill_mngr.rfkill->name = priv->cfg->name;
priv->rfkill_mngr.rfkill->data = priv;
priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON;
priv->rfkill_mngr.rfkill->toggle_radio = iwl3945_rfkill_soft_rf_kill;
priv->rfkill_mngr.rfkill->user_claim_unsupported = 1;

priv->rfkill_mngr.rfkill->dev.class->suspend = NULL;
priv->rfkill_mngr.rfkill->dev.class->resume = NULL;

priv->rfkill_mngr.input_dev = input_allocate_device();
if (!priv->rfkill_mngr.input_dev) {
IWL_ERROR("Unable to allocate rfkill input device.\n");
ret = -ENOMEM;
goto freed_rfkill;
}

priv->rfkill_mngr.input_dev->name = priv->cfg->name;
priv->rfkill_mngr.input_dev->phys = wiphy_name(priv->hw->wiphy);
priv->rfkill_mngr.input_dev->id.bustype = BUS_HOST;
priv->rfkill_mngr.input_dev->id.vendor = priv->pci_dev->vendor;
priv->rfkill_mngr.input_dev->dev.parent = device;
priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY);
set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit);

ret = rfkill_register(priv->rfkill_mngr.rfkill);
if (ret) {
IWL_ERROR("Unable to register rfkill: %d\n", ret);
goto free_input_dev;
}

ret = input_register_device(priv->rfkill_mngr.input_dev);
if (ret) {
IWL_ERROR("Unable to register rfkill input device: %d\n", ret);
goto unregister_rfkill;
}

IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n");
return ret;

unregister_rfkill:
rfkill_unregister(priv->rfkill_mngr.rfkill);
priv->rfkill_mngr.rfkill = NULL;

free_input_dev:
input_free_device(priv->rfkill_mngr.input_dev);
priv->rfkill_mngr.input_dev = NULL;

freed_rfkill:
if (priv->rfkill_mngr.rfkill != NULL)
rfkill_free(priv->rfkill_mngr.rfkill);
priv->rfkill_mngr.rfkill = NULL;

error:
IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n");
return ret;
}

void iwl3945_rfkill_unregister(struct iwl3945_priv *priv)
{

if (priv->rfkill_mngr.input_dev)
input_unregister_device(priv->rfkill_mngr.input_dev);

if (priv->rfkill_mngr.rfkill)
rfkill_unregister(priv->rfkill_mngr.rfkill);

priv->rfkill_mngr.input_dev = NULL;
priv->rfkill_mngr.rfkill = NULL;
}

/* set rf-kill to the right state. */
void iwl3945_rfkill_set_hw_state(struct iwl3945_priv *priv)
{

if (!priv->rfkill_mngr.rfkill)
return;

if (!iwl3945_is_rfkill(priv))
priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON;
else
priv->rfkill_mngr.rfkill->state = RFKILL_STATE_OFF;
}
#endif

/*****************************************************************************
*
* driver and module entry point
Expand Down

0 comments on commit ebef200

Please sign in to comment.