📄 main.c
字号:
/* * * Broadcom B43legacy wireless driver * * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de> * Copyright (c) 2005 Stefano Brivio <st3@riseup.net> * Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de> * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> * Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net> * * Some parts of the code in this file are derived from the ipw2200 * driver Copyright(c) 2003 - 2004 Intel Corporation. * 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; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, * Boston, MA 02110-1301, USA. * */#include <linux/delay.h>#include <linux/init.h>#include <linux/moduleparam.h>#include <linux/if_arp.h>#include <linux/etherdevice.h>#include <linux/version.h>#include <linux/firmware.h>#include <linux/wireless.h>#include <linux/workqueue.h>#include <linux/skbuff.h>#include <linux/dma-mapping.h>#include <net/dst.h>#include <asm/unaligned.h>#include "b43legacy.h"#include "main.h"#include "debugfs.h"#include "phy.h"#include "dma.h"#include "pio.h"#include "sysfs.h"#include "xmit.h"#include "radio.h"MODULE_DESCRIPTION("Broadcom B43legacy wireless driver");MODULE_AUTHOR("Martin Langer");MODULE_AUTHOR("Stefano Brivio");MODULE_AUTHOR("Michael Buesch");MODULE_LICENSE("GPL");#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)static int modparam_pio;module_param_named(pio, modparam_pio, int, 0444);MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");#elif defined(CONFIG_B43LEGACY_DMA)# define modparam_pio 0#elif defined(CONFIG_B43LEGACY_PIO)# define modparam_pio 1#endifstatic int modparam_bad_frames_preempt;module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames" " Preemption");static int modparam_short_retry = B43legacy_DEFAULT_SHORT_RETRY_LIMIT;module_param_named(short_retry, modparam_short_retry, int, 0444);MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");static int modparam_long_retry = B43legacy_DEFAULT_LONG_RETRY_LIMIT;module_param_named(long_retry, modparam_long_retry, int, 0444);MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");static int modparam_noleds;module_param_named(noleds, modparam_noleds, int, 0444);MODULE_PARM_DESC(noleds, "Turn off all LED activity");static char modparam_fwpostfix[16];module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load.");/* The following table supports BCM4301, BCM4303 and BCM4306/2 devices. */static const struct ssb_device_id b43legacy_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 4), SSB_DEVTABLE_END};MODULE_DEVICE_TABLE(ssb, b43legacy_ssb_tbl);/* Channel and ratetables are shared for all devices. * They can't be const, because ieee80211 puts some precalculated * data in there. This data is the same for all devices, so we don't * get concurrency issues */#define RATETAB_ENT(_rateid, _flags) \ { \ .rate = B43legacy_RATE_TO_100KBPS(_rateid), \ .val = (_rateid), \ .val2 = (_rateid), \ .flags = (_flags), \ }static struct ieee80211_rate __b43legacy_ratetable[] = { RATETAB_ENT(B43legacy_CCK_RATE_1MB, IEEE80211_RATE_CCK), RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_CCK_2), RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_CCK_2), RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_CCK_2), RATETAB_ENT(B43legacy_OFDM_RATE_6MB, IEEE80211_RATE_OFDM), RATETAB_ENT(B43legacy_OFDM_RATE_9MB, IEEE80211_RATE_OFDM), RATETAB_ENT(B43legacy_OFDM_RATE_12MB, IEEE80211_RATE_OFDM), RATETAB_ENT(B43legacy_OFDM_RATE_18MB, IEEE80211_RATE_OFDM), RATETAB_ENT(B43legacy_OFDM_RATE_24MB, IEEE80211_RATE_OFDM), RATETAB_ENT(B43legacy_OFDM_RATE_36MB, IEEE80211_RATE_OFDM), RATETAB_ENT(B43legacy_OFDM_RATE_48MB, IEEE80211_RATE_OFDM), RATETAB_ENT(B43legacy_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),};#define b43legacy_a_ratetable (__b43legacy_ratetable + 4)#define b43legacy_a_ratetable_size 8#define b43legacy_b_ratetable (__b43legacy_ratetable + 0)#define b43legacy_b_ratetable_size 4#define b43legacy_g_ratetable (__b43legacy_ratetable + 0)#define b43legacy_g_ratetable_size 12#define CHANTAB_ENT(_chanid, _freq) \ { \ .chan = (_chanid), \ .freq = (_freq), \ .val = (_chanid), \ .flag = IEEE80211_CHAN_W_SCAN | \ IEEE80211_CHAN_W_ACTIVE_SCAN | \ IEEE80211_CHAN_W_IBSS, \ .power_level = 0x0A, \ .antenna_max = 0xFF, \ }static struct ieee80211_channel b43legacy_bg_chantable[] = { CHANTAB_ENT(1, 2412), CHANTAB_ENT(2, 2417), CHANTAB_ENT(3, 2422), CHANTAB_ENT(4, 2427), CHANTAB_ENT(5, 2432), CHANTAB_ENT(6, 2437), CHANTAB_ENT(7, 2442), CHANTAB_ENT(8, 2447), CHANTAB_ENT(9, 2452), CHANTAB_ENT(10, 2457), CHANTAB_ENT(11, 2462), CHANTAB_ENT(12, 2467), CHANTAB_ENT(13, 2472), CHANTAB_ENT(14, 2484),};#define b43legacy_bg_chantable_size ARRAY_SIZE(b43legacy_bg_chantable)static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev);static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev);static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev);static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev);static int b43legacy_ratelimit(struct b43legacy_wl *wl){ if (!wl || !wl->current_dev) return 1; if (b43legacy_status(wl->current_dev) < B43legacy_STAT_STARTED) return 1; /* We are up and running. * Ratelimit the messages to avoid DoS over the net. */ return net_ratelimit();}void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...){ va_list args; if (!b43legacy_ratelimit(wl)) return; va_start(args, fmt); printk(KERN_INFO "b43legacy-%s: ", (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); vprintk(fmt, args); va_end(args);}void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...){ va_list args; if (!b43legacy_ratelimit(wl)) return; va_start(args, fmt); printk(KERN_ERR "b43legacy-%s ERROR: ", (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); vprintk(fmt, args); va_end(args);}void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...){ va_list args; if (!b43legacy_ratelimit(wl)) return; va_start(args, fmt); printk(KERN_WARNING "b43legacy-%s warning: ", (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); vprintk(fmt, args); va_end(args);}#if B43legacy_DEBUGvoid b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...){ va_list args; va_start(args, fmt); printk(KERN_DEBUG "b43legacy-%s debug: ", (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan"); vprintk(fmt, args); va_end(args);}#endif /* DEBUG */static void b43legacy_ram_write(struct b43legacy_wldev *dev, u16 offset, u32 val){ u32 status; B43legacy_WARN_ON(offset % 4 != 0); status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); if (status & B43legacy_SBF_XFER_REG_BYTESWAP) val = swab32(val); b43legacy_write32(dev, B43legacy_MMIO_RAM_CONTROL, offset); mmiowb(); b43legacy_write32(dev, B43legacy_MMIO_RAM_DATA, val);}static inlinevoid b43legacy_shm_control_word(struct b43legacy_wldev *dev, u16 routing, u16 offset){ u32 control; /* "offset" is the WORD offset. */ control = routing; control <<= 16; control |= offset; b43legacy_write32(dev, B43legacy_MMIO_SHM_CONTROL, control);}u32 b43legacy_shm_read32(struct b43legacy_wldev *dev, u16 routing, u16 offset){ u32 ret; if (routing == B43legacy_SHM_SHARED) { B43legacy_WARN_ON((offset & 0x0001) != 0); if (offset & 0x0003) { /* Unaligned access */ b43legacy_shm_control_word(dev, routing, offset >> 2); ret = b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA_UNALIGNED); ret <<= 16; b43legacy_shm_control_word(dev, routing, (offset >> 2) + 1); ret |= b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA); return ret; } offset >>= 2; } b43legacy_shm_control_word(dev, routing, offset); ret = b43legacy_read32(dev, B43legacy_MMIO_SHM_DATA); return ret;}u16 b43legacy_shm_read16(struct b43legacy_wldev *dev, u16 routing, u16 offset){ u16 ret; if (routing == B43legacy_SHM_SHARED) { B43legacy_WARN_ON((offset & 0x0001) != 0); if (offset & 0x0003) { /* Unaligned access */ b43legacy_shm_control_word(dev, routing, offset >> 2); ret = b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA_UNALIGNED); return ret; } offset >>= 2; } b43legacy_shm_control_word(dev, routing, offset); ret = b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA); return ret;}void b43legacy_shm_write32(struct b43legacy_wldev *dev, u16 routing, u16 offset, u32 value){ if (routing == B43legacy_SHM_SHARED) { B43legacy_WARN_ON((offset & 0x0001) != 0); if (offset & 0x0003) { /* Unaligned access */ b43legacy_shm_control_word(dev, routing, offset >> 2); mmiowb(); b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA_UNALIGNED, (value >> 16) & 0xffff); mmiowb(); b43legacy_shm_control_word(dev, routing, (offset >> 2) + 1); mmiowb(); b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA, value & 0xffff); return; } offset >>= 2; } b43legacy_shm_control_word(dev, routing, offset); mmiowb(); b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, value);}void b43legacy_shm_write16(struct b43legacy_wldev *dev, u16 routing, u16 offset, u16 value){ if (routing == B43legacy_SHM_SHARED) { B43legacy_WARN_ON((offset & 0x0001) != 0); if (offset & 0x0003) { /* Unaligned access */ b43legacy_shm_control_word(dev, routing, offset >> 2); mmiowb(); b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA_UNALIGNED, value); return; } offset >>= 2; } b43legacy_shm_control_word(dev, routing, offset); mmiowb(); b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA, value);}/* Read HostFlags */u32 b43legacy_hf_read(struct b43legacy_wldev *dev){ u32 ret; ret = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, B43legacy_SHM_SH_HOSTFHI); ret <<= 16; ret |= b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, B43legacy_SHM_SH_HOSTFLO); return ret;}/* Write HostFlags */void b43legacy_hf_write(struct b43legacy_wldev *dev, u32 value){ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, B43legacy_SHM_SH_HOSTFLO, (value & 0x0000FFFF)); b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, B43legacy_SHM_SH_HOSTFHI, ((value & 0xFFFF0000) >> 16));}void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf){ /* We need to be careful. As we read the TSF from multiple * registers, we should take care of register overflows. * In theory, the whole tsf read process should be atomic. * We try to be atomic here, by restaring the read process, * if any of the high registers changed (overflew). */ if (dev->dev->id.revision >= 3) { u32 low; u32 high; u32 high2; do { high = b43legacy_read32(dev, B43legacy_MMIO_REV3PLUS_TSF_HIGH); low = b43legacy_read32(dev, B43legacy_MMIO_REV3PLUS_TSF_LOW); high2 = b43legacy_read32(dev, B43legacy_MMIO_REV3PLUS_TSF_HIGH); } while (unlikely(high != high2)); *tsf = high; *tsf <<= 32; *tsf |= low; } else { u64 tmp; u16 v0; u16 v1; u16 v2; u16 v3; u16 test1; u16 test2; u16 test3; do { v3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3); v2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2); v1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1); v0 = b43legacy_read16(dev, B43legacy_MMIO_TSF_0); test3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3); test2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2); test1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1); } while (v3 != test3 || v2 != test2 || v1 != test1); *tsf = v3; *tsf <<= 48; tmp = v2; tmp <<= 32; *tsf |= tmp; tmp = v1; tmp <<= 16; *tsf |= tmp; *tsf |= v0; }}static void b43legacy_time_lock(struct b43legacy_wldev *dev){ u32 status; status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); status |= B43legacy_SBF_TIME_UPDATE; b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); mmiowb();}static void b43legacy_time_unlock(struct b43legacy_wldev *dev){ u32 status; status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); status &= ~B43legacy_SBF_TIME_UPDATE; b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);}static void b43legacy_tsf_write_locked(struct b43legacy_wldev *dev, u64 tsf){ /* Be careful with the in-progress timer. * First zero out the low register, so we have a full
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -