X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/060c85b4cbcec4bd77bf5485c6bbc7539aecb62b..f11c8d92017610e27db2dafc75f7c592fbd20f45:/package/rt2x00/src/rt2x00dev.c diff --git a/package/rt2x00/src/rt2x00dev.c b/package/rt2x00/src/rt2x00dev.c index 448f1bcad..ff399f808 100644 --- a/package/rt2x00/src/rt2x00dev.c +++ b/package/rt2x00/src/rt2x00dev.c @@ -21,8 +21,6 @@ /* Module: rt2x00lib Abstract: rt2x00 generic device routines. - Supported chipsets: RT2460, RT2560, RT2570, - rt2561, rt2561s, rt2661, rt2571W & rt2671. */ /* @@ -32,13 +30,67 @@ #include #include -#include -#include -#include -#include #include "rt2x00.h" -#include "rt2x00dev.h" +#include "rt2x00lib.h" + +/* + * Ring handler. + */ +struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev, + const unsigned int queue) +{ + int beacon = test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags); + + /* + * Check if we are requesting a reqular TX ring, + * or if we are requesting a Beacon or Atim ring. + * For Atim rings, we should check if it is supported. + */ + if (queue < rt2x00dev->hw->queues && rt2x00dev->tx) + return &rt2x00dev->tx[queue]; + + if (!rt2x00dev->bcn || !beacon) + return NULL; + + if (queue == IEEE80211_TX_QUEUE_BEACON) + return &rt2x00dev->bcn[0]; + else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) + return &rt2x00dev->bcn[1]; + + return NULL; +} +EXPORT_SYMBOL_GPL(rt2x00lib_get_ring); + +/* + * Link tuning handlers + */ +static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + rt2x00_clear_link(&rt2x00dev->link); + + /* + * Reset the link tuner. + */ + rt2x00dev->ops->lib->reset_tuner(rt2x00dev); + + queue_delayed_work(rt2x00dev->hw->workqueue, + &rt2x00dev->link.work, LINK_TUNE_INTERVAL); +} + +static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + cancel_delayed_work_sync(&rt2x00dev->link.work); +} + +void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev) +{ + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return; + + rt2x00lib_stop_link_tuner(rt2x00dev); + rt2x00lib_start_link_tuner(rt2x00dev); +} /* * Radio control handlers. @@ -49,22 +101,30 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Don't enable the radio twice. - * or if the hardware button has been disabled. + * And check if the hardware button has been disabled. */ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - (test_bit(DEVICE_SUPPORT_HW_BUTTON, &rt2x00dev->flags) && - !test_bit(DEVICE_ENABLED_RADIO_HW, &rt2x00dev->flags))) + test_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags)) return 0; - status = rt2x00dev->ops->lib->set_device_state( - rt2x00dev, STATE_RADIO_ON); + /* + * Enable radio. + */ + status = rt2x00dev->ops->lib->set_device_state(rt2x00dev, + STATE_RADIO_ON); if (status) return status; __set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags); - rt2x00lib_toggle_rx(rt2x00dev, 1); + /* + * Enable RX. + */ + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); + /* + * Start the TX queues. + */ ieee80211_start_queues(rt2x00dev->hw); return 0; @@ -75,166 +135,447 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) return; + /* + * Stop all scheduled work. + */ + if (work_pending(&rt2x00dev->beacon_work)) + cancel_work_sync(&rt2x00dev->beacon_work); + if (work_pending(&rt2x00dev->filter_work)) + cancel_work_sync(&rt2x00dev->filter_work); + if (work_pending(&rt2x00dev->config_work)) + cancel_work_sync(&rt2x00dev->config_work); + + /* + * Stop the TX queues. + */ ieee80211_stop_queues(rt2x00dev->hw); - rt2x00lib_toggle_rx(rt2x00dev, 0); + /* + * Disable RX. + */ + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); + /* + * Disable radio. + */ rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_OFF); } -void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, int enable) +void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) +{ + /* + * When we are disabling the RX, we should also stop the link tuner. + */ + if (state == STATE_RADIO_RX_OFF) + rt2x00lib_stop_link_tuner(rt2x00dev); + + rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); + + /* + * When we are enabling the RX, we should also start the link tuner. + */ + if (state == STATE_RADIO_RX_ON && + is_interface_present(&rt2x00dev->interface)) + rt2x00lib_start_link_tuner(rt2x00dev); +} + +static void rt2x00lib_precalculate_link_signal(struct link *link) +{ + if (link->rx_failed || link->rx_success) + link->rx_percentage = + (link->rx_success * 100) / + (link->rx_failed + link->rx_success); + else + link->rx_percentage = 50; + + if (link->tx_failed || link->tx_success) + link->tx_percentage = + (link->tx_success * 100) / + (link->tx_failed + link->tx_success); + else + link->tx_percentage = 50; + + link->rx_success = 0; + link->rx_failed = 0; + link->tx_success = 0; + link->tx_failed = 0; +} + +static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev, + int rssi) { + int rssi_percentage = 0; + int signal; + /* - * When we are disabling the rx, we should also stop the link tuner. + * We need a positive value for the RSSI. */ - if (!enable && work_pending(&rt2x00dev->link.work.work)) - rt2x00_stop_link_tune(rt2x00dev); + if (rssi < 0) + rssi += rt2x00dev->rssi_offset; - rt2x00dev->ops->lib->set_device_state(rt2x00dev, - enable ? STATE_RADIO_RX_ON : STATE_RADIO_RX_OFF); + /* + * Calculate the different percentages, + * which will be used for the signal. + */ + if (rt2x00dev->rssi_offset) + rssi_percentage = (rssi * 100) / rt2x00dev->rssi_offset; /* - * When we are enabling the rx, we should also start the link tuner. + * Add the individual percentages and use the WEIGHT + * defines to calculate the current link signal. */ - if (enable) - rt2x00_start_link_tune(rt2x00dev); + signal = ((WEIGHT_RSSI * rssi_percentage) + + (WEIGHT_TX * rt2x00dev->link.tx_percentage) + + (WEIGHT_RX * rt2x00dev->link.rx_percentage)) / 100; + + return (signal > 100) ? 100 : signal; } static void rt2x00lib_link_tuner(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = - container_of(work, struct rt2x00_dev, link.work.work); - int rssi; + container_of(work, struct rt2x00_dev, link.work.work); /* - * Update promisc mode (this function will first check - * if updating is really required). + * When the radio is shutting down we should + * immediately cease all link tuning. */ - rt2x00lib_config_promisc(rt2x00dev, rt2x00dev->interface.promisc); + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return; /* - * Cancel all link tuning if the eeprom has indicated - * it is not required. + * Update statistics. */ - if (test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags)) - return; + rt2x00dev->ops->lib->link_stats(rt2x00dev); + + rt2x00dev->low_level_stats.dot11FCSErrorCount += + rt2x00dev->link.rx_failed; /* - * Retrieve link quality. - * Also convert rssi to dBm using the max_rssi value. + * Only perform the link tuning when Link tuning + * has been enabled (This could have been disabled from the EEPROM). */ - rssi = rt2x00_get_link_rssi(&rt2x00dev->link); - rssi -= rt2x00dev->hw->max_rssi; + if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags)) + rt2x00dev->ops->lib->link_tuner(rt2x00dev); - rt2x00dev->ops->lib->link_tuner(rt2x00dev, rssi); + /* + * Precalculate a portion of the link signal which is + * in based on the tx/rx success/failure counters. + */ + rt2x00lib_precalculate_link_signal(&rt2x00dev->link); /* * Increase tuner counter, and reschedule the next link tuner run. */ rt2x00dev->link.count++; - queue_delayed_work(rt2x00dev->workqueue, &rt2x00dev->link.work, - LINK_TUNE_INTERVAL); + queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work, + LINK_TUNE_INTERVAL); } -/* - * Config handlers - */ -void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type) +static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) { - if (!(is_interface_present(&rt2x00dev->interface) ^ - test_bit(INTERFACE_ENABLED, &rt2x00dev->flags)) && - !(is_monitor_present(&rt2x00dev->interface) ^ - test_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags))) - return; + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, filter_work); + unsigned int filter = rt2x00dev->interface.filter; - rt2x00dev->ops->lib->config_type(rt2x00dev, type); + /* + * Since we had stored the filter inside interface.filter, + * we should now clear that field. Otherwise the driver will + * assume nothing has changed (*total_flags will be compared + * to interface.filter to determine if any action is required). + */ + rt2x00dev->interface.filter = 0; - if (type != IEEE80211_IF_TYPE_MNTR) { - if (is_interface_present(&rt2x00dev->interface)) - __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags); - else - __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags); - } else { - if (is_monitor_present(&rt2x00dev->interface)) - __set_bit(INTERFACE_ENABLED_MONITOR, - &rt2x00dev->flags); - else - __clear_bit(INTERFACE_ENABLED_MONITOR, - &rt2x00dev->flags); - } + rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw, + filter, &filter, 0, NULL); } -void rt2x00lib_config_phymode(struct rt2x00_dev *rt2x00dev, const int phymode) +static void rt2x00lib_configuration_scheduled(struct work_struct *work) { - if (rt2x00dev->rx_status.phymode == phymode) - return; - - rt2x00dev->ops->lib->config_phymode(rt2x00dev, phymode); + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, config_work); + int preamble = !test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); - rt2x00dev->rx_status.phymode = phymode; + rt2x00mac_erp_ie_changed(rt2x00dev->hw, + IEEE80211_ERP_CHANGE_PREAMBLE, 0, preamble); } -void rt2x00lib_config_channel(struct rt2x00_dev *rt2x00dev, const int value, - const int channel, const int freq, const int txpower) +/* + * Interrupt context handlers. + */ +static void rt2x00lib_beacondone_scheduled(struct work_struct *work) { - if (channel == rt2x00dev->rx_status.channel) + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, beacon_work); + struct data_ring *ring = + rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + struct data_entry *entry = rt2x00_get_data_entry(ring); + struct sk_buff *skb; + + skb = ieee80211_beacon_get(rt2x00dev->hw, + rt2x00dev->interface.id, + &entry->tx_status.control); + if (!skb) return; - rt2x00dev->ops->lib->config_channel(rt2x00dev, value, channel, txpower); + rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb, + &entry->tx_status.control); + + dev_kfree_skb(skb); +} - INFO(rt2x00dev, "Switching channel. " - "RF1: 0x%08x, RF2: 0x%08x, RF3: 0x%08x, RF3: 0x%08x.\n", - rt2x00dev->rf1, rt2x00dev->rf2, - rt2x00dev->rf3, rt2x00dev->rf4); +void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) +{ + if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + return; - rt2x00dev->rx_status.freq = freq; - rt2x00dev->rx_status.channel = channel; + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->beacon_work); } +EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); -void rt2x00lib_config_promisc(struct rt2x00_dev *rt2x00dev, const int promisc) +void rt2x00lib_txdone(struct data_entry *entry, + const int status, const int retry) { + struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev; + struct ieee80211_tx_status *tx_status = &entry->tx_status; + struct ieee80211_low_level_stats *stats = &rt2x00dev->low_level_stats; + int success = !!(status == TX_SUCCESS || status == TX_SUCCESS_RETRY); + int fail = !!(status == TX_FAIL_RETRY || status == TX_FAIL_INVALID || + status == TX_FAIL_OTHER); + /* - * Monitor mode implies promisc mode enabled. - * In all other instances, check if we need to toggle promisc mode. + * Update TX statistics. */ - if (is_monitor_present(&rt2x00dev->interface) && - !test_bit(INTERFACE_ENABLED_PROMISC, &rt2x00dev->flags)) { - rt2x00dev->ops->lib->config_promisc(rt2x00dev, 1); - __set_bit(INTERFACE_ENABLED_PROMISC, &rt2x00dev->flags); + tx_status->flags = 0; + tx_status->ack_signal = 0; + tx_status->excessive_retries = (status == TX_FAIL_RETRY); + tx_status->retry_count = retry; + rt2x00dev->link.tx_success += success; + rt2x00dev->link.tx_failed += retry + fail; + + if (!(tx_status->control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (success) + tx_status->flags |= IEEE80211_TX_STATUS_ACK; + else + stats->dot11ACKFailureCount++; } - if (test_bit(INTERFACE_ENABLED_PROMISC, &rt2x00dev->flags) != promisc) { - rt2x00dev->ops->lib->config_promisc(rt2x00dev, promisc); - __change_bit(INTERFACE_ENABLED_PROMISC, &rt2x00dev->flags); + tx_status->queue_length = entry->ring->stats.limit; + tx_status->queue_number = tx_status->control.queue; + + if (tx_status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { + if (success) + stats->dot11RTSSuccessCount++; + else + stats->dot11RTSFailureCount++; } + + /* + * Send the tx_status to mac80211, + * that method also cleans up the skb structure. + */ + ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, tx_status); + entry->skb = NULL; } +EXPORT_SYMBOL_GPL(rt2x00lib_txdone); -void rt2x00lib_config_txpower(struct rt2x00_dev *rt2x00dev, const int txpower) +void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, + struct rxdata_entry_desc *desc) { - if (txpower == rt2x00dev->tx_power) - return; + struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev; + struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; + struct ieee80211_hw_mode *mode; + struct ieee80211_rate *rate; + unsigned int i; + int val = 0; + + /* + * Update RX statistics. + */ + mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; + for (i = 0; i < mode->num_rates; i++) { + rate = &mode->rates[i]; + + /* + * 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 0.5kbit/s. + */ + if (!desc->ofdm) + val = DEVICE_GET_RATE_FIELD(rate->val, RATE); + else + val = DEVICE_GET_RATE_FIELD(rate->val, PLCP); + + if (val == desc->signal) { + val = rate->val; + break; + } + } - rt2x00dev->ops->lib->config_txpower(rt2x00dev, txpower); + rt2x00_update_link_rssi(&rt2x00dev->link, desc->rssi); + rt2x00dev->link.rx_success++; + rx_status->rate = val; + rx_status->signal = + rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi); + rx_status->ssi = desc->rssi; + rx_status->flag = desc->flags; - rt2x00dev->tx_power = txpower; + /* + * Send frame to mac80211 + */ + ieee80211_rx_irqsafe(rt2x00dev->hw, skb, rx_status); } +EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); -void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, - const int antenna_tx, const int antenna_rx) +/* + * TX descriptor initializer + */ +void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, + struct data_desc *txd, + struct ieee80211_hdr *ieee80211hdr, + unsigned int length, + struct ieee80211_tx_control *control) { - if (rt2x00dev->rx_status.antenna == antenna_rx) - return; + struct txdata_entry_desc desc; + struct data_ring *ring; + int tx_rate; + int bitrate; + int duration; + int residual; + u16 frame_control; + u16 seq_ctrl; + + /* + * Make sure the descriptor is properly cleared. + */ + memset(&desc, 0x00, sizeof(desc)); + + /* + * Get ring pointer, if we fail to obtain the + * correct ring, then use the first TX ring. + */ + ring = rt2x00lib_get_ring(rt2x00dev, control->queue); + if (!ring) + ring = rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); + + desc.cw_min = ring->tx_params.cw_min; + desc.cw_max = ring->tx_params.cw_max; + desc.aifs = ring->tx_params.aifs; + + /* + * Identify queue + */ + if (control->queue < rt2x00dev->hw->queues) + desc.queue = control->queue; + else if (control->queue == IEEE80211_TX_QUEUE_BEACON || + control->queue == IEEE80211_TX_QUEUE_AFTER_BEACON) + desc.queue = QUEUE_MGMT; + else + desc.queue = QUEUE_OTHER; + + /* + * Read required fields from ieee80211 header. + */ + frame_control = le16_to_cpu(ieee80211hdr->frame_control); + seq_ctrl = le16_to_cpu(ieee80211hdr->seq_ctrl); + + tx_rate = control->tx_rate; + + /* + * Check if this is a RTS/CTS frame + */ + if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { + __set_bit(ENTRY_TXD_BURST, &desc.flags); + if (is_rts_frame(frame_control)) + __set_bit(ENTRY_TXD_RTS_FRAME, &desc.flags); + if (control->rts_cts_rate) + tx_rate = control->rts_cts_rate; + } + + /* + * Check for OFDM + */ + if (DEVICE_GET_RATE_FIELD(tx_rate, RATEMASK) & DEV_OFDM_RATEMASK) + __set_bit(ENTRY_TXD_OFDM_RATE, &desc.flags); + + /* + * Check if more fragments are pending + */ + if (ieee80211_get_morefrag(ieee80211hdr)) { + __set_bit(ENTRY_TXD_BURST, &desc.flags); + __set_bit(ENTRY_TXD_MORE_FRAG, &desc.flags); + } + + /* + * Beacons and probe responses require the tsf timestamp + * to be inserted into the frame. + */ + if (control->queue == IEEE80211_TX_QUEUE_BEACON || + is_probe_resp(frame_control)) + __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc.flags); + + /* + * Determine with what IFS priority this frame should be send. + * Set ifs to IFS_SIFS when the this is not the first fragment, + * or this fragment came after RTS/CTS. + */ + if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 || + test_bit(ENTRY_TXD_RTS_FRAME, &desc.flags)) + desc.ifs = IFS_SIFS; + else + desc.ifs = IFS_BACKOFF; + + /* + * PLCP setup + * Length calculation depends on OFDM/CCK rate. + */ + desc.signal = DEVICE_GET_RATE_FIELD(tx_rate, PLCP); + desc.service = 0x04; + + if (test_bit(ENTRY_TXD_OFDM_RATE, &desc.flags)) { + desc.length_high = ((length + FCS_LEN) >> 6) & 0x3f; + desc.length_low = ((length + FCS_LEN) & 0x3f); + } else { + bitrate = DEVICE_GET_RATE_FIELD(tx_rate, RATE); + + /* + * Convert length to microseconds. + */ + residual = get_duration_res(length + FCS_LEN, bitrate); + duration = get_duration(length + FCS_LEN, bitrate); + + if (residual != 0) { + duration++; + + /* + * Check if we need to set the Length Extension + */ + if (bitrate == 110 && residual <= 30) + desc.service |= 0x80; + } + + desc.length_high = (duration >> 8) & 0xff; + desc.length_low = duration & 0xff; - rt2x00dev->ops->lib->config_antenna(rt2x00dev, antenna_tx, antenna_rx); + /* + * When preamble is enabled we should set the + * preamble bit for the signal. + */ + if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE)) + desc.signal |= 0x08; + } - rt2x00dev->rx_status.antenna = antenna_rx; + rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, txd, &desc, + ieee80211hdr, length, control); } +EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc); /* * Driver initialization handlers. */ static void rt2x00lib_channel(struct ieee80211_channel *entry, - const int channel, const int tx_power, const int value) + const int channel, const int tx_power, + const int value) { entry->chan = channel; if (channel <= 14) @@ -243,21 +584,22 @@ static void rt2x00lib_channel(struct ieee80211_channel *entry, entry->freq = 5000 + (5 * channel); entry->val = value; entry->flag = - IEEE80211_CHAN_W_IBSS | - IEEE80211_CHAN_W_ACTIVE_SCAN | - IEEE80211_CHAN_W_SCAN; + IEEE80211_CHAN_W_IBSS | + IEEE80211_CHAN_W_ACTIVE_SCAN | + IEEE80211_CHAN_W_SCAN; entry->power_level = tx_power; entry->antenna_max = 0xff; } static void rt2x00lib_rate(struct ieee80211_rate *entry, - const int rate,const int mask, const int plcp, const int flags) + const int rate, const int mask, + const int plcp, const int flags) { entry->rate = rate; entry->val = - DEVICE_SET_RATE_FIELD(rate, RATE) | - DEVICE_SET_RATE_FIELD(mask, RATEMASK) | - DEVICE_SET_RATE_FIELD(plcp, PLCP); + DEVICE_SET_RATE_FIELD(rate, RATE) | + DEVICE_SET_RATE_FIELD(mask, RATEMASK) | + DEVICE_SET_RATE_FIELD(plcp, PLCP); entry->flags = flags; entry->val2 = entry->val; if (entry->flags & IEEE80211_RATE_PREAMBLE2) @@ -266,8 +608,8 @@ static void rt2x00lib_rate(struct ieee80211_rate *entry, entry->min_rssi_ack_delta = 0; } -static int rt2x00lib_init_hw_modes(struct rt2x00_dev *rt2x00dev, - struct hw_mode_spec *spec) +static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, + struct hw_mode_spec *spec) { struct ieee80211_hw *hw = rt2x00dev->hw; struct ieee80211_hw_mode *hwmodes; @@ -291,48 +633,47 @@ static int rt2x00lib_init_hw_modes(struct rt2x00_dev *rt2x00dev, /* * Initialize Rate list. */ - rt2x00lib_rate(&rates[0], 10, 0x001, 0x00, IEEE80211_RATE_CCK); - rt2x00lib_rate(&rates[1], 20, 0x003, 0x01, IEEE80211_RATE_CCK_2); - rt2x00lib_rate(&rates[2], 55, 0x007, 0x02, IEEE80211_RATE_CCK_2); - rt2x00lib_rate(&rates[3], 110, 0x00f, 0x03, IEEE80211_RATE_CCK_2); + rt2x00lib_rate(&rates[0], 10, DEV_RATEMASK_1MB, + 0x00, IEEE80211_RATE_CCK); + rt2x00lib_rate(&rates[1], 20, DEV_RATEMASK_2MB, + 0x01, IEEE80211_RATE_CCK_2); + rt2x00lib_rate(&rates[2], 55, DEV_RATEMASK_5_5MB, + 0x02, IEEE80211_RATE_CCK_2); + rt2x00lib_rate(&rates[3], 110, DEV_RATEMASK_11MB, + 0x03, IEEE80211_RATE_CCK_2); if (spec->num_rates > 4) { - rt2x00lib_rate(&rates[4], 60, 0x01f, 0x0b, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[5], 90, 0x03f, 0x0f, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[6], 120, 0x07f, 0x0a, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[7], 180, 0x0ff, 0x0e, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[8], 240, 0x1ff, 0x09, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[9], 360, 0x3ff, 0x0d, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[10], 480, 0x7ff, 0x08, IEEE80211_RATE_OFDM); - rt2x00lib_rate(&rates[11], 540, 0xfff, 0x0c, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[4], 60, DEV_RATEMASK_6MB, + 0x0b, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[5], 90, DEV_RATEMASK_9MB, + 0x0f, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[6], 120, DEV_RATEMASK_12MB, + 0x0a, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[7], 180, DEV_RATEMASK_18MB, + 0x0e, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[8], 240, DEV_RATEMASK_24MB, + 0x09, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[9], 360, DEV_RATEMASK_36MB, + 0x0d, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[10], 480, DEV_RATEMASK_48MB, + 0x08, IEEE80211_RATE_OFDM); + rt2x00lib_rate(&rates[11], 540, DEV_RATEMASK_54MB, + 0x0c, IEEE80211_RATE_OFDM); } /* * Initialize Channel list. */ - for (i = 0; i < 14; i++) - rt2x00lib_channel(&channels[i], i + 1, - spec->tx_power_bg[i], spec->chan_val_bg[i]); - - if (spec->num_channels > 14) { - for (i = 14; i < spec->num_channels; i++) { - if (i < 22) - channels[i].chan = 36; - else if (i < 33) - channels[i].chan = 100; - else - channels[i].chan = 149; - channels[i].chan += ((i - 14) * 4); - - if (spec->tx_power_a) - tx_power = spec->tx_power_a[i]; - else - tx_power = spec->tx_power_default; - - rt2x00lib_channel(&channels[i], - channels[i].chan, tx_power, - spec->chan_val_a[i]); - } + for (i = 0; i < spec->num_channels; i++) { + if (spec->channels[i].channel <= 14) + tx_power = spec->tx_power_bg[i]; + else if (spec->tx_power_a) + tx_power = spec->tx_power_a[i]; + else + tx_power = spec->tx_power_default; + + rt2x00lib_channel(&channels[i], + spec->channels[i].channel, tx_power, i); } /* @@ -404,9 +745,9 @@ exit: return -ENOMEM; } -static void rt2x00lib_deinit_hw(struct rt2x00_dev *rt2x00dev) +static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) { - if (test_bit(DEVICE_INITIALIZED_HW, &rt2x00dev->flags)) + if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags)) ieee80211_unregister_hw(rt2x00dev->hw); if (likely(rt2x00dev->hwmodes)) { @@ -417,45 +758,28 @@ static void rt2x00lib_deinit_hw(struct rt2x00_dev *rt2x00dev) } } -static int rt2x00lib_init_hw(struct rt2x00_dev *rt2x00dev) +static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; int status; /* - * Initialize device. + * Initialize HW modes. */ - SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->device); + status = rt2x00lib_probe_hw_modes(rt2x00dev, spec); + if (status) + return status; /* - * Initialize MAC address. - */ - if (!is_valid_ether_addr(spec->mac_addr)) { - ERROR(rt2x00dev, "Invalid MAC addr: " MAC_FMT ".\n", - MAC_ARG(spec->mac_addr)); - return -EINVAL; - } - - rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, spec->mac_addr); - SET_IEEE80211_PERM_ADDR(rt2x00dev->hw, spec->mac_addr); - - /* - * Initialize HW modes. - */ - status = rt2x00lib_init_hw_modes(rt2x00dev, spec); - if (status) - return status; - - /* - * Register HW. + * Register HW. */ status = ieee80211_register_hw(rt2x00dev->hw); if (status) { - rt2x00lib_deinit_hw(rt2x00dev); + rt2x00lib_remove_hw(rt2x00dev); return status; } - __set_bit(DEVICE_INITIALIZED_HW, &rt2x00dev->flags); + __set_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags); return 0; } @@ -463,8 +787,9 @@ static int rt2x00lib_init_hw(struct rt2x00_dev *rt2x00dev) /* * Initialization/uninitialization handlers. */ -static int rt2x00lib_alloc_ring(struct data_ring *ring, - const u16 max_entries, const u16 data_size, const u16 desc_size) +static int rt2x00lib_alloc_entries(struct data_ring *ring, + const u16 max_entries, const u16 data_size, + const u16 desc_size) { struct data_entry *entry; unsigned int i; @@ -491,46 +816,47 @@ static int rt2x00lib_alloc_ring(struct data_ring *ring, return 0; } -static int rt2x00lib_allocate_rings(struct rt2x00_dev *rt2x00dev) +static int rt2x00lib_alloc_ring_entries(struct rt2x00_dev *rt2x00dev) { struct data_ring *ring; /* * Allocate the RX ring. */ - if (rt2x00lib_alloc_ring(rt2x00dev->rx, - RX_ENTRIES, DATA_FRAME_SIZE, rt2x00dev->ops->rxd_size)) + if (rt2x00lib_alloc_entries(rt2x00dev->rx, RX_ENTRIES, DATA_FRAME_SIZE, + rt2x00dev->ops->rxd_size)) return -ENOMEM; /* * First allocate the TX rings. */ txring_for_each(rt2x00dev, ring) { - if (rt2x00lib_alloc_ring(ring, - TX_ENTRIES, DATA_FRAME_SIZE, rt2x00dev->ops->txd_size)) + if (rt2x00lib_alloc_entries(ring, TX_ENTRIES, DATA_FRAME_SIZE, + rt2x00dev->ops->txd_size)) return -ENOMEM; } + if (!test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags)) + return 0; + /* * Allocate the BEACON ring. */ - if (rt2x00lib_alloc_ring(&rt2x00dev->bcn[0], - BEACON_ENTRIES, MGMT_FRAME_SIZE, rt2x00dev->ops->txd_size)) + if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[0], BEACON_ENTRIES, + MGMT_FRAME_SIZE, rt2x00dev->ops->txd_size)) return -ENOMEM; /* * Allocate the Atim ring. */ - if (test_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags)) { - if (rt2x00lib_alloc_ring(&rt2x00dev->bcn[1], - ATIM_ENTRIES, DATA_FRAME_SIZE, rt2x00dev->ops->txd_size)) - return -ENOMEM; - } + if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[1], ATIM_ENTRIES, + DATA_FRAME_SIZE, rt2x00dev->ops->txd_size)) + return -ENOMEM; return 0; } -static void rt2x00lib_free_rings(struct rt2x00_dev *rt2x00dev) +static void rt2x00lib_free_ring_entries(struct rt2x00_dev *rt2x00dev) { struct data_ring *ring; @@ -540,6 +866,27 @@ static void rt2x00lib_free_rings(struct rt2x00_dev *rt2x00dev) } } +void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) +{ + if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + return; + + /* + * Unregister rfkill. + */ + rt2x00rfkill_unregister(rt2x00dev); + + /* + * Allow the HW to uninitialize. + */ + rt2x00dev->ops->lib->uninitialize(rt2x00dev); + + /* + * Free allocated ring entries. + */ + rt2x00lib_free_ring_entries(rt2x00dev); +} + int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) { int status; @@ -548,11 +895,11 @@ int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) return 0; /* - * Allocate all data rings. + * Allocate all ring entries. */ - status = rt2x00lib_allocate_rings(rt2x00dev); + status = rt2x00lib_alloc_ring_entries(rt2x00dev); if (status) { - ERROR(rt2x00dev, "DMA allocation failed.\n"); + ERROR(rt2x00dev, "Ring entries allocation failed.\n"); return status; } @@ -568,7 +915,7 @@ int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) /* * Register the rfkill handler. */ - status = rt2x00lib_register_rfkill(rt2x00dev); + status = rt2x00rfkill_register(rt2x00dev); if (status) goto exit_unitialize; @@ -578,56 +925,29 @@ exit_unitialize: rt2x00lib_uninitialize(rt2x00dev); exit: - rt2x00lib_free_rings(rt2x00dev); + rt2x00lib_free_ring_entries(rt2x00dev); return status; } -void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) -{ - if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) - return; - - /* - * Flush out all pending work. - */ - flush_workqueue(rt2x00dev->workqueue); - - /* - * Unregister rfkill. - */ - rt2x00lib_unregister_rfkill(rt2x00dev); - - /* - * Allow the HW to uninitialize. - */ - rt2x00dev->ops->lib->uninitialize(rt2x00dev); - - /* - * Free allocated datarings. - */ - rt2x00lib_free_rings(rt2x00dev); -} - /* * driver allocation handlers. */ static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev) { struct data_ring *ring; - unsigned int ring_num; /* * We need the following rings: * RX: 1 * TX: hw->queues - * Beacon: 1 - * Atim: 1 (if supported) + * Beacon: 1 (if required) + * Atim: 1 (if required) */ - ring_num = 2 + rt2x00dev->hw->queues + - test_bit(DEVICE_SUPPORT_ATIM, &rt2x00dev->flags); + rt2x00dev->data_rings = 1 + rt2x00dev->hw->queues + + (2 * test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags)); - ring = kzalloc(sizeof(*ring) * ring_num, GFP_KERNEL); + ring = kzalloc(rt2x00dev->data_rings * sizeof(*ring), GFP_KERNEL); if (!ring) { ERROR(rt2x00dev, "Ring allocation failed.\n"); return -ENOMEM; @@ -636,9 +956,10 @@ static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev) /* * Initialize pointers */ - rt2x00dev->rx = &ring[0]; - rt2x00dev->tx = &ring[1]; - rt2x00dev->bcn = &ring[1 + rt2x00dev->hw->queues]; + rt2x00dev->rx = ring; + rt2x00dev->tx = &rt2x00dev->rx[1]; + if (test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags)) + rt2x00dev->bcn = &rt2x00dev->tx[rt2x00dev->hw->queues]; /* * Initialize ring parameters. @@ -655,21 +976,22 @@ static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev) return 0; } +static void rt2x00lib_free_rings(struct rt2x00_dev *rt2x00dev) +{ + kfree(rt2x00dev->rx); + rt2x00dev->rx = NULL; + rt2x00dev->tx = NULL; + rt2x00dev->bcn = NULL; +} + int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) { int retval = -ENOMEM; - /* - * Create workqueue. - */ - rt2x00dev->workqueue = create_singlethread_workqueue(DRV_NAME); - if (!rt2x00dev->workqueue) - goto exit; - /* * Let the driver probe the device to detect the capabilities. */ - retval = rt2x00dev->ops->lib->init_hw(rt2x00dev); + retval = rt2x00dev->ops->lib->probe_hw(rt2x00dev); if (retval) { ERROR(rt2x00dev, "Failed to allocate device.\n"); goto exit; @@ -678,12 +1000,15 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) /* * Initialize configuration work. */ + INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled); + INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); + INIT_WORK(&rt2x00dev->config_work, rt2x00lib_configuration_scheduled); INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); /* * Reset current working type. */ - rt2x00dev->interface.type = -EINVAL; + rt2x00dev->interface.type = INVALID_INTERFACE; /* * Allocate ring array. @@ -695,7 +1020,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) /* * Initialize ieee80211 structure. */ - retval = rt2x00lib_init_hw(rt2x00dev); + retval = rt2x00lib_probe_hw(rt2x00dev); if (retval) { ERROR(rt2x00dev, "Failed to initialize hw.\n"); goto exit; @@ -704,7 +1029,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) /* * Allocatie rfkill. */ - retval = rt2x00lib_allocate_rfkill(rt2x00dev); + retval = rt2x00rfkill_allocate(rt2x00dev); if (retval) goto exit; @@ -713,19 +1038,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) */ rt2x00debug_register(rt2x00dev); - /* - * Check if we need to load the firmware. - */ - if (test_bit(FIRMWARE_REQUIRED, &rt2x00dev->flags)) { - /* - * Request firmware and wait with further - * initializing of the card until the firmware - * has been loaded. - */ - retval = rt2x00lib_load_firmware(rt2x00dev); - if (retval) - goto exit; - } + __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); return 0; @@ -738,6 +1051,8 @@ EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev); void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) { + __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); + /* * Disable radio. */ @@ -756,49 +1071,52 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) /* * Free rfkill */ - rt2x00lib_free_rfkill(rt2x00dev); + rt2x00rfkill_free(rt2x00dev); /* * Free ieee80211_hw memory. */ - rt2x00lib_deinit_hw(rt2x00dev); + rt2x00lib_remove_hw(rt2x00dev); /* - * Free workqueue. + * Free firmware image. */ - if (likely(rt2x00dev->workqueue)) { - destroy_workqueue(rt2x00dev->workqueue); - rt2x00dev->workqueue = NULL; - } + rt2x00lib_free_firmware(rt2x00dev); /* * Free ring structures. */ - kfree(rt2x00dev->rx); - rt2x00dev->rx = NULL; - rt2x00dev->tx = NULL; - rt2x00dev->bcn = NULL; - - /* - * Free EEPROM memory. - */ - kfree(rt2x00dev->eeprom); - rt2x00dev->eeprom = NULL; + rt2x00lib_free_rings(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev); /* * Device state handlers */ -int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, - pm_message_t state) +#ifdef CONFIG_PM +int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) { int retval; NOTICE(rt2x00dev, "Going to sleep.\n"); + __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); - rt2x00lib_disable_radio(rt2x00dev); + /* + * Only continue if mac80211 has open interfaces. + */ + if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + goto exit; + __set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags); + /* + * Disable radio and unitialize all items + * that must be recreated on resume. + */ + rt2x00mac_stop(rt2x00dev->hw); + rt2x00lib_uninitialize(rt2x00dev); + rt2x00debug_deregister(rt2x00dev); + +exit: /* * Set device mode to sleep for power management. */ @@ -806,272 +1124,74 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, if (retval) return retval; - rt2x00lib_remove_dev(rt2x00dev); - return 0; } EXPORT_SYMBOL_GPL(rt2x00lib_suspend); int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) { + struct interface *intf = &rt2x00dev->interface; int retval; NOTICE(rt2x00dev, "Waking up.\n"); - - retval = rt2x00lib_probe_dev(rt2x00dev); - if (retval) { - ERROR(rt2x00dev, "Failed to allocate device.\n"); - return retval; - } - - /* - * Set device mode to awake for power management. - */ - retval = rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE); - if (retval) - return retval; - - return 0; -} -EXPORT_SYMBOL_GPL(rt2x00lib_resume); - -/* - * Interrupt context handlers. - */ -void rt2x00lib_txdone(struct data_entry *entry, - const int status, const int retry) -{ - struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev; - struct ieee80211_tx_status *tx_status = &entry->tx_status; - struct ieee80211_low_level_stats *stats = &rt2x00dev->low_level_stats; - - /* - * Update TX statistics. - */ - tx_status->flags = 0; - tx_status->ack_signal = 0; - tx_status->excessive_retries = (status == TX_FAIL_RETRY); - tx_status->retry_count = retry; - - if (!(tx_status->control.flags & IEEE80211_TXCTL_NO_ACK)) { - if (status == TX_SUCCESS || status == TX_SUCCESS_RETRY) - tx_status->flags |= IEEE80211_TX_STATUS_ACK; - else - stats->dot11ACKFailureCount++; - } - - tx_status->queue_length = entry->ring->stats.limit; - tx_status->queue_number = tx_status->control.queue; - - if (tx_status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) { - if (status == TX_SUCCESS || status == TX_SUCCESS_RETRY) - stats->dot11RTSSuccessCount++; - else - stats->dot11RTSFailureCount++; - } - - /* - * Send the tx_status to mac80211, - * that method also cleans up the skb structure. - */ - ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, tx_status); - - entry->skb = NULL; -} -EXPORT_SYMBOL_GPL(rt2x00lib_txdone); - -void rt2x00lib_rxdone(struct data_entry *entry, char *data, - const int size, const int signal, const int rssi, const int ofdm) -{ - struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev; - struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rate; - struct sk_buff *skb; - unsigned int i; - int val = 0; - - /* - * Update RX statistics. - */ - mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; - for (i = 0; i < mode->num_rates; i++) { - rate = &mode->rates[i]; - - /* - * 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 0.5kbit/s. - */ - if (!ofdm) - val = DEVICE_GET_RATE_FIELD(rate->val, RATE); - else - val = DEVICE_GET_RATE_FIELD(rate->val, PLCP); - - if (val == signal) { - /* - * Check for preamble bit. - */ - if (signal & 0x08) - val = rate->val2; - val = rate->val; - break; - } - } - - rx_status->rate = val; - rx_status->ssi = rssi; - rx_status->noise = rt2x00dev->link.curr_noise; - rt2x00_update_link_rssi(&rt2x00dev->link, rssi); - - /* - * Let's allocate a sk_buff where we can store the received data in, - * note that if data is NULL, we still have to allocate a sk_buff - * but that we should use that to replace the sk_buff which is already - * inside the entry. - */ - skb = dev_alloc_skb(size + NET_IP_ALIGN); - if (!skb) - return; - - skb_reserve(skb, NET_IP_ALIGN); - skb_put(skb, size); - - if (data) { - memcpy(skb->data, data, size); - entry->skb = skb; - skb = NULL; - } - - ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status); - entry->skb = skb; -} -EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); - -/* - * TX descriptor initializer - */ -void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct data_entry *entry, struct data_desc *txd, - struct ieee80211_hdr *ieee80211hdr, unsigned int length, - struct ieee80211_tx_control *control) -{ - struct data_entry_desc desc; - int tx_rate; - int bitrate; - int duration; - int residual; - u16 frame_control; - u16 seq_ctrl; + __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); /* - * Identify queue - */ - if (control->queue < rt2x00dev->hw->queues) - desc.queue = control->queue; - else - desc.queue = 15; - - /* - * Read required fields from ieee80211 header. - */ - frame_control = le16_to_cpu(ieee80211hdr->frame_control); - seq_ctrl = le16_to_cpu(ieee80211hdr->seq_ctrl); - - tx_rate = control->tx_rate; - - /* - * Check if this is a rts frame - */ - if (is_rts_frame(frame_control)) { - __set_bit(ENTRY_TXD_RTS_FRAME, &entry->flags); - if (control->rts_cts_rate) - tx_rate = control->rts_cts_rate; - } - - /* - * Check for OFDM + * Open the debugfs entry. */ - if (DEVICE_GET_RATE_FIELD(tx_rate, RATEMASK) & DEV_OFDM_RATE) - __set_bit(ENTRY_TXD_OFDM_RATE, &entry->flags); + rt2x00debug_register(rt2x00dev); /* - * Check if more fragments are pending + * Only continue if mac80211 had open interfaces. */ - if (ieee80211_get_morefrag(ieee80211hdr)) - __set_bit(ENTRY_TXD_MORE_FRAG, &entry->flags); + if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags)) + return 0; /* - * Check if this is a new sequence + * Reinitialize device and all active interfaces. */ - if ((seq_ctrl & IEEE80211_SCTL_FRAG) == 0) - __set_bit(ENTRY_TXD_NEW_SEQ, &entry->flags); + retval = rt2x00mac_start(rt2x00dev->hw); + if (retval) + goto exit; /* - * Beacons and probe responses require the tsf timestamp - * to be inserted into the frame. + * Reconfigure device. */ - if (control->queue == IEEE80211_TX_QUEUE_BEACON || - is_probe_resp(frame_control)) - __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &entry->flags); + rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, 1); + if (!rt2x00dev->hw->conf.radio_enabled) + rt2x00lib_disable_radio(rt2x00dev); - /* - * Check if ACK is required - */ - if (!(control->flags & IEEE80211_TXCTL_NO_ACK)) - __set_bit(ENTRY_TXD_REQ_ACK, &entry->flags); + rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); + rt2x00lib_config_bssid(rt2x00dev, intf->bssid); + rt2x00lib_config_type(rt2x00dev, intf->type); /* - * Determine with what IFS priority this frame should be send. - * Set ifs to IFS_SIFS when the this is not the first fragment, - * or this fragment came after RTS/CTS. + * It is possible that during that mac80211 has attempted + * to send frames while we were suspending or resuming. + * In that case we have disabled the TX queue and should + * now enable it again */ - if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 || - test_bit(ENTRY_TXD_RTS_FRAME, &entry->flags)) - desc.ifs = IFS_SIFS; - else - desc.ifs = IFS_BACKOFF; + ieee80211_start_queues(rt2x00dev->hw); /* - * How the length should be processed depends - * on if we are working with OFDM rates or not. + * When in Master or Ad-hoc mode, + * restart Beacon transmitting by faking a beacondone event. */ - if (test_bit(ENTRY_TXD_OFDM_RATE, &entry->flags)) { - residual = 0; - desc.length_high = ((length + FCS_LEN) >> 6) & 0x3f; - desc.length_low = ((length + FCS_LEN) & 0x3f); - - } else { - bitrate = DEVICE_GET_RATE_FIELD(tx_rate, RATE); - - /* - * Convert length to microseconds. - */ - residual = get_duration_res(length + FCS_LEN, bitrate); - duration = get_duration(length + FCS_LEN, bitrate); + if (intf->type == IEEE80211_IF_TYPE_AP || + intf->type == IEEE80211_IF_TYPE_IBSS) + rt2x00lib_beacondone(rt2x00dev); - if (residual != 0) - duration++; - - desc.length_high = duration >> 8; - desc.length_low = duration & 0xff; - } - - /* - * Create the signal and service values. - */ - desc.signal = DEVICE_GET_RATE_FIELD(tx_rate, PLCP); - if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE)) - desc.signal |= 0x08; + return 0; - desc.service = 0x04; - if (residual <= (8 % 11)) - desc.service |= 0x80; +exit: + rt2x00lib_disable_radio(rt2x00dev); + rt2x00lib_uninitialize(rt2x00dev); + rt2x00debug_deregister(rt2x00dev); - rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry, txd, &desc, - ieee80211hdr, length, control); + return retval; } -EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc); +EXPORT_SYMBOL_GPL(rt2x00lib_resume); +#endif /* CONFIG_PM */ /* * rt2x00lib module information.