X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Fipw2200.c;h=22cb3fb7502e280a16a4d5e73f95bb42482ead3a;hb=refs%2Fheads%2Fvserver;hp=f42e51a7bca76e40e6ddc3a3bbc31fb3cd647476;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index f42e51a7b..22cb3fb75 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. + Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. 802.11 status code portion of this file from ethereal-0.10.6: Copyright 2000, Axis Communications AB @@ -33,9 +33,46 @@ #include "ipw2200.h" #include -#define IPW2200_VERSION "git-1.0.8" + +#ifndef KBUILD_EXTMOD +#define VK "k" +#else +#define VK +#endif + +#ifdef CONFIG_IPW2200_DEBUG +#define VD "d" +#else +#define VD +#endif + +#ifdef CONFIG_IPW2200_MONITOR +#define VM "m" +#else +#define VM +#endif + +#ifdef CONFIG_IPW2200_PROMISCUOUS +#define VP "p" +#else +#define VP +#endif + +#ifdef CONFIG_IPW2200_RADIOTAP +#define VR "r" +#else +#define VR +#endif + +#ifdef CONFIG_IPW2200_QOS +#define VQ "q" +#else +#define VQ +#endif + +#define IPW2200_VERSION "1.2.0" VK VD VM VP VR VQ #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" -#define DRV_COPYRIGHT "Copyright(c) 2003-2005 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation" #define DRV_VERSION IPW2200_VERSION #define ETH_P_80211_STATS (ETH_P_80211_RAW + 1) @@ -55,12 +92,20 @@ static int associate = 1; static int auto_create = 1; static int led = 0; static int disable = 0; -static int hwcrypto = 1; +static int bt_coexist = 0; +static int hwcrypto = 0; +static int roaming = 1; static const char ipw_modes[] = { 'a', 'b', 'g', '?' }; +static int antenna = CFG_SYS_ANTENNA_BOTH; + +#ifdef CONFIG_IPW2200_PROMISCUOUS +static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */ +#endif + -#ifdef CONFIG_IPW_QOS +#ifdef CONFIG_IPW2200_QOS static int qos_enable = 0; static int qos_burst_enable = 0; static int qos_no_ack_mask = 0; @@ -124,7 +169,7 @@ static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_q *qos_param); static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element *qos_param); -#endif /* CONFIG_IPW_QOS */ +#endif /* CONFIG_IPW2200_QOS */ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev); static void ipw_remove_current_network(struct ipw_priv *priv); @@ -142,21 +187,15 @@ static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *); static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *); static void ipw_rx_queue_replenish(void *); static int ipw_up(struct ipw_priv *); -static void ipw_bg_up(void *); +static void ipw_bg_up(struct work_struct *work); static void ipw_down(struct ipw_priv *); -static void ipw_bg_down(void *); +static void ipw_bg_down(struct work_struct *work); static int ipw_config(struct ipw_priv *); static int init_supported_rates(struct ipw_priv *priv, struct ipw_supported_rates *prates); static void ipw_set_hwcrypto_keys(struct ipw_priv *); static void ipw_send_wep_keys(struct ipw_priv *, int); -static int ipw_is_valid_channel(struct ieee80211_device *, u8); -static int ipw_channel_to_index(struct ieee80211_device *, u8); -static u8 ipw_freq_to_channel(struct ieee80211_device *, u32); -static int ipw_set_geo(struct ieee80211_device *, const struct ieee80211_geo *); -static const struct ieee80211_geo *ipw_get_geo(struct ieee80211_device *); - static int snprint_line(char *buf, size_t count, const u8 * data, u32 len, u32 ofs) { @@ -227,12 +266,15 @@ static int snprintk_buf(u8 * output, size_t size, const u8 * data, size_t len) return total; } +/* alias for 32-bit indirect read (for SRAM/reg above 4K), with debug wrapper */ static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg); #define ipw_read_reg32(a, b) _ipw_read_reg32(a, b) +/* alias for 8-bit indirect read (for SRAM/reg above 4K), with debug wrapper */ static u8 _ipw_read_reg8(struct ipw_priv *ipw, u32 reg); #define ipw_read_reg8(a, b) _ipw_read_reg8(a, b) +/* 8-bit indirect write (for SRAM/reg above 4K), with debug wrapper */ static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value); static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c) { @@ -241,6 +283,7 @@ static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c) _ipw_write_reg8(a, b, c); } +/* 16-bit indirect write (for SRAM/reg above 4K), with debug wrapper */ static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value); static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c) { @@ -249,6 +292,7 @@ static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c) _ipw_write_reg16(a, b, c); } +/* 32-bit indirect write (for SRAM/reg above 4K), with debug wrapper */ static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value); static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c) { @@ -257,48 +301,70 @@ static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c) _ipw_write_reg32(a, b, c); } +/* 8-bit direct write (low 4K) */ #define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs)) + +/* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ #define ipw_write8(ipw, ofs, val) \ IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ _ipw_write8(ipw, ofs, val) +/* 16-bit direct write (low 4K) */ #define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs)) + +/* 16-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ #define ipw_write16(ipw, ofs, val) \ IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ _ipw_write16(ipw, ofs, val) +/* 32-bit direct write (low 4K) */ #define _ipw_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs)) + +/* 32-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ #define ipw_write32(ipw, ofs, val) \ IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ _ipw_write32(ipw, ofs, val) +/* 8-bit direct read (low 4K) */ #define _ipw_read8(ipw, ofs) readb((ipw)->hw_base + (ofs)) + +/* 8-bit direct read (low 4K), with debug wrapper */ static inline u8 __ipw_read8(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) { IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", f, l, (u32) (ofs)); return _ipw_read8(ipw, ofs); } +/* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */ #define ipw_read8(ipw, ofs) __ipw_read8(__FILE__, __LINE__, ipw, ofs) +/* 16-bit direct read (low 4K) */ #define _ipw_read16(ipw, ofs) readw((ipw)->hw_base + (ofs)) + +/* 16-bit direct read (low 4K), with debug wrapper */ static inline u16 __ipw_read16(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) { IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", f, l, (u32) (ofs)); return _ipw_read16(ipw, ofs); } +/* alias to 16-bit direct read (low 4K of SRAM/regs), with debug wrapper */ #define ipw_read16(ipw, ofs) __ipw_read16(__FILE__, __LINE__, ipw, ofs) +/* 32-bit direct read (low 4K) */ #define _ipw_read32(ipw, ofs) readl((ipw)->hw_base + (ofs)) + +/* 32-bit direct read (low 4K), with debug wrapper */ static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) { IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", f, l, (u32) (ofs)); return _ipw_read32(ipw, ofs); } +/* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */ #define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs) +/* multi-byte read (above 4K), with debug wrapper */ static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int); static inline void __ipw_read_indirect(const char *f, int l, struct ipw_priv *a, u32 b, u8 * c, int d) @@ -308,15 +374,17 @@ static inline void __ipw_read_indirect(const char *f, int l, _ipw_read_indirect(a, b, c, d); } +/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */ #define ipw_read_indirect(a, b, c, d) __ipw_read_indirect(__FILE__, __LINE__, a, b, c, d) +/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */ static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data, int num); #define ipw_write_indirect(a, b, c, d) \ IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ _ipw_write_indirect(a, b, c, d) -/* indirect write s */ +/* 32-bit indirect write (above 4K) */ static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value) { IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value); @@ -324,22 +392,29 @@ static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value) _ipw_write32(priv, IPW_INDIRECT_DATA, value); } +/* 8-bit indirect write (above 4K) */ static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value) { + u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ + u32 dif_len = reg - aligned_addr; + IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); - _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK); - _ipw_write8(priv, IPW_INDIRECT_DATA, value); + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); + _ipw_write8(priv, IPW_INDIRECT_DATA + dif_len, value); } +/* 16-bit indirect write (above 4K) */ static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value) { + u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ + u32 dif_len = (reg - aligned_addr) & (~0x1ul); + IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); - _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK); - _ipw_write16(priv, IPW_INDIRECT_DATA, value); + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); + _ipw_write16(priv, IPW_INDIRECT_DATA + dif_len, value); } -/* indirect read s */ - +/* 8-bit indirect read (above 4K) */ static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg) { u32 word; @@ -349,6 +424,7 @@ static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg) return (word >> ((reg & 0x3) * 8)) & 0xff; } +/* 32-bit indirect read (above 4K) */ static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg) { u32 value; @@ -361,11 +437,12 @@ static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg) return value; } -/* iterative/auto-increment 32 bit reads and writes */ +/* General purpose, no alignment requirement, iterative (multi-byte) read, */ +/* for area above 1st 4K of SRAM/reg space */ static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, int num) { - u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; + u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */ u32 dif_len = addr - aligned_addr; u32 i; @@ -375,7 +452,7 @@ static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, return; } - /* Read the first nibble byte by byte */ + /* Read the first dword (or portion) byte by byte */ if (unlikely(dif_len)) { _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); /* Start reading at aligned_addr + dif_len */ @@ -384,11 +461,12 @@ static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, aligned_addr += 4; } + /* Read all of the middle dwords as dwords, with auto-increment */ _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr); for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) *(u32 *) buf = _ipw_read32(priv, IPW_AUTOINC_DATA); - /* Copy the last nibble */ + /* Read the last dword (or portion) byte by byte */ if (unlikely(num)) { _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); for (i = 0; num > 0; i++, num--) @@ -396,10 +474,12 @@ static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, } } +/* General purpose, no alignment requirement, iterative (multi-byte) write, */ +/* for area above 1st 4K of SRAM/reg space */ static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, int num) { - u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; + u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */ u32 dif_len = addr - aligned_addr; u32 i; @@ -409,20 +489,21 @@ static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, return; } - /* Write the first nibble byte by byte */ + /* Write the first dword (or portion) byte by byte */ if (unlikely(dif_len)) { _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); - /* Start reading at aligned_addr + dif_len */ + /* Start writing at aligned_addr + dif_len */ for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++) _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf); aligned_addr += 4; } + /* Write all of the middle dwords as dwords, with auto-increment */ _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr); for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) _ipw_write32(priv, IPW_AUTOINC_DATA, *(u32 *) buf); - /* Copy the last nibble */ + /* Write the last dword (or portion) byte by byte */ if (unlikely(num)) { _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); for (i = 0; num > 0; i++, num--, buf++) @@ -430,23 +511,27 @@ static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, } } +/* General purpose, no alignment requirement, iterative (multi-byte) write, */ +/* for 1st 4K of SRAM/regs space */ static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf, int num) { memcpy_toio((priv->hw_base + addr), buf, num); } +/* Set bit(s) in low 4K of SRAM/regs */ static inline void ipw_set_bit(struct ipw_priv *priv, u32 reg, u32 mask) { ipw_write32(priv, reg, ipw_read32(priv, reg) | mask); } +/* Clear bit(s) in low 4K of SRAM/regs */ static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask) { ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask); } -static inline void ipw_enable_interrupts(struct ipw_priv *priv) +static inline void __ipw_enable_interrupts(struct ipw_priv *priv) { if (priv->status & STATUS_INT_ENABLED) return; @@ -454,7 +539,7 @@ static inline void ipw_enable_interrupts(struct ipw_priv *priv) ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL); } -static inline void ipw_disable_interrupts(struct ipw_priv *priv) +static inline void __ipw_disable_interrupts(struct ipw_priv *priv) { if (!(priv->status & STATUS_INT_ENABLED)) return; @@ -462,7 +547,24 @@ static inline void ipw_disable_interrupts(struct ipw_priv *priv) ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); } -#ifdef CONFIG_IPW2200_DEBUG +static inline void ipw_enable_interrupts(struct ipw_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + __ipw_enable_interrupts(priv); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + +static inline void ipw_disable_interrupts(struct ipw_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->irq_lock, flags); + __ipw_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->irq_lock, flags); +} + static char *ipw_error_desc(u32 val) { switch (val) { @@ -529,7 +631,6 @@ static void ipw_dump_error_log(struct ipw_priv *priv, error->log[i].time, error->log[i].data, error->log[i].event); } -#endif static inline int ipw_is_init(struct ipw_priv *priv) { @@ -701,7 +802,7 @@ static void ipw_init_ordinals(struct ipw_priv *priv) } -u32 ipw_register_toggle(u32 reg) +static u32 ipw_register_toggle(u32 reg) { reg &= ~IPW_START_STANDBY; if (reg & IPW_GATE_ODMA) @@ -722,11 +823,11 @@ u32 ipw_register_toggle(u32 reg) * - On radio OFF, turn off any LEDs started during radio on * */ -#define LD_TIME_LINK_ON 300 -#define LD_TIME_LINK_OFF 2700 -#define LD_TIME_ACT_ON 250 +#define LD_TIME_LINK_ON msecs_to_jiffies(300) +#define LD_TIME_LINK_OFF msecs_to_jiffies(2700) +#define LD_TIME_ACT_ON msecs_to_jiffies(250) -void ipw_led_link_on(struct ipw_priv *priv) +static void ipw_led_link_on(struct ipw_priv *priv) { unsigned long flags; u32 led; @@ -761,15 +862,16 @@ void ipw_led_link_on(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void ipw_bg_led_link_on(void *data) +static void ipw_bg_led_link_on(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_led_link_on(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, led_link_on.work); + mutex_lock(&priv->mutex); + ipw_led_link_on(priv); + mutex_unlock(&priv->mutex); } -void ipw_led_link_off(struct ipw_priv *priv) +static void ipw_led_link_off(struct ipw_priv *priv) { unsigned long flags; u32 led; @@ -805,12 +907,13 @@ void ipw_led_link_off(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void ipw_bg_led_link_off(void *data) +static void ipw_bg_led_link_off(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_led_link_off(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, led_link_off.work); + mutex_lock(&priv->mutex); + ipw_led_link_off(priv); + mutex_unlock(&priv->mutex); } static void __ipw_led_activity_on(struct ipw_priv *priv) @@ -847,6 +950,7 @@ static void __ipw_led_activity_on(struct ipw_priv *priv) } } +#if 0 void ipw_led_activity_on(struct ipw_priv *priv) { unsigned long flags; @@ -854,8 +958,9 @@ void ipw_led_activity_on(struct ipw_priv *priv) __ipw_led_activity_on(priv); spin_unlock_irqrestore(&priv->lock, flags); } +#endif /* 0 */ -void ipw_led_activity_off(struct ipw_priv *priv) +static void ipw_led_activity_off(struct ipw_priv *priv) { unsigned long flags; u32 led; @@ -882,15 +987,16 @@ void ipw_led_activity_off(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void ipw_bg_led_activity_off(void *data) +static void ipw_bg_led_activity_off(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_led_activity_off(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, led_act_off.work); + mutex_lock(&priv->mutex); + ipw_led_activity_off(priv); + mutex_unlock(&priv->mutex); } -void ipw_led_band_on(struct ipw_priv *priv) +static void ipw_led_band_on(struct ipw_priv *priv) { unsigned long flags; u32 led; @@ -925,7 +1031,7 @@ void ipw_led_band_on(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -void ipw_led_band_off(struct ipw_priv *priv) +static void ipw_led_band_off(struct ipw_priv *priv) { unsigned long flags; u32 led; @@ -948,24 +1054,24 @@ void ipw_led_band_off(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -void ipw_led_radio_on(struct ipw_priv *priv) +static void ipw_led_radio_on(struct ipw_priv *priv) { ipw_led_link_on(priv); } -void ipw_led_radio_off(struct ipw_priv *priv) +static void ipw_led_radio_off(struct ipw_priv *priv) { ipw_led_activity_off(priv); ipw_led_link_off(priv); } -void ipw_led_link_up(struct ipw_priv *priv) +static void ipw_led_link_up(struct ipw_priv *priv) { /* Set the Link Led on for all nic types */ ipw_led_link_on(priv); } -void ipw_led_link_down(struct ipw_priv *priv) +static void ipw_led_link_down(struct ipw_priv *priv) { ipw_led_activity_off(priv); ipw_led_link_off(priv); @@ -974,7 +1080,7 @@ void ipw_led_link_down(struct ipw_priv *priv) ipw_led_radio_off(priv); } -void ipw_led_init(struct ipw_priv *priv) +static void ipw_led_init(struct ipw_priv *priv) { priv->nic_type = priv->eeprom[EEPROM_NIC_TYPE]; @@ -1025,7 +1131,7 @@ void ipw_led_init(struct ipw_priv *priv) } } -void ipw_led_shutdown(struct ipw_priv *priv) +static void ipw_led_shutdown(struct ipw_priv *priv) { ipw_led_activity_off(priv); ipw_led_link_off(priv); @@ -1074,6 +1180,7 @@ static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, static inline u32 ipw_get_event_log_len(struct ipw_priv *priv) { + /* length = 1st dword in log */ return ipw_read_reg32(priv, ipw_read32(priv, IPW_EVENT_LOG)); } @@ -1121,12 +1228,6 @@ static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv) return error; } -static void ipw_free_error_log(struct ipw_fw_error *error) -{ - if (error) - kfree(error); -} - static ssize_t show_event_log(struct device *d, struct device_attribute *attr, char *buf) { @@ -1188,10 +1289,9 @@ static ssize_t clear_error(struct device *d, const char *buf, size_t count) { struct ipw_priv *priv = dev_get_drvdata(d); - if (priv->error) { - ipw_free_error_log(priv->error); - priv->error = NULL; - } + + kfree(priv->error); + priv->error = NULL; return count; } @@ -1224,6 +1324,105 @@ static ssize_t show_cmd_log(struct device *d, static DEVICE_ATTR(cmd_log, S_IRUGO, show_cmd_log, NULL); +#ifdef CONFIG_IPW2200_PROMISCUOUS +static void ipw_prom_free(struct ipw_priv *priv); +static int ipw_prom_alloc(struct ipw_priv *priv); +static ssize_t store_rtap_iface(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + int rc = 0; + + if (count < 1) + return -EINVAL; + + switch (buf[0]) { + case '0': + if (!rtap_iface) + return count; + + if (netif_running(priv->prom_net_dev)) { + IPW_WARNING("Interface is up. Cannot unregister.\n"); + return count; + } + + ipw_prom_free(priv); + rtap_iface = 0; + break; + + case '1': + if (rtap_iface) + return count; + + rc = ipw_prom_alloc(priv); + if (!rc) + rtap_iface = 1; + break; + + default: + return -EINVAL; + } + + if (rc) { + IPW_ERROR("Failed to register promiscuous network " + "device (error %d).\n", rc); + } + + return count; +} + +static ssize_t show_rtap_iface(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + if (rtap_iface) + return sprintf(buf, "%s", priv->prom_net_dev->name); + else { + buf[0] = '-'; + buf[1] = '1'; + buf[2] = '\0'; + return 3; + } +} + +static DEVICE_ATTR(rtap_iface, S_IWUSR | S_IRUSR, show_rtap_iface, + store_rtap_iface); + +static ssize_t store_rtap_filter(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + + if (!priv->prom_priv) { + IPW_ERROR("Attempting to set filter without " + "rtap_iface enabled.\n"); + return -EPERM; + } + + priv->prom_priv->filter = simple_strtol(buf, NULL, 0); + + IPW_DEBUG_INFO("Setting rtap filter to " BIT_FMT16 "\n", + BIT_ARG16(priv->prom_priv->filter)); + + return count; +} + +static ssize_t show_rtap_filter(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "0x%04X", + priv->prom_priv ? priv->prom_priv->filter : 0); +} + +static DEVICE_ATTR(rtap_filter, S_IWUSR | S_IRUSR, show_rtap_filter, + store_rtap_filter); +#endif + static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, char *buf) { @@ -1235,9 +1434,7 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { struct ipw_priv *priv = dev_get_drvdata(d); -#ifdef CONFIG_IPW2200_DEBUG struct net_device *dev = priv->net_dev; -#endif char buffer[] = "00000000"; unsigned long len = (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1; @@ -1603,7 +1800,7 @@ static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr, break; } - if (ipw_is_valid_channel(priv->ieee, channel)) + if (ieee80211_is_valid_channel(priv->ieee, channel)) priv->speed_scan[pos++] = channel; else IPW_WARNING("Skipping invalid channel request: %d\n", @@ -1667,7 +1864,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) unsigned long flags; int rc = 0; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->irq_lock, flags); inta = ipw_read32(priv, IPW_INTA_RW); inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); @@ -1676,6 +1873,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) /* Add any cached INTA values that need to be handled */ inta |= priv->isr_inta; + spin_unlock_irqrestore(&priv->irq_lock, flags); + + spin_lock_irqsave(&priv->lock, flags); + /* handle all the justifications for the interrupt */ if (inta & IPW_INTA_BIT_RX_TRANSFER) { ipw_rx(priv); @@ -1751,29 +1952,24 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) } if (inta & IPW_INTA_BIT_FATAL_ERROR) { - IPW_ERROR("Firmware error detected. Restarting.\n"); + IPW_WARNING("Firmware error detected. Restarting.\n"); if (priv->error) { - IPW_ERROR("Sysfs 'error' log already exists.\n"); -#ifdef CONFIG_IPW2200_DEBUG + IPW_DEBUG_FW("Sysfs 'error' log already exists.\n"); if (ipw_debug_level & IPW_DL_FW_ERRORS) { struct ipw_fw_error *error = ipw_alloc_error_log(priv); ipw_dump_error_log(priv, error); - if (error) - ipw_free_error_log(error); + kfree(error); } -#endif } else { priv->error = ipw_alloc_error_log(priv); if (priv->error) - IPW_ERROR("Sysfs 'error' log captured.\n"); + IPW_DEBUG_FW("Sysfs 'error' log captured.\n"); else - IPW_ERROR("Error allocating sysfs 'error' " - "log.\n"); -#ifdef CONFIG_IPW2200_DEBUG + IPW_DEBUG_FW("Error allocating sysfs 'error' " + "log.\n"); if (ipw_debug_level & IPW_DL_FW_ERRORS) ipw_dump_error_log(priv, priv->error); -#endif } /* XXX: If hardware encryption is for WPA/WPA2, @@ -1804,10 +2000,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); } + spin_unlock_irqrestore(&priv->lock, flags); + /* enable all interrupts */ ipw_enable_interrupts(priv); - - spin_unlock_irqrestore(&priv->lock, flags); } #define IPW_CMD(x) case IPW_CMD_ ## x : return #x @@ -1870,7 +2066,8 @@ static char *get_cmd_string(u8 cmd) } #define HOST_COMPLETE_TIMEOUT HZ -static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) + +static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) { int rc = 0; unsigned long flags; @@ -1897,9 +2094,15 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n", get_cmd_string(cmd->cmd), cmd->cmd, cmd->len, priv->status); - printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len); - rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0); +#ifndef DEBUG_CMD_WEP_KEY + if (cmd->cmd == IPW_CMD_WEP_KEY) + IPW_DEBUG_HC("WEP_KEY command masked out for secure.\n"); + else +#endif + printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len); + + rc = ipw_queue_tx_hcmd(priv, cmd->cmd, cmd->param, cmd->len, 0); if (rc) { priv->status &= ~STATUS_HCMD_ACTIVE; IPW_ERROR("Failed to send %s: Reason %d\n", @@ -1942,61 +2145,57 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) return rc; } -static int ipw_send_host_complete(struct ipw_priv *priv) +static int ipw_send_cmd_simple(struct ipw_priv *priv, u8 command) { struct host_cmd cmd = { - .cmd = IPW_CMD_HOST_COMPLETE, - .len = 0 + .cmd = command, }; - if (!priv) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - return ipw_send_cmd(priv, &cmd); + return __ipw_send_cmd(priv, &cmd); } -static int ipw_send_system_config(struct ipw_priv *priv, - struct ipw_sys_config *config) +static int ipw_send_cmd_pdu(struct ipw_priv *priv, u8 command, u8 len, + void *data) { struct host_cmd cmd = { - .cmd = IPW_CMD_SYSTEM_CONFIG, - .len = sizeof(*config) + .cmd = command, + .len = len, + .param = data, }; - if (!priv || !config) { + return __ipw_send_cmd(priv, &cmd); +} + +static int ipw_send_host_complete(struct ipw_priv *priv) +{ + if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(cmd.param, config, sizeof(*config)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_simple(priv, IPW_CMD_HOST_COMPLETE); } -static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) +static int ipw_send_system_config(struct ipw_priv *priv) { - struct host_cmd cmd = { - .cmd = IPW_CMD_SSID, - .len = min(len, IW_ESSID_MAX_SIZE) - }; + return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG, + sizeof(priv->sys_config), + &priv->sys_config); +} +static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) +{ if (!priv || !ssid) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(cmd.param, ssid, cmd.len); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_SSID, min(len, IW_ESSID_MAX_SIZE), + ssid); } static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) { - struct host_cmd cmd = { - .cmd = IPW_CMD_ADAPTER_ADDRESS, - .len = ETH_ALEN - }; - if (!priv || !mac) { IPW_ERROR("Invalid args\n"); return -1; @@ -2005,8 +2204,7 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n", priv->net_dev->name, MAC_ARG(mac)); - memcpy(cmd.param, mac, ETH_ALEN); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac); } /* @@ -2033,12 +2231,13 @@ static void ipw_adapter_restart(void *adapter) } } -static void ipw_bg_adapter_restart(void *data) +static void ipw_bg_adapter_restart(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_adapter_restart(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, adapter_restart); + mutex_lock(&priv->mutex); + ipw_adapter_restart(priv); + mutex_unlock(&priv->mutex); } #define IPW_SCAN_CHECK_WATCHDOG (5 * HZ) @@ -2048,68 +2247,58 @@ static void ipw_scan_check(void *data) struct ipw_priv *priv = data; if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) { IPW_DEBUG_SCAN("Scan completion watchdog resetting " - "adapter (%dms).\n", - IPW_SCAN_CHECK_WATCHDOG / 100); + "adapter after (%dms).\n", + jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG)); queue_work(priv->workqueue, &priv->adapter_restart); } } -static void ipw_bg_scan_check(void *data) +static void ipw_bg_scan_check(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_scan_check(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, scan_check.work); + mutex_lock(&priv->mutex); + ipw_scan_check(priv); + mutex_unlock(&priv->mutex); } static int ipw_send_scan_request_ext(struct ipw_priv *priv, struct ipw_scan_request_ext *request) { - struct host_cmd cmd = { - .cmd = IPW_CMD_SCAN_REQUEST_EXT, - .len = sizeof(*request) - }; - - memcpy(cmd.param, request, sizeof(*request)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_SCAN_REQUEST_EXT, + sizeof(*request), request); } static int ipw_send_scan_abort(struct ipw_priv *priv) { - struct host_cmd cmd = { - .cmd = IPW_CMD_SCAN_ABORT, - .len = 0 - }; - if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_simple(priv, IPW_CMD_SCAN_ABORT); } static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens) { - struct host_cmd cmd = { - .cmd = IPW_CMD_SENSITIVITY_CALIB, - .len = sizeof(struct ipw_sensitivity_calib) + struct ipw_sensitivity_calib calib = { + .beacon_rssi_raw = cpu_to_le16(sens), }; - struct ipw_sensitivity_calib *calib = (struct ipw_sensitivity_calib *) - &cmd.param; - calib->beacon_rssi_raw = sens; - return ipw_send_cmd(priv, &cmd); + + return ipw_send_cmd_pdu(priv, IPW_CMD_SENSITIVITY_CALIB, sizeof(calib), + &calib); } static int ipw_send_associate(struct ipw_priv *priv, struct ipw_associate *associate) { - struct host_cmd cmd = { - .cmd = IPW_CMD_ASSOCIATE, - .len = sizeof(*associate) - }; - struct ipw_associate tmp_associate; + + if (!priv || !associate) { + IPW_ERROR("Invalid args\n"); + return -1; + } + memcpy(&tmp_associate, associate, sizeof(*associate)); tmp_associate.policy_support = cpu_to_le16(tmp_associate.policy_support); @@ -2122,85 +2311,61 @@ static int ipw_send_associate(struct ipw_priv *priv, cpu_to_le16(tmp_associate.beacon_interval); tmp_associate.atim_window = cpu_to_le16(tmp_associate.atim_window); - if (!priv || !associate) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - memcpy(cmd.param, &tmp_associate, sizeof(*associate)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(tmp_associate), + &tmp_associate); } static int ipw_send_supported_rates(struct ipw_priv *priv, struct ipw_supported_rates *rates) { - struct host_cmd cmd = { - .cmd = IPW_CMD_SUPPORTED_RATES, - .len = sizeof(*rates) - }; - if (!priv || !rates) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(cmd.param, rates, sizeof(*rates)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_SUPPORTED_RATES, sizeof(*rates), + rates); } static int ipw_set_random_seed(struct ipw_priv *priv) { - struct host_cmd cmd = { - .cmd = IPW_CMD_SEED_NUMBER, - .len = sizeof(u32) - }; + u32 val; if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } - get_random_bytes(&cmd.param, sizeof(u32)); + get_random_bytes(&val, sizeof(val)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_SEED_NUMBER, sizeof(val), &val); } static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off) { - struct host_cmd cmd = { - .cmd = IPW_CMD_CARD_DISABLE, - .len = sizeof(u32) - }; - if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } - *((u32 *) & cmd.param) = phy_off; - - return ipw_send_cmd(priv, &cmd); + phy_off = cpu_to_le32(phy_off); + return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(phy_off), + &phy_off); } static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) { - struct host_cmd cmd = { - .cmd = IPW_CMD_TX_POWER, - .len = sizeof(*power) - }; - if (!priv || !power) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(cmd.param, power, sizeof(*power)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_TX_POWER, sizeof(*power), power); } static int ipw_set_tx_power(struct ipw_priv *priv) { - const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee); + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); struct ipw_tx_power tx_power; s8 max_power; int i; @@ -2245,11 +2410,7 @@ static int ipw_set_tx_power(struct ipw_priv *priv) static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts) { struct ipw_rts_threshold rts_threshold = { - .rts_threshold = rts, - }; - struct host_cmd cmd = { - .cmd = IPW_CMD_RTS_THRESHOLD, - .len = sizeof(rts_threshold) + .rts_threshold = cpu_to_le16(rts), }; if (!priv) { @@ -2257,18 +2418,14 @@ static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts) return -1; } - memcpy(cmd.param, &rts_threshold, sizeof(rts_threshold)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_RTS_THRESHOLD, + sizeof(rts_threshold), &rts_threshold); } static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag) { struct ipw_frag_threshold frag_threshold = { - .frag_threshold = frag, - }; - struct host_cmd cmd = { - .cmd = IPW_CMD_FRAG_THRESHOLD, - .len = sizeof(frag_threshold) + .frag_threshold = cpu_to_le16(frag), }; if (!priv) { @@ -2276,17 +2433,13 @@ static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag) return -1; } - memcpy(cmd.param, &frag_threshold, sizeof(frag_threshold)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_FRAG_THRESHOLD, + sizeof(frag_threshold), &frag_threshold); } static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) { - struct host_cmd cmd = { - .cmd = IPW_CMD_POWER_MODE, - .len = sizeof(u32) - }; - u32 *param = (u32 *) (&cmd.param); + u32 param; if (!priv) { IPW_ERROR("Invalid args\n"); @@ -2297,17 +2450,19 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) * level */ switch (mode) { case IPW_POWER_BATTERY: - *param = IPW_POWER_INDEX_3; + param = IPW_POWER_INDEX_3; break; case IPW_POWER_AC: - *param = IPW_POWER_MODE_CAM; + param = IPW_POWER_MODE_CAM; break; default: - *param = mode; + param = mode; break; } - return ipw_send_cmd(priv, &cmd); + param = cpu_to_le32(mode); + return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param), + ¶m); } static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit) @@ -2316,18 +2471,14 @@ static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit) .short_retry_limit = slimit, .long_retry_limit = llimit }; - struct host_cmd cmd = { - .cmd = IPW_CMD_RETRY_LIMIT, - .len = sizeof(retry_limit) - }; if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(cmd.param, &retry_limit, sizeof(retry_limit)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_RETRY_LIMIT, sizeof(retry_limit), + &retry_limit); } /* @@ -2454,7 +2605,7 @@ static void ipw_eeprom_init_sram(struct ipw_priv *priv) /* If the data looks correct, then copy it to our private copy. Otherwise let the firmware know to perform the operation - on it's own + on its own. */ if (priv->eeprom[EEPROM_VERSION] != 0) { IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n"); @@ -2513,7 +2664,7 @@ static void ipw_fw_dma_abort(struct ipw_priv *priv) IPW_DEBUG_FW(">> :\n"); - //set the Stop and Abort bit + /* set the Stop and Abort bit */ control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT; ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control); priv->sram_desc.last_cb_index = 0; @@ -2707,22 +2858,25 @@ static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, static int ipw_fw_dma_wait(struct ipw_priv *priv) { - u32 current_index = 0; + u32 current_index = 0, previous_index; u32 watchdog = 0; IPW_DEBUG_FW(">> : \n"); current_index = ipw_fw_dma_command_block_index(priv); - IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%8X\n", + IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%08X\n", (int)priv->sram_desc.last_cb_index); while (current_index < priv->sram_desc.last_cb_index) { udelay(50); + previous_index = current_index; current_index = ipw_fw_dma_command_block_index(priv); - watchdog++; - - if (watchdog > 400) { + if (previous_index < current_index) { + watchdog = 0; + continue; + } + if (++watchdog > 400) { IPW_DEBUG_FW_INFO("Timeout\n"); ipw_fw_dma_dump_command_block(priv); ipw_fw_dma_abort(priv); @@ -2772,6 +2926,7 @@ static inline int ipw_alive(struct ipw_priv *priv) return ipw_read32(priv, 0x90) == 0xd55555d5; } +/* timeout in msec, attempted in 10-msec quanta */ static int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask, int timeout) { @@ -2800,10 +2955,11 @@ static int ipw_stop_master(struct ipw_priv *priv) /* stop master. typical delay - 0 */ ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER); + /* timeout is in msec, polled in 10-msec quanta */ rc = ipw_poll_bit(priv, IPW_RESET_REG, IPW_RESET_REG_MASTER_DISABLED, 100); if (rc < 0) { - IPW_ERROR("stop master failed in 10ms\n"); + IPW_ERROR("wait for stop master failed after 100ms\n"); return -1; } @@ -2823,33 +2979,11 @@ static void ipw_arc_release(struct ipw_priv *priv) mdelay(5); } -struct fw_header { - u32 version; - u32 mode; -}; - struct fw_chunk { u32 address; u32 length; }; -#define IPW_FW_MAJOR_VERSION 2 -#define IPW_FW_MINOR_VERSION 4 - -#define IPW_FW_MINOR(x) ((x & 0xff) >> 8) -#define IPW_FW_MAJOR(x) (x & 0xff) - -#define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | IPW_FW_MAJOR_VERSION) - -#define IPW_FW_PREFIX "ipw-" __stringify(IPW_FW_MAJOR_VERSION) \ -"." __stringify(IPW_FW_MINOR_VERSION) "-" - -#if IPW_FW_MAJOR_VERSION >= 2 && IPW_FW_MINOR_VERSION > 0 -#define IPW_FW_NAME(x) IPW_FW_PREFIX "" x ".fw" -#else -#define IPW_FW_NAME(x) "ipw2200_" x ".fw" -#endif - static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) { int rc = 0, i, addr; @@ -2865,8 +2999,6 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) if (rc < 0) return rc; -// spin_lock_irqsave(&priv->lock, flags); - for (addr = IPW_SHARED_LOWER_BOUND; addr < IPW_REGISTER_DOMAIN1_END; addr += 4) { ipw_write32(priv, addr, 0); @@ -2890,8 +3022,8 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) mdelay(1); /* enable ucode store */ - ipw_write_reg8(priv, DINO_CONTROL_REG, 0x0); - ipw_write_reg8(priv, DINO_CONTROL_REG, DINO_ENABLE_CS); + ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0x0); + ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_CS); mdelay(1); /* write ucode */ @@ -2960,8 +3092,6 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) firmware have problem getting alive resp. */ ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0); -// spin_unlock_irqrestore(&priv->lock, flags); - return rc; } @@ -3036,7 +3166,7 @@ static int ipw_stop_nic(struct ipw_priv *priv) rc = ipw_poll_bit(priv, IPW_RESET_REG, IPW_RESET_REG_MASTER_DISABLED, 500); if (rc < 0) { - IPW_ERROR("wait for reg master disabled failed\n"); + IPW_ERROR("wait for reg master disabled failed after 500ms\n"); return rc; } @@ -3118,33 +3248,47 @@ static int ipw_reset_nic(struct ipw_priv *priv) return rc; } + +struct ipw_fw { + __le32 ver; + __le32 boot_size; + __le32 ucode_size; + __le32 fw_size; + u8 data[0]; +}; + static int ipw_get_fw(struct ipw_priv *priv, - const struct firmware **fw, const char *name) + const struct firmware **raw, const char *name) { - struct fw_header *header; + struct ipw_fw *fw; int rc; /* ask firmware_class module to get the boot firmware off disk */ - rc = request_firmware(fw, name, &priv->pci_dev->dev); + rc = request_firmware(raw, name, &priv->pci_dev->dev); if (rc < 0) { - IPW_ERROR("%s load failed: Reason %d\n", name, rc); + IPW_ERROR("%s request_firmware failed: Reason %d\n", name, rc); return rc; } - header = (struct fw_header *)(*fw)->data; - if (IPW_FW_MAJOR(le32_to_cpu(header->version)) != IPW_FW_MAJOR_VERSION) { - IPW_ERROR("'%s' firmware version not compatible (%d != %d)\n", - name, - IPW_FW_MAJOR(le32_to_cpu(header->version)), - IPW_FW_MAJOR_VERSION); + if ((*raw)->size < sizeof(*fw)) { + IPW_ERROR("%s is too small (%zd)\n", name, (*raw)->size); return -EINVAL; } - IPW_DEBUG_INFO("Loading firmware '%s' file v%d.%d (%zd bytes)\n", + fw = (void *)(*raw)->data; + + if ((*raw)->size < sizeof(*fw) + le32_to_cpu(fw->boot_size) + + le32_to_cpu(fw->ucode_size) + le32_to_cpu(fw->fw_size)) { + IPW_ERROR("%s is too small or corrupt (%zd)\n", + name, (*raw)->size); + return -EINVAL; + } + + IPW_DEBUG_INFO("Read firmware '%s' image v%d.%d (%zd bytes)\n", name, - IPW_FW_MAJOR(le32_to_cpu(header->version)), - IPW_FW_MINOR(le32_to_cpu(header->version)), - (*fw)->size - sizeof(struct fw_header)); + le32_to_cpu(fw->ver) >> 16, + le32_to_cpu(fw->ver) & 0xff, + (*raw)->size - sizeof(*fw)); return 0; } @@ -3184,17 +3328,13 @@ static void ipw_rx_queue_reset(struct ipw_priv *priv, #ifdef CONFIG_PM static int fw_loaded = 0; -static const struct firmware *bootfw = NULL; -static const struct firmware *firmware = NULL; -static const struct firmware *ucode = NULL; +static const struct firmware *raw = NULL; static void free_firmware(void) { if (fw_loaded) { - release_firmware(bootfw); - release_firmware(ucode); - release_firmware(firmware); - bootfw = ucode = firmware = NULL; + release_firmware(raw); + raw = NULL; fw_loaded = 0; } } @@ -3205,60 +3345,51 @@ static void free_firmware(void) static int ipw_load(struct ipw_priv *priv) { #ifndef CONFIG_PM - const struct firmware *bootfw = NULL; - const struct firmware *firmware = NULL; - const struct firmware *ucode = NULL; + const struct firmware *raw = NULL; #endif + struct ipw_fw *fw; + u8 *boot_img, *ucode_img, *fw_img; + u8 *name = NULL; int rc = 0, retries = 3; -#ifdef CONFIG_PM - if (!fw_loaded) { -#endif - rc = ipw_get_fw(priv, &bootfw, IPW_FW_NAME("boot")); - if (rc) - goto error; - - switch (priv->ieee->iw_mode) { - case IW_MODE_ADHOC: - rc = ipw_get_fw(priv, &ucode, - IPW_FW_NAME("ibss_ucode")); - if (rc) - goto error; - - rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("ibss")); - break; - + switch (priv->ieee->iw_mode) { + case IW_MODE_ADHOC: + name = "ipw2200-ibss.fw"; + break; #ifdef CONFIG_IPW2200_MONITOR - case IW_MODE_MONITOR: - rc = ipw_get_fw(priv, &ucode, - IPW_FW_NAME("sniffer_ucode")); - if (rc) - goto error; - - rc = ipw_get_fw(priv, &firmware, - IPW_FW_NAME("sniffer")); - break; + case IW_MODE_MONITOR: + name = "ipw2200-sniffer.fw"; + break; #endif - case IW_MODE_INFRA: - rc = ipw_get_fw(priv, &ucode, IPW_FW_NAME("bss_ucode")); - if (rc) - goto error; - - rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("bss")); - break; + case IW_MODE_INFRA: + name = "ipw2200-bss.fw"; + break; + } - default: - rc = -EINVAL; - } + if (!name) { + rc = -EINVAL; + goto error; + } - if (rc) +#ifdef CONFIG_PM + if (!fw_loaded) { +#endif + rc = ipw_get_fw(priv, &raw, name); + if (rc < 0) goto error; - #ifdef CONFIG_PM - fw_loaded = 1; } #endif + fw = (void *)raw->data; + boot_img = &fw->data[0]; + ucode_img = &fw->data[le32_to_cpu(fw->boot_size)]; + fw_img = &fw->data[le32_to_cpu(fw->boot_size) + + le32_to_cpu(fw->ucode_size)]; + + if (rc < 0) + goto error; + if (!priv->rxq) priv->rxq = ipw_rx_queue_alloc(priv); else @@ -3279,7 +3410,7 @@ static int ipw_load(struct ipw_priv *priv) ipw_stop_nic(priv); rc = ipw_reset_nic(priv); - if (rc) { + if (rc < 0) { IPW_ERROR("Unable to reset NIC\n"); goto error; } @@ -3288,8 +3419,7 @@ static int ipw_load(struct ipw_priv *priv) IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND); /* DMA the initial boot firmware into the device */ - rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header), - bootfw->size - sizeof(struct fw_header)); + rc = ipw_load_firmware(priv, boot_img, le32_to_cpu(fw->boot_size)); if (rc < 0) { IPW_ERROR("Unable to load boot firmware: %d\n", rc); goto error; @@ -3298,7 +3428,7 @@ static int ipw_load(struct ipw_priv *priv) /* kick start the device */ ipw_start_nic(priv); - /* wait for the device to finish it's initial startup sequence */ + /* wait for the device to finish its initial startup sequence */ rc = ipw_poll_bit(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500); if (rc < 0) { @@ -3311,8 +3441,7 @@ static int ipw_load(struct ipw_priv *priv) ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE); /* DMA the ucode into the device */ - rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header), - ucode->size - sizeof(struct fw_header)); + rc = ipw_load_ucode(priv, ucode_img, le32_to_cpu(fw->ucode_size)); if (rc < 0) { IPW_ERROR("Unable to load ucode: %d\n", rc); goto error; @@ -3322,18 +3451,19 @@ static int ipw_load(struct ipw_priv *priv) ipw_stop_nic(priv); /* DMA bss firmware into the device */ - rc = ipw_load_firmware(priv, firmware->data + - sizeof(struct fw_header), - firmware->size - sizeof(struct fw_header)); + rc = ipw_load_firmware(priv, fw_img, le32_to_cpu(fw->fw_size)); if (rc < 0) { IPW_ERROR("Unable to load firmware: %d\n", rc); goto error; } +#ifdef CONFIG_PM + fw_loaded = 1; +#endif ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0); rc = ipw_queue_reset(priv); - if (rc) { + if (rc < 0) { IPW_ERROR("Unable to initialize queues\n"); goto error; } @@ -3362,7 +3492,7 @@ static int ipw_load(struct ipw_priv *priv) rc = ipw_poll_bit(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500); if (rc < 0) { - IPW_ERROR("device failed to start after 500ms\n"); + IPW_ERROR("device failed to start within 500ms\n"); goto error; } IPW_DEBUG_INFO("device response after %dms\n", rc); @@ -3386,9 +3516,7 @@ static int ipw_load(struct ipw_priv *priv) ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL); #ifndef CONFIG_PM - release_firmware(bootfw); - release_firmware(ucode); - release_firmware(firmware); + release_firmware(raw); #endif return 0; @@ -3398,15 +3526,11 @@ static int ipw_load(struct ipw_priv *priv) priv->rxq = NULL; } ipw_tx_queue_free(priv); - if (bootfw) - release_firmware(bootfw); - if (ucode) - release_firmware(ucode); - if (firmware) - release_firmware(firmware); + if (raw) + release_firmware(raw); #ifdef CONFIG_PM fw_loaded = 0; - bootfw = ucode = firmware = NULL; + raw = NULL; #endif return rc; @@ -3712,18 +3836,30 @@ static int ipw_disassociate(void *data) return 1; } -static void ipw_bg_disassociate(void *data) +static void ipw_bg_disassociate(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_disassociate(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, disassociate); + mutex_lock(&priv->mutex); + ipw_disassociate(priv); + mutex_unlock(&priv->mutex); } -static void ipw_system_config(void *data) +static void ipw_system_config(struct work_struct *work) { - struct ipw_priv *priv = data; - ipw_send_system_config(priv, &priv->sys_config); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, system_config); + +#ifdef CONFIG_IPW2200_PROMISCUOUS + if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) { + priv->sys_config.accept_all_data_frames = 1; + priv->sys_config.accept_non_directed_frames = 1; + priv->sys_config.accept_all_mgmt_bcpr = 1; + priv->sys_config.accept_all_mgmt_frames = 1; + } +#endif + + ipw_send_system_config(priv); } struct ipw_status_code { @@ -3778,7 +3914,6 @@ static const struct ipw_status_code ipw_status_codes[] = { {0x2E, "Cipher suite is rejected per security policy"}, }; -#ifdef CONFIG_IPW2200_DEBUG static const char *ipw_get_status_code(u16 status) { int i; @@ -3787,13 +3922,19 @@ static const char *ipw_get_status_code(u16 status) return ipw_status_codes[i].reason; return "Unknown status value."; } -#endif static void inline average_init(struct average *avg) { memset(avg, 0, sizeof(*avg)); } +#define DEPTH_RSSI 8 +#define DEPTH_NOISE 16 +static s16 exponential_average(s16 prev_avg, s16 val, u8 depth) +{ + return ((depth-1)*prev_avg + val)/depth; +} + static void average_add(struct average *avg, s16 val) { avg->sum -= avg->entries[avg->pos]; @@ -3823,8 +3964,8 @@ static void ipw_reset_stats(struct ipw_priv *priv) priv->quality = 0; average_init(&priv->average_missed_beacons); - average_init(&priv->average_rssi); - average_init(&priv->average_noise); + priv->exp_avg_rssi = -60; + priv->exp_avg_noise = -85 + 0x100; priv->last_rate = 0; priv->last_missed_beacons = 0; @@ -4031,7 +4172,7 @@ static void ipw_gather_stats(struct ipw_priv *priv) IPW_DEBUG_STATS("Tx quality : %3d%% (%u errors, %u packets)\n", tx_quality, tx_failures_delta, tx_packets_delta); - rssi = average_value(&priv->average_rssi); + rssi = priv->exp_avg_rssi; signal_quality = (100 * (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) * @@ -4074,12 +4215,13 @@ static void ipw_gather_stats(struct ipw_priv *priv) IPW_STATS_INTERVAL); } -static void ipw_bg_gather_stats(void *data) +static void ipw_bg_gather_stats(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_gather_stats(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, gather_stats.work); + mutex_lock(&priv->mutex); + ipw_gather_stats(priv); + mutex_unlock(&priv->mutex); } /* Missed beacon behavior: @@ -4121,8 +4263,9 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, return; } - if (missed_count > priv->roaming_threshold && - missed_count <= priv->disassociate_threshold) { + if (roaming && + (missed_count > priv->roaming_threshold && + missed_count <= priv->disassociate_threshold)) { /* If we are not already roaming, set the ROAM * bit in the status and kick off a scan. * This can happen several times before we reach @@ -4133,8 +4276,8 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, if (!(priv->status & STATUS_ROAMING)) { priv->status |= STATUS_ROAMING; if (!(priv->status & STATUS_SCANNING)) - queue_work(priv->workqueue, - &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); } return; } @@ -4150,7 +4293,6 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, } IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count); - } /** @@ -4208,7 +4350,7 @@ static void ipw_rx_notification(struct ipw_priv *priv, queue_work(priv->workqueue, &priv->system_config); -#ifdef CONFIG_IPW_QOS +#ifdef CONFIG_IPW2200_QOS #define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \ le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_ctl)) if ((priv->status & STATUS_AUTH) && @@ -4250,7 +4392,6 @@ static void ipw_rx_notification(struct ipw_priv *priv, if (priv-> status & (STATUS_ASSOCIATED | STATUS_AUTH)) { -#ifdef CONFIG_IPW2200_DEBUG struct notif_authenticate *auth = ¬if->u.auth; IPW_DEBUG(IPW_DL_NOTIF | @@ -4268,7 +4409,6 @@ static void ipw_rx_notification(struct ipw_priv *priv, ipw_get_status_code (ntohs (auth->status))); -#endif priv->status &= ~(STATUS_ASSOCIATING | @@ -4475,8 +4615,8 @@ static void ipw_rx_notification(struct ipw_priv *priv, #ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { priv->status |= STATUS_SCAN_FORCED; - queue_work(priv->workqueue, - &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); break; } priv->status &= ~STATUS_SCAN_FORCED; @@ -4499,12 +4639,30 @@ static void ipw_rx_notification(struct ipw_priv *priv, /* Don't schedule if we aborted the scan */ priv->status &= ~STATUS_ROAMING; } else if (priv->status & STATUS_SCAN_PENDING) - queue_work(priv->workqueue, - &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); else if (priv->config & CFG_BACKGROUND_SCAN && priv->status & STATUS_ASSOCIATED) queue_delayed_work(priv->workqueue, &priv->request_scan, HZ); + + /* Send an empty event to user space. + * We don't send the received data on the event because + * it would require us to do complex transcoding, and + * we want to minimise the work done in the irq handler + * Use a request to extract the data. + * Also, we generate this even for any scan, regardless + * on how the scan was initiated. User space can just + * sync on periodic scan to get fresh data... + * Jean II */ + if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) { + union iwreq_data wrqu; + + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(priv->net_dev, SIOCGIWSCAN, + &wrqu, NULL); + } break; } @@ -4527,10 +4685,9 @@ static void ipw_rx_notification(struct ipw_priv *priv, if (notif->size == sizeof(*x)) { IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, - "link deterioration: '%s' " MAC_FMT - " \n", escape_essid(priv->essid, - priv->essid_len), - MAC_ARG(priv->bssid)); + "link deterioration: type %d, cnt %d\n", + x->silence_notification_type, + x->silence_count); memcpy(&priv->last_link_deterioration, x, sizeof(*x)); } else { @@ -4601,11 +4758,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, case HOST_NOTIFICATION_NOISE_STATS:{ if (notif->size == sizeof(u32)) { - priv->last_noise = - (u8) (le32_to_cpu(notif->u.noise.value) & - 0xff); - average_add(&priv->average_noise, - priv->last_noise); + priv->exp_avg_noise = + exponential_average(priv->exp_avg_noise, + (u8) (le32_to_cpu(notif->u.noise.value) & 0xff), + DEPTH_NOISE); break; } @@ -4895,7 +5051,6 @@ static void ipw_rx_queue_replenish(void *data) } list_del(element); - rxb->rxb = (struct ipw_rx_buffer *)rxb->skb->data; rxb->dma_addr = pci_map_single(priv->pci_dev, rxb->skb->data, IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); @@ -4908,16 +5063,17 @@ static void ipw_rx_queue_replenish(void *data) ipw_rx_queue_restock(priv); } -static void ipw_bg_rx_queue_replenish(void *data) +static void ipw_bg_rx_queue_replenish(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_rx_queue_replenish(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, rx_replenish); + mutex_lock(&priv->mutex); + ipw_rx_queue_replenish(priv); + mutex_unlock(&priv->mutex); } /* Assumes that the skb field of the buffers in 'pool' is kept accurate. - * If an SKB has been detached, the POOL needs to have it's SKB set to NULL + * If an SKB has been detached, the POOL needs to have its SKB set to NULL * This free routine walks the list of POOL entries and if SKB is set to * non NULL it is unmapped and freed */ @@ -5257,10 +5413,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " - "because of age: %lums.\n", + "because of age: %ums.\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), - 1000 * (jiffies - network->last_scanned) / HZ); + jiffies_to_msecs(jiffies - + network->last_scanned)); return 0; } @@ -5341,9 +5498,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, return 1; } -static void ipw_merge_adhoc_network(void *data) +static void ipw_merge_adhoc_network(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, merge_networks); struct ieee80211_network *network = NULL; struct ipw_network_match match = { .network = priv->assoc_network @@ -5369,7 +5527,7 @@ static void ipw_merge_adhoc_network(void *data) return; } - down(&priv->sem); + mutex_lock(&priv->mutex); if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { IPW_DEBUG_MERGE("remove network %s\n", escape_essid(priv->essid, @@ -5379,7 +5537,7 @@ static void ipw_merge_adhoc_network(void *data) ipw_disassociate(priv); priv->assoc_network = match.network; - up(&priv->sem); + mutex_unlock(&priv->mutex); return; } } @@ -5467,11 +5625,12 @@ static int ipw_best_network(struct ipw_priv *priv, if (network->last_associate && time_after(network->last_associate + (HZ * 3UL), jiffies)) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " - "because of storming (%lus since last " + "because of storming (%ums since last " "assoc attempt).\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), - (jiffies - network->last_associate) / HZ); + jiffies_to_msecs(jiffies - + network->last_associate)); return 0; } @@ -5479,10 +5638,11 @@ static int ipw_best_network(struct ipw_priv *priv, if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " - "because of age: %lums.\n", + "because of age: %ums.\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), - 1000 * (jiffies - network->last_scanned) / HZ); + jiffies_to_msecs(jiffies - + network->last_scanned)); return 0; } @@ -5510,15 +5670,6 @@ static int ipw_best_network(struct ipw_priv *priv, return 0; } - if (!priv->ieee->wpa_enabled && (network->wpa_ie_len > 0 || - network->rsn_ie_len > 0)) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " - "because of WPA capability mismatch.\n", - escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); - return 0; - } - if ((priv->config & CFG_STATIC_BSSID) && memcmp(network->bssid, priv->bssid, ETH_ALEN)) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " @@ -5539,7 +5690,7 @@ static int ipw_best_network(struct ipw_priv *priv, } /* Filter out invalid channel in current GEO */ - if (!ipw_is_valid_channel(priv->ieee, network->channel)) { + if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " "because of invalid channel in current GEO\n", escape_essid(network->ssid, network->ssid_len), @@ -5584,7 +5735,7 @@ static int ipw_best_network(struct ipw_priv *priv, static void ipw_adhoc_create(struct ipw_priv *priv, struct ieee80211_network *network) { - const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee); + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); int i; /* @@ -5599,12 +5750,11 @@ static void ipw_adhoc_create(struct ipw_priv *priv, * FW fatal error. * */ - switch (ipw_is_valid_channel(priv->ieee, priv->channel)) { + switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { case IEEE80211_52GHZ_BAND: network->mode = IEEE_A; - i = ipw_channel_to_index(priv->ieee, priv->channel); - if (i == -1) - BUG(); + i = ieee80211_channel_to_index(priv->ieee, priv->channel); + BUG_ON(i == -1); if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) { IPW_WARNING("Overriding invalid channel\n"); priv->channel = geo->a[0].channel; @@ -5616,9 +5766,8 @@ static void ipw_adhoc_create(struct ipw_priv *priv, network->mode = IEEE_G; else network->mode = IEEE_B; - i = ipw_channel_to_index(priv->ieee, priv->channel); - if (i == -1) - BUG(); + i = ieee80211_channel_to_index(priv->ieee, priv->channel); + BUG_ON(i == -1); if (geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY) { IPW_WARNING("Overriding invalid channel\n"); priv->channel = geo->bg[0].channel; @@ -5671,54 +5820,44 @@ static void ipw_adhoc_create(struct ipw_priv *priv, static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index) { - struct ipw_tgi_tx_key *key; - struct host_cmd cmd = { - .cmd = IPW_CMD_TGI_TX_KEY, - .len = sizeof(*key) - }; + struct ipw_tgi_tx_key key; if (!(priv->ieee->sec.flags & (1 << index))) return; - key = (struct ipw_tgi_tx_key *)&cmd.param; - key->key_id = index; - memcpy(key->key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH); - key->security_type = type; - key->station_index = 0; /* always 0 for BSS */ - key->flags = 0; + key.key_id = index; + memcpy(key.key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH); + key.security_type = type; + key.station_index = 0; /* always 0 for BSS */ + key.flags = 0; /* 0 for new key; previous value of counter (after fatal error) */ - key->tx_counter[0] = 0; - key->tx_counter[1] = 0; + key.tx_counter[0] = cpu_to_le32(0); + key.tx_counter[1] = cpu_to_le32(0); - ipw_send_cmd(priv, &cmd); + ipw_send_cmd_pdu(priv, IPW_CMD_TGI_TX_KEY, sizeof(key), &key); } static void ipw_send_wep_keys(struct ipw_priv *priv, int type) { - struct ipw_wep_key *key; + struct ipw_wep_key key; int i; - struct host_cmd cmd = { - .cmd = IPW_CMD_WEP_KEY, - .len = sizeof(*key) - }; - key = (struct ipw_wep_key *)&cmd.param; - key->cmd_id = DINO_CMD_WEP_KEY; - key->seq_num = 0; + key.cmd_id = DINO_CMD_WEP_KEY; + key.seq_num = 0; /* Note: AES keys cannot be set for multiple times. * Only set it at the first time. */ for (i = 0; i < 4; i++) { - key->key_index = i | type; + key.key_index = i | type; if (!(priv->ieee->sec.flags & (1 << i))) { - key->key_size = 0; + key.key_size = 0; continue; } - key->key_size = priv->ieee->sec.key_sizes[i]; - memcpy(key->key, priv->ieee->sec.keys[i], key->key_size); + key.key_size = priv->ieee->sec.key_sizes[i]; + memcpy(key.key, priv->ieee->sec.keys[i], key.key_size); - ipw_send_cmd(priv, &cmd); + ipw_send_cmd_pdu(priv, IPW_CMD_WEP_KEY, sizeof(key), &key); } } @@ -5819,15 +5958,15 @@ static void ipw_adhoc_check(void *data) priv->assoc_request.beacon_interval); } -static void ipw_bg_adhoc_check(void *data) +static void ipw_bg_adhoc_check(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_adhoc_check(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, adhoc_check.work); + mutex_lock(&priv->mutex); + ipw_adhoc_check(priv); + mutex_unlock(&priv->mutex); } -#ifdef CONFIG_IPW2200_DEBUG static void ipw_debug_config(struct ipw_priv *priv) { IPW_DEBUG_INFO("Scan completed, no valid APs matched " @@ -5852,9 +5991,6 @@ static void ipw_debug_config(struct ipw_priv *priv) IPW_DEBUG_INFO("PRIVACY off\n"); IPW_DEBUG_INFO("RATE MASK: 0x%08X\n", priv->rates_mask); } -#else -#define ipw_debug_config(x) do {} while (0) -#endif static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) { @@ -5950,7 +6086,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, const struct ieee80211_geo *geo; int i; - geo = ipw_get_geo(priv->ieee); + geo = ieee80211_get_geo(priv->ieee); if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { int start = channel_index; @@ -6010,7 +6146,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, channel_index++; scan->channels_list[channel_index] = channel; index = - ipw_channel_to_index(priv->ieee, channel); + ieee80211_channel_to_index(priv->ieee, channel); ipw_set_scan_type(scan, channel_index, geo->bg[index]. flags & @@ -6042,7 +6178,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, } } -static int ipw_request_scan(struct ipw_priv *priv) +static int ipw_request_scan_helper(struct ipw_priv *priv, int type) { struct ipw_scan_request_ext scan; int err = 0, scan_type; @@ -6051,7 +6187,7 @@ static int ipw_request_scan(struct ipw_priv *priv) (priv->status & STATUS_EXIT_PENDING)) return 0; - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->status & STATUS_SCANNING) { IPW_DEBUG_HC("Concurrent scan requested. Ignoring.\n"); @@ -6073,26 +6209,36 @@ static int ipw_request_scan(struct ipw_priv *priv) } memset(&scan, 0, sizeof(scan)); + scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); - if (priv->config & CFG_SPEED_SCAN) + if (type == IW_SCAN_TYPE_PASSIVE) { + IPW_DEBUG_WX("use passive scanning\n"); + scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN; + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = + cpu_to_le16(120); + ipw_add_scan_channels(priv, &scan, scan_type); + goto send_request; + } + + /* Use active scan by default. */ + if (priv->config & CFG_SPEED_SCAN) scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = - cpu_to_le16(30); + cpu_to_le16(30); else scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = - cpu_to_le16(20); + cpu_to_le16(20); scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = - cpu_to_le16(20); - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); + cpu_to_le16(20); - scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); #ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { u8 channel; u8 band = 0; - switch (ipw_is_valid_channel(priv->ieee, priv->channel)) { + switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { case IEEE80211_52GHZ_BAND: band = (u8) (IPW_A_MODE << 6) | 1; channel = priv->channel; @@ -6122,7 +6268,7 @@ static int ipw_request_scan(struct ipw_priv *priv) * * TODO: Move SPEED SCAN support to all modes and bands */ scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = - cpu_to_le16(2000); + cpu_to_le16(2000); } else { #endif /* CONFIG_IPW2200_MONITOR */ /* If we are roaming, then make this a directed scan for the @@ -6148,6 +6294,7 @@ static int ipw_request_scan(struct ipw_priv *priv) } #endif +send_request: err = ipw_send_scan_request_ext(priv, &scan); if (err) { IPW_DEBUG_HC("Sending scan command failed: %08X\n", err); @@ -6158,17 +6305,32 @@ static int ipw_request_scan(struct ipw_priv *priv) priv->status &= ~STATUS_SCAN_PENDING; queue_delayed_work(priv->workqueue, &priv->scan_check, IPW_SCAN_CHECK_WATCHDOG); - done: - up(&priv->sem); +done: + mutex_unlock(&priv->mutex); return err; } -static void ipw_bg_abort_scan(void *data) +static void ipw_request_passive_scan(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_abort_scan(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, request_passive_scan); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE); +} + +static void ipw_request_scan(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, request_scan.work); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE); +} + +static void ipw_bg_abort_scan(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, abort_scan); + mutex_lock(&priv->mutex); + ipw_abort_scan(priv); + mutex_unlock(&priv->mutex); } static int ipw_wpa_enable(struct ipw_priv *priv, int value) @@ -6193,6 +6355,9 @@ static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) { sec.auth_mode = WLAN_AUTH_OPEN; ieee->open_wep = 1; + } else if (value & IW_AUTH_ALG_LEAP) { + sec.auth_mode = WLAN_AUTH_LEAP; + ieee->open_wep = 1; } else return -EINVAL; @@ -6204,26 +6369,20 @@ static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) return ret; } -void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, int wpa_ie_len) +static void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, + int wpa_ie_len) { /* make sure WPA is enabled */ ipw_wpa_enable(priv, 1); - - ipw_disassociate(priv); } static int ipw_set_rsn_capa(struct ipw_priv *priv, char *capabilities, int length) { - struct host_cmd cmd = { - .cmd = IPW_CMD_RSN_CAPABILITIES, - .len = length, - }; - IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n"); - memcpy(cmd.param, capabilities, length); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_RSN_CAPABILITIES, length, + capabilities); } /* @@ -6244,13 +6403,6 @@ static int ipw_wx_set_genie(struct net_device *dev, (wrqu->data.length && extra == NULL)) return -EINVAL; - //down(&priv->sem); - - //if (!ieee->wpa_enabled) { - // err = -EOPNOTSUPP; - // goto out; - //} - if (wrqu->data.length) { buf = kmalloc(wrqu->data.length, GFP_KERNEL); if (buf == NULL) { @@ -6270,7 +6422,6 @@ static int ipw_wx_set_genie(struct net_device *dev, ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); out: - //up(&priv->sem); return err; } @@ -6283,13 +6434,6 @@ static int ipw_wx_get_genie(struct net_device *dev, struct ieee80211_device *ieee = priv->ieee; int err = 0; - //down(&priv->sem); - - //if (!ieee->wpa_enabled) { - // err = -EOPNOTSUPP; - // goto out; - //} - if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { wrqu->data.length = 0; goto out; @@ -6304,7 +6448,6 @@ static int ipw_wx_get_genie(struct net_device *dev, memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); out: - //up(&priv->sem); return err; } @@ -6408,13 +6551,13 @@ static int ipw_wx_set_auth(struct net_device *dev, case IW_AUTH_WPA_ENABLED: ret = ipw_wpa_enable(priv, param->value); + ipw_disassociate(priv); break; case IW_AUTH_RX_UNENCRYPTED_EAPOL: ieee->ieee802_1x = param->value; break; - //case IW_AUTH_ROAMING_CONTROL: case IW_AUTH_PRIVACY_INVOKED: ieee->privacy_invoked = param->value; break; @@ -6536,7 +6679,7 @@ static int ipw_wx_set_mlme(struct net_device *dev, switch (mlme->cmd) { case IW_MLME_DEAUTH: - // silently ignore + /* silently ignore */ break; case IW_MLME_DISASSOC: @@ -6549,14 +6692,14 @@ static int ipw_wx_set_mlme(struct net_device *dev, return 0; } -#ifdef CONFIG_IPW_QOS +#ifdef CONFIG_IPW2200_QOS /* QoS */ /* * get the modulation type of the current network or * the card current mode */ -u8 ipw_qos_current_mode(struct ipw_priv * priv) +static u8 ipw_qos_current_mode(struct ipw_priv * priv) { u8 mode = 0; @@ -6667,7 +6810,7 @@ static int ipw_qos_activate(struct ipw_priv *priv, burst_duration = ipw_qos_get_burst_duration(priv); for (i = 0; i < QOS_QUEUE_NUM; i++) qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] = - (u16) burst_duration; + (u16)burst_duration; } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) { if (type == IEEE_B) { IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n", @@ -6699,11 +6842,20 @@ static int ipw_qos_activate(struct ipw_priv *priv, burst_duration = ipw_qos_get_burst_duration(priv); for (i = 0; i < QOS_QUEUE_NUM; i++) qos_parameters[QOS_PARAM_SET_ACTIVE]. - tx_op_limit[i] = (u16) burst_duration; + tx_op_limit[i] = (u16)burst_duration; } } IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n"); + for (i = 0; i < 3; i++) { + int j; + for (j = 0; j < QOS_QUEUE_NUM; j++) { + qos_parameters[i].cw_min[j] = cpu_to_le16(qos_parameters[i].cw_min[j]); + qos_parameters[i].cw_max[j] = cpu_to_le16(qos_parameters[i].cw_max[j]); + qos_parameters[i].tx_op_limit[j] = cpu_to_le16(qos_parameters[i].tx_op_limit[j]); + } + } + err = ipw_send_qos_params_command(priv, (struct ieee80211_qos_parameters *) &(qos_parameters[0])); @@ -6756,8 +6908,7 @@ static int ipw_qos_association(struct ipw_priv *priv, switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: - if (!(network->capability & WLAN_CAPABILITY_IBSS)) - BUG(); + BUG_ON(!(network->capability & WLAN_CAPABILITY_IBSS)); qos_data = &ibss_data; break; @@ -6787,8 +6938,8 @@ static int ipw_qos_association(struct ipw_priv *priv, } /* -* handling the beaconing responces. if we get different QoS setting -* of the network from the the associated setting adjust the QoS +* handling the beaconing responses. if we get different QoS setting +* off the network from the associated setting, adjust the QoS * setting */ static int ipw_qos_association_resp(struct ipw_priv *priv, @@ -6897,79 +7048,74 @@ static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority) return from_priority_to_tx_queue[priority] - 1; } -/* -* add QoS parameter to the TX command -*/ -static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv, - u16 priority, - struct tfd_data *tfd, u8 unicast) +static int ipw_is_qos_active(struct net_device *dev, + struct sk_buff *skb) { - int ret = 0; - int tx_queue_id = 0; + struct ipw_priv *priv = ieee80211_priv(dev); struct ieee80211_qos_data *qos_data = NULL; int active, supported; - unsigned long flags; + u8 *daddr = skb->data + ETH_ALEN; + int unicast = !is_multicast_ether_addr(daddr); if (!(priv->status & STATUS_ASSOCIATED)) return 0; qos_data = &priv->assoc_network->qos_data; - spin_lock_irqsave(&priv->ieee->lock, flags); - if (priv->ieee->iw_mode == IW_MODE_ADHOC) { if (unicast == 0) qos_data->active = 0; else qos_data->active = qos_data->supported; } - active = qos_data->active; supported = qos_data->supported; - - spin_unlock_irqrestore(&priv->ieee->lock, flags); - IPW_DEBUG_QOS("QoS %d network is QoS active %d supported %d " "unicast %d\n", priv->qos_data.qos_enable, active, supported, unicast); - if (active && priv->qos_data.qos_enable) { - ret = from_priority_to_tx_queue[priority]; - tx_queue_id = ret - 1; - IPW_DEBUG_QOS("QoS packet priority is %d \n", priority); - if (priority <= 7) { - tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED; - tfd->tfd.tfd_26.mchdr.qos_ctrl = priority; - tfd->tfd.tfd_26.mchdr.frame_ctl |= - IEEE80211_STYPE_QOS_DATA; - - if (priv->qos_data.qos_no_ack_mask & - (1UL << tx_queue_id)) { - tfd->tx_flags &= ~DCT_FLAG_ACK_REQD; - tfd->tfd.tfd_26.mchdr.qos_ctrl |= - CTRL_QOS_NO_ACK; - } - } - } + if (active && priv->qos_data.qos_enable) + return 1; + + return 0; - return ret; +} +/* +* add QoS parameter to the TX command +*/ +static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv, + u16 priority, + struct tfd_data *tfd) +{ + int tx_queue_id = 0; + + + tx_queue_id = from_priority_to_tx_queue[priority] - 1; + tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED; + + if (priv->qos_data.qos_no_ack_mask & (1UL << tx_queue_id)) { + tfd->tx_flags &= ~DCT_FLAG_ACK_REQD; + tfd->tfd.tfd_26.mchdr.qos_ctrl |= cpu_to_le16(CTRL_QOS_NO_ACK); + } + return 0; } /* * background support to run QoS activate functionality */ -static void ipw_bg_qos_activate(void *data) +static void ipw_bg_qos_activate(struct work_struct *work) { - struct ipw_priv *priv = data; + struct ipw_priv *priv = + container_of(work, struct ipw_priv, qos_activate); if (priv == NULL) return; - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->status & STATUS_ASSOCIATED) ipw_qos_activate(priv, &(priv->assoc_network->qos_data)); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static int ipw_handle_probe_response(struct net_device *dev, @@ -7010,28 +7156,18 @@ static int ipw_handle_assoc_response(struct net_device *dev, static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters *qos_param) { - struct host_cmd cmd = { - .cmd = IPW_CMD_QOS_PARAMETERS, - .len = (sizeof(struct ieee80211_qos_parameters) * 3) - }; - - memcpy(cmd.param, qos_param, sizeof(*qos_param) * 3); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_QOS_PARAMETERS, + sizeof(*qos_param) * 3, qos_param); } static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element *qos_param) { - struct host_cmd cmd = { - .cmd = IPW_CMD_WME_INFO, - .len = sizeof(*qos_param) - }; - - memcpy(cmd.param, qos_param, sizeof(*qos_param)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_WME_INFO, sizeof(*qos_param), + qos_param); } -#endif /* CONFIG_IPW_QOS */ +#endif /* CONFIG_IPW2200_QOS */ static int ipw_associate_network(struct ipw_priv *priv, struct ieee80211_network *network, @@ -7052,19 +7188,21 @@ static int ipw_associate_network(struct ipw_priv *priv, memset(&priv->assoc_request, 0, sizeof(priv->assoc_request)); priv->assoc_request.channel = network->channel; + priv->assoc_request.auth_key = 0; + if ((priv->capability & CAP_PRIVACY_ON) && - (priv->capability & CAP_SHARED_KEY)) { + (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)) { priv->assoc_request.auth_type = AUTH_SHARED_KEY; priv->assoc_request.auth_key = priv->ieee->sec.active_key; - if ((priv->capability & CAP_PRIVACY_ON) && - (priv->ieee->sec.level == SEC_LEVEL_1) && - !(priv->ieee->host_encrypt || priv->ieee->host_decrypt)) + if (priv->ieee->sec.level == SEC_LEVEL_1) ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); - } else { + + } else if ((priv->capability & CAP_PRIVACY_ON) && + (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP)) + priv->assoc_request.auth_type = AUTH_LEAP; + else priv->assoc_request.auth_type = AUTH_OPEN; - priv->assoc_request.auth_key = 0; - } if (priv->ieee->wpa_ie_len) { priv->assoc_request.policy_support = 0x02; /* RSN active */ @@ -7168,7 +7306,7 @@ static int ipw_associate_network(struct ipw_priv *priv, else priv->sys_config.answer_broadcast_ssid_probe = 0; - err = ipw_send_system_config(priv, &priv->sys_config); + err = ipw_send_system_config(priv); if (err) { IPW_DEBUG_HC("Attempt to send sys config command failed.\n"); return err; @@ -7193,7 +7331,7 @@ static int ipw_associate_network(struct ipw_priv *priv, priv->assoc_network = network; -#ifdef CONFIG_IPW_QOS +#ifdef CONFIG_IPW2200_QOS ipw_qos_association(priv, network); #endif @@ -7275,12 +7413,13 @@ static void ipw_roam(void *data) priv->status &= ~STATUS_ROAMING; } -static void ipw_bg_roam(void *data) +static void ipw_bg_roam(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_roam(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, roam); + mutex_lock(&priv->mutex); + ipw_roam(priv); + mutex_unlock(&priv->mutex); } static int ipw_associate(void *data) @@ -7360,8 +7499,8 @@ static int ipw_associate(void *data) &priv->request_scan, SCAN_INTERVAL); else - queue_work(priv->workqueue, - &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); } return 0; @@ -7372,12 +7511,13 @@ static int ipw_associate(void *data) return 1; } -static void ipw_bg_associate(void *data) +static void ipw_bg_associate(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_associate(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, associate); + mutex_lock(&priv->mutex); + ipw_associate(priv); + mutex_unlock(&priv->mutex); } static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, @@ -7467,7 +7607,7 @@ static void ipw_handle_data_packet(struct ipw_priv *priv, } } -#ifdef CONFIG_IEEE80211_RADIOTAP +#ifdef CONFIG_IPW2200_RADIOTAP static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, struct ipw_rx_mem_buffer *rxb, struct ieee80211_rx_stats *stats) @@ -7484,15 +7624,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, /* Magic struct that slots into the radiotap header -- no reason * to build this manually element by element, we can write it much * more efficiently than we can parse it. ORDER MATTERS HERE */ - struct ipw_rt_hdr { - struct ieee80211_radiotap_header rt_hdr; - u8 rt_flags; /* radiotap packet flags */ - u8 rt_rate; /* rate in 500kb/s */ - u16 rt_channel; /* channel in mhz */ - u16 rt_chbitmask; /* channel bitfield */ - s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ - u8 rt_antenna; /* antenna number */ - } *ipw_rt; + struct ipw_rt_hdr *ipw_rt; short len = le16_to_cpu(pkt->u.frame.length); @@ -7528,41 +7660,265 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr), rxb->skb->data + IPW_RX_FRAME_SIZE, len); - /* Zero the radiotap static buffer ... We only need to zero the bytes NOT - * part of our real header, saves a little time. + /* Zero the radiotap static buffer ... We only need to zero the bytes NOT + * part of our real header, saves a little time. + * + * No longer necessary since we fill in all our data. Purge before merging + * patch officially. + * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, + * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); + */ + + ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data; + + ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ + ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total header+data */ + + /* Big bitfield of all the fields we provide in radiotap */ + ipw_rt->rt_hdr.it_present = + ((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA)); + + /* Zero the flags, we'll add to them as we go */ + ipw_rt->rt_flags = 0; + ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 | + frame->parent_tsf[2] << 16 | + frame->parent_tsf[1] << 8 | + frame->parent_tsf[0]); + + /* Convert signal to DBM */ + ipw_rt->rt_dbmsignal = antsignal; + ipw_rt->rt_dbmnoise = frame->noise; + + /* Convert the channel data and set the flags */ + ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel)); + if (received_channel > 14) { /* 802.11a */ + ipw_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); + } else if (antennaAndPhy & 32) { /* 802.11b */ + ipw_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); + } else { /* 802.11g */ + ipw_rt->rt_chbitmask = + (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ); + } + + /* set the rate in multiples of 500k/s */ + switch (pktrate) { + case IPW_TX_RATE_1MB: + ipw_rt->rt_rate = 2; + break; + case IPW_TX_RATE_2MB: + ipw_rt->rt_rate = 4; + break; + case IPW_TX_RATE_5MB: + ipw_rt->rt_rate = 10; + break; + case IPW_TX_RATE_6MB: + ipw_rt->rt_rate = 12; + break; + case IPW_TX_RATE_9MB: + ipw_rt->rt_rate = 18; + break; + case IPW_TX_RATE_11MB: + ipw_rt->rt_rate = 22; + break; + case IPW_TX_RATE_12MB: + ipw_rt->rt_rate = 24; + break; + case IPW_TX_RATE_18MB: + ipw_rt->rt_rate = 36; + break; + case IPW_TX_RATE_24MB: + ipw_rt->rt_rate = 48; + break; + case IPW_TX_RATE_36MB: + ipw_rt->rt_rate = 72; + break; + case IPW_TX_RATE_48MB: + ipw_rt->rt_rate = 96; + break; + case IPW_TX_RATE_54MB: + ipw_rt->rt_rate = 108; + break; + default: + ipw_rt->rt_rate = 0; + break; + } + + /* antenna number */ + ipw_rt->rt_antenna = (antennaAndPhy & 3); /* Is this right? */ + + /* set the preamble flag if we have it */ + if ((antennaAndPhy & 64)) + ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + /* Set the size of the skb to the size of the frame */ + skb_put(rxb->skb, len + sizeof(struct ipw_rt_hdr)); + + IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); + + if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) + priv->ieee->stats.rx_errors++; + else { /* ieee80211_rx succeeded, so it now owns the SKB */ + rxb->skb = NULL; + /* no LED during capture */ + } +} +#endif + +#ifdef CONFIG_IPW2200_PROMISCUOUS +#define ieee80211_is_probe_response(fc) \ + ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && \ + (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP ) + +#define ieee80211_is_management(fc) \ + ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) + +#define ieee80211_is_control(fc) \ + ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) + +#define ieee80211_is_data(fc) \ + ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) + +#define ieee80211_is_assoc_request(fc) \ + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ) + +#define ieee80211_is_reassoc_request(fc) \ + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) + +static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, + struct ipw_rx_mem_buffer *rxb, + struct ieee80211_rx_stats *stats) +{ + struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; + struct ipw_rx_frame *frame = &pkt->u.frame; + struct ipw_rt_hdr *ipw_rt; + + /* First cache any information we need before we overwrite + * the information provided in the skb from the hardware */ + struct ieee80211_hdr *hdr; + u16 channel = frame->received_channel; + u8 phy_flags = frame->antennaAndPhy; + s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM; + s8 noise = frame->noise; + u8 rate = frame->rate; + short len = le16_to_cpu(pkt->u.frame.length); + struct sk_buff *skb; + int hdr_only = 0; + u16 filter = priv->prom_priv->filter; + + /* If the filter is set to not include Rx frames then return */ + if (filter & IPW_PROM_NO_RX) + return; + + /* We received data from the HW, so stop the watchdog */ + priv->prom_net_dev->trans_start = jiffies; + + if (unlikely((len + IPW_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) { + priv->prom_priv->ieee->stats.rx_errors++; + IPW_DEBUG_DROP("Corruption detected! Oh no!\n"); + return; + } + + /* We only process data packets if the interface is open */ + if (unlikely(!netif_running(priv->prom_net_dev))) { + priv->prom_priv->ieee->stats.rx_dropped++; + IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); + return; + } + + /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use + * that now */ + if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) { + /* FIXME: Should alloc bigger skb instead */ + priv->prom_priv->ieee->stats.rx_dropped++; + IPW_DEBUG_DROP("Dropping too large packet in monitor\n"); + return; + } + + hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE; + if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) { + if (filter & IPW_PROM_NO_MGMT) + return; + if (filter & IPW_PROM_MGMT_HEADER_ONLY) + hdr_only = 1; + } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) { + if (filter & IPW_PROM_NO_CTL) + return; + if (filter & IPW_PROM_CTL_HEADER_ONLY) + hdr_only = 1; + } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) { + if (filter & IPW_PROM_NO_DATA) + return; + if (filter & IPW_PROM_DATA_HEADER_ONLY) + hdr_only = 1; + } + + /* Copy the SKB since this is for the promiscuous side */ + skb = skb_copy(rxb->skb, GFP_ATOMIC); + if (skb == NULL) { + IPW_ERROR("skb_clone failed for promiscuous copy.\n"); + return; + } + + /* copy the frame data to write after where the radiotap header goes */ + ipw_rt = (void *)skb->data; + + if (hdr_only) + len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + + memcpy(ipw_rt->payload, hdr, len); + + /* Zero the radiotap static buffer ... We only need to zero the bytes + * NOT part of our real header, saves a little time. * - * No longer necessary since we fill in all our data. Purge before merging - * patch officially. + * No longer necessary since we fill in all our data. Purge before + * merging patch officially. * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); */ - ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data; - ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ - ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total header+data */ + ipw_rt->rt_hdr.it_len = sizeof(*ipw_rt); /* total header+data */ + + /* Set the size of the skb to the size of the frame */ + skb_put(skb, ipw_rt->rt_hdr.it_len + len); /* Big bitfield of all the fields we provide in radiotap */ ipw_rt->rt_hdr.it_present = - ((1 << IEEE80211_RADIOTAP_FLAGS) | + ((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | (1 << IEEE80211_RADIOTAP_RATE) | (1 << IEEE80211_RADIOTAP_CHANNEL) | (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | (1 << IEEE80211_RADIOTAP_ANTENNA)); /* Zero the flags, we'll add to them as we go */ ipw_rt->rt_flags = 0; + ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 | + frame->parent_tsf[2] << 16 | + frame->parent_tsf[1] << 8 | + frame->parent_tsf[0]); - /* Convert signal to DBM */ - ipw_rt->rt_dbmsignal = antsignal; + /* Convert to DBM */ + ipw_rt->rt_dbmsignal = signal; + ipw_rt->rt_dbmnoise = noise; /* Convert the channel data and set the flags */ - ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel)); - if (received_channel > 14) { /* 802.11a */ + ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(channel)); + if (channel > 14) { /* 802.11a */ ipw_rt->rt_chbitmask = cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); - } else if (antennaAndPhy & 32) { /* 802.11b */ + } else if (phy_flags & (1 << 5)) { /* 802.11b */ ipw_rt->rt_chbitmask = cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); } else { /* 802.11g */ @@ -7571,7 +7927,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, } /* set the rate in multiples of 500k/s */ - switch (pktrate) { + switch (rate) { case IPW_TX_RATE_1MB: ipw_rt->rt_rate = 2; break; @@ -7614,22 +7970,17 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, } /* antenna number */ - ipw_rt->rt_antenna = (antennaAndPhy & 3); /* Is this right? */ + ipw_rt->rt_antenna = (phy_flags & 3); /* set the preamble flag if we have it */ - if ((antennaAndPhy & 64)) + if (phy_flags & (1 << 6)) ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - /* Set the size of the skb to the size of the frame */ - skb_put(rxb->skb, len + sizeof(struct ipw_rt_hdr)); - - IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); + IPW_DEBUG_RX("Rx packet of %d bytes.\n", skb->len); - if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) - priv->ieee->stats.rx_errors++; - else { /* ieee80211_rx succeeded, so it now owns the SKB */ - rxb->skb = NULL; - /* no LED during capture */ + if (!ieee80211_rx(priv->prom_priv->ieee, skb, stats)) { + priv->prom_priv->ieee->stats.rx_errors++; + dev_kfree_skb_any(skb); } } #endif @@ -7811,12 +8162,10 @@ static void ipw_rx(struct ipw_priv *priv) while (i != r) { rxb = priv->rxq->queue[i]; -#ifdef CONFIG_IPW2200_DEBUG if (unlikely(rxb == NULL)) { printk(KERN_CRIT "Queue not allocated!\n"); break; } -#endif priv->rxq->queue[i] = NULL; pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, @@ -7831,11 +8180,11 @@ static void ipw_rx(struct ipw_priv *priv) switch (pkt->header.message_type) { case RX_FRAME_TYPE: /* 802.11 frame */ { struct ieee80211_rx_stats stats = { - .rssi = - le16_to_cpu(pkt->u.frame.rssi_dbm) - + .rssi = pkt->u.frame.rssi_dbm - IPW_RSSI_TO_DBM, .signal = - le16_to_cpu(pkt->u.frame.signal), + le16_to_cpu(pkt->u.frame.rssi_dbm) - + IPW_RSSI_TO_DBM + 0x100, .noise = le16_to_cpu(pkt->u.frame.noise), .rate = pkt->u.frame.rate, @@ -7861,15 +8210,21 @@ static void ipw_rx(struct ipw_priv *priv) priv->rx_packets++; +#ifdef CONFIG_IPW2200_PROMISCUOUS + if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) + ipw_handle_promiscuous_rx(priv, rxb, &stats); +#endif + #ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { -#ifdef CONFIG_IEEE80211_RADIOTAP - ipw_handle_data_packet_monitor(priv, - rxb, - &stats); +#ifdef CONFIG_IPW2200_RADIOTAP + + ipw_handle_data_packet_monitor(priv, + rxb, + &stats); #else - ipw_handle_data_packet(priv, rxb, - &stats); + ipw_handle_data_packet(priv, rxb, + &stats); #endif break; } @@ -7890,16 +8245,17 @@ static void ipw_rx(struct ipw_priv *priv) if (network_packet && priv->assoc_network) { priv->assoc_network->stats.rssi = stats.rssi; - average_add(&priv->average_rssi, - stats.rssi); - priv->last_rx_rssi = stats.rssi; + priv->exp_avg_rssi = + exponential_average(priv->exp_avg_rssi, + stats.rssi, DEPTH_RSSI); } IPW_DEBUG_RX("Frame: len=%u\n", le16_to_cpu(pkt->u.frame.length)); if (le16_to_cpu(pkt->u.frame.length) < - frame_hdr_len(header)) { + ieee80211_get_hdrlen(le16_to_cpu( + header->frame_ctl))) { IPW_DEBUG_DROP ("Received packet is too small. " "Dropping.\n"); @@ -7950,7 +8306,7 @@ static void ipw_rx(struct ipw_priv *priv) ("Notification: subtype=%02X flags=%02X size=%d\n", pkt->u.notification.subtype, pkt->u.notification.flags, - pkt->u.notification.size); + le16_to_cpu(pkt->u.notification.size)); ipw_rx_notification(priv, &pkt->u.notification); break; } @@ -7989,7 +8345,14 @@ static void ipw_rx(struct ipw_priv *priv) #define DEFAULT_SHORT_RETRY_LIMIT 7U #define DEFAULT_LONG_RETRY_LIMIT 4U -static int ipw_sw_reset(struct ipw_priv *priv, int init) +/** + * ipw_sw_reset + * @option: options to control different reset behaviour + * 0 = reset everything except the 'disable' module_param + * 1 = reset everything and print out driver info (for probe only) + * 2 = reset everything + */ +static int ipw_sw_reset(struct ipw_priv *priv, int option) { int band, modulation; int old_mode = priv->ieee->iw_mode; @@ -8016,7 +8379,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init) priv->essid_len = 0; memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - if (disable) { + if (disable && option) { priv->status |= STATUS_RF_KILL_SW; IPW_DEBUG_INFO("Radio disabled.\n"); } @@ -8027,10 +8390,10 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init) IPW_DEBUG_INFO("Bind to static channel %d\n", channel); /* TODO: Validate that provided channel is in range */ } -#ifdef CONFIG_IPW_QOS +#ifdef CONFIG_IPW2200_QOS ipw_qos_init(priv, qos_enable, qos_burst_enable, burst_duration_CCK, burst_duration_OFDM); -#endif /* CONFIG_IPW_QOS */ +#endif /* CONFIG_IPW2200_QOS */ switch (mode) { case 1: @@ -8041,7 +8404,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init) #ifdef CONFIG_IPW2200_MONITOR case 2: priv->ieee->iw_mode = IW_MODE_MONITOR; -#ifdef CONFIG_IEEE80211_RADIOTAP +#ifdef CONFIG_IPW2200_RADIOTAP priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; #else priv->net_dev->type = ARPHRD_IEEE80211; @@ -8068,7 +8431,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init) if ((priv->pci_dev->device == 0x4223) || (priv->pci_dev->device == 0x4224)) { - if (init) + if (option == 1) printk(KERN_INFO DRV_NAME ": Detected Intel PRO/Wireless 2915ABG Network " "Connection\n"); @@ -8079,7 +8442,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init) priv->adapter = IPW_2915ABG; priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; } else { - if (init) + if (option == 1) printk(KERN_INFO DRV_NAME ": Detected Intel PRO/Wireless 2200BG Network " "Connection\n"); @@ -8126,7 +8489,7 @@ static int ipw_wx_get_name(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->status & STATUS_RF_KILL_MASK) strcpy(wrqu->name, "radio off"); else if (!(priv->status & STATUS_ASSOCIATED)) @@ -8135,7 +8498,7 @@ static int ipw_wx_get_name(struct net_device *dev, snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", ipw_modes[priv->assoc_request.ieee_mode]); IPW_DEBUG_WX("Name: %s\n", wrqu->name); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8196,7 +8559,7 @@ static int ipw_wx_set_freq(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee); + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); struct iw_freq *fwrq = &wrqu->freq; int ret = 0, i; u8 channel, flags; @@ -8204,24 +8567,24 @@ static int ipw_wx_set_freq(struct net_device *dev, if (fwrq->m == 0) { IPW_DEBUG_WX("SET Freq/Channel -> any\n"); - down(&priv->sem); + mutex_lock(&priv->mutex); ret = ipw_set_channel(priv, 0); - up(&priv->sem); + mutex_unlock(&priv->mutex); return ret; } /* if setting by freq convert to channel */ if (fwrq->e == 1) { - channel = ipw_freq_to_channel(priv->ieee, fwrq->m); + channel = ieee80211_freq_to_channel(priv->ieee, fwrq->m); if (channel == 0) return -EINVAL; } else channel = fwrq->m; - if (!(band = ipw_is_valid_channel(priv->ieee, channel))) + if (!(band = ieee80211_is_valid_channel(priv->ieee, channel))) return -EINVAL; if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - i = ipw_channel_to_index(priv->ieee, channel); + i = ieee80211_channel_to_index(priv->ieee, channel); if (i == -1) return -EINVAL; @@ -8234,9 +8597,9 @@ static int ipw_wx_set_freq(struct net_device *dev, } IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); - down(&priv->sem); + mutex_lock(&priv->mutex); ret = ipw_set_channel(priv, channel); - up(&priv->sem); + mutex_unlock(&priv->mutex); return ret; } @@ -8250,14 +8613,31 @@ static int ipw_wx_get_freq(struct net_device *dev, /* If we are associated, trying to associate, or have a statically * configured CHANNEL then return that; otherwise return ANY */ - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->config & CFG_STATIC_CHANNEL || - priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) - wrqu->freq.m = priv->channel; - else + priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) { + int i; + + i = ieee80211_channel_to_index(priv->ieee, priv->channel); + BUG_ON(i == -1); + wrqu->freq.e = 1; + + switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { + case IEEE80211_52GHZ_BAND: + wrqu->freq.m = priv->ieee->geo.a[i].freq * 100000; + break; + + case IEEE80211_24GHZ_BAND: + wrqu->freq.m = priv->ieee->geo.bg[i].freq * 100000; + break; + + default: + BUG(); + } + } else wrqu->freq.m = 0; - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel); return 0; } @@ -8287,7 +8667,7 @@ static int ipw_wx_set_mode(struct net_device *dev, if (wrqu->mode == priv->ieee->iw_mode) return 0; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_sw_reset(priv, 0); @@ -8296,7 +8676,7 @@ static int ipw_wx_set_mode(struct net_device *dev, priv->net_dev->type = ARPHRD_ETHER; if (wrqu->mode == IW_MODE_MONITOR) -#ifdef CONFIG_IEEE80211_RADIOTAP +#ifdef CONFIG_IPW2200_RADIOTAP priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; #else priv->net_dev->type = ARPHRD_IEEE80211; @@ -8310,7 +8690,7 @@ static int ipw_wx_set_mode(struct net_device *dev, priv->ieee->iw_mode = wrqu->mode; queue_work(priv->workqueue, &priv->adapter_restart); - up(&priv->sem); + mutex_unlock(&priv->mutex); return err; } @@ -8319,10 +8699,10 @@ static int ipw_wx_get_mode(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->mode = priv->ieee->iw_mode; IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8349,7 +8729,7 @@ static int ipw_wx_get_range(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); struct iw_range *range = (struct iw_range *)extra; - const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee); + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); int i = 0, j; wrqu->data.length = sizeof(*range); @@ -8361,7 +8741,7 @@ static int ipw_wx_get_range(struct net_device *dev, range->max_qual.qual = 100; /* TODO: Find real max RSSI and stick here */ range->max_qual.level = 0; - range->max_qual.noise = priv->ieee->worst_rssi + 0x100; + range->max_qual.noise = 0; range->max_qual.updated = 7; /* Updated all three */ range->avg_qual.qual = 70; @@ -8369,7 +8749,7 @@ static int ipw_wx_get_range(struct net_device *dev, range->avg_qual.level = 0; /* FIXME to real average level */ range->avg_qual.noise = 0; range->avg_qual.updated = 7; /* Updated all three */ - down(&priv->sem); + mutex_lock(&priv->mutex); range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES); for (i = 0; i < range->num_bitrates; i++) @@ -8387,7 +8767,7 @@ static int ipw_wx_get_range(struct net_device *dev, /* Set the Wireless Extension versions */ range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 16; + range->we_version_source = 18; i = 0; if (priv->ieee->mode & (IEEE_B | IEEE_G)) { @@ -8419,14 +8799,18 @@ static int ipw_wx_get_range(struct net_device *dev, range->num_channels = i; range->num_frequency = i; - up(&priv->sem); + mutex_unlock(&priv->mutex); /* Event capability (kernel + driver) */ range->event_capa[0] = (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | - IW_EVENT_CAPA_MASK(SIOCGIWAP)); + IW_EVENT_CAPA_MASK(SIOCGIWAP) | + IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); range->event_capa[1] = IW_EVENT_CAPA_K_1; + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + IPW_DEBUG_WX("GET Range\n"); return 0; } @@ -8446,7 +8830,7 @@ static int ipw_wx_set_wap(struct net_device *dev, if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) return -EINVAL; - down(&priv->sem); + mutex_lock(&priv->mutex); if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) || !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) { /* we disable mandatory BSSID association */ @@ -8455,14 +8839,14 @@ static int ipw_wx_set_wap(struct net_device *dev, IPW_DEBUG_ASSOC("Attempting to associate with new " "parameters.\n"); ipw_associate(priv); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } priv->config |= CFG_STATIC_BSSID; if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) { IPW_DEBUG_WX("BSSID set to current BSSID.\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8476,7 +8860,7 @@ static int ipw_wx_set_wap(struct net_device *dev, if (!ipw_disassociate(priv)) ipw_associate(priv); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8487,7 +8871,7 @@ static int ipw_wx_get_wap(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->config & CFG_STATIC_BSSID || priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { wrqu->ap_addr.sa_family = ARPHRD_ETHER; @@ -8497,7 +8881,7 @@ static int ipw_wx_get_wap(struct net_device *dev, IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n", MAC_ARG(wrqu->ap_addr.sa_data)); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8506,49 +8890,43 @@ static int ipw_wx_set_essid(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - char *essid = ""; /* ANY */ - int length = 0; - down(&priv->sem); - if (wrqu->essid.flags && wrqu->essid.length) { - length = wrqu->essid.length - 1; - essid = extra; - } - if (length == 0) { - IPW_DEBUG_WX("Setting ESSID to ANY\n"); - if ((priv->config & CFG_STATIC_ESSID) && - !(priv->status & (STATUS_ASSOCIATED | - STATUS_ASSOCIATING))) { - IPW_DEBUG_ASSOC("Attempting to associate with new " - "parameters.\n"); - priv->config &= ~CFG_STATIC_ESSID; - ipw_associate(priv); - } - up(&priv->sem); - return 0; - } + int length; - length = min(length, IW_ESSID_MAX_SIZE); + mutex_lock(&priv->mutex); + + if (!wrqu->essid.flags) + { + IPW_DEBUG_WX("Setting ESSID to ANY\n"); + ipw_disassociate(priv); + priv->config &= ~CFG_STATIC_ESSID; + ipw_associate(priv); + mutex_unlock(&priv->mutex); + return 0; + } + + length = min((int)wrqu->essid.length, IW_ESSID_MAX_SIZE); priv->config |= CFG_STATIC_ESSID; - if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) { + if (priv->essid_len == length && !memcmp(priv->essid, extra, length) + && (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { IPW_DEBUG_WX("ESSID set to current ESSID.\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } - IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length), + IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(extra, length), length); priv->essid_len = length; - memcpy(priv->essid, essid, priv->essid_len); + memcpy(priv->essid, extra, priv->essid_len); /* Network configuration changed -- force [re]association */ IPW_DEBUG_ASSOC("[re]association triggered due to ESSID change.\n"); if (!ipw_disassociate(priv)) ipw_associate(priv); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8560,7 +8938,7 @@ static int ipw_wx_get_essid(struct net_device *dev, /* If we are associated, trying to associate, or have a statically * configured ESSID then return that; otherwise return ANY */ - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->config & CFG_STATIC_ESSID || priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { IPW_DEBUG_WX("Getting essid: '%s'\n", @@ -8573,7 +8951,7 @@ static int ipw_wx_get_essid(struct net_device *dev, wrqu->essid.length = 0; wrqu->essid.flags = 0; /* active */ } - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8586,12 +8964,12 @@ static int ipw_wx_set_nick(struct net_device *dev, IPW_DEBUG_WX("Setting nick to '%s'\n", extra); if (wrqu->data.length > IW_ESSID_MAX_SIZE) return -E2BIG; - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick)); memset(priv->nick, 0, sizeof(priv->nick)); memcpy(priv->nick, extra, wrqu->data.length); IPW_DEBUG_TRACE("<<\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8602,11 +8980,57 @@ static int ipw_wx_get_nick(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); IPW_DEBUG_WX("Getting nick\n"); - down(&priv->sem); - wrqu->data.length = strlen(priv->nick) + 1; + mutex_lock(&priv->mutex); + wrqu->data.length = strlen(priv->nick); memcpy(extra, priv->nick, wrqu->data.length); wrqu->data.flags = 1; /* active */ - up(&priv->sem); + mutex_unlock(&priv->mutex); + return 0; +} + +static int ipw_wx_set_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int err = 0; + + IPW_DEBUG_WX("Setting roaming threshold to %d\n", wrqu->sens.value); + IPW_DEBUG_WX("Setting disassociate threshold to %d\n", 3*wrqu->sens.value); + mutex_lock(&priv->mutex); + + if (wrqu->sens.fixed == 0) + { + priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; + priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; + goto out; + } + if ((wrqu->sens.value > IPW_MB_ROAMING_THRESHOLD_MAX) || + (wrqu->sens.value < IPW_MB_ROAMING_THRESHOLD_MIN)) { + err = -EINVAL; + goto out; + } + + priv->roaming_threshold = wrqu->sens.value; + priv->disassociate_threshold = 3*wrqu->sens.value; + out: + mutex_unlock(&priv->mutex); + return err; +} + +static int ipw_wx_get_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + wrqu->sens.fixed = 1; + wrqu->sens.value = priv->roaming_threshold; + mutex_unlock(&priv->mutex); + + IPW_DEBUG_WX("GET roaming threshold -> %s %d \n", + wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value); + return 0; } @@ -8699,7 +9123,7 @@ static int ipw_wx_set_rate(struct net_device *dev, apply: IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n", mask, fixed ? "fixed" : "sub-rates"); - down(&priv->sem); + mutex_lock(&priv->mutex); if (mask == IEEE80211_DEFAULT_RATES_MASK) { priv->config &= ~CFG_FIXED_RATE; ipw_set_fixed_rate(priv, priv->ieee->mode); @@ -8708,7 +9132,7 @@ static int ipw_wx_set_rate(struct net_device *dev, if (priv->rates_mask == mask) { IPW_DEBUG_WX("Mask set to current mask.\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8719,7 +9143,7 @@ static int ipw_wx_set_rate(struct net_device *dev, if (!ipw_disassociate(priv)) ipw_associate(priv); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8728,9 +9152,10 @@ static int ipw_wx_get_rate(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->bitrate.value = priv->last_rate; - up(&priv->sem); + wrqu->bitrate.fixed = (priv->config & CFG_FIXED_RATE) ? 1 : 0; + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value); return 0; } @@ -8740,20 +9165,20 @@ static int ipw_wx_set_rts(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); if (wrqu->rts.disabled) priv->rts_threshold = DEFAULT_RTS_THRESHOLD; else { if (wrqu->rts.value < MIN_RTS_THRESHOLD || wrqu->rts.value > MAX_RTS_THRESHOLD) { - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EINVAL; } priv->rts_threshold = wrqu->rts.value; } ipw_send_rts_threshold(priv, priv->rts_threshold); - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold); return 0; } @@ -8763,11 +9188,11 @@ static int ipw_wx_get_rts(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->rts.value = priv->rts_threshold; wrqu->rts.fixed = 0; /* no auto select */ wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value); return 0; } @@ -8779,7 +9204,7 @@ static int ipw_wx_set_txpow(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); int err = 0; - down(&priv->sem); + mutex_lock(&priv->mutex); if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) { err = -EINPROGRESS; goto out; @@ -8802,7 +9227,7 @@ static int ipw_wx_set_txpow(struct net_device *dev, priv->tx_power = wrqu->power.value; err = ipw_set_tx_power(priv); out: - up(&priv->sem); + mutex_unlock(&priv->mutex); return err; } @@ -8811,12 +9236,12 @@ static int ipw_wx_get_txpow(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->power.value = priv->tx_power; wrqu->power.fixed = 1; wrqu->power.flags = IW_TXPOW_DBM; wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0; - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET TX Power -> %s %d \n", wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value); @@ -8829,13 +9254,13 @@ static int ipw_wx_set_frag(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); if (wrqu->frag.disabled) priv->ieee->fts = DEFAULT_FTS; else { if (wrqu->frag.value < MIN_FRAG_THRESHOLD || wrqu->frag.value > MAX_FRAG_THRESHOLD) { - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EINVAL; } @@ -8843,7 +9268,7 @@ static int ipw_wx_set_frag(struct net_device *dev, } ipw_send_frag_threshold(priv, wrqu->frag.value); - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value); return 0; } @@ -8853,11 +9278,11 @@ static int ipw_wx_get_frag(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->frag.value = priv->ieee->fts; wrqu->frag.fixed = 0; /* no auto select */ wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS); - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value); return 0; @@ -8875,13 +9300,13 @@ static int ipw_wx_set_retry(struct net_device *dev, if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) return 0; - if (wrqu->retry.value < 0 || wrqu->retry.value > 255) + if (wrqu->retry.value < 0 || wrqu->retry.value >= 255) return -EINVAL; - down(&priv->sem); - if (wrqu->retry.flags & IW_RETRY_MIN) + mutex_lock(&priv->mutex); + if (wrqu->retry.flags & IW_RETRY_SHORT) priv->short_retry_limit = (u8) wrqu->retry.value; - else if (wrqu->retry.flags & IW_RETRY_MAX) + else if (wrqu->retry.flags & IW_RETRY_LONG) priv->long_retry_limit = (u8) wrqu->retry.value; else { priv->short_retry_limit = (u8) wrqu->retry.value; @@ -8890,7 +9315,7 @@ static int ipw_wx_set_retry(struct net_device *dev, ipw_send_retry_limit(priv, priv->short_retry_limit, priv->long_retry_limit); - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("SET retry limit -> short:%d long:%d\n", priv->short_retry_limit, priv->long_retry_limit); return 0; @@ -8902,25 +9327,25 @@ static int ipw_wx_get_retry(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->retry.disabled = 0; if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EINVAL; } - if (wrqu->retry.flags & IW_RETRY_MAX) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + if (wrqu->retry.flags & IW_RETRY_LONG) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; wrqu->retry.value = priv->long_retry_limit; - } else if (wrqu->retry.flags & IW_RETRY_MIN) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; + } else if (wrqu->retry.flags & IW_RETRY_SHORT) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; wrqu->retry.value = priv->short_retry_limit; } else { wrqu->retry.flags = IW_RETRY_LIMIT; wrqu->retry.value = priv->short_retry_limit; } - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET retry -> %d \n", wrqu->retry.value); @@ -8937,7 +9362,7 @@ static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid, (priv->status & STATUS_EXIT_PENDING)) return 0; - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->status & STATUS_RF_KILL_MASK) { IPW_DEBUG_HC("Aborting scan due to RF kill activation\n"); @@ -8989,7 +9414,7 @@ static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid, priv->status |= STATUS_SCANNING; done: - up(&priv->sem); + mutex_unlock(&priv->mutex); return err; } @@ -8998,20 +9423,24 @@ static int ipw_wx_set_scan(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - struct iw_scan_req *req = NULL; - if (wrqu->data.length - && wrqu->data.length == sizeof(struct iw_scan_req)) { - req = (struct iw_scan_req *)extra; + struct iw_scan_req *req = (struct iw_scan_req *)extra; + + if (wrqu->data.length == sizeof(struct iw_scan_req)) { if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { ipw_request_direct_scan(priv, req->essid, req->essid_len); return 0; } + if (req->scan_type == IW_SCAN_TYPE_PASSIVE) { + queue_work(priv->workqueue, + &priv->request_passive_scan); + return 0; + } } IPW_DEBUG_WX("Start scan\n"); - queue_work(priv->workqueue, &priv->request_scan); + queue_delayed_work(priv->workqueue, &priv->request_scan, 0); return 0; } @@ -9032,7 +9461,7 @@ static int ipw_wx_set_encode(struct net_device *dev, int ret; u32 cap = priv->capability; - down(&priv->sem); + mutex_lock(&priv->mutex); ret = ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); /* In IBSS mode, we need to notify the firmware to update @@ -9042,7 +9471,7 @@ static int ipw_wx_set_encode(struct net_device *dev, priv->status & STATUS_ASSOCIATED) ipw_disassociate(priv); - up(&priv->sem); + mutex_unlock(&priv->mutex); return ret; } @@ -9060,17 +9489,17 @@ static int ipw_wx_set_power(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); int err; - down(&priv->sem); + mutex_lock(&priv->mutex); if (wrqu->power.disabled) { priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM); if (err) { IPW_DEBUG_WX("failed setting power mode.\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return err; } IPW_DEBUG_WX("SET Power Management Mode -> off\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9082,7 +9511,7 @@ static int ipw_wx_set_power(struct net_device *dev, default: /* Otherwise we don't support it */ IPW_DEBUG_WX("SET PM Mode: %X not supported.\n", wrqu->power.flags); - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EOPNOTSUPP; } @@ -9095,12 +9524,12 @@ static int ipw_wx_set_power(struct net_device *dev, err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); if (err) { IPW_DEBUG_WX("failed setting power mode.\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return err; } IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9109,13 +9538,13 @@ static int ipw_wx_get_power(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); if (!(priv->power_mode & IPW_POWER_ENABLED)) wrqu->power.disabled = 1; else wrqu->power.disabled = 0; - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); return 0; @@ -9128,7 +9557,7 @@ static int ipw_wx_set_powermode(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); int mode = *(int *)extra; int err; - down(&priv->sem); + mutex_lock(&priv->mutex); if ((mode < 1) || (mode > IPW_POWER_LIMIT)) { mode = IPW_POWER_AC; priv->power_mode = mode; @@ -9141,11 +9570,11 @@ static int ipw_wx_set_powermode(struct net_device *dev, if (err) { IPW_DEBUG_WX("failed setting power mode.\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return err; } } - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9194,7 +9623,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode); return -EINVAL; } - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->adapter == IPW_2915ABG) { priv->ieee->abg_true = 1; if (mode & IEEE_A) { @@ -9206,7 +9635,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, if (mode & IEEE_A) { IPW_WARNING("Attempt to set 2200BG into " "802.11a mode\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EINVAL; } @@ -9243,7 +9672,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n", mode & IEEE_A ? 'a' : '.', mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.'); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9252,7 +9681,7 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); switch (priv->ieee->mode) { case IEEE_A: strncpy(extra, "802.11a (1)", MAX_WX_STRING); @@ -9283,7 +9712,7 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra); wrqu->data.length = strlen(extra) + 1; - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9294,7 +9723,7 @@ static int ipw_wx_set_preamble(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); int mode = *(int *)extra; - down(&priv->sem); + mutex_lock(&priv->mutex); /* Switching from SHORT -> LONG requires a disassociation */ if (mode == 1) { if (!(priv->config & CFG_PREAMBLE_LONG)) { @@ -9313,11 +9742,11 @@ static int ipw_wx_set_preamble(struct net_device *dev, priv->config &= ~CFG_PREAMBLE_LONG; goto done; } - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EINVAL; done: - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9326,12 +9755,12 @@ static int ipw_wx_get_preamble(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->config & CFG_PREAMBLE_LONG) snprintf(wrqu->name, IFNAMSIZ, "long (1)"); else snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9343,11 +9772,11 @@ static int ipw_wx_set_monitor(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); int *parms = (int *)extra; int enable = (parms[0] > 0); - down(&priv->sem); + mutex_lock(&priv->mutex); IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); if (enable) { if (priv->ieee->iw_mode != IW_MODE_MONITOR) { -#ifdef CONFIG_IEEE80211_RADIOTAP +#ifdef CONFIG_IPW2200_RADIOTAP priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; #else priv->net_dev->type = ARPHRD_IEEE80211; @@ -9358,17 +9787,17 @@ static int ipw_wx_set_monitor(struct net_device *dev, ipw_set_channel(priv, parms[1]); } else { if (priv->ieee->iw_mode != IW_MODE_MONITOR) { - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } priv->net_dev->type = ARPHRD_ETHER; queue_work(priv->workqueue, &priv->adapter_restart); } - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } -#endif // CONFIG_IPW2200_MONITOR +#endif /* CONFIG_IPW2200_MONITOR */ static int ipw_wx_reset(struct net_device *dev, struct iw_request_info *info, @@ -9394,9 +9823,9 @@ static int ipw_wx_sw_reset(struct net_device *dev, IPW_DEBUG_WX("SW_RESET\n"); - down(&priv->sem); + mutex_lock(&priv->mutex); - ret = ipw_sw_reset(priv, 0); + ret = ipw_sw_reset(priv, 2); if (!ret) { free_firmware(); ipw_adapter_restart(priv); @@ -9406,9 +9835,9 @@ static int ipw_wx_sw_reset(struct net_device *dev, * module parameter, so take appropriate action */ ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW); - up(&priv->sem); + mutex_unlock(&priv->mutex); ieee80211_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL); - down(&priv->sem); + mutex_lock(&priv->mutex); if (!(priv->status & STATUS_RF_KILL_MASK)) { /* Configuration likely changed -- force [re]association */ @@ -9418,7 +9847,7 @@ static int ipw_wx_sw_reset(struct net_device *dev, ipw_associate(priv); } - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9431,6 +9860,8 @@ static iw_handler ipw_wx_handlers[] = { IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq, IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode, IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode, + IW_IOCTL(SIOCSIWSENS) = ipw_wx_set_sens, + IW_IOCTL(SIOCGIWSENS) = ipw_wx_get_sens, IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range, IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap, IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap, @@ -9573,10 +10004,10 @@ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev) } wstats->qual.qual = priv->quality; - wstats->qual.level = average_value(&priv->average_rssi); - wstats->qual.noise = average_value(&priv->average_noise); + wstats->qual.level = priv->exp_avg_rssi; + wstats->qual.noise = priv->exp_avg_noise; wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | - IW_QUAL_NOISE_UPDATED; + IW_QUAL_NOISE_UPDATED | IW_QUAL_DBM; wstats->miss.beacon = average_value(&priv->average_missed_beacons); wstats->discard.retries = priv->last_tx_failures; @@ -9594,7 +10025,7 @@ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev) static void init_sys_config(struct ipw_sys_config *sys_config) { memset(sys_config, 0, sizeof(struct ipw_sys_config)); - sys_config->bt_coexistence = 1; /* We may need to look into prvStaBtConfig */ + sys_config->bt_coexistence = 0; sys_config->answer_broadcast_ssid_probe = 0; sys_config->accept_all_data_frames = 0; sys_config->accept_non_directed_frames = 1; @@ -9602,12 +10033,15 @@ static void init_sys_config(struct ipw_sys_config *sys_config) sys_config->disable_unicast_decryption = 1; sys_config->exclude_multicast_unencrypted = 0; sys_config->disable_multicast_decryption = 1; - sys_config->antenna_diversity = CFG_SYS_ANTENNA_BOTH; + if (antenna < CFG_SYS_ANTENNA_BOTH || antenna > CFG_SYS_ANTENNA_B) + antenna = CFG_SYS_ANTENNA_BOTH; + sys_config->antenna_diversity = antenna; sys_config->pass_crc_to_host = 0; /* TODO: See if 1 gives us FCS */ sys_config->dot11g_auto_detection = 0; sys_config->enable_cts_to_self = 0; sys_config->bt_coexist_collision_thr = 0; - sys_config->pass_noise_stats_to_host = 1; //1 -- fix for 256 + sys_config->pass_noise_stats_to_host = 1; /* 1 -- fix for 256 */ + sys_config->silence_threshold = 0x1e; } static int ipw_net_open(struct net_device *dev) @@ -9615,11 +10049,11 @@ static int ipw_net_open(struct net_device *dev) struct ipw_priv *priv = ieee80211_priv(dev); IPW_DEBUG_INFO("dev->open\n"); /* we should be verifying the device is ready to be opened */ - down(&priv->sem); + mutex_lock(&priv->mutex); if (!(priv->status & STATUS_RF_KILL_MASK) && (priv->status & STATUS_ASSOCIATED)) netif_start_queue(dev); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9640,11 +10074,11 @@ we need to heavily modify the ieee80211_skb_to_txb. static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, int pri) { - struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *) + struct ieee80211_hdr_3addrqos *hdr = (struct ieee80211_hdr_3addrqos *) txb->fragments[0]->data; int i = 0; struct tfd_frame *tfd; -#ifdef CONFIG_IPW_QOS +#ifdef CONFIG_IPW2200_QOS int tx_id = ipw_get_tx_queue_number(priv, pri); struct clx2_tx_queue *txq = &priv->txq[tx_id]; #else @@ -9655,14 +10089,9 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, u16 remaining_bytes; int fc; - /* If there isn't room in the queue, we return busy and let the - * network stack requeue the packet for us */ - if (ipw_queue_space(q) < q->high_mark) - return NETDEV_TX_BUSY; - + hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: - hdr_len = IEEE80211_3ADDR_LEN; unicast = !is_multicast_ether_addr(hdr->addr1); id = ipw_find_station(priv, hdr->addr1); if (id == IPW_INVALID_STATION) { @@ -9679,7 +10108,6 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, case IW_MODE_INFRA: default: unicast = !is_multicast_ether_addr(hdr->addr3); - hdr_len = IEEE80211_3ADDR_LEN; id = 0; break; } @@ -9716,7 +10144,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, switch (priv->ieee->sec.level) { case SEC_LEVEL_3: tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= - IEEE80211_FCTL_PROTECTED; + cpu_to_le16(IEEE80211_FCTL_PROTECTED); /* XXX: ACK flag must be set for CCMP even if it * is a multicast/broadcast packet, because CCMP * group communication encrypted by GTK is @@ -9731,14 +10159,14 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, break; case SEC_LEVEL_2: tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= - IEEE80211_FCTL_PROTECTED; + cpu_to_le16(IEEE80211_FCTL_PROTECTED); tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP; tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_TKIP; tfd->u.data.key_index = DCT_WEP_INDEX_USE_IMMEDIATE; break; case SEC_LEVEL_1: tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= - IEEE80211_FCTL_PROTECTED; + cpu_to_le16(IEEE80211_FCTL_PROTECTED); tfd->u.data.key_index = priv->ieee->tx_keyidx; if (priv->ieee->sec.key_sizes[priv->ieee->tx_keyidx] <= 40) @@ -9757,9 +10185,10 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, /* No hardware encryption */ tfd->u.data.tx_flags |= DCT_FLAG_NO_WEP; -#ifdef CONFIG_IPW_QOS - ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data), unicast); -#endif /* CONFIG_IPW_QOS */ +#ifdef CONFIG_IPW2200_QOS + if (fc & IEEE80211_STYPE_QOS_DATA) + ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data)); +#endif /* CONFIG_IPW2200_QOS */ /* payload */ tfd->u.data.num_chunks = cpu_to_le32(min((u8) (NUM_TFD_CHUNKS - 2), @@ -9825,6 +10254,9 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd); ipw_write32(priv, q->reg_w, q->first_empty); + if (ipw_queue_space(q) < q->high_mark) + netif_stop_queue(priv->net_dev); + return NETDEV_TX_OK; drop: @@ -9836,12 +10268,12 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, static int ipw_net_is_queue_full(struct net_device *dev, int pri) { struct ipw_priv *priv = ieee80211_priv(dev); -#ifdef CONFIG_IPW_QOS +#ifdef CONFIG_IPW2200_QOS int tx_id = ipw_get_tx_queue_number(priv, pri); struct clx2_tx_queue *txq = &priv->txq[tx_id]; #else struct clx2_tx_queue *txq = &priv->txq[0]; -#endif /* CONFIG_IPW_QOS */ +#endif /* CONFIG_IPW2200_QOS */ if (ipw_queue_space(&txq->q) < txq->q.high_mark) return 1; @@ -9849,6 +10281,88 @@ static int ipw_net_is_queue_full(struct net_device *dev, int pri) return 0; } +#ifdef CONFIG_IPW2200_PROMISCUOUS +static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, + struct ieee80211_txb *txb) +{ + struct ieee80211_rx_stats dummystats; + struct ieee80211_hdr *hdr; + u8 n; + u16 filter = priv->prom_priv->filter; + int hdr_only = 0; + + if (filter & IPW_PROM_NO_TX) + return; + + memset(&dummystats, 0, sizeof(dummystats)); + + /* Filtering of fragment chains is done agains the first fragment */ + hdr = (void *)txb->fragments[0]->data; + if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) { + if (filter & IPW_PROM_NO_MGMT) + return; + if (filter & IPW_PROM_MGMT_HEADER_ONLY) + hdr_only = 1; + } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) { + if (filter & IPW_PROM_NO_CTL) + return; + if (filter & IPW_PROM_CTL_HEADER_ONLY) + hdr_only = 1; + } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) { + if (filter & IPW_PROM_NO_DATA) + return; + if (filter & IPW_PROM_DATA_HEADER_ONLY) + hdr_only = 1; + } + + for(n=0; nnr_frags; ++n) { + struct sk_buff *src = txb->fragments[n]; + struct sk_buff *dst; + struct ieee80211_radiotap_header *rt_hdr; + int len; + + if (hdr_only) { + hdr = (void *)src->data; + len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + } else + len = src->len; + + dst = alloc_skb( + len + IEEE80211_RADIOTAP_HDRLEN, GFP_ATOMIC); + if (!dst) continue; + + rt_hdr = (void *)skb_put(dst, sizeof(*rt_hdr)); + + rt_hdr->it_version = PKTHDR_RADIOTAP_VERSION; + rt_hdr->it_pad = 0; + rt_hdr->it_present = 0; /* after all, it's just an idea */ + rt_hdr->it_present |= (1 << IEEE80211_RADIOTAP_CHANNEL); + + *(u16*)skb_put(dst, sizeof(u16)) = cpu_to_le16( + ieee80211chan2mhz(priv->channel)); + if (priv->channel > 14) /* 802.11a */ + *(u16*)skb_put(dst, sizeof(u16)) = + cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_5GHZ); + else if (priv->ieee->mode == IEEE_B) /* 802.11b */ + *(u16*)skb_put(dst, sizeof(u16)) = + cpu_to_le16(IEEE80211_CHAN_CCK | + IEEE80211_CHAN_2GHZ); + else /* 802.11g */ + *(u16*)skb_put(dst, sizeof(u16)) = + cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_2GHZ); + + rt_hdr->it_len = dst->len; + + memcpy(skb_put(dst, len), src->data, len); + + if (!ieee80211_rx(priv->prom_priv->ieee, dst, &dummystats)) + dev_kfree_skb_any(dst); + } +} +#endif + static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, struct net_device *dev, int pri) { @@ -9866,6 +10380,11 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, goto fail_unlock; } +#ifdef CONFIG_IPW2200_PROMISCUOUS + if (rtap_iface && netif_running(priv->prom_net_dev)) + ipw_handle_promiscuous_tx(priv, txb); +#endif + ret = ipw_tx_skb(priv, txb, pri); if (ret == NETDEV_TX_OK) __ipw_led_activity_on(priv); @@ -9898,13 +10417,13 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p) struct sockaddr *addr = p; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - down(&priv->sem); + mutex_lock(&priv->mutex); priv->config |= CFG_CUSTOM_MAC; memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n", priv->net_dev->name, MAC_ARG(priv->mac_addr)); queue_work(priv->workqueue, &priv->adapter_restart); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9948,9 +10467,9 @@ static int ipw_ethtool_get_eeprom(struct net_device *dev, if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) return -EINVAL; - down(&p->sem); + mutex_lock(&p->mutex); memcpy(bytes, &p->eeprom[eeprom->offset], eeprom->len); - up(&p->sem); + mutex_unlock(&p->mutex); return 0; } @@ -9962,15 +10481,15 @@ static int ipw_ethtool_set_eeprom(struct net_device *dev, if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) return -EINVAL; - down(&p->sem); + mutex_lock(&p->mutex); memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len); for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++) ipw_write8(p, i + IPW_EEPROM_DATA, p->eeprom[i]); - up(&p->sem); + mutex_unlock(&p->mutex); return 0; } -static struct ethtool_ops ipw_ethtool_ops = { +static const struct ethtool_ops ipw_ethtool_ops = { .get_link = ipw_ethtool_get_link, .get_drvinfo = ipw_ethtool_get_drvinfo, .get_eeprom_len = ipw_ethtool_get_eeprom_len, @@ -9978,7 +10497,7 @@ static struct ethtool_ops ipw_ethtool_ops = { .set_eeprom = ipw_ethtool_set_eeprom, }; -static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) +static irqreturn_t ipw_isr(int irq, void *data) { struct ipw_priv *priv = data; u32 inta, inta_mask; @@ -9986,7 +10505,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) if (!priv) return IRQ_NONE; - spin_lock(&priv->lock); + spin_lock(&priv->irq_lock); if (!(priv->status & STATUS_INT_ENABLED)) { /* Shared IRQ */ @@ -10008,7 +10527,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) } /* tell the device to stop sending interrupts */ - ipw_disable_interrupts(priv); + __ipw_disable_interrupts(priv); /* ack current interrupts */ inta &= (IPW_INTA_MASK_ALL & inta_mask); @@ -10019,11 +10538,11 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) tasklet_schedule(&priv->irq_tasklet); - spin_unlock(&priv->lock); + spin_unlock(&priv->irq_lock); return IRQ_HANDLED; none: - spin_unlock(&priv->lock); + spin_unlock(&priv->irq_lock); return IRQ_NONE; } @@ -10058,15 +10577,16 @@ static void ipw_rf_kill(void *adapter) spin_unlock_irqrestore(&priv->lock, flags); } -static void ipw_bg_rf_kill(void *data) +static void ipw_bg_rf_kill(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_rf_kill(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, rf_kill.work); + mutex_lock(&priv->mutex); + ipw_rf_kill(priv); + mutex_unlock(&priv->mutex); } -void ipw_link_up(struct ipw_priv *priv) +static void ipw_link_up(struct ipw_priv *priv) { priv->last_seq_num = -1; priv->last_frag_num = -1; @@ -10093,15 +10613,16 @@ void ipw_link_up(struct ipw_priv *priv) queue_delayed_work(priv->workqueue, &priv->request_scan, HZ); } -static void ipw_bg_link_up(void *data) +static void ipw_bg_link_up(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_link_up(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, link_up); + mutex_lock(&priv->mutex); + ipw_link_up(priv); + mutex_unlock(&priv->mutex); } -void ipw_link_down(struct ipw_priv *priv) +static void ipw_link_down(struct ipw_priv *priv) { ipw_led_link_down(priv); netif_carrier_off(priv->net_dev); @@ -10117,16 +10638,17 @@ void ipw_link_down(struct ipw_priv *priv) if (!(priv->status & STATUS_EXIT_PENDING)) { /* Queue up another scan... */ - queue_work(priv->workqueue, &priv->request_scan); + queue_delayed_work(priv->workqueue, &priv->request_scan, 0); } } -static void ipw_bg_link_down(void *data) +static void ipw_bg_link_down(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_link_down(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, link_down); + mutex_lock(&priv->mutex); + ipw_link_down(priv); + mutex_unlock(&priv->mutex); } static int ipw_setup_deferred_work(struct ipw_priv *priv) @@ -10137,37 +10659,31 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) init_waitqueue_head(&priv->wait_command_queue); init_waitqueue_head(&priv->wait_state); - INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv); - INIT_WORK(&priv->associate, ipw_bg_associate, priv); - INIT_WORK(&priv->disassociate, ipw_bg_disassociate, priv); - INIT_WORK(&priv->system_config, ipw_system_config, priv); - INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish, priv); - INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart, priv); - INIT_WORK(&priv->rf_kill, ipw_bg_rf_kill, priv); - INIT_WORK(&priv->up, (void (*)(void *))ipw_bg_up, priv); - INIT_WORK(&priv->down, (void (*)(void *))ipw_bg_down, priv); - INIT_WORK(&priv->request_scan, - (void (*)(void *))ipw_request_scan, priv); - INIT_WORK(&priv->gather_stats, - (void (*)(void *))ipw_bg_gather_stats, priv); - INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_bg_abort_scan, priv); - INIT_WORK(&priv->roam, ipw_bg_roam, priv); - INIT_WORK(&priv->scan_check, ipw_bg_scan_check, priv); - INIT_WORK(&priv->link_up, (void (*)(void *))ipw_bg_link_up, priv); - INIT_WORK(&priv->link_down, (void (*)(void *))ipw_bg_link_down, priv); - INIT_WORK(&priv->led_link_on, (void (*)(void *))ipw_bg_led_link_on, - priv); - INIT_WORK(&priv->led_link_off, (void (*)(void *))ipw_bg_led_link_off, - priv); - INIT_WORK(&priv->led_act_off, (void (*)(void *))ipw_bg_led_activity_off, - priv); - INIT_WORK(&priv->merge_networks, - (void (*)(void *))ipw_merge_adhoc_network, priv); - -#ifdef CONFIG_IPW_QOS - INIT_WORK(&priv->qos_activate, (void (*)(void *))ipw_bg_qos_activate, - priv); -#endif /* CONFIG_IPW_QOS */ + INIT_DELAYED_WORK(&priv->adhoc_check, ipw_bg_adhoc_check); + INIT_WORK(&priv->associate, ipw_bg_associate); + INIT_WORK(&priv->disassociate, ipw_bg_disassociate); + INIT_WORK(&priv->system_config, ipw_system_config); + INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish); + INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart); + INIT_DELAYED_WORK(&priv->rf_kill, ipw_bg_rf_kill); + INIT_WORK(&priv->up, ipw_bg_up); + INIT_WORK(&priv->down, ipw_bg_down); + INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan); + INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan); + INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats); + INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan); + INIT_WORK(&priv->roam, ipw_bg_roam); + INIT_DELAYED_WORK(&priv->scan_check, ipw_bg_scan_check); + INIT_WORK(&priv->link_up, ipw_bg_link_up); + INIT_WORK(&priv->link_down, ipw_bg_link_down); + INIT_DELAYED_WORK(&priv->led_link_on, ipw_bg_led_link_on); + INIT_DELAYED_WORK(&priv->led_link_off, ipw_bg_led_link_off); + INIT_DELAYED_WORK(&priv->led_act_off, ipw_bg_led_activity_off); + INIT_WORK(&priv->merge_networks, ipw_merge_adhoc_network); + +#ifdef CONFIG_IPW2200_QOS + INIT_WORK(&priv->qos_activate, ipw_bg_qos_activate); +#endif /* CONFIG_IPW2200_QOS */ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) ipw_irq_tasklet, (unsigned long)priv); @@ -10299,12 +10815,35 @@ static int ipw_config(struct ipw_priv *priv) /* set basic system config settings */ init_sys_config(&priv->sys_config); + + /* Support Bluetooth if we have BT h/w on board, and user wants to. + * Does not support BT priority yet (don't abort or defer our Tx) */ + if (bt_coexist) { + unsigned char bt_caps = priv->eeprom[EEPROM_SKU_CAPABILITY]; + + if (bt_caps & EEPROM_SKU_CAP_BT_CHANNEL_SIG) + priv->sys_config.bt_coexistence + |= CFG_BT_COEXISTENCE_SIGNAL_CHNL; + if (bt_caps & EEPROM_SKU_CAP_BT_OOB) + priv->sys_config.bt_coexistence + |= CFG_BT_COEXISTENCE_OOB; + } + +#ifdef CONFIG_IPW2200_PROMISCUOUS + if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) { + priv->sys_config.accept_all_data_frames = 1; + priv->sys_config.accept_non_directed_frames = 1; + priv->sys_config.accept_all_mgmt_bcpr = 1; + priv->sys_config.accept_all_mgmt_frames = 1; + } +#endif + if (priv->ieee->iw_mode == IW_MODE_ADHOC) priv->sys_config.answer_broadcast_ssid_probe = 1; else priv->sys_config.answer_broadcast_ssid_probe = 0; - if (ipw_send_system_config(priv, &priv->sys_config)) + if (ipw_send_system_config(priv)) goto error; init_supported_rates(priv, &priv->rates); @@ -10316,10 +10855,10 @@ static int ipw_config(struct ipw_priv *priv) if (ipw_send_rts_threshold(priv, priv->rts_threshold)) goto error; } -#ifdef CONFIG_IPW_QOS +#ifdef CONFIG_IPW2200_QOS IPW_DEBUG_QOS("QoS: call ipw_qos_activate\n"); ipw_qos_activate(priv, NULL); -#endif /* CONFIG_IPW_QOS */ +#endif /* CONFIG_IPW2200_QOS */ if (ipw_set_random_seed(priv)) goto error; @@ -10356,6 +10895,9 @@ static int ipw_config(struct ipw_priv *priv) * not intended for resale of the above mentioned Intel adapters has * not been tested. * + * Remember to update the table in README.ipw2200 when changing this + * table. + * */ static const struct ieee80211_geo ipw_geos[] = { { /* Restricted */ @@ -10603,96 +11145,6 @@ static const struct ieee80211_geo ipw_geos[] = { } }; -/* GEO code borrowed from ieee80211_geo.c */ -static int ipw_is_valid_channel(struct ieee80211_device *ieee, u8 channel) -{ - int i; - - /* Driver needs to initialize the geography map before using - * these helper functions */ - BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); - - if (ieee->freq_band & IEEE80211_24GHZ_BAND) - for (i = 0; i < ieee->geo.bg_channels; i++) - /* NOTE: If G mode is currently supported but - * this is a B only channel, we don't see it - * as valid. */ - if ((ieee->geo.bg[i].channel == channel) && - (!(ieee->mode & IEEE_G) || - !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY))) - return IEEE80211_24GHZ_BAND; - - if (ieee->freq_band & IEEE80211_52GHZ_BAND) - for (i = 0; i < ieee->geo.a_channels; i++) - if (ieee->geo.a[i].channel == channel) - return IEEE80211_52GHZ_BAND; - - return 0; -} - -static int ipw_channel_to_index(struct ieee80211_device *ieee, u8 channel) -{ - int i; - - /* Driver needs to initialize the geography map before using - * these helper functions */ - BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); - - if (ieee->freq_band & IEEE80211_24GHZ_BAND) - for (i = 0; i < ieee->geo.bg_channels; i++) - if (ieee->geo.bg[i].channel == channel) - return i; - - if (ieee->freq_band & IEEE80211_52GHZ_BAND) - for (i = 0; i < ieee->geo.a_channels; i++) - if (ieee->geo.a[i].channel == channel) - return i; - - return -1; -} - -static u8 ipw_freq_to_channel(struct ieee80211_device *ieee, u32 freq) -{ - int i; - - /* Driver needs to initialize the geography map before using - * these helper functions */ - BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); - - freq /= 100000; - - if (ieee->freq_band & IEEE80211_24GHZ_BAND) - for (i = 0; i < ieee->geo.bg_channels; i++) - if (ieee->geo.bg[i].freq == freq) - return ieee->geo.bg[i].channel; - - if (ieee->freq_band & IEEE80211_52GHZ_BAND) - for (i = 0; i < ieee->geo.a_channels; i++) - if (ieee->geo.a[i].freq == freq) - return ieee->geo.a[i].channel; - - return 0; -} - -static int ipw_set_geo(struct ieee80211_device *ieee, - const struct ieee80211_geo *geo) -{ - memcpy(ieee->geo.name, geo->name, 3); - ieee->geo.name[3] = '\0'; - ieee->geo.bg_channels = geo->bg_channels; - ieee->geo.a_channels = geo->a_channels; - memcpy(ieee->geo.bg, geo->bg, geo->bg_channels * - sizeof(struct ieee80211_channel)); - memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels * - sizeof(struct ieee80211_channel)); - return 0; -} - -static const struct ieee80211_geo *ipw_get_geo(struct ieee80211_device *ieee) -{ - return &ieee->geo; -} - #define MAX_HW_RESTARTS 5 static int ipw_up(struct ipw_priv *priv) { @@ -10702,13 +11154,13 @@ static int ipw_up(struct ipw_priv *priv) return -EIO; if (cmdlog && !priv->cmdlog) { - priv->cmdlog = kmalloc(sizeof(*priv->cmdlog) * cmdlog, + priv->cmdlog = kcalloc(cmdlog, sizeof(*priv->cmdlog), GFP_KERNEL); if (priv->cmdlog == NULL) { IPW_ERROR("Error allocating %d command log entries.\n", cmdlog); + return -ENOMEM; } else { - memset(priv->cmdlog, 0, sizeof(*priv->cmdlog) * cmdlog); priv->cmdlog_len = cmdlog; } } @@ -10739,14 +11191,11 @@ static int ipw_up(struct ipw_priv *priv) priv->eeprom[EEPROM_COUNTRY_CODE + 2]); j = 0; } - if (ipw_set_geo(priv->ieee, &ipw_geos[j])) { + if (ieee80211_set_geo(priv->ieee, &ipw_geos[j])) { IPW_WARNING("Could not set geography."); return 0; } - IPW_DEBUG_INFO("Geography %03d [%s] detected.\n", - j, priv->ieee->geo.name); - if (priv->status & STATUS_RF_KILL_SW) { IPW_WARNING("Radio disabled by module parameter.\n"); return 0; @@ -10765,7 +11214,8 @@ static int ipw_up(struct ipw_priv *priv) /* If configure to try and auto-associate, kick * off a scan. */ - queue_work(priv->workqueue, &priv->request_scan); + queue_delayed_work(priv->workqueue, + &priv->request_scan, 0); return 0; } @@ -10786,12 +11236,13 @@ static int ipw_up(struct ipw_priv *priv) return -EIO; } -static void ipw_bg_up(void *data) +static void ipw_bg_up(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_up(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, up); + mutex_lock(&priv->mutex); + ipw_up(priv); + mutex_unlock(&priv->mutex); } static void ipw_deinit(struct ipw_priv *priv) @@ -10857,26 +11308,27 @@ static void ipw_down(struct ipw_priv *priv) ipw_led_radio_off(priv); } -static void ipw_bg_down(void *data) +static void ipw_bg_down(struct work_struct *work) { - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_down(data); - up(&priv->sem); + struct ipw_priv *priv = + container_of(work, struct ipw_priv, down); + mutex_lock(&priv->mutex); + ipw_down(priv); + mutex_unlock(&priv->mutex); } /* Called by register_netdev() */ static int ipw_net_init(struct net_device *dev) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); if (ipw_up(priv)) { - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EIO; } - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -10931,6 +11383,10 @@ static struct attribute *ipw_sysfs_entries[] = { &dev_attr_led.attr, &dev_attr_speed_scan.attr, &dev_attr_net_stats.attr, +#ifdef CONFIG_IPW2200_PROMISCUOUS + &dev_attr_rtap_iface.attr, + &dev_attr_rtap_filter.attr, +#endif NULL }; @@ -10939,6 +11395,109 @@ static struct attribute_group ipw_attribute_group = { .attrs = ipw_sysfs_entries, }; +#ifdef CONFIG_IPW2200_PROMISCUOUS +static int ipw_prom_open(struct net_device *dev) +{ + struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); + struct ipw_priv *priv = prom_priv->priv; + + IPW_DEBUG_INFO("prom dev->open\n"); + netif_carrier_off(dev); + netif_stop_queue(dev); + + if (priv->ieee->iw_mode != IW_MODE_MONITOR) { + priv->sys_config.accept_all_data_frames = 1; + priv->sys_config.accept_non_directed_frames = 1; + priv->sys_config.accept_all_mgmt_bcpr = 1; + priv->sys_config.accept_all_mgmt_frames = 1; + + ipw_send_system_config(priv); + } + + return 0; +} + +static int ipw_prom_stop(struct net_device *dev) +{ + struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); + struct ipw_priv *priv = prom_priv->priv; + + IPW_DEBUG_INFO("prom dev->stop\n"); + + if (priv->ieee->iw_mode != IW_MODE_MONITOR) { + priv->sys_config.accept_all_data_frames = 0; + priv->sys_config.accept_non_directed_frames = 0; + priv->sys_config.accept_all_mgmt_bcpr = 0; + priv->sys_config.accept_all_mgmt_frames = 0; + + ipw_send_system_config(priv); + } + + return 0; +} + +static int ipw_prom_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + IPW_DEBUG_INFO("prom dev->xmit\n"); + netif_stop_queue(dev); + return -EOPNOTSUPP; +} + +static struct net_device_stats *ipw_prom_get_stats(struct net_device *dev) +{ + struct ipw_prom_priv *prom_priv = ieee80211_priv(dev); + return &prom_priv->ieee->stats; +} + +static int ipw_prom_alloc(struct ipw_priv *priv) +{ + int rc = 0; + + if (priv->prom_net_dev) + return -EPERM; + + priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv)); + if (priv->prom_net_dev == NULL) + return -ENOMEM; + + priv->prom_priv = ieee80211_priv(priv->prom_net_dev); + priv->prom_priv->ieee = netdev_priv(priv->prom_net_dev); + priv->prom_priv->priv = priv; + + strcpy(priv->prom_net_dev->name, "rtap%d"); + + priv->prom_net_dev->type = ARPHRD_IEEE80211_RADIOTAP; + priv->prom_net_dev->open = ipw_prom_open; + priv->prom_net_dev->stop = ipw_prom_stop; + priv->prom_net_dev->get_stats = ipw_prom_get_stats; + priv->prom_net_dev->hard_start_xmit = ipw_prom_hard_start_xmit; + + priv->prom_priv->ieee->iw_mode = IW_MODE_MONITOR; + + rc = register_netdev(priv->prom_net_dev); + if (rc) { + free_ieee80211(priv->prom_net_dev); + priv->prom_net_dev = NULL; + return rc; + } + + return 0; +} + +static void ipw_prom_free(struct ipw_priv *priv) +{ + if (!priv->prom_net_dev) + return; + + unregister_netdev(priv->prom_net_dev); + free_ieee80211(priv->prom_net_dev); + + priv->prom_net_dev = NULL; +} + +#endif + + static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0; @@ -10959,14 +11518,13 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->net_dev = net_dev; priv->pci_dev = pdev; -#ifdef CONFIG_IPW2200_DEBUG ipw_debug_level = debug; -#endif + spin_lock_init(&priv->irq_lock); spin_lock_init(&priv->lock); for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); - init_MUTEX(&priv->sem); + mutex_init(&priv->mutex); if (pci_enable_device(pdev)) { err = -ENODEV; goto out_free_ieee80211; @@ -11015,7 +11573,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ipw_sw_reset(priv, 1); - err = request_irq(pdev->irq, ipw_isr, SA_SHIRQ, DRV_NAME, priv); + err = request_irq(pdev->irq, ipw_isr, IRQF_SHARED, DRV_NAME, priv); if (err) { IPW_ERROR("Error allocating IRQ %d\n", pdev->irq); goto out_destroy_workqueue; @@ -11024,17 +11582,18 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SET_MODULE_OWNER(net_dev); SET_NETDEV_DEV(net_dev, &pdev->dev); - down(&priv->sem); + mutex_lock(&priv->mutex); priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; priv->ieee->set_security = shim__set_security; priv->ieee->is_queue_full = ipw_net_is_queue_full; -#ifdef CONFIG_IPW_QOS +#ifdef CONFIG_IPW2200_QOS + priv->ieee->is_qos_active = ipw_is_qos_active; priv->ieee->handle_probe_response = ipw_handle_beacon; priv->ieee->handle_beacon = ipw_handle_probe_response; priv->ieee->handle_assoc_response = ipw_handle_assoc_response; -#endif /* CONFIG_IPW_QOS */ +#endif /* CONFIG_IPW2200_QOS */ priv->ieee->perfect_rssi = -20; priv->ieee->worst_rssi = -85; @@ -11057,16 +11616,34 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group); if (err) { IPW_ERROR("failed to create sysfs device attributes\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); goto out_release_irq; } - up(&priv->sem); + mutex_unlock(&priv->mutex); err = register_netdev(net_dev); if (err) { IPW_ERROR("failed to register network device\n"); goto out_remove_sysfs; } + +#ifdef CONFIG_IPW2200_PROMISCUOUS + if (rtap_iface) { + err = ipw_prom_alloc(priv); + if (err) { + IPW_ERROR("Failed to register promiscuous network " + "device (error %d).\n", err); + unregister_netdev(priv->net_dev); + goto out_remove_sysfs; + } + } +#endif + + printk(KERN_INFO DRV_NAME ": Detected geography %s (%d 802.11bg " + "channels, %d 802.11a channels)\n", + priv->ieee->geo.name, priv->ieee->geo.bg_channels, + priv->ieee->geo.a_channels); + return 0; out_remove_sysfs: @@ -11098,13 +11675,13 @@ static void ipw_pci_remove(struct pci_dev *pdev) if (!priv) return; - down(&priv->sem); + mutex_lock(&priv->mutex); priv->status |= STATUS_EXIT_PENDING; ipw_down(priv); sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); - up(&priv->sem); + mutex_unlock(&priv->mutex); unregister_netdev(priv->net_dev); @@ -11136,10 +11713,12 @@ static void ipw_pci_remove(struct pci_dev *pdev) } } - if (priv->error) { - ipw_free_error_log(priv->error); - priv->error = NULL; - } + kfree(priv->error); + priv->error = NULL; + +#ifdef CONFIG_IPW2200_PROMISCUOUS + ipw_prom_free(priv); +#endif free_irq(pdev->irq, priv); iounmap(priv->hw_base); @@ -11175,12 +11754,18 @@ static int ipw_pci_resume(struct pci_dev *pdev) { struct ipw_priv *priv = pci_get_drvdata(pdev); struct net_device *dev = priv->net_dev; + int err; u32 val; printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name); pci_set_power_state(pdev, PCI_D0); - pci_enable_device(pdev); + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "%s: pci_enable_device failed on resume\n", + dev->name); + return err; + } pci_restore_state(pdev); /* @@ -11204,6 +11789,16 @@ static int ipw_pci_resume(struct pci_dev *pdev) } #endif +static void ipw_pci_shutdown(struct pci_dev *pdev) +{ + struct ipw_priv *priv = pci_get_drvdata(pdev); + + /* Take down the device; powers it off, etc. */ + ipw_down(priv); + + pci_disable_device(pdev); +} + /* driver initialization stuff */ static struct pci_driver ipw_driver = { .name = DRV_NAME, @@ -11214,6 +11809,7 @@ static struct pci_driver ipw_driver = { .suspend = ipw_pci_suspend, .resume = ipw_pci_resume, #endif + .shutdown = ipw_pci_shutdown, }; static int __init ipw_init(void) @@ -11223,7 +11819,7 @@ static int __init ipw_init(void) printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); - ret = pci_module_init(&ipw_driver); + ret = pci_register_driver(&ipw_driver); if (ret) { IPW_ERROR("Unable to initialize PCI module\n"); return ret; @@ -11263,7 +11859,12 @@ MODULE_PARM_DESC(debug, "debug output mask"); module_param(channel, int, 0444); MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); -#ifdef CONFIG_IPW_QOS +#ifdef CONFIG_IPW2200_PROMISCUOUS +module_param(rtap_iface, int, 0444); +MODULE_PARM_DESC(rtap_iface, "create the rtap interface (1 - create, default 0)"); +#endif + +#ifdef CONFIG_IPW2200_QOS module_param(qos_enable, int, 0444); MODULE_PARM_DESC(qos_enable, "enable all QoS functionalitis"); @@ -11278,7 +11879,7 @@ MODULE_PARM_DESC(burst_duration_CCK, "set CCK burst value"); module_param(burst_duration_OFDM, int, 0444); MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value"); -#endif /* CONFIG_IPW_QOS */ +#endif /* CONFIG_IPW2200_QOS */ #ifdef CONFIG_IPW2200_MONITOR module_param(mode, int, 0444); @@ -11288,12 +11889,21 @@ module_param(mode, int, 0444); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)"); #endif +module_param(bt_coexist, int, 0444); +MODULE_PARM_DESC(bt_coexist, "enable bluetooth coexistence (default off)"); + module_param(hwcrypto, int, 0444); -MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default on)"); +MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default off)"); module_param(cmdlog, int, 0444); MODULE_PARM_DESC(cmdlog, "allocate a ring buffer for logging firmware commands"); +module_param(roaming, int, 0444); +MODULE_PARM_DESC(roaming, "enable roaming support (default on)"); + +module_param(antenna, int, 0444); +MODULE_PARM_DESC(antenna, "select antenna 1=Main, 3=Aux, default 0 [both], 2=slow_diversity (choose the one with lower background noise)"); + module_exit(ipw_exit); module_init(ipw_init);