Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Conflicts: drivers/net/wireless/iwlwifi/iwl-rx.c
This commit is contained in:
@@ -61,11 +61,28 @@ config B43_PCMCIA
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config B43_SDIO
|
||||
bool "Broadcom 43xx SDIO device support (EXPERIMENTAL)"
|
||||
depends on B43 && SSB_SDIOHOST_POSSIBLE && EXPERIMENTAL
|
||||
select SSB_SDIOHOST
|
||||
---help---
|
||||
Broadcom 43xx device support for Soft-MAC SDIO devices.
|
||||
|
||||
With this config option you can drive Soft-MAC b43 cards with a
|
||||
Secure Digital I/O interface.
|
||||
This includes the WLAN daughter card found on the Nintendo Wii
|
||||
video game console.
|
||||
Note that this does not support Broadcom 43xx Full-MAC devices.
|
||||
|
||||
It's safe to select Y here, even if you don't have a B43 SDIO device.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
# Data transfers to the device via PIO
|
||||
# This is only needed on PCMCIA devices. All others can do DMA properly.
|
||||
# This is only needed on PCMCIA and SDIO devices. All others can do DMA properly.
|
||||
config B43_PIO
|
||||
bool
|
||||
depends on B43 && (B43_PCMCIA || B43_FORCE_PIO)
|
||||
depends on B43 && (B43_SDIO || B43_PCMCIA || B43_FORCE_PIO)
|
||||
select SSB_BLOCKIO
|
||||
default y
|
||||
|
||||
|
@@ -16,6 +16,7 @@ b43-$(CONFIG_B43_PIO) += pio.o
|
||||
b43-y += rfkill.o
|
||||
b43-$(CONFIG_B43_LEDS) += leds.o
|
||||
b43-$(CONFIG_B43_PCMCIA) += pcmcia.o
|
||||
b43-$(CONFIG_B43_SDIO) += sdio.o
|
||||
b43-$(CONFIG_B43_DEBUG) += debugfs.o
|
||||
|
||||
obj-$(CONFIG_B43) += b43.o
|
||||
|
@@ -629,13 +629,6 @@ struct b43_wl {
|
||||
* from the mac80211 subsystem. */
|
||||
u16 mac80211_initially_registered_queues;
|
||||
|
||||
/* R/W lock for data transmission.
|
||||
* Transmissions on 2+ queues can run concurrently, but somebody else
|
||||
* might sync with TX by write_lock_irqsave()'ing. */
|
||||
rwlock_t tx_lock;
|
||||
/* Lock for LEDs access. */
|
||||
spinlock_t leds_lock;
|
||||
|
||||
/* We can only have one operating interface (802.11 core)
|
||||
* at a time. General information about this interface follows.
|
||||
*/
|
||||
@@ -686,6 +679,9 @@ struct b43_wl {
|
||||
struct work_struct tx_work;
|
||||
/* Queue of packets to be transmitted. */
|
||||
struct sk_buff_head tx_queue;
|
||||
|
||||
/* The device LEDs. */
|
||||
struct b43_leds leds;
|
||||
};
|
||||
|
||||
/* The type of the firmware file. */
|
||||
@@ -768,13 +764,10 @@ struct b43_wldev {
|
||||
/* The device initialization status.
|
||||
* Use b43_status() to query. */
|
||||
atomic_t __init_status;
|
||||
/* Saved init status for handling suspend. */
|
||||
int suspend_init_status;
|
||||
|
||||
bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */
|
||||
bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */
|
||||
bool radio_hw_enable; /* saved state of radio hardware enabled state */
|
||||
bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */
|
||||
bool qos_enabled; /* TRUE, if QoS is used. */
|
||||
bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */
|
||||
|
||||
@@ -794,12 +787,6 @@ struct b43_wldev {
|
||||
/* Various statistics about the physical device. */
|
||||
struct b43_stats stats;
|
||||
|
||||
/* The device LEDs. */
|
||||
struct b43_led led_tx;
|
||||
struct b43_led led_rx;
|
||||
struct b43_led led_assoc;
|
||||
struct b43_led led_radio;
|
||||
|
||||
/* Reason code of the last interrupt. */
|
||||
u32 irq_reason;
|
||||
u32 dma_reason[6];
|
||||
@@ -830,6 +817,10 @@ struct b43_wldev {
|
||||
/* Debugging stuff follows. */
|
||||
#ifdef CONFIG_B43_DEBUG
|
||||
struct b43_dfsentry *dfsentry;
|
||||
unsigned int irq_count;
|
||||
unsigned int irq_bit_count[32];
|
||||
unsigned int tx_count;
|
||||
unsigned int rx_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@@ -689,6 +689,7 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev)
|
||||
add_dyn_dbg("debug_lo", B43_DBG_LO, 0);
|
||||
add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
|
||||
add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0);
|
||||
add_dyn_dbg("debug_verbose_stats", B43_DBG_VERBOSESTATS, 0);
|
||||
|
||||
#undef add_dyn_dbg
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ enum b43_dyndbg { /* Dynamic debugging features */
|
||||
B43_DBG_LO,
|
||||
B43_DBG_FIRMWARE,
|
||||
B43_DBG_KEYS,
|
||||
B43_DBG_VERBOSESTATS,
|
||||
__B43_NR_DYNDBG,
|
||||
};
|
||||
|
||||
|
@@ -1428,9 +1428,9 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
|
||||
ring->nr_failed_tx_packets++;
|
||||
ring->nr_total_packet_tries += status->frame_count;
|
||||
#endif /* DEBUG */
|
||||
ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
|
||||
ieee80211_tx_status(dev->wl->hw, meta->skb);
|
||||
|
||||
/* skb is freed by ieee80211_tx_status_irqsafe() */
|
||||
/* skb is freed by ieee80211_tx_status() */
|
||||
meta->skb = NULL;
|
||||
} else {
|
||||
/* No need to call free_descriptor_buffer here, as
|
||||
|
@@ -34,35 +34,75 @@
|
||||
static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index,
|
||||
bool activelow)
|
||||
{
|
||||
struct b43_wl *wl = dev->wl;
|
||||
unsigned long flags;
|
||||
u16 ctl;
|
||||
|
||||
spin_lock_irqsave(&wl->leds_lock, flags);
|
||||
ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
|
||||
if (activelow)
|
||||
ctl &= ~(1 << led_index);
|
||||
else
|
||||
ctl |= (1 << led_index);
|
||||
b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
|
||||
spin_unlock_irqrestore(&wl->leds_lock, flags);
|
||||
}
|
||||
|
||||
static void b43_led_turn_off(struct b43_wldev *dev, u8 led_index,
|
||||
bool activelow)
|
||||
{
|
||||
struct b43_wl *wl = dev->wl;
|
||||
unsigned long flags;
|
||||
u16 ctl;
|
||||
|
||||
spin_lock_irqsave(&wl->leds_lock, flags);
|
||||
ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
|
||||
if (activelow)
|
||||
ctl |= (1 << led_index);
|
||||
else
|
||||
ctl &= ~(1 << led_index);
|
||||
b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
|
||||
spin_unlock_irqrestore(&wl->leds_lock, flags);
|
||||
}
|
||||
|
||||
static void b43_led_update(struct b43_wldev *dev,
|
||||
struct b43_led *led)
|
||||
{
|
||||
bool radio_enabled;
|
||||
bool turn_on;
|
||||
|
||||
if (!led->wl)
|
||||
return;
|
||||
|
||||
radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable);
|
||||
|
||||
/* The led->state read is racy, but we don't care. In case we raced
|
||||
* with the brightness_set handler, we will be called again soon
|
||||
* to fixup our state. */
|
||||
if (radio_enabled)
|
||||
turn_on = atomic_read(&led->state) != LED_OFF;
|
||||
else
|
||||
turn_on = 0;
|
||||
if (turn_on == led->hw_state)
|
||||
return;
|
||||
led->hw_state = turn_on;
|
||||
|
||||
if (turn_on)
|
||||
b43_led_turn_on(dev, led->index, led->activelow);
|
||||
else
|
||||
b43_led_turn_off(dev, led->index, led->activelow);
|
||||
}
|
||||
|
||||
static void b43_leds_work(struct work_struct *work)
|
||||
{
|
||||
struct b43_leds *leds = container_of(work, struct b43_leds, work);
|
||||
struct b43_wl *wl = container_of(leds, struct b43_wl, leds);
|
||||
struct b43_wldev *dev;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
dev = wl->current_dev;
|
||||
if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED))
|
||||
goto out_unlock;
|
||||
|
||||
b43_led_update(dev, &wl->leds.led_tx);
|
||||
b43_led_update(dev, &wl->leds.led_rx);
|
||||
b43_led_update(dev, &wl->leds.led_radio);
|
||||
b43_led_update(dev, &wl->leds.led_assoc);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
/* Callback from the LED subsystem. */
|
||||
@@ -70,21 +110,12 @@ static void b43_led_brightness_set(struct led_classdev *led_dev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct b43_led *led = container_of(led_dev, struct b43_led, led_dev);
|
||||
struct b43_wldev *dev = led->dev;
|
||||
bool radio_enabled;
|
||||
struct b43_wl *wl = led->wl;
|
||||
|
||||
if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED))
|
||||
return;
|
||||
|
||||
/* Checking the radio-enabled status here is slightly racy,
|
||||
* but we want to avoid the locking overhead and we don't care
|
||||
* whether the LED has the wrong state for a second. */
|
||||
radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable);
|
||||
|
||||
if (brightness == LED_OFF || !radio_enabled)
|
||||
b43_led_turn_off(dev, led->index, led->activelow);
|
||||
else
|
||||
b43_led_turn_on(dev, led->index, led->activelow);
|
||||
if (likely(!wl->leds.stop)) {
|
||||
atomic_set(&led->state, brightness);
|
||||
ieee80211_queue_work(wl->hw, &wl->leds.work);
|
||||
}
|
||||
}
|
||||
|
||||
static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
|
||||
@@ -93,15 +124,15 @@ static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
|
||||
{
|
||||
int err;
|
||||
|
||||
b43_led_turn_off(dev, led_index, activelow);
|
||||
if (led->dev)
|
||||
if (led->wl)
|
||||
return -EEXIST;
|
||||
if (!default_trigger)
|
||||
return -EINVAL;
|
||||
led->dev = dev;
|
||||
led->wl = dev->wl;
|
||||
led->index = led_index;
|
||||
led->activelow = activelow;
|
||||
strncpy(led->name, name, sizeof(led->name));
|
||||
atomic_set(&led->state, 0);
|
||||
|
||||
led->led_dev.name = led->name;
|
||||
led->led_dev.default_trigger = default_trigger;
|
||||
@@ -110,19 +141,19 @@ static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
|
||||
err = led_classdev_register(dev->dev->dev, &led->led_dev);
|
||||
if (err) {
|
||||
b43warn(dev->wl, "LEDs: Failed to register %s\n", name);
|
||||
led->dev = NULL;
|
||||
led->wl = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void b43_unregister_led(struct b43_led *led)
|
||||
{
|
||||
if (!led->dev)
|
||||
if (!led->wl)
|
||||
return;
|
||||
led_classdev_unregister(&led->led_dev);
|
||||
b43_led_turn_off(led->dev, led->index, led->activelow);
|
||||
led->dev = NULL;
|
||||
led->wl = NULL;
|
||||
}
|
||||
|
||||
static void b43_map_led(struct b43_wldev *dev,
|
||||
@@ -137,24 +168,20 @@ static void b43_map_led(struct b43_wldev *dev,
|
||||
* generic LED triggers. */
|
||||
switch (behaviour) {
|
||||
case B43_LED_INACTIVE:
|
||||
break;
|
||||
case B43_LED_OFF:
|
||||
b43_led_turn_off(dev, led_index, activelow);
|
||||
break;
|
||||
case B43_LED_ON:
|
||||
b43_led_turn_on(dev, led_index, activelow);
|
||||
break;
|
||||
case B43_LED_ACTIVITY:
|
||||
case B43_LED_TRANSFER:
|
||||
case B43_LED_APTRANSFER:
|
||||
snprintf(name, sizeof(name),
|
||||
"b43-%s::tx", wiphy_name(hw->wiphy));
|
||||
b43_register_led(dev, &dev->led_tx, name,
|
||||
b43_register_led(dev, &dev->wl->leds.led_tx, name,
|
||||
ieee80211_get_tx_led_name(hw),
|
||||
led_index, activelow);
|
||||
snprintf(name, sizeof(name),
|
||||
"b43-%s::rx", wiphy_name(hw->wiphy));
|
||||
b43_register_led(dev, &dev->led_rx, name,
|
||||
b43_register_led(dev, &dev->wl->leds.led_rx, name,
|
||||
ieee80211_get_rx_led_name(hw),
|
||||
led_index, activelow);
|
||||
break;
|
||||
@@ -164,18 +191,15 @@ static void b43_map_led(struct b43_wldev *dev,
|
||||
case B43_LED_MODE_BG:
|
||||
snprintf(name, sizeof(name),
|
||||
"b43-%s::radio", wiphy_name(hw->wiphy));
|
||||
b43_register_led(dev, &dev->led_radio, name,
|
||||
b43_register_led(dev, &dev->wl->leds.led_radio, name,
|
||||
ieee80211_get_radio_led_name(hw),
|
||||
led_index, activelow);
|
||||
/* Sync the RF-kill LED state with radio and switch states. */
|
||||
if (dev->phy.radio_on && b43_is_hw_radio_enabled(dev))
|
||||
b43_led_turn_on(dev, led_index, activelow);
|
||||
break;
|
||||
case B43_LED_WEIRD:
|
||||
case B43_LED_ASSOC:
|
||||
snprintf(name, sizeof(name),
|
||||
"b43-%s::assoc", wiphy_name(hw->wiphy));
|
||||
b43_register_led(dev, &dev->led_assoc, name,
|
||||
b43_register_led(dev, &dev->wl->leds.led_assoc, name,
|
||||
ieee80211_get_assoc_led_name(hw),
|
||||
led_index, activelow);
|
||||
break;
|
||||
@@ -186,58 +210,150 @@ static void b43_map_led(struct b43_wldev *dev,
|
||||
}
|
||||
}
|
||||
|
||||
void b43_leds_init(struct b43_wldev *dev)
|
||||
static void b43_led_get_sprominfo(struct b43_wldev *dev,
|
||||
unsigned int led_index,
|
||||
enum b43_led_behaviour *behaviour,
|
||||
bool *activelow)
|
||||
{
|
||||
struct ssb_bus *bus = dev->dev->bus;
|
||||
u8 sprom[4];
|
||||
int i;
|
||||
enum b43_led_behaviour behaviour;
|
||||
bool activelow;
|
||||
|
||||
sprom[0] = bus->sprom.gpio0;
|
||||
sprom[1] = bus->sprom.gpio1;
|
||||
sprom[2] = bus->sprom.gpio2;
|
||||
sprom[3] = bus->sprom.gpio3;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (sprom[i] == 0xFF) {
|
||||
/* There is no LED information in the SPROM
|
||||
* for this LED. Hardcode it here. */
|
||||
activelow = 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
behaviour = B43_LED_ACTIVITY;
|
||||
activelow = 1;
|
||||
if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
|
||||
behaviour = B43_LED_RADIO_ALL;
|
||||
break;
|
||||
case 1:
|
||||
behaviour = B43_LED_RADIO_B;
|
||||
if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
|
||||
behaviour = B43_LED_ASSOC;
|
||||
break;
|
||||
case 2:
|
||||
behaviour = B43_LED_RADIO_A;
|
||||
break;
|
||||
case 3:
|
||||
behaviour = B43_LED_OFF;
|
||||
break;
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
behaviour = sprom[i] & B43_LED_BEHAVIOUR;
|
||||
activelow = !!(sprom[i] & B43_LED_ACTIVELOW);
|
||||
if (sprom[led_index] == 0xFF) {
|
||||
/* There is no LED information in the SPROM
|
||||
* for this LED. Hardcode it here. */
|
||||
*activelow = 0;
|
||||
switch (led_index) {
|
||||
case 0:
|
||||
*behaviour = B43_LED_ACTIVITY;
|
||||
*activelow = 1;
|
||||
if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
|
||||
*behaviour = B43_LED_RADIO_ALL;
|
||||
break;
|
||||
case 1:
|
||||
*behaviour = B43_LED_RADIO_B;
|
||||
if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
|
||||
*behaviour = B43_LED_ASSOC;
|
||||
break;
|
||||
case 2:
|
||||
*behaviour = B43_LED_RADIO_A;
|
||||
break;
|
||||
case 3:
|
||||
*behaviour = B43_LED_OFF;
|
||||
break;
|
||||
default:
|
||||
B43_WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
b43_map_led(dev, i, behaviour, activelow);
|
||||
} else {
|
||||
*behaviour = sprom[led_index] & B43_LED_BEHAVIOUR;
|
||||
*activelow = !!(sprom[led_index] & B43_LED_ACTIVELOW);
|
||||
}
|
||||
}
|
||||
|
||||
void b43_leds_init(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_led *led;
|
||||
unsigned int i;
|
||||
enum b43_led_behaviour behaviour;
|
||||
bool activelow;
|
||||
|
||||
/* Sync the RF-kill LED state (if we have one) with radio and switch states. */
|
||||
led = &dev->wl->leds.led_radio;
|
||||
if (led->wl) {
|
||||
if (dev->phy.radio_on && b43_is_hw_radio_enabled(dev)) {
|
||||
b43_led_turn_on(dev, led->index, led->activelow);
|
||||
led->hw_state = 1;
|
||||
atomic_set(&led->state, 1);
|
||||
} else {
|
||||
b43_led_turn_off(dev, led->index, led->activelow);
|
||||
led->hw_state = 0;
|
||||
atomic_set(&led->state, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize TX/RX/ASSOC leds */
|
||||
led = &dev->wl->leds.led_tx;
|
||||
if (led->wl) {
|
||||
b43_led_turn_off(dev, led->index, led->activelow);
|
||||
led->hw_state = 0;
|
||||
atomic_set(&led->state, 0);
|
||||
}
|
||||
led = &dev->wl->leds.led_rx;
|
||||
if (led->wl) {
|
||||
b43_led_turn_off(dev, led->index, led->activelow);
|
||||
led->hw_state = 0;
|
||||
atomic_set(&led->state, 0);
|
||||
}
|
||||
led = &dev->wl->leds.led_assoc;
|
||||
if (led->wl) {
|
||||
b43_led_turn_off(dev, led->index, led->activelow);
|
||||
led->hw_state = 0;
|
||||
atomic_set(&led->state, 0);
|
||||
}
|
||||
|
||||
/* Initialize other LED states. */
|
||||
for (i = 0; i < B43_MAX_NR_LEDS; i++) {
|
||||
b43_led_get_sprominfo(dev, i, &behaviour, &activelow);
|
||||
switch (behaviour) {
|
||||
case B43_LED_OFF:
|
||||
b43_led_turn_off(dev, i, activelow);
|
||||
break;
|
||||
case B43_LED_ON:
|
||||
b43_led_turn_on(dev, i, activelow);
|
||||
break;
|
||||
default:
|
||||
/* Leave others as-is. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dev->wl->leds.stop = 0;
|
||||
}
|
||||
|
||||
void b43_leds_exit(struct b43_wldev *dev)
|
||||
{
|
||||
b43_unregister_led(&dev->led_tx);
|
||||
b43_unregister_led(&dev->led_rx);
|
||||
b43_unregister_led(&dev->led_assoc);
|
||||
b43_unregister_led(&dev->led_radio);
|
||||
struct b43_leds *leds = &dev->wl->leds;
|
||||
|
||||
b43_led_turn_off(dev, leds->led_tx.index, leds->led_tx.activelow);
|
||||
b43_led_turn_off(dev, leds->led_rx.index, leds->led_rx.activelow);
|
||||
b43_led_turn_off(dev, leds->led_assoc.index, leds->led_assoc.activelow);
|
||||
b43_led_turn_off(dev, leds->led_radio.index, leds->led_radio.activelow);
|
||||
}
|
||||
|
||||
void b43_leds_stop(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_leds *leds = &dev->wl->leds;
|
||||
|
||||
leds->stop = 1;
|
||||
cancel_work_sync(&leds->work);
|
||||
}
|
||||
|
||||
void b43_leds_register(struct b43_wldev *dev)
|
||||
{
|
||||
unsigned int i;
|
||||
enum b43_led_behaviour behaviour;
|
||||
bool activelow;
|
||||
|
||||
INIT_WORK(&dev->wl->leds.work, b43_leds_work);
|
||||
|
||||
/* Register the LEDs to the LED subsystem. */
|
||||
for (i = 0; i < B43_MAX_NR_LEDS; i++) {
|
||||
b43_led_get_sprominfo(dev, i, &behaviour, &activelow);
|
||||
b43_map_led(dev, i, behaviour, activelow);
|
||||
}
|
||||
}
|
||||
|
||||
void b43_leds_unregister(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_leds *leds = &dev->wl->leds;
|
||||
|
||||
b43_unregister_led(&leds->led_tx);
|
||||
b43_unregister_led(&leds->led_rx);
|
||||
b43_unregister_led(&leds->led_assoc);
|
||||
b43_unregister_led(&leds->led_radio);
|
||||
}
|
||||
|
@@ -7,12 +7,13 @@ struct b43_wldev;
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
|
||||
#define B43_LED_MAX_NAME_LEN 31
|
||||
|
||||
struct b43_led {
|
||||
struct b43_wldev *dev;
|
||||
struct b43_wl *wl;
|
||||
/* The LED class device */
|
||||
struct led_classdev led_dev;
|
||||
/* The index number of the LED. */
|
||||
@@ -22,8 +23,24 @@ struct b43_led {
|
||||
bool activelow;
|
||||
/* The unique name string for this LED device. */
|
||||
char name[B43_LED_MAX_NAME_LEN + 1];
|
||||
/* The current status of the LED. This is updated locklessly. */
|
||||
atomic_t state;
|
||||
/* The active state in hardware. */
|
||||
bool hw_state;
|
||||
};
|
||||
|
||||
struct b43_leds {
|
||||
struct b43_led led_tx;
|
||||
struct b43_led led_rx;
|
||||
struct b43_led led_radio;
|
||||
struct b43_led led_assoc;
|
||||
|
||||
bool stop;
|
||||
struct work_struct work;
|
||||
};
|
||||
|
||||
#define B43_MAX_NR_LEDS 4
|
||||
|
||||
#define B43_LED_BEHAVIOUR 0x7F
|
||||
#define B43_LED_ACTIVELOW 0x80
|
||||
/* LED behaviour values */
|
||||
@@ -42,23 +59,35 @@ enum b43_led_behaviour {
|
||||
B43_LED_INACTIVE,
|
||||
};
|
||||
|
||||
void b43_leds_register(struct b43_wldev *dev);
|
||||
void b43_leds_unregister(struct b43_wldev *dev);
|
||||
void b43_leds_init(struct b43_wldev *dev);
|
||||
void b43_leds_exit(struct b43_wldev *dev);
|
||||
void b43_leds_stop(struct b43_wldev *dev);
|
||||
|
||||
|
||||
#else /* CONFIG_B43_LEDS */
|
||||
/* LED support disabled */
|
||||
|
||||
struct b43_led {
|
||||
struct b43_leds {
|
||||
/* empty */
|
||||
};
|
||||
|
||||
static inline void b43_leds_register(struct b43_wldev *dev)
|
||||
{
|
||||
}
|
||||
static inline void b43_leds_unregister(struct b43_wldev *dev)
|
||||
{
|
||||
}
|
||||
static inline void b43_leds_init(struct b43_wldev *dev)
|
||||
{
|
||||
}
|
||||
static inline void b43_leds_exit(struct b43_wldev *dev)
|
||||
{
|
||||
}
|
||||
static inline void b43_leds_stop(struct b43_wldev *dev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_B43_LEDS */
|
||||
|
||||
#endif /* B43_LEDS_H_ */
|
||||
|
@@ -8,6 +8,9 @@
|
||||
Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
|
||||
Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
|
||||
|
||||
SDIO support
|
||||
Copyright (c) 2009 Albert Herranz <albert_herranz@yahoo.es>
|
||||
|
||||
Some parts of the code in this file are derived from the ipw2200
|
||||
driver Copyright(c) 2003 - 2004 Intel Corporation.
|
||||
|
||||
@@ -53,6 +56,8 @@
|
||||
#include "xmit.h"
|
||||
#include "lo.h"
|
||||
#include "pcmcia.h"
|
||||
#include "sdio.h"
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
|
||||
MODULE_DESCRIPTION("Broadcom B43 wireless driver");
|
||||
MODULE_AUTHOR("Martin Langer");
|
||||
@@ -1587,7 +1592,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
|
||||
mutex_lock(&wl->mutex);
|
||||
dev = wl->current_dev;
|
||||
if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
|
||||
if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) {
|
||||
if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
|
||||
/* wl->mutex is enough. */
|
||||
b43_do_beacon_update_trigger_work(dev);
|
||||
mmiowb();
|
||||
@@ -1825,6 +1830,16 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev)
|
||||
|
||||
/* Re-enable interrupts on the device by restoring the current interrupt mask. */
|
||||
b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
|
||||
|
||||
#if B43_DEBUG
|
||||
if (b43_debug(dev, B43_DBG_VERBOSESTATS)) {
|
||||
dev->irq_count++;
|
||||
for (i = 0; i < ARRAY_SIZE(dev->irq_bit_count); i++) {
|
||||
if (reason & (1 << i))
|
||||
dev->irq_bit_count[i]++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Interrupt thread handler. Handles device interrupts in thread context. */
|
||||
@@ -1905,6 +1920,21 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* SDIO interrupt handler. This runs in process context. */
|
||||
static void b43_sdio_interrupt_handler(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_wl *wl = dev->wl;
|
||||
irqreturn_t ret;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
ret = b43_do_interrupt(dev);
|
||||
if (ret == IRQ_WAKE_THREAD)
|
||||
b43_do_interrupt_thread(dev);
|
||||
|
||||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
void b43_do_release_fw(struct b43_firmware_file *fw)
|
||||
{
|
||||
release_firmware(fw->data);
|
||||
@@ -2645,6 +2675,20 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
|
||||
cfp_pretbtt = 50;
|
||||
}
|
||||
b43_write16(dev, 0x612, cfp_pretbtt);
|
||||
|
||||
/* FIXME: We don't currently implement the PMQ mechanism,
|
||||
* so always disable it. If we want to implement PMQ,
|
||||
* we need to enable it here (clear DISCPMQ) in AP mode.
|
||||
*/
|
||||
if (0 /* ctl & B43_MACCTL_AP */) {
|
||||
b43_write32(dev, B43_MMIO_MACCTL,
|
||||
b43_read32(dev, B43_MMIO_MACCTL)
|
||||
& ~B43_MACCTL_DISCPMQ);
|
||||
} else {
|
||||
b43_write32(dev, B43_MMIO_MACCTL,
|
||||
b43_read32(dev, B43_MMIO_MACCTL)
|
||||
| B43_MACCTL_DISCPMQ);
|
||||
}
|
||||
}
|
||||
|
||||
static void b43_rate_memory_write(struct b43_wldev *dev, u16 rate, int is_ofdm)
|
||||
@@ -2873,6 +2917,27 @@ static void b43_periodic_every15sec(struct b43_wldev *dev)
|
||||
|
||||
atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
|
||||
wmb();
|
||||
|
||||
#if B43_DEBUG
|
||||
if (b43_debug(dev, B43_DBG_VERBOSESTATS)) {
|
||||
unsigned int i;
|
||||
|
||||
b43dbg(dev->wl, "Stats: %7u IRQs/sec, %7u TX/sec, %7u RX/sec\n",
|
||||
dev->irq_count / 15,
|
||||
dev->tx_count / 15,
|
||||
dev->rx_count / 15);
|
||||
dev->irq_count = 0;
|
||||
dev->tx_count = 0;
|
||||
dev->rx_count = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(dev->irq_bit_count); i++) {
|
||||
if (dev->irq_bit_count[i]) {
|
||||
b43dbg(dev->wl, "Stats: %7u IRQ-%02u/sec (0x%08X)\n",
|
||||
dev->irq_bit_count[i] / 15, i, (1 << i));
|
||||
dev->irq_bit_count[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void do_periodic_work(struct b43_wldev *dev)
|
||||
@@ -3002,14 +3067,18 @@ static void b43_security_init(struct b43_wldev *dev)
|
||||
static int b43_rng_read(struct hwrng *rng, u32 *data)
|
||||
{
|
||||
struct b43_wl *wl = (struct b43_wl *)rng->priv;
|
||||
struct b43_wldev *dev;
|
||||
int count = -ENODEV;
|
||||
|
||||
/* FIXME: We need to take wl->mutex here to make sure the device
|
||||
* is not going away from under our ass. However it could deadlock
|
||||
* with hwrng internal locking. */
|
||||
mutex_lock(&wl->mutex);
|
||||
dev = wl->current_dev;
|
||||
if (likely(dev && b43_status(dev) >= B43_STAT_INITIALIZED)) {
|
||||
*data = b43_read16(dev, B43_MMIO_RNG);
|
||||
count = sizeof(u16);
|
||||
}
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
*data = b43_read16(wl->current_dev, B43_MMIO_RNG);
|
||||
|
||||
return (sizeof(u16));
|
||||
return count;
|
||||
}
|
||||
#endif /* CONFIG_B43_HWRNG */
|
||||
|
||||
@@ -3068,6 +3137,9 @@ static void b43_tx_work(struct work_struct *work)
|
||||
dev_kfree_skb(skb); /* Drop it */
|
||||
}
|
||||
|
||||
#if B43_DEBUG
|
||||
dev->tx_count++;
|
||||
#endif
|
||||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
@@ -3820,7 +3892,7 @@ redo:
|
||||
|
||||
/* Disable interrupts on the device. */
|
||||
b43_set_status(dev, B43_STAT_INITIALIZED);
|
||||
if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) {
|
||||
if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
|
||||
/* wl->mutex is locked. That is enough. */
|
||||
b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
|
||||
b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
|
||||
@@ -3830,10 +3902,15 @@ redo:
|
||||
b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
|
||||
spin_unlock_irq(&wl->hardirq_lock);
|
||||
}
|
||||
/* Synchronize the interrupt handlers. Unlock to avoid deadlocks. */
|
||||
/* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */
|
||||
orig_dev = dev;
|
||||
mutex_unlock(&wl->mutex);
|
||||
synchronize_irq(dev->dev->irq);
|
||||
if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
|
||||
b43_sdio_free_irq(dev);
|
||||
} else {
|
||||
synchronize_irq(dev->dev->irq);
|
||||
free_irq(dev->dev->irq, dev);
|
||||
}
|
||||
mutex_lock(&wl->mutex);
|
||||
dev = wl->current_dev;
|
||||
if (!dev)
|
||||
@@ -3850,7 +3927,7 @@ redo:
|
||||
dev_kfree_skb(skb_dequeue(&wl->tx_queue));
|
||||
|
||||
b43_mac_suspend(dev);
|
||||
free_irq(dev->dev->irq, dev);
|
||||
b43_leds_exit(dev);
|
||||
b43dbg(wl, "Wireless interface stopped\n");
|
||||
|
||||
return dev;
|
||||
@@ -3864,12 +3941,20 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
|
||||
B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
|
||||
|
||||
drain_txstatus_queue(dev);
|
||||
err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,
|
||||
b43_interrupt_thread_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||
if (err) {
|
||||
b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
|
||||
goto out;
|
||||
if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
|
||||
err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler);
|
||||
if (err) {
|
||||
b43err(dev->wl, "Cannot request SDIO IRQ\n");
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,
|
||||
b43_interrupt_thread_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||
if (err) {
|
||||
b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* We are ready to run. */
|
||||
@@ -3882,8 +3967,10 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
|
||||
/* Start maintainance work */
|
||||
b43_periodic_tasks_setup(dev);
|
||||
|
||||
b43_leds_init(dev);
|
||||
|
||||
b43dbg(dev->wl, "Wireless interface started\n");
|
||||
out:
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -4160,10 +4247,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
|
||||
macctl |= B43_MACCTL_PSM_JMP0;
|
||||
b43_write32(dev, B43_MMIO_MACCTL, macctl);
|
||||
|
||||
if (!dev->suspend_in_progress) {
|
||||
b43_leds_exit(dev);
|
||||
b43_rng_exit(dev->wl);
|
||||
}
|
||||
b43_dma_free(dev);
|
||||
b43_pio_free(dev);
|
||||
b43_chip_exit(dev);
|
||||
@@ -4180,7 +4263,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
|
||||
/* Initialize a wireless core */
|
||||
static int b43_wireless_core_init(struct b43_wldev *dev)
|
||||
{
|
||||
struct b43_wl *wl = dev->wl;
|
||||
struct ssb_bus *bus = dev->dev->bus;
|
||||
struct ssb_sprom *sprom = &bus->sprom;
|
||||
struct b43_phy *phy = &dev->phy;
|
||||
@@ -4264,7 +4346,9 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
|
||||
/* Maximum Contention Window */
|
||||
b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
|
||||
|
||||
if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || B43_FORCE_PIO) {
|
||||
if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
|
||||
(dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) ||
|
||||
B43_FORCE_PIO) {
|
||||
dev->__using_pio_transfers = 1;
|
||||
err = b43_pio_init(dev);
|
||||
} else {
|
||||
@@ -4280,15 +4364,13 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
|
||||
ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW));
|
||||
b43_upload_card_macaddress(dev);
|
||||
b43_security_init(dev);
|
||||
if (!dev->suspend_in_progress)
|
||||
b43_rng_init(wl);
|
||||
|
||||
ieee80211_wake_queues(dev->wl->hw);
|
||||
|
||||
ieee80211_wake_queues(dev->wl->hw);
|
||||
|
||||
b43_set_status(dev, B43_STAT_INITIALIZED);
|
||||
|
||||
if (!dev->suspend_in_progress)
|
||||
b43_leds_init(dev);
|
||||
out:
|
||||
return err;
|
||||
|
||||
@@ -4837,7 +4919,6 @@ static int b43_wireless_init(struct ssb_device *dev)
|
||||
|
||||
/* Initialize struct b43_wl */
|
||||
wl->hw = hw;
|
||||
spin_lock_init(&wl->leds_lock);
|
||||
mutex_init(&wl->mutex);
|
||||
spin_lock_init(&wl->hardirq_lock);
|
||||
INIT_LIST_HEAD(&wl->devlist);
|
||||
@@ -4878,6 +4959,8 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
|
||||
err = ieee80211_register_hw(wl->hw);
|
||||
if (err)
|
||||
goto err_one_core_detach;
|
||||
b43_leds_register(wl->current_dev);
|
||||
b43_rng_init(wl);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -4906,12 +4989,15 @@ static void b43_remove(struct ssb_device *dev)
|
||||
* might have modified it. Restoring is important, so the networking
|
||||
* stack can properly free resources. */
|
||||
wl->hw->queues = wl->mac80211_initially_registered_queues;
|
||||
b43_leds_stop(wldev);
|
||||
ieee80211_unregister_hw(wl->hw);
|
||||
}
|
||||
|
||||
b43_one_core_detach(dev);
|
||||
|
||||
if (list_empty(&wl->devlist)) {
|
||||
b43_rng_exit(wl);
|
||||
b43_leds_unregister(wldev);
|
||||
/* Last core on the chip unregistered.
|
||||
* We can destroy common struct b43_wl.
|
||||
*/
|
||||
@@ -4929,80 +5015,17 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason)
|
||||
ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int b43_suspend(struct ssb_device *dev, pm_message_t state)
|
||||
{
|
||||
struct b43_wldev *wldev = ssb_get_drvdata(dev);
|
||||
struct b43_wl *wl = wldev->wl;
|
||||
|
||||
b43dbg(wl, "Suspending...\n");
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
wldev->suspend_in_progress = true;
|
||||
wldev->suspend_init_status = b43_status(wldev);
|
||||
if (wldev->suspend_init_status >= B43_STAT_STARTED)
|
||||
wldev = b43_wireless_core_stop(wldev);
|
||||
if (wldev && wldev->suspend_init_status >= B43_STAT_INITIALIZED)
|
||||
b43_wireless_core_exit(wldev);
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
b43dbg(wl, "Device suspended.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b43_resume(struct ssb_device *dev)
|
||||
{
|
||||
struct b43_wldev *wldev = ssb_get_drvdata(dev);
|
||||
struct b43_wl *wl = wldev->wl;
|
||||
int err = 0;
|
||||
|
||||
b43dbg(wl, "Resuming...\n");
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) {
|
||||
err = b43_wireless_core_init(wldev);
|
||||
if (err) {
|
||||
b43err(wl, "Resume failed at core init\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (wldev->suspend_init_status >= B43_STAT_STARTED) {
|
||||
err = b43_wireless_core_start(wldev);
|
||||
if (err) {
|
||||
b43_leds_exit(wldev);
|
||||
b43_rng_exit(wldev->wl);
|
||||
b43_wireless_core_exit(wldev);
|
||||
b43err(wl, "Resume failed at core start\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
b43dbg(wl, "Device resumed.\n");
|
||||
out:
|
||||
wldev->suspend_in_progress = false;
|
||||
mutex_unlock(&wl->mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
#else /* CONFIG_PM */
|
||||
# define b43_suspend NULL
|
||||
# define b43_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct ssb_driver b43_ssb_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = b43_ssb_tbl,
|
||||
.probe = b43_probe,
|
||||
.remove = b43_remove,
|
||||
.suspend = b43_suspend,
|
||||
.resume = b43_resume,
|
||||
};
|
||||
|
||||
static void b43_print_driverinfo(void)
|
||||
{
|
||||
const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "",
|
||||
*feat_leds = "";
|
||||
*feat_leds = "", *feat_sdio = "";
|
||||
|
||||
#ifdef CONFIG_B43_PCI_AUTOSELECT
|
||||
feat_pci = "P";
|
||||
@@ -5015,12 +5038,15 @@ static void b43_print_driverinfo(void)
|
||||
#endif
|
||||
#ifdef CONFIG_B43_LEDS
|
||||
feat_leds = "L";
|
||||
#endif
|
||||
#ifdef CONFIG_B43_SDIO
|
||||
feat_sdio = "S";
|
||||
#endif
|
||||
printk(KERN_INFO "Broadcom 43xx driver loaded "
|
||||
"[ Features: %s%s%s%s, Firmware-ID: "
|
||||
"[ Features: %s%s%s%s%s, Firmware-ID: "
|
||||
B43_SUPPORTED_FIRMWARE_ID " ]\n",
|
||||
feat_pci, feat_pcmcia, feat_nphy,
|
||||
feat_leds);
|
||||
feat_leds, feat_sdio);
|
||||
}
|
||||
|
||||
static int __init b43_init(void)
|
||||
@@ -5031,13 +5057,18 @@ static int __init b43_init(void)
|
||||
err = b43_pcmcia_init();
|
||||
if (err)
|
||||
goto err_dfs_exit;
|
||||
err = ssb_driver_register(&b43_ssb_driver);
|
||||
err = b43_sdio_init();
|
||||
if (err)
|
||||
goto err_pcmcia_exit;
|
||||
err = ssb_driver_register(&b43_ssb_driver);
|
||||
if (err)
|
||||
goto err_sdio_exit;
|
||||
b43_print_driverinfo();
|
||||
|
||||
return err;
|
||||
|
||||
err_sdio_exit:
|
||||
b43_sdio_exit();
|
||||
err_pcmcia_exit:
|
||||
b43_pcmcia_exit();
|
||||
err_dfs_exit:
|
||||
@@ -5048,6 +5079,7 @@ err_dfs_exit:
|
||||
static void __exit b43_exit(void)
|
||||
{
|
||||
ssb_driver_unregister(&b43_ssb_driver);
|
||||
b43_sdio_exit();
|
||||
b43_pcmcia_exit();
|
||||
b43_debugfs_exit();
|
||||
}
|
||||
|
@@ -2228,6 +2228,16 @@ static enum b43_txpwr_result b43_lpphy_op_recalc_txpower(struct b43_wldev *dev,
|
||||
return B43_TXPWR_RES_DONE;
|
||||
}
|
||||
|
||||
void b43_lpphy_op_switch_analog(struct b43_wldev *dev, bool on)
|
||||
{
|
||||
if (on) {
|
||||
b43_phy_mask(dev, B43_LPPHY_AFE_CTL_OVR, 0xfff8);
|
||||
} else {
|
||||
b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVRVAL, 0x0007);
|
||||
b43_phy_set(dev, B43_LPPHY_AFE_CTL_OVR, 0x0007);
|
||||
}
|
||||
}
|
||||
|
||||
const struct b43_phy_operations b43_phyops_lp = {
|
||||
.allocate = b43_lpphy_op_allocate,
|
||||
.free = b43_lpphy_op_free,
|
||||
@@ -2239,7 +2249,7 @@ const struct b43_phy_operations b43_phyops_lp = {
|
||||
.radio_read = b43_lpphy_op_radio_read,
|
||||
.radio_write = b43_lpphy_op_radio_write,
|
||||
.software_rfkill = b43_lpphy_op_software_rfkill,
|
||||
.switch_analog = b43_phyop_switch_analog_generic,
|
||||
.switch_analog = b43_lpphy_op_switch_analog,
|
||||
.switch_channel = b43_lpphy_op_switch_channel,
|
||||
.get_default_chan = b43_lpphy_op_get_default_chan,
|
||||
.set_rx_antenna = b43_lpphy_op_set_rx_antenna,
|
||||
|
@@ -574,7 +574,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
|
||||
q->buffer_used -= total_len;
|
||||
q->free_packet_slots += 1;
|
||||
|
||||
ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb);
|
||||
ieee80211_tx_status(dev->wl->hw, pack->skb);
|
||||
pack->skb = NULL;
|
||||
list_add(&pack->list, &q->packets_list);
|
||||
|
||||
|
@@ -28,7 +28,7 @@
|
||||
/* Returns TRUE, if the radio is enabled in hardware. */
|
||||
bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
|
||||
{
|
||||
if (dev->phy.rev >= 3) {
|
||||
if (dev->phy.rev >= 3 || dev->phy.type == B43_PHYTYPE_LP) {
|
||||
if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI)
|
||||
& B43_MMIO_RADIO_HWENABLED_HI_MASK))
|
||||
return 1;
|
||||
|
202
drivers/net/wireless/b43/sdio.c
Normal file
202
drivers/net/wireless/b43/sdio.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Broadcom B43 wireless driver
|
||||
*
|
||||
* SDIO over Sonics Silicon Backplane bus glue for b43.
|
||||
*
|
||||
* Copyright (C) 2009 Albert Herranz
|
||||
* Copyright (C) 2009 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
#include <linux/ssb/ssb.h>
|
||||
|
||||
#include "sdio.h"
|
||||
#include "b43.h"
|
||||
|
||||
|
||||
#define HNBU_CHIPID 0x01 /* vendor & device id */
|
||||
|
||||
#define B43_SDIO_BLOCK_SIZE 64 /* rx fifo max size in bytes */
|
||||
|
||||
|
||||
static const struct b43_sdio_quirk {
|
||||
u16 vendor;
|
||||
u16 device;
|
||||
unsigned int quirks;
|
||||
} b43_sdio_quirks[] = {
|
||||
{ 0x14E4, 0x4318, SSB_QUIRK_SDIO_READ_AFTER_WRITE32, },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
||||
static unsigned int b43_sdio_get_quirks(u16 vendor, u16 device)
|
||||
{
|
||||
const struct b43_sdio_quirk *q;
|
||||
|
||||
for (q = b43_sdio_quirks; q->quirks; q++) {
|
||||
if (vendor == q->vendor && device == q->device)
|
||||
return q->quirks;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void b43_sdio_interrupt_dispatcher(struct sdio_func *func)
|
||||
{
|
||||
struct b43_sdio *sdio = sdio_get_drvdata(func);
|
||||
struct b43_wldev *dev = sdio->irq_handler_opaque;
|
||||
|
||||
if (unlikely(b43_status(dev) < B43_STAT_STARTED))
|
||||
return;
|
||||
|
||||
sdio_release_host(func);
|
||||
sdio->irq_handler(dev);
|
||||
sdio_claim_host(func);
|
||||
}
|
||||
|
||||
int b43_sdio_request_irq(struct b43_wldev *dev,
|
||||
void (*handler)(struct b43_wldev *dev))
|
||||
{
|
||||
struct ssb_bus *bus = dev->dev->bus;
|
||||
struct sdio_func *func = bus->host_sdio;
|
||||
struct b43_sdio *sdio = sdio_get_drvdata(func);
|
||||
int err;
|
||||
|
||||
sdio->irq_handler_opaque = dev;
|
||||
sdio->irq_handler = handler;
|
||||
sdio_claim_host(func);
|
||||
err = sdio_claim_irq(func, b43_sdio_interrupt_dispatcher);
|
||||
sdio_release_host(func);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void b43_sdio_free_irq(struct b43_wldev *dev)
|
||||
{
|
||||
struct ssb_bus *bus = dev->dev->bus;
|
||||
struct sdio_func *func = bus->host_sdio;
|
||||
struct b43_sdio *sdio = sdio_get_drvdata(func);
|
||||
|
||||
sdio_claim_host(func);
|
||||
sdio_release_irq(func);
|
||||
sdio_release_host(func);
|
||||
sdio->irq_handler_opaque = NULL;
|
||||
sdio->irq_handler = NULL;
|
||||
}
|
||||
|
||||
static int b43_sdio_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
struct b43_sdio *sdio;
|
||||
struct sdio_func_tuple *tuple;
|
||||
u16 vendor = 0, device = 0;
|
||||
int error;
|
||||
|
||||
/* Look for the card chip identifier. */
|
||||
tuple = func->tuples;
|
||||
while (tuple) {
|
||||
switch (tuple->code) {
|
||||
case 0x80:
|
||||
switch (tuple->data[0]) {
|
||||
case HNBU_CHIPID:
|
||||
if (tuple->size != 5)
|
||||
break;
|
||||
vendor = tuple->data[1] | (tuple->data[2]<<8);
|
||||
device = tuple->data[3] | (tuple->data[4]<<8);
|
||||
dev_info(&func->dev, "Chip ID %04x:%04x\n",
|
||||
vendor, device);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
tuple = tuple->next;
|
||||
}
|
||||
if (!vendor || !device) {
|
||||
error = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sdio_claim_host(func);
|
||||
error = sdio_set_block_size(func, B43_SDIO_BLOCK_SIZE);
|
||||
if (error) {
|
||||
dev_err(&func->dev, "failed to set block size to %u bytes,"
|
||||
" error %d\n", B43_SDIO_BLOCK_SIZE, error);
|
||||
goto err_release_host;
|
||||
}
|
||||
error = sdio_enable_func(func);
|
||||
if (error) {
|
||||
dev_err(&func->dev, "failed to enable func, error %d\n", error);
|
||||
goto err_release_host;
|
||||
}
|
||||
sdio_release_host(func);
|
||||
|
||||
sdio = kzalloc(sizeof(*sdio), GFP_KERNEL);
|
||||
if (!sdio) {
|
||||
error = -ENOMEM;
|
||||
dev_err(&func->dev, "failed to allocate ssb bus\n");
|
||||
goto err_disable_func;
|
||||
}
|
||||
error = ssb_bus_sdiobus_register(&sdio->ssb, func,
|
||||
b43_sdio_get_quirks(vendor, device));
|
||||
if (error) {
|
||||
dev_err(&func->dev, "failed to register ssb sdio bus,"
|
||||
" error %d\n", error);
|
||||
goto err_free_ssb;
|
||||
}
|
||||
sdio_set_drvdata(func, sdio);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_ssb:
|
||||
kfree(sdio);
|
||||
err_disable_func:
|
||||
sdio_disable_func(func);
|
||||
err_release_host:
|
||||
sdio_release_host(func);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void b43_sdio_remove(struct sdio_func *func)
|
||||
{
|
||||
struct b43_sdio *sdio = sdio_get_drvdata(func);
|
||||
|
||||
ssb_bus_unregister(&sdio->ssb);
|
||||
sdio_disable_func(func);
|
||||
kfree(sdio);
|
||||
sdio_set_drvdata(func, NULL);
|
||||
}
|
||||
|
||||
static const struct sdio_device_id b43_sdio_ids[] = {
|
||||
{ SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct sdio_driver b43_sdio_driver = {
|
||||
.name = "b43-sdio",
|
||||
.id_table = b43_sdio_ids,
|
||||
.probe = b43_sdio_probe,
|
||||
.remove = b43_sdio_remove,
|
||||
};
|
||||
|
||||
int b43_sdio_init(void)
|
||||
{
|
||||
return sdio_register_driver(&b43_sdio_driver);
|
||||
}
|
||||
|
||||
void b43_sdio_exit(void)
|
||||
{
|
||||
sdio_unregister_driver(&b43_sdio_driver);
|
||||
}
|
45
drivers/net/wireless/b43/sdio.h
Normal file
45
drivers/net/wireless/b43/sdio.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef B43_SDIO_H_
|
||||
#define B43_SDIO_H_
|
||||
|
||||
#include <linux/ssb/ssb.h>
|
||||
|
||||
struct b43_wldev;
|
||||
|
||||
|
||||
#ifdef CONFIG_B43_SDIO
|
||||
|
||||
struct b43_sdio {
|
||||
struct ssb_bus ssb;
|
||||
void *irq_handler_opaque;
|
||||
void (*irq_handler)(struct b43_wldev *dev);
|
||||
};
|
||||
|
||||
int b43_sdio_request_irq(struct b43_wldev *dev,
|
||||
void (*handler)(struct b43_wldev *dev));
|
||||
void b43_sdio_free_irq(struct b43_wldev *dev);
|
||||
|
||||
int b43_sdio_init(void);
|
||||
void b43_sdio_exit(void);
|
||||
|
||||
|
||||
#else /* CONFIG_B43_SDIO */
|
||||
|
||||
|
||||
int b43_sdio_request_irq(struct b43_wldev *dev,
|
||||
void (*handler)(struct b43_wldev *dev))
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
void b43_sdio_free_irq(struct b43_wldev *dev)
|
||||
{
|
||||
}
|
||||
static inline int b43_sdio_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void b43_sdio_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_B43_SDIO */
|
||||
#endif /* B43_SDIO_H_ */
|
@@ -690,8 +690,11 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
||||
}
|
||||
|
||||
memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
|
||||
ieee80211_rx_irqsafe(dev->wl->hw, skb);
|
||||
ieee80211_rx(dev->wl->hw, skb);
|
||||
|
||||
#if B43_DEBUG
|
||||
dev->rx_count++;
|
||||
#endif
|
||||
return;
|
||||
drop:
|
||||
b43dbg(dev->wl, "RX: Packet dropped\n");
|
||||
|
Reference in New Issue
Block a user