diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt73usb.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt73usb.c | 126 |
1 files changed, 75 insertions, 51 deletions
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index efc18de16fa1..46b040bf62de 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -24,6 +24,7 @@ Supported chipsets: rt2571W & rt2671. */ +#include <linux/crc-itu-t.h> #include <linux/delay.h> #include <linux/etherdevice.h> #include <linux/init.h> @@ -292,7 +293,8 @@ static void rt73usb_led_brightness(struct led_classdev *led_cdev, if (in_atomic()) { NOTICE(led->rt2x00dev, - "Ignoring LED brightness command for led %d", led->type); + "Ignoring LED brightness command for led %d\n", + led->type); return; } @@ -347,7 +349,6 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, * bits which (when set to 0) will invalidate the entire beacon. */ beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0); rt73usb_register_write(rt2x00dev, beacon_base, 0); /* @@ -355,10 +356,8 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, */ rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, - (conf->sync == TSF_SYNC_BEACON)); - rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -381,10 +380,8 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, } } -static int rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev, - const int short_preamble, - const int ack_timeout, - const int ack_consume_time) +static int rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_erp *erp) { u32 reg; @@ -396,12 +393,12 @@ static int rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev, return -EAGAIN; rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout); + rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, - !!short_preamble); + !!erp->short_preamble); rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); return 0; @@ -500,14 +497,8 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, else rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); 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: + default: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) @@ -548,14 +539,8 @@ static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); 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: + default: rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); break; @@ -605,6 +590,13 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, unsigned int i; u32 reg; + /* + * We should never come here because rt2x00lib is supposed + * to catch this and send us the correct antenna explicitely. + */ + BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY || + ant->tx == ANTENNA_SW_DIVERSITY); + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { sel = antenna_sel_a; lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); @@ -821,16 +813,30 @@ dynamic_cca_tune: } /* - * Firmware name function. + * Firmware functions */ static char *rt73usb_get_firmware_name(struct rt2x00_dev *rt2x00dev) { return FIRMWARE_RT2571; } -/* - * Initialization functions. - */ +static u16 rt73usb_get_firmware_crc(void *data, const size_t len) +{ + u16 crc; + + /* + * Use the crc itu-t algorithm. + * 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_itu_t(0, data, len - 2); + crc = crc_itu_t_byte(crc, 0); + crc = crc_itu_t_byte(crc, 0); + + return crc; +} + static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, const size_t len) { @@ -900,6 +906,9 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, return 0; } +/* + * Initialization functions. + */ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; @@ -1312,6 +1321,8 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) { + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -1370,12 +1381,21 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, { struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = (__le32 *)entry->skb->data; - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *)entry->skb->data + entry->queue->desc_size; - int header_size = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); + unsigned int offset = entry->queue->desc_size + 2; u32 word0; u32 word1; + /* + * Copy descriptor to the available headroom inside the skbuffer. + */ + skb_push(entry->skb, offset); + memcpy(entry->skb->data, rxd, entry->queue->desc_size); + rxd = (__le32 *)entry->skb->data; + + /* + * The descriptor is now aligned to 4 bytes and thus it is + * now safe to read it on all architectures. + */ rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); @@ -1385,37 +1405,30 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, /* * Obtain the status about this packet. + * When frame was received with an OFDM bitrate, + * the signal is the PLCP value. If it was received with + * a CCK bitrate the signal is the rate in 100kbit/s. */ + rxdesc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + rxdesc->signal_plcp = rxdesc->ofdm; rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1); - rxdesc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); rxdesc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS); /* - * The data behind the ieee80211 header must be - * aligned on a 4 byte boundary. + * Adjust the skb memory window to the frame boundaries. */ - if (header_size % 4 == 0) { - skb_push(entry->skb, 2); - memmove(entry->skb->data, entry->skb->data + 2, - entry->skb->len - 2); - } + skb_pull(entry->skb, offset + entry->queue->desc_size); + skb_trim(entry->skb, rxdesc->size); /* * Set descriptor and data pointer. */ - skbdesc->data = entry->skb->data + entry->queue->desc_size; + skbdesc->data = entry->skb->data; skbdesc->data_len = rxdesc->size; - skbdesc->desc = entry->skb->data; + skbdesc->desc = rxd; skbdesc->desc_len = entry->queue->desc_size; - - /* - * Remove descriptor from skb buffer and trim the whole thing - * down to only contain data. - */ - skb_pull(entry->skb, skbdesc->desc_len); - skb_trim(entry->skb, rxdesc->size); } /* @@ -1856,7 +1869,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) * This device requires firmware. */ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(DRIVER_REQUIRE_FIRMWARE_CRC_ITU_T, &rt2x00dev->flags); /* * Set the rssi offset. @@ -1989,6 +2001,7 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct skb_frame_desc *skbdesc; unsigned int beacon_base; unsigned int timeout; + u32 reg; if (unlikely(!intf->beacon)) return -ENOBUFS; @@ -2012,6 +2025,16 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, skbdesc->entry = intf->beacon; /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + + /* * mac80211 doesn't provide the control->queue variable * for beacons. Set our own queue identification so * it can be used during descriptor initialization. @@ -2054,6 +2077,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .probe_hw = rt73usb_probe_hw, .get_firmware_name = rt73usb_get_firmware_name, + .get_firmware_crc = rt73usb_get_firmware_crc, .load_firmware = rt73usb_load_firmware, .initialize = rt2x00usb_initialize, .uninitialize = rt2x00usb_uninitialize, @@ -2070,7 +2094,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .kick_tx_queue = rt73usb_kick_tx_queue, .fill_rxdone = rt73usb_fill_rxdone, .config_intf = rt73usb_config_intf, - .config_preamble = rt73usb_config_preamble, + .config_erp = rt73usb_config_erp, .config = rt73usb_config, }; |