Commit e4d6b795 authored by Michael Buesch's avatar Michael Buesch Committed by David S. Miller

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

Signed-off-by: default avatarMichael Buesch <mb@bu3sch.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 61e115a5
......@@ -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
......
......@@ -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
......@@ -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
......
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
# 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
This diff is collapsed.
This diff is collapsed.
#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_ */
This diff is collapsed.
This diff is collapsed.
/*
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);
}
#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_ */
This diff is collapsed.
#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_ */
This diff is collapsed.
/*
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_ */
/*
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);
}
#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_ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#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_ */
This diff is collapsed.
#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_ */
This diff is collapsed.
#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_ */
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment