⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rt2x00dev.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project	<http://rt2x00.serialmonkey.com>	This program is free software; you can redistribute it and/or modify	it under the terms of the GNU General Public License as published by	the Free Software Foundation; either version 2 of the License, or	(at your option) any later version.	This program is distributed in the hope that it will be useful,	but WITHOUT ANY WARRANTY; without even the implied warranty of	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the	GNU General Public License for more details.	You should have received a copy of the GNU General Public License	along with this program; if not, write to the	Free Software Foundation, Inc.,	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//*	Module: rt2x00lib	Abstract: rt2x00 generic device routines. *//* * Set enviroment defines for rt2x00.h */#define DRV_NAME "rt2x00lib"#include <linux/kernel.h>#include <linux/module.h>#include "rt2x00.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. */int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev){	int status;	/*	 * Don't enable the radio twice.	 * And check if the hardware button has been disabled.	 */	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||	    test_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags))		return 0;	/*	 * Enable radio.	 */	status = rt2x00dev->ops->lib->set_device_state(rt2x00dev,						       STATE_RADIO_ON);	if (status)		return status;	__set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags);	/*	 * Enable RX.	 */	rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);	/*	 * Start the TX queues.	 */	ieee80211_start_queues(rt2x00dev->hw);	return 0;}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);	/*	 * 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, 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;	/*	 * We need a positive value for the RSSI.	 */	if (rssi < 0)		rssi += rt2x00dev->rssi_offset;	/*	 * Calculate the different percentages,	 * which will be used for the signal.	 */	if (rt2x00dev->rssi_offset)		rssi_percentage = (rssi * 100) / rt2x00dev->rssi_offset;	/*	 * Add the individual percentages and use the WEIGHT	 * defines to calculate the current link signal.	 */	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);	/*	 * When the radio is shutting down we should	 * immediately cease all link tuning.	 */	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))		return;	/*	 * Update statistics.	 */	rt2x00dev->ops->lib->link_stats(rt2x00dev);	rt2x00dev->low_level_stats.dot11FCSErrorCount +=	    rt2x00dev->link.rx_failed;	/*	 * Only perform the link tuning when Link tuning	 * has been enabled (This could have been disabled from the EEPROM).	 */	if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))		rt2x00dev->ops->lib->link_tuner(rt2x00dev);	/*	 * 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->hw->workqueue, &rt2x00dev->link.work,			   LINK_TUNE_INTERVAL);}static void rt2x00lib_packetfilter_scheduled(struct work_struct *work){	struct rt2x00_dev *rt2x00dev =	    container_of(work, struct rt2x00_dev, filter_work);	unsigned int filter = rt2x00dev->interface.filter;	/*	 * 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;	rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw,					     filter, &filter, 0, NULL);}static void rt2x00lib_configuration_scheduled(struct work_struct *work){	struct rt2x00_dev *rt2x00dev =	    container_of(work, struct rt2x00_dev, config_work);	int preamble = !test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);	rt2x00mac_erp_ie_changed(rt2x00dev->hw,				 IEEE80211_ERP_CHANGE_PREAMBLE, 0, preamble);}/* * Interrupt context handlers. */static void rt2x00lib_beacondone_scheduled(struct work_struct *work){	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->hw->beacon_update(rt2x00dev->hw, skb,					  &entry->tx_status.control);	dev_kfree_skb(skb);}void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev){	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))		return;	queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->beacon_work);}EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);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);	/*	 * 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;	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++;	}	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_rxdone(struct data_entry *entry, struct sk_buff *skb,		      struct rxdata_entry_desc *desc){	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;		}	}	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;	/*	 * Send frame to mac80211	 */	ieee80211_rx_irqsafe(rt2x00dev->hw, skb, rx_status);}EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);/* * 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){	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;		/*		 * 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->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){	entry->chan = channel;	if (channel <= 14)		entry->freq = 2407 + (5 * channel);	else		entry->freq = 5000 + (5 * channel);	entry->val = value;	entry->flag =	    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){	entry->rate = rate;	entry->val =	    DEVICE_SET_RATE_FIELD(rate, RATE) |	    DEVICE_SET_RATE_FIELD(mask, RATEMASK) |	    DEVICE_SET_RATE_FIELD(plcp, PLCP);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -