diff options
24 files changed, 288 insertions, 170 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index bad09ebdb50b..e0874cbfefea 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
| @@ -6,7 +6,7 @@ menu "Wireless LAN (non-hamradio)" | |||
| 6 | depends on NETDEVICES | 6 | depends on NETDEVICES |
| 7 | 7 | ||
| 8 | config NET_RADIO | 8 | config NET_RADIO |
| 9 | bool "Wireless LAN drivers (non-hamradio)" | 9 | bool "Wireless LAN drivers (non-hamradio) & Wireless Extensions" |
| 10 | select WIRELESS_EXT | 10 | select WIRELESS_EXT |
| 11 | ---help--- | 11 | ---help--- |
| 12 | Support for wireless LANs and everything having to do with radio, | 12 | Support for wireless LANs and everything having to do with radio, |
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 108d9fed8f07..00764ddd74d8 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c | |||
| @@ -3139,6 +3139,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) | |||
| 3139 | } | 3139 | } |
| 3140 | if ( status & EV_LINK ) { | 3140 | if ( status & EV_LINK ) { |
| 3141 | union iwreq_data wrqu; | 3141 | union iwreq_data wrqu; |
| 3142 | int scan_forceloss = 0; | ||
| 3142 | /* The link status has changed, if you want to put a | 3143 | /* The link status has changed, if you want to put a |
| 3143 | monitor hook in, do it here. (Remember that | 3144 | monitor hook in, do it here. (Remember that |
| 3144 | interrupts are still disabled!) | 3145 | interrupts are still disabled!) |
| @@ -3157,7 +3158,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) | |||
| 3157 | code) */ | 3158 | code) */ |
| 3158 | #define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason | 3159 | #define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason |
| 3159 | code) */ | 3160 | code) */ |
| 3160 | #define ASSOCIATED 0x0400 /* Assocatied */ | 3161 | #define ASSOCIATED 0x0400 /* Associated */ |
| 3162 | #define REASSOCIATED 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */ | ||
| 3161 | #define RC_RESERVED 0 /* Reserved return code */ | 3163 | #define RC_RESERVED 0 /* Reserved return code */ |
| 3162 | #define RC_NOREASON 1 /* Unspecified reason */ | 3164 | #define RC_NOREASON 1 /* Unspecified reason */ |
| 3163 | #define RC_AUTHINV 2 /* Previous authentication invalid */ | 3165 | #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 | leaving BSS */ | 3176 | leaving BSS */ |
| 3175 | #define RC_NOAUTH 9 /* Station requesting (Re)Association is not | 3177 | #define RC_NOAUTH 9 /* Station requesting (Re)Association is not |
| 3176 | Authenticated with the responding station */ | 3178 | Authenticated with the responding station */ |
| 3177 | if (newStatus != ASSOCIATED) { | 3179 | if (newStatus == FORCELOSS && apriv->scan_timeout > 0) |
| 3178 | if (auto_wep && !apriv->expires) { | 3180 | scan_forceloss = 1; |
| 3179 | apriv->expires = RUN_AT(3*HZ); | 3181 | if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) { |
| 3180 | wake_up_interruptible(&apriv->thr_wait); | ||
| 3181 | } | ||
| 3182 | } else { | ||
| 3183 | struct task_struct *task = apriv->task; | ||
| 3184 | if (auto_wep) | 3182 | if (auto_wep) |
| 3185 | apriv->expires = 0; | 3183 | apriv->expires = 0; |
| 3186 | if (task) | 3184 | if (apriv->task) |
| 3187 | wake_up_process (task); | 3185 | wake_up_process (apriv->task); |
| 3188 | set_bit(FLAG_UPDATE_UNI, &apriv->flags); | 3186 | set_bit(FLAG_UPDATE_UNI, &apriv->flags); |
| 3189 | set_bit(FLAG_UPDATE_MULTI, &apriv->flags); | 3187 | set_bit(FLAG_UPDATE_MULTI, &apriv->flags); |
| 3190 | } | 3188 | |
| 3191 | /* Question : is ASSOCIATED the only status | ||
| 3192 | * that is valid ? We want to catch handover | ||
| 3193 | * and reassociations as valid status | ||
| 3194 | * Jean II */ | ||
| 3195 | if(newStatus == ASSOCIATED) { | ||
| 3196 | #if 0 | ||
| 3197 | /* FIXME: Grabbing scan results here | ||
| 3198 | * seems to be too early??? Just wait for | ||
| 3199 | * timeout instead. */ | ||
| 3200 | if (apriv->scan_timeout > 0) { | ||
| 3201 | set_bit(JOB_SCAN_RESULTS, &apriv->flags); | ||
| 3202 | wake_up_interruptible(&apriv->thr_wait); | ||
| 3203 | } | ||
| 3204 | #endif | ||
| 3205 | if (down_trylock(&apriv->sem) != 0) { | 3189 | if (down_trylock(&apriv->sem) != 0) { |
| 3206 | set_bit(JOB_EVENT, &apriv->flags); | 3190 | set_bit(JOB_EVENT, &apriv->flags); |
| 3207 | wake_up_interruptible(&apriv->thr_wait); | 3191 | wake_up_interruptible(&apriv->thr_wait); |
| 3208 | } else | 3192 | } else |
| 3209 | airo_send_event(dev); | 3193 | airo_send_event(dev); |
| 3210 | } else { | 3194 | } else if (!scan_forceloss) { |
| 3211 | memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); | 3195 | if (auto_wep && !apriv->expires) { |
| 3212 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 3196 | apriv->expires = RUN_AT(3*HZ); |
| 3197 | wake_up_interruptible(&apriv->thr_wait); | ||
| 3198 | } | ||
| 3213 | 3199 | ||
| 3214 | /* Send event to user space */ | 3200 | /* Send event to user space */ |
| 3201 | memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); | ||
| 3202 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
| 3215 | wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL); | 3203 | wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL); |
| 3216 | } | 3204 | } |
| 3217 | } | 3205 | } |
| @@ -7136,10 +7124,10 @@ static int airo_set_scan(struct net_device *dev, | |||
| 7136 | goto out; | 7124 | goto out; |
| 7137 | 7125 | ||
| 7138 | /* Initiate a scan command */ | 7126 | /* Initiate a scan command */ |
| 7127 | ai->scan_timeout = RUN_AT(3*HZ); | ||
| 7139 | memset(&cmd, 0, sizeof(cmd)); | 7128 | memset(&cmd, 0, sizeof(cmd)); |
| 7140 | cmd.cmd=CMD_LISTBSS; | 7129 | cmd.cmd=CMD_LISTBSS; |
| 7141 | issuecommand(ai, &cmd, &rsp); | 7130 | issuecommand(ai, &cmd, &rsp); |
| 7142 | ai->scan_timeout = RUN_AT(3*HZ); | ||
| 7143 | wake = 1; | 7131 | wake = 1; |
| 7144 | 7132 | ||
| 7145 | out: | 7133 | out: |
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 87afa6878f26..8606c88886fc 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c | |||
| @@ -3463,6 +3463,7 @@ static void atmel_command_irq(struct atmel_private *priv) | |||
| 3463 | u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); | 3463 | u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); |
| 3464 | u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); | 3464 | u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); |
| 3465 | int fast_scan; | 3465 | int fast_scan; |
| 3466 | union iwreq_data wrqu; | ||
| 3466 | 3467 | ||
| 3467 | if (status == CMD_STATUS_IDLE || | 3468 | if (status == CMD_STATUS_IDLE || |
| 3468 | status == CMD_STATUS_IN_PROGRESS) | 3469 | status == CMD_STATUS_IN_PROGRESS) |
| @@ -3487,6 +3488,7 @@ static void atmel_command_irq(struct atmel_private *priv) | |||
| 3487 | atmel_scan(priv, 1); | 3488 | atmel_scan(priv, 1); |
| 3488 | } else { | 3489 | } else { |
| 3489 | int bss_index = retrieve_bss(priv); | 3490 | int bss_index = retrieve_bss(priv); |
| 3491 | int notify_scan_complete = 1; | ||
| 3490 | if (bss_index != -1) { | 3492 | if (bss_index != -1) { |
| 3491 | atmel_join_bss(priv, bss_index); | 3493 | atmel_join_bss(priv, bss_index); |
| 3492 | } else if (priv->operating_mode == IW_MODE_ADHOC && | 3494 | } else if (priv->operating_mode == IW_MODE_ADHOC && |
| @@ -3495,8 +3497,14 @@ static void atmel_command_irq(struct atmel_private *priv) | |||
| 3495 | } else { | 3497 | } else { |
| 3496 | priv->fast_scan = !fast_scan; | 3498 | priv->fast_scan = !fast_scan; |
| 3497 | atmel_scan(priv, 1); | 3499 | atmel_scan(priv, 1); |
| 3500 | notify_scan_complete = 0; | ||
| 3498 | } | 3501 | } |
| 3499 | priv->site_survey_state = SITE_SURVEY_COMPLETED; | 3502 | priv->site_survey_state = SITE_SURVEY_COMPLETED; |
| 3503 | if (notify_scan_complete) { | ||
| 3504 | wrqu.data.length = 0; | ||
| 3505 | wrqu.data.flags = 0; | ||
| 3506 | wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); | ||
| 3507 | } | ||
| 3500 | } | 3508 | } |
| 3501 | break; | 3509 | break; |
| 3502 | 3510 | ||
| @@ -3509,6 +3517,9 @@ static void atmel_command_irq(struct atmel_private *priv) | |||
| 3509 | priv->site_survey_state = SITE_SURVEY_COMPLETED; | 3517 | priv->site_survey_state = SITE_SURVEY_COMPLETED; |
| 3510 | if (priv->station_is_associated) { | 3518 | if (priv->station_is_associated) { |
| 3511 | atmel_enter_state(priv, STATION_STATE_READY); | 3519 | atmel_enter_state(priv, STATION_STATE_READY); |
| 3520 | wrqu.data.length = 0; | ||
| 3521 | wrqu.data.flags = 0; | ||
| 3522 | wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); | ||
| 3512 | } else { | 3523 | } else { |
| 3513 | atmel_scan(priv, 1); | 3524 | atmel_scan(priv, 1); |
| 3514 | } | 3525 | } |
diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig index 418465600a77..25ea4748f0b9 100644 --- a/drivers/net/wireless/bcm43xx/Kconfig +++ b/drivers/net/wireless/bcm43xx/Kconfig | |||
| @@ -17,8 +17,11 @@ config BCM43XX_DEBUG | |||
| 17 | 17 | ||
| 18 | config BCM43XX_DMA | 18 | config BCM43XX_DMA |
| 19 | bool | 19 | bool |
| 20 | depends on BCM43XX | ||
| 21 | |||
| 20 | config BCM43XX_PIO | 22 | config BCM43XX_PIO |
| 21 | bool | 23 | bool |
| 24 | depends on BCM43XX | ||
| 22 | 25 | ||
| 23 | choice | 26 | choice |
| 24 | prompt "BCM43xx data transfer mode" | 27 | prompt "BCM43xx data transfer mode" |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index dcadd295de4f..2e83083935e1 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | 15 | ||
| 16 | #include "bcm43xx_debugfs.h" | 16 | #include "bcm43xx_debugfs.h" |
| 17 | #include "bcm43xx_leds.h" | 17 | #include "bcm43xx_leds.h" |
| 18 | #include "bcm43xx_sysfs.h" | ||
| 19 | 18 | ||
| 20 | 19 | ||
| 21 | #define PFX KBUILD_MODNAME ": " | 20 | #define PFX KBUILD_MODNAME ": " |
| @@ -638,8 +637,6 @@ struct bcm43xx_key { | |||
| 638 | }; | 637 | }; |
| 639 | 638 | ||
| 640 | struct bcm43xx_private { | 639 | struct bcm43xx_private { |
| 641 | struct bcm43xx_sysfs sysfs; | ||
| 642 | |||
| 643 | struct ieee80211_device *ieee; | 640 | struct ieee80211_device *ieee; |
| 644 | struct ieee80211softmac_device *softmac; | 641 | struct ieee80211softmac_device *softmac; |
| 645 | 642 | ||
| @@ -772,6 +769,20 @@ struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) | |||
| 772 | return ieee80211softmac_priv(dev); | 769 | return ieee80211softmac_priv(dev); |
| 773 | } | 770 | } |
| 774 | 771 | ||
| 772 | struct device; | ||
| 773 | |||
| 774 | static inline | ||
| 775 | struct bcm43xx_private * dev_to_bcm(struct device *dev) | ||
| 776 | { | ||
| 777 | struct net_device *net_dev; | ||
| 778 | struct bcm43xx_private *bcm; | ||
| 779 | |||
| 780 | net_dev = dev_get_drvdata(dev); | ||
| 781 | bcm = bcm43xx_priv(net_dev); | ||
| 782 | |||
| 783 | return bcm; | ||
| 784 | } | ||
| 785 | |||
| 775 | 786 | ||
| 776 | /* Helper function, which returns a boolean. | 787 | /* Helper function, which returns a boolean. |
| 777 | * TRUE, if PIO is used; FALSE, if DMA is used. | 788 | * TRUE, if PIO is used; FALSE, if DMA is used. |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index d2c3401e9b70..35a4fcb6d923 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | |||
| @@ -452,12 +452,12 @@ void bcm43xx_printk_dump(const char *data, | |||
| 452 | size_t i; | 452 | size_t i; |
| 453 | char c; | 453 | char c; |
| 454 | 454 | ||
| 455 | printk(KERN_INFO PFX "Data dump (%s, %u bytes):", | 455 | printk(KERN_INFO PFX "Data dump (%s, %zd bytes):", |
| 456 | description, size); | 456 | description, size); |
| 457 | for (i = 0; i < size; i++) { | 457 | for (i = 0; i < size; i++) { |
| 458 | c = data[i]; | 458 | c = data[i]; |
| 459 | if (i % 8 == 0) | 459 | if (i % 8 == 0) |
| 460 | printk("\n" KERN_INFO PFX "0x%08x: 0x%02x, ", i, c & 0xff); | 460 | printk("\n" KERN_INFO PFX "0x%08zx: 0x%02x, ", i, c & 0xff); |
| 461 | else | 461 | else |
| 462 | printk("0x%02x, ", c & 0xff); | 462 | printk("0x%02x, ", c & 0xff); |
| 463 | } | 463 | } |
| @@ -472,12 +472,12 @@ void bcm43xx_printk_bitdump(const unsigned char *data, | |||
| 472 | int j; | 472 | int j; |
| 473 | const unsigned char *d; | 473 | const unsigned char *d; |
| 474 | 474 | ||
| 475 | printk(KERN_INFO PFX "*** Bitdump (%s, %u bytes, %s) ***", | 475 | printk(KERN_INFO PFX "*** Bitdump (%s, %zd bytes, %s) ***", |
| 476 | description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB"); | 476 | description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB"); |
| 477 | for (i = 0; i < bytes; i++) { | 477 | for (i = 0; i < bytes; i++) { |
| 478 | d = data + i; | 478 | d = data + i; |
| 479 | if (i % 8 == 0) | 479 | if (i % 8 == 0) |
| 480 | printk("\n" KERN_INFO PFX "0x%08x: ", i); | 480 | printk("\n" KERN_INFO PFX "0x%08zx: ", i); |
| 481 | if (msb_to_lsb) { | 481 | if (msb_to_lsb) { |
| 482 | for (j = 7; j >= 0; j--) { | 482 | for (j = 7; j >= 0; j--) { |
| 483 | if (*d & (1 << j)) | 483 | if (*d & (1 << j)) |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index c3681b8f09b4..bbecba02e697 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c | |||
| @@ -196,8 +196,9 @@ static int alloc_ringmemory(struct bcm43xx_dmaring *ring) | |||
| 196 | } | 196 | } |
| 197 | if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) { | 197 | if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) { |
| 198 | printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G " | 198 | printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G " |
| 199 | "(0x%08x, len: %lu)\n", | 199 | "(0x%llx, len: %lu)\n", |
| 200 | ring->dmabase, BCM43xx_DMA_RINGMEMSIZE); | 200 | (unsigned long long)ring->dmabase, |
| 201 | BCM43xx_DMA_RINGMEMSIZE); | ||
| 201 | dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, | 202 | dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, |
| 202 | ring->vbase, ring->dmabase); | 203 | ring->vbase, ring->dmabase); |
| 203 | return -ENOMEM; | 204 | return -ENOMEM; |
| @@ -307,8 +308,8 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, | |||
| 307 | unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); | 308 | unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); |
| 308 | dev_kfree_skb_any(skb); | 309 | dev_kfree_skb_any(skb); |
| 309 | printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G " | 310 | printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G " |
| 310 | "(0x%08x, len: %u)\n", | 311 | "(0x%llx, len: %u)\n", |
| 311 | dmaaddr, ring->rx_buffersize); | 312 | (unsigned long long)dmaaddr, ring->rx_buffersize); |
| 312 | return -ENOMEM; | 313 | return -ENOMEM; |
| 313 | } | 314 | } |
| 314 | meta->skb = skb; | 315 | meta->skb = skb; |
| @@ -729,8 +730,8 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring, | |||
| 729 | if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) { | 730 | if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) { |
| 730 | return_slot(ring, slot); | 731 | return_slot(ring, slot); |
| 731 | printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G " | 732 | printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G " |
| 732 | "(0x%08x, len: %u)\n", | 733 | "(0x%llx, len: %u)\n", |
| 733 | meta->dmaaddr, skb->len); | 734 | (unsigned long long)meta->dmaaddr, skb->len); |
| 734 | return -ENOMEM; | 735 | return -ENOMEM; |
| 735 | } | 736 | } |
| 736 | 737 | ||
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index c37371fc9e01..9a06e61df0a2 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c | |||
| @@ -52,6 +52,7 @@ | |||
| 52 | #include "bcm43xx_wx.h" | 52 | #include "bcm43xx_wx.h" |
| 53 | #include "bcm43xx_ethtool.h" | 53 | #include "bcm43xx_ethtool.h" |
| 54 | #include "bcm43xx_xmit.h" | 54 | #include "bcm43xx_xmit.h" |
| 55 | #include "bcm43xx_sysfs.h" | ||
| 55 | 56 | ||
| 56 | 57 | ||
| 57 | MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); | 58 | MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); |
| @@ -3522,6 +3523,7 @@ static inline int bcm43xx_tx(struct bcm43xx_private *bcm, | |||
| 3522 | err = bcm43xx_pio_tx(bcm, txb); | 3523 | err = bcm43xx_pio_tx(bcm, txb); |
| 3523 | else | 3524 | else |
| 3524 | err = bcm43xx_dma_tx(bcm, txb); | 3525 | err = bcm43xx_dma_tx(bcm, txb); |
| 3526 | bcm->net_dev->trans_start = jiffies; | ||
| 3525 | 3527 | ||
| 3526 | return err; | 3528 | return err; |
| 3527 | } | 3529 | } |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 0a66f43ca0c0..33137165727f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c | |||
| @@ -2151,6 +2151,7 @@ int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm) | |||
| 2151 | phy->tssi2dbm = NULL; | 2151 | phy->tssi2dbm = NULL; |
| 2152 | printk(KERN_ERR PFX "Could not generate " | 2152 | printk(KERN_ERR PFX "Could not generate " |
| 2153 | "tssi2dBm table\n"); | 2153 | "tssi2dBm table\n"); |
| 2154 | kfree(dyn_tssi2dbm); | ||
| 2154 | return -ENODEV; | 2155 | return -ENODEV; |
| 2155 | } | 2156 | } |
| 2156 | phy->tssi2dbm = dyn_tssi2dbm; | 2157 | phy->tssi2dbm = dyn_tssi2dbm; |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.c b/drivers/net/wireless/bcm43xx/bcm43xx_power.c index 3c92b62807c5..6569da3a7a39 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_power.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.c | |||
| @@ -35,77 +35,101 @@ | |||
| 35 | #include "bcm43xx_main.h" | 35 | #include "bcm43xx_main.h" |
| 36 | 36 | ||
| 37 | 37 | ||
| 38 | /* Get the Slow Clock Source */ | ||
| 39 | static int bcm43xx_pctl_get_slowclksrc(struct bcm43xx_private *bcm) | ||
| 40 | { | ||
| 41 | u32 tmp; | ||
| 42 | int err; | ||
| 43 | |||
| 44 | assert(bcm->current_core == &bcm->core_chipcommon); | ||
| 45 | if (bcm->current_core->rev < 6) { | ||
| 46 | if (bcm->bustype == BCM43xx_BUSTYPE_PCMCIA || | ||
| 47 | bcm->bustype == BCM43xx_BUSTYPE_SB) | ||
| 48 | return BCM43xx_PCTL_CLKSRC_XTALOS; | ||
| 49 | if (bcm->bustype == BCM43xx_BUSTYPE_PCI) { | ||
| 50 | err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp); | ||
| 51 | assert(!err); | ||
| 52 | if (tmp & 0x10) | ||
| 53 | return BCM43xx_PCTL_CLKSRC_PCI; | ||
| 54 | return BCM43xx_PCTL_CLKSRC_XTALOS; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | if (bcm->current_core->rev < 10) { | ||
| 58 | tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); | ||
| 59 | tmp &= 0x7; | ||
| 60 | if (tmp == 0) | ||
| 61 | return BCM43xx_PCTL_CLKSRC_LOPWROS; | ||
| 62 | if (tmp == 1) | ||
| 63 | return BCM43xx_PCTL_CLKSRC_XTALOS; | ||
| 64 | if (tmp == 2) | ||
| 65 | return BCM43xx_PCTL_CLKSRC_PCI; | ||
| 66 | } | ||
| 67 | |||
| 68 | return BCM43xx_PCTL_CLKSRC_XTALOS; | ||
| 69 | } | ||
| 70 | |||
| 38 | /* Get max/min slowclock frequency | 71 | /* Get max/min slowclock frequency |
| 39 | * as described in http://bcm-specs.sipsolutions.net/PowerControl | 72 | * as described in http://bcm-specs.sipsolutions.net/PowerControl |
| 40 | */ | 73 | */ |
| 41 | static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, | 74 | static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, |
| 42 | int get_max) | 75 | int get_max) |
| 43 | { | 76 | { |
| 44 | int limit = 0; | 77 | int limit; |
| 78 | int clocksrc; | ||
| 45 | int divisor; | 79 | int divisor; |
| 46 | int selection; | ||
| 47 | int err; | ||
| 48 | u32 tmp; | 80 | u32 tmp; |
| 49 | struct bcm43xx_coreinfo *old_core; | ||
| 50 | 81 | ||
| 51 | if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) | 82 | assert(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL); |
| 52 | goto out; | 83 | assert(bcm->current_core == &bcm->core_chipcommon); |
| 53 | old_core = bcm->current_core; | ||
| 54 | err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); | ||
| 55 | if (err) | ||
| 56 | goto out; | ||
| 57 | 84 | ||
| 85 | clocksrc = bcm43xx_pctl_get_slowclksrc(bcm); | ||
| 58 | if (bcm->current_core->rev < 6) { | 86 | if (bcm->current_core->rev < 6) { |
| 59 | if ((bcm->bustype == BCM43xx_BUSTYPE_PCMCIA) || | 87 | switch (clocksrc) { |
| 60 | (bcm->bustype == BCM43xx_BUSTYPE_SB)) { | 88 | case BCM43xx_PCTL_CLKSRC_PCI: |
| 61 | selection = 1; | 89 | divisor = 64; |
| 90 | break; | ||
| 91 | case BCM43xx_PCTL_CLKSRC_XTALOS: | ||
| 62 | divisor = 32; | 92 | divisor = 32; |
| 63 | } else { | 93 | break; |
| 64 | err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp); | 94 | default: |
| 65 | if (err) { | 95 | assert(0); |
| 66 | printk(KERN_ERR PFX "clockfreqlimit pcicfg read failure\n"); | 96 | divisor = 1; |
| 67 | goto out_switchback; | ||
| 68 | } | ||
| 69 | if (tmp & 0x10) { | ||
| 70 | /* PCI */ | ||
| 71 | selection = 2; | ||
| 72 | divisor = 64; | ||
| 73 | } else { | ||
| 74 | /* XTAL */ | ||
| 75 | selection = 1; | ||
| 76 | divisor = 32; | ||
| 77 | } | ||
| 78 | } | 97 | } |
| 79 | } else if (bcm->current_core->rev < 10) { | 98 | } else if (bcm->current_core->rev < 10) { |
| 80 | selection = (tmp & 0x07); | 99 | switch (clocksrc) { |
| 81 | if (selection) { | 100 | case BCM43xx_PCTL_CLKSRC_LOPWROS: |
| 101 | divisor = 1; | ||
| 102 | break; | ||
| 103 | case BCM43xx_PCTL_CLKSRC_XTALOS: | ||
| 104 | case BCM43xx_PCTL_CLKSRC_PCI: | ||
| 82 | tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); | 105 | tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); |
| 83 | divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); | 106 | divisor = ((tmp & 0xFFFF0000) >> 16) + 1; |
| 84 | } else | 107 | divisor *= 4; |
| 108 | break; | ||
| 109 | default: | ||
| 110 | assert(0); | ||
| 85 | divisor = 1; | 111 | divisor = 1; |
| 112 | } | ||
| 86 | } else { | 113 | } else { |
| 87 | tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL); | 114 | tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL); |
| 88 | divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); | 115 | divisor = ((tmp & 0xFFFF0000) >> 16) + 1; |
| 89 | selection = 1; | 116 | divisor *= 4; |
| 90 | } | 117 | } |
| 91 | 118 | ||
| 92 | switch (selection) { | 119 | switch (clocksrc) { |
| 93 | case 0: | 120 | case BCM43xx_PCTL_CLKSRC_LOPWROS: |
| 94 | /* LPO */ | ||
| 95 | if (get_max) | 121 | if (get_max) |
| 96 | limit = 43000; | 122 | limit = 43000; |
| 97 | else | 123 | else |
| 98 | limit = 25000; | 124 | limit = 25000; |
| 99 | break; | 125 | break; |
| 100 | case 1: | 126 | case BCM43xx_PCTL_CLKSRC_XTALOS: |
| 101 | /* XTAL */ | ||
| 102 | if (get_max) | 127 | if (get_max) |
| 103 | limit = 20200000; | 128 | limit = 20200000; |
| 104 | else | 129 | else |
| 105 | limit = 19800000; | 130 | limit = 19800000; |
| 106 | break; | 131 | break; |
| 107 | case 2: | 132 | case BCM43xx_PCTL_CLKSRC_PCI: |
| 108 | /* PCI */ | ||
| 109 | if (get_max) | 133 | if (get_max) |
| 110 | limit = 34000000; | 134 | limit = 34000000; |
| 111 | else | 135 | else |
| @@ -113,17 +137,14 @@ static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, | |||
| 113 | break; | 137 | break; |
| 114 | default: | 138 | default: |
| 115 | assert(0); | 139 | assert(0); |
| 140 | limit = 0; | ||
| 116 | } | 141 | } |
| 117 | limit /= divisor; | 142 | limit /= divisor; |
| 118 | 143 | ||
| 119 | out_switchback: | ||
| 120 | err = bcm43xx_switch_core(bcm, old_core); | ||
| 121 | assert(err == 0); | ||
| 122 | |||
| 123 | out: | ||
| 124 | return limit; | 144 | return limit; |
| 125 | } | 145 | } |
| 126 | 146 | ||
| 147 | |||
| 127 | /* init power control | 148 | /* init power control |
| 128 | * as described in http://bcm-specs.sipsolutions.net/PowerControl | 149 | * as described in http://bcm-specs.sipsolutions.net/PowerControl |
| 129 | */ | 150 | */ |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.h b/drivers/net/wireless/bcm43xx/bcm43xx_power.h index 5f63640810bd..c966ab3a5a8c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_power.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.h | |||
| @@ -33,6 +33,15 @@ | |||
| 33 | 33 | ||
| 34 | #include <linux/types.h> | 34 | #include <linux/types.h> |
| 35 | 35 | ||
| 36 | /* Clock sources */ | ||
| 37 | enum { | ||
| 38 | /* PCI clock */ | ||
| 39 | BCM43xx_PCTL_CLKSRC_PCI, | ||
| 40 | /* Crystal slow clock oscillator */ | ||
| 41 | BCM43xx_PCTL_CLKSRC_XTALOS, | ||
| 42 | /* Low power oscillator */ | ||
| 43 | BCM43xx_PCTL_CLKSRC_LOPWROS, | ||
| 44 | }; | ||
| 36 | 45 | ||
| 37 | struct bcm43xx_private; | 46 | struct bcm43xx_private; |
| 38 | 47 | ||
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c index c44d890b949b..b438f48e891d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | |||
| @@ -71,14 +71,46 @@ static int get_boolean(const char *buf, size_t count) | |||
| 71 | return -EINVAL; | 71 | return -EINVAL; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len) | ||
| 75 | { | ||
| 76 | int i, pos = 0; | ||
| 77 | |||
| 78 | for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { | ||
| 79 | pos += snprintf(buf + pos, buf_len - pos - 1, | ||
| 80 | "%04X", swab16(sprom[i]) & 0xFFFF); | ||
| 81 | } | ||
| 82 | pos += snprintf(buf + pos, buf_len - pos - 1, "\n"); | ||
| 83 | |||
| 84 | return pos + 1; | ||
| 85 | } | ||
| 86 | |||
| 87 | static int hex2sprom(u16 *sprom, const char *dump, size_t len) | ||
| 88 | { | ||
| 89 | char tmp[5] = { 0 }; | ||
| 90 | int cnt = 0; | ||
| 91 | unsigned long parsed; | ||
| 92 | |||
| 93 | if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2) | ||
| 94 | return -EINVAL; | ||
| 95 | |||
| 96 | while (cnt < BCM43xx_SPROM_SIZE) { | ||
| 97 | memcpy(tmp, dump, 4); | ||
| 98 | dump += 4; | ||
| 99 | parsed = simple_strtoul(tmp, NULL, 16); | ||
| 100 | sprom[cnt++] = swab16((u16)parsed); | ||
| 101 | } | ||
| 102 | |||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 74 | static ssize_t bcm43xx_attr_sprom_show(struct device *dev, | 106 | static ssize_t bcm43xx_attr_sprom_show(struct device *dev, |
| 75 | struct device_attribute *attr, | 107 | struct device_attribute *attr, |
| 76 | char *buf) | 108 | char *buf) |
| 77 | { | 109 | { |
| 78 | struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); | 110 | struct bcm43xx_private *bcm = dev_to_bcm(dev); |
| 79 | u16 *sprom; | 111 | u16 *sprom; |
| 80 | unsigned long flags; | 112 | unsigned long flags; |
| 81 | int i, err; | 113 | int err; |
| 82 | 114 | ||
| 83 | if (!capable(CAP_NET_ADMIN)) | 115 | if (!capable(CAP_NET_ADMIN)) |
| 84 | return -EPERM; | 116 | return -EPERM; |
| @@ -91,55 +123,53 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev, | |||
| 91 | bcm43xx_lock_mmio(bcm, flags); | 123 | bcm43xx_lock_mmio(bcm, flags); |
| 92 | assert(bcm->initialized); | 124 | assert(bcm->initialized); |
| 93 | err = bcm43xx_sprom_read(bcm, sprom); | 125 | err = bcm43xx_sprom_read(bcm, sprom); |
| 94 | if (!err) { | 126 | if (!err) |
| 95 | for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { | 127 | err = sprom2hex(sprom, buf, PAGE_SIZE); |
| 96 | buf[i * 2] = sprom[i] & 0x00FF; | ||
| 97 | buf[i * 2 + 1] = (sprom[i] & 0xFF00) >> 8; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | bcm43xx_unlock_mmio(bcm, flags); | 128 | bcm43xx_unlock_mmio(bcm, flags); |
| 101 | kfree(sprom); | 129 | kfree(sprom); |
| 102 | 130 | ||
| 103 | return err ? err : BCM43xx_SPROM_SIZE * sizeof(u16); | 131 | return err; |
| 104 | } | 132 | } |
| 105 | 133 | ||
| 106 | static ssize_t bcm43xx_attr_sprom_store(struct device *dev, | 134 | static ssize_t bcm43xx_attr_sprom_store(struct device *dev, |
| 107 | struct device_attribute *attr, | 135 | struct device_attribute *attr, |
| 108 | const char *buf, size_t count) | 136 | const char *buf, size_t count) |
| 109 | { | 137 | { |
| 110 | struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); | 138 | struct bcm43xx_private *bcm = dev_to_bcm(dev); |
| 111 | u16 *sprom; | 139 | u16 *sprom; |
| 112 | unsigned long flags; | 140 | unsigned long flags; |
| 113 | int i, err; | 141 | int err; |
| 114 | 142 | ||
| 115 | if (!capable(CAP_NET_ADMIN)) | 143 | if (!capable(CAP_NET_ADMIN)) |
| 116 | return -EPERM; | 144 | return -EPERM; |
| 117 | 145 | ||
| 118 | if (count != BCM43xx_SPROM_SIZE * sizeof(u16)) | ||
| 119 | return -EINVAL; | ||
| 120 | sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), | 146 | sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), |
| 121 | GFP_KERNEL); | 147 | GFP_KERNEL); |
| 122 | if (!sprom) | 148 | if (!sprom) |
| 123 | return -ENOMEM; | 149 | return -ENOMEM; |
| 124 | for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { | 150 | err = hex2sprom(sprom, buf, count); |
| 125 | sprom[i] = buf[i * 2] & 0xFF; | 151 | if (err) |
| 126 | sprom[i] |= ((u16)(buf[i * 2 + 1] & 0xFF)) << 8; | 152 | goto out_kfree; |
| 127 | } | ||
| 128 | bcm43xx_lock_mmio(bcm, flags); | 153 | bcm43xx_lock_mmio(bcm, flags); |
| 129 | assert(bcm->initialized); | 154 | assert(bcm->initialized); |
| 130 | err = bcm43xx_sprom_write(bcm, sprom); | 155 | err = bcm43xx_sprom_write(bcm, sprom); |
| 131 | bcm43xx_unlock_mmio(bcm, flags); | 156 | bcm43xx_unlock_mmio(bcm, flags); |
| 157 | out_kfree: | ||
| 132 | kfree(sprom); | 158 | kfree(sprom); |
| 133 | 159 | ||
| 134 | return err ? err : count; | 160 | return err ? err : count; |
| 135 | 161 | ||
| 136 | } | 162 | } |
| 137 | 163 | ||
| 164 | static DEVICE_ATTR(sprom, 0600, | ||
| 165 | bcm43xx_attr_sprom_show, | ||
| 166 | bcm43xx_attr_sprom_store); | ||
| 167 | |||
| 138 | static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, | 168 | static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, |
| 139 | struct device_attribute *attr, | 169 | struct device_attribute *attr, |
| 140 | char *buf) | 170 | char *buf) |
| 141 | { | 171 | { |
| 142 | struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); | 172 | struct bcm43xx_private *bcm = dev_to_bcm(dev); |
| 143 | unsigned long flags; | 173 | unsigned long flags; |
| 144 | int err; | 174 | int err; |
| 145 | ssize_t count = 0; | 175 | ssize_t count = 0; |
| @@ -175,7 +205,7 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, | |||
| 175 | struct device_attribute *attr, | 205 | struct device_attribute *attr, |
| 176 | const char *buf, size_t count) | 206 | const char *buf, size_t count) |
| 177 | { | 207 | { |
| 178 | struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); | 208 | struct bcm43xx_private *bcm = dev_to_bcm(dev); |
| 179 | unsigned long flags; | 209 | unsigned long flags; |
| 180 | int err; | 210 | int err; |
| 181 | int mode; | 211 | int mode; |
| @@ -215,11 +245,15 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, | |||
| 215 | return err ? err : count; | 245 | return err ? err : count; |
| 216 | } | 246 | } |
| 217 | 247 | ||
| 248 | static DEVICE_ATTR(interference, 0644, | ||
| 249 | bcm43xx_attr_interfmode_show, | ||
| 250 | bcm43xx_attr_interfmode_store); | ||
| 251 | |||
| 218 | static ssize_t bcm43xx_attr_preamble_show(struct device *dev, | 252 | static ssize_t bcm43xx_attr_preamble_show(struct device *dev, |
| 219 | struct device_attribute *attr, | 253 | struct device_attribute *attr, |
| 220 | char *buf) | 254 | char *buf) |
| 221 | { | 255 | { |
| 222 | struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); | 256 | struct bcm43xx_private *bcm = dev_to_bcm(dev); |
| 223 | unsigned long flags; | 257 | unsigned long flags; |
| 224 | int err; | 258 | int err; |
| 225 | ssize_t count; | 259 | ssize_t count; |
| @@ -245,7 +279,7 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, | |||
| 245 | struct device_attribute *attr, | 279 | struct device_attribute *attr, |
| 246 | const char *buf, size_t count) | 280 | const char *buf, size_t count) |
| 247 | { | 281 | { |
| 248 | struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); | 282 | struct bcm43xx_private *bcm = dev_to_bcm(dev); |
| 249 | unsigned long flags; | 283 | unsigned long flags; |
| 250 | int err; | 284 | int err; |
| 251 | int value; | 285 | int value; |
| @@ -267,56 +301,41 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, | |||
| 267 | return err ? err : count; | 301 | return err ? err : count; |
| 268 | } | 302 | } |
| 269 | 303 | ||
| 304 | static DEVICE_ATTR(shortpreamble, 0644, | ||
| 305 | bcm43xx_attr_preamble_show, | ||
| 306 | bcm43xx_attr_preamble_store); | ||
| 307 | |||
| 270 | int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) | 308 | int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) |
| 271 | { | 309 | { |
| 272 | struct device *dev = &bcm->pci_dev->dev; | 310 | struct device *dev = &bcm->pci_dev->dev; |
| 273 | struct bcm43xx_sysfs *sysfs = &bcm->sysfs; | ||
| 274 | int err; | 311 | int err; |
| 275 | 312 | ||
| 276 | assert(bcm->initialized); | 313 | assert(bcm->initialized); |
| 277 | 314 | ||
| 278 | sysfs->attr_sprom.attr.name = "sprom"; | 315 | err = device_create_file(dev, &dev_attr_sprom); |
| 279 | sysfs->attr_sprom.attr.owner = THIS_MODULE; | ||
| 280 | sysfs->attr_sprom.attr.mode = 0600; | ||
| 281 | sysfs->attr_sprom.show = bcm43xx_attr_sprom_show; | ||
| 282 | sysfs->attr_sprom.store = bcm43xx_attr_sprom_store; | ||
| 283 | err = device_create_file(dev, &sysfs->attr_sprom); | ||
| 284 | if (err) | 316 | if (err) |
| 285 | goto out; | 317 | goto out; |
| 286 | 318 | err = device_create_file(dev, &dev_attr_interference); | |
| 287 | sysfs->attr_interfmode.attr.name = "interference"; | ||
| 288 | sysfs->attr_interfmode.attr.owner = THIS_MODULE; | ||
| 289 | sysfs->attr_interfmode.attr.mode = 0600; | ||
| 290 | sysfs->attr_interfmode.show = bcm43xx_attr_interfmode_show; | ||
| 291 | sysfs->attr_interfmode.store = bcm43xx_attr_interfmode_store; | ||
| 292 | err = device_create_file(dev, &sysfs->attr_interfmode); | ||
| 293 | if (err) | 319 | if (err) |
| 294 | goto err_remove_sprom; | 320 | goto err_remove_sprom; |
| 295 | 321 | err = device_create_file(dev, &dev_attr_shortpreamble); | |
| 296 | sysfs->attr_preamble.attr.name = "shortpreamble"; | ||
| 297 | sysfs->attr_preamble.attr.owner = THIS_MODULE; | ||
| 298 | sysfs->attr_preamble.attr.mode = 0600; | ||
| 299 | sysfs->attr_preamble.show = bcm43xx_attr_preamble_show; | ||
| 300 | sysfs->attr_preamble.store = bcm43xx_attr_preamble_store; | ||
| 301 | err = device_create_file(dev, &sysfs->attr_preamble); | ||
| 302 | if (err) | 322 | if (err) |
| 303 | goto err_remove_interfmode; | 323 | goto err_remove_interfmode; |
| 304 | 324 | ||
| 305 | out: | 325 | out: |
| 306 | return err; | 326 | return err; |
| 307 | err_remove_interfmode: | 327 | err_remove_interfmode: |
| 308 | device_remove_file(dev, &sysfs->attr_interfmode); | 328 | device_remove_file(dev, &dev_attr_interference); |
| 309 | err_remove_sprom: | 329 | err_remove_sprom: |
| 310 | device_remove_file(dev, &sysfs->attr_sprom); | 330 | device_remove_file(dev, &dev_attr_sprom); |
| 311 | goto out; | 331 | goto out; |
| 312 | } | 332 | } |
| 313 | 333 | ||
| 314 | void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm) | 334 | void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm) |
| 315 | { | 335 | { |
| 316 | struct device *dev = &bcm->pci_dev->dev; | 336 | struct device *dev = &bcm->pci_dev->dev; |
| 317 | struct bcm43xx_sysfs *sysfs = &bcm->sysfs; | ||
| 318 | 337 | ||
| 319 | device_remove_file(dev, &sysfs->attr_preamble); | 338 | device_remove_file(dev, &dev_attr_shortpreamble); |
| 320 | device_remove_file(dev, &sysfs->attr_interfmode); | 339 | device_remove_file(dev, &dev_attr_interference); |
| 321 | device_remove_file(dev, &sysfs->attr_sprom); | 340 | device_remove_file(dev, &dev_attr_sprom); |
| 322 | } | 341 | } |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h index 57f14514e3e0..cc701df71e2a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h | |||
| @@ -1,22 +1,6 @@ | |||
| 1 | #ifndef BCM43xx_SYSFS_H_ | 1 | #ifndef BCM43xx_SYSFS_H_ |
| 2 | #define BCM43xx_SYSFS_H_ | 2 | #define BCM43xx_SYSFS_H_ |
| 3 | 3 | ||
| 4 | #include <linux/device.h> | ||
| 5 | |||
| 6 | |||
| 7 | struct bcm43xx_sysfs { | ||
| 8 | struct device_attribute attr_sprom; | ||
| 9 | struct device_attribute attr_interfmode; | ||
| 10 | struct device_attribute attr_preamble; | ||
| 11 | }; | ||
| 12 | |||
| 13 | #define devattr_to_bcm(attr, attr_name) ({ \ | ||
| 14 | struct bcm43xx_sysfs *__s; struct bcm43xx_private *__p; \ | ||
| 15 | __s = container_of((attr), struct bcm43xx_sysfs, attr_name); \ | ||
| 16 | __p = container_of(__s, struct bcm43xx_private, sysfs); \ | ||
| 17 | __p; \ | ||
| 18 | }) | ||
| 19 | |||
| 20 | struct bcm43xx_private; | 4 | struct bcm43xx_private; |
| 21 | 5 | ||
| 22 | int bcm43xx_sysfs_register(struct bcm43xx_private *bcm); | 6 | int bcm43xx_sysfs_register(struct bcm43xx_private *bcm); |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 3daee828ef4b..3edbb481a0a0 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c | |||
| @@ -962,22 +962,22 @@ static const struct iw_priv_args bcm43xx_priv_wx_args[] = { | |||
| 962 | { | 962 | { |
| 963 | .cmd = PRIV_WX_SET_SHORTPREAMBLE, | 963 | .cmd = PRIV_WX_SET_SHORTPREAMBLE, |
| 964 | .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | 964 | .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, |
| 965 | .name = "set_shortpreambl", | 965 | .name = "set_shortpreamb", |
| 966 | }, | 966 | }, |
| 967 | { | 967 | { |
| 968 | .cmd = PRIV_WX_GET_SHORTPREAMBLE, | 968 | .cmd = PRIV_WX_GET_SHORTPREAMBLE, |
| 969 | .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, | 969 | .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, |
| 970 | .name = "get_shortpreambl", | 970 | .name = "get_shortpreamb", |
| 971 | }, | 971 | }, |
| 972 | { | 972 | { |
| 973 | .cmd = PRIV_WX_SET_SWENCRYPTION, | 973 | .cmd = PRIV_WX_SET_SWENCRYPTION, |
| 974 | .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | 974 | .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, |
| 975 | .name = "set_swencryption", | 975 | .name = "set_swencrypt", |
| 976 | }, | 976 | }, |
| 977 | { | 977 | { |
| 978 | .cmd = PRIV_WX_GET_SWENCRYPTION, | 978 | .cmd = PRIV_WX_GET_SWENCRYPTION, |
| 979 | .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, | 979 | .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, |
| 980 | .name = "get_swencryption", | 980 | .name = "get_swencrypt", |
| 981 | }, | 981 | }, |
| 982 | { | 982 | { |
| 983 | .cmd = PRIV_WX_SPROM_WRITE, | 983 | .cmd = PRIV_WX_SPROM_WRITE, |
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 8dfdfbd5966c..06523e2a8471 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c | |||
| @@ -390,7 +390,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) | |||
| 390 | } | 390 | } |
| 391 | } else { | 391 | } else { |
| 392 | struct { | 392 | struct { |
| 393 | __le16 qual, signal, noise; | 393 | __le16 qual, signal, noise, unused; |
| 394 | } __attribute__ ((packed)) cq; | 394 | } __attribute__ ((packed)) cq; |
| 395 | 395 | ||
| 396 | err = HERMES_READ_RECORD(hw, USER_BAP, | 396 | err = HERMES_READ_RECORD(hw, USER_BAP, |
diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h index b971d8c82bdd..6b3693f05ca0 100644 --- a/include/net/ieee80211softmac.h +++ b/include/net/ieee80211softmac.h | |||
| @@ -267,8 +267,9 @@ extern void ieee80211softmac_stop(struct net_device *dev); | |||
| 267 | #define IEEE80211SOFTMAC_EVENT_AUTH_FAILED 5 | 267 | #define IEEE80211SOFTMAC_EVENT_AUTH_FAILED 5 |
| 268 | #define IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT 6 | 268 | #define IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT 6 |
| 269 | #define IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND 7 | 269 | #define IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND 7 |
| 270 | #define IEEE80211SOFTMAC_EVENT_DISASSOCIATED 8 | ||
| 270 | /* keep this updated! */ | 271 | /* keep this updated! */ |
| 271 | #define IEEE80211SOFTMAC_EVENT_LAST 7 | 272 | #define IEEE80211SOFTMAC_EVENT_LAST 8 |
| 272 | /* | 273 | /* |
| 273 | * If you want to be notified of certain events, you can call | 274 | * If you want to be notified of certain events, you can call |
| 274 | * ieee80211softmac_notify[_atomic] with | 275 | * ieee80211softmac_notify[_atomic] with |
diff --git a/net/core/dev.c b/net/core/dev.c index 83231a27ae02..3bad1afc89fa 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -2698,7 +2698,8 @@ int dev_ioctl(unsigned int cmd, void __user *arg) | |||
| 2698 | /* If command is `set a parameter', or | 2698 | /* If command is `set a parameter', or |
| 2699 | * `get the encoding parameters', check if | 2699 | * `get the encoding parameters', check if |
| 2700 | * the user has the right to do it */ | 2700 | * the user has the right to do it */ |
| 2701 | if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE) { | 2701 | if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE |
| 2702 | || cmd == SIOCGIWENCODEEXT) { | ||
| 2702 | if (!capable(CAP_NET_ADMIN)) | 2703 | if (!capable(CAP_NET_ADMIN)) |
| 2703 | return -EPERM; | 2704 | return -EPERM; |
| 2704 | } | 2705 | } |
diff --git a/net/core/wireless.c b/net/core/wireless.c index 81d6995fcfdb..d2bc72d318f7 100644 --- a/net/core/wireless.c +++ b/net/core/wireless.c | |||
| @@ -1726,6 +1726,14 @@ int wireless_rtnetlink_get(struct net_device * dev, | |||
| 1726 | if(!IW_IS_GET(request->cmd)) | 1726 | if(!IW_IS_GET(request->cmd)) |
| 1727 | return -EOPNOTSUPP; | 1727 | return -EOPNOTSUPP; |
| 1728 | 1728 | ||
| 1729 | /* If command is `get the encoding parameters', check if | ||
| 1730 | * the user has the right to do it */ | ||
| 1731 | if (request->cmd == SIOCGIWENCODE || | ||
| 1732 | request->cmd == SIOCGIWENCODEEXT) { | ||
| 1733 | if (!capable(CAP_NET_ADMIN)) | ||
| 1734 | return -EPERM; | ||
| 1735 | } | ||
| 1736 | |||
| 1729 | /* Special cases */ | 1737 | /* Special cases */ |
| 1730 | if(request->cmd == SIOCGIWSTATS) | 1738 | if(request->cmd == SIOCGIWSTATS) |
| 1731 | /* Get Wireless Stats */ | 1739 | /* Get Wireless Stats */ |
diff --git a/net/ieee80211/softmac/Kconfig b/net/ieee80211/softmac/Kconfig index 6cd9f3427be6..f2a27cc6ecb1 100644 --- a/net/ieee80211/softmac/Kconfig +++ b/net/ieee80211/softmac/Kconfig | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | config IEEE80211_SOFTMAC | 1 | config IEEE80211_SOFTMAC |
| 2 | tristate "Software MAC add-on to the IEEE 802.11 networking stack" | 2 | tristate "Software MAC add-on to the IEEE 802.11 networking stack" |
| 3 | depends on IEEE80211 && EXPERIMENTAL | 3 | depends on IEEE80211 && EXPERIMENTAL |
| 4 | select WIRELESS_EXT | ||
| 4 | ---help--- | 5 | ---help--- |
| 5 | This option enables the hardware independent software MAC addon | 6 | This option enables the hardware independent software MAC addon |
| 6 | for the IEEE 802.11 networking stack. | 7 | for the IEEE 802.11 networking stack. |
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c index be61de78dfa4..4498023841dc 100644 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c | |||
| @@ -101,6 +101,7 @@ ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason) | |||
| 101 | /* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */ | 101 | /* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */ |
| 102 | mac->associated = 0; | 102 | mac->associated = 0; |
| 103 | mac->associnfo.associating = 0; | 103 | mac->associnfo.associating = 0; |
| 104 | ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL); | ||
| 104 | spin_unlock_irqrestore(&mac->lock, flags); | 105 | spin_unlock_irqrestore(&mac->lock, flags); |
| 105 | } | 106 | } |
| 106 | 107 | ||
| @@ -373,6 +374,7 @@ ieee80211softmac_handle_disassoc(struct net_device * dev, | |||
| 373 | spin_lock_irqsave(&mac->lock, flags); | 374 | spin_lock_irqsave(&mac->lock, flags); |
| 374 | mac->associnfo.bssvalid = 0; | 375 | mac->associnfo.bssvalid = 0; |
| 375 | mac->associated = 0; | 376 | mac->associated = 0; |
| 377 | ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL); | ||
| 376 | schedule_work(&mac->associnfo.work); | 378 | schedule_work(&mac->associnfo.work); |
| 377 | spin_unlock_irqrestore(&mac->lock, flags); | 379 | spin_unlock_irqrestore(&mac->lock, flags); |
| 378 | 380 | ||
| @@ -391,6 +393,7 @@ ieee80211softmac_handle_reassoc_req(struct net_device * dev, | |||
| 391 | dprintkl(KERN_INFO PFX "reassoc request from unknown network\n"); | 393 | dprintkl(KERN_INFO PFX "reassoc request from unknown network\n"); |
| 392 | return 0; | 394 | return 0; |
| 393 | } | 395 | } |
| 394 | ieee80211softmac_assoc(mac, network); | 396 | schedule_work(&mac->associnfo.work); |
| 397 | |||
| 395 | return 0; | 398 | return 0; |
| 396 | } | 399 | } |
diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c index 0a52bbda1e4c..8cc8f3f0f8e7 100644 --- a/net/ieee80211/softmac/ieee80211softmac_event.c +++ b/net/ieee80211/softmac/ieee80211softmac_event.c | |||
| @@ -67,6 +67,7 @@ static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = { | |||
| 67 | "authenticating failed", | 67 | "authenticating failed", |
| 68 | "authenticating timed out", | 68 | "authenticating timed out", |
| 69 | "associating failed because no suitable network was found", | 69 | "associating failed because no suitable network was found", |
| 70 | "disassociated", | ||
| 70 | }; | 71 | }; |
| 71 | 72 | ||
| 72 | 73 | ||
| @@ -128,13 +129,42 @@ void | |||
| 128 | ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx) | 129 | ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx) |
| 129 | { | 130 | { |
| 130 | struct ieee80211softmac_event *eventptr, *tmp; | 131 | struct ieee80211softmac_event *eventptr, *tmp; |
| 131 | union iwreq_data wrqu; | 132 | struct ieee80211softmac_network *network; |
| 132 | char *msg; | ||
| 133 | 133 | ||
| 134 | if (event >= 0) { | 134 | if (event >= 0) { |
| 135 | msg = event_descriptions[event]; | 135 | union iwreq_data wrqu; |
| 136 | wrqu.data.length = strlen(msg); | 136 | int we_event; |
| 137 | wireless_send_event(mac->dev, IWEVCUSTOM, &wrqu, msg); | 137 | char *msg = NULL; |
| 138 | |||
| 139 | switch(event) { | ||
| 140 | case IEEE80211SOFTMAC_EVENT_ASSOCIATED: | ||
| 141 | network = (struct ieee80211softmac_network *)event_ctx; | ||
| 142 | wrqu.data.length = 0; | ||
| 143 | wrqu.data.flags = 0; | ||
| 144 | memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN); | ||
| 145 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
| 146 | we_event = SIOCGIWAP; | ||
| 147 | break; | ||
| 148 | case IEEE80211SOFTMAC_EVENT_DISASSOCIATED: | ||
| 149 | wrqu.data.length = 0; | ||
| 150 | wrqu.data.flags = 0; | ||
| 151 | memset(&wrqu, '\0', sizeof (union iwreq_data)); | ||
| 152 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
| 153 | we_event = SIOCGIWAP; | ||
| 154 | break; | ||
| 155 | case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED: | ||
| 156 | wrqu.data.length = 0; | ||
| 157 | wrqu.data.flags = 0; | ||
| 158 | memset(&wrqu, '\0', sizeof (union iwreq_data)); | ||
| 159 | we_event = SIOCGIWSCAN; | ||
| 160 | break; | ||
| 161 | default: | ||
| 162 | msg = event_descriptions[event]; | ||
| 163 | wrqu.data.length = strlen(msg); | ||
| 164 | we_event = IWEVCUSTOM; | ||
| 165 | break; | ||
| 166 | } | ||
| 167 | wireless_send_event(mac->dev, we_event, &wrqu, msg); | ||
| 138 | } | 168 | } |
| 139 | 169 | ||
| 140 | if (!list_empty(&mac->events)) | 170 | if (!list_empty(&mac->events)) |
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c index febc51dbb412..cc6cd56c85b1 100644 --- a/net/ieee80211/softmac/ieee80211softmac_io.c +++ b/net/ieee80211/softmac/ieee80211softmac_io.c | |||
| @@ -180,9 +180,21 @@ ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt, | |||
| 180 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid); | 180 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid); |
| 181 | 181 | ||
| 182 | /* Fill in capability Info */ | 182 | /* Fill in capability Info */ |
| 183 | (*pkt)->capability = (mac->ieee->iw_mode == IW_MODE_MASTER) || (mac->ieee->iw_mode == IW_MODE_INFRA) ? | 183 | switch (mac->ieee->iw_mode) { |
| 184 | cpu_to_le16(WLAN_CAPABILITY_ESS) : | 184 | case IW_MODE_INFRA: |
| 185 | cpu_to_le16(WLAN_CAPABILITY_IBSS); | 185 | (*pkt)->capability = cpu_to_le16(WLAN_CAPABILITY_ESS); |
| 186 | break; | ||
| 187 | case IW_MODE_ADHOC: | ||
| 188 | (*pkt)->capability = cpu_to_le16(WLAN_CAPABILITY_IBSS); | ||
| 189 | break; | ||
| 190 | case IW_MODE_AUTO: | ||
| 191 | (*pkt)->capability = net->capabilities & (WLAN_CAPABILITY_ESS|WLAN_CAPABILITY_IBSS); | ||
| 192 | break; | ||
| 193 | default: | ||
| 194 | /* bleh. we don't ever go to these modes */ | ||
| 195 | printk(KERN_ERR PFX "invalid iw_mode!\n"); | ||
| 196 | break; | ||
| 197 | } | ||
| 186 | /* Need to add this | 198 | /* Need to add this |
| 187 | (*pkt)->capability |= mac->ieee->short_slot ? | 199 | (*pkt)->capability |= mac->ieee->short_slot ? |
| 188 | cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0; | 200 | cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0; |
diff --git a/net/ieee80211/softmac/ieee80211softmac_scan.c b/net/ieee80211/softmac/ieee80211softmac_scan.c index bb9ab8b45d09..2b9e7edfa3ce 100644 --- a/net/ieee80211/softmac/ieee80211softmac_scan.c +++ b/net/ieee80211/softmac/ieee80211softmac_scan.c | |||
| @@ -47,6 +47,7 @@ ieee80211softmac_start_scan(struct ieee80211softmac_device *sm) | |||
| 47 | sm->scanning = 1; | 47 | sm->scanning = 1; |
| 48 | spin_unlock_irqrestore(&sm->lock, flags); | 48 | spin_unlock_irqrestore(&sm->lock, flags); |
| 49 | 49 | ||
| 50 | netif_tx_disable(sm->ieee->dev); | ||
| 50 | ret = sm->start_scan(sm->dev); | 51 | ret = sm->start_scan(sm->dev); |
| 51 | if (ret) { | 52 | if (ret) { |
| 52 | spin_lock_irqsave(&sm->lock, flags); | 53 | spin_lock_irqsave(&sm->lock, flags); |
| @@ -239,6 +240,7 @@ void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm) | |||
| 239 | if (net) | 240 | if (net) |
| 240 | sm->set_channel(sm->dev, net->channel); | 241 | sm->set_channel(sm->dev, net->channel); |
| 241 | } | 242 | } |
| 243 | netif_wake_queue(sm->ieee->dev); | ||
| 242 | ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL); | 244 | ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL); |
| 243 | } | 245 | } |
| 244 | EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished); | 246 | EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished); |
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c index b559aa9b5507..00f0d4f71897 100644 --- a/net/ieee80211/softmac/ieee80211softmac_wx.c +++ b/net/ieee80211/softmac/ieee80211softmac_wx.c | |||
| @@ -41,13 +41,23 @@ ieee80211softmac_wx_trigger_scan(struct net_device *net_dev, | |||
| 41 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan); | 41 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan); |
| 42 | 42 | ||
| 43 | 43 | ||
| 44 | /* if we're still scanning, return -EAGAIN so that userspace tools | ||
| 45 | * can get the complete scan results, otherwise return 0. */ | ||
| 44 | int | 46 | int |
| 45 | ieee80211softmac_wx_get_scan_results(struct net_device *net_dev, | 47 | ieee80211softmac_wx_get_scan_results(struct net_device *net_dev, |
| 46 | struct iw_request_info *info, | 48 | struct iw_request_info *info, |
| 47 | union iwreq_data *data, | 49 | union iwreq_data *data, |
| 48 | char *extra) | 50 | char *extra) |
| 49 | { | 51 | { |
| 52 | unsigned long flags; | ||
| 50 | struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); | 53 | struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); |
| 54 | |||
| 55 | spin_lock_irqsave(&sm->lock, flags); | ||
| 56 | if (sm->scanning) { | ||
| 57 | spin_unlock_irqrestore(&sm->lock, flags); | ||
| 58 | return -EAGAIN; | ||
| 59 | } | ||
| 60 | spin_unlock_irqrestore(&sm->lock, flags); | ||
| 51 | return ieee80211_wx_get_scan(sm->ieee, info, data, extra); | 61 | return ieee80211_wx_get_scan(sm->ieee, info, data, extra); |
| 52 | } | 62 | } |
| 53 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results); | 63 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results); |
