X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/acb7b631f32248190c9b28d706536977a32bc72f..ac74991e5e88789fe6d66bf3194525cd77ddaa4e:/package/mac80211/patches/303-rt2x00-Implement-support-for-rt2800usb.patch?ds=sidebyside diff --git a/package/mac80211/patches/303-rt2x00-Implement-support-for-rt2800usb.patch b/package/mac80211/patches/303-rt2x00-Implement-support-for-rt2800usb.patch index 1da4725e8..27b4f5a05 100644 --- a/package/mac80211/patches/303-rt2x00-Implement-support-for-rt2800usb.patch +++ b/package/mac80211/patches/303-rt2x00-Implement-support-for-rt2800usb.patch @@ -1,25 +1,30 @@ -From e380f1fa260d81cba1ebb1b6c333ef8c31f2a8c5 Mon Sep 17 00:00:00 2001 +From b249bc450f982cd2491448c91faf797ed37b69b8 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn -Date: Fri, 23 Jan 2009 17:16:11 +0100 +Date: Tue, 3 Mar 2009 19:25:49 +0100 Subject: [PATCH] rt2x00: Implement support for rt2800usb Add support for the rt2800usb chipset. -Includes various patches from Mattias and Felix. +Includes various patches from Mattias, Felix, Xose and Axel. Signed-off-by: Mattias Nissler Signed-off-by: Felix Fietkau +Signed-off-by: Xose Vazquez Perez +Signed-off-by: Axel Kollhofer Signed-off-by: Ivo van Doorn --- drivers/net/wireless/rt2x00/Kconfig | 14 + drivers/net/wireless/rt2x00/Makefile | 1 + - drivers/net/wireless/rt2x00/rt2800usb.c | 2905 +++++++++++++++++++++++++++++++ - drivers/net/wireless/rt2x00/rt2800usb.h | 1944 +++++++++++++++++++++ + drivers/net/wireless/rt2x00/rt2800usb.c | 3032 +++++++++++++++++++++++++++++++ + drivers/net/wireless/rt2x00/rt2800usb.h | 1932 ++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00.h | 7 + - 5 files changed, 4871 insertions(+), 0 deletions(-) + 5 files changed, 4986 insertions(+), 0 deletions(-) create mode 100644 drivers/net/wireless/rt2x00/rt2800usb.c create mode 100644 drivers/net/wireless/rt2x00/rt2800usb.h + config RT2X00_LIB_PCI + tristate + select RT2X00_LIB --- a/drivers/net/wireless/rt2x00/Makefile +++ b/drivers/net/wireless/rt2x00/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_RT61PCI) += rt61pci.o @@ -29,7 +34,7 @@ Signed-off-by: Ivo van Doorn +obj-$(CONFIG_RT2800USB) += rt2800usb.o --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2800usb.c -@@ -0,0 +1,2905 @@ +@@ -0,0 +1,3032 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + @@ -214,9 +219,6 @@ Signed-off-by: Ivo van Doorn +{ + u32 reg; + -+ if (!word) -+ return; -+ + mutex_lock(&rt2x00dev->csr_mutex); + + /* @@ -388,20 +390,40 @@ Signed-off-by: Ivo van Doorn + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ ++ struct mac_wcid_entry wcid_entry; ++ struct mac_iveiv_entry iveiv_entry; + u32 offset; + u32 reg; + -+ offset = MAC_WCID_ATTR_ENTRY(crypto->aid); ++ offset = MAC_WCID_ATTR_ENTRY(key->hw_key_idx); + -+ reg = 0; ++ rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, + !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); -+ rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_PAIRKEY_MODE, -+ crypto->cipher); ++ rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, crypto->cipher); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, -+ (crypto->cmd == SET_KEY) ? crypto->bssidx : 0); ++ (crypto->cmd == SET_KEY) * crypto->bssidx); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, 0); + rt2x00usb_register_write(rt2x00dev, offset, reg); ++ ++ offset = MAC_IVEIV_ENTRY(key->hw_key_idx); ++ ++ memset(&iveiv_entry, 0, sizeof(iveiv_entry)); ++ if ((crypto->cipher == CIPHER_TKIP) || ++ (crypto->cipher == CIPHER_TKIP_NO_MIC) || ++ (crypto->cipher == CIPHER_AES)) ++ iveiv_entry.iv[3] |= 0x20; ++ iveiv_entry.iv[3] |= key->keyidx << 6; ++ rt2x00usb_register_multiwrite(rt2x00dev, offset, ++ &iveiv_entry, sizeof(iveiv_entry)); ++ ++ offset = MAC_WCID_ENTRY(key->hw_key_idx); ++ ++ memset(&wcid_entry, 0, sizeof(wcid_entry)); ++ if (crypto->cmd == SET_KEY) ++ memcpy(&wcid_entry, crypto->address, ETH_ALEN); ++ rt2x00usb_register_multiwrite(rt2x00dev, offset, ++ &wcid_entry, sizeof(wcid_entry)); +} + +static int rt2800usb_config_shared_key(struct rt2x00_dev *rt2x00dev, @@ -412,10 +434,11 @@ Signed-off-by: Ivo van Doorn + struct rt2x00_field32 field; + int timeout; + u32 offset; -+ u32 mask; + u32 reg; + + if (crypto->cmd == SET_KEY) { ++ key->hw_key_idx = (4 * crypto->bssidx) + key->keyidx; ++ + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, @@ -430,34 +453,23 @@ Signed-off-by: Ivo van Doorn + offset, &key_entry, + sizeof(key_entry), + timeout); -+ -+ /* -+ * The driver does not support the IV/EIV generation -+ * in hardware. However it doesn't support the IV/EIV -+ * inside the ieee80211 frame either, but requires it -+ * to be provided seperately for the descriptor. -+ * rt2x00lib will cut the IV/EIV data out of all frames -+ * given to us by mac80211, but we must tell mac80211 -+ * to generate the IV/EIV data. -+ */ -+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + + /* + * The cipher types are stored over multiple registers + * starting with SHARED_KEY_MODE_BASE each word will have -+ * 32 bits and contains the cipher types for 2 modes each. ++ * 32 bits and contains the cipher types for 2 bssidx each. + * Using the correct defines correctly will cause overhead, + * so just calculate the correct offset. + */ -+ mask = key->hw_key_idx % 8; -+ field.bit_offset = (3 * mask); ++ field.bit_offset = (4 * key->keyidx) + (16 * (crypto->bssidx & 1)); + field.bit_mask = 0x7 << field.bit_offset; + -+ offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 8); ++ offset = SHARED_KEY_MODE_ENTRY(key->hw_key_idx / 2); ++ + rt2x00usb_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, field, -+ (crypto->cmd == SET_KEY) ? crypto->cipher : 0); ++ (crypto->cmd == SET_KEY) * crypto->cipher); + rt2x00usb_register_write(rt2x00dev, offset, reg); + + /* @@ -476,13 +488,13 @@ Signed-off-by: Ivo van Doorn + int timeout; + u32 offset; + -+ /* -+ * 1 pairwise key is possible per AID, this means that the AID -+ * equals our hw_key_idx. -+ */ -+ key->hw_key_idx = crypto->aid; -+ + if (crypto->cmd == SET_KEY) { ++ /* ++ * 1 pairwise key is possible per AID, this means that the AID ++ * equals our hw_key_idx. ++ */ ++ key->hw_key_idx = crypto->aid; ++ + memcpy(key_entry.key, crypto->key, + sizeof(key_entry.key)); + memcpy(key_entry.tx_mic, crypto->tx_mic, @@ -497,17 +509,6 @@ Signed-off-by: Ivo van Doorn + offset, &key_entry, + sizeof(key_entry), + timeout); -+ -+ /* -+ * The driver does not support the IV/EIV generation -+ * in hardware. However it doesn't support the IV/EIV -+ * inside the ieee80211 frame either, but requires it -+ * to be provided seperately for the descriptor. -+ * rt2x00lib will cut the IV/EIV data out of all frames -+ * given to us by mac80211, but we must tell mac80211 -+ * to generate the IV/EIV data. -+ */ -+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + + /* @@ -555,7 +556,7 @@ Signed-off-by: Ivo van Doorn + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PSPOLL, + !(filter_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BA, 1); -+ rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 1); ++ rt2x00_set_field32(®, RX_FILTER_CFG_DROP_BAR, 0); + rt2x00_set_field32(®, RX_FILTER_CFG_DROP_CNTL, + !(filter_flags & FIF_CONTROL)); + rt2x00usb_register_write(rt2x00dev, RX_FILTER_CFG, reg); @@ -616,7 +617,7 @@ Signed-off-by: Ivo van Doorn + + rt2x00usb_register_read(rt2x00dev, TX_TIMEOUT_CFG, ®); + rt2x00_set_field32(®, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, -+ erp->ack_timeout); ++ DIV_ROUND_UP(erp->ack_timeout, erp->slot_time)); + rt2x00usb_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, AUTO_RSP_CFG, ®); @@ -633,8 +634,7 @@ Signed-off-by: Ivo van Doorn + + rt2x00usb_register_write(rt2x00dev, LEGACY_BASIC_RATE, + erp->basic_rates); -+ rt2x00usb_register_write(rt2x00dev, HT_BASIC_RATE, -+ erp->basic_rates >> 32); ++ rt2x00usb_register_write(rt2x00dev, HT_BASIC_RATE, 0x00008003); + + rt2x00usb_register_read(rt2x00dev, BKOFF_SLOT_CFG, ®); + rt2x00_set_field32(®, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time); @@ -672,10 +672,9 @@ Signed-off-by: Ivo van Doorn + switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH)) { + case 1: + rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0); -+ rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0); + break; + case 2: -+ rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 16); ++ rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2); + break; + case 3: + /* Do nothing */ @@ -725,6 +724,7 @@ Signed-off-by: Ivo van Doorn +} + +static void rt2800usb_config_channel_rt2x(struct rt2x00_dev *rt2x00dev, ++ struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ @@ -736,6 +736,7 @@ Signed-off-by: Ivo van Doorn + * Determine antenna settings from EEPROM + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); ++ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) == 1) + rt2x00_set_field32(&rf->rf2, RF2_ANTENNA_TX1, 1); + @@ -776,8 +777,7 @@ Signed-off-by: Ivo van Doorn + TXPOWER_G_TO_DEV(info->tx_power2)); + } + -+ rt2x00_set_field32(&rf->rf4, RF4_BW40, -+ test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)); ++ rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); + + rt2800usb_rf_write(rt2x00dev, 1, rf->rf1); + rt2800usb_rf_write(rt2x00dev, 2, rf->rf2); @@ -800,6 +800,7 @@ Signed-off-by: Ivo van Doorn +} + +static void rt2800usb_config_channel_rt3x(struct rt2x00_dev *rt2x00dev, ++ struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ @@ -821,10 +822,12 @@ Signed-off-by: Ivo van Doorn + rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset); + rt2800usb_rfcsr_write(rt2x00dev, 23, rfcsr); + -+ if (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags)) -+ rt2800usb_rfcsr_write(rt2x00dev, 24, rt2x00dev->calibration_bw40); ++ if (conf_is_ht40(conf)) ++ rt2800usb_rfcsr_write(rt2x00dev, 24, ++ rt2x00dev->calibration_bw40); + else -+ rt2800usb_rfcsr_write(rt2x00dev, 24, rt2x00dev->calibration_bw20); ++ rt2800usb_rfcsr_write(rt2x00dev, 24, ++ rt2x00dev->calibration_bw20); + + rt2800usb_rfcsr_read(rt2x00dev, 23, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); @@ -832,46 +835,24 @@ Signed-off-by: Ivo van Doorn +} + +static void rt2800usb_config_channel(struct rt2x00_dev *rt2x00dev, ++ struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + u32 reg; + unsigned int tx_pin; + u16 eeprom; ++ u8 bbp; + -+ if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) -+ rt2800usb_config_channel_rt2x(rt2x00dev, rf, info); -+ else -+ rt2800usb_config_channel_rt3x(rt2x00dev, rf, info); -+ -+ tx_pin = 0; -+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1); -+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1); -+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1); -+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1); -+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1); -+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1); -+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1); -+ ++ /* ++ * Determine antenna settings from EEPROM ++ */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); + -+ /* Turn off unused PA or LNA when only 1T or 1R */ -+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) == 1) { -+ -+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 0); -+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 0); -+ } -+ -+ /* Turn off unused PA or LNA when only 1T or 1R */ -+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) == 1) { -+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 0); -+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 0); -+ } -+ -+ if (rf->channel > 14) -+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, 1); ++ if (rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) ++ rt2800usb_config_channel_rt2x(rt2x00dev, conf, rf, info); + else -+ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, 1); ++ rt2800usb_config_channel_rt3x(rt2x00dev, conf, rf, info); + + /* + * Change BBP settings @@ -889,11 +870,6 @@ Signed-off-by: Ivo van Doorn + rt2800usb_bbp_write(rt2x00dev, 82, 0x84); + rt2800usb_bbp_write(rt2x00dev, 75, 0x50); + } -+ -+ rt2x00usb_register_read(rt2x00dev, TX_BAND_CFG, ®); -+ rt2x00_set_field32(&rf->rf3, TX_BAND_CFG_A, 0); -+ rt2x00_set_field32(&rf->rf3, TX_BAND_CFG_BG, 1); -+ rt2x00usb_register_write(rt2x00dev, TX_BAND_CFG, reg); + } else { + rt2800usb_bbp_write(rt2x00dev, 82, 0xf2); + @@ -901,15 +877,57 @@ Signed-off-by: Ivo van Doorn + rt2800usb_bbp_write(rt2x00dev, 75, 0x46); + else + rt2800usb_bbp_write(rt2x00dev, 75, 0x50); ++ } ++ ++ rt2x00usb_register_read(rt2x00dev, TX_BAND_CFG, ®); ++ rt2x00_set_field32(®, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf)); ++ rt2x00_set_field32(®, TX_BAND_CFG_A, rf->channel > 14); ++ rt2x00_set_field32(®, TX_BAND_CFG_BG, rf->channel <= 14); ++ rt2x00usb_register_write(rt2x00dev, TX_BAND_CFG, reg); + -+ rt2x00usb_register_read(rt2x00dev, TX_BAND_CFG, ®); -+ rt2x00_set_field32(&rf->rf3, TX_BAND_CFG_A, 1); -+ rt2x00_set_field32(&rf->rf3, TX_BAND_CFG_BG, 0); -+ rt2x00usb_register_write(rt2x00dev, TX_BAND_CFG, reg); ++ tx_pin = 0; ++ ++ /* Turn on unused PA or LNA when not using 1T or 1R */ ++ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) != 1) { ++ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1); ++ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1); ++ } ++ ++ /* Turn on unused PA or LNA when not using 1T or 1R */ ++ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) != 1) { ++ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A1_EN, 1); ++ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G1_EN, 1); + } + ++ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_A0_EN, 1); ++ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1); ++ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1); ++ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1); ++ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14); ++ rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14); ++ + rt2x00usb_register_write(rt2x00dev, TX_PIN_CFG, tx_pin); + ++ rt2800usb_bbp_read(rt2x00dev, 4, &bbp); ++ rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); ++ rt2800usb_bbp_write(rt2x00dev, 4, bbp); ++ ++ rt2800usb_bbp_read(rt2x00dev, 3, &bbp); ++ rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); ++ rt2800usb_bbp_write(rt2x00dev, 3, bbp); ++ ++ if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { ++ if (conf_is_ht40(conf)) { ++ rt2800usb_bbp_write(rt2x00dev, 69, 0x1a); ++ rt2800usb_bbp_write(rt2x00dev, 70, 0x0a); ++ rt2800usb_bbp_write(rt2x00dev, 73, 0x16); ++ } else { ++ rt2800usb_bbp_write(rt2x00dev, 69, 0x16); ++ rt2800usb_bbp_write(rt2x00dev, 70, 0x08); ++ rt2800usb_bbp_write(rt2x00dev, 73, 0x11); ++ } ++ } ++ + msleep(1); +} + @@ -1042,8 +1060,8 @@ Signed-off-by: Ivo van Doorn + rt2800usb_config_lna_gain(rt2x00dev, libconf); + + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) -+ rt2800usb_config_channel(rt2x00dev, &libconf->rf, -+ &libconf->channel); ++ rt2800usb_config_channel(rt2x00dev, libconf->conf, ++ &libconf->rf, &libconf->channel); + if (flags & IEEE80211_CONF_CHANGE_POWER) + rt2800usb_config_txpower(rt2x00dev, libconf->conf->power_level); + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) @@ -1067,12 +1085,6 @@ Signed-off-by: Ivo van Doorn + */ + rt2x00usb_register_read(rt2x00dev, RX_STA_CNT0, ®); + qual->rx_failed = rt2x00_get_field32(reg, RX_STA_CNT0_CRC_ERR); -+ -+ /* -+ * Update False CCA count from register. -+ */ -+ rt2x00usb_register_read(rt2x00dev, RX_STA_CNT1, ®); -+ qual->false_cca = rt2x00_get_field32(reg, RX_STA_CNT1_FALSE_CCA); +} + +static u8 rt2800usb_get_default_vgc(struct rt2x00_dev *rt2x00dev) @@ -1129,19 +1141,24 @@ Signed-off-by: Ivo van Doorn + return FIRMWARE_RT2870; +} + -+static u16 rt2800usb_get_firmware_crc(const void *data, const size_t len) ++static bool rt2800usb_check_crc(const u8 *data, const size_t len) +{ ++ u16 fw_crc; + u16 crc; + + /* ++ * The last 2 bytes in the firmware array are the crc checksum itself, ++ * this means that we should never pass those 2 bytes to the crc ++ * algorithm. ++ */ ++ fw_crc = (data[len - 2] << 8 | data[len - 1]); ++ ++ /* + * Use the crc ccitt algorithm. + * This will return the same value as the legacy driver which + * used bit ordering reversion on the both the firmware bytes + * before input input as well as on the final output. + * Obviously using crc ccitt directly is much more efficient. -+ * The last 2 bytes in the firmware array are the crc checksum itself, -+ * this means that we should never pass those 2 bytes to the crc -+ * algorithm. + */ + crc = crc_ccitt(~0, data, len - 2); + @@ -1151,18 +1168,16 @@ Signed-off-by: Ivo van Doorn + * will be swapped, use swab16 to convert the crc to the correct + * value. + */ -+ return swab16(crc); ++ crc = swab16(crc); ++ ++ return fw_crc == crc; +} + -+static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, -+ const void *data, const size_t len) ++static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev, ++ const u8 *data, const size_t len) +{ -+ unsigned int i; -+ int status; -+ u32 reg; -+ u32 offset; -+ u32 length; + u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff; ++ size_t offset = 0; + + /* + * Firmware files: @@ -1173,24 +1188,51 @@ Signed-off-by: Ivo van Doorn + * within the file. The first blob is the same firmware as (a), + * but the second blob is for the additional chipsets. + */ -+ if (len != 4096 && len != 8192) { -+ ERROR(rt2x00dev, "Invalid firmware file length (len=%zu)\n", len); -+ return -ENOENT; ++ if (len != 4096 && len != 8192) ++ return FW_BAD_LENGTH; ++ ++ /* ++ * Check if we need the upper 4kb firmware data or not. ++ */ ++ if ((len == 4096) && ++ (chipset != 0x2860) && ++ (chipset != 0x2872) && ++ (chipset != 0x3070)) ++ return FW_BAD_VERSION; ++ ++ /* ++ * 8kb firmware files must be checked as if it were ++ * 2 seperate firmware files. ++ */ ++ while (offset < len) { ++ if (!rt2800usb_check_crc(data + offset, 4096)) ++ return FW_BAD_CRC; ++ ++ offset += 4096; + } + ++ return FW_OK; ++} ++ ++static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, ++ const u8 *data, const size_t len) ++{ ++ unsigned int i; ++ int status; ++ u32 reg; ++ u32 offset; ++ u32 length; ++ u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff; ++ ++ /* ++ * Check which section of the firmware we need. ++ */ + if ((chipset == 0x2860) || (chipset == 0x2872) || (chipset == 0x3070)) { + offset = 0; + length = 4096; -+ } else if (len == 8192) { ++ } else { + offset = 4096; + length = 4096; -+ } else { -+ ERROR(rt2x00dev, -+ "Current firmware does not support detected chipset %04x.\n", -+ chipset); -+ ERROR(rt2x00dev, -+ "Please upgrade to a more recent firmware version.\n"); -+ return -ENOENT; + } + + /* @@ -1328,7 +1370,7 @@ Signed-off-by: Ivo van Doorn + rt2x00usb_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); + rt2x00usb_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); + } else { -+ rt2x00usb_register_write(rt2x00dev, TX_SW_CFG0, 0x00040a06); ++ rt2x00usb_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000); + rt2x00usb_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); + } + @@ -1370,25 +1412,25 @@ Signed-off-by: Ivo van Doorn + rt2x00usb_register_write(rt2x00dev, AUTO_RSP_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, CCK_PROT_CFG, ®); -+ rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 3); ++ rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_RATE, 8); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, CCK_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1); -+ rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 0); ++ rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00usb_register_write(rt2x00dev, CCK_PROT_CFG, reg); + + rt2x00usb_register_read(rt2x00dev, OFDM_PROT_CFG, ®); -+ rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 3); ++ rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_RATE, 8); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_CTRL, 0); + rt2x00_set_field32(®, OFDM_PROT_CFG_PROTECT_NAV, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1); -+ rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 0); ++ rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1); + rt2x00_set_field32(®, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1); + rt2x00usb_register_write(rt2x00dev, OFDM_PROT_CFG, reg); @@ -1460,6 +1502,8 @@ Signed-off-by: Ivo van Doorn + + rt2x00usb_register_read(rt2x00dev, TX_RTS_CFG, ®); + rt2x00_set_field32(®, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32); ++ rt2x00_set_field32(®, TX_RTS_CFG_RTS_THRES, ++ IEEE80211_MAX_RTS_THRESHOLD); + rt2x00_set_field32(®, TX_RTS_CFG_RTS_FBK_EN, 0); + rt2x00usb_register_write(rt2x00dev, TX_RTS_CFG, reg); + @@ -1469,19 +1513,19 @@ Signed-off-by: Ivo van Doorn + /* + * ASIC will keep garbage value after boot, clear encryption keys. + */ -+ for (i = 0; i < 254; i++) { ++ for (i = 0; i < 256; i++) { + u32 wcid[2] = { 0xffffffff, 0x00ffffff }; + rt2x00usb_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), + wcid, sizeof(wcid)); ++ ++ rt2x00usb_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); ++ rt2x00usb_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); + } + -+ for (i = 0; i < 4; i++) ++ for (i = 0; i < 16; i++) + rt2x00usb_register_write(rt2x00dev, + SHARED_KEY_MODE_ENTRY(i), 0); + -+ for (i = 0; i < 256; i++) -+ rt2x00usb_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 1); -+ + /* + * Clear all beacons + * For the Beacon base registers we only need to clear @@ -1526,12 +1570,12 @@ Signed-off-by: Ivo van Doorn + rt2x00usb_register_read(rt2x00dev, LG_FBK_CFG0, ®); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS0FBK, 8); + rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS1FBK, 8); -+ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 10); -+ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS3FBK, 11); -+ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS4FBK, 12); -+ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 13); -+ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS6FBK, 14); -+ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 15); ++ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS2FBK, 3); ++ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS3FBK, 10); ++ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS4FBK, 11); ++ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS5FBK, 12); ++ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS6FBK, 13); ++ rt2x00_set_field32(®, LG_FBK_CFG0_OFDMMCS7FBK, 14); + rt2x00usb_register_write(rt2x00dev, LG_FBK_CFG0, reg); + + rt2x00usb_register_read(rt2x00dev, LG_FBK_CFG1, ®); @@ -1620,6 +1664,10 @@ Signed-off-by: Ivo van Doorn + rt2800usb_bbp_write(rt2x00dev, 73, 0x12); + } + ++ if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) { ++ rt2800usb_bbp_write(rt2x00dev, 84, 0x19); ++ } ++ + if (rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { + rt2800usb_bbp_write(rt2x00dev, 70, 0x0a); + rt2800usb_bbp_write(rt2x00dev, 84, 0x99); @@ -1651,11 +1699,9 @@ Signed-off-by: Ivo van Doorn + + rt2800usb_rfcsr_write(rt2x00dev, 24, rfcsr24); + -+ if (bw40) { -+ rt2800usb_bbp_read(rt2x00dev, 4, &bbp); -+ rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0x10); -+ rt2800usb_bbp_write(rt2x00dev, 4, bbp); -+ } ++ rt2800usb_bbp_read(rt2x00dev, 4, &bbp); ++ rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * bw40); ++ rt2800usb_bbp_write(rt2x00dev, 4, bbp); + + rt2800usb_rfcsr_read(rt2x00dev, 22, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 1); @@ -1960,7 +2006,7 @@ Signed-off-by: Ivo van Doorn +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + __le32 *txi = skbdesc->desc; -+ __le32 *txwi = txi + TXINFO_DESC_SIZE; ++ __le32 *txwi = &txi[TXINFO_DESC_SIZE / sizeof(__le32)]; + u32 word; + + /* @@ -1968,7 +2014,6 @@ Signed-off-by: Ivo van Doorn + */ + rt2x00_desc_read(txwi, 0, &word); + rt2x00_set_field32(&word, TXWI_W0_FRAG, -+ test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags) || + test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0); + rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0); @@ -1993,24 +2038,32 @@ Signed-off-by: Ivo van Doorn + rt2x00_set_field32(&word, TXWI_W1_NSEQ, + test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); + rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size); -+ rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, 0xff); ++ rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, ++ test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ? ++ txdesc->key_idx : 0xff); + rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, skb->len); + rt2x00_set_field32(&word, TXWI_W1_PACKETID, + skbdesc->entry->entry_idx); + rt2x00_desc_write(txwi, 1, word); + -+ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { -+ _rt2x00_desc_write(txwi, 2, skbdesc->iv[0]); -+ _rt2x00_desc_write(txwi, 3, skbdesc->iv[1]); -+ } ++ /* ++ * Always write 0 to IV/EIV fields, hardware will insert the IV ++ * from the IVEIV register when TXINFO_W0_WIV is set to 0. ++ * When TXINFO_W0_WIV is set to 1 it will use the IV data ++ * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which ++ * crypto entry in the registers should be used to encrypt the frame. ++ */ ++ _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */); ++ _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */); + + /* + * Initialize TX descriptor + */ + rt2x00_desc_read(txi, 0, &word); + rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN, -+ roundup(skb->len + TXWI_DESC_SIZE, 4)); -+ rt2x00_set_field32(&word, TXINFO_W0_WIV, 1); ++ skb->len + TXWI_DESC_SIZE); ++ rt2x00_set_field32(&word, TXINFO_W0_WIV, ++ !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags)); + rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2); + rt2x00_set_field32(&word, TXINFO_W0_SW_USE_LAST_ROUND, 0); + rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_NEXT_VALID, 0); @@ -2067,10 +2120,11 @@ Signed-off-by: Ivo van Doorn + int length; + + /* -+ * The length _must_ be a multiple of 4, ++ * The length _must_ include 4 bytes padding, ++ * it should always be multiple of 4, + * but it must _not_ be a multiple of the USB packet size. + */ -+ length = roundup(entry->skb->len, 4); ++ length = roundup(entry->skb->len + 4, 4); + length += (4 * !(length % entry->queue->usb_maxpacket)); + + return length; @@ -2104,7 +2158,7 @@ Signed-off-by: Ivo van Doorn + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + __le32 *rxd = (__le32 *)entry->skb->data; -+ __le32 *rxwi = (__le32 *)(entry->skb->data + skbdesc->desc_len); ++ __le32 *rxwi; + u32 rxd0; + u32 rxwi0; + u32 rxwi1; @@ -2117,6 +2171,7 @@ Signed-off-by: Ivo van Doorn + */ + memcpy(skbdesc->desc, rxd, skbdesc->desc_len); + rxd = (__le32 *)skbdesc->desc; ++ rxwi = &rxd[RXD_DESC_SIZE / sizeof(__le32)]; + + /* + * It is now safe to read the descriptor on all architectures. @@ -2180,8 +2235,7 @@ Signed-off-by: Ivo van Doorn + + rxdesc->rssi = + (rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) + -+ rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1) + -+ rt2x00_get_field32(rxwi2, RXWI_W2_RSSI2)) / 3; ++ rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2; + + rxdesc->noise = + (rt2x00_get_field32(rxwi3, RXWI_W3_SNR0) + @@ -2192,7 +2246,7 @@ Signed-off-by: Ivo van Doorn + /* + * Remove RXWI descriptor from start of buffer. + */ -+ skb_pull(entry->skb, RXWI_DESC_SIZE + skbdesc->desc_len); ++ skb_pull(entry->skb, skbdesc->desc_len); + skb_trim(entry->skb, rxdesc->size); +} + @@ -2225,6 +2279,13 @@ Signed-off-by: Ivo van Doorn + rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); + rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); ++ } else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { ++ /* ++ * There is a max of 2 RX streams for RT2860 series ++ */ ++ if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2) ++ rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2); ++ rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); + } + + rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word); @@ -2322,7 +2383,8 @@ Signed-off-by: Ivo van Doorn + * identifies itself as rt2860 in the CSR register. + */ + if ((rt2x00_get_field32(reg, MAC_CSR0_ASIC_VER) != 0x2860) && -+ (rt2x00_get_field32(reg, MAC_CSR0_ASIC_VER) != 0x2870)) { ++ (rt2x00_get_field32(reg, MAC_CSR0_ASIC_VER) != 0x2870) && ++ (rt2x00_get_field32(reg, MAC_CSR0_ASIC_VER) != 0x3070)) { + ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); + return -ENODEV; + } @@ -2475,6 +2537,7 @@ Signed-off-by: Ivo van Doorn + char *tx_power1; + char *tx_power2; + unsigned int i; ++ u16 eeprom; + + /* + * Initialize all hw fields. @@ -2491,6 +2554,8 @@ Signed-off-by: Ivo van Doorn + rt2x00_eeprom_addr(rt2x00dev, + EEPROM_MAC_ADDR_0)); + ++ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom); ++ + /* + * Initialize HT information. + */ @@ -2505,10 +2570,22 @@ Signed-off-by: Ivo van Doorn + IEEE80211_HT_CAP_PSMP_SUPPORT; + spec->ht.ampdu_factor = 3; + spec->ht.ampdu_density = 4; -+ spec->ht.mcs.rx_mask[0] = 0xff; -+ spec->ht.mcs.rx_mask[1] = 0xff; + spec->ht.mcs.tx_params = -+ IEEE80211_HT_MCS_TX_DEFINED; ++ IEEE80211_HT_MCS_TX_DEFINED | ++ IEEE80211_HT_MCS_TX_RX_DIFF | ++ ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) << ++ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); ++ ++ switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) { ++ case 3: ++ spec->ht.mcs.rx_mask[2] = 0xff; ++ case 2: ++ spec->ht.mcs.rx_mask[1] = 0xff; ++ case 1: ++ spec->ht.mcs.rx_mask[0] = 0xff; ++ spec->ht.mcs.rx_mask[4] = 0x1; /* MCS32 */ ++ break; ++ } + + /* + * Initialize hw_mode information. @@ -2602,6 +2679,21 @@ Signed-off-by: Ivo van Doorn +/* + * IEEE80211 stack callback functions. + */ ++static void rt2800usb_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, ++ u32 *iv32, u16 *iv16) ++{ ++ struct rt2x00_dev *rt2x00dev = hw->priv; ++ struct mac_iveiv_entry iveiv_entry; ++ u32 offset; ++ ++ offset = MAC_IVEIV_ENTRY(hw_key_idx); ++ rt2x00usb_register_multiread(rt2x00dev, offset, ++ &iveiv_entry, sizeof(iveiv_entry)); ++ ++ memcpy(&iveiv_entry.iv[0], iv16, sizeof(iv16)); ++ memcpy(&iveiv_entry.iv[4], iv32, sizeof(iv32)); ++} ++ +static int rt2800usb_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; @@ -2706,13 +2798,6 @@ Signed-off-by: Ivo van Doorn + return 0; +} + -+#if 0 -+/* -+ * Mac80211 demands get_tsf must be atomic. -+ * This is not possible for rt2800usb since all register access -+ * functions require sleeping. Untill mac80211 no longer needs -+ * get_tsf to be atomic, this function should be disabled. -+ */ +static u64 rt2800usb_get_tsf(struct ieee80211_hw *hw) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; @@ -2726,9 +2811,6 @@ Signed-off-by: Ivo van Doorn + + return tsf; +} -+#else -+#define rt2800usb_get_tsf NULL -+#endif + +static const struct ieee80211_ops rt2800usb_mac80211_ops = { + .tx = rt2x00mac_tx, @@ -2741,6 +2823,7 @@ Signed-off-by: Ivo van Doorn + .configure_filter = rt2x00mac_configure_filter, + .set_key = rt2x00mac_set_key, + .get_stats = rt2x00mac_get_stats, ++ .get_tkip_seq = rt2800usb_get_tkip_seq, + .set_rts_threshold = rt2800usb_set_rts_threshold, + .bss_info_changed = rt2x00mac_bss_info_changed, + .conf_tx = rt2800usb_conf_tx, @@ -2751,7 +2834,7 @@ Signed-off-by: Ivo van Doorn +static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { + .probe_hw = rt2800usb_probe_hw, + .get_firmware_name = rt2800usb_get_firmware_name, -+ .get_firmware_crc = rt2800usb_get_firmware_crc, ++ .check_firmware = rt2800usb_check_firmware, + .load_firmware = rt2800usb_load_firmware, + .initialize = rt2x00usb_initialize, + .uninitialize = rt2x00usb_uninitialize, @@ -2766,6 +2849,7 @@ Signed-off-by: Ivo van Doorn + .write_beacon = rt2800usb_write_beacon, + .get_tx_data_len = rt2800usb_get_tx_data_len, + .kick_tx_queue = rt2800usb_kick_tx_queue, ++ .kill_tx_queue = rt2x00usb_kill_tx_queue, + .fill_rxdone = rt2800usb_fill_rxdone, + .config_shared_key = rt2800usb_config_shared_key, + .config_pairwise_key = rt2800usb_config_pairwise_key, @@ -2778,14 +2862,14 @@ Signed-off-by: Ivo van Doorn + +static const struct data_queue_desc rt2800usb_queue_rx = { + .entry_num = RX_ENTRIES, -+ .data_size = DATA_FRAME_SIZE, -+ .desc_size = RXD_DESC_SIZE, ++ .data_size = AGGREGATION_SIZE, ++ .desc_size = RXD_DESC_SIZE + RXWI_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb), +}; + +static const struct data_queue_desc rt2800usb_queue_tx = { + .entry_num = TX_ENTRIES, -+ .data_size = DATA_FRAME_SIZE, ++ .data_size = AGGREGATION_SIZE, + .desc_size = TXINFO_DESC_SIZE + TXWI_DESC_SIZE, + .priv_size = sizeof(struct queue_entry_priv_usb), +}; @@ -2819,22 +2903,35 @@ Signed-off-by: Ivo van Doorn + */ +static struct usb_device_id rt2800usb_device_table[] = { + /* Abocom */ -+ { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, -+ { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ /* AirTies */ ++ { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ /* Amigo */ ++ { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Amit */ + { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* ASUS */ + { USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* AzureWave */ + { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Belkin */ + { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ /* Buffalo */ ++ { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Conceptronic */ + { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -2848,35 +2945,61 @@ Signed-off-by: Ivo van Doorn + { USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* D-Link */ + { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x2001, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x2001, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Edimax */ + { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* EnGenius */ + { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ /* Gemtek */ ++ { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Gigabyte */ + { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Hawking */ + { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ /* LevelOne */ ++ { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Linksys */ + { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Logitec */ + { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ /* Pegatron */ ++ { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Philips */ + { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Planex */ + { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ /* Qcom */ ++ { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ /* Quanta */ ++ { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Ralink */ ++ { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Samsung */ + { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Siemens */ @@ -2886,9 +3009,18 @@ Signed-off-by: Ivo van Doorn + { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0df6, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* SMC */ + { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) }, ++ { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Sparklan */ @@ -2937,7 +3069,7 @@ Signed-off-by: Ivo van Doorn +module_exit(rt2800usb_exit); --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2800usb.h -@@ -0,0 +1,1944 @@ +@@ -0,0 +1,1932 @@ +/* + Copyright (C) 2004 - 2009 rt2x00 SourceForge Project + @@ -3008,8 +3140,8 @@ Signed-off-by: Ivo van Doorn +#define EEPROM_SIZE 0x0110 +#define BBP_BASE 0x0000 +#define BBP_SIZE 0x0080 -+#define RF_BASE 0x0000 -+#define RF_SIZE 0x0014 ++#define RF_BASE 0x0004 ++#define RF_SIZE 0x0010 + +/* + * Number of TX queues. @@ -3169,11 +3301,6 @@ Signed-off-by: Ivo van Doorn +#define WMM_TXOP1_CFG_AC3TXOP FIELD32(0xffff0000) + +/* -+ * RINGREG_DIFF -+ */ -+#define RINGREG_DIFF 0x0010 -+ -+/* + * GPIO_CTRL_CFG: + */ +#define GPIO_CTRL_CFG 0x0228 @@ -3748,6 +3875,7 @@ Signed-off-by: Ivo van Doorn + * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz + */ +#define TX_BAND_CFG 0x132c ++#define TX_BAND_CFG_HT40_PLUS FIELD32(0x00000001) +#define TX_BAND_CFG_A FIELD32(0x00000002) +#define TX_BAND_CFG_BG FIELD32(0x00000004) + @@ -4158,7 +4286,7 @@ Signed-off-by: Ivo van Doorn + * TX_STA_FIFO: TX Result for specific PID status fifo register + */ +#define TX_STA_FIFO 0x1718 -+#define TX_STA_FIFO_B_VALID FIELD32(0x00000001) ++#define TX_STA_FIFO_VALID FIELD32(0x00000001) +#define TX_STA_FIFO_PID_TYPE FIELD32(0x0000001e) +#define TX_STA_FIFO_TX_SUCCESS FIELD32(0x00000020) +#define TX_STA_FIFO_TX_AGGRE FIELD32(0x00000040) @@ -4239,64 +4367,54 @@ Signed-off-by: Ivo van Doorn +#define MPDU_DENSITY_CNT_RX_ZERO_DEL FIELD32(0xffff0000) + +/* -+ * Security key table memory, base address = 0x1800 -+ */ -+struct hw_pairwise_ta_entry { -+ u8 address[6]; -+ u8 reserved[2]; -+} __attribute__ ((packed)); -+ -+struct wcid_entry { -+ u8 rx_ba_bitmat7; -+ u8 rx_ba_bitmat0; -+ u8 mac[6]; -+} __attribute__ ((packed)); -+ -+struct hw_key_entry { -+ u8 key[16]; -+ u8 tx_mic[8]; -+ u8 rx_mic[8]; -+} __attribute__ ((packed)); -+ -+/* + * Security key table memory. + * MAC_WCID_BASE: 8-bytes (use only 6 bytes) * 256 entry + * PAIRWISE_KEY_TABLE_BASE: 32-byte * 256 entry -+ * PAIRWISE_IVEIV_TABLE_BASE: 8-byte * 256-entry + * MAC_IVEIV_TABLE_BASE: 8-byte * 256-entry + * MAC_WCID_ATTRIBUTE_BASE: 4-byte * 256-entry + * SHARED_KEY_TABLE_BASE: 32-byte * 16-entry -+ * SHARED_KEY_MODE_BASE: 32-byte * 16-entry ++ * SHARED_KEY_MODE_BASE: 4-byte * 16-entry + */ +#define MAC_WCID_BASE 0x1800 +#define PAIRWISE_KEY_TABLE_BASE 0x4000 -+#define PAIRWISE_IVEIV_TABLE_BASE 0x6000 +#define MAC_IVEIV_TABLE_BASE 0x6000 +#define MAC_WCID_ATTRIBUTE_BASE 0x6800 +#define SHARED_KEY_TABLE_BASE 0x6c00 +#define SHARED_KEY_MODE_BASE 0x7000 + ++#define MAC_WCID_ENTRY(__idx) \ ++ ( MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry)) ) ++#define PAIRWISE_KEY_ENTRY(__idx) \ ++ ( PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) ++#define MAC_IVEIV_ENTRY(__idx) \ ++ ( MAC_IVEIV_TABLE_BASE + ((__idx) & sizeof(struct mac_iveiv_entry)) ) ++#define MAC_WCID_ATTR_ENTRY(__idx) \ ++ ( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) ) +#define SHARED_KEY_ENTRY(__idx) \ -+ ( SHARED_KEY_TABLE_BASE + \ -+ ((__idx) * sizeof(struct hw_key_entry)) ) ++ ( SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) +#define SHARED_KEY_MODE_ENTRY(__idx) \ + ( SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32)) ) -+#define PAIRWISE_KEY_ENTRY(__idx) \ -+ ( PAIRWISE_KEY_TABLE_BASE + \ -+ ((__idx) * sizeof(struct hw_key_entry)) ) + -+#define MAC_WCID_ENTRY(__idx) \ -+ ( MAC_WCID_BASE + (2 * sizeof(u32) * (__idx)) ) -+#define MAC_WCID_ATTR_ENTRY(__idx) \ -+ ( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) ) ++struct mac_wcid_entry { ++ u8 mac[6]; ++ u8 reserved[2]; ++} __attribute__ ((packed)); ++ ++struct hw_key_entry { ++ u8 key[16]; ++ u8 tx_mic[8]; ++ u8 rx_mic[8]; ++} __attribute__ ((packed)); ++ ++struct mac_iveiv_entry { ++ u8 iv[8]; ++} __attribute__ ((packed)); + +/* + * MAC_WCID_ATTRIBUTE: -+ * KEYTAB: 0: shared key table, 1: pairwise key table -+ * BSS_IDX: multipleBSS index for the WCID + */ +#define MAC_WCID_ATTRIBUTE_KEYTAB FIELD32(0x00000001) -+#define MAC_WCID_ATTRIBUTE_PAIRKEY_MODE FIELD32(0x0000000e) ++#define MAC_WCID_ATTRIBUTE_CIPHER FIELD32(0x0000000e) +#define MAC_WCID_ATTRIBUTE_BSS_IDX FIELD32(0x00000070) +#define MAC_WCID_ATTRIBUTE_RX_WIUDF FIELD32(0x00000380) + @@ -4385,7 +4503,7 @@ Signed-off-by: Ivo van Doorn +/* + * HW_BEACON_BASE + * In order to support maximum 8 MBSS and its maximum length -+ * is 512 bytes for each beacon ++ * is 512 bytes for each beacon + * Three section discontinue memory segments will be used. + * 1. The original region for BCN 0~3 + * 2. Extract memory from FCE table for BCN 4~5 @@ -4431,10 +4549,12 @@ Signed-off-by: Ivo van Doorn + * BBP 3: RX Antenna + */ +#define BBP3_RX_ANTENNA FIELD8(0x18) ++#define BBP3_HT40_PLUS FIELD8(0x20) + +/* + * BBP 4: Bandwidth + */ ++#define BBP4_TX_BF FIELD8(0x01) +#define BBP4_BANDWIDTH FIELD8(0x18) + +/* @@ -4497,7 +4617,7 @@ Signed-off-by: Ivo van Doorn +#define RF4_TXPOWER_A_7DBM_BOOST FIELD32(0x00000040) +#define RF4_TXPOWER_A FIELD32(0x00000780) +#define RF4_FREQ_OFFSET FIELD32(0x001f8000) -+#define RF4_BW40 FIELD32(0x00200000) ++#define RF4_HT40 FIELD32(0x00200000) + +/* + * EEPROM content. @@ -4884,7 +5004,7 @@ Signed-off-by: Ivo van Doorn +#endif /* RT2800USB_H */ --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h -@@ -143,6 +143,7 @@ struct rt2x00_chip { +@@ -142,6 +142,7 @@ struct rt2x00_chip { #define RT2860D 0x0681 /* 2.4GHz, 5GHz PCI/CB */ #define RT2890 0x0701 /* 2.4GHz PCIe */ #define RT2890D 0x0781 /* 2.4GHz, 5GHz PCIe */ @@ -4892,7 +5012,7 @@ Signed-off-by: Ivo van Doorn u16 rf; u32 rev; -@@ -778,6 +779,12 @@ struct rt2x00_dev { +@@ -780,6 +781,12 @@ struct rt2x00_dev { u8 freq_offset; /*