diff options
Diffstat (limited to 'drivers/net/wireless/zd1211rw')
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_chip.c | 186 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_chip.h | 168 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_def.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_ieee80211.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_ieee80211.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.c | 487 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.h | 42 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_netdev.c | 17 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_usb.c | 59 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_usb.h | 16 |
10 files changed, 645 insertions, 344 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 7c4e32cf0d4..77e11ddad83 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -249,7 +249,6 @@ int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value) { int r; - ZD_ASSERT(!mutex_is_locked(&chip->mutex)); mutex_lock(&chip->mutex); r = zd_ioread16_locked(chip, value, addr); mutex_unlock(&chip->mutex); @@ -260,7 +259,6 @@ int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value) { int r; - ZD_ASSERT(!mutex_is_locked(&chip->mutex)); mutex_lock(&chip->mutex); r = zd_ioread32_locked(chip, value, addr); mutex_unlock(&chip->mutex); @@ -271,7 +269,6 @@ int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value) { int r; - ZD_ASSERT(!mutex_is_locked(&chip->mutex)); mutex_lock(&chip->mutex); r = zd_iowrite16_locked(chip, value, addr); mutex_unlock(&chip->mutex); @@ -282,7 +279,6 @@ int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value) { int r; - ZD_ASSERT(!mutex_is_locked(&chip->mutex)); mutex_lock(&chip->mutex); r = zd_iowrite32_locked(chip, value, addr); mutex_unlock(&chip->mutex); @@ -294,7 +290,6 @@ int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses, { int r; - ZD_ASSERT(!mutex_is_locked(&chip->mutex)); mutex_lock(&chip->mutex); r = zd_ioread32v_locked(chip, values, addresses, count); mutex_unlock(&chip->mutex); @@ -306,7 +301,6 @@ int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs, { int r; - ZD_ASSERT(!mutex_is_locked(&chip->mutex)); mutex_lock(&chip->mutex); r = zd_iowrite32a_locked(chip, ioreqs, count); mutex_unlock(&chip->mutex); @@ -331,13 +325,22 @@ static int read_pod(struct zd_chip *chip, u8 *rf_type) chip->patch_cr157 = (value >> 13) & 0x1; chip->patch_6m_band_edge = (value >> 21) & 0x1; chip->new_phy_layout = (value >> 31) & 0x1; + chip->link_led = ((value >> 4) & 1) ? LED1 : LED2; + chip->supports_tx_led = 1; + if (value & (1 << 24)) { /* LED scenario */ + if (value & (1 << 29)) + chip->supports_tx_led = 0; + } dev_dbg_f(zd_chip_dev(chip), "RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d " - "patch 6M %d new PHY %d\n", + "patch 6M %d new PHY %d link LED%d tx led %d\n", zd_rf_name(*rf_type), *rf_type, chip->pa_type, chip->patch_cck_gain, - chip->patch_cr157, chip->patch_6m_band_edge, chip->new_phy_layout); + chip->patch_cr157, chip->patch_6m_band_edge, + chip->new_phy_layout, + chip->link_led == LED1 ? 1 : 2, + chip->supports_tx_led); return 0; error: *rf_type = 0; @@ -1073,6 +1076,31 @@ static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std) return zd_iowrite32_locked(chip, rates, CR_MANDATORY_RATE_TBL); } +int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, + u8 rts_rate, int preamble) +{ + int rts_mod = ZD_RX_CCK; + u32 value = 0; + + /* Modulation bit */ + if (ZD_CS_TYPE(rts_rate) == ZD_CS_OFDM) + rts_mod = ZD_RX_OFDM; + + dev_dbg_f(zd_chip_dev(chip), "rts_rate=%x preamble=%x\n", + rts_rate, preamble); + + value |= rts_rate << RTSCTS_SH_RTS_RATE; + value |= rts_mod << RTSCTS_SH_RTS_MOD_TYPE; + value |= preamble << RTSCTS_SH_RTS_PMB_TYPE; + value |= preamble << RTSCTS_SH_CTS_PMB_TYPE; + + /* We always send 11M self-CTS messages, like the vendor driver. */ + value |= ZD_CCK_RATE_11M << RTSCTS_SH_CTS_RATE; + value |= ZD_RX_CCK << RTSCTS_SH_CTS_MOD_TYPE; + + return zd_iowrite32_locked(chip, value, CR_RTS_CTS_RATE); +} + int zd_chip_enable_hwint(struct zd_chip *chip) { int r; @@ -1181,7 +1209,7 @@ static int update_pwr_int(struct zd_chip *chip, u8 channel) u8 value = chip->pwr_int_values[channel - 1]; dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n", channel, value); - return zd_iowrite32_locked(chip, value, CR31); + return zd_iowrite16_locked(chip, value, CR31); } static int update_pwr_cal(struct zd_chip *chip, u8 channel) @@ -1189,12 +1217,12 @@ static int update_pwr_cal(struct zd_chip *chip, u8 channel) u8 value = chip->pwr_cal_values[channel-1]; dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n", channel, value); - return zd_iowrite32_locked(chip, value, CR68); + return zd_iowrite16_locked(chip, value, CR68); } static int update_ofdm_cal(struct zd_chip *chip, u8 channel) { - struct zd_ioreq32 ioreqs[3]; + struct zd_ioreq16 ioreqs[3]; ioreqs[0].addr = CR67; ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1]; @@ -1206,7 +1234,7 @@ static int update_ofdm_cal(struct zd_chip *chip, u8 channel) dev_dbg_f(zd_chip_dev(chip), "channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n", channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value); - return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); } static int update_channel_integration_and_calibration(struct zd_chip *chip, @@ -1218,7 +1246,7 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip, if (r) return r; if (chip->is_zd1211b) { - static const struct zd_ioreq32 ioreqs[] = { + static const struct zd_ioreq16 ioreqs[] = { { CR69, 0x28 }, {}, { CR69, 0x2a }, @@ -1230,7 +1258,7 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip, r = update_pwr_cal(chip, channel); if (r) return r; - r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); if (r) return r; } @@ -1252,7 +1280,7 @@ static int patch_cck_gain(struct zd_chip *chip) if (r) return r; dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff); - return zd_iowrite32_locked(chip, value & 0xff, CR47); + return zd_iowrite16_locked(chip, value & 0xff, CR47); } int zd_chip_set_channel(struct zd_chip *chip, u8 channel) @@ -1295,103 +1323,69 @@ u8 zd_chip_get_channel(struct zd_chip *chip) return channel; } -static u16 led_mask(int led) +int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) { - switch (led) { - case 1: - return LED1; - case 2: - return LED2; - default: - return 0; - } -} - -static int read_led_reg(struct zd_chip *chip, u16 *status) -{ - ZD_ASSERT(mutex_is_locked(&chip->mutex)); - return zd_ioread16_locked(chip, status, CR_LED); -} - -static int write_led_reg(struct zd_chip *chip, u16 status) -{ - ZD_ASSERT(mutex_is_locked(&chip->mutex)); - return zd_iowrite16_locked(chip, status, CR_LED); -} + static const zd_addr_t a[] = { + FW_LINK_STATUS, + CR_LED, + }; -int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status) -{ - int r, ret; - u16 mask = led_mask(led); - u16 reg; + int r; + u16 v[ARRAY_SIZE(a)]; + struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = { + [0] = { FW_LINK_STATUS }, + [1] = { CR_LED }, + }; + u16 other_led; - if (!mask) - return -EINVAL; mutex_lock(&chip->mutex); - r = read_led_reg(chip, ®); + r = zd_ioread16v_locked(chip, v, (const zd_addr_t *)a, ARRAY_SIZE(a)); if (r) - return r; + goto out; + + other_led = chip->link_led == LED1 ? LED2 : LED1; + switch (status) { - case LED_STATUS: - return (reg & mask) ? LED_ON : LED_OFF; case LED_OFF: - reg &= ~mask; - ret = LED_OFF; + ioreqs[0].value = FW_LINK_OFF; + ioreqs[1].value = v[1] & ~(LED1|LED2); break; - case LED_FLIP: - reg ^= mask; - ret = (reg&mask) ? LED_ON : LED_OFF; + case LED_SCANNING: + ioreqs[0].value = FW_LINK_OFF; + ioreqs[1].value = v[1] & ~other_led; + if (get_seconds() % 3 == 0) { + ioreqs[1].value &= ~chip->link_led; + } else { + ioreqs[1].value |= chip->link_led; + } break; - case LED_ON: - reg |= mask; - ret = LED_ON; + case LED_ASSOCIATED: + ioreqs[0].value = FW_LINK_TX; + ioreqs[1].value = v[1] & ~other_led; + ioreqs[1].value |= chip->link_led; break; default: - return -EINVAL; - } - r = write_led_reg(chip, reg); - if (r) { - ret = r; + r = -EINVAL; goto out; } -out: - mutex_unlock(&chip->mutex); - return r; -} - -int zd_chip_led_flip(struct zd_chip *chip, int led, - const unsigned int *phases_msecs, unsigned int count) -{ - int i, r; - enum led_status status; - r = zd_chip_led_status(chip, led, LED_STATUS); - if (r) - return r; - status = r; - for (i = 0; i < count; i++) { - r = zd_chip_led_status(chip, led, LED_FLIP); - if (r < 0) + if (v[0] != ioreqs[0].value || v[1] != ioreqs[1].value) { + r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + if (r) goto out; - msleep(phases_msecs[i]); } - + r = 0; out: - zd_chip_led_status(chip, led, status); + mutex_unlock(&chip->mutex); return r; } -int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates) +int zd_chip_set_basic_rates_locked(struct zd_chip *chip, u16 cr_rates) { - int r; - - if (cr_rates & ~(CR_RATES_80211B|CR_RATES_80211G)) - return -EINVAL; + ZD_ASSERT((cr_rates & ~(CR_RATES_80211B | CR_RATES_80211G)) == 0); + dev_dbg_f(zd_chip_dev(chip), "%x\n", cr_rates); - mutex_lock(&chip->mutex); - r = zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL); - mutex_unlock(&chip->mutex); - return r; + return zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL); } static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size) @@ -1680,3 +1674,15 @@ int zd_rfwritev_cr_locked(struct zd_chip *chip, return 0; } +int zd_chip_set_multicast_hash(struct zd_chip *chip, + struct zd_mc_hash *hash) +{ + struct zd_ioreq32 ioreqs[] = { + { CR_GROUP_HASH_P1, hash->low }, + { CR_GROUP_HASH_P2, hash->high }, + }; + + dev_dbg_f(zd_chip_dev(chip), "hash l 0x%08x h 0x%08x\n", + ioreqs[0].value, ioreqs[1].value); + return zd_iowrite32a(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 4b125085989..a4e3cee9b59 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -337,24 +337,24 @@ #define CR_MAC_PS_STATE CTL_REG(0x050C) #define CR_INTERRUPT CTL_REG(0x0510) -#define INT_TX_COMPLETE 0x00000001 -#define INT_RX_COMPLETE 0x00000002 -#define INT_RETRY_FAIL 0x00000004 -#define INT_WAKEUP 0x00000008 -#define INT_DTIM_NOTIFY 0x00000020 -#define INT_CFG_NEXT_BCN 0x00000040 -#define INT_BUS_ABORT 0x00000080 -#define INT_TX_FIFO_READY 0x00000100 -#define INT_UART 0x00000200 -#define INT_TX_COMPLETE_EN 0x00010000 -#define INT_RX_COMPLETE_EN 0x00020000 -#define INT_RETRY_FAIL_EN 0x00040000 -#define INT_WAKEUP_EN 0x00080000 -#define INT_DTIM_NOTIFY_EN 0x00200000 -#define INT_CFG_NEXT_BCN_EN 0x00400000 -#define INT_BUS_ABORT_EN 0x00800000 -#define INT_TX_FIFO_READY_EN 0x01000000 -#define INT_UART_EN 0x02000000 +#define INT_TX_COMPLETE (1 << 0) +#define INT_RX_COMPLETE (1 << 1) +#define INT_RETRY_FAIL (1 << 2) +#define INT_WAKEUP (1 << 3) +#define INT_DTIM_NOTIFY (1 << 5) +#define INT_CFG_NEXT_BCN (1 << 6) +#define INT_BUS_ABORT (1 << 7) +#define INT_TX_FIFO_READY (1 << 8) +#define INT_UART (1 << 9) +#define INT_TX_COMPLETE_EN (1 << 16) +#define INT_RX_COMPLETE_EN (1 << 17) +#define INT_RETRY_FAIL_EN (1 << 18) +#define INT_WAKEUP_EN (1 << 19) +#define INT_DTIM_NOTIFY_EN (1 << 21) +#define INT_CFG_NEXT_BCN_EN (1 << 22) +#define INT_BUS_ABORT_EN (1 << 23) +#define INT_TX_FIFO_READY_EN (1 << 24) +#define INT_UART_EN (1 << 25) #define CR_TSF_LOW_PART CTL_REG(0x0514) #define CR_TSF_HIGH_PART CTL_REG(0x0518) @@ -390,26 +390,35 @@ #define CR_BSSID_P1 CTL_REG(0x0618) #define CR_BSSID_P2 CTL_REG(0x061C) #define CR_BCN_PLCP_CFG CTL_REG(0x0620) + +/* Group hash table for filtering incoming packets. + * + * The group hash table is 64 bit large and split over two parts. The first + * part is the lower part. The upper 6 bits of the last byte of the target + * address are used as index. Packets are received if the hash table bit is + * set. This is used for multicast handling, but for broadcasts (address + * ff:ff:ff:ff:ff:ff) the highest bit in the second table must also be set. + */ #define CR_GROUP_HASH_P1 CTL_REG(0x0624) #define CR_GROUP_HASH_P2 CTL_REG(0x0628) -#define CR_RX_TIMEOUT CTL_REG(0x062C) +#define CR_RX_TIMEOUT CTL_REG(0x062C) /* Basic rates supported by the BSS. When producing ACK or CTS messages, the * device will use a rate in this table that is less than or equal to the rate * of the incoming frame which prompted the response */ #define CR_BASIC_RATE_TBL CTL_REG(0x0630) -#define CR_RATE_1M 0x0001 /* 802.11b */ -#define CR_RATE_2M 0x0002 /* 802.11b */ -#define CR_RATE_5_5M 0x0004 /* 802.11b */ -#define CR_RATE_11M 0x0008 /* 802.11b */ -#define CR_RATE_6M 0x0100 /* 802.11g */ -#define CR_RATE_9M 0x0200 /* 802.11g */ -#define CR_RATE_12M 0x0400 /* 802.11g */ -#define CR_RATE_18M 0x0800 /* 802.11g */ -#define CR_RATE_24M 0x1000 /* 802.11g */ -#define CR_RATE_36M 0x2000 /* 802.11g */ -#define CR_RATE_48M 0x4000 /* 802.11g */ -#define CR_RATE_54M 0x8000 /* 802.11g */ +#define CR_RATE_1M (1 << 0) /* 802.11b */ +#define CR_RATE_2M (1 << 1) /* 802.11b */ +#define CR_RATE_5_5M (1 << 2) /* 802.11b */ +#define CR_RATE_11M (1 << 3) /* 802.11b */ +#define CR_RATE_6M (1 << 8) /* 802.11g */ +#define CR_RATE_9M (1 << 9) /* 802.11g */ +#define CR_RATE_12M (1 << 10) /* 802.11g */ +#define CR_RATE_18M (1 << 11) /* 802.11g */ +#define CR_RATE_24M (1 << 12) /* 802.11g */ +#define CR_RATE_36M (1 << 13) /* 802.11g */ +#define CR_RATE_48M (1 << 14) /* 802.11g */ +#define CR_RATE_54M (1 << 15) /* 802.11g */ #define CR_RATES_80211G 0xff00 #define CR_RATES_80211B 0x000f @@ -420,14 +429,24 @@ #define CR_MANDATORY_RATE_TBL CTL_REG(0x0634) #define CR_RTS_CTS_RATE CTL_REG(0x0638) +/* These are all bit indexes in CR_RTS_CTS_RATE, so remember to shift. */ +#define RTSCTS_SH_RTS_RATE 0 +#define RTSCTS_SH_EXP_CTS_RATE 4 +#define RTSCTS_SH_RTS_MOD_TYPE 8 +#define RTSCTS_SH_RTS_PMB_TYPE 9 +#define RTSCTS_SH_CTS_RATE 16 +#define RTSCTS_SH_CTS_MOD_TYPE 24 +#define RTSCTS_SH_CTS_PMB_TYPE 25 + #define CR_WEP_PROTECT CTL_REG(0x063C) #define CR_RX_THRESHOLD CTL_REG(0x0640) /* register for controlling the LEDS */ #define CR_LED CTL_REG(0x0644) /* masks for controlling LEDs */ -#define LED1 0x0100 -#define LED2 0x0200 +#define LED1 (1 << 8) +#define LED2 (1 << 9) +#define LED_SW (1 << 10) /* Seems to indicate that the configuration is over. */ @@ -454,18 +473,18 @@ * registers, so one could argue it is a LOCK bit. But calling it * LOCK_PHY_REGS makes it confusing. */ -#define UNLOCK_PHY_REGS 0x0080 +#define UNLOCK_PHY_REGS (1 << 7) #define CR_DEVICE_STATE CTL_REG(0x0684) #define CR_UNDERRUN_CNT CTL_REG(0x0688) #define CR_RX_FILTER CTL_REG(0x068c) -#define RX_FILTER_ASSOC_RESPONSE 0x0002 -#define RX_FILTER_REASSOC_RESPONSE 0x0008 -#define RX_FILTER_PROBE_RESPONSE 0x0020 -#define RX_FILTER_BEACON 0x0100 -#define RX_FILTER_DISASSOC 0x0400 -#define RX_FILTER_AUTH 0x0800 +#define RX_FILTER_ASSOC_RESPONSE (1 << 1) +#define RX_FILTER_REASSOC_RESPONSE (1 << 3) +#define RX_FILTER_PROBE_RESPONSE (1 << 5) +#define RX_FILTER_BEACON (1 << 8) +#define RX_FILTER_DISASSOC (1 << 10) +#define RX_FILTER_AUTH (1 << 11) #define AP_RX_FILTER 0x0400feff #define STA_RX_FILTER 0x0000ffff @@ -629,6 +648,10 @@ #define FW_SOFT_RESET FW_REG(4) #define FW_FLASH_CHK FW_REG(5) +#define FW_LINK_OFF 0x0 +#define FW_LINK_TX 0x1 +/* 0x2 - link led on? */ + enum { CR_BASE_OFFSET = 0x9000, FW_START_OFFSET = 0xee00, @@ -663,8 +686,11 @@ struct zd_chip { u8 pwr_int_values[E2P_CHANNEL_COUNT]; /* SetPointOFDM in the vendor driver */ u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT]; - u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1, - new_phy_layout:1, is_zd1211b:1; + u16 link_led; + unsigned int pa_type:4, + patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1, + new_phy_layout:1, + is_zd1211b:1, supports_tx_led:1; }; static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb) @@ -786,6 +812,9 @@ void zd_chip_disable_rx(struct zd_chip *chip); int zd_chip_enable_hwint(struct zd_chip *chip); int zd_chip_disable_hwint(struct zd_chip *chip); +int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, + u8 rts_rate, int preamble); + static inline int zd_get_encryption_type(struct zd_chip *chip, u32 *type) { return zd_ioread32(chip, CR_ENCRYPTION_TYPE, type); @@ -801,7 +830,17 @@ static inline int zd_chip_get_basic_rates(struct zd_chip *chip, u16 *cr_rates) return zd_ioread16(chip, CR_BASIC_RATE_TBL, cr_rates); } -int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates); +int zd_chip_set_basic_rates_locked(struct zd_chip *chip, u16 cr_rates); + +static inline int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates) +{ + int r; + + mutex_lock(&chip->mutex); + r = zd_chip_set_basic_rates_locked(chip, cr_rates); + mutex_unlock(&chip->mutex); + return r; +} static inline int zd_chip_set_rx_filter(struct zd_chip *chip, u32 filter) { @@ -812,15 +851,12 @@ int zd_chip_lock_phy_regs(struct zd_chip *chip); int zd_chip_unlock_phy_regs(struct zd_chip *chip); enum led_status { - LED_OFF = 0, - LED_ON = 1, - LED_FLIP = 2, - LED_STATUS = 3, + LED_OFF = 0, + LED_SCANNING = 1, + LED_ASSOCIATED = 2, }; -int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status); -int zd_chip_led_flip(struct zd_chip *chip, int led, - const unsigned int *phases_msecs, unsigned int count); +int zd_chip_control_leds(struct zd_chip *chip, enum led_status status); int zd_set_beacon_interval(struct zd_chip *chip, u32 interval); @@ -837,4 +873,36 @@ u8 zd_rx_strength_percent(u8 rssi); u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status); +struct zd_mc_hash { + u32 low; + u32 high; +}; + +static inline void zd_mc_clear(struct zd_mc_hash *hash) +{ + hash->low = 0; + /* The interfaces must always received broadcasts. + * The hash of the broadcast address ff:ff:ff:ff:ff:ff is 63. + */ + hash->high = 0x80000000; +} + +static inline void zd_mc_add_all(struct zd_mc_hash *hash) +{ + hash->low = hash->high = 0xffffffff; +} + +static inline void zd_mc_add_addr(struct zd_mc_hash *hash, u8 *addr) +{ + unsigned int i = addr[5] >> 2; + if (i < 32) { + hash->low |= 1 << i; + } else { + hash->high |= 1 << (i-32); + } +} + +int zd_chip_set_multicast_hash(struct zd_chip *chip, + struct zd_mc_hash *hash); + #endif /* _ZD_CHIP_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h index a13ec72eb30..fb22f62cf1f 100644 --- a/drivers/net/wireless/zd1211rw/zd_def.h +++ b/drivers/net/wireless/zd1211rw/zd_def.h @@ -39,6 +39,7 @@ do { \ if (!(x)) { \ pr_debug("%s:%d ASSERT %s VIOLATED!\n", \ __FILE__, __LINE__, __stringify(x)); \ + dump_stack(); \ } \ } while (0) #else diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c index 66905f7b61f..189160efd2a 100644 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.c +++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.c @@ -37,7 +37,12 @@ static const struct channel_range channel_ranges[] = { [ZD_REGDOMAIN_JAPAN] = { 1, 14}, [ZD_REGDOMAIN_SPAIN] = { 1, 14}, [ZD_REGDOMAIN_FRANCE] = { 1, 14}, - [ZD_REGDOMAIN_JAPAN_ADD] = {14, 15}, + + /* Japan originally only had channel 14 available (see CHNL_ID 0x40 in + * 802.11). However, in 2001 the range was extended to include channels + * 1-13. The ZyDAS devices still use the old region code but are + * designed to allow the extra channel access in Japan. */ + [ZD_REGDOMAIN_JAPAN_ADD] = { 1, 15}, }; const struct channel_range *zd_channel_range(u8 regdomain) @@ -133,9 +138,6 @@ int zd_find_channel(u8 *channel, const struct iw_freq *freq) int i, r; u32 mhz; - if (!(freq->flags & IW_FREQ_FIXED)) - return 0; - if (freq->m < 1000) { if (freq->m > NUM_CHANNELS || freq->m == 0) return -EINVAL; diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h index f63245b0d96..26b8298dff8 100644 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h +++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h @@ -50,6 +50,7 @@ static inline u8 zd_ofdm_plcp_header_rate( return header->prefix[0] & 0xf; } +/* These are referred to as zd_rates */ #define ZD_OFDM_RATE_6M 0xb #define ZD_OFDM_RATE_9M 0xf #define ZD_OFDM_RATE_12M 0xa @@ -64,7 +65,7 @@ struct cck_plcp_header { u8 service; __le16 length; __le16 crc16; -}; +} __attribute__((packed)); static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header) { diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 1989f1c05fb..00ca704ece3 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -32,6 +32,14 @@ static void ieee_init(struct ieee80211_device *ieee); static void softmac_init(struct ieee80211softmac_device *sm); +static void set_rts_cts_work(struct work_struct *work); +static void set_basic_rates_work(struct work_struct *work); + +static void housekeeping_init(struct zd_mac *mac); +static void housekeeping_enable(struct zd_mac *mac); +static void housekeeping_disable(struct zd_mac *mac); + +static void set_multicast_hash_handler(struct work_struct *work); int zd_mac_init(struct zd_mac *mac, struct net_device *netdev, @@ -42,10 +50,14 @@ int zd_mac_init(struct zd_mac *mac, memset(mac, 0, sizeof(*mac)); spin_lock_init(&mac->lock); mac->netdev = netdev; + INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work); + INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work); ieee_init(ieee); softmac_init(ieee80211_priv(netdev)); zd_chip_init(&mac->chip, netdev, intf); + housekeeping_init(mac); + INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler); return 0; } @@ -127,6 +139,7 @@ out: void zd_mac_clear(struct zd_mac *mac) { + flush_workqueue(zd_workqueue); zd_chip_clear(&mac->chip); ZD_ASSERT(!spin_is_locked(&mac->lock)); ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); @@ -178,6 +191,7 @@ int zd_mac_open(struct net_device *netdev) if (r < 0) goto disable_rx; + housekeeping_enable(mac); ieee80211softmac_start(netdev); return 0; disable_rx: @@ -204,8 +218,16 @@ int zd_mac_stop(struct net_device *netdev) */ zd_chip_disable_rx(chip); + housekeeping_disable(mac); ieee80211softmac_stop(netdev); + /* Ensure no work items are running or queued from this point */ + cancel_delayed_work(&mac->set_rts_cts_work); + cancel_delayed_work(&mac->set_basic_rates_work); + flush_workqueue(zd_workqueue); + mac->updating_rts_rate = 0; + mac->updating_basic_rates = 0; + zd_chip_disable_hwint(chip); zd_chip_switch_radio_off(chip); zd_chip_disable_int(chip); @@ -238,6 +260,43 @@ int zd_mac_set_mac_address(struct net_device *netdev, void *p) return 0; } +static void set_multicast_hash_handler(struct work_struct *work) +{ + struct zd_mac *mac = container_of(work, struct zd_mac, + set_multicast_hash_work); + struct zd_mc_hash hash; + + spin_lock_irq(&mac->lock); + hash = mac->multicast_hash; + spin_unlock_irq(&mac->lock); + + zd_chip_set_multicast_hash(&mac->chip, &hash); +} + +void zd_mac_set_multicast_list(struct net_device *dev) +{ + struct zd_mc_hash hash; + struct zd_mac *mac = zd_netdev_mac(dev); + struct dev_mc_list *mc; + unsigned long flags; + + if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) { + zd_mc_add_all(&hash); + } else { + zd_mc_clear(&hash); + for (mc = dev->mc_list; mc; mc = mc->next) { + dev_dbg_f(zd_mac_dev(mac), "mc addr " MAC_FMT "\n", + MAC_ARG(mc->dmi_addr)); + zd_mc_add_addr(&hash, mc->dmi_addr); + } + } + + spin_lock_irqsave(&mac->lock, flags); + mac->multicast_hash = hash; + spin_unlock_irqrestore(&mac->lock, flags); + queue_work(zd_workqueue, &mac->set_multicast_hash_work); +} + int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain) { int r; @@ -279,6 +338,189 @@ u8 zd_mac_get_regdomain(struct zd_mac *mac) return regdomain; } +/* Fallback to lowest rate, if rate is unknown. */ +static u8 rate_to_zd_rate(u8 rate) +{ + switch (rate) { + case IEEE80211_CCK_RATE_2MB: + return ZD_CCK_RATE_2M; + case IEEE80211_CCK_RATE_5MB: + return ZD_CCK_RATE_5_5M; + case IEEE80211_CCK_RATE_11MB: + return ZD_CCK_RATE_11M; + case IEEE80211_OFDM_RATE_6MB: + return ZD_OFDM_RATE_6M; + case IEEE80211_OFDM_RATE_9MB: + return ZD_OFDM_RATE_9M; + case IEEE80211_OFDM_RATE_12MB: + return ZD_OFDM_RATE_12M; + case IEEE80211_OFDM_RATE_18MB: + return ZD_OFDM_RATE_18M; + case IEEE80211_OFDM_RATE_24MB: + return ZD_OFDM_RATE_24M; + case IEEE80211_OFDM_RATE_36MB: + return ZD_OFDM_RATE_36M; + case IEEE80211_OFDM_RATE_48MB: + return ZD_OFDM_RATE_48M; + case IEEE80211_OFDM_RATE_54MB: + return ZD_OFDM_RATE_54M; + } + return ZD_CCK_RATE_1M; +} + +static u16 rate_to_cr_rate(u8 rate) +{ + switch (rate) { + case IEEE80211_CCK_RATE_2MB: + return CR_RATE_1M; + case IEEE80211_CCK_RATE_5MB: + return CR_RATE_5_5M; + case IEEE80211_CCK_RATE_11MB: + return CR_RATE_11M; + case IEEE80211_OFDM_RATE_6MB: + return CR_RATE_6M; + case IEEE80211_OFDM_RATE_9MB: + return CR_RATE_9M; + case IEEE80211_OFDM_RATE_12MB: + return CR_RATE_12M; + case IEEE80211_OFDM_RATE_18MB: + return CR_RATE_18M; + case IEEE80211_OFDM_RATE_24MB: + return CR_RATE_24M; + case IEEE80211_OFDM_RATE_36MB: + return CR_RATE_36M; + case IEEE80211_OFDM_RATE_48MB: + return CR_RATE_48M; + case IEEE80211_OFDM_RATE_54MB: + return CR_RATE_54M; + } + return CR_RATE_1M; +} + +static void try_enable_tx(struct zd_mac *mac) +{ + unsigned long flags; + + spin_lock_irqsave(&mac->lock, flags); + if (mac->updating_rts_rate == 0 && mac->updating_basic_rates == 0) + netif_wake_queue(mac->netdev); + spin_unlock_irqrestore(&mac->lock, flags); +} + +static void set_rts_cts_work(struct work_struct *work) +{ + struct zd_mac *mac = + container_of(work, struct zd_mac, set_rts_cts_work.work); + unsigned long flags; + u8 rts_rate; + unsigned int short_preamble; + + mutex_lock(&mac->chip.mutex); + + spin_lock_irqsave(&mac->lock, flags); + mac->updating_rts_rate = 0; + rts_rate = mac->rts_rate; + short_preamble = mac->short_preamble; + spin_unlock_irqrestore(&mac->lock, flags); + + zd_chip_set_rts_cts_rate_locked(&mac->chip, rts_rate, short_preamble); + mutex_unlock(&mac->chip.mutex); + + try_enable_tx(mac); +} + +static void set_basic_rates_work(struct work_struct *work) +{ + struct zd_mac *mac = + container_of(work, struct zd_mac, set_basic_rates_work.work); + unsigned long flags; + u16 basic_rates; + + mutex_lock(&mac->chip.mutex); + + spin_lock_irqsave(&mac->lock, flags); + mac->updating_basic_rates = 0; + basic_rates = mac->basic_rates; + spin_unlock_irqrestore(&mac->lock, flags); + + zd_chip_set_basic_rates_locked(&mac->chip, basic_rates); + mutex_unlock(&mac->chip.mutex); + + try_enable_tx(mac); +} + +static void bssinfo_change(struct net_device *netdev, u32 changes) +{ + struct zd_mac *mac = zd_netdev_mac(netdev); + struct ieee80211softmac_device *softmac = ieee80211_priv(netdev); + struct ieee80211softmac_bss_info *bssinfo = &softmac->bssinfo; + int need_set_rts_cts = 0; + int need_set_rates = 0; + u16 basic_rates; + unsigned long flags; + + dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes); + + if (changes & IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE) { + spin_lock_irqsave(&mac->lock, flags); + mac->short_preamble = bssinfo->short_preamble; + spin_unlock_irqrestore(&mac->lock, flags); + need_set_rts_cts = 1; + } + + if (changes & IEEE80211SOFTMAC_BSSINFOCHG_RATES) { + /* Set RTS rate to highest available basic rate */ + u8 rate = ieee80211softmac_highest_supported_rate(softmac, + &bssinfo->supported_rates, 1); + rate = rate_to_zd_rate(rate); + + spin_lock_irqsave(&mac->lock, flags); + if (rate != mac->rts_rate) { + mac->rts_rate = rate; + need_set_rts_cts = 1; + } + spin_unlock_irqrestore(&mac->lock, flags); + + /* Set basic rates */ + need_set_rates = 1; + if (bssinfo->supported_rates.count == 0) { + /* Allow the device to be flexible */ + basic_rates = CR_RATES_80211B | CR_RATES_80211G; + } else { + int i = 0; + basic_rates = 0; + + for (i = 0; i < bssinfo->supported_rates.count; i++) { + u16 rate = bssinfo->supported_rates.rates[i]; + if ((rate & IEEE80211_BASIC_RATE_MASK) == 0) + continue; + + rate &= ~IEEE80211_BASIC_RATE_MASK; + basic_rates |= rate_to_cr_rate(rate); + } + } + spin_lock_irqsave(&mac->lock, flags); + mac->basic_rates = basic_rates; + spin_unlock_irqrestore(&mac->lock, flags); + } + + /* Schedule any changes we made above */ + + spin_lock_irqsave(&mac->lock, flags); + if (need_set_rts_cts && !mac->updating_rts_rate) { + mac->updating_rts_rate = 1; + netif_stop_queue(mac->netdev); + queue_delayed_work(zd_workqueue, &mac->set_rts_cts_work, 0); + } + if (need_set_rates && !mac->updating_basic_rates) { + mac->updating_basic_rates = 1; + netif_stop_queue(mac->netdev); + queue_delayed_work(zd_workqueue, &mac->set_basic_rates_work, + 0); + } + spin_unlock_irqrestore(&mac->lock, flags); +} + static void set_channel(struct net_device *netdev, u8 channel) { struct zd_mac *mac = zd_netdev_mac(netdev); @@ -288,7 +530,6 @@ static void set_channel(struct net_device *netdev, u8 channel) zd_chip_set_channel(&mac->chip, channel); } -/* TODO: Should not work in Managed mode. */ int zd_mac_request_channel(struct zd_mac *mac, u8 channel) { unsigned long lock_flags; @@ -310,31 +551,22 @@ int zd_mac_request_channel(struct zd_mac *mac, u8 channel) return 0; } -int zd_mac_get_channel(struct zd_mac *mac, u8 *channel, u8 *flags) +u8 zd_mac_get_channel(struct zd_mac *mac) { - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + u8 channel = zd_chip_get_channel(&mac->chip); - *channel = zd_chip_get_channel(&mac->chip); - if (ieee->iw_mode != IW_MODE_INFRA) { - spin_lock_irq(&mac->lock); - *flags = *channel == mac->requested_channel ? - MAC_FIXED_CHANNEL : 0; - spin_unlock(&mac->lock); - } else { - *flags = 0; - } - dev_dbg_f(zd_mac_dev(mac), "channel %u flags %u\n", *channel, *flags); - return 0; + dev_dbg_f(zd_mac_dev(mac), "channel %u\n", channel); + return channel; } /* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */ -static u8 cs_typed_rate(u8 cs_rate) +static u8 zd_rate_typed(u8 zd_rate) { static const u8 typed_rates[16] = { - [ZD_CS_CCK_RATE_1M] = ZD_CS_CCK|ZD_CS_CCK_RATE_1M, - [ZD_CS_CCK_RATE_2M] = ZD_CS_CCK|ZD_CS_CCK_RATE_2M, - [ZD_CS_CCK_RATE_5_5M] = ZD_CS_CCK|ZD_CS_CCK_RATE_5_5M, - [ZD_CS_CCK_RATE_11M] = ZD_CS_CCK|ZD_CS_CCK_RATE_11M, + [ZD_CCK_RATE_1M] = ZD_CS_CCK|ZD_CCK_RATE_1M, + [ZD_CCK_RATE_2M] = ZD_CS_CCK|ZD_CCK_RATE_2M, + [ZD_CCK_RATE_5_5M] = ZD_CS_CCK|ZD_CCK_RATE_5_5M, + [ZD_CCK_RATE_11M] = ZD_CS_CCK|ZD_CCK_RATE_11M, [ZD_OFDM_RATE_6M] = ZD_CS_OFDM|ZD_OFDM_RATE_6M, [ZD_OFDM_RATE_9M] = ZD_CS_OFDM|ZD_OFDM_RATE_9M, [ZD_OFDM_RATE_12M] = ZD_CS_OFDM|ZD_OFDM_RATE_12M, @@ -346,37 +578,7 @@ static u8 cs_typed_rate(u8 cs_rate) }; ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f); - return typed_rates[cs_rate & ZD_CS_RATE_MASK]; -} - -/* Fallback to lowest rate, if rate is unknown. */ -static u8 rate_to_cs_rate(u8 rate) -{ - switch (rate) { - case IEEE80211_CCK_RATE_2MB: - return ZD_CS_CCK_RATE_2M; - case IEEE80211_CCK_RATE_5MB: - return ZD_CS_CCK_RATE_5_5M; - case IEEE80211_CCK_RATE_11MB: - return ZD_CS_CCK_RATE_11M; - case IEEE80211_OFDM_RATE_6MB: - return ZD_OFDM_RATE_6M; - case IEEE80211_OFDM_RATE_9MB: - return ZD_OFDM_RATE_9M; - case IEEE80211_OFDM_RATE_12MB: - return ZD_OFDM_RATE_12M; - case IEEE80211_OFDM_RATE_18MB: - return ZD_OFDM_RATE_18M; - case IEEE80211_OFDM_RATE_24MB: - return ZD_OFDM_RATE_24M; - case IEEE80211_OFDM_RATE_36MB: - return ZD_OFDM_RATE_36M; - case IEEE80211_OFDM_RATE_48MB: - return ZD_OFDM_RATE_48M; - case IEEE80211_OFDM_RATE_54MB: - return ZD_OFDM_RATE_54M; - } - return ZD_CS_CCK_RATE_1M; + return typed_rates[zd_rate & ZD_CS_RATE_MASK]; } int zd_mac_set_mode(struct zd_mac *mac, u32 mode) @@ -457,6 +659,9 @@ int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range) range->we_version_compiled = WIRELESS_EXT; range->we_version_source = 20; + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + ZD_ASSERT(!irqs_disabled()); spin_lock_irq(&mac->lock); regdomain = mac->regdomain; @@ -477,13 +682,13 @@ int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range) return 0; } -static int zd_calc_tx_length_us(u8 *service, u8 cs_rate, u16 tx_length) +static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length) { static const u8 rate_divisor[] = { - [ZD_CS_CCK_RATE_1M] = 1, - [ZD_CS_CCK_RATE_2M] = 2, - [ZD_CS_CCK_RATE_5_5M] = 11, /* bits must be doubled */ - [ZD_CS_CCK_RATE_11M] = 11, + [ZD_CCK_RATE_1M] = 1, + [ZD_CCK_RATE_2M] = 2, + [ZD_CCK_RATE_5_5M] = 11, /* bits must be doubled */ + [ZD_CCK_RATE_11M] = 11, [ZD_OFDM_RATE_6M] = 6, [ZD_OFDM_RATE_9M] = 9, [ZD_OFDM_RATE_12M] = 12, @@ -497,15 +702,15 @@ static int zd_calc_tx_length_us(u8 *service, u8 cs_rate, u16 tx_length) u32 bits = (u32)tx_length * 8; u32 divisor; - divisor = rate_divisor[cs_rate]; + divisor = rate_divisor[zd_rate]; if (divisor == 0) return -EINVAL; - switch (cs_rate) { - case ZD_CS_CCK_RATE_5_5M: + switch (zd_rate) { + case ZD_CCK_RATE_5_5M: bits = (2*bits) + 10; /* round up to the next integer */ break; - case ZD_CS_CCK_RATE_11M: + case ZD_CCK_RATE_11M: if (service) { u32 t = bits % 11; *service &= ~ZD_PLCP_SERVICE_LENGTH_EXTENSION; @@ -525,16 +730,16 @@ enum { R2M_11A = 0x02, }; -static u8 cs_rate_to_modulation(u8 cs_rate, int flags) +static u8 zd_rate_to_modulation(u8 zd_rate, int flags) { u8 modulation; - modulation = cs_typed_rate(cs_rate); + modulation = zd_rate_typed(zd_rate); if (flags & R2M_SHORT_PREAMBLE) { switch (ZD_CS_RATE(modulation)) { - case ZD_CS_CCK_RATE_2M: - case ZD_CS_CCK_RATE_5_5M: - case ZD_CS_CCK_RATE_11M: + case ZD_CCK_RATE_2M: + case ZD_CCK_RATE_5_5M: + case ZD_CCK_RATE_11M: modulation |= ZD_CS_CCK_PREA_SHORT; return modulation; } @@ -551,39 +756,36 @@ static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs, { struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev); u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl)); - u8 rate, cs_rate; + u8 rate, zd_rate; int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0; + int is_multicast = is_multicast_ether_addr(hdr->addr1); + int short_preamble = ieee80211softmac_short_preamble_ok(softmac, + is_multicast, is_mgt); + int flags = 0; + + /* FIXME: 802.11a? */ + rate = ieee80211softmac_suggest_txrate(softmac, is_multicast, is_mgt); - /* FIXME: 802.11a? short preamble? */ - rate = ieee80211softmac_suggest_txrate(softmac, - is_multicast_ether_addr(hdr->addr1), is_mgt); + if (short_preamble) + flags |= R2M_SHORT_PREAMBLE; - cs_rate = rate_to_cs_rate(rate); - cs->modulation = cs_rate_to_modulation(cs_rate, 0); + zd_rate = rate_to_zd_rate(rate); + cs->modulation = zd_rate_to_modulation(zd_rate, flags); } static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, struct ieee80211_hdr_4addr *header) { + struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev); unsigned int tx_length = le16_to_cpu(cs->tx_length); u16 fctl = le16_to_cpu(header->frame_ctl); u16 ftype = WLAN_FC_GET_TYPE(fctl); u16 stype = WLAN_FC_GET_STYPE(fctl); /* - * CONTROL: - * - start at 0x00 - * - if fragment 0, enable bit 0 + * CONTROL TODO: * - if backoff needed, enable bit 0 * - if burst (backoff not needed) disable bit 0 - * - if multicast, enable bit 1 - * - if PS-POLL frame, enable bit 2 - * - if in INDEPENDENT_BSS mode and zd1205_DestPowerSave, then enable - * bit 4 (FIXME: wtf) - * - if frag_len > RTS threshold, set bit 5 as long if it isnt - * multicast or mgt - * - if bit 5 is set, and we are in OFDM mode, unset bit 5 and set bit - * 7 */ cs->control = 0; @@ -600,17 +802,18 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, if (stype == IEEE80211_STYPE_PSPOLL) cs->control |= ZD_CS_PS_POLL_FRAME; + /* Unicast data frames over the threshold should have RTS */ if (!is_multicast_ether_addr(header->addr1) && - ftype != IEEE80211_FTYPE_MGMT && - tx_length > zd_netdev_ieee80211(mac->netdev)->rts) - { - /* FIXME: check the logic */ - if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM) { - /* 802.11g */ - cs->control |= ZD_CS_SELF_CTS; - } else { /* 802.11b */ - cs->control |= ZD_CS_RTS; - } + ftype != IEEE80211_FTYPE_MGMT && + tx_length > zd_netdev_ieee80211(mac->netdev)->rts) + cs->control |= ZD_CS_RTS; + + /* Use CTS-to-self protection if required */ + if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM && + ieee80211softmac_protection_needed(softmac)) { + /* FIXME: avoid sending RTS *and* self-CTS, is that correct? */ + cs->control &= ~ZD_CS_RTS; + cs->control |= ZD_CS_SELF_CTS; } /* FIXME: Management frame? */ @@ -714,7 +917,7 @@ struct zd_rt_hdr { u8 rt_rate; u16 rt_channel; u16 rt_chbitmask; -}; +} __attribute__((packed)); static void fill_rt_header(void *buffer, struct zd_mac *mac, const struct ieee80211_rx_stats *stats, @@ -771,13 +974,16 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee, } return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 || - is_multicast_ether_addr(hdr->addr1) || + (is_multicast_ether_addr(hdr->addr1) && + memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) || (netdev->flags & IFF_PROMISC); } -/* Filters receiving packets. If it returns 1 send it to ieee80211_rx, if 0 - * return. If an error is detected -EINVAL is returned. ieee80211_rx_mgt() is - * called here. +/* Filters received packets. The function returns 1 if the packet should be + * forwarded to ieee80211_rx(). If the packet should be ignored the function + * returns 0. If an invalid packet is found the function returns -EINVAL. + * + * The function calls ieee80211_rx_mgt() directly. * * It has been based on ieee80211_rx_any. */ @@ -803,9 +1009,9 @@ static int filter_rx(struct ieee80211_device *ieee, ieee80211_rx_mgt(ieee, hdr, stats); return 0; case IEEE80211_FTYPE_CTL: - /* Ignore invalid short buffers */ return 0; case IEEE80211_FTYPE_DATA: + /* Ignore invalid short buffers */ if (length < sizeof(struct ieee80211_hdr_3addr)) return -EINVAL; return is_data_packet_for_us(ieee, hdr); @@ -901,10 +1107,8 @@ int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length) memcpy(skb_put(skb, length), buffer, length); r = ieee80211_rx(ieee, skb, &stats); - if (!r) { - ZD_ASSERT(in_irq()); - dev_kfree_skb_irq(skb); - } + if (!r) + dev_kfree_skb_any(skb); return 0; } @@ -986,6 +1190,7 @@ static void ieee_init(struct ieee80211_device *ieee) static void softmac_init(struct ieee80211softmac_device *sm) { sm->set_channel = set_channel; + sm->bssinfo_change = bssinfo_change; } struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev) @@ -1021,62 +1226,46 @@ struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev) return iw_stats; } -#ifdef DEBUG -static const char* decryption_types[] = { - [ZD_RX_NO_WEP] = "none", - [ZD_RX_WEP64] = "WEP64", - [ZD_RX_TKIP] = "TKIP", - [ZD_RX_AES] = "AES", - [ZD_RX_WEP128] = "WEP128", - [ZD_RX_WEP256] = "WEP256", -}; +#define LINK_LED_WORK_DELAY HZ -static const char *decryption_type_string(u8 type) +static void link_led_handler(struct work_struct *work) { - const char *s; + struct zd_mac *mac = + container_of(work, struct zd_mac, housekeeping.link_led_work.work); + struct zd_chip *chip = &mac->chip; + struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev); + int is_associated; + int r; - if (type < ARRAY_SIZE(decryption_types)) { - s = decryption_types[type]; - } else { - s = NULL; - } - return s ? s : "unknown"; + spin_lock_irq(&mac->lock); + is_associated = sm->associnfo.associated != 0; + spin_unlock_irq(&mac->lock); + + r = zd_chip_control_leds(chip, + is_associated ? LED_ASSOCIATED : LED_SCANNING); + if (r) + dev_err(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); + + queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work, + LINK_LED_WORK_DELAY); } -static int is_ofdm(u8 frame_status) +static void housekeeping_init(struct zd_mac *mac) { - return (frame_status & ZD_RX_OFDM); + INIT_DELAYED_WORK(&mac->housekeeping.link_led_work, link_led_handler); } -void zd_dump_rx_status(const struct rx_status *status) +static void housekeeping_enable(struct zd_mac *mac) { - const char* modulation; - u8 quality; + dev_dbg_f(zd_mac_dev(mac), "\n"); + queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work, + 0); +} - if (is_ofdm(status->frame_status)) { - modulation = "ofdm"; - quality = status->signal_quality_ofdm; - } else { - modulation = "cck"; - quality = status->signal_quality_cck; - } - pr_debug("rx status %s strength %#04x qual %#04x decryption %s\n", - modulation, status->signal_strength, quality, - decryption_type_string(status->decryption_type)); - if (status->frame_status & ZD_RX_ERROR) { - pr_debug("rx error %s%s%s%s%s%s\n", - (status->frame_status & ZD_RX_TIMEOUT_ERROR) ? - "timeout " : "", - (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR) ? - "fifo " : "", - (status->frame_status & ZD_RX_DECRYPTION_ERROR) ? - "decryption " : "", - (status->frame_status & ZD_RX_CRC32_ERROR) ? - "crc32 " : "", - (status->frame_status & ZD_RX_NO_ADDR1_MATCH_ERROR) ? - "addr1 " : "", - (status->frame_status & ZD_RX_CRC16_ERROR) ? - "crc16" : ""); - } +static void housekeeping_disable(struct zd_mac *mac) +{ + dev_dbg_f(zd_mac_dev(mac), "\n"); + cancel_rearming_delayed_workqueue(zd_workqueue, + &mac->housekeeping.link_led_work); + zd_chip_control_leds(&mac->chip, LED_OFF); } -#endif /* DEBUG */ diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 29b51fd7d4e..f0cf05dc7d3 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -20,6 +20,7 @@ #include <linux/wireless.h> #include <linux/kernel.h> +#include <linux/workqueue.h> #include <net/ieee80211.h> #include <net/ieee80211softmac.h> @@ -48,10 +49,11 @@ struct zd_ctrlset { #define ZD_CS_CCK 0x00 #define ZD_CS_OFDM 0x10 -#define ZD_CS_CCK_RATE_1M 0x00 -#define ZD_CS_CCK_RATE_2M 0x01 -#define ZD_CS_CCK_RATE_5_5M 0x02 -#define ZD_CS_CCK_RATE_11M 0x03 +/* These are referred to as zd_rates */ +#define ZD_CCK_RATE_1M 0x00 +#define ZD_CCK_RATE_2M 0x01 +#define ZD_CCK_RATE_5_5M 0x02 +#define ZD_CCK_RATE_11M 0x03 /* The rates for OFDM are encoded as in the PLCP header. Use ZD_OFDM_RATE_*. */ @@ -82,7 +84,7 @@ struct zd_ctrlset { struct rx_length_info { __le16 length[3]; __le16 tag; -}; +} __attribute__((packed)); #define RX_LENGTH_INFO_TAG 0x697e @@ -93,7 +95,7 @@ struct rx_status { u8 signal_quality_ofdm; u8 decryption_type; u8 frame_status; -}; +} __attribute__((packed)); /* rx_status field decryption_type */ #define ZD_RX_NO_WEP 0 @@ -116,8 +118,8 @@ struct rx_status { #define ZD_RX_CRC16_ERROR 0x40 #define ZD_RX_ERROR 0x80 -enum mac_flags { - MAC_FIXED_CHANNEL = 0x01, +struct housekeeping { + struct delayed_work link_led_work; }; #define ZD_MAC_STATS_BUFFER_SIZE 16 @@ -126,14 +128,35 @@ struct zd_mac { struct zd_chip chip; spinlock_t lock; struct net_device *netdev; + /* Unlocked reading possible */ struct iw_statistics iw_stats; + + struct housekeeping housekeeping; + struct work_struct set_multicast_hash_work; + struct zd_mc_hash multicast_hash; + struct delayed_work set_rts_cts_work; + struct delayed_work set_basic_rates_work; + unsigned int stats_count; u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE]; u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE]; u8 regdomain; u8 default_regdomain; u8 requested_channel; + + /* A bitpattern of cr_rates */ + u16 basic_rates; + + /* A zd_rate */ + u8 rts_rate; + + /* Short preamble (used for RTS/CTS) */ + unsigned int short_preamble:1; + + /* flags to indicate update in progress */ + unsigned int updating_rts_rate:1; + unsigned int updating_basic_rates:1; }; static inline struct ieee80211_device *zd_mac_to_ieee80211(struct zd_mac *mac) @@ -168,6 +191,7 @@ int zd_mac_init_hw(struct zd_mac *mac, u8 device_type); int zd_mac_open(struct net_device *netdev); int zd_mac_stop(struct net_device *netdev); int zd_mac_set_mac_address(struct net_device *dev, void *p); +void zd_mac_set_multicast_list(struct net_device *netdev); int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length); @@ -175,7 +199,7 @@ int zd_mac_set_regdomain(struct zd_mac *zd_mac, u8 regdomain); u8 zd_mac_get_regdomain(struct zd_mac *zd_mac); int zd_mac_request_channel(struct zd_mac *mac, u8 channel); -int zd_mac_get_channel(struct zd_mac *mac, u8 *channel, u8 *flags); +u8 zd_mac_get_channel(struct zd_mac *mac); int zd_mac_set_mode(struct zd_mac *mac, u32 mode); int zd_mac_get_mode(struct zd_mac *mac, u32 *mode); diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c index 440ef24b5fd..8bda48de31e 100644 --- a/drivers/net/wireless/zd1211rw/zd_netdev.c +++ b/drivers/net/wireless/zd1211rw/zd_netdev.c @@ -82,7 +82,7 @@ static int iw_get_nick(struct net_device *netdev, union iwreq_data *req, char *extra) { strcpy(extra, "zd1211"); - req->data.length = strlen(extra) + 1; + req->data.length = strlen(extra); req->data.flags = 1; return 0; } @@ -107,21 +107,10 @@ static int iw_get_freq(struct net_device *netdev, struct iw_request_info *info, union iwreq_data *req, char *extra) { - int r; struct zd_mac *mac = zd_netdev_mac(netdev); struct iw_freq *freq = &req->freq; - u8 channel; - u8 flags; - - r = zd_mac_get_channel(mac, &channel, &flags); - if (r) - return r; - freq->flags = (flags & MAC_FIXED_CHANNEL) ? - IW_FREQ_FIXED : IW_FREQ_AUTO; - dev_dbg_f(zd_mac_dev(mac), "channel %s\n", - (flags & MAC_FIXED_CHANNEL) ? "fixed" : "auto"); - return zd_channel_to_freq(freq, channel); + return zd_channel_to_freq(freq, zd_mac_get_channel(mac)); } static int iw_set_mode(struct net_device *netdev, @@ -253,7 +242,7 @@ struct net_device *zd_netdev_alloc(struct usb_interface *intf) netdev->open = zd_mac_open; netdev->stop = zd_mac_stop; /* netdev->get_stats = */ - /* netdev->set_multicast_list = */ + netdev->set_multicast_list = zd_mac_set_multicast_list; netdev->set_mac_address = zd_mac_set_mac_address; netdev->wireless_handlers = &iw_handler_def; /* netdev->ethtool_ops = */ diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 31027e52b04..aa782e88754 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -24,6 +24,7 @@ #include <linux/errno.h> #include <linux/skbuff.h> #include <linux/usb.h> +#include <linux/workqueue.h> #include <net/ieee80211.h> #include "zd_def.h" @@ -46,11 +47,17 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 }, /* ZD1211B */ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, {} @@ -365,15 +372,6 @@ error: return r; } -static void disable_read_regs_int(struct zd_usb *usb) -{ - struct zd_usb_interrupt *intr = &usb->intr; - - spin_lock(&intr->lock); - intr->read_regs_enabled = 0; - spin_unlock(&intr->lock); -} - #define urb_dev(urb) (&(urb)->dev->dev) static inline void handle_regs_int(struct urb *urb) @@ -407,7 +405,7 @@ static inline void handle_retry_failed_int(struct urb *urb) } -static void int_urb_complete(struct urb *urb, struct pt_regs *pt_regs) +static void int_urb_complete(struct urb *urb) { int r; struct usb_int_header *hdr; @@ -595,6 +593,8 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, unsigned int l, k, n; for (i = 0, l = 0;; i++) { k = le16_to_cpu(get_unaligned(&length_info->length[i])); + if (k == 0) + return; n = l+k; if (n > length) return; @@ -608,7 +608,7 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, } } -static void rx_urb_complete(struct urb *urb, struct pt_regs *pt_regs) +static void rx_urb_complete(struct urb *urb) { struct zd_usb *usb; struct zd_usb_rx *rx; @@ -778,7 +778,7 @@ void zd_usb_disable_rx(struct zd_usb *usb) spin_unlock_irqrestore(&rx->lock, flags); } -static void tx_urb_complete(struct urb *urb, struct pt_regs *pt_regs) +static void tx_urb_complete(struct urb *urb) { int r; @@ -1112,26 +1112,36 @@ static struct usb_driver driver = { .disconnect = disconnect, }; +struct workqueue_struct *zd_workqueue; + static int __init usb_init(void) { int r; - pr_debug("usb_init()\n"); + pr_debug("%s usb_init()\n", driver.name); + + zd_workqueue = create_singlethread_workqueue(driver.name); + if (zd_workqueue == NULL) { + printk(KERN_ERR "%s couldn't create workqueue\n", driver.name); + return -ENOMEM; + } r = usb_register(&driver); if (r) { - printk(KERN_ERR "usb_register() failed. Error number %d\n", r); + printk(KERN_ERR "%s usb_register() failed. Error number %d\n", + driver.name, r); return r; } - pr_debug("zd1211rw initialized\n"); + pr_debug("%s initialized\n", driver.name); return 0; } static void __exit usb_exit(void) { - pr_debug("usb_exit()\n"); + pr_debug("%s usb_exit()\n", driver.name); usb_deregister(&driver); + destroy_workqueue(zd_workqueue); } module_init(usb_init); @@ -1146,10 +1156,19 @@ static void prepare_read_regs_int(struct zd_usb *usb) { struct zd_usb_interrupt *intr = &usb->intr; - spin_lock(&intr->lock); + spin_lock_irq(&intr->lock); intr->read_regs_enabled = 1; INIT_COMPLETION(intr->read_regs.completion); - spin_unlock(&intr->lock); + spin_unlock_irq(&intr->lock); +} + +static void disable_read_regs_int(struct zd_usb *usb) +{ + struct zd_usb_interrupt *intr = &usb->intr; + + spin_lock_irq(&intr->lock); + intr->read_regs_enabled = 0; + spin_unlock_irq(&intr->lock); } static int get_results(struct zd_usb *usb, u16 *values, @@ -1161,7 +1180,7 @@ static int get_results(struct zd_usb *usb, u16 *values, struct read_regs_int *rr = &intr->read_regs; struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer; - spin_lock(&intr->lock); + spin_lock_irq(&intr->lock); r = -EIO; /* The created block size seems to be larger than expected. @@ -1194,7 +1213,7 @@ static int get_results(struct zd_usb *usb, u16 *values, r = 0; error_unlock: - spin_unlock(&intr->lock); + spin_unlock_irq(&intr->lock); return r; } diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index ded39de5f72..317d37c3667 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -74,17 +74,17 @@ enum control_requests { struct usb_req_read_regs { __le16 id; __le16 addr[0]; -}; +} __attribute__((packed)); struct reg_data { __le16 addr; __le16 value; -}; +} __attribute__((packed)); struct usb_req_write_regs { __le16 id; struct reg_data reg_writes[0]; -}; +} __attribute__((packed)); enum { RF_IF_LE = 0x02, @@ -101,7 +101,7 @@ struct usb_req_rfwrite { /* RF2595: 24 */ __le16 bit_values[0]; /* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */ -}; +} __attribute__((packed)); /* USB interrupt */ @@ -118,12 +118,12 @@ enum usb_int_flags { struct usb_int_header { u8 type; /* must always be 1 */ u8 id; -}; +} __attribute__((packed)); struct usb_int_regs { struct usb_int_header hdr; struct reg_data regs[0]; -}; +} __attribute__((packed)); struct usb_int_retry_fail { struct usb_int_header hdr; @@ -131,7 +131,7 @@ struct usb_int_retry_fail { u8 _dummy; u8 addr[ETH_ALEN]; u8 ibss_wakeup_dest; -}; +} __attribute__((packed)); struct read_regs_int { struct completion completion; @@ -238,4 +238,6 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits); +extern struct workqueue_struct *zd_workqueue; + #endif /* _ZD_USB_H */ |