Commit f18b95c3 authored by Jeff Garzik's avatar Jeff Garzik

Merge branch 'upstream-fixes' of...

Merge branch 'upstream-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6
parents 17c281ab 848ef855
...@@ -6,7 +6,7 @@ menu "Wireless LAN (non-hamradio)" ...@@ -6,7 +6,7 @@ menu "Wireless LAN (non-hamradio)"
depends on NETDEVICES depends on NETDEVICES
config NET_RADIO config NET_RADIO
bool "Wireless LAN drivers (non-hamradio)" bool "Wireless LAN drivers (non-hamradio) & Wireless Extensions"
select WIRELESS_EXT select WIRELESS_EXT
---help--- ---help---
Support for wireless LANs and everything having to do with radio, Support for wireless LANs and everything having to do with radio,
......
...@@ -3139,6 +3139,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -3139,6 +3139,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
} }
if ( status & EV_LINK ) { if ( status & EV_LINK ) {
union iwreq_data wrqu; union iwreq_data wrqu;
int scan_forceloss = 0;
/* The link status has changed, if you want to put a /* The link status has changed, if you want to put a
monitor hook in, do it here. (Remember that monitor hook in, do it here. (Remember that
interrupts are still disabled!) interrupts are still disabled!)
...@@ -3157,7 +3158,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -3157,7 +3158,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
code) */ code) */
#define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason #define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason
code) */ code) */
#define ASSOCIATED 0x0400 /* Assocatied */ #define ASSOCIATED 0x0400 /* Associated */
#define REASSOCIATED 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */
#define RC_RESERVED 0 /* Reserved return code */ #define RC_RESERVED 0 /* Reserved return code */
#define RC_NOREASON 1 /* Unspecified reason */ #define RC_NOREASON 1 /* Unspecified reason */
#define RC_AUTHINV 2 /* Previous authentication invalid */ #define RC_AUTHINV 2 /* Previous authentication invalid */
...@@ -3174,44 +3176,30 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -3174,44 +3176,30 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
leaving BSS */ leaving BSS */
#define RC_NOAUTH 9 /* Station requesting (Re)Association is not #define RC_NOAUTH 9 /* Station requesting (Re)Association is not
Authenticated with the responding station */ Authenticated with the responding station */
if (newStatus != ASSOCIATED) { if (newStatus == FORCELOSS && apriv->scan_timeout > 0)
if (auto_wep && !apriv->expires) { scan_forceloss = 1;
apriv->expires = RUN_AT(3*HZ); if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) {
wake_up_interruptible(&apriv->thr_wait);
}
} else {
struct task_struct *task = apriv->task;
if (auto_wep) if (auto_wep)
apriv->expires = 0; apriv->expires = 0;
if (task) if (apriv->task)
wake_up_process (task); wake_up_process (apriv->task);
set_bit(FLAG_UPDATE_UNI, &apriv->flags); set_bit(FLAG_UPDATE_UNI, &apriv->flags);
set_bit(FLAG_UPDATE_MULTI, &apriv->flags); set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
}
/* Question : is ASSOCIATED the only status
* that is valid ? We want to catch handover
* and reassociations as valid status
* Jean II */
if(newStatus == ASSOCIATED) {
#if 0
/* FIXME: Grabbing scan results here
* seems to be too early??? Just wait for
* timeout instead. */
if (apriv->scan_timeout > 0) {
set_bit(JOB_SCAN_RESULTS, &apriv->flags);
wake_up_interruptible(&apriv->thr_wait);
}
#endif
if (down_trylock(&apriv->sem) != 0) { if (down_trylock(&apriv->sem) != 0) {
set_bit(JOB_EVENT, &apriv->flags); set_bit(JOB_EVENT, &apriv->flags);
wake_up_interruptible(&apriv->thr_wait); wake_up_interruptible(&apriv->thr_wait);
} else } else
airo_send_event(dev); airo_send_event(dev);
} else { } else if (!scan_forceloss) {
memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); if (auto_wep && !apriv->expires) {
wrqu.ap_addr.sa_family = ARPHRD_ETHER; apriv->expires = RUN_AT(3*HZ);
wake_up_interruptible(&apriv->thr_wait);
}
/* Send event to user space */ /* Send event to user space */
memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL); wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL);
} }
} }
...@@ -7136,10 +7124,10 @@ static int airo_set_scan(struct net_device *dev, ...@@ -7136,10 +7124,10 @@ static int airo_set_scan(struct net_device *dev,
goto out; goto out;
/* Initiate a scan command */ /* Initiate a scan command */
ai->scan_timeout = RUN_AT(3*HZ);
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_LISTBSS; cmd.cmd=CMD_LISTBSS;
issuecommand(ai, &cmd, &rsp); issuecommand(ai, &cmd, &rsp);
ai->scan_timeout = RUN_AT(3*HZ);
wake = 1; wake = 1;
out: out:
......
...@@ -3463,6 +3463,7 @@ static void atmel_command_irq(struct atmel_private *priv) ...@@ -3463,6 +3463,7 @@ static void atmel_command_irq(struct atmel_private *priv)
u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET));
u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET));
int fast_scan; int fast_scan;
union iwreq_data wrqu;
if (status == CMD_STATUS_IDLE || if (status == CMD_STATUS_IDLE ||
status == CMD_STATUS_IN_PROGRESS) status == CMD_STATUS_IN_PROGRESS)
...@@ -3487,6 +3488,7 @@ static void atmel_command_irq(struct atmel_private *priv) ...@@ -3487,6 +3488,7 @@ static void atmel_command_irq(struct atmel_private *priv)
atmel_scan(priv, 1); atmel_scan(priv, 1);
} else { } else {
int bss_index = retrieve_bss(priv); int bss_index = retrieve_bss(priv);
int notify_scan_complete = 1;
if (bss_index != -1) { if (bss_index != -1) {
atmel_join_bss(priv, bss_index); atmel_join_bss(priv, bss_index);
} else if (priv->operating_mode == IW_MODE_ADHOC && } else if (priv->operating_mode == IW_MODE_ADHOC &&
...@@ -3495,8 +3497,14 @@ static void atmel_command_irq(struct atmel_private *priv) ...@@ -3495,8 +3497,14 @@ static void atmel_command_irq(struct atmel_private *priv)
} else { } else {
priv->fast_scan = !fast_scan; priv->fast_scan = !fast_scan;
atmel_scan(priv, 1); atmel_scan(priv, 1);
notify_scan_complete = 0;
} }
priv->site_survey_state = SITE_SURVEY_COMPLETED; priv->site_survey_state = SITE_SURVEY_COMPLETED;
if (notify_scan_complete) {
wrqu.data.length = 0;
wrqu.data.flags = 0;
wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
}
} }
break; break;
...@@ -3509,6 +3517,9 @@ static void atmel_command_irq(struct atmel_private *priv) ...@@ -3509,6 +3517,9 @@ static void atmel_command_irq(struct atmel_private *priv)
priv->site_survey_state = SITE_SURVEY_COMPLETED; priv->site_survey_state = SITE_SURVEY_COMPLETED;
if (priv->station_is_associated) { if (priv->station_is_associated) {
atmel_enter_state(priv, STATION_STATE_READY); atmel_enter_state(priv, STATION_STATE_READY);
wrqu.data.length = 0;
wrqu.data.flags = 0;
wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
} else { } else {
atmel_scan(priv, 1); atmel_scan(priv, 1);
} }
......
...@@ -17,8 +17,11 @@ config BCM43XX_DEBUG ...@@ -17,8 +17,11 @@ config BCM43XX_DEBUG
config BCM43XX_DMA config BCM43XX_DMA
bool bool
depends on BCM43XX
config BCM43XX_PIO config BCM43XX_PIO
bool bool
depends on BCM43XX
choice choice
prompt "BCM43xx data transfer mode" prompt "BCM43xx data transfer mode"
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include "bcm43xx_debugfs.h" #include "bcm43xx_debugfs.h"
#include "bcm43xx_leds.h" #include "bcm43xx_leds.h"
#include "bcm43xx_sysfs.h"
#define PFX KBUILD_MODNAME ": " #define PFX KBUILD_MODNAME ": "
...@@ -638,8 +637,6 @@ struct bcm43xx_key { ...@@ -638,8 +637,6 @@ struct bcm43xx_key {
}; };
struct bcm43xx_private { struct bcm43xx_private {
struct bcm43xx_sysfs sysfs;
struct ieee80211_device *ieee; struct ieee80211_device *ieee;
struct ieee80211softmac_device *softmac; struct ieee80211softmac_device *softmac;
...@@ -772,6 +769,20 @@ struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) ...@@ -772,6 +769,20 @@ struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
return ieee80211softmac_priv(dev); return ieee80211softmac_priv(dev);
} }
struct device;
static inline
struct bcm43xx_private * dev_to_bcm(struct device *dev)
{
struct net_device *net_dev;
struct bcm43xx_private *bcm;
net_dev = dev_get_drvdata(dev);
bcm = bcm43xx_priv(net_dev);
return bcm;
}
/* Helper function, which returns a boolean. /* Helper function, which returns a boolean.
* TRUE, if PIO is used; FALSE, if DMA is used. * TRUE, if PIO is used; FALSE, if DMA is used.
......
...@@ -452,12 +452,12 @@ void bcm43xx_printk_dump(const char *data, ...@@ -452,12 +452,12 @@ void bcm43xx_printk_dump(const char *data,
size_t i; size_t i;
char c; char c;
printk(KERN_INFO PFX "Data dump (%s, %u bytes):", printk(KERN_INFO PFX "Data dump (%s, %zd bytes):",
description, size); description, size);
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
c = data[i]; c = data[i];
if (i % 8 == 0) if (i % 8 == 0)
printk("\n" KERN_INFO PFX "0x%08x: 0x%02x, ", i, c & 0xff); printk("\n" KERN_INFO PFX "0x%08zx: 0x%02x, ", i, c & 0xff);
else else
printk("0x%02x, ", c & 0xff); printk("0x%02x, ", c & 0xff);
} }
...@@ -472,12 +472,12 @@ void bcm43xx_printk_bitdump(const unsigned char *data, ...@@ -472,12 +472,12 @@ void bcm43xx_printk_bitdump(const unsigned char *data,
int j; int j;
const unsigned char *d; const unsigned char *d;
printk(KERN_INFO PFX "*** Bitdump (%s, %u bytes, %s) ***", printk(KERN_INFO PFX "*** Bitdump (%s, %zd bytes, %s) ***",
description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB"); description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB");
for (i = 0; i < bytes; i++) { for (i = 0; i < bytes; i++) {
d = data + i; d = data + i;
if (i % 8 == 0) if (i % 8 == 0)
printk("\n" KERN_INFO PFX "0x%08x: ", i); printk("\n" KERN_INFO PFX "0x%08zx: ", i);
if (msb_to_lsb) { if (msb_to_lsb) {
for (j = 7; j >= 0; j--) { for (j = 7; j >= 0; j--) {
if (*d & (1 << j)) if (*d & (1 << j))
......
...@@ -196,8 +196,9 @@ static int alloc_ringmemory(struct bcm43xx_dmaring *ring) ...@@ -196,8 +196,9 @@ static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
} }
if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) { if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) {
printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G " printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G "
"(0x%08x, len: %lu)\n", "(0x%llx, len: %lu)\n",
ring->dmabase, BCM43xx_DMA_RINGMEMSIZE); (unsigned long long)ring->dmabase,
BCM43xx_DMA_RINGMEMSIZE);
dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
ring->vbase, ring->dmabase); ring->vbase, ring->dmabase);
return -ENOMEM; return -ENOMEM;
...@@ -307,8 +308,8 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, ...@@ -307,8 +308,8 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G " printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G "
"(0x%08x, len: %u)\n", "(0x%llx, len: %u)\n",
dmaaddr, ring->rx_buffersize); (unsigned long long)dmaaddr, ring->rx_buffersize);
return -ENOMEM; return -ENOMEM;
} }
meta->skb = skb; meta->skb = skb;
...@@ -729,8 +730,8 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring, ...@@ -729,8 +730,8 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) { if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) {
return_slot(ring, slot); return_slot(ring, slot);
printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G " printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G "
"(0x%08x, len: %u)\n", "(0x%llx, len: %u)\n",
meta->dmaaddr, skb->len); (unsigned long long)meta->dmaaddr, skb->len);
return -ENOMEM; return -ENOMEM;
} }
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include "bcm43xx_wx.h" #include "bcm43xx_wx.h"
#include "bcm43xx_ethtool.h" #include "bcm43xx_ethtool.h"
#include "bcm43xx_xmit.h" #include "bcm43xx_xmit.h"
#include "bcm43xx_sysfs.h"
MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");
...@@ -3522,6 +3523,7 @@ static inline int bcm43xx_tx(struct bcm43xx_private *bcm, ...@@ -3522,6 +3523,7 @@ static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
err = bcm43xx_pio_tx(bcm, txb); err = bcm43xx_pio_tx(bcm, txb);
else else
err = bcm43xx_dma_tx(bcm, txb); err = bcm43xx_dma_tx(bcm, txb);
bcm->net_dev->trans_start = jiffies;
return err; return err;
} }
......
...@@ -2151,6 +2151,7 @@ int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm) ...@@ -2151,6 +2151,7 @@ int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm)
phy->tssi2dbm = NULL; phy->tssi2dbm = NULL;
printk(KERN_ERR PFX "Could not generate " printk(KERN_ERR PFX "Could not generate "
"tssi2dBm table\n"); "tssi2dBm table\n");
kfree(dyn_tssi2dbm);
return -ENODEV; return -ENODEV;
} }
phy->tssi2dbm = dyn_tssi2dbm; phy->tssi2dbm = dyn_tssi2dbm;
......
...@@ -35,77 +35,101 @@ ...@@ -35,77 +35,101 @@
#include "bcm43xx_main.h" #include "bcm43xx_main.h"
/* Get the Slow Clock Source */
static int bcm43xx_pctl_get_slowclksrc(struct bcm43xx_private *bcm)
{
u32 tmp;
int err;
assert(bcm->current_core == &bcm->core_chipcommon);
if (bcm->current_core->rev < 6) {
if (bcm->bustype == BCM43xx_BUSTYPE_PCMCIA ||
bcm->bustype == BCM43xx_BUSTYPE_SB)
return BCM43xx_PCTL_CLKSRC_XTALOS;
if (bcm->bustype == BCM43xx_BUSTYPE_PCI) {
err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp);
assert(!err);
if (tmp & 0x10)
return BCM43xx_PCTL_CLKSRC_PCI;
return BCM43xx_PCTL_CLKSRC_XTALOS;
}
}
if (bcm->current_core->rev < 10) {
tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
tmp &= 0x7;
if (tmp == 0)
return BCM43xx_PCTL_CLKSRC_LOPWROS;
if (tmp == 1)
return BCM43xx_PCTL_CLKSRC_XTALOS;
if (tmp == 2)
return BCM43xx_PCTL_CLKSRC_PCI;
}
return BCM43xx_PCTL_CLKSRC_XTALOS;
}
/* Get max/min slowclock frequency /* Get max/min slowclock frequency
* as described in http://bcm-specs.sipsolutions.net/PowerControl * as described in http://bcm-specs.sipsolutions.net/PowerControl
*/ */
static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm,
int get_max) int get_max)
{ {
int limit = 0; int limit;
int clocksrc;
int divisor; int divisor;
int selection;
int err;
u32 tmp; u32 tmp;
struct bcm43xx_coreinfo *old_core;
if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) assert(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL);
goto out; assert(bcm->current_core == &bcm->core_chipcommon);
old_core = bcm->current_core;
err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
if (err)
goto out;
clocksrc = bcm43xx_pctl_get_slowclksrc(bcm);
if (bcm->current_core->rev < 6) { if (bcm->current_core->rev < 6) {
if ((bcm->bustype == BCM43xx_BUSTYPE_PCMCIA) || switch (clocksrc) {
(bcm->bustype == BCM43xx_BUSTYPE_SB)) { case BCM43xx_PCTL_CLKSRC_PCI:
selection = 1; divisor = 64;
break;
case BCM43xx_PCTL_CLKSRC_XTALOS:
divisor = 32; divisor = 32;
} else { break;
err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp); default:
if (err) { assert(0);
printk(KERN_ERR PFX "clockfreqlimit pcicfg read failure\n"); divisor = 1;
goto out_switchback;
}
if (tmp & 0x10) {
/* PCI */
selection = 2;
divisor = 64;
} else {
/* XTAL */
selection = 1;
divisor = 32;
}
} }
} else if (bcm->current_core->rev < 10) { } else if (bcm->current_core->rev < 10) {
selection = (tmp & 0x07); switch (clocksrc) {
if (selection) { case BCM43xx_PCTL_CLKSRC_LOPWROS:
divisor = 1;
break;
case BCM43xx_PCTL_CLKSRC_XTALOS:
case BCM43xx_PCTL_CLKSRC_PCI:
tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); divisor = ((tmp & 0xFFFF0000) >> 16) + 1;
} else divisor *= 4;
break;
default:
assert(0);
divisor = 1; divisor = 1;
}
} else { } else {
tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL); tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL);
divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); divisor = ((tmp & 0xFFFF0000) >> 16) + 1;
selection = 1; divisor *= 4;
} }
switch (selection) { switch (clocksrc) {
case 0: case BCM43xx_PCTL_CLKSRC_LOPWROS:
/* LPO */
if (get_max) if (get_max)
limit = 43000; limit = 43000;
else else
limit = 25000; limit = 25000;
break; break;
case 1: case BCM43xx_PCTL_CLKSRC_XTALOS:
/* XTAL */
if (get_max) if (get_max)
limit = 20200000; limit = 20200000;
else else
limit = 19800000; limit = 19800000;
break; break;
case 2: case BCM43xx_PCTL_CLKSRC_PCI:
/* PCI */
if (get_max) if (get_max)
limit = 34000000; limit = 34000000;
else else
...@@ -113,17 +137,14 @@ static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, ...@@ -113,17 +137,14 @@ static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm,
break; break;
default: default:
assert(0); assert(0);
limit = 0;
} }
limit /= divisor; limit /= divisor;
out_switchback:
err = bcm43xx_switch_core(bcm, old_core);
assert(err == 0);
out:
return limit; return limit;
} }
/* init power control /* init power control
* as described in http://bcm-specs.sipsolutions.net/PowerControl * as described in http://bcm-specs.sipsolutions.net/PowerControl
*/ */
......
...@@ -33,6 +33,15 @@ ...@@ -33,6 +33,15 @@
#include <linux/types.h> #include <linux/types.h>
/* Clock sources */
enum {
/* PCI clock */
BCM43xx_PCTL_CLKSRC_PCI,
/* Crystal slow clock oscillator */
BCM43xx_PCTL_CLKSRC_XTALOS,
/* Low power oscillator */
BCM43xx_PCTL_CLKSRC_LOPWROS,
};
struct bcm43xx_private; struct bcm43xx_private;
......
...@@ -71,14 +71,46 @@ static int get_boolean(const char *buf, size_t count) ...@@ -71,14 +71,46 @@ static int get_boolean(const char *buf, size_t count)
return -EINVAL; return -EINVAL;
} }
static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len)
{
int i, pos = 0;
for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
pos += snprintf(buf + pos, buf_len - pos - 1,
"%04X", swab16(sprom[i]) & 0xFFFF);
}
pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
return pos + 1;
}
static int hex2sprom(u16 *sprom, const char *dump, size_t len)
{
char tmp[5] = { 0 };
int cnt = 0;
unsigned long parsed;
if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
return -EINVAL;
while (cnt < BCM43xx_SPROM_SIZE) {
memcpy(tmp, dump, 4);
dump += 4;
parsed = simple_strtoul(tmp, NULL, 16);
sprom[cnt++] = swab16((u16)parsed);
}
return 0;
}
static ssize_t bcm43xx_attr_sprom_show(struct device *dev, static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); struct bcm43xx_private *bcm = dev_to_bcm(dev);
u16 *sprom; u16 *sprom;
unsigned long flags; unsigned long flags;
int i, err; int err;
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
...@@ -91,55 +123,53 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev, ...@@ -91,55 +123,53 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
bcm43xx_lock_mmio(bcm, flags); bcm43xx_lock_mmio(bcm, flags);
assert(bcm->initialized); assert(bcm->initialized);
err = bcm43xx_sprom_read(bcm, sprom); err = bcm43xx_sprom_read(bcm, sprom);
if (!err) { if (!err)
for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { err = sprom2hex(sprom, buf, PAGE_SIZE);
buf[i * 2] = sprom[i] & 0x00FF;
buf[i * 2 + 1] = (sprom[i] & 0xFF00) >> 8;
}
}
bcm43xx_unlock_mmio(bcm, flags); bcm43xx_unlock_mmio(bcm, flags);
kfree(sprom); kfree(sprom);
return err ? err : BCM43xx_SPROM_SIZE * sizeof(u16); return err;
} }
static ssize_t bcm43xx_attr_sprom_store(struct device *dev, static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); struct bcm43xx_private *bcm = dev_to_bcm(dev);
u16 *sprom; u16 *sprom;
unsigned long flags; unsigned long flags;
int i, err; int err;
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
if (count != BCM43xx_SPROM_SIZE * sizeof(u16))
return -EINVAL;
sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
GFP_KERNEL); GFP_KERNEL);
if (!sprom) if (!sprom)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { err = hex2sprom(sprom, buf, count);
sprom[i] = buf[i * 2] & 0xFF; if (err)
sprom[i] |= ((u16)(buf[i * 2 + 1] & 0xFF)) << 8; goto out_kfree;
}
bcm43xx_lock_mmio(bcm, flags); bcm43xx_lock_mmio(bcm, flags);
assert(bcm->initialized); assert(bcm->initialized);
err = bcm43xx_sprom_write(bcm, sprom); err = bcm43xx_sprom_write(bcm, sprom);
bcm43xx_unlock_mmio(bcm, flags); bcm43xx_unlock_mmio(bcm, flags);
out_kfree:
kfree(sprom); kfree(sprom);
return err ? err : count; return err ? err : count;
} }
static DEVICE_ATTR(sprom, 0600,
bcm43xx_attr_sprom_show,
bcm43xx_attr_sprom_store);
static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); struct bcm43xx_private *bcm = dev_to_bcm(dev);
unsigned long flags; unsigned long flags;
int err; int err;
ssize_t count = 0; ssize_t count = 0;
...@@ -175,7 +205,7 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, ...@@ -175,7 +205,7 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); struct bcm43xx_private *bcm = dev_to_bcm(dev);
unsigned long flags; unsigned long flags;
int err; int err;
int mode; int mode;
...@@ -215,11 +245,15 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, ...@@ -215,11 +245,15 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
return err ? err : count; return err ? err : count;
} }
static DEVICE_ATTR(interference, 0644,
bcm43xx_attr_interfmode_show,
bcm43xx_attr_interfmode_store);
static ssize_t bcm43xx_attr_preamble_show(struct device *dev, static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); struct bcm43xx_private *bcm = dev_to_bcm(dev);
unsigned long flags; unsigned long flags;
int err; int err;
ssize_t count; ssize_t count;
...@@ -245,7 +279,7 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, ...@@ -245,7 +279,7 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); struct bcm43xx_private *bcm = dev_to_bcm(dev);
unsigned long flags; unsigned long flags;
int err; int err;
int value; int value;
...@@ -267,56 +301,41 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, ...@@ -267,56 +301,41 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
return err ? err : count; return err ? err : count;
} }
static DEVICE_ATTR(shortpreamble, 0644,
bcm43xx_attr_preamble_show,
bcm43xx_attr_preamble_store);
int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
{ {
struct device *dev = &bcm->pci_dev->dev; struct device *dev = &bcm->pci_dev->dev;
struct bcm43xx_sysfs *sysfs = &bcm->sysfs;
int err; int err;
assert(bcm->initialized); assert(bcm->initialized);
sysfs->attr_sprom.attr.name = "sprom"; err = device_create_file(dev, &dev_attr_sprom);
sysfs->attr_sprom.attr.owner = THIS_MODULE;
sysfs->attr_sprom.attr.mode = 0600;
sysfs->attr_sprom.show = bcm43xx_attr_sprom_show;
sysfs->attr_sprom.store = bcm43xx_attr_sprom_store;
err = device_create_file(dev, &sysfs->attr_sprom);
if (err) if (err)
goto out; goto out;
err = device_create_file(dev, &dev_attr_interference);
sysfs->attr_interfmode.attr.name = "interference";
sysfs->attr_interfmode.attr.owner = THIS_MODULE;
sysfs->attr_interfmode.attr.mode = 0600;
sysfs->attr_interfmode.show = bcm43xx_attr_interfmode_show;
sysfs->attr_interfmode.store = bcm43xx_attr_interfmode_store;
err = device_create_file(dev, &sysfs->attr_interfmode);
if (err) if (err)
goto err_remove_sprom; goto err_remove_sprom;
err = device_create_file(dev, &dev_attr_shortpreamble);
sysfs->attr_preamble.attr.name = "shortpreamble";
sysfs->attr_preamble.attr.owner = THIS_MODULE;
sysfs->attr_preamble.attr.mode = 0600;
sysfs->attr_preamble.show = bcm43xx_attr_preamble_show;
sysfs->attr_preamble.store = bcm43xx_attr_preamble_store;
err = device_create_file(dev, &sysfs->attr_preamble);
if (err) if (err)
goto err_remove_interfmode; goto err_remove_interfmode;
out: out:
return err; return err;
err_remove_interfmode: err_remove_interfmode:
device_remove_file(dev, &sysfs->attr_interfmode); device_remove_file(dev, &dev_attr_interference);
err_remove_sprom: err_remove_sprom:
device_remove_file(dev, &sysfs->attr_sprom); device_remove_file(dev, &dev_attr_sprom);
goto out; goto out;
} }
void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm) void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
{ {
struct device *dev = &bcm->pci_dev->dev; struct device *dev = &bcm->pci_dev->dev;
struct bcm43xx_sysfs *sysfs = &bcm->sysfs;
device_remove_file(dev, &sysfs->attr_preamble); device_remove_file(dev, &dev_attr_shortpreamble);
device_remove_file(dev, &sysfs->attr_interfmode); device_remove_file(dev, &dev_attr_interference);
device_remove_file(dev, &sysfs->attr_sprom); device_remove_file(dev, &dev_attr_sprom);
} }
#ifndef BCM43xx_SYSFS_H_ #ifndef BCM43xx_SYSFS_H_
#define BCM43xx_SYSFS_H_ #define BCM43xx_SYSFS_H_
#include <linux/device.h>
struct bcm43xx_sysfs {
struct device_attribute attr_sprom;
struct device_attribute attr_interfmode;
struct device_attribute attr_preamble;
};
#define devattr_to_bcm(attr, attr_name) ({ \
struct bcm43xx_sysfs *__s; struct bcm43xx_private *__p; \
__s = container_of((attr), struct bcm43xx_sysfs, attr_name); \
__p = container_of(__s, struct bcm43xx_private, sysfs); \
__p; \
})
struct bcm43xx_private; struct bcm43xx_private;
int bcm43xx_sysfs_register(struct bcm43xx_private *bcm); int bcm43xx_sysfs_register(struct bcm43xx_private *bcm);
......
...@@ -962,22 +962,22 @@ static const struct iw_priv_args bcm43xx_priv_wx_args[] = { ...@@ -962,22 +962,22 @@ static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
{ {
.cmd = PRIV_WX_SET_SHORTPREAMBLE, .cmd = PRIV_WX_SET_SHORTPREAMBLE,
.set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
.name = "set_shortpreambl", .name = "set_shortpreamb",
}, },
{ {
.cmd = PRIV_WX_GET_SHORTPREAMBLE, .cmd = PRIV_WX_GET_SHORTPREAMBLE,
.get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
.name = "get_shortpreambl", .name = "get_shortpreamb",
}, },
{ {
.cmd = PRIV_WX_SET_SWENCRYPTION, .cmd = PRIV_WX_SET_SWENCRYPTION,
.set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
.name = "set_swencryption", .name = "set_swencrypt",
}, },
{ {
.cmd = PRIV_WX_GET_SWENCRYPTION, .cmd = PRIV_WX_GET_SWENCRYPTION,
.get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
.name = "get_swencryption", .name = "get_swencrypt",
}, },
{ {
.cmd = PRIV_WX_SPROM_WRITE, .cmd = PRIV_WX_SPROM_WRITE,
......
...@@ -390,7 +390,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) ...@@ -390,7 +390,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
} }
} else { } else {
struct { struct {
__le16 qual, signal, noise; __le16 qual, signal, noise, unused;
} __attribute__ ((packed)) cq; } __attribute__ ((packed)) cq;
err = HERMES_READ_RECORD(hw, USER_BAP, err = HERMES_READ_RECORD(hw, USER_BAP,
......
...@@ -267,8 +267,9 @@ extern void ieee80211softmac_stop(struct net_device *dev); ...@@ -267,8 +267,9 @@ extern void ieee80211softmac_stop(struct net_device *dev);
#define IEEE80211SOFTMAC_EVENT_AUTH_FAILED 5 #define IEEE80211SOFTMAC_EVENT_AUTH_FAILED 5
#define IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT 6 #define IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT 6
#define IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND 7 #define IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND 7
#define IEEE80211SOFTMAC_EVENT_DISASSOCIATED 8
/* keep this updated! */ /* keep this updated! */
#define IEEE80211SOFTMAC_EVENT_LAST 7 #define IEEE80211SOFTMAC_EVENT_LAST 8
/* /*
* If you want to be notified of certain events, you can call * If you want to be notified of certain events, you can call
* ieee80211softmac_notify[_atomic] with * ieee80211softmac_notify[_atomic] with
......
...@@ -2698,7 +2698,8 @@ int dev_ioctl(unsigned int cmd, void __user *arg) ...@@ -2698,7 +2698,8 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
/* If command is `set a parameter', or /* If command is `set a parameter', or
* `get the encoding parameters', check if * `get the encoding parameters', check if
* the user has the right to do it */ * the user has the right to do it */
if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE) { if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE
|| cmd == SIOCGIWENCODEEXT) {
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
} }
......
...@@ -1726,6 +1726,14 @@ int wireless_rtnetlink_get(struct net_device * dev, ...@@ -1726,6 +1726,14 @@ int wireless_rtnetlink_get(struct net_device * dev,
if(!IW_IS_GET(request->cmd)) if(!IW_IS_GET(request->cmd))
return -EOPNOTSUPP; return -EOPNOTSUPP;
/* If command is `get the encoding parameters', check if
* the user has the right to do it */
if (request->cmd == SIOCGIWENCODE ||
request->cmd == SIOCGIWENCODEEXT) {
if (!capable(CAP_NET_ADMIN))
return -EPERM;
}
/* Special cases */ /* Special cases */
if(request->cmd == SIOCGIWSTATS) if(request->cmd == SIOCGIWSTATS)
/* Get Wireless Stats */ /* Get Wireless Stats */
......
config IEEE80211_SOFTMAC config IEEE80211_SOFTMAC
tristate "Software MAC add-on to the IEEE 802.11 networking stack" tristate "Software MAC add-on to the IEEE 802.11 networking stack"
depends on IEEE80211 && EXPERIMENTAL depends on IEEE80211 && EXPERIMENTAL
select WIRELESS_EXT
---help--- ---help---
This option enables the hardware independent software MAC addon This option enables the hardware independent software MAC addon
for the IEEE 802.11 networking stack. for the IEEE 802.11 networking stack.
......
...@@ -101,6 +101,7 @@ ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason) ...@@ -101,6 +101,7 @@ ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason)
/* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */ /* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */
mac->associated = 0; mac->associated = 0;
mac->associnfo.associating = 0; mac->associnfo.associating = 0;
ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
spin_unlock_irqrestore(&mac->lock, flags); spin_unlock_irqrestore(&mac->lock, flags);
} }
...@@ -373,6 +374,7 @@ ieee80211softmac_handle_disassoc(struct net_device * dev, ...@@ -373,6 +374,7 @@ ieee80211softmac_handle_disassoc(struct net_device * dev,
spin_lock_irqsave(&mac->lock, flags); spin_lock_irqsave(&mac->lock, flags);
mac->associnfo.bssvalid = 0; mac->associnfo.bssvalid = 0;
mac->associated = 0; mac->associated = 0;
ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
schedule_work(&mac->associnfo.work); schedule_work(&mac->associnfo.work);
spin_unlock_irqrestore(&mac->lock, flags); spin_unlock_irqrestore(&mac->lock, flags);
...@@ -391,6 +393,7 @@ ieee80211softmac_handle_reassoc_req(struct net_device * dev, ...@@ -391,6 +393,7 @@ ieee80211softmac_handle_reassoc_req(struct net_device * dev,
dprintkl(KERN_INFO PFX "reassoc request from unknown network\n"); dprintkl(KERN_INFO PFX "reassoc request from unknown network\n");
return 0; return 0;
} }
ieee80211softmac_assoc(mac, network); schedule_work(&mac->associnfo.work);
return 0; return 0;
} }
...@@ -67,6 +67,7 @@ static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = { ...@@ -67,6 +67,7 @@ static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
"authenticating failed", "authenticating failed",
"authenticating timed out", "authenticating timed out",
"associating failed because no suitable network was found", "associating failed because no suitable network was found",
"disassociated",
}; };
...@@ -128,13 +129,42 @@ void ...@@ -128,13 +129,42 @@ void
ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx) ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx)
{ {
struct ieee80211softmac_event *eventptr, *tmp; struct ieee80211softmac_event *eventptr, *tmp;
union iwreq_data wrqu; struct ieee80211softmac_network *network;
char *msg;
if (event >= 0) { if (event >= 0) {
msg = event_descriptions[event]; union iwreq_data wrqu;
wrqu.data.length = strlen(msg); int we_event;
wireless_send_event(mac->dev, IWEVCUSTOM, &wrqu, msg); char *msg = NULL;
switch(event) {
case IEEE80211SOFTMAC_EVENT_ASSOCIATED:
network = (struct ieee80211softmac_network *)event_ctx;
wrqu.data.length = 0;
wrqu.data.flags = 0;
memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
we_event = SIOCGIWAP;
break;
case IEEE80211SOFTMAC_EVENT_DISASSOCIATED:
wrqu.data.length = 0;
wrqu.data.flags = 0;
memset(&wrqu, '\0', sizeof (union iwreq_data));
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
we_event = SIOCGIWAP;
break;
case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED:
wrqu.data.length = 0;
wrqu.data.flags = 0;
memset(&wrqu, '\0', sizeof (union iwreq_data));
we_event = SIOCGIWSCAN;
break;
default:
msg = event_descriptions[event];
wrqu.data.length = strlen(msg);
we_event = IWEVCUSTOM;
break;
}
wireless_send_event(mac->dev, we_event, &wrqu, msg);
} }
if (!list_empty(&mac->events)) if (!list_empty(&mac->events))
......
...@@ -180,9 +180,21 @@ ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt, ...@@ -180,9 +180,21 @@ ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid); ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
/* Fill in capability Info */ /* Fill in capability Info */
(*pkt)->capability = (mac->ieee->iw_mode == IW_MODE_MASTER) || (mac->ieee->iw_mode == IW_MODE_INFRA) ? switch (mac->ieee->iw_mode) {
cpu_to_le16(WLAN_CAPABILITY_ESS) : case IW_MODE_INFRA:
cpu_to_le16(WLAN_CAPABILITY_IBSS); (*pkt)->capability = cpu_to_le16(WLAN_CAPABILITY_ESS);
break;
case IW_MODE_ADHOC:
(*pkt)->capability = cpu_to_le16(WLAN_CAPABILITY_IBSS);
break;
case IW_MODE_AUTO:
(*pkt)->capability = net->capabilities & (WLAN_CAPABILITY_ESS|WLAN_CAPABILITY_IBSS);
break;
default:
/* bleh. we don't ever go to these modes */
printk(KERN_ERR PFX "invalid iw_mode!\n");
break;
}
/* Need to add this /* Need to add this
(*pkt)->capability |= mac->ieee->short_slot ? (*pkt)->capability |= mac->ieee->short_slot ?
cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0; cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0;
......
...@@ -47,6 +47,7 @@ ieee80211softmac_start_scan(struct ieee80211softmac_device *sm) ...@@ -47,6 +47,7 @@ ieee80211softmac_start_scan(struct ieee80211softmac_device *sm)
sm->scanning = 1; sm->scanning = 1;
spin_unlock_irqrestore(&sm->lock, flags); spin_unlock_irqrestore(&sm->lock, flags);
netif_tx_disable(sm->ieee->dev);
ret = sm->start_scan(sm->dev); ret = sm->start_scan(sm->dev);
if (ret) { if (ret) {
spin_lock_irqsave(&sm->lock, flags); spin_lock_irqsave(&sm->lock, flags);
...@@ -239,6 +240,7 @@ void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm) ...@@ -239,6 +240,7 @@ void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm)
if (net) if (net)
sm->set_channel(sm->dev, net->channel); sm->set_channel(sm->dev, net->channel);
} }
netif_wake_queue(sm->ieee->dev);
ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL); ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL);
} }
EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished); EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished);
...@@ -41,13 +41,23 @@ ieee80211softmac_wx_trigger_scan(struct net_device *net_dev, ...@@ -41,13 +41,23 @@ ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan); EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
/* if we're still scanning, return -EAGAIN so that userspace tools
* can get the complete scan results, otherwise return 0. */
int int
ieee80211softmac_wx_get_scan_results(struct net_device *net_dev, ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
struct iw_request_info *info, struct iw_request_info *info,
union iwreq_data *data, union iwreq_data *data,
char *extra) char *extra)
{ {
unsigned long flags;
struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
spin_lock_irqsave(&sm->lock, flags);
if (sm->scanning) {
spin_unlock_irqrestore(&sm->lock, flags);
return -EAGAIN;
}
spin_unlock_irqrestore(&sm->lock, flags);
return ieee80211_wx_get_scan(sm->ieee, info, data, extra); return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
} }
EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results); EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
......
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