Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ebef2008 authored by Abhijeet Kolekar's avatar Abhijeet Kolekar Committed by John W. Linville
Browse files

iwlwifi : Patch adds rfkill subsystem for 3945



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: default avatarAdel Gadllah <adel.gadllah@gmail.com>
Signed-off-by: default avatarAbhijeet Kolekar <abhijeet.kolekar@intel.com>
Signed-off-by: default avatarZhu Yi <yi.zhu@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2ff75b78
Loading
Loading
Loading
Loading
+25 −0
Original line number Original line Diff line number Diff line
@@ -36,6 +36,10 @@
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <net/ieee80211_radiotap.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 */
/* Hardware specific file defines the PCI IDs table for that hardware module */
extern struct pci_device_id iwl3945_hw_card_ids[];
extern struct pci_device_id iwl3945_hw_card_ids[];


@@ -686,6 +690,23 @@ enum {


#endif
#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
#define IWL_MAX_NUM_QUEUES IWL39_MAX_NUM_QUEUES


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


#ifdef CONFIG_IWLWIFI_RFKILL
	struct iwl3945_rfkill_mngr rfkill_mngr;
#endif

#ifdef CONFIG_IWL3945_LEDS
#ifdef CONFIG_IWL3945_LEDS
	struct iwl3945_led led[IWL_LED_TRG_MAX];
	struct iwl3945_led led[IWL_LED_TRG_MAX];
	unsigned long last_blink_time;
	unsigned long last_blink_time;
+151 −35
Original line number Original line Diff line number Diff line
@@ -5921,7 +5921,9 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
			       test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
			       test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
					STATUS_GEO_CONFIGURED |
					STATUS_GEO_CONFIGURED |
			       test_bit(STATUS_IN_SUSPEND, &priv->status) <<
			       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;
		goto exit;
	}
	}


@@ -5936,7 +5938,9 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
			test_bit(STATUS_IN_SUSPEND, &priv->status) <<
			test_bit(STATUS_IN_SUSPEND, &priv->status) <<
				STATUS_IN_SUSPEND |
				STATUS_IN_SUSPEND |
			test_bit(STATUS_FW_ERROR, &priv->status) <<
			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);
	spin_lock_irqsave(&priv->lock, flags);
	iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
	iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
@@ -6008,11 +6012,12 @@ static int __iwl3945_up(struct iwl3945_priv *priv)
	else {
	else {
		set_bit(STATUS_RF_KILL_HW, &priv->status);
		set_bit(STATUS_RF_KILL_HW, &priv->status);
		if (!test_bit(STATUS_IN_SUSPEND, &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");
			IWL_WARNING("Radio disabled by HW RF Kill switch\n");
			return -ENODEV;
			return -ENODEV;
		}
		}
	}
	}

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


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


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


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

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


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


#endif /* CONFIG_IWL3945_DEBUG */
#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,
static ssize_t show_temperature(struct device *d,
				struct device_attribute *attr, char *buf)
				struct device_attribute *attr, char *buf)
{
{
@@ -7928,7 +7905,6 @@ static struct attribute *iwl3945_sysfs_entries[] = {
#endif
#endif
	&dev_attr_power_level.attr,
	&dev_attr_power_level.attr,
	&dev_attr_retry_rate.attr,
	&dev_attr_retry_rate.attr,
	&dev_attr_rf_kill.attr,
	&dev_attr_rs_window.attr,
	&dev_attr_rs_window.attr,
	&dev_attr_statistics.attr,
	&dev_attr_statistics.attr,
	&dev_attr_status.attr,
	&dev_attr_status.attr,
@@ -8169,6 +8145,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
	pci_save_state(pdev);
	pci_save_state(pdev);
	pci_disable_device(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;
	return 0;


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


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


	iwl3945_rfkill_unregister(priv);
	iwl3945_dealloc_ucode_pci(priv);
	iwl3945_dealloc_ucode_pci(priv);


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


#endif /* CONFIG_PM */
#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
 * driver and module entry point