[B43]: add mac80211-based driver for modern BCM43xx devices

Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Michael Buesch 2007-09-18 15:39:42 -04:00 committed by David S. Miller
parent 61e115a56d
commit e4d6b79518
28 changed files with 16699 additions and 0 deletions

View file

@ -795,6 +795,15 @@ L: linux-hams@vger.kernel.org
W: http://www.baycom.org/~tom/ham/ham.html
S: Maintained
B43 WIRELESS DRIVER
P: Michael Buesch
M: mb@bu3sch.de
P: Stefano Brivio
M: st3@riseup.net
L: linux-wireless@vger.kernel.org
W: http://bcm43xx.berlios.de/
S: Maintained
BCM43XX WIRELESS DRIVER (SOFTMAC BASED VERSION)
P: Larry Finger
M: Larry.Finger@lwfinger.net

View file

@ -579,6 +579,7 @@ config ADM8211
source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/bcm43xx/Kconfig"
source "drivers/net/wireless/b43/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
endmenu

View file

@ -36,6 +36,7 @@ obj-$(CONFIG_PRISM54) += prism54/
obj-$(CONFIG_HOSTAP) += hostap/
obj-$(CONFIG_BCM43XX) += bcm43xx/
obj-$(CONFIG_B43) += b43/
obj-$(CONFIG_ZD1211RW) += zd1211rw/
# 16-bit wireless PCMCIA client drivers

View file

@ -0,0 +1,119 @@
config B43
tristate "Broadcom 43xx wireless support (mac80211 stack)"
depends on SSB_POSSIBLE && MAC80211 && WLAN_80211
select SSB
select FW_LOADER
select HW_RANDOM
---help---
b43 is a driver for the Broadcom 43xx series wireless devices.
Check "lspci" for something like
"Broadcom Corporation BCM43XX 802.11 Wireless LAN Controller"
to determine whether you own such a device.
This driver supports the new BCM43xx IEEE 802.11G devices, but not
the old IEEE 802.11B devices. Old devices are supported by
the b43legacy driver.
Note that this has nothing to do with the standard that your AccessPoint
supports (A, B, G or a combination).
IEEE 802.11G devices can talk to IEEE 802.11B AccessPoints.
It is safe to include both b43 and b43legacy as the underlying glue
layer will automatically load the correct version for your device.
This driver uses V4 firmware, which must be installed separately using
b43-fwcutter.
This driver can be built as a module (recommended) that will be called "b43".
If unsure, say M.
# Auto-select SSB PCI-HOST support, if possible
config B43_PCI_AUTOSELECT
bool
depends on B43 && SSB_PCIHOST_POSSIBLE
select SSB_PCIHOST
default y
# Auto-select SSB PCICORE driver, if possible
config B43_PCICORE_AUTOSELECT
bool
depends on B43 && SSB_DRIVER_PCICORE_POSSIBLE
select SSB_DRIVER_PCICORE
default y
config B43_PCMCIA
bool "Broadcom 43xx PCMCIA device support (EXPERIMENTAL)"
depends on B43 && SSB_PCMCIAHOST_POSSIBLE && EXPERIMENTAL
select SSB_PCMCIAHOST
---help---
Broadcom 43xx PCMCIA device support.
Support for 16bit PCMCIA devices.
Please note that most PC-CARD devices are _NOT_ 16bit PCMCIA
devices, but 32bit CardBUS devices. CardBUS devices are supported
out of the box by b43.
With this config option you can drive b43 cards in
CompactFlash formfactor in a PCMCIA adaptor.
CF b43 cards can sometimes be found in handheld PCs.
It's safe to select Y here, even if you don't have a B43 PCMCIA device.
If unsure, say N.
config B43_DEBUG
bool "Broadcom 43xx debugging"
depends on B43
---help---
Broadcom 43xx debugging messages.
Say Y, if you want to find out why the driver does not
work for you.
config B43_DMA
bool
depends on B43
config B43_PIO
bool
depends on B43
choice
prompt "Broadcom 43xx data transfer mode"
depends on B43
default B43_DMA_AND_PIO_MODE
config B43_DMA_AND_PIO_MODE
bool "DMA + PIO"
select B43_DMA
select B43_PIO
---help---
Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
data transfer modes.
The actually used mode is selectable through the module
parameter "pio". If the module parameter is pio=0, DMA is used.
Otherwise PIO is used. DMA is default.
If unsure, choose this option.
config B43_DMA_MODE
bool "DMA (Direct Memory Access) only"
select B43_DMA
---help---
Only include Direct Memory Access (DMA).
This reduces the size of the driver module, by omitting the PIO code.
config B43_PIO_MODE
bool "PIO (Programmed I/O) only"
select B43_PIO
---help---
Only include Programmed I/O (PIO).
This reduces the size of the driver module, by omitting the DMA code.
Please note that PIO transfers are slow (compared to DMA).
Also note that not all devices of the 43xx series support PIO.
The 4306 (Apple Airport Extreme and others) supports PIO, while
the 4318 is known to _not_ support PIO.
Only use PIO, if DMA does not work for you.
endchoice

View file

@ -0,0 +1,17 @@
# b43 core
b43-y += main.o
b43-y += tables.o
b43-y += phy.o
b43-y += sysfs.o
b43-y += leds.o
b43-y += xmit.o
b43-y += lo.o
# b43 PCMCIA support
b43-$(CONFIG_B43_PCMCIA) += pcmcia.o
# b43 debugging
b43-$(CONFIG_B43_DEBUG) += debugfs.o
# b43 DMA and PIO
b43-$(CONFIG_B43_DMA) += dma.o
b43-$(CONFIG_B43_PIO) += pio.o
obj-$(CONFIG_B43) += b43.o

View file

@ -0,0 +1,845 @@
#ifndef B43_H_
#define B43_H_
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/hw_random.h>
#include <linux/ssb/ssb.h>
#include <net/mac80211.h>
#include "debugfs.h"
#include "leds.h"
#include "lo.h"
#include "phy.h"
#ifdef CONFIG_B43_DEBUG
# define B43_DEBUG 1
#else
# define B43_DEBUG 0
#endif
#define B43_RX_MAX_SSI 60
/* MMIO offsets */
#define B43_MMIO_DMA0_REASON 0x20
#define B43_MMIO_DMA0_IRQ_MASK 0x24
#define B43_MMIO_DMA1_REASON 0x28
#define B43_MMIO_DMA1_IRQ_MASK 0x2C
#define B43_MMIO_DMA2_REASON 0x30
#define B43_MMIO_DMA2_IRQ_MASK 0x34
#define B43_MMIO_DMA3_REASON 0x38
#define B43_MMIO_DMA3_IRQ_MASK 0x3C
#define B43_MMIO_DMA4_REASON 0x40
#define B43_MMIO_DMA4_IRQ_MASK 0x44
#define B43_MMIO_DMA5_REASON 0x48
#define B43_MMIO_DMA5_IRQ_MASK 0x4C
#define B43_MMIO_MACCTL 0x120
#define B43_MMIO_STATUS2_BITFIELD 0x124
#define B43_MMIO_GEN_IRQ_REASON 0x128
#define B43_MMIO_GEN_IRQ_MASK 0x12C
#define B43_MMIO_RAM_CONTROL 0x130
#define B43_MMIO_RAM_DATA 0x134
#define B43_MMIO_PS_STATUS 0x140
#define B43_MMIO_RADIO_HWENABLED_HI 0x158
#define B43_MMIO_SHM_CONTROL 0x160
#define B43_MMIO_SHM_DATA 0x164
#define B43_MMIO_SHM_DATA_UNALIGNED 0x166
#define B43_MMIO_XMITSTAT_0 0x170
#define B43_MMIO_XMITSTAT_1 0x174
#define B43_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
#define B43_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
/* 32-bit DMA */
#define B43_MMIO_DMA32_BASE0 0x200
#define B43_MMIO_DMA32_BASE1 0x220
#define B43_MMIO_DMA32_BASE2 0x240
#define B43_MMIO_DMA32_BASE3 0x260
#define B43_MMIO_DMA32_BASE4 0x280
#define B43_MMIO_DMA32_BASE5 0x2A0
/* 64-bit DMA */
#define B43_MMIO_DMA64_BASE0 0x200
#define B43_MMIO_DMA64_BASE1 0x240
#define B43_MMIO_DMA64_BASE2 0x280
#define B43_MMIO_DMA64_BASE3 0x2C0
#define B43_MMIO_DMA64_BASE4 0x300
#define B43_MMIO_DMA64_BASE5 0x340
/* PIO */
#define B43_MMIO_PIO1_BASE 0x300
#define B43_MMIO_PIO2_BASE 0x310
#define B43_MMIO_PIO3_BASE 0x320
#define B43_MMIO_PIO4_BASE 0x330
#define B43_MMIO_PHY_VER 0x3E0
#define B43_MMIO_PHY_RADIO 0x3E2
#define B43_MMIO_PHY0 0x3E6
#define B43_MMIO_ANTENNA 0x3E8
#define B43_MMIO_CHANNEL 0x3F0
#define B43_MMIO_CHANNEL_EXT 0x3F4
#define B43_MMIO_RADIO_CONTROL 0x3F6
#define B43_MMIO_RADIO_DATA_HIGH 0x3F8
#define B43_MMIO_RADIO_DATA_LOW 0x3FA
#define B43_MMIO_PHY_CONTROL 0x3FC
#define B43_MMIO_PHY_DATA 0x3FE
#define B43_MMIO_MACFILTER_CONTROL 0x420
#define B43_MMIO_MACFILTER_DATA 0x422
#define B43_MMIO_RCMTA_COUNT 0x43C
#define B43_MMIO_RADIO_HWENABLED_LO 0x49A
#define B43_MMIO_GPIO_CONTROL 0x49C
#define B43_MMIO_GPIO_MASK 0x49E
#define B43_MMIO_TSF_0 0x632 /* core rev < 3 only */
#define B43_MMIO_TSF_1 0x634 /* core rev < 3 only */
#define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */
#define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */
#define B43_MMIO_RNG 0x65A
#define B43_MMIO_POWERUP_DELAY 0x6A8
/* SPROM boardflags_lo values */
#define B43_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */
#define B43_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */
#define B43_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */
#define B43_BFL_RSSI 0x0008 /* software calculates nrssi slope. */
#define B43_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */
#define B43_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */
#define B43_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */
#define B43_BFL_ENETADM 0x0080 /* has ADMtek switch */
#define B43_BFL_ENETVLAN 0x0100 /* can do vlan */
#define B43_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */
#define B43_BFL_NOPCI 0x0400 /* leaves PCI floating */
#define B43_BFL_FEM 0x0800 /* supports the Front End Module */
#define B43_BFL_EXTLNA 0x1000 /* has an external LNA */
#define B43_BFL_HGPA 0x2000 /* had high gain PA */
#define B43_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */
#define B43_BFL_ALTIQ 0x8000 /* alternate I/Q settings */
/* GPIO register offset, in both ChipCommon and PCI core. */
#define B43_GPIO_CONTROL 0x6c
/* SHM Routing */
enum {
B43_SHM_UCODE, /* Microcode memory */
B43_SHM_SHARED, /* Shared memory */
B43_SHM_SCRATCH, /* Scratch memory */
B43_SHM_HW, /* Internal hardware register */
B43_SHM_RCMTA, /* Receive match transmitter address (rev >= 5 only) */
};
/* SHM Routing modifiers */
#define B43_SHM_AUTOINC_R 0x0200 /* Auto-increment address on read */
#define B43_SHM_AUTOINC_W 0x0100 /* Auto-increment address on write */
#define B43_SHM_AUTOINC_RW (B43_SHM_AUTOINC_R | \
B43_SHM_AUTOINC_W)
/* Misc SHM_SHARED offsets */
#define B43_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */
#define B43_SHM_SH_PCTLWDPOS 0x0008
#define B43_SHM_SH_RXPADOFF 0x0034 /* RX Padding data offset (PIO only) */
#define B43_SHM_SH_PHYVER 0x0050 /* PHY version */
#define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */
#define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */
#define B43_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */
#define B43_SHM_SH_HOSTFHI 0x0060 /* Hostflags for ucode options (high) */
#define B43_SHM_SH_RFATT 0x0064 /* Current radio attenuation value */
#define B43_SHM_SH_RADAR 0x0066 /* Radar register */
#define B43_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */
#define B43_SHM_SH_RFRXSP1 0x0072 /* RF RX SP Register 1 */
#define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */
#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */
#define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */
/* SHM_SHARED TX FIFO variables */
#define B43_SHM_SH_SIZE01 0x0098 /* TX FIFO size for FIFO 0 (low) and 1 (high) */
#define B43_SHM_SH_SIZE23 0x009A /* TX FIFO size for FIFO 2 and 3 */
#define B43_SHM_SH_SIZE45 0x009C /* TX FIFO size for FIFO 4 and 5 */
#define B43_SHM_SH_SIZE67 0x009E /* TX FIFO size for FIFO 6 and 7 */
/* SHM_SHARED background noise */
#define B43_SHM_SH_JSSI0 0x0088 /* Measure JSSI 0 */
#define B43_SHM_SH_JSSI1 0x008A /* Measure JSSI 1 */
#define B43_SHM_SH_JSSIAUX 0x008C /* Measure JSSI AUX */
/* SHM_SHARED crypto engine */
#define B43_SHM_SH_DEFAULTIV 0x003C /* Default IV location */
#define B43_SHM_SH_NRRXTRANS 0x003E /* # of soft RX transmitter addresses (max 8) */
#define B43_SHM_SH_KTP 0x0056 /* Key table pointer */
#define B43_SHM_SH_TKIPTSCTTAK 0x0318
#define B43_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block (v4 firmware) */
#define B43_SHM_SH_PSM 0x05F4 /* PSM transmitter address match block (rev < 5) */
/* SHM_SHARED WME variables */
#define B43_SHM_SH_EDCFSTAT 0x000E /* EDCF status */
#define B43_SHM_SH_TXFCUR 0x0030 /* TXF current index */
#define B43_SHM_SH_EDCFQ 0x0240 /* EDCF Q info */
/* SHM_SHARED powersave mode related */
#define B43_SHM_SH_SLOTT 0x0010 /* Slot time */
#define B43_SHM_SH_DTIMPER 0x0012 /* DTIM period */
#define B43_SHM_SH_NOSLPZNATDTIM 0x004C /* NOSLPZNAT DTIM */
/* SHM_SHARED beacon variables */
#define B43_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */
#define B43_SHM_SH_BTL1 0x001A /* Beacon template length 1 */
#define B43_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */
#define B43_SHM_SH_TIMBPOS 0x001E /* TIM B position in beacon */
#define B43_SHM_SH_SFFBLIM 0x0044 /* Short frame fallback retry limit */
#define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */
#define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */
/* SHM_SHARED ACK/CTS control */
#define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */
/* SHM_SHARED probe response variables */
#define B43_SHM_SH_PRSSID 0x0160 /* Probe Response SSID */
#define B43_SHM_SH_PRSSIDLEN 0x0048 /* Probe Response SSID length */
#define B43_SHM_SH_PRTLEN 0x004A /* Probe Response template length */
#define B43_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */
#define B43_SHM_SH_PRPHYCTL 0x0188 /* Probe Response PHY TX control word */
/* SHM_SHARED rate tables */
#define B43_SHM_SH_OFDMDIRECT 0x01C0 /* Pointer to OFDM direct map */
#define B43_SHM_SH_OFDMBASIC 0x01E0 /* Pointer to OFDM basic rate map */
#define B43_SHM_SH_CCKDIRECT 0x0200 /* Pointer to CCK direct map */
#define B43_SHM_SH_CCKBASIC 0x0220 /* Pointer to CCK basic rate map */
/* SHM_SHARED microcode soft registers */
#define B43_SHM_SH_UCODEREV 0x0000 /* Microcode revision */
#define B43_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */
#define B43_SHM_SH_UCODEDATE 0x0004 /* Microcode date */
#define B43_SHM_SH_UCODETIME 0x0006 /* Microcode time */
#define B43_SHM_SH_UCODESTAT 0x0040 /* Microcode debug status code */
#define B43_SHM_SH_UCODESTAT_INVALID 0
#define B43_SHM_SH_UCODESTAT_INIT 1
#define B43_SHM_SH_UCODESTAT_ACTIVE 2
#define B43_SHM_SH_UCODESTAT_SUSP 3 /* suspended */
#define B43_SHM_SH_UCODESTAT_SLEEP 4 /* asleep (PS) */
#define B43_SHM_SH_MAXBFRAMES 0x0080 /* Maximum number of frames in a burst */
#define B43_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */
#define B43_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */
/* SHM_SCRATCH offsets */
#define B43_SHM_SC_MINCONT 0x0003 /* Minimum contention window */
#define B43_SHM_SC_MAXCONT 0x0004 /* Maximum contention window */
#define B43_SHM_SC_CURCONT 0x0005 /* Current contention window */
#define B43_SHM_SC_SRLIMIT 0x0006 /* Short retry count limit */
#define B43_SHM_SC_LRLIMIT 0x0007 /* Long retry count limit */
#define B43_SHM_SC_DTIMC 0x0008 /* Current DTIM count */
#define B43_SHM_SC_BTL0LEN 0x0015 /* Beacon 0 template length */
#define B43_SHM_SC_BTL1LEN 0x0016 /* Beacon 1 template length */
#define B43_SHM_SC_SCFB 0x0017 /* Short frame transmit count threshold for rate fallback */
#define B43_SHM_SC_LCFB 0x0018 /* Long frame transmit count threshold for rate fallback */
/* Hardware Radio Enable masks */
#define B43_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
#define B43_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
/* HostFlags. See b43_hf_read/write() */
#define B43_HF_ANTDIVHELP 0x00000001 /* ucode antenna div helper */
#define B43_HF_SYMW 0x00000002 /* G-PHY SYM workaround */
#define B43_HF_RXPULLW 0x00000004 /* RX pullup workaround */
#define B43_HF_CCKBOOST 0x00000008 /* 4dB CCK power boost (exclusive with OFDM boost) */
#define B43_HF_BTCOEX 0x00000010 /* Bluetooth coexistance */
#define B43_HF_GDCW 0x00000020 /* G-PHY DV canceller filter bw workaround */
#define B43_HF_OFDMPABOOST 0x00000040 /* Enable PA gain boost for OFDM */
#define B43_HF_ACPR 0x00000080 /* Disable for Japan, channel 14 */
#define B43_HF_EDCF 0x00000100 /* on if WME and MAC suspended */
#define B43_HF_TSSIRPSMW 0x00000200 /* TSSI reset PSM ucode workaround */
#define B43_HF_DSCRQ 0x00000400 /* Disable slow clock request in ucode */
#define B43_HF_ACIW 0x00000800 /* ACI workaround: shift bits by 2 on PHY CRS */
#define B43_HF_2060W 0x00001000 /* 2060 radio workaround */
#define B43_HF_RADARW 0x00002000 /* Radar workaround */
#define B43_HF_USEDEFKEYS 0x00004000 /* Enable use of default keys */
#define B43_HF_BT4PRIOCOEX 0x00010000 /* Bluetooth 2-priority coexistance */
#define B43_HF_FWKUP 0x00020000 /* Fast wake-up ucode */
#define B43_HF_VCORECALC 0x00040000 /* Force VCO recalculation when powering up synthpu */
#define B43_HF_PCISCW 0x00080000 /* PCI slow clock workaround */
#define B43_HF_4318TSSI 0x00200000 /* 4318 TSSI */
#define B43_HF_FBCMCFIFO 0x00400000 /* Flush bcast/mcast FIFO immediately */
#define B43_HF_HWPCTL 0x00800000 /* Enable hardwarre power control */
#define B43_HF_BTCOEXALT 0x01000000 /* Bluetooth coexistance in alternate pins */
#define B43_HF_TXBTCHECK 0x02000000 /* Bluetooth check during transmission */
#define B43_HF_SKCFPUP 0x04000000 /* Skip CFP update */
/* MacFilter offsets. */
#define B43_MACFILTER_SELF 0x0000
#define B43_MACFILTER_BSSID 0x0003
/* PowerControl */
#define B43_PCTL_IN 0xB0
#define B43_PCTL_OUT 0xB4
#define B43_PCTL_OUTENABLE 0xB8
#define B43_PCTL_XTAL_POWERUP 0x40
#define B43_PCTL_PLL_POWERDOWN 0x80
/* PowerControl Clock Modes */
#define B43_PCTL_CLK_FAST 0x00
#define B43_PCTL_CLK_SLOW 0x01
#define B43_PCTL_CLK_DYNAMIC 0x02
#define B43_PCTL_FORCE_SLOW 0x0800
#define B43_PCTL_FORCE_PLL 0x1000
#define B43_PCTL_DYN_XTAL 0x2000
/* PHYVersioning */
#define B43_PHYTYPE_A 0x00
#define B43_PHYTYPE_B 0x01
#define B43_PHYTYPE_G 0x02
/* PHYRegisters */
#define B43_PHY_ILT_A_CTRL 0x0072
#define B43_PHY_ILT_A_DATA1 0x0073
#define B43_PHY_ILT_A_DATA2 0x0074
#define B43_PHY_G_LO_CONTROL 0x0810
#define B43_PHY_ILT_G_CTRL 0x0472
#define B43_PHY_ILT_G_DATA1 0x0473
#define B43_PHY_ILT_G_DATA2 0x0474
#define B43_PHY_A_PCTL 0x007B
#define B43_PHY_G_PCTL 0x0029
#define B43_PHY_A_CRS 0x0029
#define B43_PHY_RADIO_BITFIELD 0x0401
#define B43_PHY_G_CRS 0x0429
#define B43_PHY_NRSSILT_CTRL 0x0803
#define B43_PHY_NRSSILT_DATA 0x0804
/* RadioRegisters */
#define B43_RADIOCTL_ID 0x01
/* MAC Control bitfield */
#define B43_MACCTL_ENABLED 0x00000001 /* MAC Enabled */
#define B43_MACCTL_PSM_RUN 0x00000002 /* Run Microcode */
#define B43_MACCTL_PSM_JMP0 0x00000004 /* Microcode jump to 0 */
#define B43_MACCTL_SHM_ENABLED 0x00000100 /* SHM Enabled */
#define B43_MACCTL_SHM_UPPER 0x00000200 /* SHM Upper */
#define B43_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */
#define B43_MACCTL_PSM_DBG 0x00002000 /* Microcode debugging enabled */
#define B43_MACCTL_GPOUTSMSK 0x0000C000 /* GPOUT Select Mask */
#define B43_MACCTL_BE 0x00010000 /* Big Endian mode */
#define B43_MACCTL_INFRA 0x00020000 /* Infrastructure mode */
#define B43_MACCTL_AP 0x00040000 /* AccessPoint mode */
#define B43_MACCTL_RADIOLOCK 0x00080000 /* Radio lock */
#define B43_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */
#define B43_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep frames with bad PLCP */
#define B43_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */
#define B43_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */
#define B43_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */
#define B43_MACCTL_HWPS 0x02000000 /* Hardware Power Saving */
#define B43_MACCTL_AWAKE 0x04000000 /* Device is awake */
#define B43_MACCTL_CLOSEDNET 0x08000000 /* Closed net (no SSID bcast) */
#define B43_MACCTL_TBTTHOLD 0x10000000 /* TBTT Hold */
#define B43_MACCTL_DISCTXSTAT 0x20000000 /* Discard TX status */
#define B43_MACCTL_DISCPMQ 0x40000000 /* Discard Power Management Queue */
#define B43_MACCTL_GMODE 0x80000000 /* G Mode */
/* 802.11 core specific TM State Low flags */
#define B43_TMSLOW_GMODE 0x20000000 /* G Mode Enable */
#define B43_TMSLOW_PLLREFSEL 0x00200000 /* PLL Frequency Reference Select */
#define B43_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Control Enable (rev >= 5) */
#define B43_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */
#define B43_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */
/* 802.11 core specific TM State High flags */
#define B43_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available (rev >= 5) */
#define B43_TMSHIGH_APHY 0x00020000 /* A-PHY available (rev >= 5) */
#define B43_TMSHIGH_GPHY 0x00010000 /* G-PHY available (rev >= 5) */
/* Generic-Interrupt reasons. */
#define B43_IRQ_MAC_SUSPENDED 0x00000001
#define B43_IRQ_BEACON 0x00000002
#define B43_IRQ_TBTT_INDI 0x00000004
#define B43_IRQ_BEACON_TX_OK 0x00000008
#define B43_IRQ_BEACON_CANCEL 0x00000010
#define B43_IRQ_ATIM_END 0x00000020
#define B43_IRQ_PMQ 0x00000040
#define B43_IRQ_PIO_WORKAROUND 0x00000100
#define B43_IRQ_MAC_TXERR 0x00000200
#define B43_IRQ_PHY_TXERR 0x00000800
#define B43_IRQ_PMEVENT 0x00001000
#define B43_IRQ_TIMER0 0x00002000
#define B43_IRQ_TIMER1 0x00004000
#define B43_IRQ_DMA 0x00008000
#define B43_IRQ_TXFIFO_FLUSH_OK 0x00010000
#define B43_IRQ_CCA_MEASURE_OK 0x00020000
#define B43_IRQ_NOISESAMPLE_OK 0x00040000
#define B43_IRQ_UCODE_DEBUG 0x08000000
#define B43_IRQ_RFKILL 0x10000000
#define B43_IRQ_TX_OK 0x20000000
#define B43_IRQ_PHY_G_CHANGED 0x40000000
#define B43_IRQ_TIMEOUT 0x80000000
#define B43_IRQ_ALL 0xFFFFFFFF
#define B43_IRQ_MASKTEMPLATE (B43_IRQ_MAC_SUSPENDED | \
B43_IRQ_BEACON | \
B43_IRQ_TBTT_INDI | \
B43_IRQ_ATIM_END | \
B43_IRQ_PMQ | \
B43_IRQ_MAC_TXERR | \
B43_IRQ_PHY_TXERR | \
B43_IRQ_DMA | \
B43_IRQ_TXFIFO_FLUSH_OK | \
B43_IRQ_NOISESAMPLE_OK | \
B43_IRQ_UCODE_DEBUG | \
B43_IRQ_RFKILL | \
B43_IRQ_TX_OK)
/* Device specific rate values.
* The actual values defined here are (rate_in_mbps * 2).
* Some code depends on this. Don't change it. */
#define B43_CCK_RATE_1MB 0x02
#define B43_CCK_RATE_2MB 0x04
#define B43_CCK_RATE_5MB 0x0B
#define B43_CCK_RATE_11MB 0x16
#define B43_OFDM_RATE_6MB 0x0C
#define B43_OFDM_RATE_9MB 0x12
#define B43_OFDM_RATE_12MB 0x18
#define B43_OFDM_RATE_18MB 0x24
#define B43_OFDM_RATE_24MB 0x30
#define B43_OFDM_RATE_36MB 0x48
#define B43_OFDM_RATE_48MB 0x60
#define B43_OFDM_RATE_54MB 0x6C
/* Convert a b43 rate value to a rate in 100kbps */
#define B43_RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
#define B43_DEFAULT_SHORT_RETRY_LIMIT 7
#define B43_DEFAULT_LONG_RETRY_LIMIT 4
/* Max size of a security key */
#define B43_SEC_KEYSIZE 16
/* Security algorithms. */
enum {
B43_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
B43_SEC_ALGO_WEP40,
B43_SEC_ALGO_TKIP,
B43_SEC_ALGO_AES,
B43_SEC_ALGO_WEP104,
B43_SEC_ALGO_AES_LEGACY,
};
struct b43_dmaring;
struct b43_pioqueue;
/* The firmware file header */
#define B43_FW_TYPE_UCODE 'u'
#define B43_FW_TYPE_PCM 'p'
#define B43_FW_TYPE_IV 'i'
struct b43_fw_header {
/* File type */
u8 type;
/* File format version */
u8 ver;
u8 __padding[2];
/* Size of the data. For ucode and PCM this is in bytes.
* For IV this is number-of-ivs. */
__be32 size;
} __attribute__((__packed__));
/* Initial Value file format */
#define B43_IV_OFFSET_MASK 0x7FFF
#define B43_IV_32BIT 0x8000
struct b43_iv {
__be16 offset_size;
union {
__be16 d16;
__be32 d32;
} data __attribute__((__packed__));
} __attribute__((__packed__));
#define B43_PHYMODE(phytype) (1 << (phytype))
#define B43_PHYMODE_A B43_PHYMODE(B43_PHYTYPE_A)
#define B43_PHYMODE_B B43_PHYMODE(B43_PHYTYPE_B)
#define B43_PHYMODE_G B43_PHYMODE(B43_PHYTYPE_G)
struct b43_phy {
/* Possible PHYMODEs on this PHY */
u8 possible_phymodes;
/* GMODE bit enabled? */
bool gmode;
/* Possible ieee80211 subsystem hwmodes for this PHY.
* Which mode is selected, depends on thr GMODE enabled bit */
#define B43_MAX_PHYHWMODES 2
struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES];
/* Analog Type */
u8 analog;
/* B43_PHYTYPE_ */
u8 type;
/* PHY revision number. */
u8 rev;
/* Radio versioning */
u16 radio_manuf; /* Radio manufacturer */
u16 radio_ver; /* Radio version */
u8 radio_rev; /* Radio revision */
bool radio_on; /* Radio switched on/off */
bool locked; /* Only used in b43_phy_{un}lock() */
bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */
/* ACI (adjacent channel interference) flags. */
bool aci_enable;
bool aci_wlan_automatic;
bool aci_hw_rssi;
u16 minlowsig[2];
u16 minlowsigpos[2];
/* TSSI to dBm table in use */
const s8 *tssi2dbm;
/* Target idle TSSI */
int tgt_idle_tssi;
/* Current idle TSSI */
int cur_idle_tssi;
/* LocalOscillator control values. */
struct b43_txpower_lo_control *lo_control;
/* Values from b43_calc_loopback_gain() */
s16 max_lb_gain; /* Maximum Loopback gain in hdB */
s16 trsw_rx_gain; /* TRSW RX gain in hdB */
s16 lna_lod_gain; /* LNA lod */
s16 lna_gain; /* LNA */
s16 pga_gain; /* PGA */
/* PHY lock for core.rev < 3
* This lock is only used by b43_phy_{un}lock()
*/
spinlock_t lock;
/* Desired TX power level (in dBm).
* This is set by the user and adjusted in b43_phy_xmitpower(). */
u8 power_level;
/* A-PHY TX Power control value. */
u16 txpwr_offset;
/* Current TX power level attenuation control values */
struct b43_bbatt bbatt;
struct b43_rfatt rfatt;
u8 tx_control; /* B43_TXCTL_XXX */
#ifdef CONFIG_B43_DEBUG
bool manual_txpower_control; /* Manual TX-power control enabled? */
#endif
/* Hardware Power Control enabled? */
bool hardware_power_control;
/* Current Interference Mitigation mode */
int interfmode;
/* Stack of saved values from the Interference Mitigation code.
* Each value in the stack is layed out as follows:
* bit 0-11: offset
* bit 12-15: register ID
* bit 16-32: value
* register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
*/
#define B43_INTERFSTACK_SIZE 26
u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure
/* Saved values from the NRSSI Slope calculation */
s16 nrssi[2];
s32 nrssislope;
/* In memory nrssi lookup table. */
s8 nrssi_lt[64];
/* current channel */
u8 channel;
u16 lofcal;
u16 initval; //FIXME rename?
};
/* Data structures for DMA transmission, per 80211 core. */
struct b43_dma {
struct b43_dmaring *tx_ring0;
struct b43_dmaring *tx_ring1;
struct b43_dmaring *tx_ring2;
struct b43_dmaring *tx_ring3;
struct b43_dmaring *tx_ring4;
struct b43_dmaring *tx_ring5;
struct b43_dmaring *rx_ring0;
struct b43_dmaring *rx_ring3; /* only available on core.rev < 5 */
};
/* Data structures for PIO transmission, per 80211 core. */
struct b43_pio {
struct b43_pioqueue *queue0;
struct b43_pioqueue *queue1;
struct b43_pioqueue *queue2;
struct b43_pioqueue *queue3;
};
/* Context information for a noise calculation (Link Quality). */
struct b43_noise_calculation {
u8 channel_at_start;
bool calculation_running;
u8 nr_samples;
s8 samples[8][4];
};
struct b43_stats {
u8 link_noise;
/* Store the last TX/RX times here for updating the leds. */
unsigned long last_tx;
unsigned long last_rx;
};
struct b43_key {
/* If keyconf is NULL, this key is disabled.
* keyconf is a cookie. Don't derefenrence it outside of the set_key
* path, because b43 doesn't own it. */
struct ieee80211_key_conf *keyconf;
u8 algorithm;
};
struct b43_wldev;
/* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */
struct b43_wl {
/* Pointer to the active wireless device on this chip */
struct b43_wldev *current_dev;
/* Pointer to the ieee80211 hardware data structure */
struct ieee80211_hw *hw;
spinlock_t irq_lock;
struct mutex mutex;
spinlock_t leds_lock;
/* We can only have one operating interface (802.11 core)
* at a time. General information about this interface follows.
*/
/* Opaque ID of the operating interface (!= monitor
* interface) from the ieee80211 subsystem.
* Do not modify.
*/
int if_id;
/* The MAC address of the operating interface. */
u8 mac_addr[ETH_ALEN];
/* Current BSSID */
u8 bssid[ETH_ALEN];
/* Interface type. (IEEE80211_IF_TYPE_XXX) */
int if_type;
/* Counter of active monitor interfaces. */
int monitor;
/* Is the card operating in AP, STA or IBSS mode? */
bool operating;
/* Promisc mode active?
* Note that (monitor != 0) implies promisc.
*/
bool promisc;
/* Stats about the wireless interface */
struct ieee80211_low_level_stats ieee_stats;
struct hwrng rng;
u8 rng_initialized;
char rng_name[30 + 1];
/* List of all wireless devices on this chip */
struct list_head devlist;
u8 nr_devs;
};
/* Pointers to the firmware data and meta information about it. */
struct b43_firmware {
/* Microcode */
const struct firmware *ucode;
/* PCM code */
const struct firmware *pcm;
/* Initial MMIO values for the firmware */
const struct firmware *initvals;
/* Initial MMIO values for the firmware, band-specific */
const struct firmware *initvals_band;
/* Firmware revision */
u16 rev;
/* Firmware patchlevel */
u16 patch;
};
/* Device (802.11 core) initialization status. */
enum {
B43_STAT_UNINIT = 0, /* Uninitialized. */
B43_STAT_INITIALIZED = 1, /* Initialized, but not started, yet. */
B43_STAT_STARTED = 2, /* Up and running. */
};
#define b43_status(wldev) atomic_read(&(wldev)->__init_status)
#define b43_set_status(wldev, stat) do { \
atomic_set(&(wldev)->__init_status, (stat)); \
smp_wmb(); \
} while (0)
/* XXX--- HOW LOCKING WORKS IN B43 ---XXX
*
* You should always acquire both, wl->mutex and wl->irq_lock unless:
* - You don't need to acquire wl->irq_lock, if the interface is stopped.
* - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet
* and packet TX path (and _ONLY_ there.)
*/
/* Data structure for one wireless device (802.11 core) */
struct b43_wldev {
struct ssb_device *dev;
struct b43_wl *wl;
/* The device initialization status.
* Use b43_status() to query. */
atomic_t __init_status;
/* Saved init status for handling suspend. */
int suspend_init_status;
bool __using_pio; /* Internal, use b43_using_pio(). */
bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */
bool reg124_set_0x4; /* Some variable to keep track of IRQ stuff. */
bool short_preamble; /* TRUE, if short preamble is enabled. */
bool short_slot; /* TRUE, if short slot timing is enabled. */
bool radio_hw_enable; /* saved state of radio hardware enabled state */
/* PHY/Radio device. */
struct b43_phy phy;
union {
/* DMA engines. */
struct b43_dma dma;
/* PIO engines. */
struct b43_pio pio;
};
/* Various statistics about the physical device. */
struct b43_stats stats;
#define B43_NR_LEDS 4
struct b43_led leds[B43_NR_LEDS];
/* Reason code of the last interrupt. */
u32 irq_reason;
u32 dma_reason[6];
/* saved irq enable/disable state bitfield. */
u32 irq_savedstate;
/* Link Quality calculation context. */
struct b43_noise_calculation noisecalc;
/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
int mac_suspended;
/* Interrupt Service Routine tasklet (bottom-half) */
struct tasklet_struct isr_tasklet;
/* Periodic tasks */
struct delayed_work periodic_work;
unsigned int periodic_state;
struct work_struct restart_work;
/* encryption/decryption */
u16 ktp; /* Key table pointer */
u8 max_nr_keys;
struct b43_key key[58];
/* Cached beacon template while uploading the template. */
struct sk_buff *cached_beacon;
/* Firmware data */
struct b43_firmware fw;
/* Devicelist in struct b43_wl (all 802.11 cores) */
struct list_head list;
/* Debugging stuff follows. */
#ifdef CONFIG_B43_DEBUG
struct b43_dfsentry *dfsentry;
#endif
};
static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
{
return hw->priv;
}
/* Helper function, which returns a boolean.
* TRUE, if PIO is used; FALSE, if DMA is used.
*/
#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
static inline int b43_using_pio(struct b43_wldev *dev)
{
return dev->__using_pio;
}
#elif defined(CONFIG_B43_DMA)
static inline int b43_using_pio(struct b43_wldev *dev)
{
return 0;
}
#elif defined(CONFIG_B43_PIO)
static inline int b43_using_pio(struct b43_wldev *dev)
{
return 1;
}
#else
# error "Using neither DMA nor PIO? Confused..."
#endif
static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev)
{
struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
return ssb_get_drvdata(ssb_dev);
}
/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */
static inline int b43_is_mode(struct b43_wl *wl, int type)
{
if (type == IEEE80211_IF_TYPE_MNTR)
return !!(wl->monitor);
return (wl->operating && wl->if_type == type);
}
static inline u16 b43_read16(struct b43_wldev *dev, u16 offset)
{
return ssb_read16(dev->dev, offset);
}
static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value)
{
ssb_write16(dev->dev, offset, value);
}
static inline u32 b43_read32(struct b43_wldev *dev, u16 offset)
{
return ssb_read32(dev->dev, offset);
}
static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)
{
ssb_write32(dev->dev, offset, value);
}
/* Message printing */
void b43info(struct b43_wl *wl, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
void b43err(struct b43_wl *wl, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
void b43warn(struct b43_wl *wl, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
#if B43_DEBUG
void b43dbg(struct b43_wl *wl, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
#else /* DEBUG */
# define b43dbg(wl, fmt...) do { /* nothing */ } while (0)
#endif /* DEBUG */
/* A WARN_ON variant that vanishes when b43 debugging is disabled.
* This _also_ evaluates the arg with debugging disabled. */
#if B43_DEBUG
# define B43_WARN_ON(x) WARN_ON(x)
#else
static inline bool __b43_warn_on_dummy(bool x) { return x; }
# define B43_WARN_ON(x) __b43_warn_on_dummy(unlikely(!!(x)))
#endif
/** Limit a value between two limits */
#ifdef limit_value
# undef limit_value
#endif
#define limit_value(value, min, max) \
({ \
typeof(value) __value = (value); \
typeof(value) __min = (min); \
typeof(value) __max = (max); \
if (__value < __min) \
__value = __min; \
else if (__value > __max) \
__value = __max; \
__value; \
})
/* Convert an integer to a Q5.2 value */
#define INT_TO_Q52(i) ((i) << 2)
/* Convert a Q5.2 value to an integer (precision loss!) */
#define Q52_TO_INT(q52) ((q52) >> 2)
/* Macros for printing a value in Q5.2 format */
#define Q52_FMT "%u.%u"
#define Q52_ARG(q52) Q52_TO_INT(q52), ((((q52) & 0x3) * 100) / 4)
#endif /* B43_H_ */

View file

@ -0,0 +1,654 @@
/*
Broadcom B43 wireless driver
debugfs driver debugging code
Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
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/fs.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/mutex.h>
#include "b43.h"
#include "main.h"
#include "debugfs.h"
#include "dma.h"
#include "pio.h"
#include "xmit.h"
/* The root directory. */
struct dentry *rootdir;
struct b43_debugfs_fops {
ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize);
int (*write)(struct b43_wldev *dev, const char *buf, size_t count);
struct file_operations fops;
/* Offset of struct b43_dfs_file in struct b43_dfsentry */
size_t file_struct_offset;
/* Take wl->irq_lock before calling read/write? */
bool take_irqlock;
};
static inline
struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev,
const struct b43_debugfs_fops *dfops)
{
void *p;
p = dev->dfsentry;
p += dfops->file_struct_offset;
return p;
}
#define fappend(fmt, x...) \
do { \
if (bufsize - count) \
count += snprintf(buf + count, \
bufsize - count, \
fmt , ##x); \
else \
printk(KERN_ERR "b43: fappend overflow\n"); \
} while (0)
/* wl->irq_lock is locked */
ssize_t tsf_read_file(struct b43_wldev *dev, char *buf, size_t bufsize)
{
ssize_t count = 0;
u64 tsf;
b43_tsf_read(dev, &tsf);
fappend("0x%08x%08x\n",
(unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
(unsigned int)(tsf & 0xFFFFFFFFULL));
return count;
}
/* wl->irq_lock is locked */
int tsf_write_file(struct b43_wldev *dev, const char *buf, size_t count)
{
u64 tsf;
if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1)
return -EINVAL;
b43_tsf_write(dev, tsf);
return 0;
}
/* wl->irq_lock is locked */
ssize_t ucode_regs_read_file(struct b43_wldev *dev, char *buf, size_t bufsize)
{
ssize_t count = 0;
int i;
for (i = 0; i < 64; i++) {
fappend("r%d = 0x%04x\n", i,
b43_shm_read16(dev, B43_SHM_SCRATCH, i));
}
return count;
}
/* wl->irq_lock is locked */
ssize_t shm_read_file(struct b43_wldev *dev, char *buf, size_t bufsize)
{
ssize_t count = 0;
int i;
u16 tmp;
__le16 *le16buf = (__le16 *)buf;
for (i = 0; i < 0x1000; i++) {
if (bufsize <= 0)
break;
tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i);
le16buf[i] = cpu_to_le16(tmp);
count += sizeof(tmp);
bufsize -= sizeof(tmp);
}
return count;
}
ssize_t txstat_read_file(struct b43_wldev *dev, char *buf, size_t bufsize)
{
struct b43_txstatus_log *log = &dev->dfsentry->txstatlog;
ssize_t count = 0;
unsigned long flags;
int i, idx;
struct b43_txstatus *stat;
spin_lock_irqsave(&log->lock, flags);
if (log->end < 0) {
fappend("Nothing transmitted, yet\n");
goto out_unlock;
}
fappend("b43 TX status reports:\n\n"
"index | cookie | seq | phy_stat | frame_count | "
"rts_count | supp_reason | pm_indicated | "
"intermediate | for_ampdu | acked\n" "---\n");
i = log->end + 1;
idx = 0;
while (1) {
if (i == B43_NR_LOGGED_TXSTATUS)
i = 0;
stat = &(log->log[i]);
if (stat->cookie) {
fappend("%03d | "
"0x%04X | 0x%04X | 0x%02X | "
"0x%X | 0x%X | "
"%u | %u | "
"%u | %u | %u\n",
idx,
stat->cookie, stat->seq, stat->phy_stat,
stat->frame_count, stat->rts_count,
stat->supp_reason, stat->pm_indicated,
stat->intermediate, stat->for_ampdu,
stat->acked);
idx++;
}
if (i == log->end)
break;
i++;
}
out_unlock:
spin_unlock_irqrestore(&log->lock, flags);
return count;
}
ssize_t txpower_g_read_file(struct b43_wldev *dev, char *buf, size_t bufsize)
{
ssize_t count = 0;
if (dev->phy.type != B43_PHYTYPE_G) {
fappend("Device is not a G-PHY\n");
goto out;
}
fappend("Control: %s\n", dev->phy.manual_txpower_control ?
"MANUAL" : "AUTOMATIC");
fappend("Baseband attenuation: %u\n", dev->phy.bbatt.att);
fappend("Radio attenuation: %u\n", dev->phy.rfatt.att);
fappend("TX Mixer Gain: %s\n",
(dev->phy.tx_control & B43_TXCTL_TXMIX) ? "ON" : "OFF");
fappend("PA Gain 2dB: %s\n",
(dev->phy.tx_control & B43_TXCTL_PA2DB) ? "ON" : "OFF");
fappend("PA Gain 3dB: %s\n",
(dev->phy.tx_control & B43_TXCTL_PA3DB) ? "ON" : "OFF");
fappend("\n\n");
fappend("You can write to this file:\n");
fappend("Writing \"auto\" enables automatic txpower control.\n");
fappend
("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" "
"enables manual txpower control.\n");
fappend("Example: 5 4 0 0 1\n");
fappend("Enables manual control with Baseband attenuation 5, "
"Radio attenuation 4, No TX Mixer Gain, "
"No PA Gain 2dB, With PA Gain 3dB.\n");
out:
return count;
}
int txpower_g_write_file(struct b43_wldev *dev, const char *buf, size_t count)
{
unsigned long flags;
unsigned long phy_flags;
int err = 0;
spin_lock_irqsave(&dev->wl->irq_lock, flags);
if (dev->phy.type != B43_PHYTYPE_G) {
err = -ENODEV;
goto out_unlock;
}
if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) {
/* Automatic control */
dev->phy.manual_txpower_control = 0;
b43_phy_xmitpower(dev);
} else {
int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0;
/* Manual control */
if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt,
&txmix, &pa2db, &pa3db) != 5) {
err = -EINVAL;
goto out_unlock;
}
b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
dev->phy.manual_txpower_control = 1;
dev->phy.bbatt.att = bbatt;
dev->phy.rfatt.att = rfatt;
dev->phy.tx_control = 0;
if (txmix)
dev->phy.tx_control |= B43_TXCTL_TXMIX;
if (pa2db)
dev->phy.tx_control |= B43_TXCTL_PA2DB;
if (pa3db)
dev->phy.tx_control |= B43_TXCTL_PA3DB;
b43_phy_lock(dev, phy_flags);
b43_radio_lock(dev);
b43_set_txpower_g(dev, &dev->phy.bbatt,
&dev->phy.rfatt, dev->phy.tx_control);
b43_radio_unlock(dev);
b43_phy_unlock(dev, phy_flags);
}
out_unlock:
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
return err;
}
/* wl->irq_lock is locked */
int restart_write_file(struct b43_wldev *dev, const char *buf, size_t count)
{
int err = 0;
if (count > 0 && buf[0] == '1') {
b43_controller_restart(dev, "manually restarted");
} else
err = -EINVAL;
return err;
}
static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize,
struct b43_loctl table[B43_NR_BB][B43_NR_RF])
{
unsigned int i, j;
struct b43_loctl *ctl;
for (i = 0; i < B43_NR_BB; i++) {
for (j = 0; j < B43_NR_RF; j++) {
ctl = &(table[i][j]);
fappend("(bbatt %2u, rfatt %2u) -> "
"(I %+3d, Q %+3d, Used: %d, Calibrated: %d)\n",
i, j, ctl->i, ctl->q,
ctl->used,
b43_loctl_is_calibrated(ctl));
}
}
return count;
}
ssize_t loctls_read_file(struct b43_wldev *dev, char *buf, size_t bufsize)
{
ssize_t count = 0;
struct b43_txpower_lo_control *lo;
int i, err = 0;
if (dev->phy.type != B43_PHYTYPE_G) {
fappend("Device is not a G-PHY\n");
err = -ENODEV;
goto out;
}
lo = dev->phy.lo_control;
fappend("-- Local Oscillator calibration data --\n\n");
fappend("Measured: %d, Rebuild: %d, HW-power-control: %d\n",
lo->lo_measured,
lo->rebuild,
dev->phy.hardware_power_control);
fappend("TX Bias: 0x%02X, TX Magn: 0x%02X\n",
lo->tx_bias, lo->tx_magn);
fappend("Power Vector: 0x%08X%08X\n",
(unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32),
(unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL));
fappend("\nControl table WITH PADMIX:\n");
count = append_lo_table(count, buf, bufsize, lo->with_padmix);
fappend("\nControl table WITHOUT PADMIX:\n");
count = append_lo_table(count, buf, bufsize, lo->no_padmix);
fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n");
for (i = 0; i < lo->rfatt_list.len; i++) {
fappend("%u(%d), ",
lo->rfatt_list.list[i].att,
lo->rfatt_list.list[i].with_padmix);
}
fappend("\n");
fappend("\nUsed Baseband attenuation values:\n");
for (i = 0; i < lo->bbatt_list.len; i++) {
fappend("%u, ",
lo->bbatt_list.list[i].att);
}
fappend("\n");
out:
return err ? err : count;
}
#undef fappend
static int b43_debugfs_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct b43_wldev *dev;
struct b43_debugfs_fops *dfops;
struct b43_dfs_file *dfile;
ssize_t ret;
char *buf;
const size_t bufsize = 1024 * 128;
const size_t buforder = get_order(bufsize);
int err = 0;
if (!count)
return 0;
dev = file->private_data;
if (!dev)
return -ENODEV;
mutex_lock(&dev->wl->mutex);
if (b43_status(dev) < B43_STAT_INITIALIZED) {
err = -ENODEV;
goto out_unlock;
}
dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
if (!dfops->read) {
err = -ENOSYS;
goto out_unlock;
}
dfile = fops_to_dfs_file(dev, dfops);
if (!dfile->buffer) {
buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
if (!buf) {
err = -ENOMEM;
goto out_unlock;
}
memset(buf, 0, bufsize);
if (dfops->take_irqlock) {
spin_lock_irq(&dev->wl->irq_lock);
ret = dfops->read(dev, buf, bufsize);
spin_unlock_irq(&dev->wl->irq_lock);
} else
ret = dfops->read(dev, buf, bufsize);
if (ret <= 0) {
free_pages((unsigned long)buf, buforder);
err = ret;
goto out_unlock;
}
dfile->data_len = ret;
dfile->buffer = buf;
}
ret = simple_read_from_buffer(userbuf, count, ppos,
dfile->buffer,
dfile->data_len);
if (*ppos >= dfile->data_len) {
free_pages((unsigned long)dfile->buffer, buforder);
dfile->buffer = NULL;
dfile->data_len = 0;
}
out_unlock:
mutex_unlock(&dev->wl->mutex);
return err ? err : ret;
}
static ssize_t b43_debugfs_write(struct file *file,
const char __user *userbuf,
size_t count, loff_t *ppos)
{
struct b43_wldev *dev;
struct b43_debugfs_fops *dfops;
char *buf;
int err = 0;
if (!count)
return 0;
if (count > PAGE_SIZE)
return -E2BIG;
dev = file->private_data;
if (!dev)
return -ENODEV;
mutex_lock(&dev->wl->mutex);
if (b43_status(dev) < B43_STAT_INITIALIZED) {
err = -ENODEV;
goto out_unlock;
}
dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
if (!dfops->write) {
err = -ENOSYS;
goto out_unlock;
}
buf = (char *)get_zeroed_page(GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto out_unlock;
}
if (copy_from_user(buf, userbuf, count)) {
err = -EFAULT;
goto out_freepage;
}
if (dfops->take_irqlock) {
spin_lock_irq(&dev->wl->irq_lock);
err = dfops->write(dev, buf, count);
spin_unlock_irq(&dev->wl->irq_lock);
} else
err = dfops->write(dev, buf, count);
if (err)
goto out_freepage;
out_freepage:
free_page((unsigned long)buf);
out_unlock:
mutex_unlock(&dev->wl->mutex);
return err ? err : count;
}
#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \
static struct b43_debugfs_fops fops_##name = { \
.read = _read, \
.write = _write, \
.fops = { \
.open = b43_debugfs_open, \
.read = b43_debugfs_read, \
.write = b43_debugfs_write, \
}, \
.file_struct_offset = offsetof(struct b43_dfsentry, \
file_##name), \
.take_irqlock = _take_irqlock, \
}
B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
B43_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1);
B43_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1);
B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0);
B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0);
int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
{
return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
}
static void b43_remove_dynamic_debug(struct b43_wldev *dev)
{
struct b43_dfsentry *e = dev->dfsentry;
int i;
for (i = 0; i < __B43_NR_DYNDBG; i++)
debugfs_remove(e->dyn_debug_dentries[i]);
}
static void b43_add_dynamic_debug(struct b43_wldev *dev)
{
struct b43_dfsentry *e = dev->dfsentry;
struct dentry *d;
#define add_dyn_dbg(name, id, initstate) do { \
e->dyn_debug[id] = (initstate); \
d = debugfs_create_bool(name, 0600, e->subdir, \
&(e->dyn_debug[id])); \
if (!IS_ERR(d)) \
e->dyn_debug_dentries[id] = d; \
} while (0)
add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, 0);
add_dyn_dbg("debug_dmaoverflow", B43_DBG_DMAOVERFLOW, 0);
add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0);
add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0);
add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
#undef add_dyn_dbg
}
void b43_debugfs_add_device(struct b43_wldev *dev)
{
struct b43_dfsentry *e;
struct b43_txstatus_log *log;
char devdir[16];
B43_WARN_ON(!dev);
e = kzalloc(sizeof(*e), GFP_KERNEL);
if (!e) {
b43err(dev->wl, "debugfs: add device OOM\n");
return;
}
e->dev = dev;
log = &e->txstatlog;
log->log = kcalloc(B43_NR_LOGGED_TXSTATUS,
sizeof(struct b43_txstatus), GFP_KERNEL);
if (!log->log) {
b43err(dev->wl, "debugfs: add device txstatus OOM\n");
kfree(e);
return;
}
log->end = -1;
spin_lock_init(&log->lock);
dev->dfsentry = e;
snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
e->subdir = debugfs_create_dir(devdir, rootdir);
if (!e->subdir || IS_ERR(e->subdir)) {
if (e->subdir == ERR_PTR(-ENODEV)) {
b43dbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
"enabled in kernel config\n");
} else {
b43err(dev->wl, "debugfs: cannot create %s directory\n",
devdir);
}
dev->dfsentry = NULL;
kfree(log->log);
kfree(e);
return;
}
#define ADD_FILE(name, mode) \
do { \
struct dentry *d; \
d = debugfs_create_file(__stringify(name), \
mode, e->subdir, dev, \
&fops_##name.fops); \
e->file_##name.dentry = NULL; \
if (!IS_ERR(d)) \
e->file_##name.dentry = d; \
} while (0)
ADD_FILE(tsf, 0600);
ADD_FILE(ucode_regs, 0400);
ADD_FILE(shm, 0400);
ADD_FILE(txstat, 0400);
ADD_FILE(txpower_g, 0600);
ADD_FILE(restart, 0200);
ADD_FILE(loctls, 0400);
#undef ADD_FILE
b43_add_dynamic_debug(dev);
}
void b43_debugfs_remove_device(struct b43_wldev *dev)
{
struct b43_dfsentry *e;
if (!dev)
return;
e = dev->dfsentry;
if (!e)
return;
b43_remove_dynamic_debug(dev);
debugfs_remove(e->file_tsf.dentry);
debugfs_remove(e->file_ucode_regs.dentry);
debugfs_remove(e->file_shm.dentry);
debugfs_remove(e->file_txstat.dentry);
debugfs_remove(e->file_txpower_g.dentry);
debugfs_remove(e->file_restart.dentry);
debugfs_remove(e->file_loctls.dentry);
debugfs_remove(e->subdir);
kfree(e->txstatlog.log);
kfree(e);
}
void b43_debugfs_log_txstat(struct b43_wldev *dev,
const struct b43_txstatus *status)
{
struct b43_dfsentry *e = dev->dfsentry;
struct b43_txstatus_log *log;
struct b43_txstatus *cur;
int i;
if (!e)
return;
log = &e->txstatlog;
B43_WARN_ON(!irqs_disabled());
spin_lock(&log->lock);
i = log->end + 1;
if (i == B43_NR_LOGGED_TXSTATUS)
i = 0;
log->end = i;
cur = &(log->log[i]);
memcpy(cur, status, sizeof(*cur));
spin_unlock(&log->lock);
}
void b43_debugfs_init(void)
{
rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
if (IS_ERR(rootdir))
rootdir = NULL;
}
void b43_debugfs_exit(void)
{
debugfs_remove(rootdir);
}

View file

@ -0,0 +1,89 @@
#ifndef B43_DEBUGFS_H_
#define B43_DEBUGFS_H_
struct b43_wldev;
struct b43_txstatus;
enum b43_dyndbg { /* Dynamic debugging features */
B43_DBG_XMITPOWER,
B43_DBG_DMAOVERFLOW,
B43_DBG_DMAVERBOSE,
B43_DBG_PWORK_FAST,
B43_DBG_PWORK_STOP,
__B43_NR_DYNDBG,
};
#ifdef CONFIG_B43_DEBUG
struct dentry;
#define B43_NR_LOGGED_TXSTATUS 100
struct b43_txstatus_log {
struct b43_txstatus *log;
int end;
spinlock_t lock;
};
struct b43_dfs_file {
struct dentry *dentry;
char *buffer;
size_t data_len;
};
struct b43_dfsentry {
struct b43_wldev *dev;
struct dentry *subdir;
struct b43_dfs_file file_tsf;
struct b43_dfs_file file_ucode_regs;
struct b43_dfs_file file_shm;
struct b43_dfs_file file_txstat;
struct b43_dfs_file file_txpower_g;
struct b43_dfs_file file_restart;
struct b43_dfs_file file_loctls;
struct b43_txstatus_log txstatlog;
/* Enabled/Disabled list for the dynamic debugging features. */
u32 dyn_debug[__B43_NR_DYNDBG];
/* Dentries for the dynamic debugging entries. */
struct dentry *dyn_debug_dentries[__B43_NR_DYNDBG];
};
int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature);
void b43_debugfs_init(void);
void b43_debugfs_exit(void);
void b43_debugfs_add_device(struct b43_wldev *dev);
void b43_debugfs_remove_device(struct b43_wldev *dev);
void b43_debugfs_log_txstat(struct b43_wldev *dev,
const struct b43_txstatus *status);
#else /* CONFIG_B43_DEBUG */
static inline int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
{
return 0;
}
static inline void b43_debugfs_init(void)
{
}
static inline void b43_debugfs_exit(void)
{
}
static inline void b43_debugfs_add_device(struct b43_wldev *dev)
{
}
static inline void b43_debugfs_remove_device(struct b43_wldev *dev)
{
}
static inline void b43_debugfs_log_txstat(struct b43_wldev *dev,
const struct b43_txstatus *status)
{
}
#endif /* CONFIG_B43_DEBUG */
#endif /* B43_DEBUGFS_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,337 @@
#ifndef B43_DMA_H_
#define B43_DMA_H_
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/linkage.h>
#include <asm/atomic.h>
#include "b43.h"
/* DMA-Interrupt reasons. */
#define B43_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \
| (1 << 14) | (1 << 15))
#define B43_DMAIRQ_NONFATALMASK (1 << 13)
#define B43_DMAIRQ_RX_DONE (1 << 16)
/*** 32-bit DMA Engine. ***/
/* 32-bit DMA controller registers. */
#define B43_DMA32_TXCTL 0x00
#define B43_DMA32_TXENABLE 0x00000001
#define B43_DMA32_TXSUSPEND 0x00000002
#define B43_DMA32_TXLOOPBACK 0x00000004
#define B43_DMA32_TXFLUSH 0x00000010
#define B43_DMA32_TXADDREXT_MASK 0x00030000
#define B43_DMA32_TXADDREXT_SHIFT 16
#define B43_DMA32_TXRING 0x04
#define B43_DMA32_TXINDEX 0x08
#define B43_DMA32_TXSTATUS 0x0C
#define B43_DMA32_TXDPTR 0x00000FFF
#define B43_DMA32_TXSTATE 0x0000F000
#define B43_DMA32_TXSTAT_DISABLED 0x00000000
#define B43_DMA32_TXSTAT_ACTIVE 0x00001000
#define B43_DMA32_TXSTAT_IDLEWAIT 0x00002000
#define B43_DMA32_TXSTAT_STOPPED 0x00003000
#define B43_DMA32_TXSTAT_SUSP 0x00004000
#define B43_DMA32_TXERROR 0x000F0000
#define B43_DMA32_TXERR_NOERR 0x00000000
#define B43_DMA32_TXERR_PROT 0x00010000
#define B43_DMA32_TXERR_UNDERRUN 0x00020000
#define B43_DMA32_TXERR_BUFREAD 0x00030000
#define B43_DMA32_TXERR_DESCREAD 0x00040000
#define B43_DMA32_TXACTIVE 0xFFF00000
#define B43_DMA32_RXCTL 0x10
#define B43_DMA32_RXENABLE 0x00000001
#define B43_DMA32_RXFROFF_MASK 0x000000FE
#define B43_DMA32_RXFROFF_SHIFT 1
#define B43_DMA32_RXDIRECTFIFO 0x00000100
#define B43_DMA32_RXADDREXT_MASK 0x00030000
#define B43_DMA32_RXADDREXT_SHIFT 16
#define B43_DMA32_RXRING 0x14
#define B43_DMA32_RXINDEX 0x18
#define B43_DMA32_RXSTATUS 0x1C
#define B43_DMA32_RXDPTR 0x00000FFF
#define B43_DMA32_RXSTATE 0x0000F000
#define B43_DMA32_RXSTAT_DISABLED 0x00000000
#define B43_DMA32_RXSTAT_ACTIVE 0x00001000
#define B43_DMA32_RXSTAT_IDLEWAIT 0x00002000
#define B43_DMA32_RXSTAT_STOPPED 0x00003000
#define B43_DMA32_RXERROR 0x000F0000
#define B43_DMA32_RXERR_NOERR 0x00000000
#define B43_DMA32_RXERR_PROT 0x00010000
#define B43_DMA32_RXERR_OVERFLOW 0x00020000
#define B43_DMA32_RXERR_BUFWRITE 0x00030000
#define B43_DMA32_RXERR_DESCREAD 0x00040000
#define B43_DMA32_RXACTIVE 0xFFF00000
/* 32-bit DMA descriptor. */
struct b43_dmadesc32 {
__le32 control;
__le32 address;
} __attribute__ ((__packed__));
#define B43_DMA32_DCTL_BYTECNT 0x00001FFF
#define B43_DMA32_DCTL_ADDREXT_MASK 0x00030000
#define B43_DMA32_DCTL_ADDREXT_SHIFT 16
#define B43_DMA32_DCTL_DTABLEEND 0x10000000
#define B43_DMA32_DCTL_IRQ 0x20000000
#define B43_DMA32_DCTL_FRAMEEND 0x40000000
#define B43_DMA32_DCTL_FRAMESTART 0x80000000
/*** 64-bit DMA Engine. ***/
/* 64-bit DMA controller registers. */
#define B43_DMA64_TXCTL 0x00
#define B43_DMA64_TXENABLE 0x00000001
#define B43_DMA64_TXSUSPEND 0x00000002
#define B43_DMA64_TXLOOPBACK 0x00000004
#define B43_DMA64_TXFLUSH 0x00000010
#define B43_DMA64_TXADDREXT_MASK 0x00030000
#define B43_DMA64_TXADDREXT_SHIFT 16
#define B43_DMA64_TXINDEX 0x04
#define B43_DMA64_TXRINGLO 0x08
#define B43_DMA64_TXRINGHI 0x0C
#define B43_DMA64_TXSTATUS 0x10
#define B43_DMA64_TXSTATDPTR 0x00001FFF
#define B43_DMA64_TXSTAT 0xF0000000
#define B43_DMA64_TXSTAT_DISABLED 0x00000000
#define B43_DMA64_TXSTAT_ACTIVE 0x10000000
#define B43_DMA64_TXSTAT_IDLEWAIT 0x20000000
#define B43_DMA64_TXSTAT_STOPPED 0x30000000
#define B43_DMA64_TXSTAT_SUSP 0x40000000
#define B43_DMA64_TXERROR 0x14
#define B43_DMA64_TXERRDPTR 0x0001FFFF
#define B43_DMA64_TXERR 0xF0000000
#define B43_DMA64_TXERR_NOERR 0x00000000
#define B43_DMA64_TXERR_PROT 0x10000000
#define B43_DMA64_TXERR_UNDERRUN 0x20000000
#define B43_DMA64_TXERR_TRANSFER 0x30000000
#define B43_DMA64_TXERR_DESCREAD 0x40000000
#define B43_DMA64_TXERR_CORE 0x50000000
#define B43_DMA64_RXCTL 0x20
#define B43_DMA64_RXENABLE 0x00000001
#define B43_DMA64_RXFROFF_MASK 0x000000FE
#define B43_DMA64_RXFROFF_SHIFT 1
#define B43_DMA64_RXDIRECTFIFO 0x00000100
#define B43_DMA64_RXADDREXT_MASK 0x00030000
#define B43_DMA64_RXADDREXT_SHIFT 16
#define B43_DMA64_RXINDEX 0x24
#define B43_DMA64_RXRINGLO 0x28
#define B43_DMA64_RXRINGHI 0x2C
#define B43_DMA64_RXSTATUS 0x30
#define B43_DMA64_RXSTATDPTR 0x00001FFF
#define B43_DMA64_RXSTAT 0xF0000000
#define B43_DMA64_RXSTAT_DISABLED 0x00000000
#define B43_DMA64_RXSTAT_ACTIVE 0x10000000
#define B43_DMA64_RXSTAT_IDLEWAIT 0x20000000
#define B43_DMA64_RXSTAT_STOPPED 0x30000000
#define B43_DMA64_RXSTAT_SUSP 0x40000000
#define B43_DMA64_RXERROR 0x34
#define B43_DMA64_RXERRDPTR 0x0001FFFF
#define B43_DMA64_RXERR 0xF0000000
#define B43_DMA64_RXERR_NOERR 0x00000000
#define B43_DMA64_RXERR_PROT 0x10000000
#define B43_DMA64_RXERR_UNDERRUN 0x20000000
#define B43_DMA64_RXERR_TRANSFER 0x30000000
#define B43_DMA64_RXERR_DESCREAD 0x40000000
#define B43_DMA64_RXERR_CORE 0x50000000
/* 64-bit DMA descriptor. */
struct b43_dmadesc64 {
__le32 control0;
__le32 control1;
__le32 address_low;
__le32 address_high;
} __attribute__ ((__packed__));
#define B43_DMA64_DCTL0_DTABLEEND 0x10000000
#define B43_DMA64_DCTL0_IRQ 0x20000000
#define B43_DMA64_DCTL0_FRAMEEND 0x40000000
#define B43_DMA64_DCTL0_FRAMESTART 0x80000000
#define B43_DMA64_DCTL1_BYTECNT 0x00001FFF
#define B43_DMA64_DCTL1_ADDREXT_MASK 0x00030000
#define B43_DMA64_DCTL1_ADDREXT_SHIFT 16
struct b43_dmadesc_generic {
union {
struct b43_dmadesc32 dma32;
struct b43_dmadesc64 dma64;
} __attribute__ ((__packed__));
} __attribute__ ((__packed__));
/* Misc DMA constants */
#define B43_DMA_RINGMEMSIZE PAGE_SIZE
#define B43_DMA0_RX_FRAMEOFFSET 30
#define B43_DMA3_RX_FRAMEOFFSET 0
/* DMA engine tuning knobs */
#define B43_TXRING_SLOTS 128
#define B43_RXRING_SLOTS 64
#define B43_DMA0_RX_BUFFERSIZE (2304 + 100)
#define B43_DMA3_RX_BUFFERSIZE 16
#ifdef CONFIG_B43_DMA
struct sk_buff;
struct b43_private;
struct b43_txstatus;
struct b43_dmadesc_meta {
/* The kernel DMA-able buffer. */
struct sk_buff *skb;
/* DMA base bus-address of the descriptor buffer. */
dma_addr_t dmaaddr;
/* ieee80211 TX status. Only used once per 802.11 frag. */
bool is_last_fragment;
struct ieee80211_tx_status txstat;
};
struct b43_dmaring;
/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */
struct b43_dma_ops {
struct b43_dmadesc_generic *(*idx2desc) (struct b43_dmaring * ring,
int slot,
struct b43_dmadesc_meta **
meta);
void (*fill_descriptor) (struct b43_dmaring * ring,
struct b43_dmadesc_generic * desc,
dma_addr_t dmaaddr, u16 bufsize, int start,
int end, int irq);
void (*poke_tx) (struct b43_dmaring * ring, int slot);
void (*tx_suspend) (struct b43_dmaring * ring);
void (*tx_resume) (struct b43_dmaring * ring);
int (*get_current_rxslot) (struct b43_dmaring * ring);
void (*set_current_rxslot) (struct b43_dmaring * ring, int slot);
};
struct b43_dmaring {
/* Lowlevel DMA ops. */
const struct b43_dma_ops *ops;
/* Kernel virtual base address of the ring memory. */
void *descbase;
/* Meta data about all descriptors. */
struct b43_dmadesc_meta *meta;
/* Cache of TX headers for each slot.
* This is to avoid an allocation on each TX.
* This is NULL for an RX ring.
*/
u8 *txhdr_cache;
/* (Unadjusted) DMA base bus-address of the ring memory. */
dma_addr_t dmabase;
/* Number of descriptor slots in the ring. */
int nr_slots;
/* Number of used descriptor slots. */
int used_slots;
/* Currently used slot in the ring. */
int current_slot;
/* Total number of packets sent. Statistics only. */
unsigned int nr_tx_packets;
/* Frameoffset in octets. */
u32 frameoffset;
/* Descriptor buffer size. */
u16 rx_buffersize;
/* The MMIO base register of the DMA controller. */
u16 mmio_base;
/* DMA controller index number (0-5). */
int index;
/* Boolean. Is this a TX ring? */
bool tx;
/* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
bool dma64;
/* Boolean. Is this ring stopped at ieee80211 level? */
bool stopped;
/* Lock, only used for TX. */
spinlock_t lock;
struct b43_wldev *dev;
#ifdef CONFIG_B43_DEBUG
/* Maximum number of used slots. */
int max_used_slots;
/* Last time we injected a ring overflow. */
unsigned long last_injected_overflow;
#endif /* CONFIG_B43_DEBUG */
};
static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset)
{
return b43_read32(ring->dev, ring->mmio_base + offset);
}
static inline
void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
{
b43_write32(ring->dev, ring->mmio_base + offset, value);
}
int b43_dma_init(struct b43_wldev *dev);
void b43_dma_free(struct b43_wldev *dev);
int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
u16 dmacontroller_mmio_base, int dma64);
int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
u16 dmacontroller_mmio_base, int dma64);
u16 b43_dmacontroller_base(int dma64bit, int dmacontroller_idx);
void b43_dma_tx_suspend(struct b43_wldev *dev);
void b43_dma_tx_resume(struct b43_wldev *dev);
void b43_dma_get_tx_stats(struct b43_wldev *dev,
struct ieee80211_tx_queue_stats *stats);
int b43_dma_tx(struct b43_wldev *dev,
struct sk_buff *skb, struct ieee80211_tx_control *ctl);
void b43_dma_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status);
void b43_dma_rx(struct b43_dmaring *ring);
#else /* CONFIG_B43_DMA */
static inline int b43_dma_init(struct b43_wldev *dev)
{
return 0;
}
static inline void b43_dma_free(struct b43_wldev *dev)
{
}
static inline
int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
u16 dmacontroller_mmio_base, int dma64)
{
return 0;
}
static inline
int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
u16 dmacontroller_mmio_base, int dma64)
{
return 0;
}
static inline
void b43_dma_get_tx_stats(struct b43_wldev *dev,
struct ieee80211_tx_queue_stats *stats)
{
}
static inline
int b43_dma_tx(struct b43_wldev *dev,
struct sk_buff *skb, struct ieee80211_tx_control *ctl)
{
return 0;
}
static inline
void b43_dma_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status)
{
}
static inline void b43_dma_rx(struct b43_dmaring *ring)
{
}
static inline void b43_dma_tx_suspend(struct b43_wldev *dev)
{
}
static inline void b43_dma_tx_resume(struct b43_wldev *dev)
{
}
#endif /* CONFIG_B43_DMA */
#endif /* B43_DMA_H_ */

View file

@ -0,0 +1,299 @@
/*
Broadcom B43 wireless driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Stefano Brivio <st3@riseup.net>
Michael Buesch <mb@bu3sch.de>
Danny van Dyk <kugelfang@gentoo.org>
Andreas Jaggi <andreas.jaggi@waterwave.ch>
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 "b43.h"
#include "leds.h"
#include "main.h"
static void b43_led_changestate(struct b43_led *led)
{
struct b43_wldev *dev = led->dev;
const int index = b43_led_index(led);
const u16 mask = (1 << index);
u16 ledctl;
B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS));
B43_WARN_ON(!led->blink_interval);
ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask);
b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl);
}
static void b43_led_blink(unsigned long d)
{
struct b43_led *led = (struct b43_led *)d;
struct b43_wldev *dev = led->dev;
unsigned long flags;
spin_lock_irqsave(&dev->wl->leds_lock, flags);
if (led->blink_interval) {
b43_led_changestate(led);
mod_timer(&led->blink_timer, jiffies + led->blink_interval);
}
spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
}
static void b43_led_blink_start(struct b43_led *led, unsigned long interval)
{
if (led->blink_interval)
return;
led->blink_interval = interval;
b43_led_changestate(led);
led->blink_timer.expires = jiffies + interval;
add_timer(&led->blink_timer);
}
static void b43_led_blink_stop(struct b43_led *led, int sync)
{
struct b43_wldev *dev = led->dev;
const int index = b43_led_index(led);
u16 ledctl;
if (!led->blink_interval)
return;
if (unlikely(sync))
del_timer_sync(&led->blink_timer);
else
del_timer(&led->blink_timer);
led->blink_interval = 0;
/* Make sure the LED is turned off. */
B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS));
ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
if (led->activelow)
ledctl |= (1 << index);
else
ledctl &= ~(1 << index);
b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl);
}
static void b43_led_init_hardcoded(struct b43_wldev *dev,
struct b43_led *led, int led_index)
{
struct ssb_bus *bus = dev->dev->bus;
/* This function is called, if the behaviour (and activelow)
* information for a LED is missing in the SPROM.
* We hardcode the behaviour values for various devices here.
* Note that the B43_LED_TEST_XXX behaviour values can
* be used to figure out which led is mapped to which index.
*/
switch (led_index) {
case 0:
led->behaviour = B43_LED_ACTIVITY;
led->activelow = 1;
if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
led->behaviour = B43_LED_RADIO_ALL;
break;
case 1:
led->behaviour = B43_LED_RADIO_B;
if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
led->behaviour = B43_LED_ASSOC;
break;
case 2:
led->behaviour = B43_LED_RADIO_A;
break;
case 3:
led->behaviour = B43_LED_OFF;
break;
default:
B43_WARN_ON(1);
}
}
int b43_leds_init(struct b43_wldev *dev)
{
struct b43_led *led;
u8 sprom[4];
int i;
sprom[0] = dev->dev->bus->sprom.r1.gpio0;
sprom[1] = dev->dev->bus->sprom.r1.gpio1;
sprom[2] = dev->dev->bus->sprom.r1.gpio2;
sprom[3] = dev->dev->bus->sprom.r1.gpio3;
for (i = 0; i < B43_NR_LEDS; i++) {
led = &(dev->leds[i]);
led->dev = dev;
setup_timer(&led->blink_timer,
b43_led_blink, (unsigned long)led);
if (sprom[i] == 0xFF) {
b43_led_init_hardcoded(dev, led, i);
} else {
led->behaviour = sprom[i] & B43_LED_BEHAVIOUR;
led->activelow = !!(sprom[i] & B43_LED_ACTIVELOW);
}
}
return 0;
}
void b43_leds_exit(struct b43_wldev *dev)
{
struct b43_led *led;
int i;
for (i = 0; i < B43_NR_LEDS; i++) {
led = &(dev->leds[i]);
b43_led_blink_stop(led, 1);
}
b43_leds_switch_all(dev, 0);
}
void b43_leds_update(struct b43_wldev *dev, int activity)
{
struct b43_led *led;
struct b43_phy *phy = &dev->phy;
const int transferring =
(jiffies - dev->stats.last_tx) < B43_LED_XFER_THRES;
int i, turn_on;
unsigned long interval = 0;
u16 ledctl;
unsigned long flags;
spin_lock_irqsave(&dev->wl->leds_lock, flags);
ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
for (i = 0; i < B43_NR_LEDS; i++) {
led = &(dev->leds[i]);
turn_on = 0;
switch (led->behaviour) {
case B43_LED_INACTIVE:
continue;
case B43_LED_OFF:
break;
case B43_LED_ON:
turn_on = 1;
break;
case B43_LED_ACTIVITY:
turn_on = activity;
break;
case B43_LED_RADIO_ALL:
turn_on = phy->radio_on && b43_is_hw_radio_enabled(dev);
break;
case B43_LED_RADIO_A:
turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev)
&& phy->type == B43_PHYTYPE_A);
break;
case B43_LED_RADIO_B:
turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev)
&& (phy->type == B43_PHYTYPE_B
|| phy->type == B43_PHYTYPE_G));
break;
case B43_LED_MODE_BG:
if (phy->type == B43_PHYTYPE_G
&& b43_is_hw_radio_enabled(dev)
&& 1 /*FIXME: using G rates. */ )
turn_on = 1;
break;
case B43_LED_TRANSFER:
if (transferring)
b43_led_blink_start(led, B43_LEDBLINK_MEDIUM);
else
b43_led_blink_stop(led, 0);
continue;
case B43_LED_APTRANSFER:
if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
if (transferring) {
interval = B43_LEDBLINK_FAST;
turn_on = 1;
}
} else {
turn_on = 1;
if (0 /*TODO: not assoc */ )
interval = B43_LEDBLINK_SLOW;
else if (transferring)
interval = B43_LEDBLINK_FAST;
else
turn_on = 0;
}
if (turn_on)
b43_led_blink_start(led, interval);
else
b43_led_blink_stop(led, 0);
continue;
case B43_LED_WEIRD:
//TODO
break;
case B43_LED_ASSOC:
if (1 /*dev->softmac->associated */ )
turn_on = 1;
break;
#ifdef CONFIG_B43_DEBUG
case B43_LED_TEST_BLINKSLOW:
b43_led_blink_start(led, B43_LEDBLINK_SLOW);
continue;
case B43_LED_TEST_BLINKMEDIUM:
b43_led_blink_start(led, B43_LEDBLINK_MEDIUM);
continue;
case B43_LED_TEST_BLINKFAST:
b43_led_blink_start(led, B43_LEDBLINK_FAST);
continue;
#endif /* CONFIG_B43_DEBUG */
default:
B43_WARN_ON(1);
};
if (led->activelow)
turn_on = !turn_on;
if (turn_on)
ledctl |= (1 << i);
else
ledctl &= ~(1 << i);
}
b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl);
spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
}
void b43_leds_switch_all(struct b43_wldev *dev, int on)
{
struct b43_led *led;
u16 ledctl;
int i;
int bit_on;
unsigned long flags;
spin_lock_irqsave(&dev->wl->leds_lock, flags);
ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
for (i = 0; i < B43_NR_LEDS; i++) {
led = &(dev->leds[i]);
if (led->behaviour == B43_LED_INACTIVE)
continue;
if (on)
bit_on = led->activelow ? 0 : 1;
else
bit_on = led->activelow ? 1 : 0;
if (bit_on)
ledctl |= (1 << i);
else
ledctl &= ~(1 << i);
}
b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl);
spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
}

View file

@ -0,0 +1,55 @@
#ifndef B43_LEDS_H_
#define B43_LEDS_H_
#include <linux/types.h>
#include <linux/timer.h>
struct b43_led {
u8 behaviour:7;
u8 activelow:1;
struct b43_wldev *dev;
struct timer_list blink_timer;
unsigned long blink_interval;
};
#define b43_led_index(led) ((int)((led) - (led)->dev->leds))
/* Delay between state changes when blinking in jiffies */
#define B43_LEDBLINK_SLOW (HZ / 1)
#define B43_LEDBLINK_MEDIUM (HZ / 4)
#define B43_LEDBLINK_FAST (HZ / 8)
#define B43_LED_XFER_THRES (HZ / 100)
#define B43_LED_BEHAVIOUR 0x7F
#define B43_LED_ACTIVELOW 0x80
enum { /* LED behaviour values */
B43_LED_OFF,
B43_LED_ON,
B43_LED_ACTIVITY,
B43_LED_RADIO_ALL,
B43_LED_RADIO_A,
B43_LED_RADIO_B,
B43_LED_MODE_BG,
B43_LED_TRANSFER,
B43_LED_APTRANSFER,
B43_LED_WEIRD, //FIXME
B43_LED_ASSOC,
B43_LED_INACTIVE,
/* Behaviour values for testing.
* With these values it is easier to figure out
* the real behaviour of leds, in case the SPROM
* is missing information.
*/
B43_LED_TEST_BLINKSLOW,
B43_LED_TEST_BLINKMEDIUM,
B43_LED_TEST_BLINKFAST,
};
int b43_leds_init(struct b43_wldev *dev);
void b43_leds_exit(struct b43_wldev *dev);
void b43_leds_update(struct b43_wldev *dev, int activity);
void b43_leds_switch_all(struct b43_wldev *dev, int on);
#endif /* B43_LEDS_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,112 @@
#ifndef B43_LO_H_
#define B43_LO_H_
#include "phy.h"
struct b43_wldev;
/* Local Oscillator control value-pair. */
struct b43_loctl {
/* Control values. */
s8 i;
s8 q;
/* "Used by hardware" flag. */
bool used;
#ifdef CONFIG_B43_DEBUG
/* Is this lo-control-array entry calibrated? */
bool calibrated;
#endif
};
/* Debugging: Poison value for i and q values. */
#define B43_LOCTL_POISON 111
/* loctl->calibrated debugging mechanism */
#ifdef CONFIG_B43_DEBUG
static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl,
bool calibrated)
{
loctl->calibrated = calibrated;
}
static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl)
{
return loctl->calibrated;
}
#else
static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl,
bool calibrated)
{
}
static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl)
{
return 1;
}
#endif
/* TX Power LO Control Array.
* Value-pairs to adjust the LocalOscillator are stored
* in this structure.
* There are two different set of values. One for "Flag is Set"
* and one for "Flag is Unset".
* By "Flag" the flag in struct b43_rfatt is meant.
* The Value arrays are two-dimensional. The first index
* is the baseband attenuation and the second index
* is the radio attenuation.
* Use b43_get_lo_g_ctl() to retrieve a value from the lists.
*/
struct b43_txpower_lo_control {
#define B43_NR_BB 12
#define B43_NR_RF 16
/* LO Control values, with PAD Mixer */
struct b43_loctl with_padmix[B43_NR_BB][B43_NR_RF];
/* LO Control values, without PAD Mixer */
struct b43_loctl no_padmix[B43_NR_BB][B43_NR_RF];
/* Flag to indicate a complete rebuild of the two tables above
* to the LO measuring code. */
bool rebuild;
/* Lists of valid RF and BB attenuation values for this device. */
struct b43_rfatt_list rfatt_list;
struct b43_bbatt_list bbatt_list;
/* Current TX Bias value */
u8 tx_bias;
/* Current TX Magnification Value (if used by the device) */
u8 tx_magn;
/* GPHY LO is measured. */
bool lo_measured;
/* Saved device PowerVector */
u64 power_vector;
};
/* Measure the BPHY Local Oscillator. */
void b43_lo_b_measure(struct b43_wldev *dev);
/* Measure the BPHY/GPHY Local Oscillator. */
void b43_lo_g_measure(struct b43_wldev *dev);
/* Adjust the Local Oscillator to the saved attenuation
* and txctl values.
*/
void b43_lo_g_adjust(struct b43_wldev *dev);
/* Adjust to specific values. */
void b43_lo_g_adjust_to(struct b43_wldev *dev,
u16 rfatt, u16 bbatt, u16 tx_control);
/* Mark all possible b43_lo_g_ctl as "unused" */
void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev);
/* Mark the b43_lo_g_ctl corresponding to the current
* attenuation values as used.
*/
void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev);
/* Get a reference to a LO Control value pair in the
* TX Power LO Control Array.
*/
struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev,
const struct b43_rfatt *rfatt,
const struct b43_bbatt *bbatt);
#endif /* B43_LO_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,142 @@
/*
Broadcom B43 wireless driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Stefano Brivio <st3@riseup.net>
Michael Buesch <mb@bu3sch.de>
Danny van Dyk <kugelfang@gentoo.org>
Andreas Jaggi <andreas.jaggi@waterwave.ch>
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.
*/
#ifndef B43_MAIN_H_
#define B43_MAIN_H_
#include "b43.h"
#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes]
#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes)
/* Magic helper macro to pad structures. Ignore those above. It's magic. */
#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes))
/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
static inline u8 b43_freq_to_channel_a(int freq)
{
return ((freq - 5000) / 5);
}
static inline u8 b43_freq_to_channel_bg(int freq)
{
u8 channel;
if (freq == 2484)
channel = 14;
else
channel = (freq - 2407) / 5;
return channel;
}
static inline u8 b43_freq_to_channel(struct b43_wldev *dev, int freq)
{
if (dev->phy.type == B43_PHYTYPE_A)
return b43_freq_to_channel_a(freq);
return b43_freq_to_channel_bg(freq);
}
/* Lightweight function to convert a channel number to a frequency (in Mhz). */
static inline int b43_channel_to_freq_a(u8 channel)
{
return (5000 + (5 * channel));
}
static inline int b43_channel_to_freq_bg(u8 channel)
{
int freq;
if (channel == 14)
freq = 2484;
else
freq = 2407 + (5 * channel);
return freq;
}
static inline int b43_channel_to_freq(struct b43_wldev *dev, u8 channel)
{
if (dev->phy.type == B43_PHYTYPE_A)
return b43_channel_to_freq_a(channel);
return b43_channel_to_freq_bg(channel);
}
static inline int b43_is_cck_rate(int rate)
{
return (rate == B43_CCK_RATE_1MB ||
rate == B43_CCK_RATE_2MB ||
rate == B43_CCK_RATE_5MB || rate == B43_CCK_RATE_11MB);
}
static inline int b43_is_ofdm_rate(int rate)
{
return !b43_is_cck_rate(rate);
}
static inline int b43_is_hw_radio_enabled(struct b43_wldev *dev)
{
/* function to return state of hardware enable of radio
* returns 0 if radio disabled, 1 if radio enabled
*/
struct b43_phy *phy = &dev->phy;
if (phy->rev >= 3)
return ((b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI)
& B43_MMIO_RADIO_HWENABLED_HI_MASK)
== 0) ? 1 : 0;
else
return ((b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO)
& B43_MMIO_RADIO_HWENABLED_LO_MASK)
== 0) ? 0 : 1;
}
void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
void b43_tsf_write(struct b43_wldev *dev, u64 tsf);
u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
u32 b43_hf_read(struct b43_wldev *dev);
void b43_hf_write(struct b43_wldev *dev, u32 value);
void b43_dummy_transmission(struct b43_wldev *dev);
void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags);
void b43_mac_suspend(struct b43_wldev *dev);
void b43_mac_enable(struct b43_wldev *dev);
void b43_controller_restart(struct b43_wldev *dev, const char *reason);
#define B43_PS_ENABLED (1 << 0) /* Force enable hardware power saving */
#define B43_PS_DISABLED (1 << 1) /* Force disable hardware power saving */
#define B43_PS_AWAKE (1 << 2) /* Force device awake */
#define B43_PS_ASLEEP (1 << 3) /* Force device asleep */
void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags);
#endif /* B43_MAIN_H_ */

View file

@ -0,0 +1,157 @@
/*
Broadcom B43 wireless driver
Copyright (c) 2007 Michael Buesch <mb@bu3sch.de>
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/ssb/ssb.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
#include <pcmcia/cisreg.h>
static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = {
PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl);
#ifdef CONFIG_PM
static int b43_pcmcia_suspend(struct pcmcia_device *dev)
{
//TODO
return 0;
}
static int b43_pcmcia_resume(struct pcmcia_device *dev)
{
//TODO
return 0;
}
#else /* CONFIG_PM */
# define b43_pcmcia_suspend NULL
# define b43_pcmcia_resume NULL
#endif /* CONFIG_PM */
static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
{
struct ssb_bus *ssb;
win_req_t win;
memreq_t mem;
tuple_t tuple;
cisparse_t parse;
int err = -ENOMEM;
int res;
unsigned char buf[64];
ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
if (!ssb)
goto out;
err = -ENODEV;
tuple.DesiredTuple = CISTPL_CONFIG;
tuple.Attributes = 0;
tuple.TupleData = buf;
tuple.TupleDataMax = sizeof(buf);
tuple.TupleOffset = 0;
res = pcmcia_get_first_tuple(dev, &tuple);
if (res != CS_SUCCESS)
goto err_kfree_ssb;
res = pcmcia_get_tuple_data(dev, &tuple);
if (res != CS_SUCCESS)
goto err_kfree_ssb;
res = pcmcia_parse_tuple(dev, &tuple, &parse);
if (res != CS_SUCCESS)
goto err_kfree_ssb;
dev->conf.ConfigBase = parse.config.base;
dev->conf.Present = parse.config.rmask[0];
dev->io.BasePort2 = 0;
dev->io.NumPorts2 = 0;
dev->io.Attributes2 = 0;
win.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
win.Base = 0;
win.Size = SSB_CORE_SIZE;
win.AccessSpeed = 1000;
res = pcmcia_request_window(&dev, &win, &dev->win);
if (res != CS_SUCCESS)
goto err_kfree_ssb;
mem.CardOffset = 0;
mem.Page = 0;
res = pcmcia_map_mem_page(dev->win, &mem);
if (res != CS_SUCCESS)
goto err_kfree_ssb;
res = pcmcia_request_configuration(dev, &dev->conf);
if (res != CS_SUCCESS)
goto err_disable;
err = ssb_bus_pcmciabus_register(ssb, dev, win.Base);
dev->priv = ssb;
out:
return err;
err_disable:
pcmcia_disable_device(dev);
err_kfree_ssb:
kfree(ssb);
return err;
}
static void __devexit b43_pcmcia_remove(struct pcmcia_device *dev)
{
struct ssb_bus *ssb = dev->priv;
ssb_bus_unregister(ssb);
pcmcia_release_window(dev->win);
pcmcia_disable_device(dev);
kfree(ssb);
dev->priv = NULL;
}
static struct pcmcia_driver b43_pcmcia_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "b43-pcmcia",
},
.id_table = b43_pcmcia_tbl,
.probe = b43_pcmcia_probe,
.remove = b43_pcmcia_remove,
.suspend = b43_pcmcia_suspend,
.resume = b43_pcmcia_resume,
};
int b43_pcmcia_init(void)
{
return pcmcia_register_driver(&b43_pcmcia_driver);
}
void b43_pcmcia_exit(void)
{
pcmcia_unregister_driver(&b43_pcmcia_driver);
}

View file

@ -0,0 +1,20 @@
#ifndef B43_PCMCIA_H_
#define B43_PCMCIA_H_
#ifdef CONFIG_B43_PCMCIA
int b43_pcmcia_init(void);
void b43_pcmcia_exit(void);
#else /* CONFIG_B43_PCMCIA */
static inline int b43_pcmcia_init(void)
{
return 0;
}
static inline void b43_pcmcia_exit(void)
{
}
#endif /* CONFIG_B43_PCMCIA */
#endif /* B43_PCMCIA_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,297 @@
#ifndef B43_PHY_H_
#define B43_PHY_H_
#include <linux/types.h>
struct b43_wldev;
struct b43_phy;
/*** PHY Registers ***/
/* Routing */
#define B43_PHYROUTE_OFDM_GPHY 0x400
#define B43_PHYROUTE_EXT_GPHY 0x800
/* Base registers. */
#define B43_PHY_BASE(reg) (reg)
/* OFDM (A) registers of a G-PHY */
#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY)
/* Extended G-PHY registers */
#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY)
/* OFDM (A) PHY Registers */
#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */
#define B43_PHY_BBANDCFG B43_PHY_OFDM(0x01) /* Baseband config */
#define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */
#define B43_PHY_BBANDCFG_RXANT_SHIFT 7
#define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */
#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 */
#define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */
#define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */
#define B43_PHY_CRS0 B43_PHY_OFDM(0x29)
#define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */
#define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */
#define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */
#define B43_PHY_ENCORE_EN 0x0200 /* Encore enable */
#define B43_PHY_LMS B43_PHY_OFDM(0x55)
#define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */
#define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */
#define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */
#define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */
#define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */
#define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */
#define B43_PHY_OTABLENR_SHIFT 10
#define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */
#define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */
#define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */
#define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */
#define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */
#define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */
#define B43_PHY_CLIPPWRDOWNT B43_PHY_OFDM(0x93) /* Clip powerdown threshold */
#define B43_PHY_OFDM9B B43_PHY_OFDM(0x9B) /* FIXME rename */
#define B43_PHY_N1P1GAIN B43_PHY_OFDM(0xA0)
#define B43_PHY_P1P2GAIN B43_PHY_OFDM(0xA1)
#define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2)
#define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3)
#define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4)
#define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */
#define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9)
#define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA)
#define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB)
#define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */
#define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */
#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (rev 1 only) */
#define B43_PHY_CRSTHRES2_R1 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (rev 1 only) */
#define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */
#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */
#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */
/* CCK (B) PHY Registers */
#define B43_PHY_VERSION_CCK B43_PHY_BASE(0x00) /* Versioning register for B-PHY */
#define B43_PHY_CCKBBANDCFG B43_PHY_BASE(0x01) /* Contains antenna 0/1 control bit */
#define B43_PHY_PGACTL B43_PHY_BASE(0x15) /* PGA control */
#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */
#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */
#define B43_PHY_PGACTL_UNKNOWN 0xEFA0
#define B43_PHY_FBCTL1 B43_PHY_BASE(0x18) /* Frequency bandwidth control 1 */
#define B43_PHY_ITSSI B43_PHY_BASE(0x29) /* Idle TSSI */
#define B43_PHY_LO_LEAKAGE B43_PHY_BASE(0x2D) /* Measured LO leakage */
#define B43_PHY_ENERGY B43_PHY_BASE(0x33) /* Energy */
#define B43_PHY_SYNCCTL B43_PHY_BASE(0x35)
#define B43_PHY_FBCTL2 B43_PHY_BASE(0x38) /* Frequency bandwidth control 2 */
#define B43_PHY_DACCTL B43_PHY_BASE(0x60) /* DAC control */
#define B43_PHY_RCCALOVER B43_PHY_BASE(0x78) /* RC calibration override */
/* Extended G-PHY Registers */
#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */
#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */
#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */
#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */
#define B43_PHY_GTABNR_SHIFT 10
#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */
#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */
#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */
#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */
#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */
#define B43_PHY_RFOVERVAL_EXTLNA 0x8000
#define B43_PHY_RFOVERVAL_LNA 0x7000
#define B43_PHY_RFOVERVAL_LNA_SHIFT 12
#define B43_PHY_RFOVERVAL_PGA 0x0F00
#define B43_PHY_RFOVERVAL_PGA_SHIFT 8
#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */
#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0
#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */
#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */
#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */
#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */
#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */
/*** OFDM table numbers ***/
#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset))
#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0)
#define B43_OFDMTAB_GAIN0 B43_OFDMTAB(0x00, 0)
#define B43_OFDMTAB_GAINX B43_OFDMTAB(0x01, 0) //TODO rename
#define B43_OFDMTAB_GAIN1 B43_OFDMTAB(0x01, 4)
#define B43_OFDMTAB_AGC3 B43_OFDMTAB(0x02, 0)
#define B43_OFDMTAB_GAIN2 B43_OFDMTAB(0x02, 3)
#define B43_OFDMTAB_LNAHPFGAIN1 B43_OFDMTAB(0x03, 0)
#define B43_OFDMTAB_WRSSI B43_OFDMTAB(0x04, 0)
#define B43_OFDMTAB_LNAHPFGAIN2 B43_OFDMTAB(0x04, 0)
#define B43_OFDMTAB_NOISESCALE B43_OFDMTAB(0x05, 0)
#define B43_OFDMTAB_AGC2 B43_OFDMTAB(0x06, 0)
#define B43_OFDMTAB_ROTOR B43_OFDMTAB(0x08, 0)
#define B43_OFDMTAB_ADVRETARD B43_OFDMTAB(0x09, 0)
#define B43_OFDMTAB_DAC B43_OFDMTAB(0x0C, 0)
#define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7)
#define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12)
#define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13)
//TODO
#define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12)
#define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0)
//TODO
#define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0)
#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO rename
#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 1)
#define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0)
#define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4)
#define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0)
#define B43_OFDMTAB_DACRFPABB B43_OFDMTAB(0x16, 0)
#define B43_OFDMTAB_DACOFF B43_OFDMTAB(0x17, 0)
#define B43_OFDMTAB_DCBIAS B43_OFDMTAB(0x18, 0)
u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset);
void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
u16 offset, u16 value);
u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset);
void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
u16 offset, u32 value);
/*** G-PHY table numbers */
#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset))
#define B43_GTAB_NRSSI B43_GTAB(0x00, 0)
#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120)
#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298)
u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset); //TODO implement
void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value); //TODO implement
#define B43_DEFAULT_CHANNEL_A 36
#define B43_DEFAULT_CHANNEL_BG 6
enum {
B43_ANTENNA0, /* Antenna 0 */
B43_ANTENNA1, /* Antenna 0 */
B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
};
enum {
B43_INTERFMODE_NONE,
B43_INTERFMODE_NONWLAN,
B43_INTERFMODE_MANUALWLAN,
B43_INTERFMODE_AUTOWLAN,
};
/* Masks for the different PHY versioning registers. */
#define B43_PHYVER_ANALOG 0xF000
#define B43_PHYVER_ANALOG_SHIFT 12
#define B43_PHYVER_TYPE 0x0F00
#define B43_PHYVER_TYPE_SHIFT 8
#define B43_PHYVER_VERSION 0x00FF
void b43_raw_phy_lock(struct b43_wldev *dev);
#define b43_phy_lock(dev, flags) \
do { \
local_irq_save(flags); \
b43_raw_phy_lock(dev); \
} while (0)
void b43_raw_phy_unlock(struct b43_wldev *dev);
#define b43_phy_unlock(dev, flags) \
do { \
b43_raw_phy_unlock(dev); \
local_irq_restore(flags); \
} while (0)
u16 b43_phy_read(struct b43_wldev *dev, u16 offset);
void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val);
int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev);
void b43_phy_early_init(struct b43_wldev *dev);
int b43_phy_init(struct b43_wldev *dev);
void b43_set_rx_antenna(struct b43_wldev *dev, int antenna);
void b43_phy_xmitpower(struct b43_wldev *dev);
void b43_gphy_dc_lt_init(struct b43_wldev *dev);
/* Returns the boolean whether the board has HardwarePowerControl */
bool b43_has_hardware_pctl(struct b43_phy *phy);
/* Returns the boolean whether "TX Magnification" is enabled. */
#define has_tx_magnification(phy) \
(((phy)->rev >= 2) && \
((phy)->radio_ver == 0x2050) && \
((phy)->radio_rev == 8))
/* Card uses the loopback gain stuff */
#define has_loopback_gain(phy) \
(((phy)->rev > 1) || ((phy)->gmode))
/* Radio Attenuation (RF Attenuation) */
struct b43_rfatt {
u8 att; /* Attenuation value */
bool with_padmix; /* Flag, PAD Mixer enabled. */
};
struct b43_rfatt_list {
/* Attenuation values list */
const struct b43_rfatt *list;
u8 len;
/* Minimum/Maximum attenuation values */
u8 min_val;
u8 max_val;
};
/* Baseband Attenuation */
struct b43_bbatt {
u8 att; /* Attenuation value */
};
struct b43_bbatt_list {
/* Attenuation values list */
const struct b43_bbatt *list;
u8 len;
/* Minimum/Maximum attenuation values */
u8 min_val;
u8 max_val;
};
/* tx_control bits. */
#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */
#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */
#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */
/* Write BasebandAttenuation value to the device. */
void b43_phy_set_baseband_attenuation(struct b43_wldev *dev,
u16 baseband_attenuation);
extern const u8 b43_radio_channel_codes_bg[];
void b43_radio_lock(struct b43_wldev *dev);
void b43_radio_unlock(struct b43_wldev *dev);
u16 b43_radio_read16(struct b43_wldev *dev, u16 offset);
void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val);
u16 b43_radio_init2050(struct b43_wldev *dev);
void b43_radio_init2060(struct b43_wldev *dev);
void b43_radio_turn_on(struct b43_wldev *dev);
void b43_radio_turn_off(struct b43_wldev *dev);
int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel,
int synthetic_pu_workaround);
u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel);
u8 b43_radio_aci_scan(struct b43_wldev *dev);
int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode);
void b43_calc_nrssi_slope(struct b43_wldev *dev);
void b43_calc_nrssi_threshold(struct b43_wldev *dev);
s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset);
void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val);
void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val);
void b43_nrssi_mem_update(struct b43_wldev *dev);
void b43_radio_set_tx_iq(struct b43_wldev *dev);
u16 b43_radio_calibrationvalue(struct b43_wldev *dev);
void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
int *_bbatt, int *_rfatt);
void b43_set_txpower_g(struct b43_wldev *dev,
const struct b43_bbatt *bbatt,
const struct b43_rfatt *rfatt, u8 tx_control);
#endif /* B43_PHY_H_ */

View file

@ -0,0 +1,650 @@
/*
Broadcom B43 wireless driver
PIO Transmission
Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
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 "b43.h"
#include "pio.h"
#include "main.h"
#include "xmit.h"
#include <linux/delay.h>
static void tx_start(struct b43_pioqueue *queue)
{
b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_INIT);
}
static void tx_octet(struct b43_pioqueue *queue, u8 octet)
{
if (queue->need_workarounds) {
b43_pio_write(queue, B43_PIO_TXDATA, octet);
b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
} else {
b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
b43_pio_write(queue, B43_PIO_TXDATA, octet);
}
}
static u16 tx_get_next_word(const u8 * txhdr,
const u8 * packet,
size_t txhdr_size, unsigned int *pos)
{
const u8 *source;
unsigned int i = *pos;
u16 ret;
if (i < txhdr_size) {
source = txhdr;
} else {
source = packet;
i -= txhdr_size;
}
ret = le16_to_cpu(*((u16 *) (source + i)));
*pos += 2;
return ret;
}
static void tx_data(struct b43_pioqueue *queue,
u8 * txhdr, const u8 * packet, unsigned int octets)
{
u16 data;
unsigned int i = 0;
if (queue->need_workarounds) {
data = tx_get_next_word(txhdr, packet,
sizeof(struct b43_txhdr_fw4), &i);
b43_pio_write(queue, B43_PIO_TXDATA, data);
}
b43_pio_write(queue, B43_PIO_TXCTL,
B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI);
while (i < octets - 1) {
data = tx_get_next_word(txhdr, packet,
sizeof(struct b43_txhdr_fw4), &i);
b43_pio_write(queue, B43_PIO_TXDATA, data);
}
if (octets % 2)
tx_octet(queue,
packet[octets - sizeof(struct b43_txhdr_fw4) - 1]);
}
static void tx_complete(struct b43_pioqueue *queue, struct sk_buff *skb)
{
if (queue->need_workarounds) {
b43_pio_write(queue, B43_PIO_TXDATA, skb->data[skb->len - 1]);
b43_pio_write(queue, B43_PIO_TXCTL,
B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_COMPLETE);
} else {
b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_COMPLETE);
}
}
static u16 generate_cookie(struct b43_pioqueue *queue,
struct b43_pio_txpacket *packet)
{
u16 cookie = 0x0000;
int packetindex;
/* We use the upper 4 bits for the PIO
* controller ID and the lower 12 bits
* for the packet index (in the cache).
*/
switch (queue->mmio_base) {
case B43_MMIO_PIO1_BASE:
break;
case B43_MMIO_PIO2_BASE:
cookie = 0x1000;
break;
case B43_MMIO_PIO3_BASE:
cookie = 0x2000;
break;
case B43_MMIO_PIO4_BASE:
cookie = 0x3000;
break;
default:
B43_WARN_ON(1);
}
packetindex = pio_txpacket_getindex(packet);
B43_WARN_ON(packetindex & ~0x0FFF);
cookie |= (u16) packetindex;
return cookie;
}
static
struct b43_pioqueue *parse_cookie(struct b43_wldev *dev,
u16 cookie, struct b43_pio_txpacket **packet)
{
struct b43_pio *pio = &dev->pio;
struct b43_pioqueue *queue = NULL;
int packetindex;
switch (cookie & 0xF000) {
case 0x0000:
queue = pio->queue0;
break;
case 0x1000:
queue = pio->queue1;
break;
case 0x2000:
queue = pio->queue2;
break;
case 0x3000:
queue = pio->queue3;
break;
default:
B43_WARN_ON(1);
}
packetindex = (cookie & 0x0FFF);
B43_WARN_ON(!(packetindex >= 0 && packetindex < B43_PIO_MAXTXPACKETS));
*packet = &(queue->tx_packets_cache[packetindex]);
return queue;
}
union txhdr_union {
struct b43_txhdr_fw4 txhdr_fw4;
};
static void pio_tx_write_fragment(struct b43_pioqueue *queue,
struct sk_buff *skb,
struct b43_pio_txpacket *packet,
size_t txhdr_size)
{
union txhdr_union txhdr_data;
u8 *txhdr = NULL;
unsigned int octets;
txhdr = (u8 *) (&txhdr_data.txhdr_fw4);
B43_WARN_ON(skb_shinfo(skb)->nr_frags);
b43_generate_txhdr(queue->dev,
txhdr, skb->data, skb->len,
&packet->txstat.control,
generate_cookie(queue, packet));
tx_start(queue);
octets = skb->len + txhdr_size;
if (queue->need_workarounds)
octets--;
tx_data(queue, txhdr, (u8 *) skb->data, octets);
tx_complete(queue, skb);
}
static void free_txpacket(struct b43_pio_txpacket *packet)
{
struct b43_pioqueue *queue = packet->queue;
if (packet->skb)
dev_kfree_skb_any(packet->skb);
list_move(&packet->list, &queue->txfree);
queue->nr_txfree++;
}
static int pio_tx_packet(struct b43_pio_txpacket *packet)
{
struct b43_pioqueue *queue = packet->queue;
struct sk_buff *skb = packet->skb;
u16 octets;
octets = (u16) skb->len + sizeof(struct b43_txhdr_fw4);
if (queue->tx_devq_size < octets) {
b43warn(queue->dev->wl, "PIO queue too small. "
"Dropping packet.\n");
/* Drop it silently (return success) */
free_txpacket(packet);
return 0;
}
B43_WARN_ON(queue->tx_devq_packets > B43_PIO_MAXTXDEVQPACKETS);
B43_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
/* Check if there is sufficient free space on the device
* TX queue. If not, return and let the TX tasklet
* retry later.
*/
if (queue->tx_devq_packets == B43_PIO_MAXTXDEVQPACKETS)
return -EBUSY;
if (queue->tx_devq_used + octets > queue->tx_devq_size)
return -EBUSY;
/* Now poke the device. */
pio_tx_write_fragment(queue, skb, packet, sizeof(struct b43_txhdr_fw4));
/* Account for the packet size.
* (We must not overflow the device TX queue)
*/
queue->tx_devq_packets++;
queue->tx_devq_used += octets;
/* Transmission started, everything ok, move the
* packet to the txrunning list.
*/
list_move_tail(&packet->list, &queue->txrunning);
return 0;
}
static void tx_tasklet(unsigned long d)
{
struct b43_pioqueue *queue = (struct b43_pioqueue *)d;
struct b43_wldev *dev = queue->dev;
unsigned long flags;
struct b43_pio_txpacket *packet, *tmp_packet;
int err;
u16 txctl;
spin_lock_irqsave(&dev->wl->irq_lock, flags);
if (queue->tx_frozen)
goto out_unlock;
txctl = b43_pio_read(queue, B43_PIO_TXCTL);
if (txctl & B43_PIO_TXCTL_SUSPEND)
goto out_unlock;
list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
/* Try to transmit the packet. This can fail, if
* the device queue is full. In case of failure, the
* packet is left in the txqueue.
* If transmission succeed, the packet is moved to txrunning.
* If it is impossible to transmit the packet, it
* is dropped.
*/
err = pio_tx_packet(packet);
if (err)
break;
}
out_unlock:
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
}
static void setup_txqueues(struct b43_pioqueue *queue)
{
struct b43_pio_txpacket *packet;
int i;
queue->nr_txfree = B43_PIO_MAXTXPACKETS;
for (i = 0; i < B43_PIO_MAXTXPACKETS; i++) {
packet = &(queue->tx_packets_cache[i]);
packet->queue = queue;
INIT_LIST_HEAD(&packet->list);
list_add(&packet->list, &queue->txfree);
}
}
static
struct b43_pioqueue *b43_setup_pioqueue(struct b43_wldev *dev,
u16 pio_mmio_base)
{
struct b43_pioqueue *queue;
u16 qsize;
queue = kzalloc(sizeof(*queue), GFP_KERNEL);
if (!queue)
goto out;
queue->dev = dev;
queue->mmio_base = pio_mmio_base;
queue->need_workarounds = (dev->dev->id.revision < 3);
INIT_LIST_HEAD(&queue->txfree);
INIT_LIST_HEAD(&queue->txqueue);
INIT_LIST_HEAD(&queue->txrunning);
tasklet_init(&queue->txtask, tx_tasklet, (unsigned long)queue);
b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
& ~B43_MACCTL_BE);
qsize = b43_read16(dev, queue->mmio_base + B43_PIO_TXQBUFSIZE);
if (qsize == 0) {
b43err(dev->wl, "This card does not support PIO "
"operation mode. Please use DMA mode "
"(module parameter pio=0).\n");
goto err_freequeue;
}
if (qsize <= B43_PIO_TXQADJUST) {
b43err(dev->wl, "PIO tx device-queue too small (%u)\n", qsize);
goto err_freequeue;
}
qsize -= B43_PIO_TXQADJUST;
queue->tx_devq_size = qsize;
setup_txqueues(queue);
out:
return queue;
err_freequeue:
kfree(queue);
queue = NULL;
goto out;
}
static void cancel_transfers(struct b43_pioqueue *queue)
{
struct b43_pio_txpacket *packet, *tmp_packet;
tasklet_disable(&queue->txtask);
list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
free_txpacket(packet);
list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
free_txpacket(packet);
}
static void b43_destroy_pioqueue(struct b43_pioqueue *queue)
{
if (!queue)
return;
cancel_transfers(queue);
kfree(queue);
}
void b43_pio_free(struct b43_wldev *dev)
{
struct b43_pio *pio;
if (!b43_using_pio(dev))
return;
pio = &dev->pio;
b43_destroy_pioqueue(pio->queue3);
pio->queue3 = NULL;
b43_destroy_pioqueue(pio->queue2);
pio->queue2 = NULL;
b43_destroy_pioqueue(pio->queue1);
pio->queue1 = NULL;
b43_destroy_pioqueue(pio->queue0);
pio->queue0 = NULL;
}
int b43_pio_init(struct b43_wldev *dev)
{
struct b43_pio *pio = &dev->pio;
struct b43_pioqueue *queue;
int err = -ENOMEM;
queue = b43_setup_pioqueue(dev, B43_MMIO_PIO1_BASE);
if (!queue)
goto out;
pio->queue0 = queue;
queue = b43_setup_pioqueue(dev, B43_MMIO_PIO2_BASE);
if (!queue)
goto err_destroy0;
pio->queue1 = queue;
queue = b43_setup_pioqueue(dev, B43_MMIO_PIO3_BASE);
if (!queue)
goto err_destroy1;
pio->queue2 = queue;
queue = b43_setup_pioqueue(dev, B43_MMIO_PIO4_BASE);
if (!queue)
goto err_destroy2;
pio->queue3 = queue;
if (dev->dev->id.revision < 3)
dev->irq_savedstate |= B43_IRQ_PIO_WORKAROUND;
b43dbg(dev->wl, "PIO initialized\n");
err = 0;
out:
return err;
err_destroy2:
b43_destroy_pioqueue(pio->queue2);
pio->queue2 = NULL;
err_destroy1:
b43_destroy_pioqueue(pio->queue1);
pio->queue1 = NULL;
err_destroy0:
b43_destroy_pioqueue(pio->queue0);
pio->queue0 = NULL;
goto out;
}
int b43_pio_tx(struct b43_wldev *dev,
struct sk_buff *skb, struct ieee80211_tx_control *ctl)
{
struct b43_pioqueue *queue = dev->pio.queue1;
struct b43_pio_txpacket *packet;
B43_WARN_ON(queue->tx_suspended);
B43_WARN_ON(list_empty(&queue->txfree));
packet = list_entry(queue->txfree.next, struct b43_pio_txpacket, list);
packet->skb = skb;
memset(&packet->txstat, 0, sizeof(packet->txstat));
memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
list_move_tail(&packet->list, &queue->txqueue);
queue->nr_txfree--;
queue->nr_tx_packets++;
B43_WARN_ON(queue->nr_txfree >= B43_PIO_MAXTXPACKETS);
tasklet_schedule(&queue->txtask);
return 0;
}
void b43_pio_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status)
{
struct b43_pioqueue *queue;
struct b43_pio_txpacket *packet;
queue = parse_cookie(dev, status->cookie, &packet);
if (B43_WARN_ON(!queue))
return;
queue->tx_devq_packets--;
queue->tx_devq_used -=
(packet->skb->len + sizeof(struct b43_txhdr_fw4));
if (status->acked) {
packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
} else {
if (!(packet->txstat.control.flags & IEEE80211_TXCTL_NO_ACK))
packet->txstat.excessive_retries = 1;
}
if (status->frame_count == 0) {
/* The frame was not transmitted at all. */
packet->txstat.retry_count = 0;
} else
packet->txstat.retry_count = status->frame_count - 1;
ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
&(packet->txstat));
packet->skb = NULL;
free_txpacket(packet);
/* If there are packets on the txqueue, poke the tasklet
* to transmit them.
*/
if (!list_empty(&queue->txqueue))
tasklet_schedule(&queue->txtask);
}
void b43_pio_get_tx_stats(struct b43_wldev *dev,
struct ieee80211_tx_queue_stats *stats)
{
struct b43_pio *pio = &dev->pio;
struct b43_pioqueue *queue;
struct ieee80211_tx_queue_stats_data *data;
queue = pio->queue1;
data = &(stats->data[0]);
data->len = B43_PIO_MAXTXPACKETS - queue->nr_txfree;
data->limit = B43_PIO_MAXTXPACKETS;
data->count = queue->nr_tx_packets;
}
static void pio_rx_error(struct b43_pioqueue *queue,
int clear_buffers, const char *error)
{
int i;
b43err(queue->dev->wl, "PIO RX error: %s\n", error);
b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_READY);
if (clear_buffers) {
B43_WARN_ON(queue->mmio_base != B43_MMIO_PIO1_BASE);
for (i = 0; i < 15; i++) {
/* Dummy read. */
b43_pio_read(queue, B43_PIO_RXDATA);
}
}
}
void b43_pio_rx(struct b43_pioqueue *queue)
{
u16 preamble[21] = { 0 };
struct b43_rxhdr_fw4 *rxhdr;
u16 tmp, len, macstat;
int i, preamble_readwords;
struct sk_buff *skb;
tmp = b43_pio_read(queue, B43_PIO_RXCTL);
if (!(tmp & B43_PIO_RXCTL_DATAAVAILABLE))
return;
b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_DATAAVAILABLE);
for (i = 0; i < 10; i++) {
tmp = b43_pio_read(queue, B43_PIO_RXCTL);
if (tmp & B43_PIO_RXCTL_READY)
goto data_ready;
udelay(10);
}
b43dbg(queue->dev->wl, "PIO RX timed out\n");
return;
data_ready:
len = b43_pio_read(queue, B43_PIO_RXDATA);
if (unlikely(len > 0x700)) {
pio_rx_error(queue, 0, "len > 0x700");
return;
}
if (unlikely(len == 0 && queue->mmio_base != B43_MMIO_PIO4_BASE)) {
pio_rx_error(queue, 0, "len == 0");
return;
}
preamble[0] = cpu_to_le16(len);
if (queue->mmio_base == B43_MMIO_PIO4_BASE)
preamble_readwords = 14 / sizeof(u16);
else
preamble_readwords = 18 / sizeof(u16);
for (i = 0; i < preamble_readwords; i++) {
tmp = b43_pio_read(queue, B43_PIO_RXDATA);
preamble[i + 1] = cpu_to_le16(tmp);
}
rxhdr = (struct b43_rxhdr_fw4 *)preamble;
macstat = le16_to_cpu(rxhdr->mac_status);
if (macstat & B43_RX_MAC_FCSERR) {
pio_rx_error(queue,
(queue->mmio_base == B43_MMIO_PIO1_BASE),
"Frame FCS error");
return;
}
if (queue->mmio_base == B43_MMIO_PIO4_BASE) {
/* We received an xmit status. */
struct b43_hwtxstatus *hw;
hw = (struct b43_hwtxstatus *)(preamble + 1);
b43_handle_hwtxstatus(queue->dev, hw);
return;
}
skb = dev_alloc_skb(len);
if (unlikely(!skb)) {
pio_rx_error(queue, 1, "OOM");
return;
}
skb_put(skb, len);
for (i = 0; i < len - 1; i += 2) {
tmp = b43_pio_read(queue, B43_PIO_RXDATA);
*((u16 *) (skb->data + i)) = cpu_to_le16(tmp);
}
if (len % 2) {
tmp = b43_pio_read(queue, B43_PIO_RXDATA);
skb->data[len - 1] = (tmp & 0x00FF);
/* The specs say the following is required, but
* it is wrong and corrupts the PLCP. If we don't do
* this, the PLCP seems to be correct. So ifdef it out for now.
*/
#if 0
if (rxflags2 & B43_RXHDR_FLAGS2_TYPE2FRAME)
skb->data[2] = (tmp & 0xFF00) >> 8;
else
skb->data[0] = (tmp & 0xFF00) >> 8;
#endif
}
b43_rx(queue->dev, skb, rxhdr);
}
void b43_pio_tx_suspend(struct b43_pioqueue *queue)
{
b43_power_saving_ctl_bits(queue->dev, B43_PS_AWAKE);
b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
| B43_PIO_TXCTL_SUSPEND);
}
void b43_pio_tx_resume(struct b43_pioqueue *queue)
{
b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
& ~B43_PIO_TXCTL_SUSPEND);
b43_power_saving_ctl_bits(queue->dev, 0);
tasklet_schedule(&queue->txtask);
}
void b43_pio_freeze_txqueues(struct b43_wldev *dev)
{
struct b43_pio *pio;
B43_WARN_ON(!b43_using_pio(dev));
pio = &dev->pio;
pio->queue0->tx_frozen = 1;
pio->queue1->tx_frozen = 1;
pio->queue2->tx_frozen = 1;
pio->queue3->tx_frozen = 1;
}
void b43_pio_thaw_txqueues(struct b43_wldev *dev)
{
struct b43_pio *pio;
B43_WARN_ON(!b43_using_pio(dev));
pio = &dev->pio;
pio->queue0->tx_frozen = 0;
pio->queue1->tx_frozen = 0;
pio->queue2->tx_frozen = 0;
pio->queue3->tx_frozen = 0;
if (!list_empty(&pio->queue0->txqueue))
tasklet_schedule(&pio->queue0->txtask);
if (!list_empty(&pio->queue1->txqueue))
tasklet_schedule(&pio->queue1->txtask);
if (!list_empty(&pio->queue2->txqueue))
tasklet_schedule(&pio->queue2->txtask);
if (!list_empty(&pio->queue3->txqueue))
tasklet_schedule(&pio->queue3->txtask);
}

View file

@ -0,0 +1,153 @@
#ifndef B43_PIO_H_
#define B43_PIO_H_
#include "b43.h"
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/skbuff.h>
#define B43_PIO_TXCTL 0x00
#define B43_PIO_TXDATA 0x02
#define B43_PIO_TXQBUFSIZE 0x04
#define B43_PIO_RXCTL 0x08
#define B43_PIO_RXDATA 0x0A
#define B43_PIO_TXCTL_WRITELO (1 << 0)
#define B43_PIO_TXCTL_WRITEHI (1 << 1)
#define B43_PIO_TXCTL_COMPLETE (1 << 2)
#define B43_PIO_TXCTL_INIT (1 << 3)
#define B43_PIO_TXCTL_SUSPEND (1 << 7)
#define B43_PIO_RXCTL_DATAAVAILABLE (1 << 0)
#define B43_PIO_RXCTL_READY (1 << 1)
/* PIO constants */
#define B43_PIO_MAXTXDEVQPACKETS 31
#define B43_PIO_TXQADJUST 80
/* PIO tuning knobs */
#define B43_PIO_MAXTXPACKETS 256
#ifdef CONFIG_B43_PIO
struct b43_pioqueue;
struct b43_xmitstatus;
struct b43_pio_txpacket {
struct b43_pioqueue *queue;
struct sk_buff *skb;
struct ieee80211_tx_status txstat;
struct list_head list;
};
#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache))
struct b43_pioqueue {
struct b43_wldev *dev;
u16 mmio_base;
bool tx_suspended;
bool tx_frozen;
bool need_workarounds; /* Workarounds needed for core.rev < 3 */
/* Adjusted size of the device internal TX buffer. */
u16 tx_devq_size;
/* Used octets of the device internal TX buffer. */
u16 tx_devq_used;
/* Used packet slots in the device internal TX buffer. */
u8 tx_devq_packets;
/* Packets from the txfree list can
* be taken on incoming TX requests.
*/
struct list_head txfree;
unsigned int nr_txfree;
/* Packets on the txqueue are queued,
* but not completely written to the chip, yet.
*/
struct list_head txqueue;
/* Packets on the txrunning queue are completely
* posted to the device. We are waiting for the txstatus.
*/
struct list_head txrunning;
/* Total number or packets sent.
* (This counter can obviously wrap).
*/
unsigned int nr_tx_packets;
struct tasklet_struct txtask;
struct b43_pio_txpacket tx_packets_cache[B43_PIO_MAXTXPACKETS];
};
static inline u16 b43_pio_read(struct b43_pioqueue *queue, u16 offset)
{
return b43_read16(queue->dev, queue->mmio_base + offset);
}
static inline
void b43_pio_write(struct b43_pioqueue *queue, u16 offset, u16 value)
{
b43_write16(queue->dev, queue->mmio_base + offset, value);
mmiowb();
}
int b43_pio_init(struct b43_wldev *dev);
void b43_pio_free(struct b43_wldev *dev);
int b43_pio_tx(struct b43_wldev *dev,
struct sk_buff *skb, struct ieee80211_tx_control *ctl);
void b43_pio_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status);
void b43_pio_get_tx_stats(struct b43_wldev *dev,
struct ieee80211_tx_queue_stats *stats);
void b43_pio_rx(struct b43_pioqueue *queue);
/* Suspend TX queue in hardware. */
void b43_pio_tx_suspend(struct b43_pioqueue *queue);
void b43_pio_tx_resume(struct b43_pioqueue *queue);
/* Suspend (freeze) the TX tasklet (software level). */
void b43_pio_freeze_txqueues(struct b43_wldev *dev);
void b43_pio_thaw_txqueues(struct b43_wldev *dev);
#else /* CONFIG_B43_PIO */
static inline int b43_pio_init(struct b43_wldev *dev)
{
return 0;
}
static inline void b43_pio_free(struct b43_wldev *dev)
{
}
static inline
int b43_pio_tx(struct b43_wldev *dev,
struct sk_buff *skb, struct ieee80211_tx_control *ctl)
{
return 0;
}
static inline
void b43_pio_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status)
{
}
static inline
void b43_pio_get_tx_stats(struct b43_wldev *dev,
struct ieee80211_tx_queue_stats *stats)
{
}
static inline void b43_pio_rx(struct b43_pioqueue *queue)
{
}
static inline void b43_pio_tx_suspend(struct b43_pioqueue *queue)
{
}
static inline void b43_pio_tx_resume(struct b43_pioqueue *queue)
{
}
static inline void b43_pio_freeze_txqueues(struct b43_wldev *dev)
{
}
static inline void b43_pio_thaw_txqueues(struct b43_wldev *dev)
{
}
#endif /* CONFIG_B43_PIO */
#endif /* B43_PIO_H_ */

View file

@ -0,0 +1,235 @@
/*
Broadcom B43 wireless driver
SYSFS support routines
Copyright (c) 2006 Michael Buesch <mb@bu3sch.de>
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 "b43.h"
#include "sysfs.h"
#include "main.h"
#include "phy.h"
#include <linux/capability.h>
#define GENERIC_FILESIZE 64
static int get_integer(const char *buf, size_t count)
{
char tmp[10 + 1] = { 0 };
int ret = -EINVAL;
if (count == 0)
goto out;
count = min(count, (size_t) 10);
memcpy(tmp, buf, count);
ret = simple_strtol(tmp, NULL, 10);
out:
return ret;
}
static int get_boolean(const char *buf, size_t count)
{
if (count != 0) {
if (buf[0] == '1')
return 1;
if (buf[0] == '0')
return 0;
if (count >= 4 && memcmp(buf, "true", 4) == 0)
return 1;
if (count >= 5 && memcmp(buf, "false", 5) == 0)
return 0;
if (count >= 3 && memcmp(buf, "yes", 3) == 0)
return 1;
if (count >= 2 && memcmp(buf, "no", 2) == 0)
return 0;
if (count >= 2 && memcmp(buf, "on", 2) == 0)
return 1;
if (count >= 3 && memcmp(buf, "off", 3) == 0)
return 0;
}
return -EINVAL;
}
static ssize_t b43_attr_interfmode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct b43_wldev *wldev = dev_to_b43_wldev(dev);
ssize_t count = 0;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
mutex_lock(&wldev->wl->mutex);
switch (wldev->phy.interfmode) {
case B43_INTERFMODE_NONE:
count =
snprintf(buf, PAGE_SIZE,
"0 (No Interference Mitigation)\n");
break;
case B43_INTERFMODE_NONWLAN:
count =
snprintf(buf, PAGE_SIZE,
"1 (Non-WLAN Interference Mitigation)\n");
break;
case B43_INTERFMODE_MANUALWLAN:
count =
snprintf(buf, PAGE_SIZE,
"2 (WLAN Interference Mitigation)\n");
break;
default:
B43_WARN_ON(1);
}
mutex_unlock(&wldev->wl->mutex);
return count;
}
static ssize_t b43_attr_interfmode_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct b43_wldev *wldev = dev_to_b43_wldev(dev);
unsigned long flags;
int err;
int mode;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
mode = get_integer(buf, count);
switch (mode) {
case 0:
mode = B43_INTERFMODE_NONE;
break;
case 1:
mode = B43_INTERFMODE_NONWLAN;
break;
case 2:
mode = B43_INTERFMODE_MANUALWLAN;
break;
case 3:
mode = B43_INTERFMODE_AUTOWLAN;
break;
default:
return -EINVAL;
}
mutex_lock(&wldev->wl->mutex);
spin_lock_irqsave(&wldev->wl->irq_lock, flags);
err = b43_radio_set_interference_mitigation(wldev, mode);
if (err) {
b43err(wldev->wl, "Interference Mitigation not "
"supported by device\n");
}
mmiowb();
spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
mutex_unlock(&wldev->wl->mutex);
return err ? err : count;
}
static DEVICE_ATTR(interference, 0644,
b43_attr_interfmode_show, b43_attr_interfmode_store);
static ssize_t b43_attr_preamble_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct b43_wldev *wldev = dev_to_b43_wldev(dev);
ssize_t count;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
mutex_lock(&wldev->wl->mutex);
if (wldev->short_preamble)
count =
snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
else
count =
snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
mutex_unlock(&wldev->wl->mutex);
return count;
}
static ssize_t b43_attr_preamble_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct b43_wldev *wldev = dev_to_b43_wldev(dev);
unsigned long flags;
int value;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
value = get_boolean(buf, count);
if (value < 0)
return value;
mutex_lock(&wldev->wl->mutex);
spin_lock_irqsave(&wldev->wl->irq_lock, flags);
wldev->short_preamble = !!value;
spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
mutex_unlock(&wldev->wl->mutex);
return count;
}
static DEVICE_ATTR(shortpreamble, 0644,
b43_attr_preamble_show, b43_attr_preamble_store);
int b43_sysfs_register(struct b43_wldev *wldev)
{
struct device *dev = wldev->dev->dev;
int err;
B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
err = device_create_file(dev, &dev_attr_interference);
if (err)
goto out;
err = device_create_file(dev, &dev_attr_shortpreamble);
if (err)
goto err_remove_interfmode;
out:
return err;
err_remove_interfmode:
device_remove_file(dev, &dev_attr_interference);
goto out;
}
void b43_sysfs_unregister(struct b43_wldev *wldev)
{
struct device *dev = wldev->dev->dev;
device_remove_file(dev, &dev_attr_shortpreamble);
device_remove_file(dev, &dev_attr_interference);
}

View file

@ -0,0 +1,9 @@
#ifndef B43_SYSFS_H_
#define B43_SYSFS_H_
struct b43_wldev;
int b43_sysfs_register(struct b43_wldev *dev);
void b43_sysfs_unregister(struct b43_wldev *dev);
#endif /* B43_SYSFS_H_ */

View file

@ -0,0 +1,375 @@
/*
Broadcom B43 wireless driver
Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
Copyright (c) 2006, 2006 Michael Buesch <mb@bu3sch.de>
Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
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 "b43.h"
#include "tables.h"
#include "phy.h"
const u32 b43_tab_rotor[] = {
0xFEB93FFD, 0xFEC63FFD, /* 0 */
0xFED23FFD, 0xFEDF3FFD,
0xFEEC3FFE, 0xFEF83FFE,
0xFF053FFE, 0xFF113FFE,
0xFF1E3FFE, 0xFF2A3FFF, /* 8 */
0xFF373FFF, 0xFF443FFF,
0xFF503FFF, 0xFF5D3FFF,
0xFF693FFF, 0xFF763FFF,
0xFF824000, 0xFF8F4000, /* 16 */
0xFF9B4000, 0xFFA84000,
0xFFB54000, 0xFFC14000,
0xFFCE4000, 0xFFDA4000,
0xFFE74000, 0xFFF34000, /* 24 */
0x00004000, 0x000D4000,
0x00194000, 0x00264000,
0x00324000, 0x003F4000,
0x004B4000, 0x00584000, /* 32 */
0x00654000, 0x00714000,
0x007E4000, 0x008A3FFF,
0x00973FFF, 0x00A33FFF,
0x00B03FFF, 0x00BC3FFF, /* 40 */
0x00C93FFF, 0x00D63FFF,
0x00E23FFE, 0x00EF3FFE,
0x00FB3FFE, 0x01083FFE,
0x01143FFE, 0x01213FFD, /* 48 */
0x012E3FFD, 0x013A3FFD,
0x01473FFD,
};
const u32 b43_tab_retard[] = {
0xDB93CB87, 0xD666CF64, /* 0 */
0xD1FDD358, 0xCDA6D826,
0xCA38DD9F, 0xC729E2B4,
0xC469E88E, 0xC26AEE2B,
0xC0DEF46C, 0xC073FA62, /* 8 */
0xC01D00D5, 0xC0760743,
0xC1560D1E, 0xC2E51369,
0xC4ED18FF, 0xC7AC1ED7,
0xCB2823B2, 0xCEFA28D9, /* 16 */
0xD2F62D3F, 0xD7BB3197,
0xDCE53568, 0xE1FE3875,
0xE7D13B35, 0xED663D35,
0xF39B3EC4, 0xF98E3FA7, /* 24 */
0x00004000, 0x06723FA7,
0x0C653EC4, 0x129A3D35,
0x182F3B35, 0x1E023875,
0x231B3568, 0x28453197, /* 32 */
0x2D0A2D3F, 0x310628D9,
0x34D823B2, 0x38541ED7,
0x3B1318FF, 0x3D1B1369,
0x3EAA0D1E, 0x3F8A0743, /* 40 */
0x3FE300D5, 0x3F8DFA62,
0x3F22F46C, 0x3D96EE2B,
0x3B97E88E, 0x38D7E2B4,
0x35C8DD9F, 0x325AD826, /* 48 */
0x2E03D358, 0x299ACF64,
0x246DCB87,
};
const u16 b43_tab_finefreqa[] = {
0x0082, 0x0082, 0x0102, 0x0182, /* 0 */
0x0202, 0x0282, 0x0302, 0x0382,
0x0402, 0x0482, 0x0502, 0x0582,
0x05E2, 0x0662, 0x06E2, 0x0762,
0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */
0x09C2, 0x0A22, 0x0AA2, 0x0B02,
0x0B82, 0x0BE2, 0x0C62, 0x0CC2,
0x0D42, 0x0DA2, 0x0E02, 0x0E62,
0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */
0x1062, 0x10C2, 0x1122, 0x1182,
0x11E2, 0x1242, 0x12A2, 0x12E2,
0x1342, 0x13A2, 0x1402, 0x1442,
0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */
0x15E2, 0x1622, 0x1662, 0x16C1,
0x1701, 0x1741, 0x1781, 0x17E1,
0x1821, 0x1861, 0x18A1, 0x18E1,
0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */
0x1A21, 0x1A61, 0x1AA1, 0x1AC1,
0x1B01, 0x1B41, 0x1B81, 0x1BA1,
0x1BE1, 0x1C21, 0x1C41, 0x1C81,
0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */
0x1D61, 0x1DA1, 0x1DC1, 0x1E01,
0x1E21, 0x1E61, 0x1E81, 0x1EA1,
0x1EE1, 0x1F01, 0x1F21, 0x1F41,
0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */
0x2001, 0x2041, 0x2061, 0x2081,
0x20A1, 0x20C1, 0x20E1, 0x2101,
0x2121, 0x2141, 0x2161, 0x2181,
0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */
0x2221, 0x2241, 0x2261, 0x2281,
0x22A1, 0x22C1, 0x22C1, 0x22E1,
0x2301, 0x2321, 0x2341, 0x2361,
0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */
0x23E1, 0x23E1, 0x2401, 0x2421,
0x2441, 0x2441, 0x2461, 0x2481,
0x2481, 0x24A1, 0x24C1, 0x24C1,
0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */
0x2541, 0x2541, 0x2561, 0x2561,
0x2581, 0x25A1, 0x25A1, 0x25C1,
0x25C1, 0x25E1, 0x2601, 0x2601,
0x2621, 0x2621, 0x2641, 0x2641, /* 160 */
0x2661, 0x2661, 0x2681, 0x2681,
0x26A1, 0x26A1, 0x26C1, 0x26C1,
0x26E1, 0x26E1, 0x2701, 0x2701,
0x2721, 0x2721, 0x2740, 0x2740, /* 176 */
0x2760, 0x2760, 0x2780, 0x2780,
0x2780, 0x27A0, 0x27A0, 0x27C0,
0x27C0, 0x27E0, 0x27E0, 0x27E0,
0x2800, 0x2800, 0x2820, 0x2820, /* 192 */
0x2820, 0x2840, 0x2840, 0x2840,
0x2860, 0x2860, 0x2880, 0x2880,
0x2880, 0x28A0, 0x28A0, 0x28A0,
0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */
0x28E0, 0x28E0, 0x2900, 0x2900,
0x2900, 0x2920, 0x2920, 0x2920,
0x2940, 0x2940, 0x2940, 0x2960,
0x2960, 0x2960, 0x2960, 0x2980, /* 224 */
0x2980, 0x2980, 0x29A0, 0x29A0,
0x29A0, 0x29A0, 0x29C0, 0x29C0,
0x29C0, 0x29E0, 0x29E0, 0x29E0,
0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */
0x2A00, 0x2A20, 0x2A20, 0x2A20,
0x2A20, 0x2A40, 0x2A40, 0x2A40,
0x2A40, 0x2A60, 0x2A60, 0x2A60,
};
const u16 b43_tab_finefreqg[] = {
0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */
0x05A9, 0x0669, 0x0709, 0x0789,
0x0829, 0x08A9, 0x0929, 0x0989,
0x0A09, 0x0A69, 0x0AC9, 0x0B29,
0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */
0x0D09, 0x0D69, 0x0DA9, 0x0E09,
0x0E69, 0x0EA9, 0x0F09, 0x0F49,
0x0FA9, 0x0FE9, 0x1029, 0x1089,
0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */
0x11E9, 0x1229, 0x1289, 0x12C9,
0x1309, 0x1349, 0x1389, 0x13C9,
0x1409, 0x1449, 0x14A9, 0x14E9,
0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */
0x1629, 0x1669, 0x16A9, 0x16E8,
0x1728, 0x1768, 0x17A8, 0x17E8,
0x1828, 0x1868, 0x18A8, 0x18E8,
0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */
0x1A28, 0x1A68, 0x1AA8, 0x1AE8,
0x1B28, 0x1B68, 0x1BA8, 0x1BE8,
0x1C28, 0x1C68, 0x1CA8, 0x1CE8,
0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */
0x1E48, 0x1E88, 0x1EC8, 0x1F08,
0x1F48, 0x1F88, 0x1FE8, 0x2028,
0x2068, 0x20A8, 0x2108, 0x2148,
0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */
0x22C8, 0x2308, 0x2348, 0x23A8,
0x23E8, 0x2448, 0x24A8, 0x24E8,
0x2548, 0x25A8, 0x2608, 0x2668,
0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */
0x2847, 0x28C7, 0x2947, 0x29A7,
0x2A27, 0x2AC7, 0x2B47, 0x2BE7,
0x2CA7, 0x2D67, 0x2E47, 0x2F67,
0x3247, 0x3526, 0x3646, 0x3726, /* 128 */
0x3806, 0x38A6, 0x3946, 0x39E6,
0x3A66, 0x3AE6, 0x3B66, 0x3BC6,
0x3C45, 0x3CA5, 0x3D05, 0x3D85,
0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */
0x3F45, 0x3FA5, 0x4005, 0x4045,
0x40A5, 0x40E5, 0x4145, 0x4185,
0x41E5, 0x4225, 0x4265, 0x42C5,
0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */
0x4424, 0x4464, 0x44C4, 0x4504,
0x4544, 0x4584, 0x45C4, 0x4604,
0x4644, 0x46A4, 0x46E4, 0x4724,
0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */
0x4864, 0x48A4, 0x48E4, 0x4924,
0x4964, 0x49A4, 0x49E4, 0x4A24,
0x4A64, 0x4AA4, 0x4AE4, 0x4B23,
0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */
0x4C63, 0x4CA3, 0x4CE3, 0x4D23,
0x4D63, 0x4DA3, 0x4DE3, 0x4E23,
0x4E63, 0x4EA3, 0x4EE3, 0x4F23,
0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */
0x5083, 0x50C3, 0x5103, 0x5143,
0x5183, 0x51E2, 0x5222, 0x5262,
0x52A2, 0x52E2, 0x5342, 0x5382,
0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */
0x5502, 0x5542, 0x55A2, 0x55E2,
0x5642, 0x5682, 0x56E2, 0x5722,
0x5782, 0x57E1, 0x5841, 0x58A1,
0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */
0x5AA1, 0x5B01, 0x5B81, 0x5BE1,
0x5C61, 0x5D01, 0x5D80, 0x5E20,
0x5EE0, 0x5FA0, 0x6080, 0x61C0,
};
const u16 b43_tab_noisea2[] = {
0x0001, 0x0001, 0x0001, 0xFFFE,
0xFFFE, 0x3FFF, 0x1000, 0x0393,
};
const u16 b43_tab_noisea3[] = {
0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
};
const u16 b43_tab_noiseg1[] = {
0x013C, 0x01F5, 0x031A, 0x0631,
0x0001, 0x0001, 0x0001, 0x0001,
};
const u16 b43_tab_noiseg2[] = {
0x5484, 0x3C40, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
};
const u16 b43_tab_noisescaleg1[] = {
0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */
0x2F2D, 0x2A2A, 0x2527, 0x1F21,
0x1A1D, 0x1719, 0x1616, 0x1414,
0x1414, 0x1400, 0x1414, 0x1614,
0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */
0x2A27, 0x2F2A, 0x332D, 0x3B35,
0x5140, 0x6C62, 0x0077,
};
const u16 b43_tab_noisescaleg2[] = {
0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */
0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
0x969B, 0x9195, 0x8F8F, 0x8A8A,
0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */
0xADA9, 0xB2AD, 0xB6B0, 0xBCB7,
0xCBC0, 0xD8D4, 0x00DD,
};
const u16 b43_tab_noisescaleg3[] = {
0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */
0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
0xA4A4, 0xA400, 0xA4A4, 0xA4A4,
0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */
0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
0xA4A4, 0xA4A4, 0x00A4,
};
const u16 b43_tab_sigmasqr1[] = {
0x007A, 0x0075, 0x0071, 0x006C, /* 0 */
0x0067, 0x0063, 0x005E, 0x0059,
0x0054, 0x0050, 0x004B, 0x0046,
0x0042, 0x003D, 0x003D, 0x003D,
0x003D, 0x003D, 0x003D, 0x003D, /* 16 */
0x003D, 0x003D, 0x003D, 0x003D,
0x003D, 0x003D, 0x0000, 0x003D,
0x003D, 0x003D, 0x003D, 0x003D,
0x003D, 0x003D, 0x003D, 0x003D, /* 32 */
0x003D, 0x003D, 0x003D, 0x003D,
0x0042, 0x0046, 0x004B, 0x0050,
0x0054, 0x0059, 0x005E, 0x0063,
0x0067, 0x006C, 0x0071, 0x0075, /* 48 */
0x007A,
};
const u16 b43_tab_sigmasqr2[] = {
0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */
0x00D6, 0x00D4, 0x00D2, 0x00CF,
0x00CD, 0x00CA, 0x00C7, 0x00C4,
0x00C1, 0x00BE, 0x00BE, 0x00BE,
0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */
0x00BE, 0x00BE, 0x00BE, 0x00BE,
0x00BE, 0x00BE, 0x0000, 0x00BE,
0x00BE, 0x00BE, 0x00BE, 0x00BE,
0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */
0x00BE, 0x00BE, 0x00BE, 0x00BE,
0x00C1, 0x00C4, 0x00C7, 0x00CA,
0x00CD, 0x00CF, 0x00D2, 0x00D4,
0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */
0x00DE,
};
static inline void assert_sizes(void)
{
BUILD_BUG_ON(B43_TAB_ROTOR_SIZE != ARRAY_SIZE(b43_tab_rotor));
BUILD_BUG_ON(B43_TAB_RETARD_SIZE != ARRAY_SIZE(b43_tab_retard));
BUILD_BUG_ON(B43_TAB_FINEFREQA_SIZE != ARRAY_SIZE(b43_tab_finefreqa));
BUILD_BUG_ON(B43_TAB_FINEFREQG_SIZE != ARRAY_SIZE(b43_tab_finefreqg));
BUILD_BUG_ON(B43_TAB_NOISEA2_SIZE != ARRAY_SIZE(b43_tab_noisea2));
BUILD_BUG_ON(B43_TAB_NOISEA3_SIZE != ARRAY_SIZE(b43_tab_noisea3));
BUILD_BUG_ON(B43_TAB_NOISEG1_SIZE != ARRAY_SIZE(b43_tab_noiseg1));
BUILD_BUG_ON(B43_TAB_NOISEG2_SIZE != ARRAY_SIZE(b43_tab_noiseg2));
BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
ARRAY_SIZE(b43_tab_noisescaleg1));
BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
ARRAY_SIZE(b43_tab_noisescaleg2));
BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
ARRAY_SIZE(b43_tab_noisescaleg3));
BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr1));
BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr2));
}
u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset)
{
assert_sizes();
b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
return b43_phy_read(dev, B43_PHY_OTABLEI);
}
void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
u16 offset, u16 value)
{
b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
b43_phy_write(dev, B43_PHY_OTABLEI, value);
}
u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
{
u32 ret;
b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
ret = b43_phy_read(dev, B43_PHY_OTABLEQ);
ret <<= 16;
ret |= b43_phy_read(dev, B43_PHY_OTABLEI);
return ret;
}
void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
u16 offset, u32 value)
{
b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
b43_phy_write(dev, B43_PHY_OTABLEI, value);
b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16));
}
u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset)
{
b43_phy_write(dev, B43_PHY_GTABCTL, table + offset);
return b43_phy_read(dev, B43_PHY_GTABDATA);
}
void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value)
{
b43_phy_write(dev, B43_PHY_GTABCTL, table + offset);
b43_phy_write(dev, B43_PHY_GTABDATA, value);
}

View file

@ -0,0 +1,28 @@
#ifndef B43_TABLES_H_
#define B43_TABLES_H_
#define B43_TAB_ROTOR_SIZE 53
extern const u32 b43_tab_rotor[];
#define B43_TAB_RETARD_SIZE 53
extern const u32 b43_tab_retard[];
#define B43_TAB_FINEFREQA_SIZE 256
extern const u16 b43_tab_finefreqa[];
#define B43_TAB_FINEFREQG_SIZE 256
extern const u16 b43_tab_finefreqg[];
#define B43_TAB_NOISEA2_SIZE 8
extern const u16 b43_tab_noisea2[];
#define B43_TAB_NOISEA3_SIZE 8
extern const u16 b43_tab_noisea3[];
#define B43_TAB_NOISEG1_SIZE 8
extern const u16 b43_tab_noiseg1[];
#define B43_TAB_NOISEG2_SIZE 8
extern const u16 b43_tab_noiseg2[];
#define B43_TAB_NOISESCALEG_SIZE 27
extern const u16 b43_tab_noisescaleg1[];
extern const u16 b43_tab_noisescaleg2[];
extern const u16 b43_tab_noisescaleg3[];
#define B43_TAB_SIGMASQR_SIZE 53
extern const u16 b43_tab_sigmasqr1[];
extern const u16 b43_tab_sigmasqr2[];
#endif /* B43_TABLES_H_ */

View file

@ -0,0 +1,648 @@
/*
Broadcom B43 wireless driver
Transmission (TX/RX) related functions.
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>
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 "xmit.h"
#include "phy.h"
#include "dma.h"
#include "pio.h"
/* Extract the bitrate out of a CCK PLCP header. */
static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp)
{
switch (plcp->raw[0]) {
case 0x0A:
return B43_CCK_RATE_1MB;
case 0x14:
return B43_CCK_RATE_2MB;
case 0x37:
return B43_CCK_RATE_5MB;
case 0x6E:
return B43_CCK_RATE_11MB;
}
B43_WARN_ON(1);
return 0;
}
/* Extract the bitrate out of an OFDM PLCP header. */
static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp)
{
switch (plcp->raw[0] & 0xF) {
case 0xB:
return B43_OFDM_RATE_6MB;
case 0xF:
return B43_OFDM_RATE_9MB;
case 0xA:
return B43_OFDM_RATE_12MB;
case 0xE:
return B43_OFDM_RATE_18MB;
case 0x9:
return B43_OFDM_RATE_24MB;
case 0xD:
return B43_OFDM_RATE_36MB;
case 0x8:
return B43_OFDM_RATE_48MB;
case 0xC:
return B43_OFDM_RATE_54MB;
}
B43_WARN_ON(1);
return 0;
}
u8 b43_plcp_get_ratecode_cck(const u8 bitrate)
{
switch (bitrate) {
case B43_CCK_RATE_1MB:
return 0x0A;
case B43_CCK_RATE_2MB:
return 0x14;
case B43_CCK_RATE_5MB:
return 0x37;
case B43_CCK_RATE_11MB:
return 0x6E;
}
B43_WARN_ON(1);
return 0;
}
u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate)
{
switch (bitrate) {
case B43_OFDM_RATE_6MB:
return 0xB;
case B43_OFDM_RATE_9MB:
return 0xF;
case B43_OFDM_RATE_12MB:
return 0xA;
case B43_OFDM_RATE_18MB:
return 0xE;
case B43_OFDM_RATE_24MB:
return 0x9;
case B43_OFDM_RATE_36MB:
return 0xD;
case B43_OFDM_RATE_48MB:
return 0x8;
case B43_OFDM_RATE_54MB:
return 0xC;
}
B43_WARN_ON(1);
return 0;
}
void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
const u16 octets, const u8 bitrate)
{
__le32 *data = &(plcp->data);
__u8 *raw = plcp->raw;
if (b43_is_ofdm_rate(bitrate)) {
*data = b43_plcp_get_ratecode_ofdm(bitrate);
B43_WARN_ON(octets & 0xF000);
*data |= (octets << 5);
*data = cpu_to_le32(*data);
} else {
u32 plen;
plen = octets * 16 / bitrate;
if ((octets * 16 % bitrate) > 0) {
plen++;
if ((bitrate == B43_CCK_RATE_11MB)
&& ((octets * 8 % 11) < 4)) {
raw[1] = 0x84;
} else
raw[1] = 0x04;
} else
raw[1] = 0x04;
*data |= cpu_to_le32(plen << 16);
raw[0] = b43_plcp_get_ratecode_cck(bitrate);
}
}
static u8 b43_calc_fallback_rate(u8 bitrate)
{
switch (bitrate) {
case B43_CCK_RATE_1MB:
return B43_CCK_RATE_1MB;
case B43_CCK_RATE_2MB:
return B43_CCK_RATE_1MB;
case B43_CCK_RATE_5MB:
return B43_CCK_RATE_2MB;
case B43_CCK_RATE_11MB:
return B43_CCK_RATE_5MB;
case B43_OFDM_RATE_6MB:
return B43_CCK_RATE_5MB;
case B43_OFDM_RATE_9MB:
return B43_OFDM_RATE_6MB;
case B43_OFDM_RATE_12MB:
return B43_OFDM_RATE_9MB;
case B43_OFDM_RATE_18MB:
return B43_OFDM_RATE_12MB;
case B43_OFDM_RATE_24MB:
return B43_OFDM_RATE_18MB;
case B43_OFDM_RATE_36MB:
return B43_OFDM_RATE_24MB;
case B43_OFDM_RATE_48MB:
return B43_OFDM_RATE_36MB;
case B43_OFDM_RATE_54MB:
return B43_OFDM_RATE_48MB;
}
B43_WARN_ON(1);
return 0;
}
static void generate_txhdr_fw4(struct b43_wldev *dev,
struct b43_txhdr_fw4 *txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
const struct ieee80211_tx_control *txctl,
u16 cookie)
{
const struct b43_phy *phy = &dev->phy;
const struct ieee80211_hdr *wlhdr =
(const struct ieee80211_hdr *)fragment_data;
int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
u16 fctl = le16_to_cpu(wlhdr->frame_control);
u8 rate, rate_fb;
int rate_ofdm, rate_fb_ofdm;
unsigned int plcp_fragment_len;
u32 mac_ctl = 0;
u16 phy_ctl = 0;
u8 extra_ft = 0;
memset(txhdr, 0, sizeof(*txhdr));
rate = txctl->tx_rate;
rate_ofdm = b43_is_ofdm_rate(rate);
rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
if (rate_ofdm)
txhdr->phy_rate = b43_plcp_get_ratecode_ofdm(rate);
else
txhdr->phy_rate = b43_plcp_get_ratecode_cck(rate);
txhdr->mac_frame_ctl = wlhdr->frame_control;
memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
/* Calculate duration for fallback rate */
if ((rate_fb == rate) ||
(wlhdr->duration_id & cpu_to_le16(0x8000)) ||
(wlhdr->duration_id == cpu_to_le16(0))) {
/* If the fallback rate equals the normal rate or the
* dur_id field contains an AID, CFP magic or 0,
* use the original dur_id field. */
txhdr->dur_fb = wlhdr->duration_id;
} else {
int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb);
txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
dev->wl->if_id,
fragment_len,
fbrate_base100kbps);
}
plcp_fragment_len = fragment_len + FCS_LEN;
if (use_encryption) {
u8 key_idx = (u16) (txctl->key_idx);
struct b43_key *key;
int wlhdr_len;
size_t iv_len;
B43_WARN_ON(key_idx >= dev->max_nr_keys);
key = &(dev->key[key_idx]);
B43_WARN_ON(!key->keyconf);
/* Hardware appends ICV. */
plcp_fragment_len += txctl->icv_len;
key_idx = b43_kidx_to_fw(dev, key_idx);
mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) &
B43_TX4_MAC_KEYIDX;
mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) &
B43_TX4_MAC_KEYALG;
wlhdr_len = ieee80211_get_hdrlen(fctl);
iv_len = min((size_t) txctl->iv_len,
ARRAY_SIZE(txhdr->iv));
memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
}
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp),
plcp_fragment_len, rate);
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
plcp_fragment_len, rate_fb);
/* Extra Frame Types */
if (rate_fb_ofdm)
extra_ft |= B43_TX4_EFT_FBOFDM;
/* Set channel radio code. Note that the micrcode ORs 0x100 to
* this value before comparing it to the value in SHM, if this
* is a 5Ghz packet.
*/
txhdr->chan_radio_code = phy->channel;
/* PHY TX Control word */
if (rate_ofdm)
phy_ctl |= B43_TX4_PHY_OFDM;
if (dev->short_preamble)
phy_ctl |= B43_TX4_PHY_SHORTPRMBL;
switch (txctl->antenna_sel_tx) {
case 0:
phy_ctl |= B43_TX4_PHY_ANTLAST;
break;
case 1:
phy_ctl |= B43_TX4_PHY_ANT0;
break;
case 2:
phy_ctl |= B43_TX4_PHY_ANT1;
break;
default:
B43_WARN_ON(1);
}
/* MAC control */
if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
mac_ctl |= B43_TX4_MAC_ACK;
if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
mac_ctl |= B43_TX4_MAC_HWSEQ;
if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
mac_ctl |= B43_TX4_MAC_STMSDU;
if (phy->type == B43_PHYTYPE_A)
mac_ctl |= B43_TX4_MAC_5GHZ;
/* Generate the RTS or CTS-to-self frame */
if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
(txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
unsigned int len;
struct ieee80211_hdr *hdr;
int rts_rate, rts_rate_fb;
int rts_rate_ofdm, rts_rate_fb_ofdm;
rts_rate = txctl->rts_cts_rate;
rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
rts_rate_fb = b43_calc_fallback_rate(rts_rate);
rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id,
fragment_data, fragment_len,
txctl,
(struct ieee80211_cts *)(txhdr->
rts_frame));
mac_ctl |= B43_TX4_MAC_SENDCTS;
len = sizeof(struct ieee80211_cts);
} else {
ieee80211_rts_get(dev->wl->hw, dev->wl->if_id,
fragment_data, fragment_len, txctl,
(struct ieee80211_rts *)(txhdr->
rts_frame));
mac_ctl |= B43_TX4_MAC_SENDRTS;
len = sizeof(struct ieee80211_rts);
}
len += FCS_LEN;
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
rts_plcp), len,
rts_rate);
b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
rts_plcp_fb),
len, rts_rate_fb);
hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
txhdr->rts_dur_fb = hdr->duration_id;
if (rts_rate_ofdm) {
extra_ft |= B43_TX4_EFT_RTSOFDM;
txhdr->phy_rate_rts =
b43_plcp_get_ratecode_ofdm(rts_rate);
} else
txhdr->phy_rate_rts =
b43_plcp_get_ratecode_cck(rts_rate);
if (rts_rate_fb_ofdm)
extra_ft |= B43_TX4_EFT_RTSFBOFDM;
mac_ctl |= B43_TX4_MAC_LONGFRAME;
}
/* Magic cookie */
txhdr->cookie = cpu_to_le16(cookie);
/* Apply the bitfields */
txhdr->mac_ctl = cpu_to_le32(mac_ctl);
txhdr->phy_ctl = cpu_to_le16(phy_ctl);
txhdr->extra_ft = extra_ft;
}
void b43_generate_txhdr(struct b43_wldev *dev,
u8 * txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
const struct ieee80211_tx_control *txctl, u16 cookie)
{
generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr,
fragment_data, fragment_len, txctl, cookie);
}
static s8 b43_rssi_postprocess(struct b43_wldev *dev,
u8 in_rssi, int ofdm,
int adjust_2053, int adjust_2050)
{
struct b43_phy *phy = &dev->phy;
s32 tmp;
switch (phy->radio_ver) {
case 0x2050:
if (ofdm) {
tmp = in_rssi;
if (tmp > 127)
tmp -= 256;
tmp *= 73;
tmp /= 64;
if (adjust_2050)
tmp += 25;
else
tmp -= 3;
} else {
if (dev->dev->bus->sprom.r1.
boardflags_lo & B43_BFL_RSSI) {
if (in_rssi > 63)
in_rssi = 63;
tmp = phy->nrssi_lt[in_rssi];
tmp = 31 - tmp;
tmp *= -131;
tmp /= 128;
tmp -= 57;
} else {
tmp = in_rssi;
tmp = 31 - tmp;
tmp *= -149;
tmp /= 128;
tmp -= 68;
}
if (phy->type == B43_PHYTYPE_G && adjust_2050)
tmp += 25;
}
break;
case 0x2060:
if (in_rssi > 127)
tmp = in_rssi - 256;
else
tmp = in_rssi;
break;
default:
tmp = in_rssi;
tmp -= 11;
tmp *= 103;
tmp /= 64;
if (adjust_2053)
tmp -= 109;
else
tmp -= 83;
}
return (s8) tmp;
}
//TODO
#if 0
static s8 b43_rssinoise_postprocess(struct b43_wldev *dev, u8 in_rssi)
{
struct b43_phy *phy = &dev->phy;
s8 ret;
if (phy->type == B43_PHYTYPE_A) {
//TODO: Incomplete specs.
ret = 0;
} else
ret = b43_rssi_postprocess(dev, in_rssi, 0, 1, 1);
return ret;
}
#endif
void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
{
struct ieee80211_rx_status status;
struct b43_plcp_hdr6 *plcp;
struct ieee80211_hdr *wlhdr;
const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
u16 fctl;
u16 phystat0, phystat3, chanstat, mactime;
u32 macstat;
u16 chanid;
u8 jssi;
int padding;
memset(&status, 0, sizeof(status));
/* Get metadata about the frame from the header. */
phystat0 = le16_to_cpu(rxhdr->phy_status0);
phystat3 = le16_to_cpu(rxhdr->phy_status3);
jssi = rxhdr->jssi;
macstat = le32_to_cpu(rxhdr->mac_status);
mactime = le16_to_cpu(rxhdr->mac_time);
chanstat = le16_to_cpu(rxhdr->channel);
if (macstat & B43_RX_MAC_FCSERR)
dev->wl->ieee_stats.dot11FCSErrorCount++;
if (macstat & B43_RX_MAC_DECERR) {
/* Decryption with the given key failed.
* Drop the packet. We also won't be able to decrypt it with
* the key in software. */
goto drop;
}
/* Skip PLCP and padding */
padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0;
if (unlikely(skb->len < (sizeof(struct b43_plcp_hdr6) + padding))) {
b43dbg(dev->wl, "RX: Packet size underrun (1)\n");
goto drop;
}
plcp = (struct b43_plcp_hdr6 *)(skb->data + padding);
skb_pull(skb, sizeof(struct b43_plcp_hdr6) + padding);
/* The skb contains the Wireless Header + payload data now */
if (unlikely(skb->len < (2 + 2 + 6 /*minimum hdr */ + FCS_LEN))) {
b43dbg(dev->wl, "RX: Packet size underrun (2)\n");
goto drop;
}
wlhdr = (struct ieee80211_hdr *)(skb->data);
fctl = le16_to_cpu(wlhdr->frame_control);
skb_trim(skb, skb->len - FCS_LEN);
if (macstat & B43_RX_MAC_DEC) {
unsigned int keyidx;
int wlhdr_len;
keyidx = ((macstat & B43_RX_MAC_KEYIDX)
>> B43_RX_MAC_KEYIDX_SHIFT);
/* We must adjust the key index here. We want the "physical"
* key index, but the ucode passed it slightly different.
*/
keyidx = b43_kidx_to_raw(dev, keyidx);
B43_WARN_ON(keyidx >= dev->max_nr_keys);
if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) {
wlhdr_len = ieee80211_get_hdrlen(fctl);
if (unlikely(skb->len < (wlhdr_len + 3))) {
b43dbg(dev->wl,
"RX: Packet size underrun (3)\n");
goto drop;
}
status.flag |= RX_FLAG_DECRYPTED;
}
}
status.ssi = b43_rssi_postprocess(dev, jssi,
(phystat0 & B43_RX_PHYST0_OFDM),
(phystat0 & B43_RX_PHYST0_GAINCTL),
(phystat3 & B43_RX_PHYST3_TRSTATE));
status.noise = dev->stats.link_noise;
/* the next line looks wrong, but is what mac80211 wants */
status.signal = (jssi * 100) / B43_RX_MAX_SSI;
if (phystat0 & B43_RX_PHYST0_OFDM)
status.rate = b43_plcp_get_bitrate_ofdm(plcp);
else
status.rate = b43_plcp_get_bitrate_cck(plcp);
status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
status.mactime = mactime;
chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
switch (chanstat & B43_RX_CHAN_PHYTYPE) {
case B43_PHYTYPE_A:
status.phymode = MODE_IEEE80211A;
status.freq = chanid;
status.channel = b43_freq_to_channel_a(chanid);
break;
case B43_PHYTYPE_B:
status.phymode = MODE_IEEE80211B;
status.freq = chanid + 2400;
status.channel = b43_freq_to_channel_bg(chanid + 2400);
break;
case B43_PHYTYPE_G:
status.phymode = MODE_IEEE80211G;
status.freq = chanid + 2400;
status.channel = b43_freq_to_channel_bg(chanid + 2400);
break;
default:
B43_WARN_ON(1);
}
dev->stats.last_rx = jiffies;
ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
return;
drop:
b43dbg(dev->wl, "RX: Packet dropped\n");
dev_kfree_skb_any(skb);
}
void b43_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status)
{
b43_debugfs_log_txstat(dev, status);
if (status->intermediate)
return;
if (status->for_ampdu)
return;
if (!status->acked)
dev->wl->ieee_stats.dot11ACKFailureCount++;
if (status->rts_count) {
if (status->rts_count == 0xF) //FIXME
dev->wl->ieee_stats.dot11RTSFailureCount++;
else
dev->wl->ieee_stats.dot11RTSSuccessCount++;
}
if (b43_using_pio(dev))
b43_pio_handle_txstatus(dev, status);
else
b43_dma_handle_txstatus(dev, status);
}
/* Handle TX status report as received through DMA/PIO queues */
void b43_handle_hwtxstatus(struct b43_wldev *dev,
const struct b43_hwtxstatus *hw)
{
struct b43_txstatus status;
u8 tmp;
status.cookie = le16_to_cpu(hw->cookie);
status.seq = le16_to_cpu(hw->seq);
status.phy_stat = hw->phy_stat;
tmp = hw->count;
status.frame_count = (tmp >> 4);
status.rts_count = (tmp & 0x0F);
tmp = hw->flags;
status.supp_reason = ((tmp & 0x1C) >> 2);
status.pm_indicated = !!(tmp & 0x80);
status.intermediate = !!(tmp & 0x40);
status.for_ampdu = !!(tmp & 0x20);
status.acked = !!(tmp & 0x02);
b43_handle_txstatus(dev, &status);
}
/* Stop any TX operation on the device (suspend the hardware queues) */
void b43_tx_suspend(struct b43_wldev *dev)
{
if (b43_using_pio(dev))
b43_pio_freeze_txqueues(dev);
else
b43_dma_tx_suspend(dev);
}
/* Resume any TX operation on the device (resume the hardware queues) */
void b43_tx_resume(struct b43_wldev *dev)
{
if (b43_using_pio(dev))
b43_pio_thaw_txqueues(dev);
else
b43_dma_tx_resume(dev);
}
#if 0
static void upload_qos_parms(struct b43_wldev *dev,
const u16 * parms, u16 offset)
{
int i;
for (i = 0; i < B43_NR_QOSPARMS; i++) {
b43_shm_write16(dev, B43_SHM_SHARED,
offset + (i * 2), parms[i]);
}
}
#endif
/* Initialize the QoS parameters */
void b43_qos_init(struct b43_wldev *dev)
{
/* FIXME: This function must probably be called from the mac80211
* config callback. */
return;
b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
//FIXME kill magic
b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4);
/*TODO: We might need some stack support here to get the values. */
}

View file

@ -0,0 +1,250 @@
#ifndef B43_XMIT_H_
#define B43_XMIT_H_
#include "main.h"
#define _b43_declare_plcp_hdr(size) \
struct b43_plcp_hdr##size { \
union { \
__le32 data; \
__u8 raw[size]; \
} __attribute__((__packed__)); \
} __attribute__((__packed__))
/* struct b43_plcp_hdr4 */
_b43_declare_plcp_hdr(4);
/* struct b43_plcp_hdr6 */
_b43_declare_plcp_hdr(6);
#undef _b43_declare_plcp_hdr
/* TX header for v4 firmware */
struct b43_txhdr_fw4 {
__le32 mac_ctl; /* MAC TX control */
__le16 mac_frame_ctl; /* Copy of the FrameControl field */
__le16 tx_fes_time_norm; /* TX FES Time Normal */
__le16 phy_ctl; /* PHY TX control */
__le16 phy_ctl_0; /* Unused */
__le16 phy_ctl_1; /* Unused */
__le16 phy_ctl_rts_0; /* Unused */
__le16 phy_ctl_rts_1; /* Unused */
__u8 phy_rate; /* PHY rate */
__u8 phy_rate_rts; /* PHY rate for RTS/CTS */
__u8 extra_ft; /* Extra Frame Types */
__u8 chan_radio_code; /* Channel Radio Code */
__u8 iv[16]; /* Encryption IV */
__u8 tx_receiver[6]; /* TX Frame Receiver address */
__le16 tx_fes_time_fb; /* TX FES Time Fallback */
struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP */
__le16 rts_dur_fb; /* RTS fallback duration */
struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP */
__le16 dur_fb; /* Fallback duration */
__le16 mm_dur_time; /* Unused */
__le16 mm_dur_time_fb; /* Unused */
__le32 time_stamp; /* Timestamp */
PAD_BYTES(2);
__le16 cookie; /* TX frame cookie */
__le16 tx_status; /* TX status */
struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP */
__u8 rts_frame[16]; /* The RTS frame (if used) */
PAD_BYTES(2);
struct b43_plcp_hdr6 plcp; /* Main PLCP */
} __attribute__ ((__packed__));
/* MAC TX control */
#define B43_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */
#define B43_TX4_MAC_KEYIDX_SHIFT 20
#define B43_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */
#define B43_TX4_MAC_KEYALG_SHIFT 16
#define B43_TX4_MAC_LIFETIME 0x00001000
#define B43_TX4_MAC_FRAMEBURST 0x00000800
#define B43_TX4_MAC_SENDCTS 0x00000400
#define B43_TX4_MAC_AMPDU 0x00000300
#define B43_TX4_MAC_AMPDU_SHIFT 8
#define B43_TX4_MAC_5GHZ 0x00000080
#define B43_TX4_MAC_IGNPMQ 0x00000020
#define B43_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */
#define B43_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */
#define B43_TX4_MAC_SENDRTS 0x00000004
#define B43_TX4_MAC_LONGFRAME 0x00000002
#define B43_TX4_MAC_ACK 0x00000001
/* Extra Frame Types */
#define B43_TX4_EFT_FBOFDM 0x0001 /* Data frame fallback rate type */
#define B43_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */
#define B43_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */
/* PHY TX control word */
#define B43_TX4_PHY_OFDM 0x0001 /* Data frame rate type */
#define B43_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
#define B43_TX4_PHY_ANT 0x03C0 /* Antenna selection */
#define B43_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */
#define B43_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */
#define B43_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */
void b43_generate_txhdr(struct b43_wldev *dev,
u8 * txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
const struct ieee80211_tx_control *txctl, u16 cookie);
/* Transmit Status */
struct b43_txstatus {
u16 cookie; /* The cookie from the txhdr */
u16 seq; /* Sequence number */
u8 phy_stat; /* PHY TX status */
u8 frame_count; /* Frame transmit count */
u8 rts_count; /* RTS transmit count */
u8 supp_reason; /* Suppression reason */
/* flags */
u8 pm_indicated; /* PM mode indicated to AP */
u8 intermediate; /* Intermediate status notification (not final) */
u8 for_ampdu; /* Status is for an AMPDU (afterburner) */
u8 acked; /* Wireless ACK received */
};
/* txstatus supp_reason values */
enum {
B43_TXST_SUPP_NONE, /* Not suppressed */
B43_TXST_SUPP_PMQ, /* Suppressed due to PMQ entry */
B43_TXST_SUPP_FLUSH, /* Suppressed due to flush request */
B43_TXST_SUPP_PREV, /* Previous fragment failed */
B43_TXST_SUPP_CHAN, /* Channel mismatch */
B43_TXST_SUPP_LIFE, /* Lifetime expired */
B43_TXST_SUPP_UNDER, /* Buffer underflow */
B43_TXST_SUPP_ABNACK, /* Afterburner NACK */
};
/* Transmit Status as received through DMA/PIO on old chips */
struct b43_hwtxstatus {
PAD_BYTES(4);
__le16 cookie;
u8 flags;
u8 count;
PAD_BYTES(2);
__le16 seq;
u8 phy_stat;
PAD_BYTES(1);
} __attribute__ ((__packed__));
/* Receive header for v4 firmware. */
struct b43_rxhdr_fw4 {
__le16 frame_len; /* Frame length */
PAD_BYTES(2);
__le16 phy_status0; /* PHY RX Status 0 */
__u8 jssi; /* PHY RX Status 1: JSSI */
__u8 sig_qual; /* PHY RX Status 1: Signal Quality */
__le16 phy_status2; /* PHY RX Status 2 */
__le16 phy_status3; /* PHY RX Status 3 */
__le32 mac_status; /* MAC RX status */
__le16 mac_time;
__le16 channel;
} __attribute__ ((__packed__));
/* PHY RX Status 0 */
#define B43_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */
#define B43_RX_PHYST0_PLCPHCF 0x0200
#define B43_RX_PHYST0_PLCPFV 0x0100
#define B43_RX_PHYST0_SHORTPRMBL 0x0080 /* Received with Short Preamble */
#define B43_RX_PHYST0_LCRS 0x0040
#define B43_RX_PHYST0_ANT 0x0020 /* Antenna */
#define B43_RX_PHYST0_UNSRATE 0x0010
#define B43_RX_PHYST0_CLIP 0x000C
#define B43_RX_PHYST0_CLIP_SHIFT 2
#define B43_RX_PHYST0_FTYPE 0x0003 /* Frame type */
#define B43_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */
#define B43_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */
#define B43_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */
#define B43_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */
/* PHY RX Status 2 */
#define B43_RX_PHYST2_LNAG 0xC000 /* LNA Gain */
#define B43_RX_PHYST2_LNAG_SHIFT 14
#define B43_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */
#define B43_RX_PHYST2_PNAG_SHIFT 10
#define B43_RX_PHYST2_FOFF 0x03FF /* F offset */
/* PHY RX Status 3 */
#define B43_RX_PHYST3_DIGG 0x1800 /* DIG Gain */
#define B43_RX_PHYST3_DIGG_SHIFT 11
#define B43_RX_PHYST3_TRSTATE 0x0400 /* TR state */
/* MAC RX Status */
#define B43_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */
#define B43_RX_MAC_KEYIDX 0x000007E0 /* Key index */
#define B43_RX_MAC_KEYIDX_SHIFT 5
#define B43_RX_MAC_DECERR 0x00000010 /* Decrypt error */
#define B43_RX_MAC_DEC 0x00000008 /* Decryption attempted */
#define B43_RX_MAC_PADDING 0x00000004 /* Pad bytes present */
#define B43_RX_MAC_RESP 0x00000002 /* Response frame transmitted */
#define B43_RX_MAC_FCSERR 0x00000001 /* FCS error */
/* RX channel */
#define B43_RX_CHAN_GAIN 0xFC00 /* Gain */
#define B43_RX_CHAN_GAIN_SHIFT 10
#define B43_RX_CHAN_ID 0x03FC /* Channel ID */
#define B43_RX_CHAN_ID_SHIFT 2
#define B43_RX_CHAN_PHYTYPE 0x0003 /* PHY type */
u8 b43_plcp_get_ratecode_cck(const u8 bitrate);
u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate);
void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
const u16 octets, const u8 bitrate);
void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr);
void b43_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status);
void b43_handle_hwtxstatus(struct b43_wldev *dev,
const struct b43_hwtxstatus *hw);
void b43_tx_suspend(struct b43_wldev *dev);
void b43_tx_resume(struct b43_wldev *dev);
#define B43_NR_QOSPARMS 22
enum {
B43_QOSPARM_TXOP = 0,
B43_QOSPARM_CWMIN,
B43_QOSPARM_CWMAX,
B43_QOSPARM_CWCUR,
B43_QOSPARM_AIFS,
B43_QOSPARM_BSLOTS,
B43_QOSPARM_REGGAP,
B43_QOSPARM_STATUS,
};
void b43_qos_init(struct b43_wldev *dev);
/* Helper functions for converting the key-table index from "firmware-format"
* to "raw-format" and back. The firmware API changed for this at some revision.
* We need to account for that here. */
static inline int b43_new_kidx_api(struct b43_wldev *dev)
{
/* FIXME: Not sure the change was at rev 351 */
return (dev->fw.rev >= 351);
}
static inline u8 b43_kidx_to_fw(struct b43_wldev *dev, u8 raw_kidx)
{
u8 firmware_kidx;
if (b43_new_kidx_api(dev)) {
firmware_kidx = raw_kidx;
} else {
if (raw_kidx >= 4) /* Is per STA key? */
firmware_kidx = raw_kidx - 4;
else
firmware_kidx = raw_kidx; /* TX default key */
}
return firmware_kidx;
}
static inline u8 b43_kidx_to_raw(struct b43_wldev *dev, u8 firmware_kidx)
{
u8 raw_kidx;
if (b43_new_kidx_api(dev))
raw_kidx = firmware_kidx;
else
raw_kidx = firmware_kidx + 4; /* RX default keys or per STA keys */
return raw_kidx;
}
#endif /* B43_XMIT_H_ */