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

📄 iwl-3945.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************** * * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * * Contact Information: * James P. Ketrenos <ipw2100-admin@linux.intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/#include <linux/kernel.h>#include <linux/module.h>#include <linux/version.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/dma-mapping.h>#include <linux/delay.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/wireless.h>#include <linux/firmware.h>#include <net/mac80211.h>#include <linux/etherdevice.h>#define IWL 3945#include "iwlwifi.h"#include "iwl-helpers.h"#include "iwl-3945.h"#include "iwl-3945-rs.h"#define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np)    \	[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,   \				    IWL_RATE_##r##M_IEEE,   \				    IWL_RATE_##ip##M_INDEX, \				    IWL_RATE_##in##M_INDEX, \				    IWL_RATE_##rp##M_INDEX, \				    IWL_RATE_##rn##M_INDEX, \				    IWL_RATE_##pp##M_INDEX, \				    IWL_RATE_##np##M_INDEX, \				    IWL_RATE_##r##M_INDEX_TABLE, \				    IWL_RATE_##ip##M_INDEX_TABLE }/* * Parameter order: *   rate, prev rate, next rate, prev tgg rate, next tgg rate * * If there isn't a valid next or previous rate then INV is used which * maps to IWL_RATE_INVALID * */const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {	IWL_DECLARE_RATE_INFO(1, INV, 2, INV, 2, INV, 2),    /*  1mbps */	IWL_DECLARE_RATE_INFO(2, 1, 5, 1, 5, 1, 5),          /*  2mbps */	IWL_DECLARE_RATE_INFO(5, 2, 6, 2, 11, 2, 11),        /*5.5mbps */	IWL_DECLARE_RATE_INFO(11, 9, 12, 5, 12, 5, 18),      /* 11mbps */	IWL_DECLARE_RATE_INFO(6, 5, 9, 5, 11, 5, 11),        /*  6mbps */	IWL_DECLARE_RATE_INFO(9, 6, 11, 5, 11, 5, 11),       /*  9mbps */	IWL_DECLARE_RATE_INFO(12, 11, 18, 11, 18, 11, 18),   /* 12mbps */	IWL_DECLARE_RATE_INFO(18, 12, 24, 12, 24, 11, 24),   /* 18mbps */	IWL_DECLARE_RATE_INFO(24, 18, 36, 18, 36, 18, 36),   /* 24mbps */	IWL_DECLARE_RATE_INFO(36, 24, 48, 24, 48, 24, 48),   /* 36mbps */	IWL_DECLARE_RATE_INFO(48, 36, 54, 36, 54, 36, 54),   /* 48mbps */	IWL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */};/* 1 = enable the iwl_disable_events() function */#define IWL_EVT_DISABLE (0)#define IWL_EVT_DISABLE_SIZE (1532/32)/** * iwl_disable_events - Disable selected events in uCode event log * * Disable an event by writing "1"s into "disable" *   bitmap in SRAM.  Bit position corresponds to Event # (id/type). *   Default values of 0 enable uCode events to be logged. * Use for only special debugging.  This function is just a placeholder as-is, *   you'll need to provide the special bits! ... *   ... and set IWL_EVT_DISABLE to 1. */void iwl_disable_events(struct iwl_priv *priv){	int rc;	int i;	u32 base;		/* SRAM address of event log header */	u32 disable_ptr;	/* SRAM address of event-disable bitmap array */	u32 array_size;		/* # of u32 entries in array */	u32 evt_disable[IWL_EVT_DISABLE_SIZE] = {		0x00000000,	/*   31 -    0  Event id numbers */		0x00000000,	/*   63 -   32 */		0x00000000,	/*   95 -   64 */		0x00000000,	/*  127 -   96 */		0x00000000,	/*  159 -  128 */		0x00000000,	/*  191 -  160 */		0x00000000,	/*  223 -  192 */		0x00000000,	/*  255 -  224 */		0x00000000,	/*  287 -  256 */		0x00000000,	/*  319 -  288 */		0x00000000,	/*  351 -  320 */		0x00000000,	/*  383 -  352 */		0x00000000,	/*  415 -  384 */		0x00000000,	/*  447 -  416 */		0x00000000,	/*  479 -  448 */		0x00000000,	/*  511 -  480 */		0x00000000,	/*  543 -  512 */		0x00000000,	/*  575 -  544 */		0x00000000,	/*  607 -  576 */		0x00000000,	/*  639 -  608 */		0x00000000,	/*  671 -  640 */		0x00000000,	/*  703 -  672 */		0x00000000,	/*  735 -  704 */		0x00000000,	/*  767 -  736 */		0x00000000,	/*  799 -  768 */		0x00000000,	/*  831 -  800 */		0x00000000,	/*  863 -  832 */		0x00000000,	/*  895 -  864 */		0x00000000,	/*  927 -  896 */		0x00000000,	/*  959 -  928 */		0x00000000,	/*  991 -  960 */		0x00000000,	/* 1023 -  992 */		0x00000000,	/* 1055 - 1024 */		0x00000000,	/* 1087 - 1056 */		0x00000000,	/* 1119 - 1088 */		0x00000000,	/* 1151 - 1120 */		0x00000000,	/* 1183 - 1152 */		0x00000000,	/* 1215 - 1184 */		0x00000000,	/* 1247 - 1216 */		0x00000000,	/* 1279 - 1248 */		0x00000000,	/* 1311 - 1280 */		0x00000000,	/* 1343 - 1312 */		0x00000000,	/* 1375 - 1344 */		0x00000000,	/* 1407 - 1376 */		0x00000000,	/* 1439 - 1408 */		0x00000000,	/* 1471 - 1440 */		0x00000000,	/* 1503 - 1472 */	};	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);	if (!iwl_hw_valid_rtc_data_addr(base)) {		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);		return;	}	rc = iwl_grab_restricted_access(priv);	if (rc) {		IWL_WARNING("Can not read from adapter at this time.\n");		return;	}	disable_ptr = iwl_read_restricted_mem(priv, base + (4 * sizeof(u32)));	array_size = iwl_read_restricted_mem(priv, base + (5 * sizeof(u32)));	iwl_release_restricted_access(priv);	if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) {		IWL_DEBUG_INFO("Disabling selected uCode log events at 0x%x\n",			       disable_ptr);		rc = iwl_grab_restricted_access(priv);		for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++)			iwl_write_restricted_mem(priv,						 disable_ptr +						 (i * sizeof(u32)),						 evt_disable[i]);		iwl_release_restricted_access(priv);	} else {		IWL_DEBUG_INFO("Selected uCode log events may be disabled\n");		IWL_DEBUG_INFO("  by writing \"1\"s into disable bitmap\n");		IWL_DEBUG_INFO("  in SRAM at 0x%x, size %d u32s\n",			       disable_ptr, array_size);	}}/** * iwl3945_get_antenna_flags - Get antenna flags for RXON command * @priv: eeprom and antenna fields are used to determine antenna flags * * priv->eeprom  is used to determine if antenna AUX/MAIN are reversed * priv->antenna specifies the antenna diversity mode: * * IWL_ANTENNA_DIVERISTY - NIC selects best antenna by itself * IWL_ANTENNA_MAIN      - Force MAIN antenna * IWL_ANTENNA_AUX       - Force AUX antenna */__le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv){	switch (priv->antenna) {	case IWL_ANTENNA_DIVERSITY:		return 0;	case IWL_ANTENNA_MAIN:		if (priv->eeprom.antenna_switch_type)			return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK;		return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK;	case IWL_ANTENNA_AUX:		if (priv->eeprom.antenna_switch_type)			return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK;		return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK;	}	/* bad antenna selector value */	IWL_ERROR("Bad antenna selector value (0x%x)\n", priv->antenna);	return 0;		/* "diversity" is default if error */}/***************************************************************************** * * Intel PRO/Wireless 3945ABG/BG Network Connection * *  RX handler implementations * *  Used by iwl-base.c * *****************************************************************************/void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb){	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;	IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n",		     (int)sizeof(struct iwl_notif_statistics),		     le32_to_cpu(pkt->len));	memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics));	priv->last_statistics_time = jiffies;}static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data,				   struct iwl_rx_mem_buffer *rxb,				   struct ieee80211_rx_status *stats,				   u16 phy_flags){	struct ieee80211_hdr *hdr;	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;	struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);	struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);	short len = le16_to_cpu(rx_hdr->len);	/* We received data from the HW, so stop the watchdog */	if (unlikely((len + IWL_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {		IWL_DEBUG_DROP("Corruption detected!\n");		return;	}	/* We only process data packets if the interface is open */	if (unlikely(!priv->is_open)) {		IWL_DEBUG_DROP_LIMIT		    ("Dropping packet while interface is not open.\n");		return;	}	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {		if (iwl_param_hwcrypto)			iwl_set_decrypted_flag(priv, rxb->skb,					       le32_to_cpu(rx_end->status),					       stats);		iwl_handle_data_packet_monitor(priv, rxb, IWL_RX_DATA(pkt),					       len, stats, phy_flags);		return;	}	skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt);	/* Set the size of the skb to the size of the frame */	skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));	hdr = (void *)rxb->skb->data;	if (iwl_param_hwcrypto)		iwl_set_decrypted_flag(priv, rxb->skb,				       le32_to_cpu(rx_end->status), stats);	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);	rxb->skb = NULL;}static void iwl3945_rx_reply_rx(struct iwl_priv *priv,				struct iwl_rx_mem_buffer *rxb){	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;	struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);	struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);	struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);	struct ieee80211_hdr *header;	u16 phy_flags = le16_to_cpu(rx_hdr->phy_flags);	u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg);	u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff);	struct ieee80211_rx_status stats = {		.mactime = le64_to_cpu(rx_end->timestamp),		.freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)),		.channel = le16_to_cpu(rx_hdr->channel),		.phymode = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?		MODE_IEEE80211G : MODE_IEEE80211A,		.antenna = 0,		.rate = rx_hdr->rate,		.flag = 0,	};	u8 network_packet;	int snr;	if ((unlikely(rx_stats->phy_count > 20))) {		IWL_DEBUG_DROP		    ("dsp size out of range [0,20]: "		     "%d/n", rx_stats->phy_count);		return;	}	if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR)	    || !(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {		IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", rx_end->status);		return;	}	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {		iwl3945_handle_data_packet(priv, 1, rxb, &stats, phy_flags);		return;	}	/* Convert 3945's rssi indicator to dBm */	stats.ssi = rx_stats->rssi - IWL_RSSI_OFFSET;	/* Set default noise value to -127 */	if (priv->last_rx_noise == 0)		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;	/* 3945 provides noise info for OFDM frames only.	 * sig_avg and noise_diff are measured by the 3945's digital signal	 *   processor (DSP), and indicate linear levels of signal level and	 *   distortion/noise within the packet preamble after	 *   automatic gain control (AGC).  sig_avg should stay fairly	 *   constant if the radio's AGC is working well.	 * Since these values are linear (not dB or dBm), linear	 *   signal-to-noise ratio (SNR) is (sig_avg / noise_diff).	 * Convert linear SNR to dB SNR, then subtract that from rssi dBm	 *   to obtain noise level in dBm.	 * Calculate stats.signal (quality indicator in %) based on SNR. */	if (rx_stats_noise_diff) {		snr = rx_stats_sig_avg / rx_stats_noise_diff;		stats.noise = stats.ssi - iwl_calc_db_from_ratio(snr);		stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise);	/* If noise info not available, calculate signal quality indicator (%)	 *   using just the dBm signal level. */	} else {		stats.noise = priv->last_rx_noise;		stats.signal = iwl_calc_sig_qual(stats.ssi, 0);	}	IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n",			stats.ssi, stats.noise, stats.signal,			rx_stats_sig_avg, rx_stats_noise_diff);	stats.freq = ieee80211chan2mhz(stats.channel);	/* can be covered by iwl_report_frame() in most cases *//*      IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */	header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);	network_packet = iwl_is_network_packet(priv, header);#ifdef CONFIG_IWLWIFI_DEBUG	if (iwl_debug_level & IWL_DL_STATS && net_ratelimit())		IWL_DEBUG_STATS		    ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n",		     network_packet ? '*' : ' ',		     stats.channel, stats.ssi, stats.ssi,		     stats.ssi, stats.rate);	if (iwl_debug_level & (IWL_DL_RX))		/* Set "1" to report good data frames in groups of 100 */		iwl_report_frame(priv, pkt, header, 1);#endif	if (network_packet) {		priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);		priv->last_tsf = le64_to_cpu(rx_end->timestamp);		priv->last_rx_rssi = stats.ssi;		priv->last_rx_noise = stats.noise;	}	switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) {	case IEEE80211_FTYPE_MGMT:		switch (le16_to_cpu(header->frame_control) &			IEEE80211_FCTL_STYPE) {		case IEEE80211_STYPE_PROBE_RESP:		case IEEE80211_STYPE_BEACON:{				/* If this is a beacon or probe response for				 * our network then cache the beacon				 * timestamp */				if ((((priv->iw_mode == IEEE80211_IF_TYPE_STA)				      && !compare_ether_addr(header->addr2,							     priv->bssid)) ||				     ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS)				      && !compare_ether_addr(header->addr3,							     priv->bssid)))) {					struct ieee80211_mgmt *mgmt =					    (struct ieee80211_mgmt *)header;					__le32 *pos;					pos =					    (__le32 *) & mgmt->u.beacon.					    timestamp;					priv->timestamp0 = le32_to_cpu(pos[0]);					priv->timestamp1 = le32_to_cpu(pos[1]);					priv->beacon_int = le16_to_cpu(					    mgmt->u.beacon.beacon_int);					if (priv->call_post_assoc_from_beacon &&					    (priv->iw_mode ==						IEEE80211_IF_TYPE_STA))						queue_work(priv->workqueue,						    &priv->post_associate.work);					priv->call_post_assoc_from_beacon = 0;				}				break;			}		case IEEE80211_STYPE_ACTION:			/* TODO: Parse 802.11h frames for CSA... */			break;			/*			 * TODO: There is no callback function from upper			 * stack to inform us when associated status. this			 * work around to sniff assoc_resp management frame			 * and finish the association process.			 */		case IEEE80211_STYPE_ASSOC_RESP:		case IEEE80211_STYPE_REASSOC_RESP:{				struct ieee80211_mgmt *mgnt =				    (struct ieee80211_mgmt *)header;				priv->assoc_id = (~((1 << 15) | (1 << 14)) &						  le16_to_cpu(mgnt->u.							      assoc_resp.aid));				priv->assoc_capability =

⌨️ 快捷键说明

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