Supported chipsets: RT2570.
*/
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt2500usb"
-
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
* between each attampt. When the busy bit is still set at that time,
* the access attempt is considered to have failed,
* and we will print an error.
+ * If the usb_cache_mutex is already held then the _lock variants must
+ * be used instead.
*/
-static inline void rt2500usb_register_read(const struct rt2x00_dev *rt2x00dev,
+static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u16 *value)
{
*value = le16_to_cpu(reg);
}
-static inline void rt2500usb_register_multiread(const struct rt2x00_dev
- *rt2x00dev,
+static inline void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u16 *value)
+{
+ __le16 reg;
+ rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ ®, sizeof(u16), REGISTER_TIMEOUT);
+ *value = le16_to_cpu(reg);
+}
+
+static inline void rt2500usb_register_multiread(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
void *value, const u16 length)
{
value, length, timeout);
}
-static inline void rt2500usb_register_write(const struct rt2x00_dev *rt2x00dev,
+static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
u16 value)
{
®, sizeof(u16), REGISTER_TIMEOUT);
}
-static inline void rt2500usb_register_multiwrite(const struct rt2x00_dev
- *rt2x00dev,
+static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u16 value)
+{
+ __le16 reg = cpu_to_le16(value);
+ rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ ®, sizeof(u16), REGISTER_TIMEOUT);
+}
+
+static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
void *value, const u16 length)
{
value, length, timeout);
}
-static u16 rt2500usb_bbp_check(const struct rt2x00_dev *rt2x00dev)
+static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev)
{
u16 reg;
unsigned int i;
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2500usb_register_read(rt2x00dev, PHY_CSR8, ®);
+ rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, ®);
if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY))
break;
udelay(REGISTER_BUSY_DELAY);
return reg;
}
-static void rt2500usb_bbp_write(const struct rt2x00_dev *rt2x00dev,
+static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
{
u16 reg;
+ mutex_lock(&rt2x00dev->usb_cache_mutex);
+
/*
* Wait until the BBP becomes ready.
*/
reg = rt2500usb_bbp_check(rt2x00dev);
if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
return;
}
rt2x00_set_field16(®, PHY_CSR7_REG_ID, word);
rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 0);
- rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+ rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
+
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
}
-static void rt2500usb_bbp_read(const struct rt2x00_dev *rt2x00dev,
+static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
const unsigned int word, u8 *value)
{
u16 reg;
+ mutex_lock(&rt2x00dev->usb_cache_mutex);
+
/*
* Wait until the BBP becomes ready.
*/
rt2x00_set_field16(®, PHY_CSR7_REG_ID, word);
rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 1);
- rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+ rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
/*
* Wait until the BBP becomes ready.
if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
*value = 0xff;
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
return;
}
- rt2500usb_register_read(rt2x00dev, PHY_CSR7, ®);
+ rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, ®);
*value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
+
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
}
-static void rt2500usb_rf_write(const struct rt2x00_dev *rt2x00dev,
+static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u32 value)
{
u16 reg;
if (!word)
return;
+ mutex_lock(&rt2x00dev->usb_cache_mutex);
+
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2500usb_register_read(rt2x00dev, PHY_CSR10, ®);
+ rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, ®);
if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY))
goto rf_write;
udelay(REGISTER_BUSY_DELAY);
}
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n");
return;
rf_write:
reg = 0;
rt2x00_set_field16(®, PHY_CSR9_RF_VALUE, value);
- rt2500usb_register_write(rt2x00dev, PHY_CSR9, reg);
+ rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg);
reg = 0;
rt2x00_set_field16(®, PHY_CSR10_RF_VALUE, value >> 16);
rt2x00_set_field16(®, PHY_CSR10_RF_IF_SELECT, 0);
rt2x00_set_field16(®, PHY_CSR10_RF_BUSY, 1);
- rt2500usb_register_write(rt2x00dev, PHY_CSR10, reg);
+ rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
rt2x00_rf_write(rt2x00dev, word, value);
+
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
}
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u16)) )
-static void rt2500usb_read_csr(const struct rt2x00_dev *rt2x00dev,
+static void rt2500usb_read_csr(struct rt2x00_dev *rt2x00dev,
const unsigned int word, u32 *data)
{
rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data);
}
-static void rt2500usb_write_csr(const struct rt2x00_dev *rt2x00dev,
+static void rt2500usb_write_csr(struct rt2x00_dev *rt2x00dev,
const unsigned int word, u32 data)
{
rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
/*
* Configuration handlers.
*/
-static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *addr)
+static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev,
+ __le32 *mac)
{
- __le16 reg[3];
-
- memset(®, 0, sizeof(reg));
- memcpy(®, addr, ETH_ALEN);
-
- /*
- * The MAC address is passed to us as an array of bytes,
- * that array is little endian, so no need for byte ordering.
- */
- rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, ®, sizeof(reg));
+ rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, mac,
+ (3 * sizeof(__le16)));
}
-static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid)
+static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev,
+ __le32 *bssid)
{
- __le16 reg[3];
-
- memset(®, 0, sizeof(reg));
- memcpy(®, bssid, ETH_ALEN);
-
- /*
- * The BSSID is passed to us as an array of bytes,
- * that array is little endian, so no need for byte ordering.
- */
- rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, ®, sizeof(reg));
+ rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, bssid,
+ (3 * sizeof(__le16)));
}
-static void rt2500usb_config_packet_filter(struct rt2x00_dev *rt2x00dev,
- const unsigned int filter)
-{
- int promisc = !!(filter & IFF_PROMISC);
- int multicast = !!(filter & IFF_MULTICAST);
- int broadcast = !!(filter & IFF_BROADCAST);
- u16 reg;
-
- rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®);
- rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, !promisc);
- rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, !multicast);
- rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, !broadcast);
- rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
-}
-
-static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type)
+static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+ const int tsf_sync)
{
u16 reg;
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
- /*
- * Apply hardware packet filter.
- */
- rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®);
-
- if (!is_monitor_present(&rt2x00dev->interface) &&
- (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA))
- rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 1);
- else
- rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 0);
-
- /*
- * If there is a non-monitor interface present
- * the packet should be strict (even if a monitor interface is present!).
- * When there is only 1 interface present which is in monitor mode
- * we should start accepting _all_ frames.
- */
- if (is_interface_present(&rt2x00dev->interface)) {
- rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 1);
- rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 1);
- rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 1);
- rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1);
- } else if (is_monitor_present(&rt2x00dev->interface)) {
- rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 0);
- rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 0);
- rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 0);
- rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 0);
- }
-
- rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
-
/*
* Enable beacon config
*/
rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®);
rt2x00_set_field16(®, TXRX_CSR20_OFFSET,
- (PREAMBLE + get_duration(IEEE80211_HEADER, 2)) >> 6);
+ (PREAMBLE + get_duration(IEEE80211_HEADER, 20)) >> 6);
if (type == IEEE80211_IF_TYPE_STA)
rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 0);
else
rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®);
- if (is_interface_present(&rt2x00dev->interface)) {
- rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1);
- rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1);
- }
-
+ rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1);
+ rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1);
rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0);
- if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP)
- rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 2);
- else if (type == IEEE80211_IF_TYPE_STA)
- rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 1);
- else if (is_monitor_present(&rt2x00dev->interface) &&
- !is_interface_present(&rt2x00dev->interface))
- rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 0);
-
+ rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, tsf_sync);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
}
-static void rt2500usb_config_rate(struct rt2x00_dev *rt2x00dev, const int rate)
+static void rt2500usb_config_preamble(struct rt2x00_dev *rt2x00dev,
+ const int short_preamble,
+ const int ack_timeout,
+ const int ack_consume_time)
{
- struct ieee80211_conf *conf = &rt2x00dev->hw->conf;
u16 reg;
- u16 value;
- u16 preamble;
-
- if (DEVICE_GET_RATE_FIELD(rate, PREAMBLE))
- preamble = SHORT_PREAMBLE;
- else
- preamble = PREAMBLE;
-
- reg = DEVICE_GET_RATE_FIELD(rate, RATEMASK) & DEV_BASIC_RATEMASK;
- rt2500usb_register_write(rt2x00dev, TXRX_CSR11, reg);
+ /*
+ * When in atomic context, reschedule and let rt2x00lib
+ * call this function again.
+ */
+ if (in_atomic()) {
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work);
+ return;
+ }
rt2500usb_register_read(rt2x00dev, TXRX_CSR1, ®);
- value = ((conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) ?
- SHORT_DIFS : DIFS) +
- PLCP + preamble + get_duration(ACK_SIZE, 10);
- rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, value);
+ rt2x00_set_field16(®, TXRX_CSR1_ACK_TIMEOUT, ack_timeout);
rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg);
rt2500usb_register_read(rt2x00dev, TXRX_CSR10, ®);
- if (preamble == SHORT_PREAMBLE)
- rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, 1);
- else
- rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, 0);
+ rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE,
+ !!short_preamble);
rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg);
}
static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev,
- const int phymode)
+ const int phymode,
+ const int basic_rate_mask)
{
- struct ieee80211_hw_mode *mode;
- struct ieee80211_rate *rate;
-
- if (phymode == MODE_IEEE80211A)
- rt2x00dev->curr_hwmode = HWMODE_A;
- else if (phymode == MODE_IEEE80211B)
- rt2x00dev->curr_hwmode = HWMODE_B;
- else
- rt2x00dev->curr_hwmode = HWMODE_G;
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask);
- mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode];
- rate = &mode->rates[mode->num_rates - 1];
-
- rt2500usb_config_rate(rt2x00dev, rate->val2);
-
- if (phymode == MODE_IEEE80211B) {
+ if (phymode == HWMODE_B) {
rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x000b);
rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x0040);
} else {
}
static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
- const int index, const int channel,
- const int txpower)
+ struct rf_channel *rf, const int txpower)
{
- struct rf_channel reg;
-
- /*
- * Fill rf_reg structure.
- */
- memcpy(®, &rt2x00dev->spec.channels[index], sizeof(reg));
-
/*
* Set TXpower.
*/
- rt2x00_set_field32(®.rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
/*
* For RT2525E we should first set the channel to half band higher.
0x00000902, 0x00000906
};
- rt2500usb_rf_write(rt2x00dev, 2, vals[channel - 1]);
- if (reg.rf4)
- rt2500usb_rf_write(rt2x00dev, 4, reg.rf4);
+ rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
+ if (rf->rf4)
+ rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
}
- rt2500usb_rf_write(rt2x00dev, 1, reg.rf1);
- rt2500usb_rf_write(rt2x00dev, 2, reg.rf2);
- rt2500usb_rf_write(rt2x00dev, 3, reg.rf3);
- if (reg.rf4)
- rt2500usb_rf_write(rt2x00dev, 4, reg.rf4);
+ rt2500usb_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2500usb_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2500usb_rf_write(rt2x00dev, 3, rf->rf3);
+ if (rf->rf4)
+ rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
}
static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev,
}
static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
- const int antenna_tx, const int antenna_rx)
+ struct antenna_setup *ant)
{
u8 r2;
u8 r14;
/*
* Configure the TX antenna.
*/
- switch (antenna_tx) {
- case ANTENNA_SW_DIVERSITY:
+ switch (ant->tx) {
case ANTENNA_HW_DIVERSITY:
rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 1);
rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 1);
rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 0);
rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 0);
break;
+ case ANTENNA_SW_DIVERSITY:
+ /*
+ * NOTE: We should never come here because rt2x00lib is
+ * supposed to catch this and send us the correct antenna
+ * explicitely. However we are nog going to bug about this.
+ * Instead, just default to antenna B.
+ */
case ANTENNA_B:
rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 2);
/*
* Configure the RX antenna.
*/
- switch (antenna_rx) {
- case ANTENNA_SW_DIVERSITY:
+ switch (ant->rx) {
case ANTENNA_HW_DIVERSITY:
rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 1);
break;
case ANTENNA_A:
rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
break;
+ case ANTENNA_SW_DIVERSITY:
+ /*
+ * NOTE: We should never come here because rt2x00lib is
+ * supposed to catch this and send us the correct antenna
+ * explicitely. However we are nog going to bug about this.
+ * Instead, just default to antenna B.
+ */
case ANTENNA_B:
rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
break;
}
static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev,
- const int short_slot_time,
- const int beacon_int)
+ struct rt2x00lib_conf *libconf)
{
u16 reg;
- rt2500usb_register_write(rt2x00dev, MAC_CSR10,
- short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time);
rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®);
- rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, beacon_int * 4);
+ rt2x00_set_field16(®, TXRX_CSR18_INTERVAL,
+ libconf->conf->beacon_int * 4);
rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
}
static void rt2500usb_config(struct rt2x00_dev *rt2x00dev,
const unsigned int flags,
- struct ieee80211_conf *conf)
+ struct rt2x00lib_conf *libconf)
{
- int short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME;
-
if (flags & CONFIG_UPDATE_PHYMODE)
- rt2500usb_config_phymode(rt2x00dev, conf->phymode);
+ rt2500usb_config_phymode(rt2x00dev, libconf->phymode,
+ libconf->basic_rates);
if (flags & CONFIG_UPDATE_CHANNEL)
- rt2500usb_config_channel(rt2x00dev, conf->channel_val,
- conf->channel, conf->power_level);
+ rt2500usb_config_channel(rt2x00dev, &libconf->rf,
+ libconf->conf->power_level);
if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
- rt2500usb_config_txpower(rt2x00dev, conf->power_level);
+ rt2500usb_config_txpower(rt2x00dev,
+ libconf->conf->power_level);
if (flags & CONFIG_UPDATE_ANTENNA)
- rt2500usb_config_antenna(rt2x00dev, conf->antenna_sel_tx,
- conf->antenna_sel_rx);
+ rt2500usb_config_antenna(rt2x00dev, &libconf->ant);
if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
- rt2500usb_config_duration(rt2x00dev, short_slot_time,
- conf->beacon_int);
+ rt2500usb_config_duration(rt2x00dev, libconf);
}
/*
rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg);
rt2500usb_register_read(rt2x00dev, MAC_CSR20, ®);
-
- if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
- rt2x00_set_field16(®, MAC_CSR20_LINK, 1);
- rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 0);
- } else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
- rt2x00_set_field16(®, MAC_CSR20_LINK, 0);
- rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 1);
- } else {
- rt2x00_set_field16(®, MAC_CSR20_LINK, 1);
- rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 1);
- }
-
+ rt2x00_set_field16(®, MAC_CSR20_LINK,
+ (rt2x00dev->led_mode != LED_MODE_ASUS));
+ rt2x00_set_field16(®, MAC_CSR20_ACTIVITY,
+ (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY));
rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg);
}
/*
* Link tuning
*/
-static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev)
+static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev,
+ struct link_qual *qual)
{
u16 reg;
* Update FCS error count from register.
*/
rt2500usb_register_read(rt2x00dev, STA_CSR0, ®);
- rt2x00dev->link.rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR);
+ qual->rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR);
/*
* Update False CCA count from register.
*/
rt2500usb_register_read(rt2x00dev, STA_CSR3, ®);
- rt2x00dev->link.false_cca =
- rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR);
+ qual->false_cca = rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR);
}
static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
if (r17 > up_bound) {
rt2500usb_bbp_write(rt2x00dev, 17, up_bound);
rt2x00dev->link.vgc_level = up_bound;
- } else if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) {
+ } else if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) {
rt2500usb_bbp_write(rt2x00dev, 17, ++r17);
rt2x00dev->link.vgc_level = r17;
- } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
+ } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) {
rt2500usb_bbp_write(rt2x00dev, 17, --r17);
rt2x00dev->link.vgc_level = r17;
}
rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 1);
rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
- if (rt2x00_get_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) {
+ if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) {
rt2500usb_register_read(rt2x00dev, PHY_CSR2, ®);
- reg &= ~0x0002;
+ rt2x00_set_field16(®, PHY_CSR2_LNA, 0);
} else {
- reg = 0x3002;
+ reg = 0;
+ rt2x00_set_field16(®, PHY_CSR2_LNA, 1);
+ rt2x00_set_field16(®, PHY_CSR2_LNA_MODE, 3);
}
rt2500usb_register_write(rt2x00dev, PHY_CSR2, reg);
* TX descriptor initialization
*/
static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
- struct data_desc *txd,
- struct data_entry_desc *desc,
+ __le32 *txd,
+ struct txdata_entry_desc *desc,
struct ieee80211_hdr *ieee80211hdr,
unsigned int length,
struct ieee80211_tx_control *control)
rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
rt2x00_set_field32(&word, TXD_W0_ACK,
- !(control->flags & IEEE80211_TXCTL_NO_ACK));
+ test_bit(ENTRY_TXD_ACK, &desc->flags));
rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
rt2x00_set_field32(&word, TXD_W0_OFDM,
rt2x00_desc_write(txd, 0, word);
}
+static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
+ struct sk_buff *skb)
+{
+ int length;
+
+ /*
+ * The length _must_ be a multiple of 2,
+ * but it must _not_ be a multiple of the USB packet size.
+ */
+ length = roundup(skb->len, 2);
+ length += (2 * !(length % rt2x00dev->usb_maxpacket));
+
+ return length;
+}
+
/*
* TX data initialization
*/
/*
* RX control handlers
*/
-static int rt2500usb_fill_rxdone(struct data_entry *entry,
- int *signal, int *rssi, int *ofdm, int *size)
+static void rt2500usb_fill_rxdone(struct data_entry *entry,
+ struct rxdata_entry_desc *desc)
{
struct urb *urb = entry->priv;
- struct data_desc *rxd = (struct data_desc *)(entry->skb->data +
- (urb->actual_length -
- entry->ring->desc_size));
+ __le32 *rxd = (__le32 *)(entry->skb->data +
+ (urb->actual_length - entry->ring->desc_size));
u32 word0;
u32 word1;
rt2x00_desc_read(rxd, 0, &word0);
rt2x00_desc_read(rxd, 1, &word1);
- if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) ||
- rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR) ||
- rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
- return -EINVAL;
+ desc->flags = 0;
+ if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+ desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+ if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+ desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
/*
* Obtain the status about this packet.
*/
- *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
- *rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
+ desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+ desc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
entry->ring->rt2x00dev->rssi_offset;
- *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
- *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+ desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- return 0;
+ return;
}
/*
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
- rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0);
- rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0);
- rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT,
+ ANTENNA_SW_DIVERSITY);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT,
+ ANTENNA_SW_DIVERSITY);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE,
+ LED_MODE_DEFAULT);
rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522);
rt2500usb_register_read(rt2x00dev, MAC_CSR0, ®);
rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
- if (rt2x00_rev(&rt2x00dev->chip, 0xffff0)) {
+ if (!rt2x00_check_rev(&rt2x00dev->chip, 0)) {
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
return -ENODEV;
}
/*
* Identify default antenna configuration.
*/
- rt2x00dev->hw->conf.antenna_sel_tx =
+ rt2x00dev->default_ant.tx =
rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
- rt2x00dev->hw->conf.antenna_sel_rx =
+ rt2x00dev->default_ant.rx =
rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+ /*
+ * When the eeprom indicates SW_DIVERSITY use HW_DIVERSITY instead.
+ * I am not 100% sure about this, but the legacy drivers do not
+ * indicate antenna swapping in software is required when
+ * diversity is enabled.
+ */
+ if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
+ rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY;
+ if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
+ rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY;
+
/*
* Store led mode, for correct led behaviour.
*/
rt2x00dev->hw->flags =
IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_MONITOR_DURING_OPER |
- IEEE80211_HW_NO_PROBE_FILTERING;
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
rt2x00dev->hw->max_signal = MAX_SIGNAL;
rt2x00dev->hw->max_rssi = MAX_RX_SSI;
rt2500usb_probe_hw_mode(rt2x00dev);
/*
- * USB devices require scheduled packet filter toggling
- *This device requires the beacon ring
+ * This device requires the beacon ring
*/
- __set_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags);
- __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags);
+ __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
/*
* Set the rssi offset.
/*
* IEEE80211 stack callback functions.
*/
+static void rt2500usb_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+ u16 reg;
+
+ /*
+ * Mask off any flags we are going to ignore from
+ * the total_flags field.
+ */
+ *total_flags &=
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_PROMISC_IN_BSS;
+
+ /*
+ * Apply some rules to the filters:
+ * - Some filters imply different filters to be set.
+ * - Some things we can't filter out at all.
+ * - Some filters are set based on interface type.
+ */
+ if (mc_count)
+ *total_flags |= FIF_ALLMULTI;
+ if (*total_flags & FIF_OTHER_BSS ||
+ *total_flags & FIF_PROMISC_IN_BSS)
+ *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+ if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+ *total_flags |= FIF_PROMISC_IN_BSS;
+
+ /*
+ * Check if there is any work left for us.
+ */
+ if (intf->filter == *total_flags)
+ return;
+ intf->filter = *total_flags;
+
+ /*
+ * When in atomic context, reschedule and let rt2x00lib
+ * call this function again.
+ */
+ if (in_atomic()) {
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+ return;
+ }
+
+ /*
+ * Start configuration steps.
+ * Note that the version error will always be dropped
+ * and broadcast frames will always be accepted since
+ * there is no filter for it at this time.
+ */
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®);
+ rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC,
+ !(*total_flags & FIF_FCSFAIL));
+ rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL,
+ !(*total_flags & FIF_PLCPFAIL));
+ rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL,
+ !(*total_flags & FIF_CONTROL));
+ rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1);
+ rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST,
+ !(*total_flags & FIF_ALLMULTI));
+ rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+}
+
static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ieee80211_tx_control *control)
rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
struct data_entry *beacon;
struct data_entry *guardian;
+ int pipe = usb_sndbulkpipe(usb_dev, 1);
int length;
/*
* First we create the beacon.
*/
skb_push(skb, ring->desc_size);
- rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
+ memset(skb->data, 0, ring->desc_size);
+
+ rt2x00lib_write_tx_desc(rt2x00dev, (__le32 *)skb->data,
(struct ieee80211_hdr *)(skb->data +
ring->desc_size),
skb->len - ring->desc_size, control);
- /*
- * Length passed to usb_fill_urb cannot be an odd number,
- * so add 1 byte to make it even.
- */
- length = skb->len;
- if (length % 2)
- length++;
+ length = rt2500usb_get_tx_data_len(rt2x00dev, skb);
- usb_fill_bulk_urb(beacon->priv, usb_dev,
- usb_sndbulkpipe(usb_dev, 1),
+ usb_fill_bulk_urb(beacon->priv, usb_dev, pipe,
skb->data, length, rt2500usb_beacondone, beacon);
beacon->skb = skb;
* the 'flags' field we are not using for beacons.
*/
guardian->flags = 0;
- usb_fill_bulk_urb(guardian->priv, usb_dev,
- usb_sndbulkpipe(usb_dev, 1),
+ usb_fill_bulk_urb(guardian->priv, usb_dev, pipe,
&guardian->flags, 1, rt2500usb_beacondone, guardian);
/*
static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
.add_interface = rt2x00mac_add_interface,
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.config_interface = rt2x00mac_config_interface,
- .set_multicast_list = rt2x00mac_set_multicast_list,
+ .configure_filter = rt2500usb_configure_filter,
.get_stats = rt2x00mac_get_stats,
+ .erp_ie_changed = rt2x00mac_erp_ie_changed,
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.beacon_update = rt2500usb_beacon_update,
.link_tuner = rt2500usb_link_tuner,
.write_tx_desc = rt2500usb_write_tx_desc,
.write_tx_data = rt2x00usb_write_tx_data,
+ .get_tx_data_len = rt2500usb_get_tx_data_len,
.kick_tx_queue = rt2500usb_kick_tx_queue,
.fill_rxdone = rt2500usb_fill_rxdone,
.config_mac_addr = rt2500usb_config_mac_addr,
.config_bssid = rt2500usb_config_bssid,
- .config_packet_filter = rt2500usb_config_packet_filter,
.config_type = rt2500usb_config_type,
+ .config_preamble = rt2500usb_config_preamble,
.config = rt2500usb_config,
};
static const struct rt2x00_ops rt2500usb_ops = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.rxd_size = RXD_DESC_SIZE,
.txd_size = TXD_DESC_SIZE,
.eeprom_size = EEPROM_SIZE,
MODULE_LICENSE("GPL");
static struct usb_driver rt2500usb_driver = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.id_table = rt2500usb_device_table,
.probe = rt2x00usb_probe,
.disconnect = rt2x00usb_disconnect,