aboutsummaryrefslogtreecommitdiffstats
path: root/package/rt2x00/src/rt2x00mac.c
diff options
context:
space:
mode:
authorFlorian Fainelli <florian@openwrt.org>2008-03-09 10:55:19 +0000
committerFlorian Fainelli <florian@openwrt.org>2008-03-09 10:55:19 +0000
commitfef15a956c143d470e76258f410ef5d1349dd6a9 (patch)
tree47097d050dd1c91feb0af8f1bf4dd8e77eecd803 /package/rt2x00/src/rt2x00mac.c
parent3d66117ef06d4a85967d0d1a9c26af38320b4e4c (diff)
downloadupstream-fef15a956c143d470e76258f410ef5d1349dd6a9.tar.gz
upstream-fef15a956c143d470e76258f410ef5d1349dd6a9.tar.bz2
upstream-fef15a956c143d470e76258f410ef5d1349dd6a9.zip
Fix rt2x00 compilation and upgrade to the current mainline version (2.6.24)
SVN-Revision: 10573
Diffstat (limited to 'package/rt2x00/src/rt2x00mac.c')
-rw-r--r--package/rt2x00/src/rt2x00mac.c377
1 files changed, 208 insertions, 169 deletions
diff --git a/package/rt2x00/src/rt2x00mac.c b/package/rt2x00/src/rt2x00mac.c
index 8835df2e2e..85ea8a8e65 100644
--- a/package/rt2x00/src/rt2x00mac.c
+++ b/package/rt2x00/src/rt2x00mac.c
@@ -19,10 +19,8 @@
*/
/*
- Module: rt2x00lib
+ Module: rt2x00mac
Abstract: rt2x00 generic mac80211 routines.
- Supported chipsets: RT2460, RT2560, RT2570,
- rt2561, rt2561s, rt2661, rt2571W & rt2671.
*/
/*
@@ -30,15 +28,16 @@
*/
#define DRV_NAME "rt2x00lib"
-#include <linux/netdevice.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
-#include "rt2x00dev.h"
-static int rt2x00_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
- struct data_ring *ring, struct sk_buff *frag_skb,
- struct ieee80211_tx_control *control)
+static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring,
+ struct sk_buff *frag_skb,
+ struct ieee80211_tx_control *control)
{
struct sk_buff *skb;
int size;
@@ -58,13 +57,13 @@ static int rt2x00_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
skb_put(skb, size);
if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
- ieee80211_ctstoself_get(rt2x00dev->hw,
- frag_skb->data, frag_skb->len, control,
- (struct ieee80211_cts*)(skb->data));
+ ieee80211_ctstoself_get(rt2x00dev->hw, rt2x00dev->interface.id,
+ frag_skb->data, frag_skb->len, control,
+ (struct ieee80211_cts *)(skb->data));
else
- ieee80211_rts_get(rt2x00dev->hw,
- frag_skb->data, frag_skb->len, control,
- (struct ieee80211_rts*)(skb->data));
+ ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id,
+ frag_skb->data, frag_skb->len, control,
+ (struct ieee80211_rts *)(skb->data));
if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) {
WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
@@ -74,23 +73,34 @@ static int rt2x00_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
return NETDEV_TX_OK;
}
-int rt2x00lib_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr*)skb->data;
+ struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
struct data_ring *ring;
u16 frame_control;
/*
+ * Mac80211 might be calling this function while we are trying
+ * to remove the device or perhaps suspending it.
+ * Note that we can only stop the TX queues inside the TX path
+ * due to possible race conditions in mac80211.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) {
+ ieee80211_stop_queues(hw);
+ return 0;
+ }
+
+ /*
* Determine which ring to put packet on.
*/
- ring = rt2x00_get_ring(rt2x00dev, control->queue);
+ ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
if (unlikely(!ring)) {
ERROR(rt2x00dev,
- "Attempt to send packet over invalid queue %d.\n"
- "Please file bug report to %s.\n",
- control->queue, DRV_PROJECT);
+ "Attempt to send packet over invalid queue %d.\n"
+ "Please file bug report to %s.\n",
+ control->queue, DRV_PROJECT);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -102,12 +112,13 @@ int rt2x00lib_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
* frame as well as the data frame.
*/
frame_control = le16_to_cpu(ieee80211hdr->frame_control);
- if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS &&
- !is_cts_frame(frame_control) && !is_rts_frame(frame_control)) {
+ if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) &&
+ (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS |
+ IEEE80211_TXCTL_USE_CTS_PROTECT))) {
if (rt2x00_ring_free(ring) <= 1)
return NETDEV_TX_BUSY;
- if (rt2x00_tx_rts_cts(rt2x00dev, ring, skb, control))
+ if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control))
return NETDEV_TX_BUSY;
}
@@ -119,131 +130,149 @@ int rt2x00lib_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
return NETDEV_TX_OK;
}
-EXPORT_SYMBOL_GPL(rt2x00lib_tx);
+EXPORT_SYMBOL_GPL(rt2x00mac_tx);
-int rt2x00lib_reset(struct ieee80211_hw *hw)
+int rt2x00mac_start(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
+ int status;
+
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+ test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * If this is the first interface which is added,
+ * we should load the firmware now.
+ */
+ if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) {
+ status = rt2x00lib_load_firmware(rt2x00dev);
+ if (status)
+ return status;
+ }
+
+ /*
+ * Initialize the device.
+ */
+ status = rt2x00lib_initialize(rt2x00dev);
+ if (status)
+ return status;
+
+ /*
+ * Enable radio.
+ */
+ status = rt2x00lib_enable_radio(rt2x00dev);
+ if (status) {
+ rt2x00lib_uninitialize(rt2x00dev);
+ return status;
+ }
+
+ __set_bit(DEVICE_STARTED, &rt2x00dev->flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_start);
+
+void rt2x00mac_stop(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+ return;
+
+ /*
+ * Perhaps we can add something smarter here,
+ * but for now just disabling the radio should do.
+ */
rt2x00lib_disable_radio(rt2x00dev);
- return rt2x00lib_enable_radio(rt2x00dev);
+
+ __clear_bit(DEVICE_STARTED, &rt2x00dev->flags);
}
-EXPORT_SYMBOL_GPL(rt2x00lib_reset);
+EXPORT_SYMBOL_GPL(rt2x00mac_stop);
-int rt2x00lib_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+int rt2x00mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct interface *intf = &rt2x00dev->interface;
- int status;
+
+ /* FIXME: Beaconing is broken in rt2x00. */
+ if (conf->type == IEEE80211_IF_TYPE_IBSS ||
+ conf->type == IEEE80211_IF_TYPE_AP) {
+ ERROR(rt2x00dev,
+ "rt2x00 does not support Adhoc or Master mode");
+ return -EOPNOTSUPP;
+ }
/*
- * We only support 1 non-monitor interface.
+ * Don't allow interfaces to be added while
+ * either the device has disappeared or when
+ * another interface is already present.
*/
- if (conf->type != IEEE80211_IF_TYPE_MNTR &&
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
is_interface_present(intf))
return -ENOBUFS;
- /*
- * We support muliple monitor mode interfaces.
- * All we need to do is increase the monitor_count.
- */
- if (conf->type == IEEE80211_IF_TYPE_MNTR) {
- intf->monitor_count++;
- } else {
- intf->id = conf->if_id;
- intf->type = conf->type;
- if (conf->type == IEEE80211_IF_TYPE_AP)
- memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
- intf->promisc = 0;
- }
+ intf->id = conf->if_id;
+ intf->type = conf->type;
+ if (conf->type == IEEE80211_IF_TYPE_AP)
+ memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
+ memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
/*
- * Initialize interface, and enable the radio when this
- * is the first interface that is brought up.
+ * The MAC adddress must be configured after the device
+ * has been initialized. Otherwise the device can reset
+ * the MAC registers.
*/
- if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) {
- /*
- * We must wait on the firmware before
- * we can safely continue.
- */
- status = rt2x00lib_load_firmware_wait(rt2x00dev);
- if (status)
- return status;
-
- /*
- * Before initialization, the mac address should
- * be configured.
- */
- rt2x00dev->ops->lib->config_mac_addr(rt2x00dev,
- conf->mac_addr);
-
- /*
- * Initialize the device.
- */
- status = rt2x00lib_initialize(rt2x00dev);
- if (status)
- return status;
-
- /*
- * Enable radio.
- */
- status = rt2x00lib_enable_radio(rt2x00dev);
- if (status)
- return status;
- }
+ rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
+ rt2x00lib_config_type(rt2x00dev, conf->type);
return 0;
}
-EXPORT_SYMBOL_GPL(rt2x00lib_add_interface);
+EXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
-void rt2x00lib_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_if_init_conf *conf)
+void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct interface *intf = &rt2x00dev->interface;
/*
- * We only support 1 non-monitor interface.
+ * Don't allow interfaces to be remove while
+ * either the device has disappeared or when
+ * no interface is present.
*/
- if (conf->type != IEEE80211_IF_TYPE_MNTR &&
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
!is_interface_present(intf))
return;
- /*
- * When removing an monitor interface, decrease monitor_count.
- * For non-monitor interfaces, all interface data needs to be reset.
- */
- if (conf->type == IEEE80211_IF_TYPE_MNTR) {
- intf->monitor_count--;
- } else if (intf->type == conf->type) {
- intf->id = 0;
- intf->type = -EINVAL;
- memset(&intf->bssid, 0x00, ETH_ALEN);
- intf->promisc = 0;
- }
+ intf->id = 0;
+ intf->type = INVALID_INTERFACE;
+ memset(&intf->bssid, 0x00, ETH_ALEN);
+ memset(&intf->mac, 0x00, ETH_ALEN);
/*
- * If this was the last interface,
- * this is the time to disable the radio.
- * If this is not the last interface, then we should
- * check if we should switch completely to monitor
- * mode or completely switch to the non-monitor mode.
+ * Make sure the bssid and mac address registers
+ * are cleared to prevent false ACKing of frames.
*/
- if (!is_monitor_present(intf) && !is_interface_present(intf))
- rt2x00lib_disable_radio(rt2x00dev);
- else if (is_monitor_present(intf) ^ is_interface_present(intf))
- rt2x00lib_config_type(rt2x00dev,
- is_interface_present(intf) ?
- intf->type : IEEE80211_IF_TYPE_MNTR);
+ rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
+ rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
+ rt2x00lib_config_type(rt2x00dev, intf->type);
}
-EXPORT_SYMBOL_GPL(rt2x00lib_remove_interface);
+EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
-int rt2x00lib_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
/*
+ * Mac80211 might be calling this function while we are trying
+ * to remove the device or perhaps suspending it.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+ return 0;
+
+ /*
* Check if we need to disable the radio,
* if this is not the case, at least the RX must be disabled.
*/
@@ -251,46 +280,42 @@ int rt2x00lib_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
if (!conf->radio_enabled)
rt2x00lib_disable_radio(rt2x00dev);
else
- rt2x00lib_toggle_rx(rt2x00dev, 0);
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
}
- rt2x00lib_config_phymode(rt2x00dev, conf->phymode);
- rt2x00lib_config_channel(rt2x00dev, conf->channel_val,
- conf->channel, conf->freq, conf->power_level);
- rt2x00lib_config_txpower(rt2x00dev, conf->power_level);
- rt2x00lib_config_antenna(rt2x00dev,
- conf->antenna_sel_tx, conf->antenna_sel_rx);
- rt2x00dev->ops->lib->config_duration(rt2x00dev,
- (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME),
- conf->beacon_int);
+ rt2x00lib_config(rt2x00dev, conf, 0);
/*
* Reenable RX only if the radio should be on.
*/
if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2x00lib_toggle_rx(rt2x00dev, 1);
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
else if (conf->radio_enabled)
return rt2x00lib_enable_radio(rt2x00dev);
return 0;
}
-EXPORT_SYMBOL_GPL(rt2x00lib_config);
+EXPORT_SYMBOL_GPL(rt2x00mac_config);
-int rt2x00lib_config_interface(struct ieee80211_hw *hw, int if_id,
- struct ieee80211_if_conf *conf)
+int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id,
+ struct ieee80211_if_conf *conf)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct interface *intf = &rt2x00dev->interface;
int status;
/*
- * Monitor mode does not need configuring.
+ * Mac80211 might be calling this function while we are trying
+ * to remove the device or perhaps suspending it.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+ return 0;
+
+ /*
* If the given type does not match the configured type,
* there has been a problem.
*/
- if (conf->type == IEEE80211_IF_TYPE_MNTR)
- return 0;
- else if (conf->type != intf->type)
+ if (conf->type != intf->type)
return -EINVAL;
/*
@@ -300,14 +325,7 @@ int rt2x00lib_config_interface(struct ieee80211_hw *hw, int if_id,
*/
if (conf->type != IEEE80211_IF_TYPE_AP)
memcpy(&intf->bssid, conf->bssid, ETH_ALEN);
-
- /*
- * Enable configuration.
- * For Monitor mode, promisc mode will be forced on.
- */
- rt2x00lib_config_type(rt2x00dev, conf->type);
- rt2x00lib_config_promisc(rt2x00dev, rt2x00dev->interface.promisc);
- rt2x00dev->ops->lib->config_bssid(rt2x00dev, intf->bssid);
+ rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
/*
* We only need to initialize the beacon when master mode is enabled.
@@ -316,65 +334,86 @@ int rt2x00lib_config_interface(struct ieee80211_hw *hw, int if_id,
return 0;
status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
- conf->beacon, conf->beacon_control);
+ conf->beacon,
+ conf->beacon_control);
if (status)
dev_kfree_skb(conf->beacon);
return status;
}
-EXPORT_SYMBOL_GPL(rt2x00lib_config_interface);
+EXPORT_SYMBOL_GPL(rt2x00mac_config_interface);
-void rt2x00lib_set_multicast_list(struct ieee80211_hw *hw,
- unsigned short flags, int mc_count)
+int rt2x00mac_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
/*
- * Promisc mode is forced on for Monitor interfaces.
+ * The dot11ACKFailureCount, dot11RTSFailureCount and
+ * dot11RTSSuccessCount are updated in interrupt time.
+ * dot11FCSErrorCount is updated in the link tuner.
*/
- if (is_monitor_present(&rt2x00dev->interface))
- return;
+ memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats));
- /*
- * Check if the new state is different then the old state.
- */
- if (test_bit(INTERFACE_ENABLED_PROMISC, &rt2x00dev->flags) ==
- !!(flags & IFF_PROMISC))
- return;
-
- rt2x00dev->interface.promisc = !!(flags & IFF_PROMISC);
-
- /*
- * Schedule the link tuner if this does not run
- * automatically. The link tuner will be automatically
- * switched off when it is not required.
- */
- if (!work_pending(&rt2x00dev->link.work.work))
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work.work);
+ return 0;
}
-EXPORT_SYMBOL_GPL(rt2x00lib_set_multicast_list);
+EXPORT_SYMBOL_GPL(rt2x00mac_get_stats);
-int rt2x00lib_get_tx_stats(struct ieee80211_hw *hw,
- struct ieee80211_tx_queue_stats *stats)
+int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
unsigned int i;
for (i = 0; i < hw->queues; i++)
memcpy(&stats->data[i], &rt2x00dev->tx[i].stats,
- sizeof(rt2x00dev->tx[i].stats));
+ sizeof(rt2x00dev->tx[i].stats));
return 0;
}
-EXPORT_SYMBOL_GPL(rt2x00lib_get_tx_stats);
+EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats);
+
+void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes,
+ int cts_protection, int preamble)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int short_preamble;
+ int ack_timeout;
+ int ack_consume_time;
+ int difs;
+
+ /*
+ * We only support changing preamble mode.
+ */
+ if (!(changes & IEEE80211_ERP_CHANGE_PREAMBLE))
+ return;
+
+ short_preamble = !preamble;
+ preamble = !!(preamble) ? PREAMBLE : SHORT_PREAMBLE;
+
+ difs = (hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) ?
+ SHORT_DIFS : DIFS;
+ ack_timeout = difs + PLCP + preamble + get_duration(ACK_SIZE, 10);
+
+ ack_consume_time = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10);
+
+ if (short_preamble)
+ __set_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+ else
+ __clear_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+
+ rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble,
+ ack_timeout, ack_consume_time);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_erp_ie_changed);
-int rt2x00lib_conf_tx(struct ieee80211_hw *hw, int queue,
- const struct ieee80211_tx_queue_params *params)
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
+ const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_ring *ring;
- ring = rt2x00_get_ring(rt2x00dev, queue);
+ ring = rt2x00lib_get_ring(rt2x00dev, queue);
if (unlikely(!ring))
return -EINVAL;
@@ -398,10 +437,10 @@ int rt2x00lib_conf_tx(struct ieee80211_hw *hw, int queue,
ring->tx_params.aifs = 2;
INFO(rt2x00dev,
- "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
- queue, ring->tx_params.cw_min, ring->tx_params.cw_max,
- ring->tx_params.aifs);
+ "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
+ queue, ring->tx_params.cw_min, ring->tx_params.cw_max,
+ ring->tx_params.aifs);
return 0;
}
-EXPORT_SYMBOL_GPL(rt2x00lib_conf_tx);
+EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);