From: "John W. Linville" <linville@tuxdriver.com>
To: netdev@vger.kernel.org
Subject: What's new in wireless-dev?
Date: Tue, 8 Aug 2006 19:41:28 -0400 [thread overview]
Message-ID: <20060808234123.GB20706@tuxdriver.com> (raw)
The following changes since commit d2970f6c700f2291c1a80b061ebcd6041d2f3f1e:
John W. Linville:
Merge branch 'from-linus'
are found in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-dev.git
Ivo van Doorn:
rt2x00 - pci request/release regions
rt2x00 - ieee80211_hw->config no longer requires scheduling
rt2x00 - optimize MAC reading & initialize perm_addr
rt2x00 - txpower limits
rt2x00 - misc fixes
rt2x00 - scan handlers
rfkill - Add rfkill driver to misc input devices
rfkill - rt2x00 should use rfkill
Jiri Benc:
d80211: fix wrong logical operations
d80211: more correct WE support on master interface
Jouni Malinen:
d80211: Fix RTS threshold use
d80211: Fix PS-Poll frame dropping
d80211: Fix PLCP header length comment
d80211: Send Layer 2 Update frames in kernel
d80211: Fix ieee80211_remove_tx_extra() if key not configured
d80211: Fix TKIP replay protection
Michael Wu:
d80211: Fix issues with QOS bitwise ops
adm8211: Use ieee80211_*_queue functions
d80211 drivers: Use IRQF_SHARED instead of SA_SHIRQ
drivers/input/misc/Kconfig | 15 +
drivers/input/misc/Makefile | 1
drivers/input/misc/rfkill.c | 210 ++++++++++++++++++++
drivers/net/wireless/d80211/adm8211/adm8211.c | 18 +-
drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c | 2
drivers/net/wireless/d80211/rt2x00/Kconfig | 24 +-
drivers/net/wireless/d80211/rt2x00/rt2400pci.c | 193 +++++++++---------
drivers/net/wireless/d80211/rt2x00/rt2400pci.h | 4
drivers/net/wireless/d80211/rt2x00/rt2500pci.c | 197 ++++++++++---------
drivers/net/wireless/d80211/rt2x00/rt2500pci.h | 4
drivers/net/wireless/d80211/rt2x00/rt2500usb.c | 99 +++------
drivers/net/wireless/d80211/rt2x00/rt2500usb.h | 4
drivers/net/wireless/d80211/rt2x00/rt2x00.h | 62 +++++-
drivers/net/wireless/d80211/rt2x00/rt2x00pci.h | 111 -----------
drivers/net/wireless/d80211/rt2x00/rt61pci.c | 200 +++++++++----------
drivers/net/wireless/d80211/rt2x00/rt61pci.h | 4
drivers/net/wireless/d80211/rt2x00/rt73usb.c | 92 +++------
drivers/net/wireless/d80211/rt2x00/rt73usb.h | 4
include/linux/input.h | 1
include/linux/rfkill.h | 98 +++++++++
net/d80211/ieee80211.c | 26 +-
net/d80211/ieee80211_i.h | 1
net/d80211/ieee80211_ioctl.c | 87 ++++++++
net/d80211/tkip.c | 1
net/d80211/wme.c | 4
net/d80211/wpa.c | 2
26 files changed, 868 insertions(+), 596 deletions(-)
create mode 100644 drivers/input/misc/rfkill.c
create mode 100644 include/linux/rfkill.h
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index a6dfc74..ac10c02 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -79,4 +79,19 @@ config HP_SDC_RTC
Say Y here if you want to support the built-in real time clock
of the HP SDC controller.
+config RFKILL
+ tristate "RF button support"
+ help
+ If you say yes here, the rfkill driver will be build
+ which allowed network devices to register their hardware
+ RF button which controls the radio state. This driver
+ will then create an input device for it.
+
+ When the input device is not used, the rfkill driver
+ will make sure that when the RF button is pressed the radio
+ is enabled or disabled accordingly. When the input device
+ has been opened by the user this radio control will be left
+ to the user, and rfkill will only send the RF button status
+ change to userspace.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 415c491..e788a1b 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
+obj-$(CONFIG_RFKILL) += rfkill.o
diff --git a/drivers/input/misc/rfkill.c b/drivers/input/misc/rfkill.c
new file mode 100644
index 0000000..7b78053
--- /dev/null
+++ b/drivers/input/misc/rfkill.c
@@ -0,0 +1,210 @@
+/*
+ Copyright (C) 2006 Ivo van Doorn
+
+ 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/rfkill.h>
+
+#include <asm/atomic.h>
+
+MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>");
+MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("RF button support");
+MODULE_LICENSE("GPL");
+
+/*
+ * List of all registered buttons.
+ */
+static struct list_head rfkill_list;
+static spinlock_t rfkill_list_lock;
+
+/*
+ * Polling timer, poll_delay and use count.
+ */
+static struct timer_list poll_timer;
+static atomic_t poll_required;
+
+static void rfkill_toggle_radio(int new_status)
+{
+ struct list_head *entry;
+ struct rfkill *rfkill;
+
+ /*
+ * Go through the list of all radio's to toggle the radio state.
+ */
+ list_for_each(entry, &rfkill_list) {
+ rfkill = list_entry(entry, struct rfkill, entry);
+
+ rfkill->current_status = new_status;
+
+ /*
+ * If the input_device has been opened
+ * all radio events should be send to user space.
+ */
+ if (rfkill->input_dev->users) {
+ input_report_key(rfkill->input_dev,
+ KEY_RFKILL, new_status);
+ input_sync(rfkill->input_dev);
+ continue;
+ }
+
+ /*
+ * If the hardware does not toggle the radio status automaticly,
+ * we should take care of it.
+ */
+ if (new_status && rfkill->enable_radio)
+ rfkill->enable_radio(rfkill->data);
+ else if (!new_status && rfkill->disable_radio)
+ rfkill->disable_radio(rfkill->data);
+ }
+}
+
+static void rfkill_poll_button(unsigned long data)
+{
+ struct list_head *entry;
+ struct rfkill *rfkill;
+ int status;
+
+ spin_lock(&rfkill_list_lock);
+
+ list_for_each(entry, &rfkill_list) {
+ rfkill = list_entry(entry, struct rfkill, entry);
+
+ if (!rfkill->poll)
+ continue;
+
+ status = !!rfkill->poll(rfkill->data);
+
+ if (status != rfkill->current_status) {
+ rfkill_toggle_radio(status);
+ break;
+ }
+ }
+
+ spin_unlock(&rfkill_list_lock);
+
+ /*
+ * Check if polling is still required.
+ */
+ if (atomic_read(&poll_required)) {
+ poll_timer.expires = jiffies + RFKILL_POLL_DELAY;
+ add_timer(&poll_timer);
+ }
+}
+
+void rfkill_button_event(struct rfkill *rfkill, int status)
+{
+ if (status != rfkill->current_status) {
+ spin_lock(&rfkill_list_lock);
+ rfkill_toggle_radio(status);
+ spin_unlock(&rfkill_list_lock);
+ }
+}
+EXPORT_SYMBOL(rfkill_button_event);
+
+int rfkill_add_device(struct rfkill *rfkill)
+{
+ int status;
+
+ /*
+ * Allocate, initialize and register input device.
+ */
+ rfkill->input_dev = input_allocate_device();
+ if (!rfkill->input_dev) {
+ printk(KERN_ERR "Failed to allocate input device %s.\n",
+ rfkill->dev_name);
+ return -ENOMEM;
+ }
+
+ rfkill->input_dev->name = "Radio button";
+ rfkill->input_dev->phys = rfkill->dev_name;
+ rfkill->input_dev->id.bustype = BUS_HOST;
+ set_bit(KEY_RFKILL, rfkill->input_dev->keybit);
+
+ status = input_register_device(rfkill->input_dev);
+ if (status) {
+ printk(KERN_ERR "Failed to register input device %s.\n",
+ rfkill->dev_name);
+ input_free_device(rfkill->input_dev);
+ return status;
+ }
+
+ INIT_LIST_HEAD(&rfkill->entry);
+
+ spin_lock(&rfkill_list_lock);
+ list_add(&rfkill->entry, &rfkill_list);
+ spin_unlock(&rfkill_list_lock);
+
+ /*
+ * If polling is required the poll_required counter should be
+ * increased. If it was previously 0 we should start the polling timer.
+ */
+ if (rfkill->poll) {
+ if (!atomic_read(&poll_required)) {
+ poll_timer.expires = jiffies + RFKILL_POLL_DELAY;
+ add_timer(&poll_timer);
+ }
+ atomic_inc(&poll_required);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(rfkill_add_device);
+
+void rfkill_del_device(struct rfkill *rfkill)
+{
+ spin_lock(&rfkill_list_lock);
+
+ /*
+ * Check if this button required polling and if this
+ * was the last button that required polling.
+ */
+ if (rfkill->poll && atomic_dec_and_test(&poll_required))
+ del_timer(&poll_timer);
+
+ list_del(&rfkill->entry);
+
+ spin_unlock(&rfkill_list_lock);
+}
+EXPORT_SYMBOL(rfkill_del_device);
+
+static int __init radiobtn_init(void)
+{
+ printk(KERN_INFO "Loading rfkill driver.\n");
+
+ INIT_LIST_HEAD(&rfkill_list);
+ spin_lock_init(&rfkill_list_lock);
+
+ init_timer(&poll_timer);
+ poll_timer.function = rfkill_poll_button;
+ poll_timer.data = 0;
+ atomic_set(&poll_required, 0);
+
+ return 0;
+}
+
+static void __exit radiobtn_exit(void)
+{
+ printk(KERN_INFO "Unloading rfkill driver.\n");
+}
+
+module_init(radiobtn_init);
+module_exit(radiobtn_exit);
diff --git a/drivers/net/wireless/d80211/adm8211/adm8211.c b/drivers/net/wireless/d80211/adm8211/adm8211.c
index 748eb26..dcabeab 100644
--- a/drivers/net/wireless/d80211/adm8211/adm8211.c
+++ b/drivers/net/wireless/d80211/adm8211/adm8211.c
@@ -452,7 +452,7 @@ static void adm8211_interrupt_tci(struct
}
if (priv->cur_tx - dirty_tx < priv->tx_ring_size - 2)
- netif_wake_queue(dev);
+ ieee80211_wake_queue(dev, 0);
priv->dirty_tx = dirty_tx;
spin_unlock(&priv->lock);
@@ -1627,7 +1627,7 @@ static int adm8211_open(struct net_devic
adm8211_rf_set_channel(dev, priv->channel);
retval = request_irq(dev->irq, &adm8211_interrupt,
- SA_SHIRQ, dev->name, dev);
+ IRQF_SHARED, dev->name, dev);
if (retval) {
printk(KERN_ERR "%s: failed to register IRQ handler\n",
dev->name);
@@ -1765,17 +1765,13 @@ static void adm8211_tx_raw(struct net_de
spin_lock_irqsave(&priv->lock, flags);
- if (priv->cur_tx - priv->dirty_tx < priv->tx_ring_size / 2)
+ if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size / 2)
flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS;
- else if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size / 2)
- flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS;
- else if (priv->cur_tx - priv->dirty_tx < priv->tx_ring_size - 2)
+ else
flag = TDES1_CONTROL_LS | TDES1_CONTROL_FS;
- else {
- flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS;
- printk(KERN_DEBUG "%s: Yikes, this shouldn't happen!\n", dev->name);
- netif_stop_queue(dev);
- }
+
+ if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size - 2)
+ ieee80211_stop_queue(dev, 0);
entry = priv->cur_tx % priv->tx_ring_size;
diff --git a/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c
index 59d137b..6366020 100644
--- a/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c
@@ -2295,7 +2295,7 @@ #ifdef CONFIG_BCM947XX
}
#endif
err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
- SA_SHIRQ, KBUILD_MODNAME, bcm);
+ IRQF_SHARED, KBUILD_MODNAME, bcm);
if (err)
printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
diff --git a/drivers/net/wireless/d80211/rt2x00/Kconfig b/drivers/net/wireless/d80211/rt2x00/Kconfig
index d9b97f1..9e91fd6 100644
--- a/drivers/net/wireless/d80211/rt2x00/Kconfig
+++ b/drivers/net/wireless/d80211/rt2x00/Kconfig
@@ -17,12 +17,12 @@ config RT2400PCI
config RT2400PCI_BUTTON
bool "Ralink rt2400 hardware button support"
- depends on RT2400PCI && X86
+ depends on RT2400PCI && RFKILL
---help---
In some notebooks the rt2400 chipset is integrated in the machine,
- with this option enabled the device will periodically poll the
- the status of this button and will send and ACPI event when
- the button has been pressed.
+ with this option enabled the driver will register itself to the
+ rfkill driver for periodical polling of the hardware button
+ status, and the correct handling of button press events.
config RT2400PCI_DEBUG
bool "Ralink rt2400 debug output"
@@ -40,12 +40,12 @@ config RT2500PCI
config RT2500PCI_BUTTON
bool "Ralink rt2500 hardware button support"
- depends on RT2500PCI && X86
+ depends on RT2500PCI && RFKILL
---help---
In some notebooks the rt2500 chipset is integrated in the machine,
- with this option enabled the device will periodically poll the
- the status of this button and will send and ACPI event when
- the button has been pressed.
+ with this option enabled the driver will register itself to the
+ rfkill driver for periodical polling of the hardware button
+ status, and the correct handling of button press events.
config RT2500PCI_DEBUG
bool "Ralink rt2500 debug output"
@@ -63,12 +63,12 @@ config RT61PCI
config RT61PCI_BUTTON
bool "Ralink rt61 hardware button support"
- depends on RT61PCI && X86
+ depends on RT61PCI && RFKILL
---help---
In some notebooks the rt61 chipset is integrated in the machine,
- with this option enabled the device will periodically poll the
- the status of this button and will send and ACPI event when
- the button has been pressed.
+ with this option enabled the driver will register itself to the
+ rfkill driver for periodical polling of the hardware button
+ status, and the correct handling of button press events.
config RT61PCI_DEBUG
bool "Ralink rt61 debug output"
diff --git a/drivers/net/wireless/d80211/rt2x00/rt2400pci.c b/drivers/net/wireless/d80211/rt2x00/rt2400pci.c
index 709cdbf..96bcdf4 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/d80211/rt2x00/rt2400pci.c
@@ -346,23 +346,6 @@ static void rt2x00_eeprom_multiread(cons
rt2x00_eeprom_read(rt2x00dev, word + i, data++);
}
-#ifdef CONFIG_RT2400PCI_BUTTON
-/*
- * Hardware button poll handler.
- */
-static void rt2400pci_button_poll(unsigned long data)
-{
- struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev*)data;
- u32 reg;
-
- rt2x00_register_read(rt2x00dev, GPIOCSR, ®);
- rt2x00pci_button_status(
- rt2x00dev, rt2x00_get_field32(reg, GPIOCSR_BIT0));
-}
-#else /* CONFIG_RT2400PCI_BUTTON */
-static void rt2400pci_button_poll(unsigned long data){}
-#endif /* CONFIG_RT2400PCI_BUTTON */
-
/*
* Ethtool handlers.
*/
@@ -434,8 +417,63 @@ #endif /* CONFIG_RT2400PCI_DEBUG */
.get_link = ethtool_op_get_link,
.get_eeprom_len = rt2400pci_get_eeprom_len,
.get_eeprom = rt2400pci_get_eeprom,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
+#ifdef CONFIG_RT2400PCI_BUTTON
+static int rt2400pci_button_poll(unsigned long data)
+{
+ struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev*)data;
+ u32 reg;
+
+ rt2x00_register_read(rt2x00dev, GPIOCSR, ®);
+ return rt2x00_get_field32(reg, GPIOCSR_BIT0);
+}
+
+static void rt2400pci_button_enable_radio(unsigned long data)
+{
+ rt2400pci_enable_radio((struct rt2x00_dev*)data);
+}
+
+static void rt2400pci_button_disable_radio(unsigned long data)
+{
+ rt2400pci_disable_radio((struct rt2x00_dev*)data);
+}
+
+static void rt2400pci_button_start(struct rt2x00_dev *rt2x00dev)
+{
+ struct rfkill *rfkill = &rt2x00dev->rfkill;
+
+ /*
+ * Only start the button polling when
+ * the hardware button is present.
+ */
+ if (!GET_FLAG(rt2x00dev, DEVICE_SUPPORT_HW_BUTTON))
+ return;
+
+ rfkill->dev_name = "rt2400pci";
+ rfkill->data = (unsigned long)rt2x00dev;
+ rfkill->poll = rt2400pci_button_poll;
+ rfkill->enable_radio = rt2400pci_button_enable_radio;
+ rfkill->disable_radio = rt2400pci_button_disable_radio;
+ rfkill->current_status = !!rt2400pci_button_poll(rfkill->data);
+
+ if (rfkill_add_device(rfkill))
+ ERROR("Failed to register button handler.\n");
+}
+
+static void rt2400pci_button_stop(struct rt2x00_dev *rt2x00dev)
+{
+ if (!GET_FLAG(rt2x00dev, DEVICE_SUPPORT_HW_BUTTON))
+ return;
+
+ rfkill_del_device(&rt2x00dev->rfkill);
+}
+#else /* CONFIG_RT2400PCI_BUTTON */
+static void rt2400pci_button_start(struct rt2x00_dev *rt2x00dev){}
+static void rt2400pci_button_stop(struct rt2x00_dev *rt2x00dev){}
+#endif /* CONFIG_RT2400PCI_BUTTON */
+
/*
* Configuration handlers.
*/
@@ -1356,7 +1394,7 @@ static int rt2400pci_initialize(struct r
* Register interrupt handler.
*/
if (request_irq(rt2x00dev_pci(rt2x00dev)->irq, rt2400pci_interrupt,
- SA_SHIRQ, net_dev->name, rt2x00dev)) {
+ IRQF_SHARED, net_dev->name, rt2x00dev)) {
ERROR("IRQ %d allocation failed.\n",
rt2x00dev_pci(rt2x00dev)->irq);
goto exit_fail;
@@ -1380,10 +1418,8 @@ static void rt2400pci_uninitialize(struc
/*
* Cancel scanning.
*/
- if (rt2x00dev->scan) {
- rt2x00dev->scan->status = SCANNING_CANCELLED;
- complete_all(&rt2x00dev->scan->completion);
- }
+ if (rt2x00dev->scan)
+ rt2x00_signal_scan(rt2x00dev->scan, SCANNING_CANCELLED);
/*
* Flush out all pending work.
@@ -1801,10 +1837,8 @@ static void rt2400pci_txdone(void *data)
if (rt2x00dev->scan &&
rt2x00_ring_empty(&rt2x00dev->ring[RING_TX]) &&
rt2x00_ring_empty(&rt2x00dev->ring[RING_ATIM]) &&
- rt2x00_ring_empty(&rt2x00dev->ring[RING_PRIO])) {
- rt2x00dev->scan->status = SCANNING_READY;
- complete(&rt2x00dev->scan->completion);
- }
+ rt2x00_ring_empty(&rt2x00dev->ring[RING_PRIO]))
+ rt2x00_signal_scan(rt2x00dev->scan, SCANNING_READY);
/*
* If the data ring was full before the txdone handler
@@ -2050,11 +2084,10 @@ static void rt2400pci_remove_interface(s
rt2400pci_disable_radio(rt2x00dev);
}
-static void rt2400pci_config_update(void *data)
+static int rt2400pci_config(struct net_device *net_dev,
+ struct ieee80211_conf *conf)
{
- struct rt2x00_dev *rt2x00dev = data;
- struct net_device *net_dev = pci_get_drvdata(rt2x00dev_pci(rt2x00dev));
- struct ieee80211_conf *conf = ieee80211_get_hw_conf(net_dev);
+ struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
u32 reg;
/*
@@ -2085,21 +2118,10 @@ static void rt2400pci_config_update(void
rt2x00_register_read(rt2x00dev, RXCSR0, ®);
rt2x00_set_field32(®, RXCSR0_DISABLE_RX, 0);
rt2x00_register_write(rt2x00dev, RXCSR0, reg);
- } else if (conf->radio_enabled) {
- if (rt2400pci_enable_radio(rt2x00dev))
- return;
- }
-}
-
-static int rt2400pci_config(struct net_device *net_dev,
- struct ieee80211_conf *conf)
-{
- struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
+ } else if (conf->radio_enabled)
+ return rt2400pci_enable_radio(rt2x00dev);
- /*
- * Queue work.
- */
- return !queue_work(rt2x00dev->workqueue, &rt2x00dev->config_work);
+ return 0;
}
static int rt2400pci_config_interface(struct net_device *net_dev, int if_id,
@@ -2164,14 +2186,7 @@ static void rt2400pci_scan(void *data)
* we need to wait untill all TX rings are empty to
* guarentee that all frames are send on the correct channel.
*/
- if (rt2x00dev->scan->status != SCANNING_READY)
- wait_for_completion(&rt2x00dev->scan->completion);
-
- /*
- * Check if this scan has been cancelled while
- * work was still scheduled.
- */
- if (rt2x00dev->scan->status == SCANNING_CANCELLED)
+ if (rt2x00_wait_scan(rt2x00dev->scan))
goto exit;
/*
@@ -2243,13 +2258,7 @@ static int rt2400pci_passive_scan(struct
/*
* Initialize Scanning structure.
*/
- init_completion(&rt2x00dev->scan->completion);
-
- memcpy(&rt2x00dev->scan->conf, conf, sizeof(*conf));
-
- rt2x00dev->scan->state = state;
-
- rt2x00dev->scan->status = 0;
+ rt2x00_start_scan(rt2x00dev->scan, conf, state);
/*
* Queue work.
@@ -2521,25 +2530,29 @@ static int rt2400pci_init_eeprom(struct
static int rt2400pci_init_mac(struct rt2x00_dev *rt2x00dev)
{
struct net_device *net_dev = pci_get_drvdata(rt2x00dev_pci(rt2x00dev));
- u32 reg[2] = { 0, 0 };
+ u8 reg[8];
if (GET_FLAG(rt2x00dev, DEVICE_INITIALIZED_MAC))
return 0;
- rt2x00_register_multiread(rt2x00dev, CSR3, ®[0], sizeof(reg));
+ /*
+ * Read MAC address from MAC register.
+ */
+ rt2x00_register_multiread(rt2x00dev, CSR3, (u32*)®[0], 6);
- net_dev->dev_addr[0] = rt2x00_get_field32(reg[0], CSR3_BYTE0);
- net_dev->dev_addr[1] = rt2x00_get_field32(reg[0], CSR3_BYTE1);
- net_dev->dev_addr[2] = rt2x00_get_field32(reg[0], CSR3_BYTE2);
- net_dev->dev_addr[3] = rt2x00_get_field32(reg[0], CSR3_BYTE3);
- net_dev->dev_addr[4] = rt2x00_get_field32(reg[1], CSR4_BYTE4);
- net_dev->dev_addr[5] = rt2x00_get_field32(reg[1], CSR4_BYTE5);
+ /*
+ * Check if a valid MAC address has been read.
+ */
+ if (!is_valid_ether_addr(®[0]))
+ return -EINVAL;
+ /*
+ * Copy to netdevice structure.
+ */
+ memcpy(&net_dev->dev_addr[0], ®[0], 6);
+ memcpy(&net_dev->perm_addr[0], ®[0], 6);
net_dev->addr_len = 6;
- if (!is_valid_ether_addr(&net_dev->dev_addr[0]))
- return -EINVAL;
-
SET_FLAG(rt2x00dev, DEVICE_INITIALIZED_MAC);
return 0;
}
@@ -2738,7 +2751,7 @@ static void rt2400pci_free_dev(struct ne
/*
* Shutdown poll_timer for hardware button.
*/
- rt2x00pci_button_stop(rt2x00dev);
+ rt2400pci_button_stop(rt2x00dev);
/*
* Free ring structures.
@@ -2798,11 +2811,6 @@ static int rt2400pci_alloc_dev(struct pc
goto exit;
/*
- * Initialize cofniguration work.
- */
- INIT_WORK(&rt2x00dev->config_work, rt2400pci_config_update, rt2x00dev);
-
- /*
* Reset current working type.
*/
rt2x00dev->interface.type = -EINVAL;
@@ -2832,7 +2840,7 @@ static int rt2400pci_alloc_dev(struct pc
/*
* If required start hardware button polling.
*/
- rt2x00pci_button_start(rt2x00dev, rt2400pci_button_poll);
+ rt2400pci_button_start(rt2x00dev);
return 0;
@@ -2851,10 +2859,16 @@ static int rt2400pci_probe(struct pci_de
struct net_device *net_dev;
int status;
+ status = pci_request_regions(pci_dev, pci_name(pci_dev));
+ if (status) {
+ ERROR("PCI request regions failed.\n");
+ return status;
+ }
+
status = pci_enable_device(pci_dev);
if (status) {
ERROR("Enable device failed.\n");
- return status;
+ goto exit_release_regions;
}
pci_set_master(pci_dev);
@@ -2869,17 +2883,11 @@ static int rt2400pci_probe(struct pci_de
goto exit_disable_device;
}
- status = pci_request_regions(pci_dev, pci_name(pci_dev));
- if (status) {
- ERROR("PCI request regions failed.\n");
- goto exit_disable_device;
- }
-
net_dev = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), NULL);
if (!net_dev) {
ERROR("Failed to allocate hardware.\n");
status = -ENOMEM;
- goto exit_release_regions;
+ goto exit_disable_device;
}
SET_ETHTOOL_OPS(net_dev, &rt2400pci_ethtool_ops);
@@ -2898,13 +2906,13 @@ static int rt2400pci_probe(struct pci_de
exit_free_device:
ieee80211_free_hw(net_dev);
-exit_release_regions:
- pci_release_regions(pci_dev);
-
exit_disable_device:
if (status != -EBUSY)
pci_disable_device(pci_dev);
+exit_release_regions:
+ pci_release_regions(pci_dev);
+
pci_set_drvdata(pci_dev, NULL);
return status;
@@ -2927,9 +2935,9 @@ static void rt2400pci_remove(struct pci_
pci_set_drvdata(pci_dev, NULL);
- pci_release_regions(pci_dev);
-
pci_disable_device(pci_dev);
+
+ pci_release_regions(pci_dev);
}
#ifdef CONFIG_PM
@@ -3024,11 +3032,6 @@ module_param_named(debug, rt2x00_debug_l
MODULE_PARM_DESC(debug, "Set this parameter to 1 to enable debug output.");
#endif /* CONFIG_RT2400PCI_DEBUG */
-#ifdef CONFIG_RT2400PCI_BUTTON
-module_param_named(poll_delay, rt2x00_poll_delay, short, S_IRUGO);
-MODULE_PARM_DESC(debug, "Delay between WiFi button pollings (in 100ms).");
-#endif /* CONFIG_RT2400PCI_BUTTON */
-
static struct pci_driver rt2400pci_driver = {
.name = DRV_NAME,
.id_table = rt2400pci_device_table,
diff --git a/drivers/net/wireless/d80211/rt2x00/rt2400pci.h b/drivers/net/wireless/d80211/rt2x00/rt2400pci.h
index b592eef..ae0ea54 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/d80211/rt2x00/rt2400pci.h
@@ -881,8 +881,8 @@ #define TXPOWER_FROM_DEV(__txpower) \
#define TXPOWER_TO_DEV(__txpower) \
({ \
(__txpower) += MIN_TXPOWER; \
- ((__txpower) < MIN_TXPOWER) ? MAX_TXPOWER : \
- (((__txpower) > MAX_TXPOWER) ? MIN_TXPOWER : \
+ ((__txpower) <= MIN_TXPOWER) ? MAX_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MIN_TXPOWER : \
(MAX_TXPOWER - ((__txpower) - MIN_TXPOWER))); \
})
diff --git a/drivers/net/wireless/d80211/rt2x00/rt2500pci.c b/drivers/net/wireless/d80211/rt2x00/rt2500pci.c
index 8a22968..20095aa 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/d80211/rt2x00/rt2500pci.c
@@ -346,23 +346,6 @@ static void rt2x00_eeprom_multiread(cons
rt2x00_eeprom_read(rt2x00dev, word + i, data++);
}
-#ifdef CONFIG_RT2500PCI_BUTTON
-/*
- * Hardware button poll handler.
- */
-static void rt2500pci_button_poll(unsigned long data)
-{
- struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev*)data;
- u32 reg;
-
- rt2x00_register_read(rt2x00dev, GPIOCSR, ®);
- rt2x00pci_button_status(
- rt2x00dev, rt2x00_get_field32(reg, GPIOCSR_BIT0));
-}
-#else /* CONFIG_RT2500PCI_BUTTON */
-static void rt2500pci_button_poll(unsigned long data){}
-#endif /* CONFIG_RT2500PCI_BUTTON */
-
/*
* Ethtool handlers.
*/
@@ -434,8 +417,63 @@ #endif /* CONFIG_RT2500PCI_DEBUG */
.get_link = ethtool_op_get_link,
.get_eeprom_len = rt2500pci_get_eeprom_len,
.get_eeprom = rt2500pci_get_eeprom,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
+#ifdef CONFIG_RT2500PCI_BUTTON
+static int rt2500pci_button_poll(unsigned long data)
+{
+ struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev*)data;
+ u32 reg;
+
+ rt2x00_register_read(rt2x00dev, GPIOCSR, ®);
+ return rt2x00_get_field32(reg, GPIOCSR_BIT0);
+}
+
+static void rt2500pci_button_enable_radio(unsigned long data)
+{
+ rt2500pci_enable_radio((struct rt2x00_dev*)data);
+}
+
+static void rt2500pci_button_disable_radio(unsigned long data)
+{
+ rt2500pci_disable_radio((struct rt2x00_dev*)data);
+}
+
+static void rt2500pci_button_start(struct rt2x00_dev *rt2x00dev)
+{
+ struct rfkill *rfkill = &rt2x00dev->rfkill;
+
+ /*
+ * Only start the button polling when
+ * the hardware button is present.
+ */
+ if (!GET_FLAG(rt2x00dev, DEVICE_SUPPORT_HW_BUTTON))
+ return;
+
+ rfkill->dev_name = "rt2500pci";
+ rfkill->data = (unsigned long)rt2x00dev;
+ rfkill->poll = rt2500pci_button_poll;
+ rfkill->enable_radio = rt2500pci_button_enable_radio;
+ rfkill->disable_radio = rt2500pci_button_disable_radio;
+ rfkill->current_status = !!rt2500pci_button_poll(rfkill->data);
+
+ if (rfkill_add_device(rfkill))
+ ERROR("Failed to register button handler.\n");
+}
+
+static void rt2500pci_button_stop(struct rt2x00_dev *rt2x00dev)
+{
+ if (!GET_FLAG(rt2x00dev, DEVICE_SUPPORT_HW_BUTTON))
+ return;
+
+ rfkill_del_device(&rt2x00dev->rfkill);
+}
+#else /* CONFIG_RT2500PCI_BUTTON */
+static void rt2500pci_button_start(struct rt2x00_dev *rt2x00dev){}
+static void rt2500pci_button_stop(struct rt2x00_dev *rt2x00dev){}
+#endif /* CONFIG_RT2500PCI_BUTTON */
+
/*
* Configuration handlers.
*/
@@ -1476,7 +1514,7 @@ static int rt2500pci_initialize(struct r
* Register interrupt handler.
*/
if (request_irq(rt2x00dev_pci(rt2x00dev)->irq, rt2500pci_interrupt,
- SA_SHIRQ, net_dev->name, rt2x00dev)) {
+ IRQF_SHARED, net_dev->name, rt2x00dev)) {
ERROR("IRQ %d allocation failed.\n",
rt2x00dev_pci(rt2x00dev)->irq);
goto exit_fail;
@@ -1500,10 +1538,8 @@ static void rt2500pci_uninitialize(struc
/*
* Cancel scanning.
*/
- if (rt2x00dev->scan) {
- rt2x00dev->scan->status = SCANNING_CANCELLED;
- complete_all(&rt2x00dev->scan->completion);
- }
+ if (rt2x00dev->scan)
+ rt2x00_signal_scan(rt2x00dev->scan, SCANNING_CANCELLED);
/*
* Flush out all pending work.
@@ -1948,10 +1984,8 @@ static void rt2500pci_txdone(void *data)
if (rt2x00dev->scan &&
rt2x00_ring_empty(&rt2x00dev->ring[RING_TX]) &&
rt2x00_ring_empty(&rt2x00dev->ring[RING_ATIM]) &&
- rt2x00_ring_empty(&rt2x00dev->ring[RING_PRIO])) {
- rt2x00dev->scan->status = SCANNING_READY;
- complete(&rt2x00dev->scan->completion);
- }
+ rt2x00_ring_empty(&rt2x00dev->ring[RING_PRIO]))
+ rt2x00_signal_scan(rt2x00dev->scan, SCANNING_READY);
/*
* If the data ring was full before the txdone handler
@@ -2197,11 +2231,10 @@ static void rt2500pci_remove_interface(s
rt2500pci_disable_radio(rt2x00dev);
}
-static void rt2500pci_config_update(void *data)
+static int rt2500pci_config(struct net_device *net_dev,
+ struct ieee80211_conf *conf)
{
- struct rt2x00_dev *rt2x00dev = data;
- struct net_device *net_dev = pci_get_drvdata(rt2x00dev_pci(rt2x00dev));
- struct ieee80211_conf *conf = ieee80211_get_hw_conf(net_dev);
+ struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
u32 reg;
/*
@@ -2233,21 +2266,10 @@ static void rt2500pci_config_update(void
rt2x00_register_read(rt2x00dev, RXCSR0, ®);
rt2x00_set_field32(®, RXCSR0_DISABLE_RX, 0);
rt2x00_register_write(rt2x00dev, RXCSR0, reg);
- } else if (conf->radio_enabled) {
- if (rt2500pci_enable_radio(rt2x00dev))
- return;
- }
-}
-
-static int rt2500pci_config(struct net_device *net_dev,
- struct ieee80211_conf *conf)
-{
- struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
+ } else if (conf->radio_enabled)
+ return rt2500pci_enable_radio(rt2x00dev);
- /*
- * Queue work.
- */
- return !queue_work(rt2x00dev->workqueue, &rt2x00dev->config_work);
+ return 0;
}
static int rt2500pci_config_interface(struct net_device *net_dev, int if_id,
@@ -2312,14 +2334,7 @@ static void rt2500pci_scan(void *data)
* we need to wait untill all TX rings are empty to
* guarentee that all frames are send on the correct channel.
*/
- if (rt2x00dev->scan->status != SCANNING_READY)
- wait_for_completion(&rt2x00dev->scan->completion);
-
- /*
- * Check if this scan has been cancelled while
- * work was still scheduled.
- */
- if (rt2x00dev->scan->status == SCANNING_CANCELLED)
+ if (rt2x00_wait_scan(rt2x00dev->scan))
goto exit;
/*
@@ -2337,7 +2352,7 @@ static void rt2500pci_scan(void *data)
} else {
rt2500pci_config_phymode(rt2x00dev,
rt2x00dev->scan->conf.running_phymode);
-
+
rt2500pci_config_channel(rt2x00dev,
rt2x00dev->scan->conf.running_channel_val,
rt2x00dev->scan->conf.running_channel,
@@ -2387,13 +2402,7 @@ static int rt2500pci_passive_scan(struct
/*
* Initialize Scanning structure.
*/
- init_completion(&rt2x00dev->scan->completion);
-
- memcpy(&rt2x00dev->scan->conf, conf, sizeof(*conf));
-
- rt2x00dev->scan->state = state;
-
- rt2x00dev->scan->status = 0;
+ rt2x00_start_scan(rt2x00dev->scan, conf, state);
/*
* Queue work.
@@ -2673,25 +2682,29 @@ static int rt2500pci_init_eeprom(struct
static int rt2500pci_init_mac(struct rt2x00_dev *rt2x00dev)
{
struct net_device *net_dev = pci_get_drvdata(rt2x00dev_pci(rt2x00dev));
- u32 reg[2] = { 0, 0 };
+ u8 reg[8];
if (GET_FLAG(rt2x00dev, DEVICE_INITIALIZED_MAC))
return 0;
- rt2x00_register_multiread(rt2x00dev, CSR3, ®[0], sizeof(reg));
+ /*
+ * Read MAC address from MAC register.
+ */
+ rt2x00_register_multiread(rt2x00dev, CSR3, (u32*)®[0], 6);
- net_dev->dev_addr[0] = rt2x00_get_field32(reg[0], CSR3_BYTE0);
- net_dev->dev_addr[1] = rt2x00_get_field32(reg[0], CSR3_BYTE1);
- net_dev->dev_addr[2] = rt2x00_get_field32(reg[0], CSR3_BYTE2);
- net_dev->dev_addr[3] = rt2x00_get_field32(reg[0], CSR3_BYTE3);
- net_dev->dev_addr[4] = rt2x00_get_field32(reg[1], CSR4_BYTE4);
- net_dev->dev_addr[5] = rt2x00_get_field32(reg[1], CSR4_BYTE5);
+ /*
+ * Check if a valid MAC address has been read.
+ */
+ if (!is_valid_ether_addr(®[0]))
+ return -EINVAL;
+ /*
+ * Copy to netdevice structure.
+ */
+ memcpy(&net_dev->dev_addr[0], ®[0], 6);
+ memcpy(&net_dev->perm_addr[0], ®[0], 6);
net_dev->addr_len = 6;
- if (!is_valid_ether_addr(&net_dev->dev_addr[0]))
- return -EINVAL;
-
SET_FLAG(rt2x00dev, DEVICE_INITIALIZED_MAC);
return 0;
}
@@ -2866,7 +2879,7 @@ static void rt2500pci_init_hw_channels(s
};
struct ieee80211_channel *chan = channels + 14;
-
+
for (i = 0; i < ARRAY_SIZE(vals); i++)
(chan++)->val = cpu_to_le32(vals[i]);
}
@@ -3021,7 +3034,7 @@ static void rt2500pci_free_dev(struct ne
/*
* Shutdown poll_timer for hardware button.
*/
- rt2x00pci_button_stop(rt2x00dev);
+ rt2500pci_button_stop(rt2x00dev);
/*
* Free ring structures.
@@ -3081,11 +3094,6 @@ static int rt2500pci_alloc_dev(struct pc
goto exit;
/*
- * Initialize cofniguration work.
- */
- INIT_WORK(&rt2x00dev->config_work, rt2500pci_config_update, rt2x00dev);
-
- /*
* Reset current working type.
*/
rt2x00dev->interface.type = -EINVAL;
@@ -3115,7 +3123,7 @@ static int rt2500pci_alloc_dev(struct pc
/*
* If required start hardware button polling.
*/
- rt2x00pci_button_start(rt2x00dev, rt2500pci_button_poll);
+ rt2500pci_button_start(rt2x00dev);
return 0;
@@ -3134,10 +3142,16 @@ static int rt2500pci_probe(struct pci_de
struct net_device *net_dev;
int status;
+ status = pci_request_regions(pci_dev, pci_name(pci_dev));
+ if (status) {
+ ERROR("PCI request regions failed.\n");
+ return status;
+ }
+
status = pci_enable_device(pci_dev);
if (status) {
ERROR("Enable device failed.\n");
- return status;
+ goto exit_release_regions;
}
pci_set_master(pci_dev);
@@ -3152,17 +3166,11 @@ static int rt2500pci_probe(struct pci_de
goto exit_disable_device;
}
- status = pci_request_regions(pci_dev, pci_name(pci_dev));
- if (status) {
- ERROR("PCI request regions failed.\n");
- goto exit_disable_device;
- }
-
net_dev = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), NULL);
if (!net_dev) {
ERROR("Failed to allocate hardware.\n");
status = -ENOMEM;
- goto exit_release_regions;
+ goto exit_disable_device;
}
SET_ETHTOOL_OPS(net_dev, &rt2500pci_ethtool_ops);
@@ -3181,13 +3189,13 @@ static int rt2500pci_probe(struct pci_de
exit_free_device:
ieee80211_free_hw(net_dev);
-exit_release_regions:
- pci_release_regions(pci_dev);
-
exit_disable_device:
if (status != -EBUSY)
pci_disable_device(pci_dev);
+exit_release_regions:
+ pci_release_regions(pci_dev);
+
pci_set_drvdata(pci_dev, NULL);
return status;
@@ -3210,9 +3218,9 @@ static void rt2500pci_remove(struct pci_
pci_set_drvdata(pci_dev, NULL);
- pci_release_regions(pci_dev);
-
pci_disable_device(pci_dev);
+
+ pci_release_regions(pci_dev);
}
#ifdef CONFIG_PM
@@ -3307,11 +3315,6 @@ module_param_named(debug, rt2x00_debug_l
MODULE_PARM_DESC(debug, "Set this parameter to 1 to enable debug output.");
#endif /* CONFIG_RT2500PCI_DEBUG */
-#ifdef CONFIG_RT2500PCI_BUTTON
-module_param_named(poll_delay, rt2x00_poll_delay, short, S_IRUGO);
-MODULE_PARM_DESC(debug, "Delay between WiFi button pollings (in 100ms).");
-#endif /* CONFIG_RT2500PCI_BUTTON */
-
static struct pci_driver rt2500pci_driver = {
.name = DRV_NAME,
.id_table = rt2500pci_device_table,
diff --git a/drivers/net/wireless/d80211/rt2x00/rt2500pci.h b/drivers/net/wireless/d80211/rt2x00/rt2500pci.h
index 671265b..8ef5ae5 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/d80211/rt2x00/rt2500pci.h
@@ -1142,8 +1142,8 @@ #define TXPOWER_FROM_DEV(__txpower) \
#define TXPOWER_TO_DEV(__txpower) \
({ \
- ((__txpower) < MIN_TXPOWER) ? MIN_TXPOWER : \
- (((__txpower) > MAX_TXPOWER) ? MAX_TXPOWER : \
+ ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
(__txpower)); \
})
diff --git a/drivers/net/wireless/d80211/rt2x00/rt2500usb.c b/drivers/net/wireless/d80211/rt2x00/rt2500usb.c
index d15a33e..383f4a9 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/d80211/rt2x00/rt2500usb.c
@@ -170,7 +170,8 @@ static void rt2x00_bbp_read(const struct
*value = 0xff;
}
-static void rt2x00_rf_write(const struct rt2x00_dev *rt2x00dev, const u32 value)
+static void rt2x00_rf_write(const struct rt2x00_dev *rt2x00dev,
+ const u32 value)
{
u16 reg;
unsigned int i;
@@ -284,6 +285,7 @@ #endif /* CONFIG_RT2500USB_DEBUG */
.get_link = ethtool_op_get_link,
.get_eeprom_len = rt2500usb_get_eeprom_len,
.get_eeprom = rt2500usb_get_eeprom,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
/*
@@ -1263,10 +1265,8 @@ static void rt2500usb_uninitialize(struc
/*
* Cancel scanning.
*/
- if (rt2x00dev->scan) {
- rt2x00dev->scan->status = SCANNING_CANCELLED;
- complete_all(&rt2x00dev->scan->completion);
- }
+ if (rt2x00dev->scan)
+ rt2x00_signal_scan(rt2x00dev->scan, SCANNING_CANCELLED);
/*
* Flush out all pending work.
@@ -1482,7 +1482,7 @@ static void rt2500usb_write_tx_desc(stru
else
rt2x00_set_field32(&txd->word0, TXD_W0_MORE_FRAG, 0);
- if ((ieee80211hdr->seq_ctrl & IEEE80211_SCTL_FRAG) == 0)
+ if ((le16_to_cpu(ieee80211hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) == 0)
rt2x00_set_field32(&txd->word0, TXD_W0_NEW_SEQ, 1);
else
rt2x00_set_field32(&txd->word0, TXD_W0_NEW_SEQ, 0);
@@ -1712,10 +1712,8 @@ static void rt2500usb_txdone(void *data)
if (rt2x00dev->scan &&
rt2x00_ring_empty(&rt2x00dev->ring[RING_TX]) &&
rt2x00_ring_empty(&rt2x00dev->ring[RING_ATIM]) &&
- rt2x00_ring_empty(&rt2x00dev->ring[RING_PRIO])) {
- rt2x00dev->scan->status = SCANNING_READY;
- complete(&rt2x00dev->scan->completion);
- }
+ rt2x00_ring_empty(&rt2x00dev->ring[RING_PRIO]))
+ rt2x00_signal_scan(rt2x00dev->scan, SCANNING_READY);
/*
* If the data ring was full before the txdone handler
@@ -1912,12 +1910,10 @@ static void rt2500usb_remove_interface(s
rt2500usb_disable_radio(rt2x00dev);
}
-static void rt2500usb_config_update(void *data)
+static int rt2500usb_config(struct net_device *net_dev,
+ struct ieee80211_conf *conf)
{
- struct rt2x00_dev *rt2x00dev = data;
- struct net_device *net_dev =
- usb_get_intfdata(rt2x00dev_usb(rt2x00dev));
- struct ieee80211_conf *conf = ieee80211_get_hw_conf(net_dev);
+ struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
u16 reg;
/*
@@ -1949,21 +1945,10 @@ static void rt2500usb_config_update(void
rt2x00_register_read(rt2x00dev, TXRX_CSR2, ®);
rt2x00_set_field16_nb(®, TXRX_CSR2_DISABLE_RX, 0);
rt2x00_register_write(rt2x00dev, TXRX_CSR2, reg);
- } else if (conf->radio_enabled) {
- if (rt2500usb_enable_radio(rt2x00dev))
- return;
- }
-}
-
-static int rt2500usb_config(struct net_device *net_dev,
- struct ieee80211_conf *conf)
-{
- struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
+ } else if (conf->radio_enabled)
+ return rt2500usb_enable_radio(rt2x00dev);
- /*
- * Queue work.
- */
- return !queue_work(rt2x00dev->workqueue, &rt2x00dev->config_work);
+ return 0;
}
static void rt2500usb_interface_update(void *data)
@@ -2038,14 +2023,7 @@ static void rt2500usb_scan(void *data)
* we need to wait untill all TX rings are empty to
* guarentee that all frames are send on the correct channel.
*/
- if (rt2x00dev->scan->status != SCANNING_READY)
- wait_for_completion(&rt2x00dev->scan->completion);
-
- /*
- * Check if this scan has been cancelled while
- * work was still scheduled.
- */
- if (rt2x00dev->scan->status == SCANNING_CANCELLED)
+ if (rt2x00_wait_scan(rt2x00dev->scan))
goto exit;
/*
@@ -2054,7 +2032,7 @@ static void rt2500usb_scan(void *data)
if (rt2x00dev->scan->state == IEEE80211_SCAN_START) {
rt2500usb_config_phymode(rt2x00dev,
rt2x00dev->scan->conf.scan_phymode);
-
+
rt2500usb_config_channel(rt2x00dev,
rt2x00dev->scan->conf.scan_channel_val,
rt2x00dev->scan->conf.scan_channel,
@@ -2063,7 +2041,7 @@ static void rt2500usb_scan(void *data)
} else {
rt2500usb_config_phymode(rt2x00dev,
rt2x00dev->scan->conf.running_phymode);
-
+
rt2500usb_config_channel(rt2x00dev,
rt2x00dev->scan->conf.running_channel_val,
rt2x00dev->scan->conf.running_channel,
@@ -2113,13 +2091,7 @@ static int rt2500usb_passive_scan(struct
/*
* Initialize Scanning structure.
*/
- init_completion(&rt2x00dev->scan->completion);
-
- memcpy(&rt2x00dev->scan->conf, conf, sizeof(*conf));
-
- rt2x00dev->scan->state = state;
-
- rt2x00dev->scan->status = 0;
+ rt2x00_start_scan(rt2x00dev->scan, conf, state);
/*
* Queue work.
@@ -2345,7 +2317,7 @@ static int rt2500usb_init_mac(struct rt2
{
struct net_device *net_dev =
usb_get_intfdata(rt2x00dev_usb(rt2x00dev));
- u16 eeprom[3] = { 0, 0, 0 };
+ u8 eeprom[6];
if (GET_FLAG(rt2x00dev, DEVICE_INITIALIZED_MAC))
return 0;
@@ -2353,26 +2325,22 @@ static int rt2500usb_init_mac(struct rt2
/*
* Read MAC address from EEPROM.
*/
- rt2x00_eeprom_multiread(rt2x00dev, EEPROM_MAC_ADDR, &eeprom[0], 6);
-
- net_dev->dev_addr[0] = rt2x00_get_field16(eeprom[0],
- EEPROM_MAC_ADDR_BYTE0);
- net_dev->dev_addr[1] = rt2x00_get_field16(eeprom[0],
- EEPROM_MAC_ADDR_BYTE1);
- net_dev->dev_addr[2] = rt2x00_get_field16(eeprom[1],
- EEPROM_MAC_ADDR_BYTE2);
- net_dev->dev_addr[3] = rt2x00_get_field16(eeprom[1],
- EEPROM_MAC_ADDR_BYTE3);
- net_dev->dev_addr[4] = rt2x00_get_field16(eeprom[2],
- EEPROM_MAC_ADDR_BYTE4);
- net_dev->dev_addr[5] = rt2x00_get_field16(eeprom[2],
- EEPROM_MAC_ADDR_BYTE5);
-
- net_dev->addr_len = 6;
+ rt2x00_eeprom_multiread(rt2x00dev, EEPROM_MAC_ADDR,
+ (u16*)&eeprom[0], 6);
- if (!is_valid_ether_addr(&net_dev->dev_addr[0]))
+ /*
+ * Check if a valid MAC address has been read.
+ */
+ if (!is_valid_ether_addr(&eeprom[0]))
return -EINVAL;
+ /*
+ * Copy to netdevice structure.
+ */
+ memcpy(&net_dev->dev_addr[0], &eeprom[0], 6);
+ memcpy(&net_dev->perm_addr[0], &eeprom[0], 6);
+ net_dev->addr_len = 6;
+
SET_FLAG(rt2x00dev, DEVICE_INITIALIZED_MAC);
return 0;
}
@@ -2738,9 +2706,8 @@ static int rt2500usb_alloc_dev(struct us
return -ENODEV;
/*
- * Initialize cofniguration work.
+ * Initialize configuration work.
*/
- INIT_WORK(&rt2x00dev->config_work, rt2500usb_config_update, rt2x00dev);
INIT_WORK(&rt2x00dev->interface.work,
rt2500usb_interface_update, rt2x00dev);
diff --git a/drivers/net/wireless/d80211/rt2x00/rt2500usb.h b/drivers/net/wireless/d80211/rt2x00/rt2500usb.h
index 42d44aa..917ba4c 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/d80211/rt2x00/rt2500usb.h
@@ -679,8 +679,8 @@ #define TXPOWER_FROM_DEV(__txpower) \
#define TXPOWER_TO_DEV(__txpower) \
({ \
- ((__txpower) < MIN_TXPOWER) ? MIN_TXPOWER : \
- (((__txpower) > MAX_TXPOWER) ? MAX_TXPOWER : \
+ ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
(__txpower)); \
})
diff --git a/drivers/net/wireless/d80211/rt2x00/rt2x00.h b/drivers/net/wireless/d80211/rt2x00/rt2x00.h
index 06fa2be..eb56aea 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/d80211/rt2x00/rt2x00.h
@@ -82,6 +82,16 @@ #define DEBUG(__message, __args...) \
__FUNCTION__, ##__args);
/*
+ * Hardware button support (through radiobtn)
+ * The delay between each poll can be set by the user
+ * using the module parameter. Default value is 0,
+ * which means polling is disabled.
+ */
+#ifdef CONFIG_RT2X00_BUTTON
+#include <linux/rfkill.h>
+#endif /* CONFIG_RT2X00_BUTTON */
+
+/*
* Ring sizes.
* Ralink PCI devices demand the Frame size to be a multiple of 128 bytes.
* DATA_FRAME_SIZE is used for TX, RX, ATIM and PRIO rings.
@@ -734,7 +744,8 @@ struct scanning {
* Flag to see if this scan has been cancelled.
*/
short status;
-#define SCANNING_READY 0x0001
+#define SCANNING_READY 0x0000
+#define SCANNING_WAITING 0x0001
#define SCANNING_CANCELLED 0x0002
/*
@@ -743,6 +754,48 @@ #define SCANNING_CANCELLED 0x0002
struct work_struct work;
};
+static inline void rt2x00_start_scan(struct scanning *scan,
+ struct ieee80211_scan_conf *conf, int state)
+{
+ init_completion(&scan->completion);
+
+ memcpy(&scan->conf, conf, sizeof(*conf));
+
+ scan->state = state;
+
+ /*
+ * Set initial status to SCANNING_WAITING to prevent scanning
+ * to begin while there are still TX packets queued.
+ */
+ scan->status = SCANNING_WAITING;
+}
+
+static inline void rt2x00_signal_scan(struct scanning *scan, short status)
+{
+ scan->status = status;
+
+ complete_all(&scan->completion);
+}
+
+static inline int rt2x00_wait_scan(struct scanning *scan)
+{
+ /*
+ * Only wait for completion when the status
+ * indicates we should. The SCANNING_READY
+ * and SCANNING_CANCELLED are both states
+ * which indicate complete_all has already
+ * been called.
+ */
+ if (scan->status == SCANNING_WAITING)
+ wait_for_completion(&scan->completion);
+
+ /*
+ * Status field will have been updated by the handler
+ * that has called complete_all() on our complete structure.
+ */
+ return scan->status;
+}
+
/*
* rt2x00 device structure.
*/
@@ -751,7 +804,7 @@ struct rt2x00_dev {
* Device structure.
* The structure stored in here depends on the
* system bus (PCI or USB).
- * When accessing this variable, the rt2x00{pci,usb}_dev
+ * When accessing this variable, the rt2x00dev_{pci,usb}
* macro's should be used for correct typecasting.
*/
void *dev;
@@ -873,11 +926,6 @@ #endif /* CONFIG_RT2X00_BUTTON */
struct ieee80211_rx_status rx_params;
/*
- * work structure for configuration changes.
- */
- struct work_struct config_work;
-
- /*
* Scanning structure.
*/
struct scanning *scan;
diff --git a/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h b/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h
index fe6f833..bd39395 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h
@@ -44,115 +44,4 @@ #define EEPROM_WIDTH_93C66 8
#define EEPROM_WRITE_OPCODE 0x05
#define EEPROM_READ_OPCODE 0x06
-/*
- * HW button structure.
- */
-#ifdef CONFIG_RT2X00_BUTTON
-#include <acpi/acpi_bus.h>
-
-struct rt2x00_button {
- /*
- * ACPI device for generation of ACPI events.
- */
- struct acpi_device acpi_dev;
-
- /*
- * Timer for register polling.
- */
- struct timer_list poll_timer;
-
- /*
- * Timer delay.
- */
- short poll_delay;
-
- /*
- * Current status of button.
- */
- short button_status:1;
- short active_poll:1;
- short __pad:14;
-};
-#endif /* CONFIG_RT2X00_BUTTON */
-
-/*
- * HW button variables & functions.
- * The delay between each poll is set by the module parameter.
- */
-#ifdef CONFIG_RT2X00_BUTTON
-/*
- * Module parameter.
- */
-static short rt2x00_poll_delay = 0;
-
-static inline void rt2x00pci_button_status(struct rt2x00_dev *rt2x00dev,
- char status)
-{
- struct rt2x00_button *button = &rt2x00dev->button;
-
- if (!button->active_poll)
- return;
-
- if (status != button->button_status) {
- button->button_status = status;
- acpi_bus_generate_event(
- &button->acpi_dev, ACPI_TYPE_EVENT, status);
- }
-
- button->poll_timer.expires = jiffies + button->poll_delay;
-
- if (button->active_poll)
- add_timer(&button->poll_timer);
-}
-
-static inline void rt2x00pci_button_start(struct rt2x00_dev *rt2x00dev,
- void (*handler)(unsigned long data))
-{
- struct rt2x00_button *button = &rt2x00dev->button;
-
- /*
- * Only enable polling when the user has
- * set the poll delay module parameter,
- * and the device contains a hardware button.
- */
- if(!GET_FLAG(rt2x00dev, DEVICE_SUPPORT_HW_BUTTON) ||
- !rt2x00_poll_delay)
- return;
-
- strcpy(acpi_device_class(&button->acpi_dev), DRV_NAME "_button");
- strcpy(acpi_device_bid(&button->acpi_dev), DRV_NAME);
- strcpy(acpi_device_name(&button->acpi_dev), DRV_NAME);
-
- init_timer(&button->poll_timer);
-
- button->poll_delay = rt2x00_poll_delay * (HZ / 10);
- button->button_status = 0;
- button->active_poll = 1;
-
- button->poll_timer.function = handler;
- button->poll_timer.data = (unsigned long)rt2x00dev;
- button->poll_timer.expires = jiffies + button->poll_delay;
-
- add_timer(&button->poll_timer);
-}
-
-static inline void rt2x00pci_button_stop(struct rt2x00_dev *rt2x00dev)
-{
- /*
- * Shutdown poll_timer for hardware button,
- * make sure only to disable polling when
- * it was enabled in the first place.
- */
- if(!rt2x00dev->button.active_poll)
- return;
-
- rt2x00dev->button.active_poll = 0;
- del_timer_sync(&rt2x00dev->button.poll_timer);
-}
-#else /* CONFIG_RT2X00_BUTTON */
-static inline void rt2x00pci_button_start(struct rt2x00_dev *rt2x00dev,
- void (*handler)(unsigned long data)){}
-static inline void rt2x00pci_button_stop(struct rt2x00_dev *rt2x00dev){}
-#endif /* CONFIG_RT2X00_BUTTON */
-
#endif /* RT2X00PCI_H */
diff --git a/drivers/net/wireless/d80211/rt2x00/rt61pci.c b/drivers/net/wireless/d80211/rt2x00/rt61pci.c
index 8bb9de9..cc6789e 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/d80211/rt2x00/rt61pci.c
@@ -377,23 +377,6 @@ static void rt2x00_eeprom_multiread(cons
rt2x00_eeprom_read(rt2x00dev, word + i, data++);
}
-#ifdef CONFIG_RT61PCI_BUTTON
-/*
- * Hardware button poll handler.
- */
-static void rt61pci_button_poll(unsigned long data)
-{
- struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev*)data;
- u32 reg;
-
- rt2x00_register_read(rt2x00dev, MAC_CSR13, ®);
- rt2x00pci_button_status(
- rt2x00dev, rt2x00_get_field32(reg, MAC_CSR13_BIT5));
-}
-#else /* CONFIG_RT61PCI_BUTTON */
-static void rt61pci_button_poll(unsigned long data){}
-#endif /* CONFIG_RT61PCI_BUTTON */
-
/*
* Ethtool handlers.
*/
@@ -465,8 +448,63 @@ #endif /* CONFIG_RT61PCI_DEBUG */
.get_link = ethtool_op_get_link,
.get_eeprom_len = rt61pci_get_eeprom_len,
.get_eeprom = rt61pci_get_eeprom,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
+#ifdef CONFIG_RT61PCI_BUTTON
+static int rt61pci_button_poll(unsigned long data)
+{
+ struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev*)data;
+ u32 reg;
+
+ rt2x00_register_read(rt2x00dev, MAC_CSR13, ®);
+ return rt2x00_get_field32(reg, MAC_CSR13_BIT5);
+}
+
+static void rt61pci_button_enable_radio(unsigned long data)
+{
+ rt61pci_enable_radio((struct rt2x00_dev*)data);
+}
+
+static void rt61pci_button_disable_radio(unsigned long data)
+{
+ rt61pci_disable_radio((struct rt2x00_dev*)data);
+}
+
+static void rt61pci_button_start(struct rt2x00_dev *rt2x00dev)
+{
+ struct rfkill *rfkill = &rt2x00dev->rfkill;
+
+ /*
+ * Only start the button polling when
+ * the hardware button is present.
+ */
+ if (!GET_FLAG(rt2x00dev, DEVICE_SUPPORT_HW_BUTTON))
+ return;
+
+ rfkill->dev_name = "rt61pci";
+ rfkill->data = (unsigned long)rt2x00dev;
+ rfkill->poll = rt61pci_button_poll;
+ rfkill->enable_radio = rt61pci_button_enable_radio;
+ rfkill->disable_radio = rt61pci_button_disable_radio;
+ rfkill->current_status = !!rt61pci_button_poll(rfkill->data);
+
+ if (rfkill_add_device(rfkill))
+ ERROR("Failed to register button handler.\n");
+}
+
+static void rt61pci_button_stop(struct rt2x00_dev *rt2x00dev)
+{
+ if (!GET_FLAG(rt2x00dev, DEVICE_SUPPORT_HW_BUTTON))
+ return;
+
+ rfkill_del_device(&rt2x00dev->rfkill);
+}
+#else /* CONFIG_RT61PCI_BUTTON */
+static void rt61pci_button_start(struct rt2x00_dev *rt2x00dev){}
+static void rt61pci_button_stop(struct rt2x00_dev *rt2x00dev){}
+#endif /* CONFIG_RT61PCI_BUTTON */
+
/*
* Configuration handlers.
*/
@@ -1902,7 +1940,7 @@ static int rt61pci_initialize(struct rt2
* Register interrupt handler.
*/
if (request_irq(rt2x00dev_pci(rt2x00dev)->irq, rt61pci_interrupt,
- SA_SHIRQ, net_dev->name, rt2x00dev)) {
+ IRQF_SHARED, net_dev->name, rt2x00dev)) {
ERROR("IRQ %d allocation failed.\n",
rt2x00dev_pci(rt2x00dev)->irq);
goto exit_fail;
@@ -1926,10 +1964,8 @@ static void rt61pci_uninitialize(struct
/*
* Cancel scanning.
*/
- if (rt2x00dev->scan) {
- rt2x00dev->scan->status = SCANNING_CANCELLED;
- complete_all(&rt2x00dev->scan->completion);
- }
+ if (rt2x00dev->scan)
+ rt2x00_signal_scan(rt2x00dev->scan, SCANNING_CANCELLED);
/*
* Flush out all pending work.
@@ -2448,10 +2484,8 @@ static void rt61pci_txdone(void *data)
rt2x00_ring_empty(&rt2x00dev->ring[RING_AC_BE]) &&
rt2x00_ring_empty(&rt2x00dev->ring[RING_AC_VI]) &&
rt2x00_ring_empty(&rt2x00dev->ring[RING_AC_VO]) &&
- rt2x00_ring_empty(&rt2x00dev->ring[RING_PRIO])) {
- rt2x00dev->scan->status = SCANNING_READY;
- complete(&rt2x00dev->scan->completion);
- }
+ rt2x00_ring_empty(&rt2x00dev->ring[RING_PRIO]))
+ rt2x00_signal_scan(rt2x00dev->scan, SCANNING_READY);
}
static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance,
@@ -2675,11 +2709,10 @@ static void rt61pci_remove_interface(str
rt61pci_disable_radio(rt2x00dev);
}
-static void rt61pci_config_update(void *data)
+static int rt61pci_config(struct net_device *net_dev,
+ struct ieee80211_conf *conf)
{
- struct rt2x00_dev *rt2x00dev = data;
- struct net_device *net_dev = pci_get_drvdata(rt2x00dev_pci(rt2x00dev));
- struct ieee80211_conf *conf = ieee80211_get_hw_conf(net_dev);
+ struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
u32 reg;
/*
@@ -2711,21 +2744,10 @@ static void rt61pci_config_update(void *
rt2x00_register_read(rt2x00dev, TXRX_CSR0, ®);
rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0);
rt2x00_register_write(rt2x00dev, TXRX_CSR0, reg);
- } else if (conf->radio_enabled) {
- if (rt61pci_enable_radio(rt2x00dev))
- return;
- }
-}
-
-static int rt61pci_config(struct net_device *net_dev,
- struct ieee80211_conf *conf)
-{
- struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
+ } else if (conf->radio_enabled)
+ return rt61pci_enable_radio(rt2x00dev);
- /*
- * Queue work.
- */
- return !queue_work(rt2x00dev->workqueue, &rt2x00dev->config_work);
+ return 0;
}
static int rt61pci_config_interface(struct net_device *net_dev, int if_id,
@@ -2790,14 +2812,7 @@ static void rt61pci_scan(void *data)
* we need to wait untill all TX rings are empty to
* guarentee that all frames are send on the correct channel.
*/
- if (rt2x00dev->scan->status != SCANNING_READY)
- wait_for_completion(&rt2x00dev->scan->completion);
-
- /*
- * Check if this scan has been cancelled while
- * work was still scheduled.
- */
- if (rt2x00dev->scan->status == SCANNING_CANCELLED)
+ if (rt2x00_wait_scan(rt2x00dev->scan))
goto exit;
/*
@@ -2865,13 +2880,7 @@ static int rt61pci_passive_scan(struct n
/*
* Initialize Scanning structure.
*/
- init_completion(&rt2x00dev->scan->completion);
-
- memcpy(&rt2x00dev->scan->conf, conf, sizeof(*conf));
-
- rt2x00dev->scan->state = state;
-
- rt2x00dev->scan->status = 0;
+ rt2x00_start_scan(rt2x00dev->scan, conf, state);
/*
* Queue work.
@@ -3198,7 +3207,7 @@ static int rt61pci_init_eeprom(struct rt
static int rt61pci_init_mac(struct rt2x00_dev *rt2x00dev)
{
struct net_device *net_dev = pci_get_drvdata(rt2x00dev_pci(rt2x00dev));
- u16 eeprom[3] = { 0, 0, 0 };
+ u8 eeprom[6];
if (GET_FLAG(rt2x00dev, DEVICE_INITIALIZED_MAC))
return 0;
@@ -3206,26 +3215,22 @@ static int rt61pci_init_mac(struct rt2x0
/*
* Read MAC address from EEPROM.
*/
- rt2x00_eeprom_multiread(rt2x00dev, EEPROM_MAC_ADDR, &eeprom[0], 6);
-
- net_dev->dev_addr[0] = rt2x00_get_field16(eeprom[0],
- EEPROM_MAC_ADDR_BYTE0);
- net_dev->dev_addr[1] = rt2x00_get_field16(eeprom[0],
- EEPROM_MAC_ADDR_BYTE1);
- net_dev->dev_addr[2] = rt2x00_get_field16(eeprom[1],
- EEPROM_MAC_ADDR_BYTE2);
- net_dev->dev_addr[3] = rt2x00_get_field16(eeprom[1],
- EEPROM_MAC_ADDR_BYTE3);
- net_dev->dev_addr[4] = rt2x00_get_field16(eeprom[2],
- EEPROM_MAC_ADDR_BYTE4);
- net_dev->dev_addr[5] = rt2x00_get_field16(eeprom[2],
- EEPROM_MAC_ADDR_BYTE5);
+ rt2x00_eeprom_multiread(rt2x00dev, EEPROM_MAC_ADDR,
+ (u16*)&eeprom[0], 6);
- net_dev->addr_len = 6;
-
- if (!is_valid_ether_addr(&net_dev->dev_addr[0]))
+ /*
+ * Check if a valid MAC address has been read.
+ */
+ if (!is_valid_ether_addr(&eeprom[0]))
return -EINVAL;
+ /*
+ * Copy to netdevice structure.
+ */
+ memcpy(&net_dev->dev_addr[0], &eeprom[0], 6);
+ memcpy(&net_dev->perm_addr[0], &eeprom[0], 6);
+ net_dev->addr_len = 6;
+
SET_FLAG(rt2x00dev, DEVICE_INITIALIZED_MAC);
return 0;
}
@@ -3491,7 +3496,6 @@ static int rt61pci_init_hw_modes(struct
hw->modes[0].num_channels = 14;
hw->modes[0].num_rates = 12;
-
/*
* Intitialize 802.11b
* Rates: CCK.
@@ -3547,7 +3551,7 @@ static void rt61pci_free_dev(struct net_
/*
* Shutdown poll_timer for hardware button.
*/
- rt2x00pci_button_stop(rt2x00dev);
+ rt61pci_button_stop(rt2x00dev);
/*
* Free ring structures.
@@ -3607,11 +3611,6 @@ static int rt61pci_alloc_dev(struct pci_
goto exit;
/*
- * Initialize configuration work.
- */
- INIT_WORK(&rt2x00dev->config_work, rt61pci_config_update, rt2x00dev);
-
- /*
* Reset current working type.
*/
rt2x00dev->interface.type = -EINVAL;
@@ -3646,7 +3645,7 @@ static int rt61pci_alloc_dev(struct pci_
/*
* If required start hardware button polling.
*/
- rt2x00pci_button_start(rt2x00dev, rt61pci_button_poll);
+ rt61pci_button_start(rt2x00dev);
return 0;
@@ -3665,10 +3664,16 @@ static int rt61pci_probe(struct pci_dev
struct net_device *net_dev;
int status;
+ status = pci_request_regions(pci_dev, pci_name(pci_dev));
+ if (status) {
+ ERROR("PCI request regions failed.\n");
+ return status;
+ }
+
status = pci_enable_device(pci_dev);
if (status) {
ERROR("Enable device failed.\n");
- return status;
+ goto exit_release_regions;
}
pci_set_master(pci_dev);
@@ -3683,17 +3688,11 @@ static int rt61pci_probe(struct pci_dev
goto exit_disable_device;
}
- status = pci_request_regions(pci_dev, pci_name(pci_dev));
- if (status) {
- ERROR("PCI request regions failed.\n");
- goto exit_disable_device;
- }
-
net_dev = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), NULL);
if (!net_dev) {
ERROR("Failed to allocate hardware.\n");
status = -ENOMEM;
- goto exit_release_regions;
+ goto exit_disable_device;
}
SET_ETHTOOL_OPS(net_dev, &rt61pci_ethtool_ops);
@@ -3712,13 +3711,13 @@ static int rt61pci_probe(struct pci_dev
exit_free_device:
ieee80211_free_hw(net_dev);
-exit_release_regions:
- pci_release_regions(pci_dev);
-
exit_disable_device:
if (status != -EBUSY)
pci_disable_device(pci_dev);
+exit_release_regions:
+ pci_release_regions(pci_dev);
+
pci_set_drvdata(pci_dev, NULL);
return status;
@@ -3741,9 +3740,9 @@ static void rt61pci_remove(struct pci_de
pci_set_drvdata(pci_dev, NULL);
- pci_release_regions(pci_dev);
-
pci_disable_device(pci_dev);
+
+ pci_release_regions(pci_dev);
}
#ifdef CONFIG_PM
@@ -3844,11 +3843,6 @@ module_param_named(debug, rt2x00_debug_l
MODULE_PARM_DESC(debug, "Set this parameter to 1 to enable debug output.");
#endif /* CONFIG_RT61PCI_DEBUG */
-#ifdef CONFIG_RT61PCI_BUTTON
-module_param_named(poll_delay, rt2x00_poll_delay, short, S_IRUGO);
-MODULE_PARM_DESC(debug, "Delay between WiFi button pollings (in 100ms).");
-#endif /* CONFIG_RT61PCI_BUTTON */
-
static struct pci_driver rt61pci_driver = {
.name = DRV_NAME,
.id_table = rt61pci_device_table,
diff --git a/drivers/net/wireless/d80211/rt2x00/rt61pci.h b/drivers/net/wireless/d80211/rt2x00/rt61pci.h
index d334390..2c5065b 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/d80211/rt2x00/rt61pci.h
@@ -1360,8 +1360,8 @@ #define TXPOWER_FROM_DEV(__txpower) \
#define TXPOWER_TO_DEV(__txpower) \
({ \
- ((__txpower) < MIN_TXPOWER) ? MIN_TXPOWER : \
- (((__txpower) > MAX_TXPOWER) ? MAX_TXPOWER : \
+ ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
(__txpower)); \
})
diff --git a/drivers/net/wireless/d80211/rt2x00/rt73usb.c b/drivers/net/wireless/d80211/rt2x00/rt73usb.c
index acc5357..682d078 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/d80211/rt2x00/rt73usb.c
@@ -286,6 +286,7 @@ #endif /* CONFIG_RT2500USB_DEBUG */
.get_link = ethtool_op_get_link,
.get_eeprom_len = rt73usb_get_eeprom_len,
.get_eeprom = rt73usb_get_eeprom,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
/*
@@ -1524,10 +1525,8 @@ static void rt73usb_uninitialize(struct
/*
* Cancel scanning.
*/
- if (rt2x00dev->scan) {
- rt2x00dev->scan->status = SCANNING_CANCELLED;
- complete_all(&rt2x00dev->scan->completion);
- }
+ if (rt2x00dev->scan)
+ rt2x00_signal_scan(rt2x00dev->scan, SCANNING_CANCELLED);
/*
* Flush out all pending work.
@@ -1999,10 +1998,8 @@ static void rt73usb_txdone(void *data)
rt2x00_ring_empty(&rt2x00dev->ring[RING_AC_BE]) &&
rt2x00_ring_empty(&rt2x00dev->ring[RING_AC_VI]) &&
rt2x00_ring_empty(&rt2x00dev->ring[RING_AC_VO]) &&
- rt2x00_ring_empty(&rt2x00dev->ring[RING_PRIO])) {
- rt2x00dev->scan->status = SCANNING_READY;
- complete(&rt2x00dev->scan->completion);
- }
+ rt2x00_ring_empty(&rt2x00dev->ring[RING_PRIO]))
+ rt2x00_signal_scan(rt2x00dev->scan, SCANNING_READY);
/*
* If the data ring was full before the txdone handler
@@ -2127,6 +2124,7 @@ static int rt73usb_tx(struct net_device
static int rt73usb_reset(struct net_device *net_dev)
{
struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
+
rt73usb_disable_radio(rt2x00dev);
return rt73usb_enable_radio(rt2x00dev);
}
@@ -2195,12 +2193,10 @@ static void rt73usb_remove_interface(str
rt73usb_disable_radio(rt2x00dev);
}
-static void rt73usb_config_update(void *data)
+static int rt73usb_config(struct net_device *net_dev,
+ struct ieee80211_conf *conf)
{
- struct rt2x00_dev *rt2x00dev = data;
- struct net_device *net_dev =
- usb_get_intfdata(rt2x00dev_usb(rt2x00dev));
- struct ieee80211_conf *conf = ieee80211_get_hw_conf(net_dev);
+ struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
u32 reg;
/*
@@ -2232,21 +2228,10 @@ static void rt73usb_config_update(void *
rt2x00_register_read(rt2x00dev, TXRX_CSR0, ®);
rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0);
rt2x00_register_write(rt2x00dev, TXRX_CSR0, reg);
- } else if (conf->radio_enabled) {
- if (rt73usb_enable_radio(rt2x00dev))
- return;
- }
-}
-
-static int rt73usb_config(struct net_device *net_dev,
- struct ieee80211_conf *conf)
-{
- struct rt2x00_dev *rt2x00dev = ieee80211_dev_hw_data(net_dev);
+ } else if (conf->radio_enabled)
+ return rt73usb_enable_radio(rt2x00dev);
- /*
- * Queue work.
- */
- return !queue_work(rt2x00dev->workqueue, &rt2x00dev->config_work);
+ return 0;
}
static void rt73usb_interface_update(void *data)
@@ -2321,14 +2306,7 @@ static void rt73usb_scan(void *data)
* we need to wait untill all TX rings are empty to
* guarentee that all frames are send on the correct channel.
*/
- if (rt2x00dev->scan->status != SCANNING_READY)
- wait_for_completion(&rt2x00dev->scan->completion);
-
- /*
- * Check if this scan has been cancelled while
- * work was still scheduled.
- */
- if (rt2x00dev->scan->status == SCANNING_CANCELLED)
+ if (rt2x00_wait_scan(rt2x00dev->scan))
goto exit;
/*
@@ -2396,13 +2374,7 @@ static int rt73usb_passive_scan(struct n
/*
* Initialize Scanning structure.
*/
- init_completion(&rt2x00dev->scan->completion);
-
- memcpy(&rt2x00dev->scan->conf, conf, sizeof(*conf));
-
- rt2x00dev->scan->state = state;
-
- rt2x00dev->scan->status = 0;
+ rt2x00_start_scan(rt2x00dev->scan, conf, state);
/*
* Queue work.
@@ -2710,7 +2682,7 @@ static int rt73usb_init_mac(struct rt2x0
{
struct net_device *net_dev =
usb_get_intfdata(rt2x00dev_usb(rt2x00dev));
- u16 eeprom[3] = { 0, 0, 0 };
+ u8 eeprom[6];
if (GET_FLAG(rt2x00dev, DEVICE_INITIALIZED_MAC))
return 0;
@@ -2718,26 +2690,22 @@ static int rt73usb_init_mac(struct rt2x0
/*
* Read MAC address from EEPROM.
*/
- rt2x00_eeprom_multiread(rt2x00dev, EEPROM_MAC_ADDR, &eeprom[0], 6);
-
- net_dev->dev_addr[0] = rt2x00_get_field16(eeprom[0],
- EEPROM_MAC_ADDR_BYTE0);
- net_dev->dev_addr[1] = rt2x00_get_field16(eeprom[0],
- EEPROM_MAC_ADDR_BYTE1);
- net_dev->dev_addr[2] = rt2x00_get_field16(eeprom[1],
- EEPROM_MAC_ADDR_BYTE2);
- net_dev->dev_addr[3] = rt2x00_get_field16(eeprom[1],
- EEPROM_MAC_ADDR_BYTE3);
- net_dev->dev_addr[4] = rt2x00_get_field16(eeprom[2],
- EEPROM_MAC_ADDR_BYTE4);
- net_dev->dev_addr[5] = rt2x00_get_field16(eeprom[2],
- EEPROM_MAC_ADDR_BYTE5);
+ rt2x00_eeprom_multiread(rt2x00dev, EEPROM_MAC_ADDR,
+ (u16*)&eeprom[0], 6);
- net_dev->addr_len = 6;
-
- if (!is_valid_ether_addr(&net_dev->dev_addr[0]))
+ /*
+ * Check if a valid MAC address has been read.
+ */
+ if (!is_valid_ether_addr(&eeprom[0]))
return -EINVAL;
+ /*
+ * Copy to netdevice structure.
+ */
+ memcpy(&net_dev->dev_addr[0], &eeprom[0], 6);
+ memcpy(&net_dev->perm_addr[0], &eeprom[0], 6);
+ net_dev->addr_len = 6;
+
SET_FLAG(rt2x00dev, DEVICE_INITIALIZED_MAC);
return 0;
}
@@ -3000,7 +2968,6 @@ static int rt73usb_init_hw_modes(struct
hw->modes[0].num_channels = 14;
hw->modes[0].num_rates = 12;
-
/*
* Intitialize 802.11b
* Rates: CCK.
@@ -3095,9 +3062,8 @@ static int rt73usb_alloc_dev(struct usb_
return -ENODEV;
/*
- * Initialize cofniguration work.
+ * Initialize configuration work.
*/
- INIT_WORK(&rt2x00dev->config_work, rt73usb_config_update, rt2x00dev);
INIT_WORK(&rt2x00dev->interface.work,
rt73usb_interface_update, rt2x00dev);
diff --git a/drivers/net/wireless/d80211/rt2x00/rt73usb.h b/drivers/net/wireless/d80211/rt2x00/rt73usb.h
index 662ca30..5be5e14 100644
--- a/drivers/net/wireless/d80211/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/d80211/rt2x00/rt73usb.h
@@ -939,8 +939,8 @@ #define TXPOWER_FROM_DEV(__txpower) \
#define TXPOWER_TO_DEV(__txpower) \
({ \
- ((__txpower) < MIN_TXPOWER) ? MIN_TXPOWER : \
- (((__txpower) > MAX_TXPOWER) ? MAX_TXPOWER : \
+ ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
(__txpower)); \
})
diff --git a/include/linux/input.h b/include/linux/input.h
index b3253ab..f16da66 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -488,6 +488,7 @@ #define KEY_PREVIOUS 0x19c
#define KEY_DIGITS 0x19d
#define KEY_TEEN 0x19e
#define KEY_TWEN 0x19f
+#define KEY_RFKILL 0x1a0
#define KEY_DEL_EOL 0x1c0
#define KEY_DEL_EOS 0x1c1
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
new file mode 100644
index 0000000..2e1c740
--- /dev/null
+++ b/include/linux/rfkill.h
@@ -0,0 +1,98 @@
+/*
+ Copyright (C) 2006 Ivo van Doorn
+
+ 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ RF button support
+ Laptops are quite often equiped with a RF button to enable or
+ disable the radio of the network device attached to that button.
+ This network device usually is an integrated wireless network device,
+ or bluetooth device.
+ Some of these devices will disable the radio automaticly when the
+ RF button has been pressed, while other devices need to be polled
+ for the RF button status.
+ But in all cases the only interface that will have its radio disabled
+ will be the device that has the RF button attached to it. But it could
+ be desired that userspace performs this disabling of all radios in case
+ there are also interfaces without a RF button that need to be disabled.
+
+ The rfkill driver will contain a list of all devices with a RF button,
+ hardware drivers need to register their hardware to teh rfkill
+ interface it can take care of everything. If the RF button requires
+ polling to obtain the status this will be handled by rfkill as well.
+ Once the status of the button has changed and the hardware does not
+ automaticly enable or disable the radio rfkill provides with the
+ interface to do this correctly.
+
+ For each registered hardware button an input device will be created.
+ If this input device has been opened by the user, rfkill will send a
+ signal to userspace instead of the hardware about the new button
+ status. This will allow userpace to perform the correct steps
+ in order to bring down all interfaces.
+ */
+
+#ifndef RFKILL_H
+#define RFKILL_H
+
+#include <linux/list.h>
+#include <linux/input.h>
+
+#define RFKILL_POLL_DELAY ( HZ / 10 ) /* 100 ms */
+
+/**
+ * struct rfkill - rfkill button control structure.
+ * @dev_name: Name of the interface. This will become the name
+ * of the input device which will be created for this button.
+ * @data: Private data which will be passed along with the radio and polling
+ * handlers.
+ * @poll(unsigned long data): Optional handler which will frequently be
+ * called to determine the current status of the RF button.
+ * @enable_radio(unsigned long data): Optional handler to enable the radio
+ * once the RF button has been pressed and the hardware does enable
+ * the radio automaticly.
+ * @disable_radio(unsigned long data): Optional handler to disable the radio
+ * once the RF button has been pressed and the hardware does disable
+ * the radio automaticly.
+ * @current_status: Contains the current status of the radio as it was
+ * previously indicated by the radio. This field may only be changed
+ * by the driver at initialization time.
+ */
+struct rfkill {
+ const char *dev_name;
+
+ unsigned long data;
+
+ int (*poll)(unsigned long data);
+ void (*enable_radio)(unsigned long data);
+ void (*disable_radio)(unsigned long data);
+
+ unsigned int current_status;
+
+ /*
+ * These fields are private to rfkill, and
+ * should not be used by the RF button driver.
+ */
+ struct list_head entry;
+ struct input_dev *input_dev;
+};
+
+void rfkill_button_event(struct rfkill *rfkill, int status);
+int rfkill_add_device(struct rfkill *rfkill);
+void rfkill_del_device(struct rfkill *rfkill);
+
+#endif /* RFKILL_H */
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 60eca90..11804d5 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -250,7 +250,7 @@ int ieee80211_get_hdrlen(u16 fc)
case IEEE80211_FTYPE_DATA:
if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
hdrlen = 30; /* Addr4 */
- if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_QOS_DATA)
+ if (fc & IEEE80211_STYPE_QOS_DATA)
hdrlen += 2; /* QoS Control Field */
break;
case IEEE80211_FTYPE_CTL:
@@ -637,7 +637,7 @@ static int ieee80211_frame_duration(stru
* 802.11 (DS): 15.3.3, 802.11b: 18.3.4
* aSIFSTime = 10 usec
* aPreambleLength = 144 usec or 72 usec with short preamble
- * aPLCPHeaderLength = 48 ms or 24 ms with short preamble
+ * aPLCPHeaderLength = 48 usec or 24 usec with short preamble
*/
dur = 10; /* aSIFSTime = 10 usec */
dur += short_preamble ? (72 + 24) : (144 + 48);
@@ -762,7 +762,7 @@ ieee80211_tx_h_misc(struct ieee80211_txr
struct ieee80211_tx_control *control = tx->u.tx.control;
if (!is_multicast_ether_addr(hdr->addr1)) {
- if (tx->skb->len >= tx->local->rts_threshold &&
+ if (tx->skb->len + FCS_LEN > tx->local->rts_threshold &&
tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) {
control->use_rts_cts = 1;
control->retry_limit =
@@ -1519,7 +1519,7 @@ static int ieee80211_subif_start_xmit(st
sta = sta_info_get(local, hdr.addr1);
if (sta) {
if (sta->flags & WLAN_STA_WME) {
- fc |= IEEE80211_STYPE_QOS_DATA << 4;
+ fc |= IEEE80211_STYPE_QOS_DATA;
hdrlen += 2;
}
sta_info_put(sta);
@@ -3074,8 +3074,9 @@ ieee80211_rx_h_check(struct ieee80211_tx
rx->sdata->type != IEEE80211_IF_TYPE_IBSS &&
(!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {
if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
- !(rx->fc & IEEE80211_FCTL_TODS)) ||
- !rx->u.rx.ra_match) {
+ !(rx->fc & IEEE80211_FCTL_TODS) &&
+ (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
+ || !rx->u.rx.ra_match) {
/* Drop IBSS frames and frames for other hosts
* silently. */
return TXRX_DROP;
@@ -3976,11 +3977,11 @@ static void ieee80211_remove_tx_extra(st
pkt_data->requeue = control->requeue;
pkt_data->queue = control->queue;
- if (key == NULL)
- return;
-
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ if (key == NULL)
+ goto no_key;
+
switch (key->alg) {
case ALG_WEP:
iv_len = WEP_IV_LEN;
@@ -3995,7 +3996,7 @@ static void ieee80211_remove_tx_extra(st
mic_len = CCMP_MIC_LEN;
break;
default:
- return;
+ goto no_key;
}
if (skb->len >= mic_len && key->force_sw_encrypt)
@@ -4005,11 +4006,12 @@ static void ieee80211_remove_tx_extra(st
skb_pull(skb, iv_len);
}
+no_key:
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u16 fc = le16_to_cpu(hdr->frame_control);
if ((fc & 0x8C) == 0x88) /* QoS Control Field */ {
- fc &= ~(IEEE80211_STYPE_QOS_DATA << 4);
+ fc &= ~IEEE80211_STYPE_QOS_DATA;
hdr->frame_control = cpu_to_le16(fc);
memmove(skb->data + 2, skb->data, hdrlen - 2);
skb_pull(skb, 2);
@@ -4379,7 +4381,7 @@ struct net_device *ieee80211_alloc_hw(si
mdev->hard_start_xmit = ieee80211_master_start_xmit;
mdev->wireless_handlers =
- (struct iw_handler_def *) &ieee80211_iw_handler_def;
+ (struct iw_handler_def *) &ieee80211_iw_master_handler_def;
mdev->do_ioctl = ieee80211_ioctl;
mdev->change_mtu = ieee80211_change_mtu;
mdev->tx_timeout = ieee80211_tx_timeout;
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 7e021ec..bdaaf5e 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -569,6 +569,7 @@ void ieee80211_if_mgmt_setup(struct net_
/* ieee80211_ioctl.c */
int ieee80211_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
extern const struct iw_handler_def ieee80211_iw_handler_def;
+extern const struct iw_handler_def ieee80211_iw_master_handler_def;
/* Set hw encryption from ieee80211 */
int ieee80211_set_hw_encryption(struct net_device *dev,
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index dd52555..b983716 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -15,6 +15,7 @@ #include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
@@ -215,6 +216,52 @@ static int ieee80211_ioctl_flush(struct
}
+/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
+struct iapp_layer2_update {
+ u8 da[ETH_ALEN]; /* broadcast */
+ u8 sa[ETH_ALEN]; /* STA addr */
+ u16 len; /* 6 */
+ u8 dsap; /* 0 */
+ u8 ssap; /* 0 */
+ u8 control;
+ u8 xid_info[3];
+} __attribute__ ((packed));
+
+static void ieee80211_send_layer2_update(struct net_device *dev,
+ const u8 *addr)
+{
+ struct iapp_layer2_update *msg;
+ struct sk_buff *skb;
+
+ /* Send Level 2 Update Frame to update forwarding tables in layer 2
+ * bridge devices */
+
+ skb = dev_alloc_skb(sizeof(*msg));
+ if (skb == NULL)
+ return;
+ msg = (struct iapp_layer2_update *) skb_put(skb, sizeof(*msg));
+
+ /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
+ * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
+
+ memset(msg->da, 0xff, ETH_ALEN);
+ memcpy(msg->sa, addr, ETH_ALEN);
+ msg->len = htons(6);
+ msg->dsap = 0;
+ msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */
+ msg->control = 0xaf; /* XID response lsb.1111F101.
+ * F=0 (no poll command; unsolicited frame) */
+ msg->xid_info[0] = 0x81; /* XID format identifier */
+ msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
+ msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
+
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+}
+
+
static int ieee80211_ioctl_add_sta(struct net_device *dev,
struct prism2_hostapd_param *param)
{
@@ -296,6 +343,10 @@ static int ieee80211_ioctl_add_sta(struc
sta_info_put(sta);
+ if (sdata->type == IEEE80211_IF_TYPE_AP ||
+ sdata->type == IEEE80211_IF_TYPE_VLAN)
+ ieee80211_send_layer2_update(dev, param->sta_addr);
+
return 0;
}
@@ -1168,6 +1219,10 @@ #if 0
dev->name, MAC_ARG(param->sta_addr),
new_vlan_dev->name);
#endif
+ if (sta->dev != new_vlan_dev) {
+ ieee80211_send_layer2_update(new_vlan_dev,
+ sta->addr);
+ }
sta->dev = new_vlan_dev;
sta->vlan_id = param->u.set_sta_vlan.vlan_id;
dev_put(new_vlan_dev);
@@ -2500,7 +2555,7 @@ static int ieee80211_ioctl_prism2_param(
break;
case PRISM2_PARAM_MIXED_CELL:
- if (sdata->type != IEEE80211_IF_TYPE_STA ||
+ if (sdata->type != IEEE80211_IF_TYPE_STA &&
sdata->type != IEEE80211_IF_TYPE_IBSS)
ret = -EINVAL;
else
@@ -2525,7 +2580,7 @@ static int ieee80211_ioctl_prism2_param(
sdata->u.sta.create_ibss = !!value;
break;
case PRISM2_PARAM_WMM_ENABLED:
- if (sdata->type != IEEE80211_IF_TYPE_STA ||
+ if (sdata->type != IEEE80211_IF_TYPE_STA &&
sdata->type != IEEE80211_IF_TYPE_IBSS)
ret = -EINVAL;
else
@@ -2712,7 +2767,7 @@ static int ieee80211_ioctl_get_prism2_pa
break;
case PRISM2_PARAM_MIXED_CELL:
- if (sdata->type != IEEE80211_IF_TYPE_STA ||
+ if (sdata->type != IEEE80211_IF_TYPE_STA &&
sdata->type != IEEE80211_IF_TYPE_IBSS)
ret = -EINVAL;
else
@@ -2726,7 +2781,7 @@ static int ieee80211_ioctl_get_prism2_pa
*param = sdata->u.sta.key_mgmt;
break;
case PRISM2_PARAM_WMM_ENABLED:
- if (sdata->type != IEEE80211_IF_TYPE_STA ||
+ if (sdata->type != IEEE80211_IF_TYPE_STA &&
sdata->type != IEEE80211_IF_TYPE_IBSS)
ret = -EINVAL;
else
@@ -2778,7 +2833,7 @@ static int ieee80211_ioctl_siwmlme(struc
struct iw_mlme *mlme = (struct iw_mlme *) extra;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->type != IEEE80211_IF_TYPE_STA ||
+ if (sdata->type != IEEE80211_IF_TYPE_STA &&
sdata->type != IEEE80211_IF_TYPE_IBSS)
return -EINVAL;
@@ -3129,3 +3184,25 @@ const struct iw_handler_def ieee80211_iw
.private = (iw_handler *) ieee80211_private_handler,
.private_args = (struct iw_priv_args *) ieee80211_ioctl_priv,
};
+
+/* Wireless handlers for master interface */
+
+static const iw_handler ieee80211_master_handler[] =
+{
+ [SIOCGIWNAME - SIOCIWFIRST] = (iw_handler) ieee80211_ioctl_giwname,
+ [SIOCSIWFREQ - SIOCIWFIRST] = (iw_handler) ieee80211_ioctl_siwfreq,
+ [SIOCGIWFREQ - SIOCIWFIRST] = (iw_handler) ieee80211_ioctl_giwfreq,
+ [SIOCGIWRANGE - SIOCIWFIRST] = (iw_handler) ieee80211_ioctl_giwrange,
+ [SIOCSIWRTS - SIOCIWFIRST] = (iw_handler) ieee80211_ioctl_siwrts,
+ [SIOCGIWRTS - SIOCIWFIRST] = (iw_handler) ieee80211_ioctl_giwrts,
+ [SIOCSIWFRAG - SIOCIWFIRST] = (iw_handler) ieee80211_ioctl_siwfrag,
+ [SIOCGIWFRAG - SIOCIWFIRST] = (iw_handler) ieee80211_ioctl_giwfrag,
+ [SIOCSIWRETRY - SIOCIWFIRST] = (iw_handler) ieee80211_ioctl_siwretry,
+ [SIOCGIWRETRY - SIOCIWFIRST] = (iw_handler) ieee80211_ioctl_giwretry,
+};
+
+const struct iw_handler_def ieee80211_iw_master_handler_def =
+{
+ .num_standard = sizeof(ieee80211_master_handler) / sizeof(iw_handler),
+ .standard = ieee80211_master_handler,
+};
diff --git a/net/d80211/tkip.c b/net/d80211/tkip.c
index 3f0cf57..c27a7fe 100644
--- a/net/d80211/tkip.c
+++ b/net/d80211/tkip.c
@@ -286,6 +286,7 @@ #endif /* CONFIG_TKIP_DEBUG */
if (only_iv) {
res = TKIP_DECRYPT_OK;
+ key->u.tkip.rx_initialized[queue] = 1;
goto done;
}
diff --git a/net/d80211/wme.c b/net/d80211/wme.c
index c3c961d..fc2a113 100644
--- a/net/d80211/wme.c
+++ b/net/d80211/wme.c
@@ -76,7 +76,7 @@ ieee80211_rx_h_remove_qos_control(struct
memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2);
hdr = (struct ieee80211_hdr *) skb_pull(rx->skb, 2);
/* change frame type to non QOS */
- rx->fc = fc &= ~(IEEE80211_STYPE_QOS_DATA << 4);
+ rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA;
hdr->frame_control = cpu_to_le16(fc);
return TXRX_CONTINUE;
@@ -199,7 +199,7 @@ static inline int classify80211(struct s
}
/* is this a QoS frame? */
- qos = fc & (IEEE80211_STYPE_QOS_DATA << 4);
+ qos = fc & IEEE80211_STYPE_QOS_DATA;
if (!qos) {
skb->priority = 0; /* required for correct WPA/11i MIC */
diff --git a/net/d80211/wpa.c b/net/d80211/wpa.c
index 7919620..fe5861f 100644
--- a/net/d80211/wpa.c
+++ b/net/d80211/wpa.c
@@ -70,7 +70,7 @@ int ieee80211_get_hdr_info(const struct
a4_included = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
- (fc & IEEE80211_FCTL_STYPE) & IEEE80211_STYPE_QOS_DATA) {
+ fc & IEEE80211_STYPE_QOS_DATA) {
pos = (u8 *) &hdr->addr4;
if (a4_included)
pos += 6;
--
John W. Linville
linville@tuxdriver.com
next reply other threads:[~2006-08-08 23:42 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-08-08 23:41 John W. Linville [this message]
-- strict thread matches above, loose matches on Subject: below --
2006-09-05 0:10 What's new in wireless-dev? John W. Linville
2006-09-05 0:02 John W. Linville
2006-09-04 23:53 John W. Linville
2006-08-24 19:08 John W. Linville
2006-07-30 1:30 John W. Linville
2006-07-11 20:45 John W. Linville
2006-07-12 9:48 ` Jiri Benc
2006-07-12 12:48 ` John W. Linville
2006-07-13 2:30 ` John W. Linville
2006-06-15 21:10 John W. Linville
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20060808234123.GB20706@tuxdriver.com \
--to=linville@tuxdriver.com \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.