📄 ipw2200.c
字号:
/****************************************************************************** Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. 802.11 status code portion of this file from ethereal-0.10.6: Copyright 2000, Axis Communications AB Ethereal - Network traffic analyzer By Gerald Combs <gerald@ethereal.com> Copyright 1998 Gerald Combs 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 "ipw2200.h"#include <linux/version.h>#ifndef KBUILD_EXTMOD#define VK "k"#else#define VK#endif#ifdef CONFIG_IPW2200_DEBUG#define VD "d"#else#define VD#endif#ifdef CONFIG_IPW2200_MONITOR#define VM "m"#else#define VM#endif#ifdef CONFIG_IPW2200_PROMISCUOUS#define VP "p"#else#define VP#endif#ifdef CONFIG_IPW2200_RADIOTAP#define VR "r"#else#define VR#endif#ifdef CONFIG_IPW2200_QOS#define VQ "q"#else#define VQ#endif#define IPW2200_VERSION "1.2.0" VK VD VM VP VR VQ#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver"#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"#define DRV_VERSION IPW2200_VERSION#define ETH_P_80211_STATS (ETH_P_80211_RAW + 1)MODULE_DESCRIPTION(DRV_DESCRIPTION);MODULE_VERSION(DRV_VERSION);MODULE_AUTHOR(DRV_COPYRIGHT);MODULE_LICENSE("GPL");static int cmdlog = 0;static int debug = 0;static int channel = 0;static int mode = 0;static u32 ipw_debug_level;static int associate = 1;static int auto_create = 1;static int led = 0;static int disable = 0;static int bt_coexist = 0;static int hwcrypto = 0;static int roaming = 1;static const char ipw_modes[] = { 'a', 'b', 'g', '?'};static int antenna = CFG_SYS_ANTENNA_BOTH;#ifdef CONFIG_IPW2200_PROMISCUOUSstatic int rtap_iface = 0; /* def: 0 -- do not create rtap interface */#endif#ifdef CONFIG_IPW2200_QOSstatic int qos_enable = 0;static int qos_burst_enable = 0;static int qos_no_ack_mask = 0;static int burst_duration_CCK = 0;static int burst_duration_OFDM = 0;static struct ieee80211_qos_parameters def_qos_parameters_OFDM = { {QOS_TX0_CW_MIN_OFDM, QOS_TX1_CW_MIN_OFDM, QOS_TX2_CW_MIN_OFDM, QOS_TX3_CW_MIN_OFDM}, {QOS_TX0_CW_MAX_OFDM, QOS_TX1_CW_MAX_OFDM, QOS_TX2_CW_MAX_OFDM, QOS_TX3_CW_MAX_OFDM}, {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS}, {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM}, {QOS_TX0_TXOP_LIMIT_OFDM, QOS_TX1_TXOP_LIMIT_OFDM, QOS_TX2_TXOP_LIMIT_OFDM, QOS_TX3_TXOP_LIMIT_OFDM}};static struct ieee80211_qos_parameters def_qos_parameters_CCK = { {QOS_TX0_CW_MIN_CCK, QOS_TX1_CW_MIN_CCK, QOS_TX2_CW_MIN_CCK, QOS_TX3_CW_MIN_CCK}, {QOS_TX0_CW_MAX_CCK, QOS_TX1_CW_MAX_CCK, QOS_TX2_CW_MAX_CCK, QOS_TX3_CW_MAX_CCK}, {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS}, {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM}, {QOS_TX0_TXOP_LIMIT_CCK, QOS_TX1_TXOP_LIMIT_CCK, QOS_TX2_TXOP_LIMIT_CCK, QOS_TX3_TXOP_LIMIT_CCK}};static struct ieee80211_qos_parameters def_parameters_OFDM = { {DEF_TX0_CW_MIN_OFDM, DEF_TX1_CW_MIN_OFDM, DEF_TX2_CW_MIN_OFDM, DEF_TX3_CW_MIN_OFDM}, {DEF_TX0_CW_MAX_OFDM, DEF_TX1_CW_MAX_OFDM, DEF_TX2_CW_MAX_OFDM, DEF_TX3_CW_MAX_OFDM}, {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS}, {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM}, {DEF_TX0_TXOP_LIMIT_OFDM, DEF_TX1_TXOP_LIMIT_OFDM, DEF_TX2_TXOP_LIMIT_OFDM, DEF_TX3_TXOP_LIMIT_OFDM}};static struct ieee80211_qos_parameters def_parameters_CCK = { {DEF_TX0_CW_MIN_CCK, DEF_TX1_CW_MIN_CCK, DEF_TX2_CW_MIN_CCK, DEF_TX3_CW_MIN_CCK}, {DEF_TX0_CW_MAX_CCK, DEF_TX1_CW_MAX_CCK, DEF_TX2_CW_MAX_CCK, DEF_TX3_CW_MAX_CCK}, {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS}, {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM}, {DEF_TX0_TXOP_LIMIT_CCK, DEF_TX1_TXOP_LIMIT_CCK, DEF_TX2_TXOP_LIMIT_CCK, DEF_TX3_TXOP_LIMIT_CCK}};static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };static int from_priority_to_tx_queue[] = { IPW_TX_QUEUE_1, IPW_TX_QUEUE_2, IPW_TX_QUEUE_2, IPW_TX_QUEUE_1, IPW_TX_QUEUE_3, IPW_TX_QUEUE_3, IPW_TX_QUEUE_4, IPW_TX_QUEUE_4};static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv);static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters *qos_param);static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element *qos_param);#endif /* CONFIG_IPW2200_QOS */static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev);static void ipw_remove_current_network(struct ipw_priv *priv);static void ipw_rx(struct ipw_priv *priv);static int ipw_queue_tx_reclaim(struct ipw_priv *priv, struct clx2_tx_queue *txq, int qindex);static int ipw_queue_reset(struct ipw_priv *priv);static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf, int len, int sync);static void ipw_tx_queue_free(struct ipw_priv *);static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *);static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *);static void ipw_rx_queue_replenish(void *);static int ipw_up(struct ipw_priv *);static void ipw_bg_up(void *);static void ipw_down(struct ipw_priv *);static void ipw_bg_down(void *);static int ipw_config(struct ipw_priv *);static int init_supported_rates(struct ipw_priv *priv, struct ipw_supported_rates *prates);static void ipw_set_hwcrypto_keys(struct ipw_priv *);static void ipw_send_wep_keys(struct ipw_priv *, int);static inline int ipw_is_multicast_ether_addr(const u8 * addr){ return (0x01 & addr[0]);}static int snprint_line(char *buf, size_t count, const u8 * data, u32 len, u32 ofs){ int out, i, j, l; char c; out = snprintf(buf, count, "%08X", ofs); for (l = 0, i = 0; i < 2; i++) { out += snprintf(buf + out, count - out, " "); for (j = 0; j < 8 && l < len; j++, l++) out += snprintf(buf + out, count - out, "%02X ", data[(i * 8 + j)]); for (; j < 8; j++) out += snprintf(buf + out, count - out, " "); } out += snprintf(buf + out, count - out, " "); for (l = 0, i = 0; i < 2; i++) { out += snprintf(buf + out, count - out, " "); for (j = 0; j < 8 && l < len; j++, l++) { c = data[(i * 8 + j)]; if (!isascii(c) || !isprint(c)) c = '.'; out += snprintf(buf + out, count - out, "%c", c); } for (; j < 8; j++) out += snprintf(buf + out, count - out, " "); } return out;}static void printk_buf(int level, const u8 * data, u32 len){ char line[81]; u32 ofs = 0; if (!(ipw_debug_level & level)) return; while (len) { snprint_line(line, sizeof(line), &data[ofs], min(len, 16U), ofs); printk(KERN_DEBUG "%s\n", line); ofs += 16; len -= min(len, 16U); }}static int snprintk_buf(u8 * output, size_t size, const u8 * data, size_t len){ size_t out = size; u32 ofs = 0; int total = 0; while (size && len) { out = snprint_line(output, size, &data[ofs], min_t(size_t, len, 16U), ofs); ofs += 16; output += out; size -= out; len -= min_t(size_t, len, 16U); total += out; } return total;}/* alias for 32-bit indirect read (for SRAM/reg above 4K), with debug wrapper */static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg);#define ipw_read_reg32(a, b) _ipw_read_reg32(a, b)/* alias for 8-bit indirect read (for SRAM/reg above 4K), with debug wrapper */static u8 _ipw_read_reg8(struct ipw_priv *ipw, u32 reg);#define ipw_read_reg8(a, b) _ipw_read_reg8(a, b)/* 8-bit indirect write (for SRAM/reg above 4K), with debug wrapper */static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value);static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c){ IPW_DEBUG_IO("%s %d: write_indirect8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32) (b), (u32) (c)); _ipw_write_reg8(a, b, c);}/* 16-bit indirect write (for SRAM/reg above 4K), with debug wrapper */static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value);static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c){ IPW_DEBUG_IO("%s %d: write_indirect16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32) (b), (u32) (c)); _ipw_write_reg16(a, b, c);}/* 32-bit indirect write (for SRAM/reg above 4K), with debug wrapper */static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value);static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c){ IPW_DEBUG_IO("%s %d: write_indirect32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32) (b), (u32) (c)); _ipw_write_reg32(a, b, c);}/* 8-bit direct write (low 4K) */#define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs))/* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */#define ipw_write8(ipw, ofs, val) \ IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ _ipw_write8(ipw, ofs, val)/* 16-bit direct write (low 4K) */#define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs))/* 16-bit direct write (for low 4K of SRAM/regs), with debug wrapper */#define ipw_write16(ipw, ofs, val) \ IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ _ipw_write16(ipw, ofs, val)/* 32-bit direct write (low 4K) */#define _ipw_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs))/* 32-bit direct write (for low 4K of SRAM/regs), with debug wrapper */#define ipw_write32(ipw, ofs, val) \ IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ _ipw_write32(ipw, ofs, val)/* 8-bit direct read (low 4K) */#define _ipw_read8(ipw, ofs) readb((ipw)->hw_base + (ofs))/* 8-bit direct read (low 4K), with debug wrapper */static inline u8 __ipw_read8(char *f, u32 l, struct ipw_priv *ipw, u32 ofs){ IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", f, l, (u32) (ofs)); return _ipw_read8(ipw, ofs);}/* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */#define ipw_read8(ipw, ofs) __ipw_read8(__FILE__, __LINE__, ipw, ofs)/* 16-bit direct read (low 4K) */#define _ipw_read16(ipw, ofs) readw((ipw)->hw_base + (ofs))/* 16-bit direct read (low 4K), with debug wrapper */static inline u16 __ipw_read16(char *f, u32 l, struct ipw_priv *ipw, u32 ofs){ IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", f, l, (u32) (ofs)); return _ipw_read16(ipw, ofs);}/* alias to 16-bit direct read (low 4K of SRAM/regs), with debug wrapper */#define ipw_read16(ipw, ofs) __ipw_read16(__FILE__, __LINE__, ipw, ofs)/* 32-bit direct read (low 4K) */#define _ipw_read32(ipw, ofs) readl((ipw)->hw_base + (ofs))/* 32-bit direct read (low 4K), with debug wrapper */static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs){ IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", f, l, (u32) (ofs)); return _ipw_read32(ipw, ofs);}/* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */#define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs)/* multi-byte read (above 4K), with debug wrapper */static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int);static inline void __ipw_read_indirect(const char *f, int l, struct ipw_priv *a, u32 b, u8 * c, int d){ IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", f, l, (u32) (b), d); _ipw_read_indirect(a, b, c, d);}/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */#define ipw_read_indirect(a, b, c, d) __ipw_read_indirect(__FILE__, __LINE__, a, b, c, d)/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data, int num);#define ipw_write_indirect(a, b, c, d) \ IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ _ipw_write_indirect(a, b, c, d)/* 32-bit indirect write (above 4K) */static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value){ IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value); _ipw_write32(priv, IPW_INDIRECT_ADDR, reg); _ipw_write32(priv, IPW_INDIRECT_DATA, value);}/* 8-bit indirect write (above 4K) */static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value){ u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ u32 dif_len = reg - aligned_addr; IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); _ipw_write8(priv, IPW_INDIRECT_DATA + dif_len, value);}/* 16-bit indirect write (above 4K) */static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value){ u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ u32 dif_len = (reg - aligned_addr) & (~0x1ul); IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); _ipw_write16(priv, IPW_INDIRECT_DATA + dif_len, value);}/* 8-bit indirect read (above 4K) */static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg){ u32 word; _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK); IPW_DEBUG_IO(" reg = 0x%8X : \n", reg); word = _ipw_read32(priv, IPW_INDIRECT_DATA); return (word >> ((reg & 0x3) * 8)) & 0xff;}/* 32-bit indirect read (above 4K) */static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg){ u32 value; IPW_DEBUG_IO("%p : reg = 0x%08x\n", priv, reg); _ipw_write32(priv, IPW_INDIRECT_ADDR, reg); value = _ipw_read32(priv, IPW_INDIRECT_DATA); IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x \n", reg, value); return value;}/* General purpose, no alignment requirement, iterative (multi-byte) read, *//* for area above 1st 4K of SRAM/reg space */static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, int num){ u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */ u32 dif_len = addr - aligned_addr; u32 i; IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); if (num <= 0) { return; } /* Read the first dword (or portion) byte by byte */ if (unlikely(dif_len)) { _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); /* Start reading at aligned_addr + dif_len */ for (i = dif_len; ((i < 4) && (num > 0)); i++, num--) *buf++ = _ipw_read8(priv, IPW_INDIRECT_DATA + i); aligned_addr += 4; } /* Read all of the middle dwords as dwords, with auto-increment */ _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr); for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) *(u32 *) buf = _ipw_read32(priv, IPW_AUTOINC_DATA); /* Read the last dword (or portion) byte by byte */ if (unlikely(num)) { _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); for (i = 0; num > 0; i++, num--) *buf++ = ipw_read8(priv, IPW_INDIRECT_DATA + i); }}/* General purpose, no alignment requirement, iterative (multi-byte) write, *//* for area above 1st 4K of SRAM/reg space */static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, int num){ u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -