]> err.no Git - linux-2.6/blobdiff - drivers/net/wireless/rt2x00/rt2x00mac.c
rt2x00: Always call ieee80211_stop_queue() when return NETDEV_TX_BUSY
[linux-2.6] / drivers / net / wireless / rt2x00 / rt2x00mac.c
index e98d013a189f30e4785b05922c752a6382931d19..1ab2fb6c38da5a6a572e7499a045028d3bf73045 100644 (file)
        Abstract: rt2x00 generic mac80211 routines.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt2x00lib"
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 
@@ -89,7 +84,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
         */
        if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) {
                ieee80211_stop_queues(hw);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /*
@@ -115,15 +110,24 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
        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)
+               if (rt2x00_ring_free(ring) <= 1) {
+                       ieee80211_stop_queue(rt2x00dev->hw, control->queue);
                        return NETDEV_TX_BUSY;
+               }
 
-               if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control))
+               if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control)) {
+                       ieee80211_stop_queue(rt2x00dev->hw, control->queue);
                        return NETDEV_TX_BUSY;
+               }
        }
 
-       if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control))
+       if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) {
+               ieee80211_stop_queue(rt2x00dev->hw, control->queue);
                return NETDEV_TX_BUSY;
+       }
+
+       if (rt2x00_ring_full(ring))
+               ieee80211_stop_queue(rt2x00dev->hw, control->queue);
 
        if (rt2x00dev->ops->lib->kick_tx_queue)
                rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
@@ -196,6 +200,14 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct interface *intf = &rt2x00dev->interface;
 
+       /* 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;
+       }
+
        /*
         * Don't allow interfaces to be added while
         * either the device has disappeared or when
@@ -239,7 +251,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
                return;
 
        intf->id = 0;
-       intf->type = INVALID_INTERFACE;
+       intf->type = IEEE80211_IF_TYPE_INVALID;
        memset(&intf->bssid, 0x00, ETH_ALEN);
        memset(&intf->mac, 0x00, ETH_ALEN);
 
@@ -272,7 +284,7 @@ int rt2x00mac_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(rt2x00dev, conf, 0);
@@ -281,7 +293,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
         * 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);
 
@@ -365,6 +377,40 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
 }
 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 rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
                      const struct ieee80211_tx_queue_params *params)
 {