diff options
Diffstat (limited to 'drivers/net/wireless/zd1211rw')
22 files changed, 4571 insertions, 3177 deletions
diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig index 66ed55bc546..96c8e1de087 100644 --- a/drivers/net/wireless/zd1211rw/Kconfig +++ b/drivers/net/wireless/zd1211rw/Kconfig @@ -1,13 +1,13 @@ config ZD1211RW tristate "ZyDAS ZD1211/ZD1211B USB-wireless support" - depends on USB && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL + depends on USB && MAC80211 select FW_LOADER ---help--- This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless chip, present in many USB-wireless adapters. - Device firmware is required alongside this driver. You can download the - firmware distribution from http://zd1211.ath.cx/get-firmware + Device firmware is required alongside this driver. You can download + the firmware distribution from http://zd1211.ath.cx/get-firmware config ZD1211RW_DEBUG bool "ZyDAS ZD1211 debugging" diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile index 6603ad5be63..5728a918e50 100644 --- a/drivers/net/wireless/zd1211rw/Makefile +++ b/drivers/net/wireless/zd1211rw/Makefile @@ -1,12 +1,9 @@ obj-$(CONFIG_ZD1211RW) += zd1211rw.o -zd1211rw-objs := zd_chip.o zd_ieee80211.o \ - zd_mac.o zd_netdev.o \ +zd1211rw-objs := zd_chip.o zd_mac.o \ zd_rf_al2230.o zd_rf_rf2959.o \ - zd_rf_al7230b.o \ - zd_rf.o zd_usb.o zd_util.o + zd_rf_al7230b.o zd_rf_uw2453.o \ + zd_rf.o zd_usb.o -ifeq ($(CONFIG_ZD1211RW_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_ZD1211RW_DEBUG) := -DDEBUG diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index aa661b2b76c..73a49b86803 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -1,4 +1,7 @@ -/* zd_chip.c +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ /* This file implements all the hardware specific functions for the ZD1211 @@ -22,21 +24,20 @@ #include <linux/kernel.h> #include <linux/errno.h> +#include <linux/slab.h> #include "zd_def.h" #include "zd_chip.h" -#include "zd_ieee80211.h" #include "zd_mac.h" #include "zd_rf.h" -#include "zd_util.h" void zd_chip_init(struct zd_chip *chip, - struct net_device *netdev, + struct ieee80211_hw *hw, struct usb_interface *intf) { memset(chip, 0, sizeof(*chip)); mutex_init(&chip->mutex); - zd_usb_init(&chip->usb, netdev, intf); + zd_usb_init(&chip->usb, hw, intf); zd_rf_init(&chip->rf); } @@ -49,8 +50,9 @@ void zd_chip_clear(struct zd_chip *chip) ZD_MEMCLEAR(chip, sizeof(*chip)); } -static int scnprint_mac_oui(const u8 *addr, char *buffer, size_t size) +static int scnprint_mac_oui(struct zd_chip *chip, char *buffer, size_t size) { + u8 *addr = zd_mac_get_perm_addr(zd_chip_to_mac(chip)); return scnprintf(buffer, size, "%02x-%02x-%02x", addr[0], addr[1], addr[2]); } @@ -61,17 +63,18 @@ static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size) int i = 0; i = scnprintf(buffer, size, "zd1211%s chip ", - chip->is_zd1211b ? "b" : ""); + zd_chip_is_zd1211b(chip) ? "b" : ""); i += zd_usb_scnprint_id(&chip->usb, buffer+i, size-i); i += scnprintf(buffer+i, size-i, " "); - i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i); + i += scnprint_mac_oui(chip, buffer+i, size-i); i += scnprintf(buffer+i, size-i, " "); i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i); - i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type, + i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type, chip->patch_cck_gain ? 'g' : '-', chip->patch_cr157 ? '7' : '-', chip->patch_6m_band_edge ? '6' : '-', - chip->new_phy_layout ? 'N' : '-'); + chip->new_phy_layout ? 'N' : '-', + chip->al2230s_bit ? 'S' : '-'); return i; } @@ -84,6 +87,18 @@ static void print_id(struct zd_chip *chip) dev_info(zd_chip_dev(chip), "%s\n", buffer); } +static zd_addr_t inc_addr(zd_addr_t addr) +{ + u16 a = (u16)addr; + /* Control registers use byte addressing, but everything else uses word + * addressing. */ + if ((a & 0xf000) == CR_START) + a += 2; + else + a += 1; + return (zd_addr_t)a; +} + /* Read a variable number of 32-bit values. Parameter count is not allowed to * exceed USB_MAX_IOREAD32_COUNT. */ @@ -92,29 +107,22 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr { int r; int i; - zd_addr_t *a16 = (zd_addr_t *)NULL; - u16 *v16; + zd_addr_t a16[USB_MAX_IOREAD32_COUNT * 2]; + u16 v16[USB_MAX_IOREAD32_COUNT * 2]; unsigned int count16; if (count > USB_MAX_IOREAD32_COUNT) return -EINVAL; - /* Allocate a single memory block for values and addresses. */ - count16 = 2*count; - a16 = (zd_addr_t *)kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)), - GFP_NOFS); - if (!a16) { - dev_dbg_f(zd_chip_dev(chip), - "error ENOMEM in allocation of a16\n"); - r = -ENOMEM; - goto out; - } - v16 = (u16 *)(a16 + count16); + /* Use stack for values and addresses. */ + count16 = 2 * count; + BUG_ON(count16 * sizeof(zd_addr_t) > sizeof(a16)); + BUG_ON(count16 * sizeof(u16) > sizeof(v16)); for (i = 0; i < count; i++) { int j = 2*i; /* We read the high word always first. */ - a16[j] = zd_inc_word(addr[i]); + a16[j] = inc_addr(addr[i]); a16[j+1] = addr[i]; } @@ -122,7 +130,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr if (r) { dev_dbg_f(zd_chip_dev(chip), "error: zd_ioread16v_locked. Error number %d\n", r); - goto out; + return r; } for (i = 0; i < count; i++) { @@ -130,18 +138,19 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr values[i] = (v16[j] << 16) | v16[j+1]; } -out: - kfree((void *)a16); - return r; + return 0; } -int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs, - unsigned int count) +static int _zd_iowrite32v_async_locked(struct zd_chip *chip, + const struct zd_ioreq32 *ioreqs, + unsigned int count) { int i, j, r; - struct zd_ioreq16 *ioreqs16; + struct zd_ioreq16 ioreqs16[USB_MAX_IOWRITE32_COUNT * 2]; unsigned int count16; + /* Use stack for values and addresses. */ + ZD_ASSERT(mutex_is_locked(&chip->mutex)); if (count == 0) @@ -149,37 +158,42 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs, if (count > USB_MAX_IOWRITE32_COUNT) return -EINVAL; - /* Allocate a single memory block for values and addresses. */ - count16 = 2*count; - ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_NOFS); - if (!ioreqs16) { - r = -ENOMEM; - dev_dbg_f(zd_chip_dev(chip), - "error %d in ioreqs16 allocation\n", r); - goto out; - } + count16 = 2 * count; + BUG_ON(count16 * sizeof(struct zd_ioreq16) > sizeof(ioreqs16)); for (i = 0; i < count; i++) { j = 2*i; /* We write the high word always first. */ ioreqs16[j].value = ioreqs[i].value >> 16; - ioreqs16[j].addr = zd_inc_word(ioreqs[i].addr); + ioreqs16[j].addr = inc_addr(ioreqs[i].addr); ioreqs16[j+1].value = ioreqs[i].value; ioreqs16[j+1].addr = ioreqs[i].addr; } - r = zd_usb_iowrite16v(&chip->usb, ioreqs16, count16); + r = zd_usb_iowrite16v_async(&chip->usb, ioreqs16, count16); #ifdef DEBUG if (r) { dev_dbg_f(zd_chip_dev(chip), "error %d in zd_usb_write16v\n", r); } #endif /* DEBUG */ -out: - kfree(ioreqs16); return r; } +int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs, + unsigned int count) +{ + int r; + + zd_usb_iowrite16v_async_start(&chip->usb); + r = _zd_iowrite32v_async_locked(chip, ioreqs, count); + if (r) { + zd_usb_iowrite16v_async_end(&chip->usb, 0); + return r; + } + return zd_usb_iowrite16v_async_end(&chip->usb, 50 /* ms */); +} + int zd_iowrite16a_locked(struct zd_chip *chip, const struct zd_ioreq16 *ioreqs, unsigned int count) { @@ -187,6 +201,8 @@ int zd_iowrite16a_locked(struct zd_chip *chip, unsigned int i, j, t, max; ZD_ASSERT(mutex_is_locked(&chip->mutex)); + zd_usb_iowrite16v_async_start(&chip->usb); + for (i = 0; i < count; i += j + t) { t = 0; max = count-i; @@ -199,8 +215,9 @@ int zd_iowrite16a_locked(struct zd_chip *chip, } } - r = zd_usb_iowrite16v(&chip->usb, &ioreqs[i], j); + r = zd_usb_iowrite16v_async(&chip->usb, &ioreqs[i], j); if (r) { + zd_usb_iowrite16v_async_end(&chip->usb, 0); dev_dbg_f(zd_chip_dev(chip), "error zd_usb_iowrite16v. Error number %d\n", r); @@ -208,7 +225,7 @@ int zd_iowrite16a_locked(struct zd_chip *chip, } } - return 0; + return zd_usb_iowrite16v_async_end(&chip->usb, 50 /* ms */); } /* Writes a variable number of 32 bit registers. The functions will split @@ -221,6 +238,8 @@ int zd_iowrite32a_locked(struct zd_chip *chip, int r; unsigned int i, j, t, max; + zd_usb_iowrite16v_async_start(&chip->usb); + for (i = 0; i < count; i += j + t) { t = 0; max = count-i; @@ -233,8 +252,9 @@ int zd_iowrite32a_locked(struct zd_chip *chip, } } - r = _zd_iowrite32v_locked(chip, &ioreqs[i], j); + r = _zd_iowrite32v_async_locked(chip, &ioreqs[i], j); if (r) { + zd_usb_iowrite16v_async_end(&chip->usb, 0); dev_dbg_f(zd_chip_dev(chip), "error _zd_iowrite32v_locked." " Error number %d\n", r); @@ -242,7 +262,7 @@ int zd_iowrite32a_locked(struct zd_chip *chip, } } - return 0; + return zd_usb_iowrite16v_async_end(&chip->usb, 50 /* ms */); } int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value) @@ -325,6 +345,7 @@ 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->al2230s_bit = (value >> 7) & 0x1; chip->link_led = ((value >> 4) & 1) ? LED1 : LED2; chip->supports_tx_led = 1; if (value & (1 << 24)) { /* LED scenario */ @@ -352,92 +373,52 @@ error: return r; } -static int _read_mac_addr(struct zd_chip *chip, u8 *mac_addr, - const zd_addr_t *addr) +static int zd_write_mac_addr_common(struct zd_chip *chip, const u8 *mac_addr, + const struct zd_ioreq32 *in_reqs, + const char *type) { int r; - u32 parts[2]; - - r = zd_ioread32v_locked(chip, parts, (const zd_addr_t *)addr, 2); - if (r) { - dev_dbg_f(zd_chip_dev(chip), - "error: couldn't read e2p macs. Error number %d\n", r); - return r; + struct zd_ioreq32 reqs[2] = {in_reqs[0], in_reqs[1]}; + + if (mac_addr) { + reqs[0].value = (mac_addr[3] << 24) + | (mac_addr[2] << 16) + | (mac_addr[1] << 8) + | mac_addr[0]; + reqs[1].value = (mac_addr[5] << 8) + | mac_addr[4]; + dev_dbg_f(zd_chip_dev(chip), "%s addr %pM\n", type, mac_addr); + } else { + dev_dbg_f(zd_chip_dev(chip), "set NULL %s\n", type); } - mac_addr[0] = parts[0]; - mac_addr[1] = parts[0] >> 8; - mac_addr[2] = parts[0] >> 16; - mac_addr[3] = parts[0] >> 24; - mac_addr[4] = parts[1]; - mac_addr[5] = parts[1] >> 8; - - return 0; -} - -static int read_e2p_mac_addr(struct zd_chip *chip) -{ - static const zd_addr_t addr[2] = { E2P_MAC_ADDR_P1, E2P_MAC_ADDR_P2 }; - - ZD_ASSERT(mutex_is_locked(&chip->mutex)); - return _read_mac_addr(chip, chip->e2p_mac, (const zd_addr_t *)addr); -} - -/* MAC address: if custom mac addresses are to to be used CR_MAC_ADDR_P1 and - * CR_MAC_ADDR_P2 must be overwritten - */ -void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr) -{ - mutex_lock(&chip->mutex); - memcpy(mac_addr, chip->e2p_mac, ETH_ALEN); - mutex_unlock(&chip->mutex); -} - -static int read_mac_addr(struct zd_chip *chip, u8 *mac_addr) -{ - static const zd_addr_t addr[2] = { CR_MAC_ADDR_P1, CR_MAC_ADDR_P2 }; - return _read_mac_addr(chip, mac_addr, (const zd_addr_t *)addr); -} - -int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr) -{ - int r; - - dev_dbg_f(zd_chip_dev(chip), "\n"); mutex_lock(&chip->mutex); - r = read_mac_addr(chip, mac_addr); + r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs)); mutex_unlock(&chip->mutex); return r; } +/* MAC address: if custom mac addresses are to be used CR_MAC_ADDR_P1 and + * CR_MAC_ADDR_P2 must be overwritten + */ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) { - int r; - struct zd_ioreq32 reqs[2] = { + static const struct zd_ioreq32 reqs[2] = { [0] = { .addr = CR_MAC_ADDR_P1 }, [1] = { .addr = CR_MAC_ADDR_P2 }, }; - reqs[0].value = (mac_addr[3] << 24) - | (mac_addr[2] << 16) - | (mac_addr[1] << 8) - | mac_addr[0]; - reqs[1].value = (mac_addr[5] << 8) - | mac_addr[4]; + return zd_write_mac_addr_common(chip, mac_addr, reqs, "mac"); +} - dev_dbg_f(zd_chip_dev(chip), - "mac addr " MAC_FMT "\n", MAC_ARG(mac_addr)); +int zd_write_bssid(struct zd_chip *chip, const u8 *bssid) +{ + static const struct zd_ioreq32 reqs[2] = { + [0] = { .addr = CR_BSSID_P1 }, + [1] = { .addr = CR_BSSID_P2 }, + }; - mutex_lock(&chip->mutex); - r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs)); -#ifdef DEBUG - { - u8 tmp[ETH_ALEN]; - read_mac_addr(chip, tmp); - } -#endif /* DEBUG */ - mutex_unlock(&chip->mutex); - return r; + return zd_write_mac_addr_common(chip, bssid, reqs, "bssid"); } int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain) @@ -466,7 +447,8 @@ static int read_values(struct zd_chip *chip, u8 *values, size_t count, ZD_ASSERT(mutex_is_locked(&chip->mutex)); for (i = 0;;) { - r = zd_ioread32_locked(chip, &v, e2p_addr+i/2); + r = zd_ioread32_locked(chip, &v, + (zd_addr_t)((u16)e2p_addr+i/2)); if (r) return r; v -= guard; @@ -545,8 +527,6 @@ int zd_chip_lock_phy_regs(struct zd_chip *chip) return r; } - dev_dbg_f(zd_chip_dev(chip), - "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp & ~UNLOCK_PHY_REGS); tmp &= ~UNLOCK_PHY_REGS; r = zd_iowrite32_locked(chip, tmp, CR_REG1); @@ -568,8 +548,6 @@ int zd_chip_unlock_phy_regs(struct zd_chip *chip) return r; } - dev_dbg_f(zd_chip_dev(chip), - "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp | UNLOCK_PHY_REGS); tmp |= UNLOCK_PHY_REGS; r = zd_iowrite32_locked(chip, tmp, CR_REG1); @@ -578,21 +556,21 @@ int zd_chip_unlock_phy_regs(struct zd_chip *chip) return r; } -/* CR157 can be optionally patched by the EEPROM */ +/* ZD_CR157 can be optionally patched by the EEPROM for original ZD1211 */ static int patch_cr157(struct zd_chip *chip) { int r; - u32 value; + u16 value; if (!chip->patch_cr157) return 0; - r = zd_ioread32_locked(chip, &value, E2P_PHY_REG); + r = zd_ioread16_locked(chip, &value, E2P_PHY_REG); if (r) return r; dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8); - return zd_iowrite32_locked(chip, value >> 8, CR157); + return zd_iowrite32_locked(chip, value >> 8, ZD_CR157); } /* @@ -600,16 +578,24 @@ static int patch_cr157(struct zd_chip *chip) * Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge * bit (for AL2230, AL2230S) */ -static int patch_6m_band_edge(struct zd_chip *chip, int channel) +static int patch_6m_band_edge(struct zd_chip *chip, u8 channel) +{ + ZD_ASSERT(mutex_is_locked(&chip->mutex)); + if (!chip->patch_6m_band_edge) + return 0; + + return zd_rf_patch_6m_band_edge(&chip->rf, channel); +} + +/* Generic implementation of 6M band edge patching, used by most RFs via + * zd_rf_generic_patch_6m() */ +int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) { struct zd_ioreq16 ioreqs[] = { - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR47, 0x1e }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR47, 0x1e }, }; - if (!chip->patch_6m_band_edge || !chip->rf.patch_6m_band_edge) - return 0; - /* FIXME: Channel 11 is not the edge for all regulatory domains. */ if (channel == 1 || channel == 11) ioreqs[0].value = 0x12; @@ -621,69 +607,69 @@ static int patch_6m_band_edge(struct zd_chip *chip, int channel) static int zd1211_hw_reset_phy(struct zd_chip *chip) { static const struct zd_ioreq16 ioreqs[] = { - { CR0, 0x0a }, { CR1, 0x06 }, { CR2, 0x26 }, - { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xa0 }, - { CR10, 0x81 }, { CR11, 0x00 }, { CR12, 0x7f }, - { CR13, 0x8c }, { CR14, 0x80 }, { CR15, 0x3d }, - { CR16, 0x20 }, { CR17, 0x1e }, { CR18, 0x0a }, - { CR19, 0x48 }, { CR20, 0x0c }, { CR21, 0x0c }, - { CR22, 0x23 }, { CR23, 0x90 }, { CR24, 0x14 }, - { CR25, 0x40 }, { CR26, 0x10 }, { CR27, 0x19 }, - { CR28, 0x7f }, { CR29, 0x80 }, { CR30, 0x4b }, - { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 }, - { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 }, - { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c }, - { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 }, - { CR43, 0x10 }, { CR44, 0x12 }, { CR46, 0xff }, - { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b }, - { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 }, - { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 }, - { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff }, - { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 }, - { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 }, - { CR79, 0x68 }, { CR80, 0x64 }, { CR81, 0x64 }, - { CR82, 0x00 }, { CR83, 0x00 }, { CR84, 0x00 }, - { CR85, 0x02 }, { CR86, 0x00 }, { CR87, 0x00 }, - { CR88, 0xff }, { CR89, 0xfc }, { CR90, 0x00 }, - { CR91, 0x00 }, { CR92, 0x00 }, { CR93, 0x08 }, - { CR94, 0x00 }, { CR95, 0x00 }, { CR96, 0xff }, - { CR97, 0xe7 }, { CR98, 0x00 }, { CR99, 0x00 }, - { CR100, 0x00 }, { CR101, 0xae }, { CR102, 0x02 }, - { CR103, 0x00 }, { CR104, 0x03 }, { CR105, 0x65 }, - { CR106, 0x04 }, { CR107, 0x00 }, { CR108, 0x0a }, - { CR109, 0xaa }, { CR110, 0xaa }, { CR111, 0x25 }, - { CR112, 0x25 }, { CR113, 0x00 }, { CR119, 0x1e }, - { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 }, + { ZD_CR0, 0x0a }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, + { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xa0 }, + { ZD_CR10, 0x81 }, { ZD_CR11, 0x00 }, { ZD_CR12, 0x7f }, + { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, { ZD_CR15, 0x3d }, + { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, { ZD_CR18, 0x0a }, + { ZD_CR19, 0x48 }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0c }, + { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, { ZD_CR24, 0x14 }, + { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, { ZD_CR27, 0x19 }, + { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, { ZD_CR30, 0x4b }, + { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, + { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, + { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, + { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, + { ZD_CR43, 0x10 }, { ZD_CR44, 0x12 }, { ZD_CR46, 0xff }, + { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, + { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, + { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, + { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, + { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, + { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, + { ZD_CR79, 0x68 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, + { ZD_CR82, 0x00 }, { ZD_CR83, 0x00 }, { ZD_CR84, 0x00 }, + { ZD_CR85, 0x02 }, { ZD_CR86, 0x00 }, { ZD_CR87, 0x00 }, + { ZD_CR88, 0xff }, { ZD_CR89, 0xfc }, { ZD_CR90, 0x00 }, + { ZD_CR91, 0x00 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x08 }, + { ZD_CR94, 0x00 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0xff }, + { ZD_CR97, 0xe7 }, { ZD_CR98, 0x00 }, { ZD_CR99, 0x00 }, + { ZD_CR100, 0x00 }, { ZD_CR101, 0xae }, { ZD_CR102, 0x02 }, + { ZD_CR103, 0x00 }, { ZD_CR104, 0x03 }, { ZD_CR105, 0x65 }, + { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, { ZD_CR108, 0x0a }, + { ZD_CR109, 0xaa }, { ZD_CR110, 0xaa }, { ZD_CR111, 0x25 }, + { ZD_CR112, 0x25 }, { ZD_CR113, 0x00 }, { ZD_CR119, 0x1e }, + { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, { }, - { CR5, 0x00 }, { CR6, 0x00 }, { CR7, 0x00 }, - { CR8, 0x00 }, { CR9, 0x20 }, { CR12, 0xf0 }, - { CR20, 0x0e }, { CR21, 0x0e }, { CR27, 0x10 }, - { CR44, 0x33 }, { CR47, 0x1E }, { CR83, 0x24 }, - { CR84, 0x04 }, { CR85, 0x00 }, { CR86, 0x0C }, - { CR87, 0x12 }, { CR88, 0x0C }, { CR89, 0x00 }, - { CR90, 0x10 }, { CR91, 0x08 }, { CR93, 0x00 }, - { CR94, 0x01 }, { CR95, 0x00 }, { CR96, 0x50 }, - { CR97, 0x37 }, { CR98, 0x35 }, { CR101, 0x13 }, - { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 }, - { CR105, 0x12 }, { CR109, 0x27 }, { CR110, 0x27 }, - { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, - { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, - { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f }, - { CR123, 0x27 }, { CR125, 0xaa }, { CR127, 0x03 }, - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR131, 0x0C }, { CR136, 0xdf }, { CR137, 0x40 }, - { CR138, 0xa0 }, { CR139, 0xb0 }, { CR140, 0x99 }, - { CR141, 0x82 }, { CR142, 0x54 }, { CR143, 0x1c }, - { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x4c }, - { CR149, 0x50 }, { CR150, 0x0e }, { CR151, 0x18 }, - { CR160, 0xfe }, { CR161, 0xee }, { CR162, 0xaa }, - { CR163, 0xfa }, { CR164, 0xfa }, { CR165, 0xea }, - { CR166, 0xbe }, { CR167, 0xbe }, { CR168, 0x6a }, - { CR169, 0xba }, { CR170, 0xba }, { CR171, 0xba }, - /* Note: CR204 must lead the CR203 */ - { CR204, 0x7d }, + { ZD_CR5, 0x00 }, { ZD_CR6, 0x00 }, { ZD_CR7, 0x00 }, + { ZD_CR8, 0x00 }, { ZD_CR9, 0x20 }, { ZD_CR12, 0xf0 }, + { ZD_CR20, 0x0e }, { ZD_CR21, 0x0e }, { ZD_CR27, 0x10 }, + { ZD_CR44, 0x33 }, { ZD_CR47, 0x1E }, { ZD_CR83, 0x24 }, + { ZD_CR84, 0x04 }, { ZD_CR85, 0x00 }, { ZD_CR86, 0x0C }, + { ZD_CR87, 0x12 }, { ZD_CR88, 0x0C }, { ZD_CR89, 0x00 }, + { ZD_CR90, 0x10 }, { ZD_CR91, 0x08 }, { ZD_CR93, 0x00 }, + { ZD_CR94, 0x01 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0x50 }, + { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, { ZD_CR101, 0x13 }, + { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, + { ZD_CR105, 0x12 }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, + { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, + { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR120, 0x4f }, + { ZD_CR125, 0xaa }, { ZD_CR127, 0x03 }, { ZD_CR128, 0x14 }, + { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, { ZD_CR131, 0x0C }, + { ZD_CR136, 0xdf }, { ZD_CR137, 0x40 }, { ZD_CR138, 0xa0 }, + { ZD_CR139, 0xb0 }, { ZD_CR140, 0x99 }, { ZD_CR141, 0x82 }, + { ZD_CR142, 0x54 }, { ZD_CR143, 0x1c }, { ZD_CR144, 0x6c }, + { ZD_CR147, 0x07 }, { ZD_CR148, 0x4c }, { ZD_CR149, 0x50 }, + { ZD_CR150, 0x0e }, { ZD_CR151, 0x18 }, { ZD_CR160, 0xfe }, + { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, + { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, + { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, + { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, + /* Note: ZD_CR204 must lead the ZD_CR203 */ + { ZD_CR204, 0x7d }, { }, - { CR203, 0x30 }, + { ZD_CR203, 0x30 }, }; int r, t; @@ -710,62 +696,62 @@ out: static int zd1211b_hw_reset_phy(struct zd_chip *chip) { static const struct zd_ioreq16 ioreqs[] = { - { CR0, 0x14 }, { CR1, 0x06 }, { CR2, 0x26 }, - { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xe0 }, - { CR10, 0x81 }, - /* power control { { CR11, 1 << 6 }, */ - { CR11, 0x00 }, - { CR12, 0xf0 }, { CR13, 0x8c }, { CR14, 0x80 }, - { CR15, 0x3d }, { CR16, 0x20 }, { CR17, 0x1e }, - { CR18, 0x0a }, { CR19, 0x48 }, - { CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */ - { CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 }, - { CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 }, - { CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 }, - { CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ - { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 }, - { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 }, - { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c }, - { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 }, - { CR43, 0x10 }, { CR44, 0x33 }, { CR46, 0xff }, - { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b }, - { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 }, - { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 }, - { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff }, - { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 }, - { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 }, - { CR79, 0xf0 }, { CR80, 0x64 }, { CR81, 0x64 }, - { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 }, - { CR85, 0x00 }, { CR86, 0x0c }, { CR87, 0x12 }, - { CR88, 0x0c }, { CR89, 0x00 }, { CR90, 0x58 }, - { CR91, 0x04 }, { CR92, 0x00 }, { CR93, 0x00 }, - { CR94, 0x01 }, - { CR95, 0x20 }, /* ZD1211B */ - { CR96, 0x50 }, { CR97, 0x37 }, { CR98, 0x35 }, - { CR99, 0x00 }, { CR100, 0x01 }, { CR101, 0x13 }, - { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 }, - { CR105, 0x12 }, { CR106, 0x04 }, { CR107, 0x00 }, - { CR108, 0x0a }, { CR109, 0x27 }, { CR110, 0x27 }, - { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, - { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, - { CR117, 0xfc }, { CR118, 0xfa }, { CR119, 0x1e }, - { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 }, - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR131, 0x0c }, { CR136, 0xdf }, { CR137, 0xa0 }, - { CR138, 0xa8 }, { CR139, 0xb4 }, { CR140, 0x98 }, - { CR141, 0x82 }, { CR142, 0x53 }, { CR143, 0x1c }, - { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x40 }, - { CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */ - { CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */ - { CR151, 0x18 }, { CR159, 0x70 }, { CR160, 0xfe }, - { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa }, - { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe }, - { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba }, - { CR170, 0xba }, { CR171, 0xba }, - /* Note: CR204 must lead the CR203 */ - { CR204, 0x7d }, + { ZD_CR0, 0x14 }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, + { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xe0 }, + { ZD_CR10, 0x81 }, + /* power control { { ZD_CR11, 1 << 6 }, */ + { ZD_CR11, 0x00 }, + { ZD_CR12, 0xf0 }, { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, + { ZD_CR15, 0x3d }, { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, + { ZD_CR18, 0x0a }, { ZD_CR19, 0x48 }, + { ZD_CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */ + { ZD_CR21, 0x0e }, { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, + { ZD_CR24, 0x14 }, { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, + { ZD_CR27, 0x10 }, { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, + { ZD_CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ + { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, + { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, + { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, + { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, + { ZD_CR43, 0x10 }, { ZD_CR44, 0x33 }, { ZD_CR46, 0xff }, + { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, + { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, + { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, + { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, + { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, + { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, + { ZD_CR79, 0xf0 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, + { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 }, + { ZD_CR85, 0x00 }, { ZD_CR86, 0x0c }, { ZD_CR87, 0x12 }, + { ZD_CR88, 0x0c }, { ZD_CR89, 0x00 }, { ZD_CR90, 0x58 }, + { ZD_CR91, 0x04 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x00 }, + { ZD_CR94, 0x01 }, + { ZD_CR95, 0x20 }, /* ZD1211B */ + { ZD_CR96, 0x50 }, { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, + { ZD_CR99, 0x00 }, { ZD_CR100, 0x01 }, { ZD_CR101, 0x13 }, + { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, + { ZD_CR105, 0x12 }, { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, + { ZD_CR108, 0x0a }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, + { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, + { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x1e }, + { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR131, 0x0c }, { ZD_CR136, 0xdf }, { ZD_CR137, 0xa0 }, + { ZD_CR138, 0xa8 }, { ZD_CR139, 0xb4 }, { ZD_CR140, 0x98 }, + { ZD_CR141, 0x82 }, { ZD_CR142, 0x53 }, { ZD_CR143, 0x1c }, + { ZD_CR144, 0x6c }, { ZD_CR147, 0x07 }, { ZD_CR148, 0x40 }, + { ZD_CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */ + { ZD_CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */ + { ZD_CR151, 0x18 }, { ZD_CR159, 0x70 }, { ZD_CR160, 0xfe }, + { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, + { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, + { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, + { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, + /* Note: ZD_CR204 must lead the ZD_CR203 */ + { ZD_CR204, 0x7d }, {}, - { CR203, 0x30 }, + { ZD_CR203, 0x30 }, }; int r, t; @@ -777,11 +763,6 @@ static int zd1211b_hw_reset_phy(struct zd_chip *chip) goto out; r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); - if (r) - goto unlock; - - r = patch_cr157(chip); -unlock: t = zd_chip_unlock_phy_regs(chip); if (t && !r) r = t; @@ -791,62 +772,47 @@ out: static int hw_reset_phy(struct zd_chip *chip) { - return chip->is_zd1211b ? zd1211b_hw_reset_phy(chip) : + return zd_chip_is_zd1211b(chip) ? zd1211b_hw_reset_phy(chip) : zd1211_hw_reset_phy(chip); } static int zd1211_hw_init_hmac(struct zd_chip *chip) { static const struct zd_ioreq32 ioreqs[] = { - { CR_ACK_TIMEOUT_EXT, 0x20 }, - { CR_ADDA_MBIAS_WARMTIME, 0x30000808 }, - { CR_ZD1211_RETRY_MAX, 0x2 }, - { CR_SNIFFER_ON, 0 }, - { CR_RX_FILTER, STA_RX_FILTER }, - { CR_GROUP_HASH_P1, 0x00 }, - { CR_GROUP_HASH_P2, 0x80000000 }, - { CR_REG1, 0xa4 }, - { CR_ADDA_PWR_DWN, 0x7f }, - { CR_BCN_PLCP_CFG, 0x00f00401 }, - { CR_PHY_DELAY, 0x00 }, - { CR_ACK_TIMEOUT_EXT, 0x80 }, - { CR_ADDA_PWR_DWN, 0x00 }, - { CR_ACK_TIME_80211, 0x100 }, - { CR_RX_PE_DELAY, 0x70 }, - { CR_PS_CTRL, 0x10000000 }, - { CR_RTS_CTS_RATE, 0x02030203 }, + { CR_ZD1211_RETRY_MAX, ZD1211_RETRY_COUNT }, { CR_RX_THRESHOLD, 0x000c0640 }, - { CR_AFTER_PNP, 0x1 }, - { CR_WEP_PROTECT, 0x114 }, }; - int r; - dev_dbg_f(zd_chip_dev(chip), "\n"); ZD_ASSERT(mutex_is_locked(&chip->mutex)); - r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); -#ifdef DEBUG - if (r) { - dev_err(zd_chip_dev(chip), - "error in zd_iowrite32a_locked. Error number %d\n", r); - } -#endif /* DEBUG */ - return r; + return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); } static int zd1211b_hw_init_hmac(struct zd_chip *chip) { static const struct zd_ioreq32 ioreqs[] = { - { CR_ACK_TIMEOUT_EXT, 0x20 }, - { CR_ADDA_MBIAS_WARMTIME, 0x30000808 }, - { CR_ZD1211B_RETRY_MAX, 0x02020202 }, - { CR_ZD1211B_TX_PWR_CTL4, 0x007f003f }, - { CR_ZD1211B_TX_PWR_CTL3, 0x007f003f }, - { CR_ZD1211B_TX_PWR_CTL2, 0x003f001f }, - { CR_ZD1211B_TX_PWR_CTL1, 0x001f000f }, + { CR_ZD1211B_RETRY_MAX, ZD1211B_RETRY_COUNT }, + { CR_ZD1211B_CWIN_MAX_MIN_AC0, 0x007f003f }, + { CR_ZD1211B_CWIN_MAX_MIN_AC1, 0x007f003f }, + { CR_ZD1211B_CWIN_MAX_MIN_AC2, 0x003f001f }, + { CR_ZD1211B_CWIN_MAX_MIN_AC3, 0x001f000f }, { CR_ZD1211B_AIFS_CTL1, 0x00280028 }, { CR_ZD1211B_AIFS_CTL2, 0x008C003C }, { CR_ZD1211B_TXOP, 0x01800824 }, + { CR_RX_THRESHOLD, 0x000c0eff, }, + }; + + dev_dbg_f(zd_chip_dev(chip), "\n"); + ZD_ASSERT(mutex_is_locked(&chip->mutex)); + return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} + +static int hw_init_hmac(struct zd_chip *chip) +{ + int r; + static const struct zd_ioreq32 ioreqs[] = { + { CR_ACK_TIMEOUT_EXT, 0x20 }, + { CR_ADDA_MBIAS_WARMTIME, 0x30000808 }, { CR_SNIFFER_ON, 0 }, { CR_RX_FILTER, STA_RX_FILTER }, { CR_GROUP_HASH_P1, 0x00 }, @@ -861,26 +827,18 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip) { CR_RX_PE_DELAY, 0x70 }, { CR_PS_CTRL, 0x10000000 }, { CR_RTS_CTS_RATE, 0x02030203 }, - { CR_RX_THRESHOLD, 0x000c0eff, }, { CR_AFTER_PNP, 0x1 }, { CR_WEP_PROTECT, 0x114 }, + { CR_IFS_VALUE, IFS_VALUE_DEFAULT }, + { CR_CAM_MODE, MODE_AP_WDS}, }; - int r; - - dev_dbg_f(zd_chip_dev(chip), "\n"); ZD_ASSERT(mutex_is_locked(&chip->mutex)); r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); - if (r) { - dev_dbg_f(zd_chip_dev(chip), - "error in zd_iowrite32a_locked. Error number %d\n", r); - } - return r; -} + if (r) + return r; -static int hw_init_hmac(struct zd_chip *chip) -{ - return chip->is_zd1211b ? + return zd_chip_is_zd1211b(chip) ? zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip); } @@ -907,19 +865,18 @@ static int get_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s) s->atim_wnd_period = values[0]; s->pre_tbtt = values[1]; s->beacon_interval = values[2]; - dev_dbg_f(zd_chip_dev(chip), "aw %u pt %u bi %u\n", - s->atim_wnd_period, s->pre_tbtt, s->beacon_interval); return 0; } static int set_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s) { struct zd_ioreq32 reqs[3]; + u16 b_interval = s->beacon_interval & 0xffff; - if (s->beacon_interval <= 5) - s->beacon_interval = 5; - if (s->pre_tbtt < 4 || s->pre_tbtt >= s->beacon_interval) - s->pre_tbtt = s->beacon_interval - 1; + if (b_interval <= 5) + b_interval = 5; + if (s->pre_tbtt < 4 || s->pre_tbtt >= b_interval) + s->pre_tbtt = b_interval - 1; if (s->atim_wnd_period >= s->pre_tbtt) s->atim_wnd_period = s->pre_tbtt - 1; @@ -928,34 +885,57 @@ static int set_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s) reqs[1].addr = CR_PRE_TBTT; reqs[1].value = s->pre_tbtt; reqs[2].addr = CR_BCN_INTERVAL; - reqs[2].value = s->beacon_interval; + reqs[2].value = (s->beacon_interval & ~0xffff) | b_interval; - dev_dbg_f(zd_chip_dev(chip), - "aw %u pt %u bi %u\n", s->atim_wnd_period, s->pre_tbtt, - s->beacon_interval); return zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs)); } -static int set_beacon_interval(struct zd_chip *chip, u32 interval) +static int set_beacon_interval(struct zd_chip *chip, u16 interval, + u8 dtim_period, int type) { int r; struct aw_pt_bi s; + u32 b_interval, mode_flag; ZD_ASSERT(mutex_is_locked(&chip->mutex)); + + if (interval > 0) { + switch (type) { + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + mode_flag = BCN_MODE_IBSS; + break; + case NL80211_IFTYPE_AP: + mode_flag = BCN_MODE_AP; + break; + default: + mode_flag = 0; + break; + } + } else { + dtim_period = 0; + mode_flag = 0; + } + + b_interval = mode_flag | (dtim_period << 16) | interval; + + r = zd_iowrite32_locked(chip, b_interval, CR_BCN_INTERVAL); + if (r) + return r; r = get_aw_pt_bi(chip, &s); if (r) return r; - s.beacon_interval = interval; return set_aw_pt_bi(chip, &s); } -int zd_set_beacon_interval(struct zd_chip *chip, u32 interval) +int zd_set_beacon_interval(struct zd_chip *chip, u16 interval, u8 dtim_period, + int type) { int r; mutex_lock(&chip->mutex); - r = set_beacon_interval(chip, interval); + r = set_beacon_interval(chip, interval, dtim_period, type); mutex_unlock(&chip->mutex); return r; } @@ -974,14 +954,12 @@ static int hw_init(struct zd_chip *chip) if (r) return r; - /* Although the vendor driver defaults to a different value during - * init, it overwrites the IFS value with the following every time - * the channel changes. We should aim to be more intelligent... */ - r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE); - if (r) - return r; + return set_beacon_interval(chip, 100, 0, NL80211_IFTYPE_UNSPECIFIED); +} - return set_beacon_interval(chip, 100); +static zd_addr_t fw_reg_addr(struct zd_chip *chip, u16 offset) +{ + return (zd_addr_t)((u16)chip->fw_regs_base + offset); } #ifdef DEBUG @@ -1018,9 +996,11 @@ static int test_init(struct zd_chip *chip) static void dump_fw_registers(struct zd_chip *chip) { - static const zd_addr_t addr[4] = { - FW_FIRMWARE_VER, FW_USB_SPEED, FW_FIX_TX_RATE, - FW_LINK_STATUS + const zd_addr_t addr[4] = { + fw_reg_addr(chip, FW_REG_FIRMWARE_VER), + fw_reg_addr(chip, FW_REG_USB_SPEED), + fw_reg_addr(chip, FW_REG_FIX_TX_RATE), + fw_reg_addr(chip, FW_REG_LED_LINK_STATUS), }; int r; @@ -1043,18 +1023,24 @@ static void dump_fw_registers(struct zd_chip *chip) static int print_fw_version(struct zd_chip *chip) { + struct wiphy *wiphy = zd_chip_to_mac(chip)->hw->wiphy; int r; u16 version; - r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER); + r = zd_ioread16_locked(chip, &version, + fw_reg_addr(chip, FW_REG_FIRMWARE_VER)); if (r) return r; dev_info(zd_chip_dev(chip),"firmware version %04hx\n", version); + + snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), + "%04hx", version); + return 0; } -static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std) +static int set_mandatory_rates(struct zd_chip *chip, int gmode) { u32 rates; ZD_ASSERT(mutex_is_locked(&chip->mutex)); @@ -1062,20 +1048,33 @@ static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std) * that the device is supporting. Until further notice we should try * to support 802.11g also for full speed USB. */ - switch (std) { - case IEEE80211B: + if (!gmode) rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M; - break; - case IEEE80211G: + else rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M| CR_RATE_6M|CR_RATE_12M|CR_RATE_24M; - break; - default: - return -EINVAL; - } + return zd_iowrite32_locked(chip, rates, CR_MANDATORY_RATE_TBL); } +int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, + int preamble) +{ + u32 value = 0; + + dev_dbg_f(zd_chip_dev(chip), "preamble=%x\n", preamble); + value |= preamble << RTSCTS_SH_RTS_PMB_TYPE; + value |= preamble << RTSCTS_SH_CTS_PMB_TYPE; + + /* We always send 11M RTS/self-CTS messages, like the vendor driver. */ + value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_RTS_RATE; + value |= ZD_RX_CCK << RTSCTS_SH_RTS_MOD_TYPE; + value |= ZD_PURE_RATE(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; @@ -1101,7 +1100,30 @@ int zd_chip_disable_hwint(struct zd_chip *chip) return r; } -int zd_chip_init_hw(struct zd_chip *chip, u8 device_type) +static int read_fw_regs_offset(struct zd_chip *chip) +{ + int r; + + ZD_ASSERT(mutex_is_locked(&chip->mutex)); + r = zd_ioread16_locked(chip, (u16*)&chip->fw_regs_base, + FWRAW_REGS_ADDR); + if (r) + return r; + dev_dbg_f(zd_chip_dev(chip), "fw_regs_base: %#06hx\n", + (u16)chip->fw_regs_base); + + return 0; +} + +/* Read mac address using pre-firmware interface */ +int zd_chip_read_mac_addr_fw(struct zd_chip *chip, u8 *addr) +{ + dev_dbg_f(zd_chip_dev(chip), "\n"); + return zd_usb_read_fw(&chip->usb, E2P_MAC_ADDR_P1, addr, + ETH_ALEN); +} + +int zd_chip_init_hw(struct zd_chip *chip) { int r; u8 rf_type; @@ -1109,7 +1131,6 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type) dev_dbg_f(zd_chip_dev(chip), "\n"); mutex_lock(&chip->mutex); - chip->is_zd1211b = (device_type == DEVICE_ZD1211B) != 0; #ifdef DEBUG r = test_init(chip); @@ -1120,7 +1141,7 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type) if (r) goto out; - r = zd_usb_init_hw(&chip->usb); + r = read_fw_regs_offset(chip); if (r) goto out; @@ -1133,10 +1154,10 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type) if (r) goto out; /* Currently we support IEEE 802.11g for full and high speed USB. - * It might be discussed, whether we should suppport pure b mode for + * It might be discussed, whether we should support pure b mode for * full speed USB. */ - r = set_mandatory_rates(chip, IEEE80211G); + r = set_mandatory_rates(chip, 1); if (r) goto out; /* Disabling interrupts is certainly a smart thing here. @@ -1165,10 +1186,6 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type) goto out; #endif /* DEBUG */ - r = read_e2p_mac_addr(chip); - if (r) - goto out; - r = read_cal_int_tables(chip); if (r) goto out; @@ -1182,33 +1199,26 @@ out: 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_iowrite16_locked(chip, value, CR31); + return zd_iowrite16_locked(chip, value, ZD_CR31); } 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_iowrite16_locked(chip, value, CR68); + return zd_iowrite16_locked(chip, value, ZD_CR68); } static int update_ofdm_cal(struct zd_chip *chip, u8 channel) { struct zd_ioreq16 ioreqs[3]; - ioreqs[0].addr = CR67; + ioreqs[0].addr = ZD_CR67; ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1]; - ioreqs[1].addr = CR66; + ioreqs[1].addr = ZD_CR66; ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1]; - ioreqs[2].addr = CR65; + ioreqs[2].addr = ZD_CR65; ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1]; - 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_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); } @@ -1217,14 +1227,17 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip, { int r; + if (!zd_rf_should_update_pwr_int(&chip->rf)) + return 0; + r = update_pwr_int(chip, channel); if (r) return r; - if (chip->is_zd1211b) { + if (zd_chip_is_zd1211b(chip)) { static const struct zd_ioreq16 ioreqs[] = { - { CR69, 0x28 }, + { ZD_CR69, 0x28 }, {}, - { CR69, 0x2a }, + { ZD_CR69, 0x2a }, }; r = update_ofdm_cal(chip, channel); @@ -1247,7 +1260,7 @@ static int patch_cck_gain(struct zd_chip *chip) int r; u32 value; - if (!chip->patch_cck_gain) + if (!chip->patch_cck_gain || !zd_rf_should_patch_cck_gain(&chip->rf)) return 0; ZD_ASSERT(mutex_is_locked(&chip->mutex)); @@ -1255,7 +1268,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_iowrite16_locked(chip, value & 0xff, CR47); + return zd_iowrite16_locked(chip, value & 0xff, ZD_CR47); } int zd_chip_set_channel(struct zd_chip *chip, u8 channel) @@ -1300,15 +1313,15 @@ u8 zd_chip_get_channel(struct zd_chip *chip) int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) { - static const zd_addr_t a[] = { - FW_LINK_STATUS, + const zd_addr_t a[] = { + fw_reg_addr(chip, FW_REG_LED_LINK_STATUS), CR_LED, }; int r; u16 v[ARRAY_SIZE(a)]; struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = { - [0] = { FW_LINK_STATUS }, + [0] = { fw_reg_addr(chip, FW_REG_LED_LINK_STATUS) }, [1] = { CR_LED }, }; u16 other_led; @@ -1321,11 +1334,11 @@ int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) other_led = chip->link_led == LED1 ? LED2 : LED1; switch (status) { - case LED_OFF: + case ZD_LED_OFF: ioreqs[0].value = FW_LINK_OFF; ioreqs[1].value = v[1] & ~(LED1|LED2); break; - case LED_SCANNING: + case ZD_LED_SCANNING: ioreqs[0].value = FW_LINK_OFF; ioreqs[1].value = v[1] & ~other_led; if (get_seconds() % 3 == 0) { @@ -1334,7 +1347,7 @@ int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) ioreqs[1].value |= chip->link_led; } break; - case LED_ASSOCIATED: + case ZD_LED_ASSOCIATED: ioreqs[0].value = FW_LINK_TX; ioreqs[1].value = v[1] & ~other_led; ioreqs[1].value |= chip->link_led; @@ -1368,191 +1381,44 @@ int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates) return r; } -static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size) +static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame) { - static const u16 constants[] = { - 715, 655, 585, 540, 470, 410, 360, 315, - 270, 235, 205, 175, 150, 125, 105, 85, - 65, 50, 40, 25, 15 - }; - - int i; - u32 x; - - /* It seems that their quality parameter is somehow per signal - * and is now transferred per bit. - */ - switch (rate) { - case ZD_OFDM_RATE_6M: - case ZD_OFDM_RATE_12M: - case ZD_OFDM_RATE_24M: - size *= 2; - break; - case ZD_OFDM_RATE_9M: - case ZD_OFDM_RATE_18M: - case ZD_OFDM_RATE_36M: - case ZD_OFDM_RATE_54M: - size *= 4; - size /= 3; - break; - case ZD_OFDM_RATE_48M: - size *= 3; - size /= 2; - break; - default: - return -EINVAL; - } - - x = (10000 * status_quality)/size; - for (i = 0; i < ARRAY_SIZE(constants); i++) { - if (x > constants[i]) - break; - } - - switch (rate) { - case ZD_OFDM_RATE_6M: - case ZD_OFDM_RATE_9M: - i += 3; - break; - case ZD_OFDM_RATE_12M: - case ZD_OFDM_RATE_18M: - i += 5; - break; - case ZD_OFDM_RATE_24M: - case ZD_OFDM_RATE_36M: - i += 9; - break; - case ZD_OFDM_RATE_48M: - case ZD_OFDM_RATE_54M: - i += 15; - break; - default: - return -EINVAL; - } - - return i; + return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame); } -static int ofdm_qual_percent(u8 status_quality, u8 rate, unsigned int size) -{ - int r; - - r = ofdm_qual_db(status_quality, rate, size); - ZD_ASSERT(r >= 0); - if (r < 0) - r = 0; - - r = (r * 100)/29; - return r <= 100 ? r : 100; -} - -static unsigned int log10times100(unsigned int x) -{ - static const u8 log10[] = { - 0, - 0, 30, 47, 60, 69, 77, 84, 90, 95, 100, - 104, 107, 111, 114, 117, 120, 123, 125, 127, 130, - 132, 134, 136, 138, 139, 141, 143, 144, 146, 147, - 149, 150, 151, 153, 154, 155, 156, 157, 159, 160, - 161, 162, 163, 164, 165, 166, 167, 168, 169, 169, - 170, 171, 172, 173, 174, 174, 175, 176, 177, 177, - 178, 179, 179, 180, 181, 181, 182, 183, 183, 184, - 185, 185, 186, 186, 187, 188, 188, 189, 189, 190, - 190, 191, 191, 192, 192, 193, 193, 194, 194, 195, - 195, 196, 196, 197, 197, 198, 198, 199, 199, 200, - 200, 200, 201, 201, 202, 202, 202, 203, 203, 204, - 204, 204, 205, 205, 206, 206, 206, 207, 207, 207, - 208, 208, 208, 209, 209, 210, 210, 210, 211, 211, - 211, 212, 212, 212, 213, 213, 213, 213, 214, 214, - 214, 215, 215, 215, 216, 216, 216, 217, 217, 217, - 217, 218, 218, 218, 219, 219, 219, 219, 220, 220, - 220, 220, 221, 221, 221, 222, 222, 222, 222, 223, - 223, 223, 223, 224, 224, 224, 224, - }; - - return x < ARRAY_SIZE(log10) ? log10[x] : 225; -} - -enum { - MAX_CCK_EVM_DB = 45, -}; - -static int cck_evm_db(u8 status_quality) -{ - return (20 * log10times100(status_quality)) / 100; -} - -static int cck_snr_db(u8 status_quality) -{ - int r = MAX_CCK_EVM_DB - cck_evm_db(status_quality); - ZD_ASSERT(r >= 0); - return r; -} - -static int cck_qual_percent(u8 status_quality) -{ - int r; - - r = cck_snr_db(status_quality); - r = (100*r)/17; - return r <= 100 ? r : 100; -} - -u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size, - const struct rx_status *status) -{ - return (status->frame_status&ZD_RX_OFDM) ? - ofdm_qual_percent(status->signal_quality_ofdm, - zd_ofdm_plcp_header_rate(rx_frame), - size) : - cck_qual_percent(status->signal_quality_cck); -} - -u8 zd_rx_strength_percent(u8 rssi) -{ - int r = (rssi*100) / 41; - if (r > 100) - r = 100; - return (u8) r; -} - -u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status) +/** + * zd_rx_rate - report zd-rate + * @rx_frame - received frame + * @rx_status - rx_status as given by the device + * + * This function converts the rate as encoded in the received packet to the + * zd-rate, we are using on other places in the driver. + */ +u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status) { - static const u16 ofdm_rates[] = { - [ZD_OFDM_RATE_6M] = 60, - [ZD_OFDM_RATE_9M] = 90, - [ZD_OFDM_RATE_12M] = 120, - [ZD_OFDM_RATE_18M] = 180, - [ZD_OFDM_RATE_24M] = 240, - [ZD_OFDM_RATE_36M] = 360, - [ZD_OFDM_RATE_48M] = 480, - [ZD_OFDM_RATE_54M] = 540, - }; - u16 rate; + u8 zd_rate; if (status->frame_status & ZD_RX_OFDM) { - u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame); - rate = ofdm_rates[ofdm_rate & 0xf]; + zd_rate = zd_rate_from_ofdm_plcp_header(rx_frame); } else { - u8 cck_rate = zd_cck_plcp_header_rate(rx_frame); - switch (cck_rate) { - case ZD_CCK_SIGNAL_1M: - rate = 10; + switch (zd_cck_plcp_header_signal(rx_frame)) { + case ZD_CCK_PLCP_SIGNAL_1M: + zd_rate = ZD_CCK_RATE_1M; break; - case ZD_CCK_SIGNAL_2M: - rate = 20; + case ZD_CCK_PLCP_SIGNAL_2M: + zd_rate = ZD_CCK_RATE_2M; break; - case ZD_CCK_SIGNAL_5M5: - rate = 55; + case ZD_CCK_PLCP_SIGNAL_5M5: + zd_rate = ZD_CCK_RATE_5_5M; break; - case ZD_CCK_SIGNAL_11M: - rate = 110; + case ZD_CCK_PLCP_SIGNAL_11M: + zd_rate = ZD_CCK_RATE_11M; break; default: - rate = 0; + zd_rate = 0; } } - return rate; + return zd_rate; } int zd_chip_switch_radio_on(struct zd_chip *chip) @@ -1590,22 +1456,29 @@ void zd_chip_disable_int(struct zd_chip *chip) mutex_lock(&chip->mutex); zd_usb_disable_int(&chip->usb); mutex_unlock(&chip->mutex); + + /* cancel pending interrupt work */ + cancel_work_sync(&zd_chip_to_mac(chip)->process_intr); } -int zd_chip_enable_rx(struct zd_chip *chip) +int zd_chip_enable_rxtx(struct zd_chip *chip) { int r; mutex_lock(&chip->mutex); + zd_usb_enable_tx(&chip->usb); r = zd_usb_enable_rx(&chip->usb); + zd_tx_watchdog_enable(&chip->usb); mutex_unlock(&chip->mutex); return r; } -void zd_chip_disable_rx(struct zd_chip *chip) +void zd_chip_disable_rxtx(struct zd_chip *chip) { mutex_lock(&chip->mutex); + zd_tx_watchdog_disable(&chip->usb); zd_usb_disable_rx(&chip->usb); + zd_usb_disable_tx(&chip->usb); mutex_unlock(&chip->mutex); } @@ -1630,10 +1503,10 @@ int zd_rfwritev_locked(struct zd_chip *chip, */ int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value) { - struct zd_ioreq16 ioreqs[] = { - { CR244, (value >> 16) & 0xff }, - { CR243, (value >> 8) & 0xff }, - { CR242, value & 0xff }, + const struct zd_ioreq16 ioreqs[] = { + { ZD_CR244, (value >> 16) & 0xff }, + { ZD_CR243, (value >> 8) & 0xff }, + { ZD_CR242, value & 0xff }, }; ZD_ASSERT(mutex_is_locked(&chip->mutex)); return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -1653,3 +1526,35 @@ 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) +{ + const struct zd_ioreq32 ioreqs[] = { + { CR_GROUP_HASH_P1, hash->low }, + { CR_GROUP_HASH_P2, hash->high }, + }; + + return zd_iowrite32a(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} + +u64 zd_chip_get_tsf(struct zd_chip *chip) +{ + int r; + static const zd_addr_t aw_pt_bi_addr[] = + { CR_TSF_LOW_PART, CR_TSF_HIGH_PART }; + u32 values[2]; + u64 tsf; + + mutex_lock(&chip->mutex); + r = zd_ioread32v_locked(chip, values, (const zd_addr_t *)aw_pt_bi_addr, + ARRAY_SIZE(aw_pt_bi_addr)); + mutex_unlock(&chip->mutex); + if (r) + return 0; + + tsf = values[1]; + tsf = (tsf << 32) | values[0]; + + return tsf; +} diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index ae59597ce4e..b03786c9f3a 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -1,4 +1,7 @@ -/* zd_chip.h +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,14 +14,14 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #ifndef _ZD_CHIP_H #define _ZD_CHIP_H -#include "zd_types.h" +#include <net/mac80211.h> + #include "zd_rf.h" #include "zd_usb.h" @@ -27,282 +30,324 @@ * adds a processor for handling the USB protocol. */ +/* Address space */ +enum { + /* CONTROL REGISTERS */ + CR_START = 0x9000, + + + /* FIRMWARE */ + FW_START = 0xee00, + + + /* EEPROM */ + E2P_START = 0xf800, + E2P_LEN = 0x800, + + /* EEPROM layout */ + E2P_LOAD_CODE_LEN = 0xe, /* base 0xf800 */ + E2P_LOAD_VECT_LEN = 0x9, /* base 0xf80e */ + /* E2P_DATA indexes into this */ + E2P_DATA_LEN = 0x7e, /* base 0xf817 */ + E2P_BOOT_CODE_LEN = 0x760, /* base 0xf895 */ + E2P_INTR_VECT_LEN = 0xb, /* base 0xfff5 */ + + /* Some precomputed offsets into the EEPROM */ + E2P_DATA_OFFSET = E2P_LOAD_CODE_LEN + E2P_LOAD_VECT_LEN, + E2P_BOOT_CODE_OFFSET = E2P_DATA_OFFSET + E2P_DATA_LEN, +}; + +#define CTL_REG(offset) ((zd_addr_t)(CR_START + (offset))) +#define E2P_DATA(offset) ((zd_addr_t)(E2P_START + E2P_DATA_OFFSET + (offset))) +#define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset))) + /* 8-bit hardware registers */ -#define CR0 CTL_REG(0x0000) -#define CR1 CTL_REG(0x0004) -#define CR2 CTL_REG(0x0008) -#define CR3 CTL_REG(0x000C) +#define ZD_CR0 CTL_REG(0x0000) +#define ZD_CR1 CTL_REG(0x0004) +#define ZD_CR2 CTL_REG(0x0008) +#define ZD_CR3 CTL_REG(0x000C) -#define CR5 CTL_REG(0x0010) +#define ZD_CR5 CTL_REG(0x0010) /* bit 5: if set short preamble used * bit 6: filter band - Japan channel 14 on, else off */ -#define CR6 CTL_REG(0x0014) -#define CR7 CTL_REG(0x0018) -#define CR8 CTL_REG(0x001C) +#define ZD_CR6 CTL_REG(0x0014) +#define ZD_CR7 CTL_REG(0x0018) +#define ZD_CR8 CTL_REG(0x001C) -#define CR4 CTL_REG(0x0020) +#define ZD_CR4 CTL_REG(0x0020) -#define CR9 CTL_REG(0x0024) -/* bit 2: antenna switch (together with CR10) */ -#define CR10 CTL_REG(0x0028) -/* bit 1: antenna switch (together with CR9) - * RF2959 controls with CR11 radion on and off +#define ZD_CR9 CTL_REG(0x0024) +/* bit 2: antenna switch (together with ZD_CR10) */ +#define ZD_CR10 CTL_REG(0x0028) +/* bit 1: antenna switch (together with ZD_CR9) + * RF2959 controls with ZD_CR11 radion on and off */ -#define CR11 CTL_REG(0x002C) +#define ZD_CR11 CTL_REG(0x002C) /* bit 6: TX power control for OFDM - * RF2959 controls with CR10 radio on and off + * RF2959 controls with ZD_CR10 radio on and off */ -#define CR12 CTL_REG(0x0030) -#define CR13 CTL_REG(0x0034) -#define CR14 CTL_REG(0x0038) -#define CR15 CTL_REG(0x003C) -#define CR16 CTL_REG(0x0040) -#define CR17 CTL_REG(0x0044) -#define CR18 CTL_REG(0x0048) -#define CR19 CTL_REG(0x004C) -#define CR20 CTL_REG(0x0050) -#define CR21 CTL_REG(0x0054) -#define CR22 CTL_REG(0x0058) -#define CR23 CTL_REG(0x005C) -#define CR24 CTL_REG(0x0060) /* CCA threshold */ -#define CR25 CTL_REG(0x0064) -#define CR26 CTL_REG(0x0068) -#define CR27 CTL_REG(0x006C) -#define CR28 CTL_REG(0x0070) -#define CR29 CTL_REG(0x0074) -#define CR30 CTL_REG(0x0078) -#define CR31 CTL_REG(0x007C) /* TX power control for RF in CCK mode */ -#define CR32 CTL_REG(0x0080) -#define CR33 CTL_REG(0x0084) -#define CR34 CTL_REG(0x0088) -#define CR35 CTL_REG(0x008C) -#define CR36 CTL_REG(0x0090) -#define CR37 CTL_REG(0x0094) -#define CR38 CTL_REG(0x0098) -#define CR39 CTL_REG(0x009C) -#define CR40 CTL_REG(0x00A0) -#define CR41 CTL_REG(0x00A4) -#define CR42 CTL_REG(0x00A8) -#define CR43 CTL_REG(0x00AC) -#define CR44 CTL_REG(0x00B0) -#define CR45 CTL_REG(0x00B4) -#define CR46 CTL_REG(0x00B8) -#define CR47 CTL_REG(0x00BC) /* CCK baseband gain - * (patch value might be in EEPROM) - */ -#define CR48 CTL_REG(0x00C0) -#define CR49 CTL_REG(0x00C4) -#define CR50 CTL_REG(0x00C8) -#define CR51 CTL_REG(0x00CC) /* TX power control for RF in 6-36M modes */ -#define CR52 CTL_REG(0x00D0) /* TX power control for RF in 48M mode */ -#define CR53 CTL_REG(0x00D4) /* TX power control for RF in 54M mode */ -#define CR54 CTL_REG(0x00D8) -#define CR55 CTL_REG(0x00DC) -#define CR56 CTL_REG(0x00E0) -#define CR57 CTL_REG(0x00E4) -#define CR58 CTL_REG(0x00E8) -#define CR59 CTL_REG(0x00EC) -#define CR60 CTL_REG(0x00F0) -#define CR61 CTL_REG(0x00F4) -#define CR62 CTL_REG(0x00F8) -#define CR63 CTL_REG(0x00FC) -#define CR64 CTL_REG(0x0100) -#define CR65 CTL_REG(0x0104) /* OFDM 54M calibration */ -#define CR66 CTL_REG(0x0108) /* OFDM 48M calibration */ -#define CR67 CTL_REG(0x010C) /* OFDM 36M calibration */ -#define CR68 CTL_REG(0x0110) /* CCK calibration */ -#define CR69 CTL_REG(0x0114) -#define CR70 CTL_REG(0x0118) -#define CR71 CTL_REG(0x011C) -#define CR72 CTL_REG(0x0120) -#define CR73 CTL_REG(0x0124) -#define CR74 CTL_REG(0x0128) -#define CR75 CTL_REG(0x012C) -#define CR76 CTL_REG(0x0130) -#define CR77 CTL_REG(0x0134) -#define CR78 CTL_REG(0x0138) -#define CR79 CTL_REG(0x013C) -#define CR80 CTL_REG(0x0140) -#define CR81 CTL_REG(0x0144) -#define CR82 CTL_REG(0x0148) -#define CR83 CTL_REG(0x014C) -#define CR84 CTL_REG(0x0150) -#define CR85 CTL_REG(0x0154) -#define CR86 CTL_REG(0x0158) -#define CR87 CTL_REG(0x015C) -#define CR88 CTL_REG(0x0160) -#define CR89 CTL_REG(0x0164) -#define CR90 CTL_REG(0x0168) -#define CR91 CTL_REG(0x016C) -#define CR92 CTL_REG(0x0170) -#define CR93 CTL_REG(0x0174) -#define CR94 CTL_REG(0x0178) -#define CR95 CTL_REG(0x017C) -#define CR96 CTL_REG(0x0180) -#define CR97 CTL_REG(0x0184) -#define CR98 CTL_REG(0x0188) -#define CR99 CTL_REG(0x018C) -#define CR100 CTL_REG(0x0190) -#define CR101 CTL_REG(0x0194) -#define CR102 CTL_REG(0x0198) -#define CR103 CTL_REG(0x019C) -#define CR104 CTL_REG(0x01A0) -#define CR105 CTL_REG(0x01A4) -#define CR106 CTL_REG(0x01A8) -#define CR107 CTL_REG(0x01AC) -#define CR108 CTL_REG(0x01B0) -#define CR109 CTL_REG(0x01B4) -#define CR110 CTL_REG(0x01B8) -#define CR111 CTL_REG(0x01BC) -#define CR112 CTL_REG(0x01C0) -#define CR113 CTL_REG(0x01C4) -#define CR114 CTL_REG(0x01C8) -#define CR115 CTL_REG(0x01CC) -#define CR116 CTL_REG(0x01D0) -#define CR117 CTL_REG(0x01D4) -#define CR118 CTL_REG(0x01D8) -#define CR119 CTL_REG(0x01DC) -#define CR120 CTL_REG(0x01E0) -#define CR121 CTL_REG(0x01E4) -#define CR122 CTL_REG(0x01E8) -#define CR123 CTL_REG(0x01EC) -#define CR124 CTL_REG(0x01F0) -#define CR125 CTL_REG(0x01F4) -#define CR126 CTL_REG(0x01F8) -#define CR127 CTL_REG(0x01FC) -#define CR128 CTL_REG(0x0200) -#define CR129 CTL_REG(0x0204) -#define CR130 CTL_REG(0x0208) -#define CR131 CTL_REG(0x020C) -#define CR132 CTL_REG(0x0210) -#define CR133 CTL_REG(0x0214) -#define CR134 CTL_REG(0x0218) -#define CR135 CTL_REG(0x021C) -#define CR136 CTL_REG(0x0220) -#define CR137 CTL_REG(0x0224) -#define CR138 CTL_REG(0x0228) -#define CR139 CTL_REG(0x022C) -#define CR140 CTL_REG(0x0230) -#define CR141 CTL_REG(0x0234) -#define CR142 CTL_REG(0x0238) -#define CR143 CTL_REG(0x023C) -#define CR144 CTL_REG(0x0240) -#define CR145 CTL_REG(0x0244) -#define CR146 CTL_REG(0x0248) -#define CR147 CTL_REG(0x024C) -#define CR148 CTL_REG(0x0250) -#define CR149 CTL_REG(0x0254) -#define CR150 CTL_REG(0x0258) -#define CR151 CTL_REG(0x025C) -#define CR152 CTL_REG(0x0260) -#define CR153 CTL_REG(0x0264) -#define CR154 CTL_REG(0x0268) -#define CR155 CTL_REG(0x026C) -#define CR156 CTL_REG(0x0270) -#define CR157 CTL_REG(0x0274) -#define CR158 CTL_REG(0x0278) -#define CR159 CTL_REG(0x027C) -#define CR160 CTL_REG(0x0280) -#define CR161 CTL_REG(0x0284) -#define CR162 CTL_REG(0x0288) -#define CR163 CTL_REG(0x028C) -#define CR164 CTL_REG(0x0290) -#define CR165 CTL_REG(0x0294) -#define CR166 CTL_REG(0x0298) -#define CR167 CTL_REG(0x029C) -#define CR168 CTL_REG(0x02A0) -#define CR169 CTL_REG(0x02A4) -#define CR170 CTL_REG(0x02A8) -#define CR171 CTL_REG(0x02AC) -#define CR172 CTL_REG(0x02B0) -#define CR173 CTL_REG(0x02B4) -#define CR174 CTL_REG(0x02B8) -#define CR175 CTL_REG(0x02BC) -#define CR176 CTL_REG(0x02C0) -#define CR177 CTL_REG(0x02C4) -#define CR178 CTL_REG(0x02C8) -#define CR179 CTL_REG(0x02CC) -#define CR180 CTL_REG(0x02D0) -#define CR181 CTL_REG(0x02D4) -#define CR182 CTL_REG(0x02D8) -#define CR183 CTL_REG(0x02DC) -#define CR184 CTL_REG(0x02E0) -#define CR185 CTL_REG(0x02E4) -#define CR186 CTL_REG(0x02E8) -#define CR187 CTL_REG(0x02EC) -#define CR188 CTL_REG(0x02F0) -#define CR189 CTL_REG(0x02F4) -#define CR190 CTL_REG(0x02F8) -#define CR191 CTL_REG(0x02FC) -#define CR192 CTL_REG(0x0300) -#define CR193 CTL_REG(0x0304) -#define CR194 CTL_REG(0x0308) -#define CR195 CTL_REG(0x030C) -#define CR196 CTL_REG(0x0310) -#define CR197 CTL_REG(0x0314) -#define CR198 CTL_REG(0x0318) -#define CR199 CTL_REG(0x031C) -#define CR200 CTL_REG(0x0320) -#define CR201 CTL_REG(0x0324) -#define CR202 CTL_REG(0x0328) -#define CR203 CTL_REG(0x032C) /* I2C bus template value & flash control */ -#define CR204 CTL_REG(0x0330) -#define CR205 CTL_REG(0x0334) -#define CR206 CTL_REG(0x0338) -#define CR207 CTL_REG(0x033C) -#define CR208 CTL_REG(0x0340) -#define CR209 CTL_REG(0x0344) -#define CR210 CTL_REG(0x0348) -#define CR211 CTL_REG(0x034C) -#define CR212 CTL_REG(0x0350) -#define CR213 CTL_REG(0x0354) -#define CR214 CTL_REG(0x0358) -#define CR215 CTL_REG(0x035C) -#define CR216 CTL_REG(0x0360) -#define CR217 CTL_REG(0x0364) -#define CR218 CTL_REG(0x0368) -#define CR219 CTL_REG(0x036C) -#define CR220 CTL_REG(0x0370) -#define CR221 CTL_REG(0x0374) -#define CR222 CTL_REG(0x0378) -#define CR223 CTL_REG(0x037C) -#define CR224 CTL_REG(0x0380) -#define CR225 CTL_REG(0x0384) -#define CR226 CTL_REG(0x0388) -#define CR227 CTL_REG(0x038C) -#define CR228 CTL_REG(0x0390) -#define CR229 CTL_REG(0x0394) -#define CR230 CTL_REG(0x0398) -#define CR231 CTL_REG(0x039C) -#define CR232 CTL_REG(0x03A0) -#define CR233 CTL_REG(0x03A4) -#define CR234 CTL_REG(0x03A8) -#define CR235 CTL_REG(0x03AC) -#define CR236 CTL_REG(0x03B0) - -#define CR240 CTL_REG(0x03C0) -/* bit 7: host-controlled RF register writes - * CR241-CR245: for hardware controlled writing of RF bits, not needed for - * USB +#define ZD_CR12 CTL_REG(0x0030) +#define ZD_CR13 CTL_REG(0x0034) +#define ZD_CR14 CTL_REG(0x0038) +#define ZD_CR15 CTL_REG(0x003C) +#define ZD_CR16 CTL_REG(0x0040) +#define ZD_CR17 CTL_REG(0x0044) +#define ZD_CR18 CTL_REG(0x0048) +#define ZD_CR19 CTL_REG(0x004C) +#define ZD_CR20 CTL_REG(0x0050) +#define ZD_CR21 CTL_REG(0x0054) +#define ZD_CR22 CTL_REG(0x0058) +#define ZD_CR23 CTL_REG(0x005C) +#define ZD_CR24 CTL_REG(0x0060) /* CCA threshold */ +#define ZD_CR25 CTL_REG(0x0064) +#define ZD_CR26 CTL_REG(0x0068) +#define ZD_CR27 CTL_REG(0x006C) +#define ZD_CR28 CTL_REG(0x0070) +#define ZD_CR29 CTL_REG(0x0074) +#define ZD_CR30 CTL_REG(0x0078) +#define ZD_CR31 CTL_REG(0x007C) /* TX power control for RF in + * CCK mode + */ +#define ZD_CR32 CTL_REG(0x0080) +#define ZD_CR33 CTL_REG(0x0084) +#define ZD_CR34 CTL_REG(0x0088) +#define ZD_CR35 CTL_REG(0x008C) +#define ZD_CR36 CTL_REG(0x0090) +#define ZD_CR37 CTL_REG(0x0094) +#define ZD_CR38 CTL_REG(0x0098) +#define ZD_CR39 CTL_REG(0x009C) +#define ZD_CR40 CTL_REG(0x00A0) +#define ZD_CR41 CTL_REG(0x00A4) +#define ZD_CR42 CTL_REG(0x00A8) +#define ZD_CR43 CTL_REG(0x00AC) +#define ZD_CR44 CTL_REG(0x00B0) +#define ZD_CR45 CTL_REG(0x00B4) +#define ZD_CR46 CTL_REG(0x00B8) +#define ZD_CR47 CTL_REG(0x00BC) /* CCK baseband gain + * (patch value might be in EEPROM) + */ +#define ZD_CR48 CTL_REG(0x00C0) +#define ZD_CR49 CTL_REG(0x00C4) +#define ZD_CR50 CTL_REG(0x00C8) +#define ZD_CR51 CTL_REG(0x00CC) /* TX power control for RF in + * 6-36M modes + */ +#define ZD_CR52 CTL_REG(0x00D0) /* TX power control for RF in + * 48M mode + */ +#define ZD_CR53 CTL_REG(0x00D4) /* TX power control for RF in + * 54M mode + */ +#define ZD_CR54 CTL_REG(0x00D8) +#define ZD_CR55 CTL_REG(0x00DC) +#define ZD_CR56 CTL_REG(0x00E0) +#define ZD_CR57 CTL_REG(0x00E4) +#define ZD_CR58 CTL_REG(0x00E8) +#define ZD_CR59 CTL_REG(0x00EC) +#define ZD_CR60 CTL_REG(0x00F0) +#define ZD_CR61 CTL_REG(0x00F4) +#define ZD_CR62 CTL_REG(0x00F8) +#define ZD_CR63 CTL_REG(0x00FC) +#define ZD_CR64 CTL_REG(0x0100) +#define ZD_CR65 CTL_REG(0x0104) /* OFDM 54M calibration */ +#define ZD_CR66 CTL_REG(0x0108) /* OFDM 48M calibration */ +#define ZD_CR67 CTL_REG(0x010C) /* OFDM 36M calibration */ +#define ZD_CR68 CTL_REG(0x0110) /* CCK calibration */ +#define ZD_CR69 CTL_REG(0x0114) +#define ZD_CR70 CTL_REG(0x0118) +#define ZD_CR71 CTL_REG(0x011C) +#define ZD_CR72 CTL_REG(0x0120) +#define ZD_CR73 CTL_REG(0x0124) +#define ZD_CR74 CTL_REG(0x0128) +#define ZD_CR75 CTL_REG(0x012C) +#define ZD_CR76 CTL_REG(0x0130) +#define ZD_CR77 CTL_REG(0x0134) +#define ZD_CR78 CTL_REG(0x0138) +#define ZD_CR79 CTL_REG(0x013C) +#define ZD_CR80 CTL_REG(0x0140) +#define ZD_CR81 CTL_REG(0x0144) +#define ZD_CR82 CTL_REG(0x0148) +#define ZD_CR83 CTL_REG(0x014C) +#define ZD_CR84 CTL_REG(0x0150) +#define ZD_CR85 CTL_REG(0x0154) +#define ZD_CR86 CTL_REG(0x0158) +#define ZD_CR87 CTL_REG(0x015C) +#define ZD_CR88 CTL_REG(0x0160) +#define ZD_CR89 CTL_REG(0x0164) +#define ZD_CR90 CTL_REG(0x0168) +#define ZD_CR91 CTL_REG(0x016C) +#define ZD_CR92 CTL_REG(0x0170) +#define ZD_CR93 CTL_REG(0x0174) +#define ZD_CR94 CTL_REG(0x0178) +#define ZD_CR95 CTL_REG(0x017C) +#define ZD_CR96 CTL_REG(0x0180) +#define ZD_CR97 CTL_REG(0x0184) +#define ZD_CR98 CTL_REG(0x0188) +#define ZD_CR99 CTL_REG(0x018C) +#define ZD_CR100 CTL_REG(0x0190) +#define ZD_CR101 CTL_REG(0x0194) +#define ZD_CR102 CTL_REG(0x0198) +#define ZD_CR103 CTL_REG(0x019C) +#define ZD_CR104 CTL_REG(0x01A0) +#define ZD_CR105 CTL_REG(0x01A4) +#define ZD_CR106 CTL_REG(0x01A8) +#define ZD_CR107 CTL_REG(0x01AC) +#define ZD_CR108 CTL_REG(0x01B0) +#define ZD_CR109 CTL_REG(0x01B4) +#define ZD_CR110 CTL_REG(0x01B8) +#define ZD_CR111 CTL_REG(0x01BC) +#define ZD_CR112 CTL_REG(0x01C0) +#define ZD_CR113 CTL_REG(0x01C4) +#define ZD_CR114 CTL_REG(0x01C8) +#define ZD_CR115 CTL_REG(0x01CC) +#define ZD_CR116 CTL_REG(0x01D0) +#define ZD_CR117 CTL_REG(0x01D4) +#define ZD_CR118 CTL_REG(0x01D8) +#define ZD_CR119 CTL_REG(0x01DC) +#define ZD_CR120 CTL_REG(0x01E0) +#define ZD_CR121 CTL_REG(0x01E4) +#define ZD_CR122 CTL_REG(0x01E8) +#define ZD_CR123 CTL_REG(0x01EC) +#define ZD_CR124 CTL_REG(0x01F0) +#define ZD_CR125 CTL_REG(0x01F4) +#define ZD_CR126 CTL_REG(0x01F8) +#define ZD_CR127 CTL_REG(0x01FC) +#define ZD_CR128 CTL_REG(0x0200) +#define ZD_CR129 CTL_REG(0x0204) +#define ZD_CR130 CTL_REG(0x0208) +#define ZD_CR131 CTL_REG(0x020C) +#define ZD_CR132 CTL_REG(0x0210) +#define ZD_CR133 CTL_REG(0x0214) +#define ZD_CR134 CTL_REG(0x0218) +#define ZD_CR135 CTL_REG(0x021C) +#define ZD_CR136 CTL_REG(0x0220) +#define ZD_CR137 CTL_REG(0x0224) +#define ZD_CR138 CTL_REG(0x0228) +#define ZD_CR139 CTL_REG(0x022C) +#define ZD_CR140 CTL_REG(0x0230) +#define ZD_CR141 CTL_REG(0x0234) +#define ZD_CR142 CTL_REG(0x0238) +#define ZD_CR143 CTL_REG(0x023C) +#define ZD_CR144 CTL_REG(0x0240) +#define ZD_CR145 CTL_REG(0x0244) +#define ZD_CR146 CTL_REG(0x0248) +#define ZD_CR147 CTL_REG(0x024C) +#define ZD_CR148 CTL_REG(0x0250) +#define ZD_CR149 CTL_REG(0x0254) +#define ZD_CR150 CTL_REG(0x0258) +#define ZD_CR151 CTL_REG(0x025C) +#define ZD_CR152 CTL_REG(0x0260) +#define ZD_CR153 CTL_REG(0x0264) +#define ZD_CR154 CTL_REG(0x0268) +#define ZD_CR155 CTL_REG(0x026C) +#define ZD_CR156 CTL_REG(0x0270) +#define ZD_CR157 CTL_REG(0x0274) +#define ZD_CR158 CTL_REG(0x0278) +#define ZD_CR159 CTL_REG(0x027C) +#define ZD_CR160 CTL_REG(0x0280) +#define ZD_CR161 CTL_REG(0x0284) +#define ZD_CR162 CTL_REG(0x0288) +#define ZD_CR163 CTL_REG(0x028C) +#define ZD_CR164 CTL_REG(0x0290) +#define ZD_CR165 CTL_REG(0x0294) +#define ZD_CR166 CTL_REG(0x0298) +#define ZD_CR167 CTL_REG(0x029C) +#define ZD_CR168 CTL_REG(0x02A0) +#define ZD_CR169 CTL_REG(0x02A4) +#define ZD_CR170 CTL_REG(0x02A8) +#define ZD_CR171 CTL_REG(0x02AC) +#define ZD_CR172 CTL_REG(0x02B0) +#define ZD_CR173 CTL_REG(0x02B4) +#define ZD_CR174 CTL_REG(0x02B8) +#define ZD_CR175 CTL_REG(0x02BC) +#define ZD_CR176 CTL_REG(0x02C0) +#define ZD_CR177 CTL_REG(0x02C4) +#define ZD_CR178 CTL_REG(0x02C8) +#define ZD_CR179 CTL_REG(0x02CC) +#define ZD_CR180 CTL_REG(0x02D0) +#define ZD_CR181 CTL_REG(0x02D4) +#define ZD_CR182 CTL_REG(0x02D8) +#define ZD_CR183 CTL_REG(0x02DC) +#define ZD_CR184 CTL_REG(0x02E0) +#define ZD_CR185 CTL_REG(0x02E4) +#define ZD_CR186 CTL_REG(0x02E8) +#define ZD_CR187 CTL_REG(0x02EC) +#define ZD_CR188 CTL_REG(0x02F0) +#define ZD_CR189 CTL_REG(0x02F4) +#define ZD_CR190 CTL_REG(0x02F8) +#define ZD_CR191 CTL_REG(0x02FC) +#define ZD_CR192 CTL_REG(0x0300) +#define ZD_CR193 CTL_REG(0x0304) +#define ZD_CR194 CTL_REG(0x0308) +#define ZD_CR195 CTL_REG(0x030C) +#define ZD_CR196 CTL_REG(0x0310) +#define ZD_CR197 CTL_REG(0x0314) +#define ZD_CR198 CTL_REG(0x0318) +#define ZD_CR199 CTL_REG(0x031C) +#define ZD_CR200 CTL_REG(0x0320) +#define ZD_CR201 CTL_REG(0x0324) +#define ZD_CR202 CTL_REG(0x0328) +#define ZD_CR203 CTL_REG(0x032C) /* I2C bus template value & flash + * control + */ +#define ZD_CR204 CTL_REG(0x0330) +#define ZD_CR205 CTL_REG(0x0334) +#define ZD_CR206 CTL_REG(0x0338) +#define ZD_CR207 CTL_REG(0x033C) +#define ZD_CR208 CTL_REG(0x0340) +#define ZD_CR209 CTL_REG(0x0344) +#define ZD_CR210 CTL_REG(0x0348) +#define ZD_CR211 CTL_REG(0x034C) +#define ZD_CR212 CTL_REG(0x0350) +#define ZD_CR213 CTL_REG(0x0354) +#define ZD_CR214 CTL_REG(0x0358) +#define ZD_CR215 CTL_REG(0x035C) +#define ZD_CR216 CTL_REG(0x0360) +#define ZD_CR217 CTL_REG(0x0364) +#define ZD_CR218 CTL_REG(0x0368) +#define ZD_CR219 CTL_REG(0x036C) +#define ZD_CR220 CTL_REG(0x0370) +#define ZD_CR221 CTL_REG(0x0374) +#define ZD_CR222 CTL_REG(0x0378) +#define ZD_CR223 CTL_REG(0x037C) +#define ZD_CR224 CTL_REG(0x0380) +#define ZD_CR225 CTL_REG(0x0384) +#define ZD_CR226 CTL_REG(0x0388) +#define ZD_CR227 CTL_REG(0x038C) +#define ZD_CR228 CTL_REG(0x0390) +#define ZD_CR229 CTL_REG(0x0394) +#define ZD_CR230 CTL_REG(0x0398) +#define ZD_CR231 CTL_REG(0x039C) +#define ZD_CR232 CTL_REG(0x03A0) +#define ZD_CR233 CTL_REG(0x03A4) +#define ZD_CR234 CTL_REG(0x03A8) +#define ZD_CR235 CTL_REG(0x03AC) +#define ZD_CR236 CTL_REG(0x03B0) + +#define ZD_CR240 CTL_REG(0x03C0) +/* bit 7: host-controlled RF register writes + * ZD_CR241-ZD_CR245: for hardware controlled writing of RF bits, not needed for + * USB */ -#define CR241 CTL_REG(0x03C4) -#define CR242 CTL_REG(0x03C8) -#define CR243 CTL_REG(0x03CC) -#define CR244 CTL_REG(0x03D0) -#define CR245 CTL_REG(0x03D4) - -#define CR251 CTL_REG(0x03EC) /* only used for activation and deactivation of - * Airoha RFs AL2230 and AL7230B - */ -#define CR252 CTL_REG(0x03F0) -#define CR253 CTL_REG(0x03F4) -#define CR254 CTL_REG(0x03F8) -#define CR255 CTL_REG(0x03FC) +#define ZD_CR241 CTL_REG(0x03C4) +#define ZD_CR242 CTL_REG(0x03C8) +#define ZD_CR243 CTL_REG(0x03CC) +#define ZD_CR244 CTL_REG(0x03D0) +#define ZD_CR245 CTL_REG(0x03D4) + +#define ZD_CR251 CTL_REG(0x03EC) /* only used for activation and + * deactivation of Airoha RFs AL2230 + * and AL7230B + */ +#define ZD_CR252 CTL_REG(0x03F0) +#define ZD_CR253 CTL_REG(0x03F4) +#define ZD_CR254 CTL_REG(0x03F8) +#define ZD_CR255 CTL_REG(0x03FC) #define CR_MAX_PHY_REG 255 -/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211 +/* Taken from the ZYDAS driver, not all of them are relevant for the ZD1211 * driver. */ @@ -337,24 +382,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 +435,36 @@ #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) /* 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 */ + * 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,15 +475,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 LED_SW 0x0400 +#define LED1 (1 << 8) +#define LED2 (1 << 9) +#define LED_SW (1 << 10) /* Seems to indicate that the configuration is over. */ @@ -437,6 +501,7 @@ #define CR_RX_OFFSET CTL_REG(0x065c) +#define CR_BCN_LENGTH CTL_REG(0x0664) #define CR_PHY_DELAY CTL_REG(0x066C) #define CR_BCN_FIFO CTL_REG(0x0670) #define CR_SNIFFER_ON CTL_REG(0x0674) @@ -455,20 +520,46 @@ * 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 AP_RX_FILTER 0x0400feff -#define STA_RX_FILTER 0x0000ffff +#define RX_FILTER_ASSOC_REQUEST (1 << 0) +#define RX_FILTER_ASSOC_RESPONSE (1 << 1) +#define RX_FILTER_REASSOC_REQUEST (1 << 2) +#define RX_FILTER_REASSOC_RESPONSE (1 << 3) +#define RX_FILTER_PROBE_REQUEST (1 << 4) +#define RX_FILTER_PROBE_RESPONSE (1 << 5) +/* bits 6 and 7 reserved */ +#define RX_FILTER_BEACON (1 << 8) +#define RX_FILTER_ATIM (1 << 9) +#define RX_FILTER_DISASSOC (1 << 10) +#define RX_FILTER_AUTH (1 << 11) +#define RX_FILTER_DEAUTH (1 << 12) +#define RX_FILTER_PSPOLL (1 << 26) +#define RX_FILTER_RTS (1 << 27) +#define RX_FILTER_CTS (1 << 28) +#define RX_FILTER_ACK (1 << 29) +#define RX_FILTER_CFEND (1 << 30) +#define RX_FILTER_CFACK (1 << 31) + +/* Enable bits for all frames you are interested in. */ +#define STA_RX_FILTER (RX_FILTER_ASSOC_REQUEST | RX_FILTER_ASSOC_RESPONSE | \ + RX_FILTER_REASSOC_REQUEST | RX_FILTER_REASSOC_RESPONSE | \ + RX_FILTER_PROBE_REQUEST | RX_FILTER_PROBE_RESPONSE | \ + (0x3 << 6) /* vendor driver sets these reserved bits */ | \ + RX_FILTER_BEACON | RX_FILTER_ATIM | RX_FILTER_DISASSOC | \ + RX_FILTER_AUTH | RX_FILTER_DEAUTH | \ + (0x7 << 13) /* vendor driver sets these reserved bits */ | \ + RX_FILTER_PSPOLL | RX_FILTER_ACK) /* 0x2400ffff */ + +#define RX_FILTER_CTRL (RX_FILTER_RTS | RX_FILTER_CTS | \ + RX_FILTER_CFEND | RX_FILTER_CFACK) + +#define BCN_MODE_AP 0x1000000 +#define BCN_MODE_IBSS 0x2000000 /* Monitor mode sets filter to 0xfffff */ @@ -503,6 +594,11 @@ /* CAM: Continuous Access Mode (power management) */ #define CR_CAM_MODE CTL_REG(0x0700) +#define MODE_IBSS 0x0 +#define MODE_AP 0x1 +#define MODE_STA 0x2 +#define MODE_AP_WDS 0x3 + #define CR_CAM_ROLL_TB_LOW CTL_REG(0x0704) #define CR_CAM_ROLL_TB_HIGH CTL_REG(0x0708) #define CR_CAM_ADDRESS CTL_REG(0x070C) @@ -550,20 +646,38 @@ #define CR_S_MD CTL_REG(0x0830) #define CR_USB_DEBUG_PORT CTL_REG(0x0888) - -#define CR_ZD1211B_TX_PWR_CTL1 CTL_REG(0x0b00) -#define CR_ZD1211B_TX_PWR_CTL2 CTL_REG(0x0b04) -#define CR_ZD1211B_TX_PWR_CTL3 CTL_REG(0x0b08) -#define CR_ZD1211B_TX_PWR_CTL4 CTL_REG(0x0b0c) +#define CR_ZD1211B_CWIN_MAX_MIN_AC0 CTL_REG(0x0b00) +#define CR_ZD1211B_CWIN_MAX_MIN_AC1 CTL_REG(0x0b04) +#define CR_ZD1211B_CWIN_MAX_MIN_AC2 CTL_REG(0x0b08) +#define CR_ZD1211B_CWIN_MAX_MIN_AC3 CTL_REG(0x0b0c) #define CR_ZD1211B_AIFS_CTL1 CTL_REG(0x0b10) #define CR_ZD1211B_AIFS_CTL2 CTL_REG(0x0b14) #define CR_ZD1211B_TXOP CTL_REG(0x0b20) #define CR_ZD1211B_RETRY_MAX CTL_REG(0x0b28) +/* Value for CR_ZD1211_RETRY_MAX & CR_ZD1211B_RETRY_MAX. Vendor driver uses 2, + * we use 0. The first rate is tried (count+2), then all next rates are tried + * twice, until 1 Mbits is tried. */ +#define ZD1211_RETRY_COUNT 0 +#define ZD1211B_RETRY_COUNT \ + (ZD1211_RETRY_COUNT << 0)| \ + (ZD1211_RETRY_COUNT << 8)| \ + (ZD1211_RETRY_COUNT << 16)| \ + (ZD1211_RETRY_COUNT << 24) + +/* Used to detect PLL lock */ +#define UW2453_INTR_REG ((zd_addr_t)0x85c1) + #define CWIN_SIZE 0x007f043f -#define HWINT_ENABLED 0x004f0000 +#define HWINT_ENABLED \ + (INT_TX_COMPLETE_EN| \ + INT_RX_COMPLETE_EN| \ + INT_RETRY_FAIL_EN| \ + INT_WAKEUP_EN| \ + INT_CFG_NEXT_BCN_EN) + #define HWINT_DISABLED 0 #define E2P_PWR_INT_GUARD 8 @@ -576,81 +690,71 @@ /* * Upper 16 bit contains the regulatory domain. */ -#define E2P_SUBID E2P_REG(0x00) -#define E2P_POD E2P_REG(0x02) -#define E2P_MAC_ADDR_P1 E2P_REG(0x04) -#define E2P_MAC_ADDR_P2 E2P_REG(0x06) -#define E2P_PWR_CAL_VALUE1 E2P_REG(0x08) -#define E2P_PWR_CAL_VALUE2 E2P_REG(0x0a) -#define E2P_PWR_CAL_VALUE3 E2P_REG(0x0c) -#define E2P_PWR_CAL_VALUE4 E2P_REG(0x0e) -#define E2P_PWR_INT_VALUE1 E2P_REG(0x10) -#define E2P_PWR_INT_VALUE2 E2P_REG(0x12) -#define E2P_PWR_INT_VALUE3 E2P_REG(0x14) -#define E2P_PWR_INT_VALUE4 E2P_REG(0x16) +#define E2P_SUBID E2P_DATA(0x00) +#define E2P_POD E2P_DATA(0x02) +#define E2P_MAC_ADDR_P1 E2P_DATA(0x04) +#define E2P_MAC_ADDR_P2 E2P_DATA(0x06) +#define E2P_PWR_CAL_VALUE1 E2P_DATA(0x08) +#define E2P_PWR_CAL_VALUE2 E2P_DATA(0x0a) +#define E2P_PWR_CAL_VALUE3 E2P_DATA(0x0c) +#define E2P_PWR_CAL_VALUE4 E2P_DATA(0x0e) +#define E2P_PWR_INT_VALUE1 E2P_DATA(0x10) +#define E2P_PWR_INT_VALUE2 E2P_DATA(0x12) +#define E2P_PWR_INT_VALUE3 E2P_DATA(0x14) +#define E2P_PWR_INT_VALUE4 E2P_DATA(0x16) /* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30) * also only 11 channels. */ -#define E2P_ALLOWED_CHANNEL E2P_REG(0x18) - -#define E2P_PHY_REG E2P_REG(0x1a) -#define E2P_DEVICE_VER E2P_REG(0x20) -#define E2P_36M_CAL_VALUE1 E2P_REG(0x28) -#define E2P_36M_CAL_VALUE2 E2P_REG(0x2a) -#define E2P_36M_CAL_VALUE3 E2P_REG(0x2c) -#define E2P_36M_CAL_VALUE4 E2P_REG(0x2e) -#define E2P_11A_INT_VALUE1 E2P_REG(0x30) -#define E2P_11A_INT_VALUE2 E2P_REG(0x32) -#define E2P_11A_INT_VALUE3 E2P_REG(0x34) -#define E2P_11A_INT_VALUE4 E2P_REG(0x36) -#define E2P_48M_CAL_VALUE1 E2P_REG(0x38) -#define E2P_48M_CAL_VALUE2 E2P_REG(0x3a) -#define E2P_48M_CAL_VALUE3 E2P_REG(0x3c) -#define E2P_48M_CAL_VALUE4 E2P_REG(0x3e) -#define E2P_48M_INT_VALUE1 E2P_REG(0x40) -#define E2P_48M_INT_VALUE2 E2P_REG(0x42) -#define E2P_48M_INT_VALUE3 E2P_REG(0x44) -#define E2P_48M_INT_VALUE4 E2P_REG(0x46) -#define E2P_54M_CAL_VALUE1 E2P_REG(0x48) /* ??? */ -#define E2P_54M_CAL_VALUE2 E2P_REG(0x4a) -#define E2P_54M_CAL_VALUE3 E2P_REG(0x4c) -#define E2P_54M_CAL_VALUE4 E2P_REG(0x4e) -#define E2P_54M_INT_VALUE1 E2P_REG(0x50) -#define E2P_54M_INT_VALUE2 E2P_REG(0x52) -#define E2P_54M_INT_VALUE3 E2P_REG(0x54) -#define E2P_54M_INT_VALUE4 E2P_REG(0x56) - -/* All 16 bit values */ -#define FW_FIRMWARE_VER FW_REG(0) -/* non-zero if USB high speed connection */ -#define FW_USB_SPEED FW_REG(1) -#define FW_FIX_TX_RATE FW_REG(2) -/* Seems to be able to control LEDs over the firmware */ -#define FW_LINK_STATUS FW_REG(3) -#define FW_SOFT_RESET FW_REG(4) -#define FW_FLASH_CHK FW_REG(5) +#define E2P_ALLOWED_CHANNEL E2P_DATA(0x18) + +#define E2P_DEVICE_VER E2P_DATA(0x20) +#define E2P_PHY_REG E2P_DATA(0x25) +#define E2P_36M_CAL_VALUE1 E2P_DATA(0x28) +#define E2P_36M_CAL_VALUE2 E2P_DATA(0x2a) +#define E2P_36M_CAL_VALUE3 E2P_DATA(0x2c) +#define E2P_36M_CAL_VALUE4 E2P_DATA(0x2e) +#define E2P_11A_INT_VALUE1 E2P_DATA(0x30) +#define E2P_11A_INT_VALUE2 E2P_DATA(0x32) +#define E2P_11A_INT_VALUE3 E2P_DATA(0x34) +#define E2P_11A_INT_VALUE4 E2P_DATA(0x36) +#define E2P_48M_CAL_VALUE1 E2P_DATA(0x38) +#define E2P_48M_CAL_VALUE2 E2P_DATA(0x3a) +#define E2P_48M_CAL_VALUE3 E2P_DATA(0x3c) +#define E2P_48M_CAL_VALUE4 E2P_DATA(0x3e) +#define E2P_48M_INT_VALUE1 E2P_DATA(0x40) +#define E2P_48M_INT_VALUE2 E2P_DATA(0x42) +#define E2P_48M_INT_VALUE3 E2P_DATA(0x44) +#define E2P_48M_INT_VALUE4 E2P_DATA(0x46) +#define E2P_54M_CAL_VALUE1 E2P_DATA(0x48) /* ??? */ +#define E2P_54M_CAL_VALUE2 E2P_DATA(0x4a) +#define E2P_54M_CAL_VALUE3 E2P_DATA(0x4c) +#define E2P_54M_CAL_VALUE4 E2P_DATA(0x4e) +#define E2P_54M_INT_VALUE1 E2P_DATA(0x50) +#define E2P_54M_INT_VALUE2 E2P_DATA(0x52) +#define E2P_54M_INT_VALUE3 E2P_DATA(0x54) +#define E2P_54M_INT_VALUE4 E2P_DATA(0x56) + +/* This word contains the base address of the FW_REG_ registers below */ +#define FWRAW_REGS_ADDR FWRAW_DATA(0x1d) + +/* All 16 bit values, offset from the address in FWRAW_REGS_ADDR */ +enum { + FW_REG_FIRMWARE_VER = 0, + /* non-zero if USB high speed connection */ + FW_REG_USB_SPEED = 1, + FW_REG_FIX_TX_RATE = 2, + /* Seems to be able to control LEDs over the firmware */ + FW_REG_LED_LINK_STATUS = 3, + FW_REG_SOFT_RESET = 4, + FW_REG_FLASH_CHK = 5, +}; +/* Values for FW_LINK_STATUS */ #define FW_LINK_OFF 0x0 #define FW_LINK_TX 0x1 /* 0x2 - link led on? */ enum { - CR_BASE_OFFSET = 0x9000, - FW_START_OFFSET = 0xee00, - FW_BASE_ADDR_OFFSET = FW_START_OFFSET + 0x1d, - EEPROM_START_OFFSET = 0xf800, - EEPROM_SIZE = 0x800, /* words */ - LOAD_CODE_SIZE = 0xe, /* words */ - LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */ - EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE, - EEPROM_REGS_SIZE = 0x7e, /* words */ - E2P_BASE_OFFSET = EEPROM_START_OFFSET + - EEPROM_REGS_OFFSET, -}; - -#define FW_REG_TABLE_ADDR USB_ADDR(FW_START_OFFSET + 0x1d) - -enum { /* indices for ofdm_cal_values */ OFDM_36M_INDEX = 0, OFDM_48M_INDEX = 1, @@ -661,7 +765,8 @@ struct zd_chip { struct zd_usb usb; struct zd_rf rf; struct mutex mutex; - u8 e2p_mac[ETH_ALEN]; + /* Base address of FW_REG_ registers */ + zd_addr_t fw_regs_base; /* EepSetPoint in the vendor driver */ u8 pwr_cal_values[E2P_CHANNEL_COUNT]; /* integration values in the vendor driver */ @@ -671,8 +776,8 @@ struct zd_chip { 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; + new_phy_layout:1, al2230s_bit:1, + supports_tx_led:1; }; static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb) @@ -688,12 +793,18 @@ static inline struct zd_chip *zd_rf_to_chip(struct zd_rf *rf) #define zd_chip_dev(chip) (&(chip)->usb.intf->dev) void zd_chip_init(struct zd_chip *chip, - struct net_device *netdev, + struct ieee80211_hw *hw, struct usb_interface *intf); void zd_chip_clear(struct zd_chip *chip); -int zd_chip_init_hw(struct zd_chip *chip, u8 device_type); +int zd_chip_read_mac_addr_fw(struct zd_chip *chip, u8 *addr); +int zd_chip_init_hw(struct zd_chip *chip); int zd_chip_reset(struct zd_chip *chip); +static inline int zd_chip_is_zd1211b(struct zd_chip *chip) +{ + return chip->usb.is_zd1211b; +} + static inline int zd_ioread16v_locked(struct zd_chip *chip, u16 *values, const zd_addr_t *addresses, unsigned int count) @@ -715,7 +826,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, static inline int zd_ioread32_locked(struct zd_chip *chip, u32 *value, const zd_addr_t addr) { - return zd_ioread32v_locked(chip, value, (const zd_addr_t *)&addr, 1); + return zd_ioread32v_locked(chip, value, &addr, 1); } static inline int zd_iowrite16_locked(struct zd_chip *chip, u16 value, @@ -782,17 +893,18 @@ static inline u8 _zd_chip_get_channel(struct zd_chip *chip) } u8 zd_chip_get_channel(struct zd_chip *chip); int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain); -void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr); -int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr); int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr); +int zd_write_bssid(struct zd_chip *chip, const u8 *bssid); int zd_chip_switch_radio_on(struct zd_chip *chip); int zd_chip_switch_radio_off(struct zd_chip *chip); int zd_chip_enable_int(struct zd_chip *chip); void zd_chip_disable_int(struct zd_chip *chip); -int zd_chip_enable_rx(struct zd_chip *chip); -void zd_chip_disable_rx(struct zd_chip *chip); +int zd_chip_enable_rxtx(struct zd_chip *chip); +void zd_chip_disable_rxtx(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_generic_patch_6m_band(struct zd_chip *chip, int channel); +int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, int preamble); static inline int zd_get_encryption_type(struct zd_chip *chip, u32 *type) { @@ -811,23 +923,19 @@ static inline int zd_chip_get_basic_rates(struct zd_chip *chip, u16 *cr_rates) int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates); -static inline int zd_chip_set_rx_filter(struct zd_chip *chip, u32 filter) -{ - return zd_iowrite32(chip, CR_RX_FILTER, filter); -} - 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_SCANNING = 1, - LED_ASSOCIATED = 2, + ZD_LED_OFF = 0, + ZD_LED_SCANNING = 1, + ZD_LED_ASSOCIATED = 2, }; int zd_chip_control_leds(struct zd_chip *chip, enum led_status status); -int zd_set_beacon_interval(struct zd_chip *chip, u32 interval); +int zd_set_beacon_interval(struct zd_chip *chip, u16 interval, u8 dtim_period, + int type); static inline int zd_get_beacon_interval(struct zd_chip *chip, u32 *interval) { @@ -836,10 +944,40 @@ static inline int zd_get_beacon_interval(struct zd_chip *chip, u32 *interval) struct rx_status; -u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size, - const struct rx_status *status); -u8 zd_rx_strength_percent(u8 rssi); +u8 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); -u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status); +u64 zd_chip_get_tsf(struct zd_chip *chip); #endif /* _ZD_CHIP_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h index a13ec72eb30..41bd755bc13 100644 --- a/drivers/net/wireless/zd1211rw/zd_def.h +++ b/drivers/net/wireless/zd1211rw/zd_def.h @@ -1,4 +1,7 @@ -/* zd_def.h +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #ifndef _ZD_DEF_H @@ -21,7 +23,8 @@ #include <linux/kernel.h> #include <linux/stringify.h> #include <linux/device.h> -#include <linux/kernel.h> + +typedef u16 __nocast zd_addr_t; #define dev_printk_f(level, dev, fmt, args...) \ dev_printk(level, dev, "%s() " fmt, __func__, ##args) @@ -29,16 +32,28 @@ #ifdef DEBUG # define dev_dbg_f(dev, fmt, args...) \ dev_printk_f(KERN_DEBUG, dev, fmt, ## args) +# define dev_dbg_f_limit(dev, fmt, args...) do { \ + if (net_ratelimit()) \ + dev_printk_f(KERN_DEBUG, dev, fmt, ## args); \ +} while (0) +# define dev_dbg_f_cond(dev, cond, fmt, args...) ({ \ + bool __cond = !!(cond); \ + if (unlikely(__cond)) \ + dev_printk_f(KERN_DEBUG, dev, fmt, ## args); \ +}) #else # define dev_dbg_f(dev, fmt, args...) do { (void)(dev); } while (0) +# define dev_dbg_f_limit(dev, fmt, args...) do { (void)(dev); } while (0) +# define dev_dbg_f_cond(dev, cond, fmt, args...) do { (void)(dev); } while (0) #endif /* DEBUG */ #ifdef DEBUG # define ZD_ASSERT(x) \ do { \ - if (!(x)) { \ + if (unlikely(!(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 deleted file mode 100644 index 66905f7b61f..00000000000 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.c +++ /dev/null @@ -1,191 +0,0 @@ -/* zd_ieee80211.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * A lot of this code is generic and should be moved into the upper layers - * at some point. - */ - -#include <linux/errno.h> -#include <linux/wireless.h> -#include <linux/kernel.h> -#include <net/ieee80211.h> - -#include "zd_def.h" -#include "zd_ieee80211.h" -#include "zd_mac.h" - -static const struct channel_range channel_ranges[] = { - [0] = { 0, 0}, - [ZD_REGDOMAIN_FCC] = { 1, 12}, - [ZD_REGDOMAIN_IC] = { 1, 12}, - [ZD_REGDOMAIN_ETSI] = { 1, 14}, - [ZD_REGDOMAIN_JAPAN] = { 1, 14}, - [ZD_REGDOMAIN_SPAIN] = { 1, 14}, - [ZD_REGDOMAIN_FRANCE] = { 1, 14}, - [ZD_REGDOMAIN_JAPAN_ADD] = {14, 15}, -}; - -const struct channel_range *zd_channel_range(u8 regdomain) -{ - if (regdomain >= ARRAY_SIZE(channel_ranges)) - regdomain = 0; - return &channel_ranges[regdomain]; -} - -int zd_regdomain_supports_channel(u8 regdomain, u8 channel) -{ - const struct channel_range *range = zd_channel_range(regdomain); - return range->start <= channel && channel < range->end; -} - -int zd_regdomain_supported(u8 regdomain) -{ - const struct channel_range *range = zd_channel_range(regdomain); - return range->start != 0; -} - -/* Stores channel frequencies in MHz. */ -static const u16 channel_frequencies[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, - 2452, 2457, 2462, 2467, 2472, 2484, -}; - -#define NUM_CHANNELS ARRAY_SIZE(channel_frequencies) - -static int compute_freq(struct iw_freq *freq, u32 mhz, u32 hz) -{ - u32 factor; - - freq->e = 0; - if (mhz >= 1000000000U) { - pr_debug("zd1211 mhz %u to large\n", mhz); - freq->m = 0; - return -EINVAL; - } - - factor = 1000; - while (mhz >= factor) { - - freq->e += 1; - factor *= 10; - } - - factor /= 1000U; - freq->m = mhz * (1000000U/factor) + hz/factor; - - return 0; -} - -int zd_channel_to_freq(struct iw_freq *freq, u8 channel) -{ - if (channel > NUM_CHANNELS) { - freq->m = 0; - freq->e = 0; - return -EINVAL; - } - if (!channel) { - freq->m = 0; - freq->e = 0; - return -EINVAL; - } - return compute_freq(freq, channel_frequencies[channel-1], 0); -} - -static int freq_to_mhz(const struct iw_freq *freq) -{ - u32 factor; - int e; - - /* Such high frequencies are not supported. */ - if (freq->e > 6) - return -EINVAL; - - factor = 1; - for (e = freq->e; e > 0; --e) { - factor *= 10; - } - factor = 1000000U / factor; - - if (freq->m % factor) { - return -EINVAL; - } - - return freq->m / factor; -} - -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; - *channel = freq->m; - return 1; - } - - r = freq_to_mhz(freq); - if (r < 0) - return r; - mhz = r; - - for (i = 0; i < NUM_CHANNELS; i++) { - if (mhz == channel_frequencies[i]) { - *channel = i+1; - return 1; - } - } - - return -EINVAL; -} - -int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain) -{ - struct ieee80211_geo geo; - const struct channel_range *range; - int i; - u8 channel; - - dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)), - "regdomain %#04x\n", regdomain); - - range = zd_channel_range(regdomain); - if (range->start == 0) { - dev_err(zd_mac_dev(zd_netdev_mac(ieee->dev)), - "zd1211 regdomain %#04x not supported\n", - regdomain); - return -EINVAL; - } - - memset(&geo, 0, sizeof(geo)); - - for (i = 0, channel = range->start; channel < range->end; channel++) { - struct ieee80211_channel *chan = &geo.bg[i++]; - chan->freq = channel_frequencies[channel - 1]; - chan->channel = channel; - } - - geo.bg_channels = i; - memcpy(geo.name, "XX ", 4); - ieee80211_set_geo(ieee, &geo); - return 0; -} diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h deleted file mode 100644 index f63245b0d96..00000000000 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef _ZD_IEEE80211_H -#define _ZD_IEEE80211_H - -#include <net/ieee80211.h> -#include "zd_types.h" - -/* Additional definitions from the standards. - */ - -#define ZD_REGDOMAIN_FCC 0x10 -#define ZD_REGDOMAIN_IC 0x20 -#define ZD_REGDOMAIN_ETSI 0x30 -#define ZD_REGDOMAIN_SPAIN 0x31 -#define ZD_REGDOMAIN_FRANCE 0x32 -#define ZD_REGDOMAIN_JAPAN_ADD 0x40 -#define ZD_REGDOMAIN_JAPAN 0x41 - -enum { - MIN_CHANNEL24 = 1, - MAX_CHANNEL24 = 14, -}; - -struct channel_range { - u8 start; - u8 end; /* exclusive (channel must be less than end) */ -}; - -struct iw_freq; - -int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain); - -const struct channel_range *zd_channel_range(u8 regdomain); -int zd_regdomain_supports_channel(u8 regdomain, u8 channel); -int zd_regdomain_supported(u8 regdomain); - -/* for 2.4 GHz band */ -int zd_channel_to_freq(struct iw_freq *freq, u8 channel); -int zd_find_channel(u8 *channel, const struct iw_freq *freq); - -#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80 - -struct ofdm_plcp_header { - u8 prefix[3]; - __le16 service; -} __attribute__((packed)); - -static inline u8 zd_ofdm_plcp_header_rate( - const struct ofdm_plcp_header *header) -{ - return header->prefix[0] & 0xf; -} - -#define ZD_OFDM_RATE_6M 0xb -#define ZD_OFDM_RATE_9M 0xf -#define ZD_OFDM_RATE_12M 0xa -#define ZD_OFDM_RATE_18M 0xe -#define ZD_OFDM_RATE_24M 0x9 -#define ZD_OFDM_RATE_36M 0xd -#define ZD_OFDM_RATE_48M 0x8 -#define ZD_OFDM_RATE_54M 0xc - -struct cck_plcp_header { - u8 signal; - u8 service; - __le16 length; - __le16 crc16; -}; - -static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header) -{ - return header->signal; -} - -#define ZD_CCK_SIGNAL_1M 0x0a -#define ZD_CCK_SIGNAL_2M 0x14 -#define ZD_CCK_SIGNAL_5M5 0x37 -#define ZD_CCK_SIGNAL_11M 0x6e - -enum ieee80211_std { - IEEE80211B = 0x01, - IEEE80211A = 0x02, - IEEE80211G = 0x04, -}; - -#endif /* _ZD_IEEE80211_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 2d12837052b..e7af261e919 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -1,4 +1,9 @@ -/* zd_mac.c +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> + * Copyright (C) 2006-2007 Michael Wu <flamingice@sourmilk.net> + * Copyright (C) 2007-2008 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,13 +16,12 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/netdevice.h> #include <linux/etherdevice.h> -#include <linux/wireless.h> +#include <linux/slab.h> #include <linux/usb.h> #include <linux/jiffies.h> #include <net/ieee80211_radiotap.h> @@ -25,93 +29,190 @@ #include "zd_def.h" #include "zd_chip.h" #include "zd_mac.h" -#include "zd_ieee80211.h" -#include "zd_netdev.h" #include "zd_rf.h" -#include "zd_util.h" -static void ieee_init(struct ieee80211_device *ieee); -static void softmac_init(struct ieee80211softmac_device *sm); +struct zd_reg_alpha2_map { + u32 reg; + char alpha2[2]; +}; + +static struct zd_reg_alpha2_map reg_alpha2_map[] = { + { ZD_REGDOMAIN_FCC, "US" }, + { ZD_REGDOMAIN_IC, "CA" }, + { ZD_REGDOMAIN_ETSI, "DE" }, /* Generic ETSI, use most restrictive */ + { ZD_REGDOMAIN_JAPAN, "JP" }, + { ZD_REGDOMAIN_JAPAN_2, "JP" }, + { ZD_REGDOMAIN_JAPAN_3, "JP" }, + { ZD_REGDOMAIN_SPAIN, "ES" }, + { ZD_REGDOMAIN_FRANCE, "FR" }, +}; + +/* This table contains the hardware specific values for the modulation rates. */ +static const struct ieee80211_rate zd_rates[] = { + { .bitrate = 10, + .hw_value = ZD_CCK_RATE_1M, }, + { .bitrate = 20, + .hw_value = ZD_CCK_RATE_2M, + .hw_value_short = ZD_CCK_RATE_2M | ZD_CCK_PREA_SHORT, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = ZD_CCK_RATE_5_5M, + .hw_value_short = ZD_CCK_RATE_5_5M | ZD_CCK_PREA_SHORT, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = ZD_CCK_RATE_11M, + .hw_value_short = ZD_CCK_RATE_11M | ZD_CCK_PREA_SHORT, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = ZD_OFDM_RATE_6M, + .flags = 0 }, + { .bitrate = 90, + .hw_value = ZD_OFDM_RATE_9M, + .flags = 0 }, + { .bitrate = 120, + .hw_value = ZD_OFDM_RATE_12M, + .flags = 0 }, + { .bitrate = 180, + .hw_value = ZD_OFDM_RATE_18M, + .flags = 0 }, + { .bitrate = 240, + .hw_value = ZD_OFDM_RATE_24M, + .flags = 0 }, + { .bitrate = 360, + .hw_value = ZD_OFDM_RATE_36M, + .flags = 0 }, + { .bitrate = 480, + .hw_value = ZD_OFDM_RATE_48M, + .flags = 0 }, + { .bitrate = 540, + .hw_value = ZD_OFDM_RATE_54M, + .flags = 0 }, +}; + +/* + * Zydas retry rates table. Each line is listed in the same order as + * in zd_rates[] and contains all the rate used when a packet is sent + * starting with a given rates. Let's consider an example : + * + * "11 Mbits : 4, 3, 2, 1, 0" means : + * - packet is sent using 4 different rates + * - 1st rate is index 3 (ie 11 Mbits) + * - 2nd rate is index 2 (ie 5.5 Mbits) + * - 3rd rate is index 1 (ie 2 Mbits) + * - 4th rate is index 0 (ie 1 Mbits) + */ + +static const struct tx_retry_rate zd_retry_rates[] = { + { /* 1 Mbits */ 1, { 0 }}, + { /* 2 Mbits */ 2, { 1, 0 }}, + { /* 5.5 Mbits */ 3, { 2, 1, 0 }}, + { /* 11 Mbits */ 4, { 3, 2, 1, 0 }}, + { /* 6 Mbits */ 5, { 4, 3, 2, 1, 0 }}, + { /* 9 Mbits */ 6, { 5, 4, 3, 2, 1, 0}}, + { /* 12 Mbits */ 5, { 6, 3, 2, 1, 0 }}, + { /* 18 Mbits */ 6, { 7, 6, 3, 2, 1, 0 }}, + { /* 24 Mbits */ 6, { 8, 6, 3, 2, 1, 0 }}, + { /* 36 Mbits */ 7, { 9, 8, 6, 3, 2, 1, 0 }}, + { /* 48 Mbits */ 8, {10, 9, 8, 6, 3, 2, 1, 0 }}, + { /* 54 Mbits */ 9, {11, 10, 9, 8, 6, 3, 2, 1, 0 }} +}; + +static const struct ieee80211_channel zd_channels[] = { + { .center_freq = 2412, .hw_value = 1 }, + { .center_freq = 2417, .hw_value = 2 }, + { .center_freq = 2422, .hw_value = 3 }, + { .center_freq = 2427, .hw_value = 4 }, + { .center_freq = 2432, .hw_value = 5 }, + { .center_freq = 2437, .hw_value = 6 }, + { .center_freq = 2442, .hw_value = 7 }, + { .center_freq = 2447, .hw_value = 8 }, + { .center_freq = 2452, .hw_value = 9 }, + { .center_freq = 2457, .hw_value = 10 }, + { .center_freq = 2462, .hw_value = 11 }, + { .center_freq = 2467, .hw_value = 12 }, + { .center_freq = 2472, .hw_value = 13 }, + { .center_freq = 2484, .hw_value = 14 }, +}; 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 beacon_init(struct zd_mac *mac); +static void beacon_enable(struct zd_mac *mac); +static void beacon_disable(struct zd_mac *mac); +static void set_rts_cts(struct zd_mac *mac, unsigned int short_preamble); +static int zd_mac_config_beacon(struct ieee80211_hw *hw, + struct sk_buff *beacon, bool in_intr); + +static int zd_reg2alpha2(u8 regdomain, char *alpha2) +{ + unsigned int i; + struct zd_reg_alpha2_map *reg_map; + for (i = 0; i < ARRAY_SIZE(reg_alpha2_map); i++) { + reg_map = ®_alpha2_map[i]; + if (regdomain == reg_map->reg) { + alpha2[0] = reg_map->alpha2[0]; + alpha2[1] = reg_map->alpha2[1]; + return 0; + } + } + return 1; +} -int zd_mac_init(struct zd_mac *mac, - struct net_device *netdev, - struct usb_interface *intf) +static int zd_check_signal(struct ieee80211_hw *hw, int signal) { - struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev); + struct zd_mac *mac = zd_hw_mac(hw); - memset(mac, 0, sizeof(*mac)); - spin_lock_init(&mac->lock); - mac->netdev = netdev; + dev_dbg_f_cond(zd_mac_dev(mac), signal < 0 || signal > 100, + "%s: signal value from device not in range 0..100, " + "but %d.\n", __func__, signal); - ieee_init(ieee); - softmac_init(ieee80211_priv(netdev)); - zd_chip_init(&mac->chip, netdev, intf); - housekeeping_init(mac); - return 0; + if (signal < 0) + signal = 0; + else if (signal > 100) + signal = 100; + + return signal; } -static int reset_channel(struct zd_mac *mac) +int zd_mac_preinit_hw(struct ieee80211_hw *hw) { int r; - unsigned long flags; - const struct channel_range *range; + u8 addr[ETH_ALEN]; + struct zd_mac *mac = zd_hw_mac(hw); - spin_lock_irqsave(&mac->lock, flags); - range = zd_channel_range(mac->regdomain); - if (!range->start) { - r = -EINVAL; - goto out; - } - mac->requested_channel = range->start; - r = 0; -out: - spin_unlock_irqrestore(&mac->lock, flags); - return r; + r = zd_chip_read_mac_addr_fw(&mac->chip, addr); + if (r) + return r; + + SET_IEEE80211_PERM_ADDR(hw, addr); + + return 0; } -int zd_mac_init_hw(struct zd_mac *mac, u8 device_type) +int zd_mac_init_hw(struct ieee80211_hw *hw) { int r; + struct zd_mac *mac = zd_hw_mac(hw); struct zd_chip *chip = &mac->chip; - u8 addr[ETH_ALEN]; + char alpha2[2]; u8 default_regdomain; r = zd_chip_enable_int(chip); if (r) goto out; - r = zd_chip_init_hw(chip, device_type); + r = zd_chip_init_hw(chip); if (r) goto disable_int; - zd_get_e2p_mac_addr(chip, addr); - r = zd_write_mac_addr(chip, addr); - if (r) - goto disable_int; ZD_ASSERT(!irqs_disabled()); - spin_lock_irq(&mac->lock); - memcpy(mac->netdev->dev_addr, addr, ETH_ALEN); - spin_unlock_irq(&mac->lock); r = zd_read_regdomain(chip, &default_regdomain); if (r) goto disable_int; - if (!zd_regdomain_supported(default_regdomain)) { - dev_dbg_f(zd_mac_dev(mac), - "Regulatory Domain %#04x is not supported.\n", - default_regdomain); - r = -EINVAL; - goto disable_int; - } spin_lock_irq(&mac->lock); mac->regdomain = mac->default_regdomain = default_regdomain; spin_unlock_irq(&mac->lock); - r = reset_channel(mac); - if (r) - goto disable_int; /* We must inform the device that we are doing encryption/decryption in * software at the moment. */ @@ -119,11 +220,11 @@ int zd_mac_init_hw(struct zd_mac *mac, u8 device_type) if (r) goto disable_int; - r = zd_geo_init(zd_mac_to_ieee80211(mac), mac->regdomain); + r = zd_reg2alpha2(mac->regdomain, alpha2); if (r) goto disable_int; - r = 0; + r = regulatory_hint(hw->wiphy, alpha2); disable_int: zd_chip_disable_int(chip); out: @@ -132,34 +233,65 @@ 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)); } -static int reset_mode(struct zd_mac *mac) +static int set_rx_filter(struct zd_mac *mac) { - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - struct zd_ioreq32 ioreqs[3] = { - { CR_RX_FILTER, STA_RX_FILTER }, - { CR_SNIFFER_ON, 0U }, - }; + unsigned long flags; + u32 filter = STA_RX_FILTER; - if (ieee->iw_mode == IW_MODE_MONITOR) { - ioreqs[0].value = 0xffffffff; - ioreqs[1].value = 0x1; - ioreqs[2].value = ENC_SNIFFER; - } + spin_lock_irqsave(&mac->lock, flags); + if (mac->pass_ctrl) + filter |= RX_FILTER_CTRL; + spin_unlock_irqrestore(&mac->lock, flags); - return zd_iowrite32a(&mac->chip, ioreqs, 3); + return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter); } -int zd_mac_open(struct net_device *netdev) +static int set_mac_and_bssid(struct zd_mac *mac) { - struct zd_mac *mac = zd_netdev_mac(netdev); + int r; + + if (!mac->vif) + return -1; + + r = zd_write_mac_addr(&mac->chip, mac->vif->addr); + if (r) + return r; + + /* Vendor driver after setting MAC either sets BSSID for AP or + * filter for other modes. + */ + if (mac->type != NL80211_IFTYPE_AP) + return set_rx_filter(mac); + else + return zd_write_bssid(&mac->chip, mac->vif->addr); +} + +static int set_mc_hash(struct zd_mac *mac) +{ + struct zd_mc_hash hash; + zd_mc_clear(&hash); + return zd_chip_set_multicast_hash(&mac->chip, &hash); +} + +int zd_op_start(struct ieee80211_hw *hw) +{ + struct zd_mac *mac = zd_hw_mac(hw); struct zd_chip *chip = &mac->chip; + struct zd_usb *usb = &chip->usb; int r; + if (!usb->initialized) { + r = zd_usb_init_hw(usb); + if (r) + goto out; + } + r = zd_chip_enable_int(chip); if (r < 0) goto out; @@ -167,27 +299,38 @@ int zd_mac_open(struct net_device *netdev) r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G); if (r < 0) goto disable_int; - r = reset_mode(mac); + r = set_rx_filter(mac); + if (r) + goto disable_int; + r = set_mc_hash(mac); if (r) goto disable_int; + + /* Wait after setting the multicast hash table and powering on + * the radio otherwise interface bring up will fail. This matches + * what the vendor driver did. + */ + msleep(10); + r = zd_chip_switch_radio_on(chip); - if (r < 0) + if (r < 0) { + dev_err(zd_chip_dev(chip), + "%s: failed to set radio on\n", __func__); goto disable_int; - r = zd_chip_set_channel(chip, mac->requested_channel); - if (r < 0) - goto disable_radio; - r = zd_chip_enable_rx(chip); + } + r = zd_chip_enable_rxtx(chip); if (r < 0) goto disable_radio; r = zd_chip_enable_hwint(chip); if (r < 0) - goto disable_rx; + goto disable_rxtx; housekeeping_enable(mac); - ieee80211softmac_start(netdev); + beacon_enable(mac); + set_bit(ZD_DEVICE_RUNNING, &mac->flags); return 0; -disable_rx: - zd_chip_disable_rx(chip); +disable_rxtx: + zd_chip_disable_rxtx(chip); disable_radio: zd_chip_switch_radio_off(chip); disable_int: @@ -196,323 +339,306 @@ out: return r; } -int zd_mac_stop(struct net_device *netdev) +void zd_op_stop(struct ieee80211_hw *hw) { - struct zd_mac *mac = zd_netdev_mac(netdev); + struct zd_mac *mac = zd_hw_mac(hw); struct zd_chip *chip = &mac->chip; + struct sk_buff *skb; + struct sk_buff_head *ack_wait_queue = &mac->ack_wait_queue; - netif_stop_queue(netdev); + clear_bit(ZD_DEVICE_RUNNING, &mac->flags); - /* - * The order here deliberately is a little different from the open() + /* The order here deliberately is a little different from the open() * method, since we need to make sure there is no opportunity for RX - * frames to be processed by softmac after we have stopped it. + * frames to be processed by mac80211 after we have stopped it. */ - zd_chip_disable_rx(chip); + zd_chip_disable_rxtx(chip); + beacon_disable(mac); housekeeping_disable(mac); - ieee80211softmac_stop(netdev); + flush_workqueue(zd_workqueue); zd_chip_disable_hwint(chip); zd_chip_switch_radio_off(chip); zd_chip_disable_int(chip); - return 0; -} - -int zd_mac_set_mac_address(struct net_device *netdev, void *p) -{ - int r; - unsigned long flags; - struct sockaddr *addr = p; - struct zd_mac *mac = zd_netdev_mac(netdev); - struct zd_chip *chip = &mac->chip; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - dev_dbg_f(zd_mac_dev(mac), - "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data)); - - r = zd_write_mac_addr(chip, addr->sa_data); - if (r) - return r; - - spin_lock_irqsave(&mac->lock, flags); - memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN); - spin_unlock_irqrestore(&mac->lock, flags); - - return 0; + while ((skb = skb_dequeue(ack_wait_queue))) + dev_kfree_skb_any(skb); } -int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain) +int zd_restore_settings(struct zd_mac *mac) { - int r; + struct sk_buff *beacon; + struct zd_mc_hash multicast_hash; + unsigned int short_preamble; + int r, beacon_interval, beacon_period; u8 channel; - ZD_ASSERT(!irqs_disabled()); + dev_dbg_f(zd_mac_dev(mac), "\n"); + spin_lock_irq(&mac->lock); - if (regdomain == 0) { - regdomain = mac->default_regdomain; - } - if (!zd_regdomain_supported(regdomain)) { - spin_unlock_irq(&mac->lock); - return -EINVAL; - } - mac->regdomain = regdomain; - channel = mac->requested_channel; + multicast_hash = mac->multicast_hash; + short_preamble = mac->short_preamble; + beacon_interval = mac->beacon.interval; + beacon_period = mac->beacon.period; + channel = mac->channel; spin_unlock_irq(&mac->lock); - r = zd_geo_init(zd_mac_to_ieee80211(mac), regdomain); - if (r) + r = set_mac_and_bssid(mac); + if (r < 0) { + dev_dbg_f(zd_mac_dev(mac), "set_mac_and_bssid failed, %d\n", r); return r; - if (!zd_regdomain_supports_channel(regdomain, channel)) { - r = reset_channel(mac); - if (r) - return r; } - return 0; -} + r = zd_chip_set_channel(&mac->chip, channel); + if (r < 0) { + dev_dbg_f(zd_mac_dev(mac), "zd_chip_set_channel failed, %d\n", + r); + return r; + } -u8 zd_mac_get_regdomain(struct zd_mac *mac) -{ - unsigned long flags; - u8 regdomain; + set_rts_cts(mac, short_preamble); - spin_lock_irqsave(&mac->lock, flags); - regdomain = mac->regdomain; - spin_unlock_irqrestore(&mac->lock, flags); - return regdomain; -} + r = zd_chip_set_multicast_hash(&mac->chip, &multicast_hash); + if (r < 0) { + dev_dbg_f(zd_mac_dev(mac), + "zd_chip_set_multicast_hash failed, %d\n", r); + return r; + } -static void set_channel(struct net_device *netdev, u8 channel) -{ - struct zd_mac *mac = zd_netdev_mac(netdev); + if (mac->type == NL80211_IFTYPE_MESH_POINT || + mac->type == NL80211_IFTYPE_ADHOC || + mac->type == NL80211_IFTYPE_AP) { + if (mac->vif != NULL) { + beacon = ieee80211_beacon_get(mac->hw, mac->vif); + if (beacon) + zd_mac_config_beacon(mac->hw, beacon, false); + } - dev_dbg_f(zd_mac_dev(mac), "channel %d\n", channel); + zd_set_beacon_interval(&mac->chip, beacon_interval, + beacon_period, mac->type); + + spin_lock_irq(&mac->lock); + mac->beacon.last_update = jiffies; + spin_unlock_irq(&mac->lock); + } - zd_chip_set_channel(&mac->chip, channel); + return 0; } -/* TODO: Should not work in Managed mode. */ -int zd_mac_request_channel(struct zd_mac *mac, u8 channel) +/** + * zd_mac_tx_status - reports tx status of a packet if required + * @hw - a &struct ieee80211_hw pointer + * @skb - a sk-buffer + * @flags: extra flags to set in the TX status info + * @ackssi: ACK signal strength + * @success - True for successful transmission of the frame + * + * This information calls ieee80211_tx_status_irqsafe() if required by the + * control information. It copies the control information into the status + * information. + * + * If no status information has been requested, the skb is freed. + */ +static void zd_mac_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, + int ackssi, struct tx_status *tx_status) { - unsigned long lock_flags; - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int i; + int success = 1, retry = 1; + int first_idx; + const struct tx_retry_rate *retries; - if (ieee->iw_mode == IW_MODE_INFRA) - return -EPERM; + ieee80211_tx_info_clear_status(info); - spin_lock_irqsave(&mac->lock, lock_flags); - if (!zd_regdomain_supports_channel(mac->regdomain, channel)) { - spin_unlock_irqrestore(&mac->lock, lock_flags); - return -EINVAL; + if (tx_status) { + success = !tx_status->failure; + retry = tx_status->retry + success; } - mac->requested_channel = channel; - spin_unlock_irqrestore(&mac->lock, lock_flags); - if (netif_running(mac->netdev)) - return zd_chip_set_channel(&mac->chip, channel); - else - return 0; -} - -int zd_mac_get_channel(struct zd_mac *mac, u8 *channel, u8 *flags) -{ - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - *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); + if (success) { + /* success */ + info->flags |= IEEE80211_TX_STAT_ACK; } else { - *flags = 0; + /* failure */ + info->flags &= ~IEEE80211_TX_STAT_ACK; } - dev_dbg_f(zd_mac_dev(mac), "channel %u flags %u\n", *channel, *flags); - return 0; -} -/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */ -static u8 cs_typed_rate(u8 cs_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_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, - [ZD_OFDM_RATE_18M] = ZD_CS_OFDM|ZD_OFDM_RATE_18M, - [ZD_OFDM_RATE_24M] = ZD_CS_OFDM|ZD_OFDM_RATE_24M, - [ZD_OFDM_RATE_36M] = ZD_CS_OFDM|ZD_OFDM_RATE_36M, - [ZD_OFDM_RATE_48M] = ZD_CS_OFDM|ZD_OFDM_RATE_48M, - [ZD_OFDM_RATE_54M] = ZD_CS_OFDM|ZD_OFDM_RATE_54M, - }; + first_idx = info->status.rates[0].idx; + ZD_ASSERT(0<=first_idx && first_idx<ARRAY_SIZE(zd_retry_rates)); + retries = &zd_retry_rates[first_idx]; + ZD_ASSERT(1 <= retry && retry <= retries->count); - ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f); - return typed_rates[cs_rate & ZD_CS_RATE_MASK]; -} + info->status.rates[0].idx = retries->rate[0]; + info->status.rates[0].count = 1; // (retry > 1 ? 2 : 1); -/* 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; + for (i=1; i<IEEE80211_TX_MAX_RATES-1 && i<retry; i++) { + info->status.rates[i].idx = retries->rate[i]; + info->status.rates[i].count = 1; // ((i==retry-1) && success ? 1:2); } - return ZD_CS_CCK_RATE_1M; -} - -int zd_mac_set_mode(struct zd_mac *mac, u32 mode) -{ - struct ieee80211_device *ieee; - - switch (mode) { - case IW_MODE_AUTO: - case IW_MODE_ADHOC: - case IW_MODE_INFRA: - mac->netdev->type = ARPHRD_ETHER; - break; - case IW_MODE_MONITOR: - mac->netdev->type = ARPHRD_IEEE80211_RADIOTAP; - break; - default: - dev_dbg_f(zd_mac_dev(mac), "wrong mode %u\n", mode); - return -EINVAL; + for (; i<IEEE80211_TX_MAX_RATES && i<retry; i++) { + info->status.rates[i].idx = retries->rate[retry - 1]; + info->status.rates[i].count = 1; // (success ? 1:2); } + if (i<IEEE80211_TX_MAX_RATES) + info->status.rates[i].idx = -1; /* terminate */ - ieee = zd_mac_to_ieee80211(mac); - ZD_ASSERT(!irqs_disabled()); - spin_lock_irq(&ieee->lock); - ieee->iw_mode = mode; - spin_unlock_irq(&ieee->lock); - - if (netif_running(mac->netdev)) - return reset_mode(mac); - - return 0; + info->status.ack_signal = zd_check_signal(hw, ackssi); + ieee80211_tx_status_irqsafe(hw, skb); } -int zd_mac_get_mode(struct zd_mac *mac, u32 *mode) +/** + * zd_mac_tx_failed - callback for failed frames + * @dev: the mac80211 wireless device + * + * This function is called if a frame couldn't be successfully + * transferred. The first frame from the tx queue, will be selected and + * reported as error to the upper layers. + */ +void zd_mac_tx_failed(struct urb *urb) { + struct ieee80211_hw * hw = zd_usb_to_hw(urb->context); + struct zd_mac *mac = zd_hw_mac(hw); + struct sk_buff_head *q = &mac->ack_wait_queue; + struct sk_buff *skb; + struct tx_status *tx_status = (struct tx_status *)urb->transfer_buffer; unsigned long flags; - struct ieee80211_device *ieee; - - ieee = zd_mac_to_ieee80211(mac); - spin_lock_irqsave(&ieee->lock, flags); - *mode = ieee->iw_mode; - spin_unlock_irqrestore(&ieee->lock, flags); - return 0; -} - -int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range) -{ - int i; - const struct channel_range *channel_range; - u8 regdomain; - - memset(range, 0, sizeof(*range)); + int success = !tx_status->failure; + int retry = tx_status->retry + success; + int found = 0; + int i, position = 0; + + q = &mac->ack_wait_queue; + spin_lock_irqsave(&q->lock, flags); + + skb_queue_walk(q, skb) { + struct ieee80211_hdr *tx_hdr; + struct ieee80211_tx_info *info; + int first_idx, final_idx; + const struct tx_retry_rate *retries; + u8 final_rate; + + position ++; + + /* if the hardware reports a failure and we had a 802.11 ACK + * pending, then we skip the first skb when searching for a + * matching frame */ + if (tx_status->failure && mac->ack_pending && + skb_queue_is_first(q, skb)) { + continue; + } - /* FIXME: Not so important and depends on the mode. For 802.11g - * usually this value is used. It seems to be that Bit/s number is - * given here. - */ - range->throughput = 27 * 1000 * 1000; + tx_hdr = (struct ieee80211_hdr *)skb->data; - range->max_qual.qual = 100; - range->max_qual.level = 100; + /* we skip all frames not matching the reported destination */ + if (unlikely(!ether_addr_equal(tx_hdr->addr1, tx_status->mac))) + continue; - /* FIXME: Needs still to be tuned. */ - range->avg_qual.qual = 71; - range->avg_qual.level = 80; + /* we skip all frames not matching the reported final rate */ - /* FIXME: depends on standard? */ - range->min_rts = 256; - range->max_rts = 2346; + info = IEEE80211_SKB_CB(skb); + first_idx = info->status.rates[0].idx; + ZD_ASSERT(0<=first_idx && first_idx<ARRAY_SIZE(zd_retry_rates)); + retries = &zd_retry_rates[first_idx]; + if (retry <= 0 || retry > retries->count) + continue; - range->min_frag = MIN_FRAG_THRESHOLD; - range->max_frag = MAX_FRAG_THRESHOLD; + final_idx = retries->rate[retry - 1]; + final_rate = zd_rates[final_idx].hw_value; - range->max_encoding_tokens = WEP_KEYS; - range->num_encoding_sizes = 2; - range->encoding_size[0] = 5; - range->encoding_size[1] = WEP_KEY_LEN; + if (final_rate != tx_status->rate) { + continue; + } - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 20; + found = 1; + break; + } - ZD_ASSERT(!irqs_disabled()); - spin_lock_irq(&mac->lock); - regdomain = mac->regdomain; - spin_unlock_irq(&mac->lock); - channel_range = zd_channel_range(regdomain); + if (found) { + for (i=1; i<=position; i++) { + skb = __skb_dequeue(q); + zd_mac_tx_status(hw, skb, + mac->ack_pending ? mac->ack_signal : 0, + i == position ? tx_status : NULL); + mac->ack_pending = 0; + } + } - range->num_channels = channel_range->end - channel_range->start; - range->old_num_channels = range->num_channels; - range->num_frequency = range->num_channels; - range->old_num_frequency = range->num_frequency; + spin_unlock_irqrestore(&q->lock, flags); +} - for (i = 0; i < range->num_frequency; i++) { - struct iw_freq *freq = &range->freq[i]; - freq->i = channel_range->start + i; - zd_channel_to_freq(freq, freq->i); +/** + * zd_mac_tx_to_dev - callback for USB layer + * @skb: a &sk_buff pointer + * @error: error value, 0 if transmission successful + * + * Informs the MAC layer that the frame has successfully transferred to the + * device. If an ACK is required and the transfer to the device has been + * successful, the packets are put on the @ack_wait_queue with + * the control set removed. + */ +void zd_mac_tx_to_dev(struct sk_buff *skb, int error) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hw *hw = info->rate_driver_data[0]; + struct zd_mac *mac = zd_hw_mac(hw); + + ieee80211_tx_info_clear_status(info); + + skb_pull(skb, sizeof(struct zd_ctrlset)); + if (unlikely(error || + (info->flags & IEEE80211_TX_CTL_NO_ACK))) { + /* + * FIXME : do we need to fill in anything ? + */ + ieee80211_tx_status_irqsafe(hw, skb); + } else { + struct sk_buff_head *q = &mac->ack_wait_queue; + + skb_queue_tail(q, skb); + while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) { + zd_mac_tx_status(hw, skb_dequeue(q), + mac->ack_pending ? mac->ack_signal : 0, + NULL); + mac->ack_pending = 0; + } } - - 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) { + /* ZD_PURE_RATE() must be used to remove the modulation type flag of + * the zd-rate values. + */ 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_OFDM_RATE_6M] = 6, - [ZD_OFDM_RATE_9M] = 9, - [ZD_OFDM_RATE_12M] = 12, - [ZD_OFDM_RATE_18M] = 18, - [ZD_OFDM_RATE_24M] = 24, - [ZD_OFDM_RATE_36M] = 36, - [ZD_OFDM_RATE_48M] = 48, - [ZD_OFDM_RATE_54M] = 54, + [ZD_PURE_RATE(ZD_CCK_RATE_1M)] = 1, + [ZD_PURE_RATE(ZD_CCK_RATE_2M)] = 2, + /* Bits must be doubled. */ + [ZD_PURE_RATE(ZD_CCK_RATE_5_5M)] = 11, + [ZD_PURE_RATE(ZD_CCK_RATE_11M)] = 11, + [ZD_PURE_RATE(ZD_OFDM_RATE_6M)] = 6, + [ZD_PURE_RATE(ZD_OFDM_RATE_9M)] = 9, + [ZD_PURE_RATE(ZD_OFDM_RATE_12M)] = 12, + [ZD_PURE_RATE(ZD_OFDM_RATE_18M)] = 18, + [ZD_PURE_RATE(ZD_OFDM_RATE_24M)] = 24, + [ZD_PURE_RATE(ZD_OFDM_RATE_36M)] = 36, + [ZD_PURE_RATE(ZD_OFDM_RATE_48M)] = 48, + [ZD_PURE_RATE(ZD_OFDM_RATE_54M)] = 54, }; u32 bits = (u32)tx_length * 8; u32 divisor; - divisor = rate_divisor[cs_rate]; + divisor = rate_divisor[ZD_PURE_RATE(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; @@ -527,137 +653,251 @@ static int zd_calc_tx_length_us(u8 *service, u8 cs_rate, u16 tx_length) return bits/divisor; } -enum { - R2M_SHORT_PREAMBLE = 0x01, - R2M_11A = 0x02, -}; - -static u8 cs_rate_to_modulation(u8 cs_rate, int flags) -{ - u8 modulation; - - modulation = cs_typed_rate(cs_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: - modulation |= ZD_CS_CCK_PREA_SHORT; - return modulation; - } - } - if (flags & R2M_11A) { - if (ZD_CS_TYPE(modulation) == ZD_CS_OFDM) - modulation |= ZD_CS_OFDM_MODE_11A; - } - return modulation; -} - -static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs, - struct ieee80211_hdr_4addr *hdr) -{ - struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev); - u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl)); - u8 rate, cs_rate; - int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0; - - /* FIXME: 802.11a? short preamble? */ - rate = ieee80211softmac_suggest_txrate(softmac, - is_multicast_ether_addr(hdr->addr1), is_mgt); - - cs_rate = rate_to_cs_rate(rate); - cs->modulation = cs_rate_to_modulation(cs_rate, 0); -} - static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, - struct ieee80211_hdr_4addr *header) + struct ieee80211_hdr *header, + struct ieee80211_tx_info *info) { - 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; /* First fragment */ - if (WLAN_GET_SEQ_FRAG(le16_to_cpu(header->seq_ctl)) == 0) + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; - /* Multicast */ - if (is_multicast_ether_addr(header->addr1)) - cs->control |= ZD_CS_MULTICAST; + /* No ACK expected (multicast, etc.) */ + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + cs->control |= ZD_CS_NO_ACK; /* PS-POLL */ - if (stype == IEEE80211_STYPE_PSPOLL) + if (ieee80211_is_pspoll(header->frame_control)) cs->control |= ZD_CS_PS_POLL_FRAME; - 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; + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) + cs->control |= ZD_CS_RTS; + + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) + cs->control |= ZD_CS_SELF_CTS; + + /* FIXME: Management frame? */ +} + +static bool zd_mac_match_cur_beacon(struct zd_mac *mac, struct sk_buff *beacon) +{ + if (!mac->beacon.cur_beacon) + return false; + + if (mac->beacon.cur_beacon->len != beacon->len) + return false; + + return !memcmp(beacon->data, mac->beacon.cur_beacon->data, beacon->len); +} + +static void zd_mac_free_cur_beacon_locked(struct zd_mac *mac) +{ + ZD_ASSERT(mutex_is_locked(&mac->chip.mutex)); + + kfree_skb(mac->beacon.cur_beacon); + mac->beacon.cur_beacon = NULL; +} + +static void zd_mac_free_cur_beacon(struct zd_mac *mac) +{ + mutex_lock(&mac->chip.mutex); + zd_mac_free_cur_beacon_locked(mac); + mutex_unlock(&mac->chip.mutex); +} + +static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon, + bool in_intr) +{ + struct zd_mac *mac = zd_hw_mac(hw); + int r, ret, num_cmds, req_pos = 0; + u32 tmp, j = 0; + /* 4 more bytes for tail CRC */ + u32 full_len = beacon->len + 4; + unsigned long end_jiffies, message_jiffies; + struct zd_ioreq32 *ioreqs; + + mutex_lock(&mac->chip.mutex); + + /* Check if hw already has this beacon. */ + if (zd_mac_match_cur_beacon(mac, beacon)) { + r = 0; + goto out_nofree; + } + + /* Alloc memory for full beacon write at once. */ + num_cmds = 1 + zd_chip_is_zd1211b(&mac->chip) + full_len; + ioreqs = kmalloc(num_cmds * sizeof(struct zd_ioreq32), GFP_KERNEL); + if (!ioreqs) { + r = -ENOMEM; + goto out_nofree; + } + + r = zd_iowrite32_locked(&mac->chip, 0, CR_BCN_FIFO_SEMAPHORE); + if (r < 0) + goto out; + r = zd_ioread32_locked(&mac->chip, &tmp, CR_BCN_FIFO_SEMAPHORE); + if (r < 0) + goto release_sema; + if (in_intr && tmp & 0x2) { + r = -EBUSY; + goto release_sema; + } + + end_jiffies = jiffies + HZ / 2; /*~500ms*/ + message_jiffies = jiffies + HZ / 10; /*~100ms*/ + while (tmp & 0x2) { + r = zd_ioread32_locked(&mac->chip, &tmp, CR_BCN_FIFO_SEMAPHORE); + if (r < 0) + goto release_sema; + if (time_is_before_eq_jiffies(message_jiffies)) { + message_jiffies = jiffies + HZ / 10; + dev_err(zd_mac_dev(mac), + "CR_BCN_FIFO_SEMAPHORE not ready\n"); + if (time_is_before_eq_jiffies(end_jiffies)) { + dev_err(zd_mac_dev(mac), + "Giving up beacon config.\n"); + r = -ETIMEDOUT; + goto reset_device; + } } + msleep(20); } - /* FIXME: Management frame? */ + ioreqs[req_pos].addr = CR_BCN_FIFO; + ioreqs[req_pos].value = full_len - 1; + req_pos++; + if (zd_chip_is_zd1211b(&mac->chip)) { + ioreqs[req_pos].addr = CR_BCN_LENGTH; + ioreqs[req_pos].value = full_len - 1; + req_pos++; + } + + for (j = 0 ; j < beacon->len; j++) { + ioreqs[req_pos].addr = CR_BCN_FIFO; + ioreqs[req_pos].value = *((u8 *)(beacon->data + j)); + req_pos++; + } + + for (j = 0; j < 4; j++) { + ioreqs[req_pos].addr = CR_BCN_FIFO; + ioreqs[req_pos].value = 0x0; + req_pos++; + } + + BUG_ON(req_pos != num_cmds); + + r = zd_iowrite32a_locked(&mac->chip, ioreqs, num_cmds); + +release_sema: + /* + * Try very hard to release device beacon semaphore, as otherwise + * device/driver can be left in unusable state. + */ + end_jiffies = jiffies + HZ / 2; /*~500ms*/ + ret = zd_iowrite32_locked(&mac->chip, 1, CR_BCN_FIFO_SEMAPHORE); + while (ret < 0) { + if (in_intr || time_is_before_eq_jiffies(end_jiffies)) { + ret = -ETIMEDOUT; + break; + } + + msleep(20); + ret = zd_iowrite32_locked(&mac->chip, 1, CR_BCN_FIFO_SEMAPHORE); + } + + if (ret < 0) + dev_err(zd_mac_dev(mac), "Could not release " + "CR_BCN_FIFO_SEMAPHORE!\n"); + if (r < 0 || ret < 0) { + if (r >= 0) + r = ret; + + /* We don't know if beacon was written successfully or not, + * so clear current. */ + zd_mac_free_cur_beacon_locked(mac); + + goto out; + } + + /* Beacon has now been written successfully, update current. */ + zd_mac_free_cur_beacon_locked(mac); + mac->beacon.cur_beacon = beacon; + beacon = NULL; + + /* 802.11b/g 2.4G CCK 1Mb + * 802.11a, not yet implemented, uses different values (see GPL vendor + * driver) + */ + r = zd_iowrite32_locked(&mac->chip, 0x00000400 | (full_len << 19), + CR_BCN_PLCP_CFG); +out: + kfree(ioreqs); +out_nofree: + kfree_skb(beacon); + mutex_unlock(&mac->chip.mutex); + + return r; + +reset_device: + zd_mac_free_cur_beacon_locked(mac); + kfree_skb(beacon); + + mutex_unlock(&mac->chip.mutex); + kfree(ioreqs); + + /* semaphore stuck, reset device to avoid fw freeze later */ + dev_warn(zd_mac_dev(mac), "CR_BCN_FIFO_SEMAPHORE stuck, " + "resetting device..."); + usb_queue_reset_device(mac->chip.usb.intf); + + return r; } static int fill_ctrlset(struct zd_mac *mac, - struct ieee80211_txb *txb, - int frag_num) + struct sk_buff *skb) { int r; - struct sk_buff *skb = txb->fragments[frag_num]; - struct ieee80211_hdr_4addr *hdr = - (struct ieee80211_hdr_4addr *) skb->data; - unsigned int frag_len = skb->len + IEEE80211_FCS_LEN; - unsigned int next_frag_len; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + unsigned int frag_len = skb->len + FCS_LEN; unsigned int packet_length; + struct ieee80211_rate *txrate; struct zd_ctrlset *cs = (struct zd_ctrlset *) skb_push(skb, sizeof(struct zd_ctrlset)); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - if (frag_num+1 < txb->nr_frags) { - next_frag_len = txb->fragments[frag_num+1]->len + - IEEE80211_FCS_LEN; - } else { - next_frag_len = 0; - } ZD_ASSERT(frag_len <= 0xffff); - ZD_ASSERT(next_frag_len <= 0xffff); - cs_set_modulation(mac, cs, hdr); + /* + * Firmware computes the duration itself (for all frames except PSPoll) + * and needs the field set to 0 at input, otherwise firmware messes up + * duration_id and sets bits 14 and 15 on. + */ + if (!ieee80211_is_pspoll(hdr->frame_control)) + hdr->duration_id = 0; + + txrate = ieee80211_get_tx_rate(mac->hw, info); + + cs->modulation = txrate->hw_value; + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + cs->modulation = txrate->hw_value_short; cs->tx_length = cpu_to_le16(frag_len); - cs_set_control(mac, cs, hdr); + cs_set_control(mac, cs, hdr, info); packet_length = frag_len + sizeof(struct zd_ctrlset) + 10; ZD_ASSERT(packet_length <= 0xffff); /* ZD1211B: Computing the length difference this way, gives us * flexibility to compute the packet length. */ - cs->packet_length = cpu_to_le16(mac->chip.is_zd1211b ? + cs->packet_length = cpu_to_le16(zd_chip_is_zd1211b(&mac->chip) ? packet_length - frag_len : packet_length); /* @@ -674,446 +914,625 @@ static int fill_ctrlset(struct zd_mac *mac, * - see line 53 of zdinlinef.h */ cs->service = 0; - r = zd_calc_tx_length_us(&cs->service, ZD_CS_RATE(cs->modulation), + r = zd_calc_tx_length_us(&cs->service, ZD_RATE(cs->modulation), le16_to_cpu(cs->tx_length)); if (r < 0) return r; cs->current_length = cpu_to_le16(r); - - if (next_frag_len == 0) { - cs->next_frame_length = 0; - } else { - r = zd_calc_tx_length_us(NULL, ZD_CS_RATE(cs->modulation), - next_frag_len); - if (r < 0) - return r; - cs->next_frame_length = cpu_to_le16(r); - } + cs->next_frame_length = 0; return 0; } -static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri) +/** + * zd_op_tx - transmits a network frame to the device + * + * @dev: mac80211 hardware device + * @skb: socket buffer + * @control: the control structure + * + * This function transmit an IEEE 802.11 network frame to the device. The + * control block of the skbuff will be initialized. If necessary the incoming + * mac80211 queues will be stopped. + */ +static void zd_op_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, + struct sk_buff *skb) { - int i, r; + struct zd_mac *mac = zd_hw_mac(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int r; - for (i = 0; i < txb->nr_frags; i++) { - struct sk_buff *skb = txb->fragments[i]; + r = fill_ctrlset(mac, skb); + if (r) + goto fail; - r = fill_ctrlset(mac, txb, i); - if (r) - return r; - r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len); - if (r) - return r; - } + info->rate_driver_data[0] = hw; - /* FIXME: shouldn't this be handled by the upper layers? */ - mac->netdev->trans_start = jiffies; + r = zd_usb_tx(&mac->chip.usb, skb); + if (r) + goto fail; + return; - ieee80211_txb_free(txb); - return 0; +fail: + dev_kfree_skb(skb); } -struct zd_rt_hdr { - struct ieee80211_radiotap_header rt_hdr; - u8 rt_flags; - u8 rt_rate; - u16 rt_channel; - u16 rt_chbitmask; -}; - -static void fill_rt_header(void *buffer, struct zd_mac *mac, - const struct ieee80211_rx_stats *stats, - const struct rx_status *status) +/** + * filter_ack - filters incoming packets for acknowledgements + * @dev: the mac80211 device + * @rx_hdr: received header + * @stats: the status for the received packet + * + * This functions looks for ACK packets and tries to match them with the + * frames in the tx queue. If a match is found the frame will be dequeued and + * the upper layers is informed about the successful transmission. If + * mac80211 queues have been stopped and the number of frames still to be + * transmitted is low the queues will be opened again. + * + * Returns 1 if the frame was an ACK, 0 if it was ignored. + */ +static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, + struct ieee80211_rx_status *stats) { - struct zd_rt_hdr *hdr = buffer; - - hdr->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - hdr->rt_hdr.it_pad = 0; - hdr->rt_hdr.it_len = cpu_to_le16(sizeof(struct zd_rt_hdr)); - hdr->rt_hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_RATE)); - - hdr->rt_flags = 0; - if (status->decryption_type & (ZD_RX_WEP64|ZD_RX_WEP128|ZD_RX_WEP256)) - hdr->rt_flags |= IEEE80211_RADIOTAP_F_WEP; - - hdr->rt_rate = stats->rate / 5; - - /* FIXME: 802.11a */ - hdr->rt_channel = cpu_to_le16(ieee80211chan2mhz( - _zd_chip_get_channel(&mac->chip))); - hdr->rt_chbitmask = cpu_to_le16(IEEE80211_CHAN_2GHZ | - ((status->frame_status & ZD_RX_FRAME_MODULATION_MASK) == - ZD_RX_OFDM ? IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK)); + struct zd_mac *mac = zd_hw_mac(hw); + struct sk_buff *skb; + struct sk_buff_head *q; + unsigned long flags; + int found = 0; + int i, position = 0; + + if (!ieee80211_is_ack(rx_hdr->frame_control)) + return 0; + + q = &mac->ack_wait_queue; + spin_lock_irqsave(&q->lock, flags); + skb_queue_walk(q, skb) { + struct ieee80211_hdr *tx_hdr; + + position ++; + + if (mac->ack_pending && skb_queue_is_first(q, skb)) + continue; + + tx_hdr = (struct ieee80211_hdr *)skb->data; + if (likely(ether_addr_equal(tx_hdr->addr2, rx_hdr->addr1))) + { + found = 1; + break; + } + } + + if (found) { + for (i=1; i<position; i++) { + skb = __skb_dequeue(q); + zd_mac_tx_status(hw, skb, + mac->ack_pending ? mac->ack_signal : 0, + NULL); + mac->ack_pending = 0; + } + + mac->ack_pending = 1; + mac->ack_signal = stats->signal; + + /* Prevent pending tx-packet on AP-mode */ + if (mac->type == NL80211_IFTYPE_AP) { + skb = __skb_dequeue(q); + zd_mac_tx_status(hw, skb, mac->ack_signal, NULL); + mac->ack_pending = 0; + } + } + + spin_unlock_irqrestore(&q->lock, flags); + return 1; } -/* Returns 1 if the data packet is for us and 0 otherwise. */ -static int is_data_packet_for_us(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *hdr) +int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) { - struct net_device *netdev = ieee->dev; - u16 fc = le16_to_cpu(hdr->frame_ctl); + struct zd_mac *mac = zd_hw_mac(hw); + struct ieee80211_rx_status stats; + const struct rx_status *status; + struct sk_buff *skb; + int bad_frame = 0; + __le16 fc; + int need_padding; + int i; + u8 rate; - ZD_ASSERT(WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA); + if (length < ZD_PLCP_HEADER_SIZE + 10 /* IEEE80211_1ADDR_LEN */ + + FCS_LEN + sizeof(struct rx_status)) + return -EINVAL; - switch (ieee->iw_mode) { - case IW_MODE_ADHOC: - if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 || - memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0) - return 0; - break; - case IW_MODE_AUTO: - case IW_MODE_INFRA: - if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != - IEEE80211_FCTL_FROMDS || - memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0) - return 0; + memset(&stats, 0, sizeof(stats)); + + /* Note about pass_failed_fcs and pass_ctrl access below: + * mac locking intentionally omitted here, as this is the only unlocked + * reader and the only writer is configure_filter. Plus, if there were + * any races accessing these variables, it wouldn't really matter. + * If mac80211 ever provides a way for us to access filter flags + * from outside configure_filter, we could improve on this. Also, this + * situation may change once we implement some kind of DMA-into-skb + * RX path. */ + + /* Caller has to ensure that length >= sizeof(struct rx_status). */ + status = (struct rx_status *) + (buffer + (length - sizeof(struct rx_status))); + if (status->frame_status & ZD_RX_ERROR) { + if (mac->pass_failed_fcs && + (status->frame_status & ZD_RX_CRC32_ERROR)) { + stats.flag |= RX_FLAG_FAILED_FCS_CRC; + bad_frame = 1; + } else { + return -EINVAL; + } + } + + stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq; + stats.band = IEEE80211_BAND_2GHZ; + stats.signal = zd_check_signal(hw, status->signal_strength); + + rate = zd_rx_rate(buffer, status); + + /* todo: return index in the big switches in zd_rx_rate instead */ + for (i = 0; i < mac->band.n_bitrates; i++) + if (rate == mac->band.bitrates[i].hw_value) + stats.rate_idx = i; + + length -= ZD_PLCP_HEADER_SIZE + sizeof(struct rx_status); + buffer += ZD_PLCP_HEADER_SIZE; + + /* Except for bad frames, filter each frame to see if it is an ACK, in + * which case our internal TX tracking is updated. Normally we then + * bail here as there's no need to pass ACKs on up to the stack, but + * there is also the case where the stack has requested us to pass + * control frames on up (pass_ctrl) which we must consider. */ + if (!bad_frame && + filter_ack(hw, (struct ieee80211_hdr *)buffer, &stats) + && !mac->pass_ctrl) + return 0; + + fc = get_unaligned((__le16*)buffer); + need_padding = ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc); + + skb = dev_alloc_skb(length + (need_padding ? 2 : 0)); + if (skb == NULL) + return -ENOMEM; + if (need_padding) { + /* Make sure the payload data is 4 byte aligned. */ + skb_reserve(skb, 2); + } + + /* FIXME : could we avoid this big memcpy ? */ + memcpy(skb_put(skb, length), buffer, length); + + memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats)); + ieee80211_rx_irqsafe(hw, skb); + return 0; +} + +static int zd_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct zd_mac *mac = zd_hw_mac(hw); + + /* using NL80211_IFTYPE_UNSPECIFIED to indicate no mode selected */ + if (mac->type != NL80211_IFTYPE_UNSPECIFIED) + return -EOPNOTSUPP; + + switch (vif->type) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + mac->type = vif->type; break; default: - ZD_ASSERT(ieee->iw_mode != IW_MODE_MONITOR); - return 0; + return -EOPNOTSUPP; } - return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 || - is_multicast_ether_addr(hdr->addr1) || - (netdev->flags & IFF_PROMISC); + mac->vif = vif; + + return set_mac_and_bssid(mac); } -/* 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. - * - * It has been based on ieee80211_rx_any. - */ -static int filter_rx(struct ieee80211_device *ieee, - const u8 *buffer, unsigned int length, - struct ieee80211_rx_stats *stats) +static void zd_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { - struct ieee80211_hdr_4addr *hdr; - u16 fc; + struct zd_mac *mac = zd_hw_mac(hw); + mac->type = NL80211_IFTYPE_UNSPECIFIED; + mac->vif = NULL; + zd_set_beacon_interval(&mac->chip, 0, 0, NL80211_IFTYPE_UNSPECIFIED); + zd_write_mac_addr(&mac->chip, NULL); - if (ieee->iw_mode == IW_MODE_MONITOR) - return 1; + zd_mac_free_cur_beacon(mac); +} - hdr = (struct ieee80211_hdr_4addr *)buffer; - fc = le16_to_cpu(hdr->frame_ctl); - if ((fc & IEEE80211_FCTL_VERS) != 0) - return -EINVAL; +static int zd_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct zd_mac *mac = zd_hw_mac(hw); + struct ieee80211_conf *conf = &hw->conf; - switch (WLAN_FC_GET_TYPE(fc)) { - case IEEE80211_FTYPE_MGMT: - if (length < sizeof(struct ieee80211_hdr_3addr)) - return -EINVAL; - ieee80211_rx_mgt(ieee, hdr, stats); - return 0; - case IEEE80211_FTYPE_CTL: - /* Ignore invalid short buffers */ - return 0; - case IEEE80211_FTYPE_DATA: - if (length < sizeof(struct ieee80211_hdr_3addr)) - return -EINVAL; - return is_data_packet_for_us(ieee, hdr); - } + spin_lock_irq(&mac->lock); + mac->channel = conf->chandef.chan->hw_value; + spin_unlock_irq(&mac->lock); - return -EINVAL; + return zd_chip_set_channel(&mac->chip, conf->chandef.chan->hw_value); } -static void update_qual_rssi(struct zd_mac *mac, - const u8 *buffer, unsigned int length, - u8 qual_percent, u8 rssi_percent) +static void zd_beacon_done(struct zd_mac *mac) { - unsigned long flags; - struct ieee80211_hdr_3addr *hdr; - int i; + struct sk_buff *skb, *beacon; - hdr = (struct ieee80211_hdr_3addr *)buffer; - if (length < offsetof(struct ieee80211_hdr_3addr, addr3)) + if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags)) return; - if (memcmp(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid, ETH_ALEN) != 0) + if (!mac->vif || mac->vif->type != NL80211_IFTYPE_AP) return; + /* + * Send out buffered broad- and multicast frames. + */ + while (!ieee80211_queue_stopped(mac->hw, 0)) { + skb = ieee80211_get_buffered_bc(mac->hw, mac->vif); + if (!skb) + break; + zd_op_tx(mac->hw, NULL, skb); + } + + /* + * Fetch next beacon so that tim_count is updated. + */ + beacon = ieee80211_beacon_get(mac->hw, mac->vif); + if (beacon) + zd_mac_config_beacon(mac->hw, beacon, true); + + spin_lock_irq(&mac->lock); + mac->beacon.last_update = jiffies; + spin_unlock_irq(&mac->lock); +} + +static void zd_process_intr(struct work_struct *work) +{ + u16 int_status; + unsigned long flags; + struct zd_mac *mac = container_of(work, struct zd_mac, process_intr); + spin_lock_irqsave(&mac->lock, flags); - i = mac->stats_count % ZD_MAC_STATS_BUFFER_SIZE; - mac->qual_buffer[i] = qual_percent; - mac->rssi_buffer[i] = rssi_percent; - mac->stats_count++; + int_status = le16_to_cpu(*(__le16 *)(mac->intr_buffer + 4)); spin_unlock_irqrestore(&mac->lock, flags); + + if (int_status & INT_CFG_NEXT_BCN) { + /*dev_dbg_f_limit(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");*/ + zd_beacon_done(mac); + } else { + dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n"); + } + + zd_chip_enable_hwint(&mac->chip); } -static int fill_rx_stats(struct ieee80211_rx_stats *stats, - const struct rx_status **pstatus, - struct zd_mac *mac, - const u8 *buffer, unsigned int length) + +static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw, + struct netdev_hw_addr_list *mc_list) { - const struct rx_status *status; + struct zd_mac *mac = zd_hw_mac(hw); + struct zd_mc_hash hash; + struct netdev_hw_addr *ha; - *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status)); - if (status->frame_status & ZD_RX_ERROR) { - /* FIXME: update? */ - return -EINVAL; + zd_mc_clear(&hash); + + netdev_hw_addr_list_for_each(ha, mc_list) { + dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", ha->addr); + zd_mc_add_addr(&hash, ha->addr); } - memset(stats, 0, sizeof(struct ieee80211_rx_stats)); - stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN + - + sizeof(struct rx_status)); - /* FIXME: 802.11a */ - stats->freq = IEEE80211_24GHZ_BAND; - stats->received_channel = _zd_chip_get_channel(&mac->chip); - stats->rssi = zd_rx_strength_percent(status->signal_strength); - stats->signal = zd_rx_qual_percent(buffer, - length - sizeof(struct rx_status), - status); - stats->mask = IEEE80211_STATMASK_RSSI | IEEE80211_STATMASK_SIGNAL; - stats->rate = zd_rx_rate(buffer, status); - if (stats->rate) - stats->mask |= IEEE80211_STATMASK_RATE; - return 0; + return hash.low | ((u64)hash.high << 32); } -int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length) +#define SUPPORTED_FIF_FLAGS \ + (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \ + FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC) +static void zd_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *new_flags, + u64 multicast) { + struct zd_mc_hash hash = { + .low = multicast, + .high = multicast >> 32, + }; + struct zd_mac *mac = zd_hw_mac(hw); + unsigned long flags; int r; - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - struct ieee80211_rx_stats stats; - const struct rx_status *status; - struct sk_buff *skb; - if (length < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN + - IEEE80211_FCS_LEN + sizeof(struct rx_status)) - return -EINVAL; - - r = fill_rx_stats(&stats, &status, mac, buffer, length); - if (r) - return r; + /* Only deal with supported flags */ + changed_flags &= SUPPORTED_FIF_FLAGS; + *new_flags &= SUPPORTED_FIF_FLAGS; - length -= ZD_PLCP_HEADER_SIZE+IEEE80211_FCS_LEN+ - sizeof(struct rx_status); - buffer += ZD_PLCP_HEADER_SIZE; - - update_qual_rssi(mac, buffer, length, stats.signal, stats.rssi); + /* + * If multicast parameter (as returned by zd_op_prepare_multicast) + * has changed, no bit in changed_flags is set. To handle this + * situation, we do not return if changed_flags is 0. If we do so, + * we will have some issue with IPv6 which uses multicast for link + * layer address resolution. + */ + if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) + zd_mc_add_all(&hash); - r = filter_rx(ieee, buffer, length, &stats); - if (r <= 0) - return r; + spin_lock_irqsave(&mac->lock, flags); + mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL); + mac->pass_ctrl = !!(*new_flags & FIF_CONTROL); + mac->multicast_hash = hash; + spin_unlock_irqrestore(&mac->lock, flags); - skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length); - if (!skb) - return -ENOMEM; - if (ieee->iw_mode == IW_MODE_MONITOR) - fill_rt_header(skb_put(skb, sizeof(struct zd_rt_hdr)), mac, - &stats, status); - memcpy(skb_put(skb, length), buffer, length); + zd_chip_set_multicast_hash(&mac->chip, &hash); - r = ieee80211_rx(ieee, skb, &stats); - if (!r) { - ZD_ASSERT(in_irq()); - dev_kfree_skb_irq(skb); + if (changed_flags & FIF_CONTROL) { + r = set_rx_filter(mac); + if (r) + dev_err(zd_mac_dev(mac), "set_rx_filter error %d\n", r); } - return 0; + + /* no handling required for FIF_OTHER_BSS as we don't currently + * do BSSID filtering */ + /* FIXME: in future it would be nice to enable the probe response + * filter (so that the driver doesn't see them) until + * FIF_BCN_PRBRESP_PROMISC is set. however due to atomicity here, we'd + * have to schedule work to enable prbresp reception, which might + * happen too late. For now we'll just listen and forward them all the + * time. */ } -static int netdev_tx(struct ieee80211_txb *txb, struct net_device *netdev, - int pri) +static void set_rts_cts(struct zd_mac *mac, unsigned int short_preamble) { - return zd_mac_tx(zd_netdev_mac(netdev), txb, pri); + mutex_lock(&mac->chip.mutex); + zd_chip_set_rts_cts_rate_locked(&mac->chip, short_preamble); + mutex_unlock(&mac->chip.mutex); } -static void set_security(struct net_device *netdev, - struct ieee80211_security *sec) +static void zd_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) { - struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev); - struct ieee80211_security *secinfo = &ieee->sec; - int keyidx; - - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n"); - - for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) - if (sec->flags & (1<<keyidx)) { - secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx]; - secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx]; - memcpy(secinfo->keys[keyidx], sec->keys[keyidx], - SCM_KEY_LEN); + struct zd_mac *mac = zd_hw_mac(hw); + int associated; + + dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes); + + if (mac->type == NL80211_IFTYPE_MESH_POINT || + mac->type == NL80211_IFTYPE_ADHOC || + mac->type == NL80211_IFTYPE_AP) { + associated = true; + if (changes & BSS_CHANGED_BEACON) { + struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); + + if (beacon) { + zd_chip_disable_hwint(&mac->chip); + zd_mac_config_beacon(hw, beacon, false); + zd_chip_enable_hwint(&mac->chip); + } } - if (sec->flags & SEC_ACTIVE_KEY) { - secinfo->active_key = sec->active_key; - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), - " .active_key = %d\n", sec->active_key); - } - if (sec->flags & SEC_UNICAST_GROUP) { - secinfo->unicast_uses_group = sec->unicast_uses_group; - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), - " .unicast_uses_group = %d\n", - sec->unicast_uses_group); - } - if (sec->flags & SEC_LEVEL) { - secinfo->level = sec->level; - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), - " .level = %d\n", sec->level); - } - if (sec->flags & SEC_ENABLED) { - secinfo->enabled = sec->enabled; - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), - " .enabled = %d\n", sec->enabled); - } - if (sec->flags & SEC_ENCRYPT) { - secinfo->encrypt = sec->encrypt; - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), - " .encrypt = %d\n", sec->encrypt); - } - if (sec->flags & SEC_AUTH_MODE) { - secinfo->auth_mode = sec->auth_mode; - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), - " .auth_mode = %d\n", sec->auth_mode); + if (changes & BSS_CHANGED_BEACON_ENABLED) { + u16 interval = 0; + u8 period = 0; + + if (bss_conf->enable_beacon) { + period = bss_conf->dtim_period; + interval = bss_conf->beacon_int; + } + + spin_lock_irq(&mac->lock); + mac->beacon.period = period; + mac->beacon.interval = interval; + mac->beacon.last_update = jiffies; + spin_unlock_irq(&mac->lock); + + zd_set_beacon_interval(&mac->chip, interval, period, + mac->type); + } + } else + associated = is_valid_ether_addr(bss_conf->bssid); + + spin_lock_irq(&mac->lock); + mac->associated = associated; + spin_unlock_irq(&mac->lock); + + /* TODO: do hardware bssid filtering */ + + if (changes & BSS_CHANGED_ERP_PREAMBLE) { + spin_lock_irq(&mac->lock); + mac->short_preamble = bss_conf->use_short_preamble; + spin_unlock_irq(&mac->lock); + + set_rts_cts(mac, bss_conf->use_short_preamble); } } -static void ieee_init(struct ieee80211_device *ieee) +static u64 zd_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - ieee->mode = IEEE_B | IEEE_G; - ieee->freq_band = IEEE80211_24GHZ_BAND; - ieee->modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION; - ieee->tx_headroom = sizeof(struct zd_ctrlset); - ieee->set_security = set_security; - ieee->hard_start_xmit = netdev_tx; - - /* Software encryption/decryption for now */ - ieee->host_build_iv = 0; - ieee->host_encrypt = 1; - ieee->host_decrypt = 1; - - /* FIXME: default to managed mode, until ieee80211 and zd1211rw can - * correctly support AUTO */ - ieee->iw_mode = IW_MODE_INFRA; + struct zd_mac *mac = zd_hw_mac(hw); + return zd_chip_get_tsf(&mac->chip); } -static void softmac_init(struct ieee80211softmac_device *sm) +static const struct ieee80211_ops zd_ops = { + .tx = zd_op_tx, + .start = zd_op_start, + .stop = zd_op_stop, + .add_interface = zd_op_add_interface, + .remove_interface = zd_op_remove_interface, + .config = zd_op_config, + .prepare_multicast = zd_op_prepare_multicast, + .configure_filter = zd_op_configure_filter, + .bss_info_changed = zd_op_bss_info_changed, + .get_tsf = zd_op_get_tsf, +}; + +struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) { - sm->set_channel = set_channel; + struct zd_mac *mac; + struct ieee80211_hw *hw; + + hw = ieee80211_alloc_hw(sizeof(struct zd_mac), &zd_ops); + if (!hw) { + dev_dbg_f(&intf->dev, "out of memory\n"); + return NULL; + } + + mac = zd_hw_mac(hw); + + memset(mac, 0, sizeof(*mac)); + spin_lock_init(&mac->lock); + mac->hw = hw; + + mac->type = NL80211_IFTYPE_UNSPECIFIED; + + memcpy(mac->channels, zd_channels, sizeof(zd_channels)); + memcpy(mac->rates, zd_rates, sizeof(zd_rates)); + mac->band.n_bitrates = ARRAY_SIZE(zd_rates); + mac->band.bitrates = mac->rates; + mac->band.n_channels = ARRAY_SIZE(zd_channels); + mac->band.channels = mac->channels; + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; + + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_UNSPEC | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_MFP_CAPABLE; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP); + + hw->max_signal = 100; + hw->queues = 1; + hw->extra_tx_headroom = sizeof(struct zd_ctrlset); + + /* + * Tell mac80211 that we support multi rate retries + */ + hw->max_rates = IEEE80211_TX_MAX_RATES; + hw->max_rate_tries = 18; /* 9 rates * 2 retries/rate */ + + skb_queue_head_init(&mac->ack_wait_queue); + mac->ack_pending = 0; + + zd_chip_init(&mac->chip, hw, intf); + housekeeping_init(mac); + beacon_init(mac); + INIT_WORK(&mac->process_intr, zd_process_intr); + + SET_IEEE80211_DEV(hw, &intf->dev); + return hw; } -struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev) +#define BEACON_WATCHDOG_DELAY round_jiffies_relative(HZ) + +static void beacon_watchdog_handler(struct work_struct *work) { - struct zd_mac *mac = zd_netdev_mac(ndev); - struct iw_statistics *iw_stats = &mac->iw_stats; - unsigned int i, count, qual_total, rssi_total; + struct zd_mac *mac = + container_of(work, struct zd_mac, beacon.watchdog_work.work); + struct sk_buff *beacon; + unsigned long timeout; + int interval, period; + + if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags)) + goto rearm; + if (mac->type != NL80211_IFTYPE_AP || !mac->vif) + goto rearm; - memset(iw_stats, 0, sizeof(struct iw_statistics)); - /* We are not setting the status, because ieee->state is not updated - * at all and this driver doesn't track authentication state. - */ spin_lock_irq(&mac->lock); - count = mac->stats_count < ZD_MAC_STATS_BUFFER_SIZE ? - mac->stats_count : ZD_MAC_STATS_BUFFER_SIZE; - qual_total = rssi_total = 0; - for (i = 0; i < count; i++) { - qual_total += mac->qual_buffer[i]; - rssi_total += mac->rssi_buffer[i]; - } + interval = mac->beacon.interval; + period = mac->beacon.period; + timeout = mac->beacon.last_update + + msecs_to_jiffies(interval * 1024 / 1000) * 3; spin_unlock_irq(&mac->lock); - iw_stats->qual.updated = IW_QUAL_NOISE_INVALID; - if (count > 0) { - iw_stats->qual.qual = qual_total / count; - iw_stats->qual.level = rssi_total / count; - iw_stats->qual.updated |= - IW_QUAL_QUAL_UPDATED|IW_QUAL_LEVEL_UPDATED; - } else { - iw_stats->qual.updated |= - IW_QUAL_QUAL_INVALID|IW_QUAL_LEVEL_INVALID; - } - /* TODO: update counter */ - 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", -}; + if (interval > 0 && time_is_before_jiffies(timeout)) { + dev_dbg_f(zd_mac_dev(mac), "beacon interrupt stalled, " + "restarting. " + "(interval: %d, dtim: %d)\n", + interval, period); -static const char *decryption_type_string(u8 type) -{ - const char *s; + zd_chip_disable_hwint(&mac->chip); - if (type < ARRAY_SIZE(decryption_types)) { - s = decryption_types[type]; - } else { - s = NULL; + beacon = ieee80211_beacon_get(mac->hw, mac->vif); + if (beacon) { + zd_mac_free_cur_beacon(mac); + + zd_mac_config_beacon(mac->hw, beacon, false); + } + + zd_set_beacon_interval(&mac->chip, interval, period, mac->type); + + zd_chip_enable_hwint(&mac->chip); + + spin_lock_irq(&mac->lock); + mac->beacon.last_update = jiffies; + spin_unlock_irq(&mac->lock); } - return s ? s : "unknown"; + +rearm: + queue_delayed_work(zd_workqueue, &mac->beacon.watchdog_work, + BEACON_WATCHDOG_DELAY); } -static int is_ofdm(u8 frame_status) +static void beacon_init(struct zd_mac *mac) { - return (frame_status & ZD_RX_OFDM); + INIT_DELAYED_WORK(&mac->beacon.watchdog_work, beacon_watchdog_handler); } -void zd_dump_rx_status(const struct rx_status *status) +static void beacon_enable(struct zd_mac *mac) { - const char* modulation; - u8 quality; + dev_dbg_f(zd_mac_dev(mac), "\n"); - 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" : ""); - } + mac->beacon.last_update = jiffies; + queue_delayed_work(zd_workqueue, &mac->beacon.watchdog_work, + BEACON_WATCHDOG_DELAY); +} + +static void beacon_disable(struct zd_mac *mac) +{ + dev_dbg_f(zd_mac_dev(mac), "\n"); + cancel_delayed_work_sync(&mac->beacon.watchdog_work); + + zd_mac_free_cur_beacon(mac); } -#endif /* DEBUG */ #define LINK_LED_WORK_DELAY HZ -static void link_led_handler(void *p) +static void link_led_handler(struct work_struct *work) { - struct zd_mac *mac = p; + 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 (!test_bit(ZD_DEVICE_RUNNING, &mac->flags)) + goto requeue; + spin_lock_irq(&mac->lock); - is_associated = sm->associated != 0; + is_associated = mac->associated; spin_unlock_irq(&mac->lock); r = zd_chip_control_leds(chip, - is_associated ? LED_ASSOCIATED : LED_SCANNING); + is_associated ? ZD_LED_ASSOCIATED : ZD_LED_SCANNING); if (r) - dev_err(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); + dev_dbg_f(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); +requeue: queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work, LINK_LED_WORK_DELAY); } static void housekeeping_init(struct zd_mac *mac) { - INIT_WORK(&mac->housekeeping.link_led_work, link_led_handler, mac); + INIT_DELAYED_WORK(&mac->housekeeping.link_led_work, link_led_handler); } static void housekeeping_enable(struct zd_mac *mac) @@ -1126,7 +1545,6 @@ static void housekeeping_enable(struct zd_mac *mac) 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); + cancel_delayed_work_sync(&mac->housekeeping.link_led_work); + zd_chip_control_leds(&mac->chip, ZD_LED_OFF); } diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index b8ea3de7924..5a484235308 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -1,4 +1,7 @@ -/* zd_mac.h +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,20 +14,16 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #ifndef _ZD_MAC_H #define _ZD_MAC_H -#include <linux/wireless.h> #include <linux/kernel.h> -#include <net/ieee80211.h> -#include <net/ieee80211softmac.h> +#include <net/mac80211.h> #include "zd_chip.h" -#include "zd_netdev.h" struct zd_ctrlset { u8 modulation; @@ -35,35 +34,59 @@ struct zd_ctrlset { __le16 current_length; u8 service; __le16 next_frame_length; -} __attribute__((packed)); +} __packed; #define ZD_CS_RESERVED_SIZE 25 -/* zd_crtlset field modulation */ -#define ZD_CS_RATE_MASK 0x0f -#define ZD_CS_TYPE_MASK 0x10 -#define ZD_CS_RATE(modulation) ((modulation) & ZD_CS_RATE_MASK) -#define ZD_CS_TYPE(modulation) ((modulation) & ZD_CS_TYPE_MASK) - -#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 -/* The rates for OFDM are encoded as in the PLCP header. Use ZD_OFDM_RATE_*. +/* The field modulation of struct zd_ctrlset controls the bit rate, the use + * of short or long preambles in 802.11b (CCK mode) or the use of 802.11a or + * 802.11g in OFDM mode. + * + * The term zd-rate is used for the combination of the modulation type flag + * and the "pure" rate value. + */ +#define ZD_PURE_RATE_MASK 0x0f +#define ZD_MODULATION_TYPE_MASK 0x10 +#define ZD_RATE_MASK (ZD_PURE_RATE_MASK|ZD_MODULATION_TYPE_MASK) +#define ZD_PURE_RATE(modulation) ((modulation) & ZD_PURE_RATE_MASK) +#define ZD_MODULATION_TYPE(modulation) ((modulation) & ZD_MODULATION_TYPE_MASK) +#define ZD_RATE(modulation) ((modulation) & ZD_RATE_MASK) + +/* The two possible modulation types. Notify that 802.11b doesn't use the CCK + * codeing for the 1 and 2 MBit/s rate. We stay with the term here to remain + * consistent with uses the term at other places. */ +#define ZD_CCK 0x00 +#define ZD_OFDM 0x10 -/* bit 5 is preamble (when in CCK mode), or a/g selection (when in OFDM mode) */ -#define ZD_CS_CCK_PREA_LONG 0x00 -#define ZD_CS_CCK_PREA_SHORT 0x20 -#define ZD_CS_OFDM_MODE_11G 0x00 -#define ZD_CS_OFDM_MODE_11A 0x20 +/* The ZD1211 firmware uses proprietary encodings of the 802.11b (CCK) rates. + * For OFDM the PLCP rate encodings are used. We combine these "pure" rates + * with the modulation type flag and call the resulting values zd-rates. + */ +#define ZD_CCK_RATE_1M (ZD_CCK|0x00) +#define ZD_CCK_RATE_2M (ZD_CCK|0x01) +#define ZD_CCK_RATE_5_5M (ZD_CCK|0x02) +#define ZD_CCK_RATE_11M (ZD_CCK|0x03) +#define ZD_OFDM_RATE_6M (ZD_OFDM|ZD_OFDM_PLCP_RATE_6M) +#define ZD_OFDM_RATE_9M (ZD_OFDM|ZD_OFDM_PLCP_RATE_9M) +#define ZD_OFDM_RATE_12M (ZD_OFDM|ZD_OFDM_PLCP_RATE_12M) +#define ZD_OFDM_RATE_18M (ZD_OFDM|ZD_OFDM_PLCP_RATE_18M) +#define ZD_OFDM_RATE_24M (ZD_OFDM|ZD_OFDM_PLCP_RATE_24M) +#define ZD_OFDM_RATE_36M (ZD_OFDM|ZD_OFDM_PLCP_RATE_36M) +#define ZD_OFDM_RATE_48M (ZD_OFDM|ZD_OFDM_PLCP_RATE_48M) +#define ZD_OFDM_RATE_54M (ZD_OFDM|ZD_OFDM_PLCP_RATE_54M) + +/* The bit 5 of the zd_ctrlset modulation field controls the preamble in CCK + * mode or the 802.11a/802.11g selection in OFDM mode. + */ +#define ZD_CCK_PREA_LONG 0x00 +#define ZD_CCK_PREA_SHORT 0x20 +#define ZD_OFDM_MODE_11G 0x00 +#define ZD_OFDM_MODE_11A 0x20 /* zd_ctrlset control field */ #define ZD_CS_NEED_RANDOM_BACKOFF 0x01 -#define ZD_CS_MULTICAST 0x02 +#define ZD_CS_NO_ACK 0x02 #define ZD_CS_FRAME_TYPE_MASK 0x0c #define ZD_CS_DATA_FRAME 0x00 @@ -82,7 +105,7 @@ struct zd_ctrlset { struct rx_length_info { __le16 length[3]; __le16 tag; -}; +} __packed; #define RX_LENGTH_INFO_TAG 0x697e @@ -93,7 +116,7 @@ struct rx_status { u8 signal_quality_ofdm; u8 decryption_type; u8 frame_status; -}; +} __packed; /* rx_status field decryption_type */ #define ZD_RX_NO_WEP 0 @@ -116,39 +139,152 @@ struct rx_status { #define ZD_RX_CRC16_ERROR 0x40 #define ZD_RX_ERROR 0x80 +struct tx_retry_rate { + int count; /* number of valid element in rate[] array */ + int rate[10]; /* retry rates, described by an index in zd_rates[] */ +}; + +struct tx_status { + u8 type; /* must always be 0x01 : USB_INT_TYPE */ + u8 id; /* must always be 0xa0 : USB_INT_ID_RETRY_FAILED */ + u8 rate; + u8 pad; + u8 mac[ETH_ALEN]; + u8 retry; + u8 failure; +} __packed; + enum mac_flags { MAC_FIXED_CHANNEL = 0x01, }; struct housekeeping { - struct work_struct link_led_work; + struct delayed_work link_led_work; +}; + +struct beacon { + struct delayed_work watchdog_work; + struct sk_buff *cur_beacon; + unsigned long last_update; + u16 interval; + u8 period; +}; + +enum zd_device_flags { + ZD_DEVICE_RUNNING, }; #define ZD_MAC_STATS_BUFFER_SIZE 16 +#define ZD_MAC_MAX_ACK_WAITERS 50 + struct zd_mac { struct zd_chip chip; spinlock_t lock; - struct net_device *netdev; - /* Unlocked reading possible */ - struct iw_statistics iw_stats; + spinlock_t intr_lock; + struct ieee80211_hw *hw; + struct ieee80211_vif *vif; struct housekeeping housekeeping; - unsigned int stats_count; - u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE]; - u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE]; + struct beacon beacon; + struct work_struct set_rts_cts_work; + struct work_struct process_intr; + struct zd_mc_hash multicast_hash; + u8 intr_buffer[USB_MAX_EP_INT_BUFFER]; u8 regdomain; u8 default_regdomain; - u8 requested_channel; + u8 channel; + int type; + int associated; + unsigned long flags; + struct sk_buff_head ack_wait_queue; + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[12]; + struct ieee80211_supported_band band; + + /* Short preamble (used for RTS/CTS) */ + unsigned int short_preamble:1; + + /* whether to pass frames with CRC errors to stack */ + unsigned int pass_failed_fcs:1; + + /* whether to pass control frames to stack */ + unsigned int pass_ctrl:1; + + /* whether we have received a 802.11 ACK that is pending */ + unsigned int ack_pending:1; + + /* signal strength of the last 802.11 ACK received */ + int ack_signal; +}; + +#define ZD_REGDOMAIN_FCC 0x10 +#define ZD_REGDOMAIN_IC 0x20 +#define ZD_REGDOMAIN_ETSI 0x30 +#define ZD_REGDOMAIN_SPAIN 0x31 +#define ZD_REGDOMAIN_FRANCE 0x32 +#define ZD_REGDOMAIN_JAPAN_2 0x40 +#define ZD_REGDOMAIN_JAPAN 0x41 +#define ZD_REGDOMAIN_JAPAN_3 0x49 + +enum { + MIN_CHANNEL24 = 1, + MAX_CHANNEL24 = 14, }; -static inline struct ieee80211_device *zd_mac_to_ieee80211(struct zd_mac *mac) +#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80 + +struct ofdm_plcp_header { + u8 prefix[3]; + __le16 service; +} __packed; + +static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header) { - return zd_netdev_ieee80211(mac->netdev); + return header->prefix[0] & 0xf; } -static inline struct zd_mac *zd_netdev_mac(struct net_device *netdev) +/* The following defines give the encoding of the 4-bit rate field in the + * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to + * define the zd-rate values for OFDM. + * + * See the struct zd_ctrlset definition in zd_mac.h. + */ +#define ZD_OFDM_PLCP_RATE_6M 0xb +#define ZD_OFDM_PLCP_RATE_9M 0xf +#define ZD_OFDM_PLCP_RATE_12M 0xa +#define ZD_OFDM_PLCP_RATE_18M 0xe +#define ZD_OFDM_PLCP_RATE_24M 0x9 +#define ZD_OFDM_PLCP_RATE_36M 0xd +#define ZD_OFDM_PLCP_RATE_48M 0x8 +#define ZD_OFDM_PLCP_RATE_54M 0xc + +struct cck_plcp_header { + u8 signal; + u8 service; + __le16 length; + __le16 crc16; +} __packed; + +static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header) { - return ieee80211softmac_priv(netdev); + return header->signal; +} + +/* These defines give the encodings of the signal field in the 802.11b PLCP + * header. The signal field gives the bit rate of the following packet. Even + * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s + * rate to stay consistent with Zydas and our use of the term. + * + * Notify that these values are *not* used in the zd-rates. + */ +#define ZD_CCK_PLCP_SIGNAL_1M 0x0a +#define ZD_CCK_PLCP_SIGNAL_2M 0x14 +#define ZD_CCK_PLCP_SIGNAL_5M5 0x37 +#define ZD_CCK_PLCP_SIGNAL_11M 0x6e + +static inline struct zd_mac *zd_hw_mac(struct ieee80211_hw *hw) +{ + return hw->priv; } static inline struct zd_mac *zd_chip_to_mac(struct zd_chip *chip) @@ -161,33 +297,26 @@ static inline struct zd_mac *zd_usb_to_mac(struct zd_usb *usb) return zd_chip_to_mac(zd_usb_to_chip(usb)); } +static inline u8 *zd_mac_get_perm_addr(struct zd_mac *mac) +{ + return mac->hw->wiphy->perm_addr; +} + #define zd_mac_dev(mac) (zd_chip_dev(&(mac)->chip)) -int zd_mac_init(struct zd_mac *mac, - struct net_device *netdev, - struct usb_interface *intf); +struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf); void zd_mac_clear(struct zd_mac *mac); -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); - -int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length); - -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); - -int zd_mac_set_mode(struct zd_mac *mac, u32 mode); -int zd_mac_get_mode(struct zd_mac *mac, u32 *mode); +int zd_mac_preinit_hw(struct ieee80211_hw *hw); +int zd_mac_init_hw(struct ieee80211_hw *hw); -int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range); +int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length); +void zd_mac_tx_failed(struct urb *urb); +void zd_mac_tx_to_dev(struct sk_buff *skb, int error); -struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev); +int zd_op_start(struct ieee80211_hw *hw); +void zd_op_stop(struct ieee80211_hw *hw); +int zd_restore_settings(struct zd_mac *mac); #ifdef DEBUG void zd_dump_rx_status(const struct rx_status *status); diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c deleted file mode 100644 index af3a7b36d07..00000000000 --- a/drivers/net/wireless/zd1211rw/zd_netdev.c +++ /dev/null @@ -1,276 +0,0 @@ -/* zd_netdev.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <net/ieee80211.h> -#include <net/ieee80211softmac.h> -#include <net/ieee80211softmac_wx.h> -#include <net/iw_handler.h> - -#include "zd_def.h" -#include "zd_netdev.h" -#include "zd_mac.h" -#include "zd_ieee80211.h" - -/* Region 0 means reset regdomain to default. */ -static int zd_set_regdomain(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - const u8 *regdomain = (u8 *)req; - return zd_mac_set_regdomain(zd_netdev_mac(netdev), *regdomain); -} - -static int zd_get_regdomain(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - u8 *regdomain = (u8 *)req; - if (!regdomain) - return -EINVAL; - *regdomain = zd_mac_get_regdomain(zd_netdev_mac(netdev)); - return 0; -} - -static const struct iw_priv_args zd_priv_args[] = { - { - .cmd = ZD_PRIV_SET_REGDOMAIN, - .set_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - .name = "set_regdomain", - }, - { - .cmd = ZD_PRIV_GET_REGDOMAIN, - .get_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - .name = "get_regdomain", - }, -}; - -#define PRIV_OFFSET(x) [(x)-SIOCIWFIRSTPRIV] - -static const iw_handler zd_priv_handler[] = { - PRIV_OFFSET(ZD_PRIV_SET_REGDOMAIN) = zd_set_regdomain, - PRIV_OFFSET(ZD_PRIV_GET_REGDOMAIN) = zd_get_regdomain, -}; - -static int iw_get_name(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - /* FIXME: check whether 802.11a will also supported */ - strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ); - return 0; -} - -static int iw_get_nick(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - strcpy(extra, "zd1211"); - req->data.length = strlen(extra); - req->data.flags = 1; - return 0; -} - -static int iw_set_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; - - r = zd_find_channel(&channel, freq); - if (r < 0) - return r; - r = zd_mac_request_channel(mac, channel); - return r; -} - -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); -} - -static int iw_set_mode(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - return zd_mac_set_mode(zd_netdev_mac(netdev), req->mode); -} - -static int iw_get_mode(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - return zd_mac_get_mode(zd_netdev_mac(netdev), &req->mode); -} - -static int iw_get_range(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n"); - req->data.length = sizeof(*range); - return zd_mac_get_range(zd_netdev_mac(netdev), range); -} - -static int iw_set_encode(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - return ieee80211_wx_set_encode(zd_netdev_ieee80211(netdev), info, - data, extra); -} - -static int iw_get_encode(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - return ieee80211_wx_get_encode(zd_netdev_ieee80211(netdev), info, - data, extra); -} - -static int iw_set_encodeext(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - return ieee80211_wx_set_encodeext(zd_netdev_ieee80211(netdev), info, - data, extra); -} - -static int iw_get_encodeext(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - return ieee80211_wx_get_encodeext(zd_netdev_ieee80211(netdev), info, - data, extra); -} - -#define WX(x) [(x)-SIOCIWFIRST] - -static const iw_handler zd_standard_iw_handlers[] = { - WX(SIOCGIWNAME) = iw_get_name, - WX(SIOCGIWNICKN) = iw_get_nick, - WX(SIOCSIWFREQ) = iw_set_freq, - WX(SIOCGIWFREQ) = iw_get_freq, - WX(SIOCSIWMODE) = iw_set_mode, - WX(SIOCGIWMODE) = iw_get_mode, - WX(SIOCGIWRANGE) = iw_get_range, - WX(SIOCSIWENCODE) = iw_set_encode, - WX(SIOCGIWENCODE) = iw_get_encode, - WX(SIOCSIWENCODEEXT) = iw_set_encodeext, - WX(SIOCGIWENCODEEXT) = iw_get_encodeext, - WX(SIOCSIWAUTH) = ieee80211_wx_set_auth, - WX(SIOCGIWAUTH) = ieee80211_wx_get_auth, - WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan, - WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results, - WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid, - WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid, - WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap, - WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap, - WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate, - WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate, - WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie, - WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie, - WX(SIOCSIWMLME) = ieee80211softmac_wx_set_mlme, -}; - -static const struct iw_handler_def iw_handler_def = { - .standard = zd_standard_iw_handlers, - .num_standard = ARRAY_SIZE(zd_standard_iw_handlers), - .private = zd_priv_handler, - .num_private = ARRAY_SIZE(zd_priv_handler), - .private_args = zd_priv_args, - .num_private_args = ARRAY_SIZE(zd_priv_args), - .get_wireless_stats = zd_mac_get_wireless_stats, -}; - -struct net_device *zd_netdev_alloc(struct usb_interface *intf) -{ - int r; - struct net_device *netdev; - struct zd_mac *mac; - - netdev = alloc_ieee80211softmac(sizeof(struct zd_mac)); - if (!netdev) { - dev_dbg_f(&intf->dev, "out of memory\n"); - return NULL; - } - - mac = zd_netdev_mac(netdev); - r = zd_mac_init(mac, netdev, intf); - if (r) { - usb_set_intfdata(intf, NULL); - free_ieee80211(netdev); - return NULL; - } - - SET_MODULE_OWNER(netdev); - SET_NETDEV_DEV(netdev, &intf->dev); - - dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags); - dev_dbg_f(&intf->dev, "netdev->features %#010lx\n", netdev->features); - - netdev->open = zd_mac_open; - netdev->stop = zd_mac_stop; - /* netdev->get_stats = */ - /* netdev->set_multicast_list = */ - netdev->set_mac_address = zd_mac_set_mac_address; - netdev->wireless_handlers = &iw_handler_def; - /* netdev->ethtool_ops = */ - - return netdev; -} - -void zd_netdev_free(struct net_device *netdev) -{ - if (!netdev) - return; - - zd_mac_clear(zd_netdev_mac(netdev)); - free_ieee80211(netdev); -} - -void zd_netdev_disconnect(struct net_device *netdev) -{ - unregister_netdev(netdev); -} diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.h b/drivers/net/wireless/zd1211rw/zd_netdev.h deleted file mode 100644 index 374a957073c..00000000000 --- a/drivers/net/wireless/zd1211rw/zd_netdev.h +++ /dev/null @@ -1,45 +0,0 @@ -/* zd_netdev.h: Header for net device related functions. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ZD_NETDEV_H -#define _ZD_NETDEV_H - -#include <linux/usb.h> -#include <linux/netdevice.h> -#include <net/ieee80211.h> - -#define ZD_PRIV_SET_REGDOMAIN (SIOCIWFIRSTPRIV) -#define ZD_PRIV_GET_REGDOMAIN (SIOCIWFIRSTPRIV+1) - -static inline struct ieee80211_device *zd_netdev_ieee80211( - struct net_device *ndev) -{ - return netdev_priv(ndev); -} - -static inline struct net_device *zd_ieee80211_to_netdev( - struct ieee80211_device *ieee) -{ - return ieee->dev; -} - -struct net_device *zd_netdev_alloc(struct usb_interface *intf); -void zd_netdev_free(struct net_device *netdev); - -void zd_netdev_disconnect(struct net_device *netdev); - -#endif /* _ZD_NETDEV_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c index f50cff3db91..dc179c41451 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.c +++ b/drivers/net/wireless/zd1211rw/zd_rf.c @@ -1,4 +1,7 @@ -/* zd_rf.c +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/errno.h> @@ -20,10 +22,10 @@ #include "zd_def.h" #include "zd_rf.h" -#include "zd_ieee80211.h" +#include "zd_mac.h" #include "zd_chip.h" -static const char *rfs[] = { +static const char * const rfs[] = { [0] = "unknown RF0", [1] = "unknown RF1", [UW2451_RF] = "UW2451_RF", @@ -52,34 +54,40 @@ const char *zd_rf_name(u8 type) void zd_rf_init(struct zd_rf *rf) { memset(rf, 0, sizeof(*rf)); + + /* default to update channel integration, as almost all RF's do want + * this */ + rf->update_channel_int = 1; } void zd_rf_clear(struct zd_rf *rf) { + if (rf->clear) + rf->clear(rf); ZD_MEMCLEAR(rf, sizeof(*rf)); } int zd_rf_init_hw(struct zd_rf *rf, u8 type) { - int r, t; + int r = 0; + int t; struct zd_chip *chip = zd_rf_to_chip(rf); ZD_ASSERT(mutex_is_locked(&chip->mutex)); switch (type) { case RF2959_RF: r = zd_rf_init_rf2959(rf); - if (r) - return r; break; case AL2230_RF: + case AL2230S_RF: r = zd_rf_init_al2230(rf); - if (r) - return r; break; case AL7230B_RF: r = zd_rf_init_al7230b(rf); - if (r) - return r; + break; + case MAXIM_NEW_RF: + case UW2453_RF: + r = zd_rf_init_uw2453(rf); break; default: dev_err(zd_chip_dev(chip), @@ -88,6 +96,9 @@ int zd_rf_init_hw(struct zd_rf *rf, u8 type) return -ENODEV; } + if (r) + return r; + rf->type = type; r = zd_chip_lock_phy_regs(chip); @@ -154,3 +165,17 @@ int zd_switch_radio_off(struct zd_rf *rf) r = t; return r; } + +int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel) +{ + if (!rf->patch_6m_band_edge) + return 0; + + return rf->patch_6m_band_edge(rf, channel); +} + +int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel) +{ + return zd_chip_generic_patch_6m_band(zd_rf_to_chip(rf), channel); +} + diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h index 676b3734f1e..8f14e25e104 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.h +++ b/drivers/net/wireless/zd1211rw/zd_rf.h @@ -1,4 +1,7 @@ -/* zd_rf.h +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,15 +14,12 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #ifndef _ZD_RF_H #define _ZD_RF_H -#include "zd_types.h" - #define UW2451_RF 0x2 #define UCHIP_RF 0x3 #define AL2230_RF 0x4 @@ -49,17 +49,27 @@ struct zd_rf { u8 type; u8 channel; - /* - * Whether this RF should patch the 6M band edge - * (assuming E2P_POD agrees) - */ - u8 patch_6m_band_edge:1; + + /* whether channel integration and calibration should be updated + * defaults to 1 (yes) */ + u8 update_channel_int:1; + + /* whether ZD_CR47 should be patched from the EEPROM, if the appropriate + * flag is set in the POD. The vendor driver suggests that this should + * be done for all RF's, but a bug in their code prevents but their + * HW_OverWritePhyRegFromE2P() routine from ever taking effect. */ + u8 patch_cck_gain:1; + + /* private RF driver data */ + void *priv; /* RF-specific functions */ int (*init_hw)(struct zd_rf *rf); int (*set_channel)(struct zd_rf *rf, u8 channel); int (*switch_radio_on)(struct zd_rf *rf); int (*switch_radio_off)(struct zd_rf *rf); + int (*patch_6m_band_edge)(struct zd_rf *rf, u8 channel); + void (*clear)(struct zd_rf *rf); }; const char *zd_rf_name(u8 type); @@ -74,10 +84,27 @@ int zd_rf_set_channel(struct zd_rf *rf, u8 channel); int zd_switch_radio_on(struct zd_rf *rf); int zd_switch_radio_off(struct zd_rf *rf); +int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel); +int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel); + +static inline int zd_rf_should_update_pwr_int(struct zd_rf *rf) +{ + return rf->update_channel_int; +} + +static inline int zd_rf_should_patch_cck_gain(struct zd_rf *rf) +{ + return rf->patch_cck_gain; +} + +int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel); +int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel); + /* Functions for individual RF chips */ int zd_rf_init_rf2959(struct zd_rf *rf); int zd_rf_init_al2230(struct zd_rf *rf); int zd_rf_init_al7230b(struct zd_rf *rf); +int zd_rf_init_uw2453(struct zd_rf *rf); #endif /* _ZD_RF_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c index 25323a13a3d..99aed7d7895 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c @@ -1,4 +1,7 @@ -/* zd_rf_al2230.c: Functions for the AL2230 RF controller +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> @@ -21,6 +23,8 @@ #include "zd_usb.h" #include "zd_chip.h" +#define IS_AL2230S(chip) ((chip)->al2230s_bit || (chip)->rf.type == AL2230S_RF) + static const u32 zd1211_al2230_table[][3] = { RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, }, RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, }, @@ -56,19 +60,31 @@ static const u32 zd1211b_al2230_table[][3] = { }; static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = { - { CR240, 0x57 }, { CR9, 0xe0 }, + { ZD_CR240, 0x57 }, { ZD_CR9, 0xe0 }, +}; + +static const struct zd_ioreq16 ioreqs_init_al2230s[] = { + { ZD_CR47, 0x1e }, /* MARK_002 */ + { ZD_CR106, 0x22 }, + { ZD_CR107, 0x2a }, /* MARK_002 */ + { ZD_CR109, 0x13 }, /* MARK_002 */ + { ZD_CR118, 0xf8 }, /* MARK_002 */ + { ZD_CR119, 0x12 }, { ZD_CR122, 0xe0 }, + { ZD_CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ + { ZD_CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ + { ZD_CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ }; static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) { int r; static const struct zd_ioreq16 ioreqs[] = { - { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, - { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, - { CR203, 0x06 }, + { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, + { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, + { ZD_CR203, 0x06 }, { }, - { CR240, 0x80 }, + { ZD_CR240, 0x80 }, }; r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -77,12 +93,12 @@ static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) /* related to antenna selection? */ if (chip->new_phy_layout) { - r = zd_iowrite16_locked(chip, 0xe1, CR9); + r = zd_iowrite16_locked(chip, 0xe1, ZD_CR9); if (r) return r; } - return zd_iowrite16_locked(chip, 0x06, CR203); + return zd_iowrite16_locked(chip, 0x06, ZD_CR203); } static int zd1211_al2230_init_hw(struct zd_rf *rf) @@ -90,45 +106,44 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) int r; struct zd_chip *chip = zd_rf_to_chip(rf); - static const struct zd_ioreq16 ioreqs[] = { - { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, - { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, - { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a }, - { CR109, 0x09 }, { CR110, 0x27 }, { CR111, 0x2b }, - { CR112, 0x2b }, { CR119, 0x0a }, { CR10, 0x89 }, + static const struct zd_ioreq16 ioreqs_init[] = { + { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, + { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR44, 0x33 }, { ZD_CR106, 0x2a }, { ZD_CR107, 0x1a }, + { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 }, { ZD_CR111, 0x2b }, + { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a }, { ZD_CR10, 0x89 }, /* for newest (3rd cut) AL2300 */ - { CR17, 0x28 }, - { CR26, 0x93 }, { CR34, 0x30 }, + { ZD_CR17, 0x28 }, + { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 }, /* for newest (3rd cut) AL2300 */ - { CR35, 0x3e }, - { CR41, 0x24 }, { CR44, 0x32 }, + { ZD_CR35, 0x3e }, + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, /* for newest (3rd cut) AL2300 */ - { CR46, 0x96 }, - { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 }, - { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, - { CR92, 0x0a }, { CR99, 0x28 }, { CR100, 0x00 }, - { CR101, 0x13 }, { CR102, 0x27 }, { CR106, 0x24 }, - { CR107, 0x2a }, { CR109, 0x09 }, { CR110, 0x13 }, - { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x27 }, + { ZD_CR46, 0x96 }, + { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, + { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 }, + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR106, 0x24 }, + { ZD_CR107, 0x2a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x13 }, + { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, /* for newest (3rd cut) AL2300 */ - { CR115, 0x24 }, - { CR116, 0x24 }, { CR117, 0xf4 }, { CR118, 0xfc }, - { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 }, - { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff }, - { CR253, 0xff }, - - /* These following happen separately in the vendor driver */ - { }, + { ZD_CR115, 0x24 }, + { ZD_CR116, 0x24 }, { ZD_CR117, 0xf4 }, { ZD_CR118, 0xfc }, + { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f }, { ZD_CR121, 0x77 }, + { ZD_CR122, 0xe0 }, { ZD_CR137, 0x88 }, { ZD_CR252, 0xff }, + { ZD_CR253, 0xff }, + }; + static const struct zd_ioreq16 ioreqs_pll[] = { /* shdnb(PLL_ON)=0 */ - { CR251, 0x2f }, + { ZD_CR251, 0x2f }, /* shdnb(PLL_ON)=1 */ - { CR251, 0x3f }, - { CR138, 0x28 }, { CR203, 0x06 }, + { ZD_CR251, 0x3f }, + { ZD_CR138, 0x28 }, { ZD_CR203, 0x06 }, }; - static const u32 rv[] = { + static const u32 rv1[] = { /* Channel 1 */ 0x03f790, 0x033331, @@ -137,19 +152,23 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) 0x0b3331, 0x03b812, 0x00fff3, + }; + + static const u32 rv2[] = { 0x000da4, 0x0f4dc5, /* fix freq shift, 0x04edc5 */ 0x0805b6, 0x011687, 0x000688, - 0x0403b9, /* external control TX power (CR31) */ + 0x0403b9, /* external control TX power (ZD_CR31) */ 0x00dbba, 0x00099b, 0x0bdffc, 0x00000d, 0x00500f, + }; - /* These writes happen separately in the vendor driver */ + static const u32 rv3[] = { 0x00d00f, 0x004c0f, 0x00540f, @@ -157,11 +176,38 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) 0x00500f, }; - r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + r = zd_iowrite16a_locked(chip, ioreqs_init, ARRAY_SIZE(ioreqs_init)); + if (r) + return r; + + if (IS_AL2230S(chip)) { + r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s, + ARRAY_SIZE(ioreqs_init_al2230s)); + if (r) + return r; + } + + r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS); + if (r) + return r; + + /* improve band edge for AL2230S */ + if (IS_AL2230S(chip)) + r = zd_rfwrite_locked(chip, 0x000824, RF_RV_BITS); + else + r = zd_rfwrite_locked(chip, 0x0005a4, RF_RV_BITS); + if (r) + return r; + + r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS); + if (r) + return r; + + r = zd_iowrite16a_locked(chip, ioreqs_pll, ARRAY_SIZE(ioreqs_pll)); if (r) return r; - r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS); + r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS); if (r) return r; @@ -174,52 +220,54 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs1[] = { - { CR10, 0x89 }, { CR15, 0x20 }, - { CR17, 0x2B }, /* for newest(3rd cut) AL2230 */ - { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 }, - { CR28, 0x3e }, { CR29, 0x00 }, - { CR33, 0x28 }, /* 5621 */ - { CR34, 0x30 }, - { CR35, 0x3e }, /* for newest(3rd cut) AL2230 */ - { CR41, 0x24 }, { CR44, 0x32 }, - { CR46, 0x99 }, /* for newest(3rd cut) AL2230 */ - { CR47, 0x1e }, + { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 }, + { ZD_CR17, 0x2B }, /* for newest(3rd cut) AL2230 */ + { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, + { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR33, 0x28 }, /* 5621 */ + { ZD_CR34, 0x30 }, + { ZD_CR35, 0x3e }, /* for newest(3rd cut) AL2230 */ + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + { ZD_CR46, 0x99 }, /* for newest(3rd cut) AL2230 */ + { ZD_CR47, 0x1e }, /* ZD1211B 05.06.10 */ - { CR48, 0x06 }, { CR49, 0xf9 }, { CR51, 0x01 }, - { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, - { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, - { CR69, 0x28 }, - - { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, - { CR87, 0x0a }, { CR89, 0x04 }, - { CR91, 0x00 }, /* 5621 */ - { CR92, 0x0a }, - { CR98, 0x8d }, /* 4804, for 1212 new algorithm */ - { CR99, 0x00 }, /* 5621 */ - { CR101, 0x13 }, { CR102, 0x27 }, - { CR106, 0x24 }, /* for newest(3rd cut) AL2230 */ - { CR107, 0x2a }, - { CR109, 0x13 }, /* 4804, for 1212 new algorithm */ - { CR110, 0x1f }, /* 4804, for 1212 new algorithm */ - { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x27 }, - { CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) AL2230 */ - { CR116, 0x24 }, - { CR117, 0xfa }, /* for 1211b */ - { CR118, 0xfa }, /* for 1211b */ - { CR119, 0x10 }, - { CR120, 0x4f }, - { CR121, 0x6c }, /* for 1211b */ - { CR122, 0xfc }, /* E0->FC at 4902 */ - { CR123, 0x57 }, /* 5623 */ - { CR125, 0xad }, /* 4804, for 1212 new algorithm */ - { CR126, 0x6c }, /* 5614 */ - { CR127, 0x03 }, /* 4804, for 1212 new algorithm */ - { CR137, 0x50 }, /* 5614 */ - { CR138, 0xa8 }, - { CR144, 0xac }, /* 5621 */ - { CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 }, + { ZD_CR48, 0x06 }, { ZD_CR49, 0xf9 }, { ZD_CR51, 0x01 }, + { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 }, + { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 }, + { ZD_CR69, 0x28 }, + + { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, + { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR91, 0x00 }, /* 5621 */ + { ZD_CR92, 0x0a }, + { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */ + { ZD_CR99, 0x00 }, /* 5621 */ + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, + { ZD_CR106, 0x24 }, /* for newest(3rd cut) AL2230 */ + { ZD_CR107, 0x2a }, + { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */ + { ZD_CR110, 0x1f }, /* 4804, for 1212 new algorithm */ + { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, + { ZD_CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) + * AL2230 + */ + { ZD_CR116, 0x24 }, + { ZD_CR117, 0xfa }, /* for 1211b */ + { ZD_CR118, 0xfa }, /* for 1211b */ + { ZD_CR119, 0x10 }, + { ZD_CR120, 0x4f }, + { ZD_CR121, 0x6c }, /* for 1211b */ + { ZD_CR122, 0xfc }, /* E0->FC at 4902 */ + { ZD_CR123, 0x57 }, /* 5623 */ + { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */ + { ZD_CR126, 0x6c }, /* 5614 */ + { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */ + { ZD_CR137, 0x50 }, /* 5614 */ + { ZD_CR138, 0xa8 }, + { ZD_CR144, 0xac }, /* 5621 */ + { ZD_CR150, 0x0d }, { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 }, }; static const u32 rv1[] = { @@ -227,7 +275,9 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) 0x481dc0, 0xcfff00, 0x25a000, + }; + static const u32 rv2[] = { /* To improve AL2230 yield, improve phase noise, 4713 */ 0x25a000, 0xa3b2f0, @@ -235,7 +285,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) 0x6da010, /* Reg6 update for MP versio */ 0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */ 0x116000, - 0x9dc020, /* External control TX power (CR31) */ + 0x9dc020, /* External control TX power (ZD_CR31) */ 0x5ddb00, /* RegA update for MP version */ 0xd99000, /* RegB update for MP version */ 0x3ffbd0, /* RegC update for MP version */ @@ -246,11 +296,11 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) }; static const struct zd_ioreq16 ioreqs2[] = { - { CR251, 0x2f }, /* shdnb(PLL_ON)=0 */ - { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ + { ZD_CR251, 0x2f }, /* shdnb(PLL_ON)=0 */ + { ZD_CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ }; - static const u32 rv2[] = { + static const u32 rv3[] = { /* To improve AL2230 yield, 4713 */ 0xf01b00, 0xf01e00, @@ -259,7 +309,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) static const struct zd_ioreq16 ioreqs3[] = { /* related to 6M band edge patching, happens unconditionally */ - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, }; r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1, @@ -269,18 +319,37 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1)); if (r) return r; + + if (IS_AL2230S(chip)) { + r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s, + ARRAY_SIZE(ioreqs_init_al2230s)); + if (r) + return r; + } + r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3); if (r) return r; r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1)); if (r) return r; - r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2)); + + if (IS_AL2230S(chip)) + r = zd_rfwrite_locked(chip, 0x241000, RF_RV_BITS); + else + r = zd_rfwrite_locked(chip, 0x25a000, RF_RV_BITS); if (r) return r; + r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2)); if (r) return r; + r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2)); + if (r) + return r; + r = zd_rfwritev_cr_locked(chip, rv3, ARRAY_SIZE(rv3)); + if (r) + return r; r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3)); if (r) return r; @@ -293,8 +362,8 @@ static int zd1211_al2230_set_channel(struct zd_rf *rf, u8 channel) const u32 *rv = zd1211_al2230_table[channel-1]; struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR138, 0x28 }, - { CR203, 0x06 }, + { ZD_CR138, 0x28 }, + { ZD_CR203, 0x06 }, }; r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS); @@ -325,8 +394,8 @@ static int zd1211_al2230_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x3f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x3f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -336,8 +405,8 @@ static int zd1211b_al2230_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x7f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x7f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -347,8 +416,8 @@ static int al2230_switch_radio_off(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x04 }, - { CR251, 0x2f }, + { ZD_CR11, 0x04 }, + { ZD_CR251, 0x2f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -359,7 +428,7 @@ int zd_rf_init_al2230(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); rf->switch_radio_off = al2230_switch_radio_off; - if (chip->is_zd1211b) { + if (zd_chip_is_zd1211b(chip)) { rf->init_hw = zd1211b_al2230_init_hw; rf->set_channel = zd1211b_al2230_set_channel; rf->switch_radio_on = zd1211b_al2230_switch_radio_on; @@ -368,6 +437,7 @@ int zd_rf_init_al2230(struct zd_rf *rf) rf->set_channel = zd1211_al2230_set_channel; rf->switch_radio_on = zd1211_al2230_switch_radio_on; } - rf->patch_6m_band_edge = 1; + rf->patch_6m_band_edge = zd_rf_generic_patch_6m; + rf->patch_cck_gain = 1; return 0; } diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c index a289f95187e..5fea485be57 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c @@ -1,4 +1,7 @@ -/* zd_rf_al7230b.c: Functions for the AL7230B RF controller +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> @@ -51,105 +53,245 @@ static const u32 std_rv[] = { 0xd8c010, }; -static int al7230b_init_hw(struct zd_rf *rf) +static const u32 rv_init1[] = { + 0x3c9000, + 0xbfffff, + 0x700000, + 0xf15d58, +}; + +static const u32 rv_init2[] = { + 0xf15d59, + 0xf15d5c, + 0xf15d58, +}; + +static const struct zd_ioreq16 ioreqs_sw[] = { + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, +}; + +static int zd1211b_al7230b_finalize(struct zd_chip *chip) +{ + int r; + static const struct zd_ioreq16 ioreqs[] = { + { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, + { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, + { ZD_CR203, 0x04 }, + { }, + { ZD_CR240, 0x80 }, + }; + + r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + if (r) + return r; + + if (chip->new_phy_layout) { + /* antenna selection? */ + r = zd_iowrite16_locked(chip, 0xe5, ZD_CR9); + if (r) + return r; + } + + return zd_iowrite16_locked(chip, 0x04, ZD_CR203); +} + +static int zd1211_al7230b_init_hw(struct zd_rf *rf) { - int i, r; + int r; struct zd_chip *chip = zd_rf_to_chip(rf); /* All of these writes are identical to AL2230 unless otherwise * specified */ static const struct zd_ioreq16 ioreqs_1[] = { /* This one is 7230-specific, and happens before the rest */ - { CR240, 0x57 }, + { ZD_CR240, 0x57 }, { }, - { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, - { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, - { CR44, 0x33 }, + { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, + { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR44, 0x33 }, /* This value is different for 7230 (was: 0x2a) */ - { CR106, 0x22 }, - { CR107, 0x1a }, { CR109, 0x09 }, { CR110, 0x27 }, - { CR111, 0x2b }, { CR112, 0x2b }, { CR119, 0x0a }, + { ZD_CR106, 0x22 }, + { ZD_CR107, 0x1a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 }, + { ZD_CR111, 0x2b }, { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a }, /* This happened further down in AL2230, * and the value changed (was: 0xe0) */ - { CR122, 0xfc }, - { CR10, 0x89 }, + { ZD_CR122, 0xfc }, + { ZD_CR10, 0x89 }, /* for newest (3rd cut) AL2300 */ - { CR17, 0x28 }, - { CR26, 0x93 }, { CR34, 0x30 }, + { ZD_CR17, 0x28 }, + { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 }, /* for newest (3rd cut) AL2300 */ - { CR35, 0x3e }, - { CR41, 0x24 }, { CR44, 0x32 }, + { ZD_CR35, 0x3e }, + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, /* for newest (3rd cut) AL2300 */ - { CR46, 0x96 }, - { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 }, - { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 }, - { CR92, 0x0a }, { CR99, 0x28 }, + { ZD_CR46, 0x96 }, + { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, + { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 }, /* This value is different for 7230 (was: 0x00) */ - { CR100, 0x02 }, - { CR101, 0x13 }, { CR102, 0x27 }, + { ZD_CR100, 0x02 }, + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, /* This value is different for 7230 (was: 0x24) */ - { CR106, 0x22 }, + { ZD_CR106, 0x22 }, /* This value is different for 7230 (was: 0x2a) */ - { CR107, 0x3f }, - { CR109, 0x09 }, + { ZD_CR107, 0x3f }, + { ZD_CR109, 0x09 }, /* This value is different for 7230 (was: 0x13) */ - { CR110, 0x1f }, - { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 }, - { CR114, 0x27 }, + { ZD_CR110, 0x1f }, + { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x27 }, /* for newest (3rd cut) AL2300 */ - { CR115, 0x24 }, + { ZD_CR115, 0x24 }, /* This value is different for 7230 (was: 0x24) */ - { CR116, 0x3f }, + { ZD_CR116, 0x3f }, /* This value is different for 7230 (was: 0xf4) */ - { CR117, 0xfa }, - { CR118, 0xfc }, { CR119, 0x10 }, { CR120, 0x4f }, - { CR121, 0x77 }, { CR137, 0x88 }, + { ZD_CR117, 0xfa }, + { ZD_CR118, 0xfc }, { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f }, + { ZD_CR121, 0x77 }, { ZD_CR137, 0x88 }, /* This one is 7230-specific */ - { CR138, 0xa8 }, + { ZD_CR138, 0xa8 }, /* This value is different for 7230 (was: 0xff) */ - { CR252, 0x34 }, + { ZD_CR252, 0x34 }, /* This value is different for 7230 (was: 0xff) */ - { CR253, 0x34 }, + { ZD_CR253, 0x34 }, /* PLL_OFF */ - { CR251, 0x2f }, + { ZD_CR251, 0x2f }, }; static const struct zd_ioreq16 ioreqs_2[] = { - /* PLL_ON */ - { CR251, 0x3f }, - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, + { ZD_CR251, 0x3f }, /* PLL_ON */ + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, }; r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); if (r) return r; - r = zd_rfwrite_cr_locked(chip, 0x09ec04); + r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0])); if (r) return r; - r = zd_rfwrite_cr_locked(chip, 0x8cccc8); + + r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); if (r) return r; - for (i = 0; i < ARRAY_SIZE(std_rv); i++) { - r = zd_rfwrite_cr_locked(chip, std_rv[i]); - if (r) - return r; - } + r = zd_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1)); + if (r) + return r; - r = zd_rfwrite_cr_locked(chip, 0x3c9000); + r = zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2)); if (r) return r; - r = zd_rfwrite_cr_locked(chip, 0xbfffff); + + r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2)); if (r) return r; - r = zd_rfwrite_cr_locked(chip, 0x700000); + + r = zd_iowrite16_locked(chip, 0x06, ZD_CR203); if (r) return r; - r = zd_rfwrite_cr_locked(chip, 0xf15d58); + r = zd_iowrite16_locked(chip, 0x80, ZD_CR240); + if (r) + return r; + + return 0; +} + +static int zd1211b_al7230b_init_hw(struct zd_rf *rf) +{ + int r; + struct zd_chip *chip = zd_rf_to_chip(rf); + + static const struct zd_ioreq16 ioreqs_1[] = { + { ZD_CR240, 0x57 }, { ZD_CR9, 0x9 }, + { }, + { ZD_CR10, 0x8b }, { ZD_CR15, 0x20 }, + { ZD_CR17, 0x2B }, /* for newest (3rd cut) AL2230 */ + { ZD_CR20, 0x10 }, /* 4N25->Stone Request */ + { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, + { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR33, 0x28 }, /* 5613 */ + { ZD_CR34, 0x30 }, + { ZD_CR35, 0x3e }, /* for newest (3rd cut) AL2230 */ + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + { ZD_CR46, 0x99 }, /* for newest (3rd cut) AL2230 */ + { ZD_CR47, 0x1e }, + + /* ZD1215 5610 */ + { ZD_CR48, 0x00 }, { ZD_CR49, 0x00 }, { ZD_CR51, 0x01 }, + { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 }, + { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 }, + { ZD_CR69, 0x28 }, + + { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, + { ZD_CR87, 0x0A }, { ZD_CR89, 0x04 }, + { ZD_CR90, 0x58 }, /* 5112 */ + { ZD_CR91, 0x00 }, /* 5613 */ + { ZD_CR92, 0x0a }, + { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */ + { ZD_CR99, 0x00 }, { ZD_CR100, 0x02 }, { ZD_CR101, 0x13 }, + { ZD_CR102, 0x27 }, + { ZD_CR106, 0x20 }, /* change to 0x24 for AL7230B */ + { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */ + { ZD_CR112, 0x1f }, + }; + + static const struct zd_ioreq16 ioreqs_new_phy[] = { + { ZD_CR107, 0x28 }, + { ZD_CR110, 0x1f }, /* 5127, 0x13->0x1f */ + { ZD_CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */ + { ZD_CR116, 0x2a }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x12 }, + { ZD_CR121, 0x6c }, /* 5613 */ + }; + + static const struct zd_ioreq16 ioreqs_old_phy[] = { + { ZD_CR107, 0x24 }, + { ZD_CR110, 0x13 }, /* 5127, 0x13->0x1f */ + { ZD_CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */ + { ZD_CR116, 0x24 }, { ZD_CR118, 0xfc }, { ZD_CR119, 0x11 }, + { ZD_CR121, 0x6a }, /* 5613 */ + }; + + static const struct zd_ioreq16 ioreqs_2[] = { + { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x24 }, + { ZD_CR117, 0xfa }, { ZD_CR120, 0x4f }, + { ZD_CR122, 0xfc }, /* E0->FCh at 4901 */ + { ZD_CR123, 0x57 }, /* 5613 */ + { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */ + { ZD_CR126, 0x6c }, /* 5613 */ + { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */ + { ZD_CR130, 0x10 }, + { ZD_CR131, 0x00 }, /* 5112 */ + { ZD_CR137, 0x50 }, /* 5613 */ + { ZD_CR138, 0xa8 }, /* 5112 */ + { ZD_CR144, 0xac }, /* 5613 */ + { ZD_CR148, 0x40 }, /* 5112 */ + { ZD_CR149, 0x40 }, /* 4O07, 50->40 */ + { ZD_CR150, 0x1a }, /* 5112, 0C->1A */ + { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 }, + { ZD_CR251, 0x2f }, /* PLL_OFF */ + }; + + static const struct zd_ioreq16 ioreqs_3[] = { + { ZD_CR251, 0x7f }, /* PLL_ON */ + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, + { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf }, + }; + + r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); + if (r) + return r; + + if (chip->new_phy_layout) + r = zd_iowrite16a_locked(chip, ioreqs_new_phy, + ARRAY_SIZE(ioreqs_new_phy)); + else + r = zd_iowrite16a_locked(chip, ioreqs_old_phy, + ARRAY_SIZE(ioreqs_old_phy)); if (r) return r; @@ -157,57 +299,53 @@ static int al7230b_init_hw(struct zd_rf *rf) if (r) return r; - r = zd_rfwrite_cr_locked(chip, 0xf15d59); + r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0])); if (r) return r; - r = zd_rfwrite_cr_locked(chip, 0xf15d5c); + + r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); if (r) return r; - r = zd_rfwrite_cr_locked(chip, 0xf15d58); + + r = zd_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1)); if (r) return r; - r = zd_iowrite16_locked(chip, 0x06, CR203); + r = zd_iowrite16a_locked(chip, ioreqs_3, ARRAY_SIZE(ioreqs_3)); if (r) return r; - r = zd_iowrite16_locked(chip, 0x80, CR240); + + r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2)); if (r) return r; - return 0; + return zd1211b_al7230b_finalize(chip); } -static int al7230b_set_channel(struct zd_rf *rf, u8 channel) +static int zd1211_al7230b_set_channel(struct zd_rf *rf, u8 channel) { - int i, r; + int r; const u32 *rv = chan_rv[channel-1]; struct zd_chip *chip = zd_rf_to_chip(rf); - struct zd_ioreq16 ioreqs_1[] = { - { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, - { CR38, 0x38 }, { CR136, 0xdf }, - }; - - struct zd_ioreq16 ioreqs_2[] = { + static const struct zd_ioreq16 ioreqs[] = { /* PLL_ON */ - { CR251, 0x3f }, - { CR203, 0x06 }, { CR240, 0x08 }, + { ZD_CR251, 0x3f }, + { ZD_CR203, 0x06 }, { ZD_CR240, 0x08 }, }; - r = zd_iowrite16_locked(chip, 0x57, CR240); + r = zd_iowrite16_locked(chip, 0x57, ZD_CR240); if (r) return r; /* PLL_OFF */ - r = zd_iowrite16_locked(chip, 0x2f, CR251); + r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251); if (r) return r; - for (i = 0; i < ARRAY_SIZE(std_rv); i++) { - r = zd_rfwrite_cr_locked(chip, std_rv[i]); - if (r) - return r; - } + r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); + if (r) + return r; r = zd_rfwrite_cr_locked(chip, 0x3c9000); if (r) @@ -216,29 +354,85 @@ static int al7230b_set_channel(struct zd_rf *rf, u8 channel) if (r) return r; - r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); + r = zd_iowrite16a_locked(chip, ioreqs_sw, ARRAY_SIZE(ioreqs_sw)); if (r) return r; - for (i = 0; i < 2; i++) { - r = zd_rfwrite_cr_locked(chip, rv[i]); - if (r) - return r; - } + r = zd_rfwritev_cr_locked(chip, rv, 2); + if (r) + return r; r = zd_rfwrite_cr_locked(chip, 0x3c9000); if (r) return r; - return zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2)); + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); } -static int al7230b_switch_radio_on(struct zd_rf *rf) +static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel) +{ + int r; + const u32 *rv = chan_rv[channel-1]; + struct zd_chip *chip = zd_rf_to_chip(rf); + + r = zd_iowrite16_locked(chip, 0x57, ZD_CR240); + if (r) + return r; + r = zd_iowrite16_locked(chip, 0xe4, ZD_CR9); + if (r) + return r; + + /* PLL_OFF */ + r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251); + if (r) + return r; + r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); + if (r) + return r; + + r = zd_rfwrite_cr_locked(chip, 0x3c9000); + if (r) + return r; + r = zd_rfwrite_cr_locked(chip, 0xf15d58); + if (r) + return r; + + r = zd_iowrite16a_locked(chip, ioreqs_sw, ARRAY_SIZE(ioreqs_sw)); + if (r) + return r; + + r = zd_rfwritev_cr_locked(chip, rv, 2); + if (r) + return r; + + r = zd_rfwrite_cr_locked(chip, 0x3c9000); + if (r) + return r; + + r = zd_iowrite16_locked(chip, 0x7f, ZD_CR251); + if (r) + return r; + + return zd1211b_al7230b_finalize(chip); +} + +static int zd1211_al7230b_switch_radio_on(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x00 }, - { CR251, 0x3f }, + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x3f }, + }; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} + +static int zd1211b_al7230b_switch_radio_on(struct zd_rf *rf) +{ + struct zd_chip *chip = zd_rf_to_chip(rf); + static const struct zd_ioreq16 ioreqs[] = { + { ZD_CR11, 0x00 }, + { ZD_CR251, 0x7f }, }; return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); @@ -248,10 +442,32 @@ static int al7230b_switch_radio_off(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR11, 0x04 }, - { CR251, 0x2f }, + { ZD_CR11, 0x04 }, + { ZD_CR251, 0x2f }, + }; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} + +/* ZD1211B+AL7230B 6m band edge patching differs slightly from other + * configurations */ +static int zd1211b_al7230b_patch_6m(struct zd_rf *rf, u8 channel) +{ + struct zd_chip *chip = zd_rf_to_chip(rf); + struct zd_ioreq16 ioreqs[] = { + { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, }; + /* FIXME: Channel 11 is not the edge for all regulatory domains. */ + if (channel == 1) { + ioreqs[0].value = 0x0e; + ioreqs[1].value = 0x10; + } else if (channel == 11) { + ioreqs[0].value = 0x10; + ioreqs[1].value = 0x10; + } + + dev_dbg_f(zd_chip_dev(chip), "patching for channel %d\n", channel); return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); } @@ -259,16 +475,20 @@ int zd_rf_init_al7230b(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); - if (chip->is_zd1211b) { - dev_err(zd_chip_dev(chip), "AL7230B is currently not " - "supported for ZD1211B devices\n"); - return -ENODEV; + if (zd_chip_is_zd1211b(chip)) { + rf->init_hw = zd1211b_al7230b_init_hw; + rf->switch_radio_on = zd1211b_al7230b_switch_radio_on; + rf->set_channel = zd1211b_al7230b_set_channel; + rf->patch_6m_band_edge = zd1211b_al7230b_patch_6m; + } else { + rf->init_hw = zd1211_al7230b_init_hw; + rf->switch_radio_on = zd1211_al7230b_switch_radio_on; + rf->set_channel = zd1211_al7230b_set_channel; + rf->patch_6m_band_edge = zd_rf_generic_patch_6m; + rf->patch_cck_gain = 1; } - rf->init_hw = al7230b_init_hw; - rf->set_channel = al7230b_set_channel; - rf->switch_radio_on = al7230b_switch_radio_on; rf->switch_radio_off = al7230b_switch_radio_off; - rf->patch_6m_band_edge = 1; + return 0; } diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c index 58247271cc2..a93f657a41c 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c @@ -1,4 +1,7 @@ -/* zd_rf_rfmd.c: Functions for the RFMD RF controller +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/kernel.h> @@ -21,7 +23,7 @@ #include "zd_usb.h" #include "zd_chip.h" -static u32 rf2959_table[][2] = { +static const u32 rf2959_table[][2] = { RF_CHANNEL( 1) = { 0x181979, 0x1e6666 }, RF_CHANNEL( 2) = { 0x181989, 0x1e6666 }, RF_CHANNEL( 3) = { 0x181999, 0x1e6666 }, @@ -149,44 +151,44 @@ static int rf2959_init_hw(struct zd_rf *rf) struct zd_chip *chip = zd_rf_to_chip(rf); static const struct zd_ioreq16 ioreqs[] = { - { CR2, 0x1E }, { CR9, 0x20 }, { CR10, 0x89 }, - { CR11, 0x00 }, { CR15, 0xD0 }, { CR17, 0x68 }, - { CR19, 0x4a }, { CR20, 0x0c }, { CR21, 0x0E }, - { CR23, 0x48 }, + { ZD_CR2, 0x1E }, { ZD_CR9, 0x20 }, { ZD_CR10, 0x89 }, + { ZD_CR11, 0x00 }, { ZD_CR15, 0xD0 }, { ZD_CR17, 0x68 }, + { ZD_CR19, 0x4a }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0E }, + { ZD_CR23, 0x48 }, /* normal size for cca threshold */ - { CR24, 0x14 }, - /* { CR24, 0x20 }, */ - { CR26, 0x90 }, { CR27, 0x30 }, { CR29, 0x20 }, - { CR31, 0xb2 }, { CR32, 0x43 }, { CR33, 0x28 }, - { CR38, 0x30 }, { CR34, 0x0f }, { CR35, 0xF0 }, - { CR41, 0x2a }, { CR46, 0x7F }, { CR47, 0x1E }, - { CR51, 0xc5 }, { CR52, 0xc5 }, { CR53, 0xc5 }, - { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, - { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 }, - { CR85, 0x00 }, { CR86, 0x10 }, { CR87, 0x2A }, - { CR88, 0x10 }, { CR89, 0x24 }, { CR90, 0x18 }, - /* { CR91, 0x18 }, */ - /* should solve continous CTS frame problems */ - { CR91, 0x00 }, - { CR92, 0x0a }, { CR93, 0x00 }, { CR94, 0x01 }, - { CR95, 0x00 }, { CR96, 0x40 }, { CR97, 0x37 }, - { CR98, 0x05 }, { CR99, 0x28 }, { CR100, 0x00 }, - { CR101, 0x13 }, { CR102, 0x27 }, { CR103, 0x27 }, - { CR104, 0x18 }, { CR105, 0x12 }, + { ZD_CR24, 0x14 }, + /* { ZD_CR24, 0x20 }, */ + { ZD_CR26, 0x90 }, { ZD_CR27, 0x30 }, { ZD_CR29, 0x20 }, + { ZD_CR31, 0xb2 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x28 }, + { ZD_CR38, 0x30 }, { ZD_CR34, 0x0f }, { ZD_CR35, 0xF0 }, + { ZD_CR41, 0x2a }, { ZD_CR46, 0x7F }, { ZD_CR47, 0x1E }, + { ZD_CR51, 0xc5 }, { ZD_CR52, 0xc5 }, { ZD_CR53, 0xc5 }, + { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, + { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 }, + { ZD_CR85, 0x00 }, { ZD_CR86, 0x10 }, { ZD_CR87, 0x2A }, + { ZD_CR88, 0x10 }, { ZD_CR89, 0x24 }, { ZD_CR90, 0x18 }, + /* { ZD_CR91, 0x18 }, */ + /* should solve continuous CTS frame problems */ + { ZD_CR91, 0x00 }, + { ZD_CR92, 0x0a }, { ZD_CR93, 0x00 }, { ZD_CR94, 0x01 }, + { ZD_CR95, 0x00 }, { ZD_CR96, 0x40 }, { ZD_CR97, 0x37 }, + { ZD_CR98, 0x05 }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 }, + { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, + { ZD_CR104, 0x18 }, { ZD_CR105, 0x12 }, /* normal size */ - { CR106, 0x1a }, - /* { CR106, 0x22 }, */ - { CR107, 0x24 }, { CR108, 0x0a }, { CR109, 0x13 }, - { CR110, 0x2F }, { CR111, 0x27 }, { CR112, 0x27 }, - { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x40 }, - { CR116, 0x40 }, { CR117, 0xF0 }, { CR118, 0xF0 }, - { CR119, 0x16 }, + { ZD_CR106, 0x1a }, + /* { ZD_CR106, 0x22 }, */ + { ZD_CR107, 0x24 }, { ZD_CR108, 0x0a }, { ZD_CR109, 0x13 }, + { ZD_CR110, 0x2F }, { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, + { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x40 }, + { ZD_CR116, 0x40 }, { ZD_CR117, 0xF0 }, { ZD_CR118, 0xF0 }, + { ZD_CR119, 0x16 }, /* no TX continuation */ - { CR122, 0x00 }, - /* { CR122, 0xff }, */ - { CR127, 0x03 }, { CR131, 0x08 }, { CR138, 0x28 }, - { CR148, 0x44 }, { CR150, 0x10 }, { CR169, 0xBB }, - { CR170, 0xBB }, + { ZD_CR122, 0x00 }, + /* { ZD_CR122, 0xff }, */ + { ZD_CR127, 0x03 }, { ZD_CR131, 0x08 }, { ZD_CR138, 0x28 }, + { ZD_CR148, 0x44 }, { ZD_CR150, 0x10 }, { ZD_CR169, 0xBB }, + { ZD_CR170, 0xBB }, }; static const u32 rv[] = { @@ -207,7 +209,7 @@ static int rf2959_init_hw(struct zd_rf *rf) */ 0x294128, /* internal power */ /* 0x28252c, */ /* External control TX power */ - /* CR31_CCK, CR51_6-36M, CR52_48M, CR53_54M */ + /* ZD_CR31_CCK, ZD_CR51_6-36M, ZD_CR52_48M, ZD_CR53_54M */ 0x2c0000, 0x300000, 0x340000, /* REG13(0xD) */ @@ -228,7 +230,7 @@ static int rf2959_init_hw(struct zd_rf *rf) static int rf2959_set_channel(struct zd_rf *rf, u8 channel) { int i, r; - u32 *rv = rf2959_table[channel-1]; + const u32 *rv = rf2959_table[channel-1]; struct zd_chip *chip = zd_rf_to_chip(rf); for (i = 0; i < 2; i++) { @@ -242,8 +244,8 @@ static int rf2959_set_channel(struct zd_rf *rf, u8 channel) static int rf2959_switch_radio_on(struct zd_rf *rf) { static const struct zd_ioreq16 ioreqs[] = { - { CR10, 0x89 }, - { CR11, 0x00 }, + { ZD_CR10, 0x89 }, + { ZD_CR11, 0x00 }, }; struct zd_chip *chip = zd_rf_to_chip(rf); @@ -253,8 +255,8 @@ static int rf2959_switch_radio_on(struct zd_rf *rf) static int rf2959_switch_radio_off(struct zd_rf *rf) { static const struct zd_ioreq16 ioreqs[] = { - { CR10, 0x15 }, - { CR11, 0x81 }, + { ZD_CR10, 0x15 }, + { ZD_CR11, 0x81 }, }; struct zd_chip *chip = zd_rf_to_chip(rf); @@ -265,7 +267,7 @@ int zd_rf_init_rf2959(struct zd_rf *rf) { struct zd_chip *chip = zd_rf_to_chip(rf); - if (chip->is_zd1211b) { + if (zd_chip_is_zd1211b(chip)) { dev_err(zd_chip_dev(chip), "RF2959 is currently not supported for ZD1211B" " devices\n"); diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c new file mode 100644 index 00000000000..61b92402735 --- /dev/null +++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c @@ -0,0 +1,539 @@ +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/slab.h> + +#include "zd_rf.h" +#include "zd_usb.h" +#include "zd_chip.h" + +/* This RF programming code is based upon the code found in v2.16.0.0 of the + * ZyDAS vendor driver. Unlike other RF's, Ubec publish full technical specs + * for this RF on their website, so we're able to understand more than + * usual as to what is going on. Thumbs up for Ubec for doing that. */ + +/* The 3-wire serial interface provides access to 8 write-only registers. + * The data format is a 4 bit register address followed by a 20 bit value. */ +#define UW2453_REGWRITE(reg, val) ((((reg) & 0xf) << 20) | ((val) & 0xfffff)) + +/* For channel tuning, we have to configure registers 1 (synthesizer), 2 (synth + * fractional divide ratio) and 3 (VCO config). + * + * We configure the RF to produce an interrupt when the PLL is locked onto + * the configured frequency. During initialization, we run through a variety + * of different VCO configurations on channel 1 until we detect a PLL lock. + * When this happens, we remember which VCO configuration produced the lock + * and use it later. Actually, we use the configuration *after* the one that + * produced the lock, which seems odd, but it works. + * + * If we do not see a PLL lock on any standard VCO config, we fall back on an + * autocal configuration, which has a fixed (as opposed to per-channel) VCO + * config and different synth values from the standard set (divide ratio + * is still shared with the standard set). */ + +/* The per-channel synth values for all standard VCO configurations. These get + * written to register 1. */ +static const u8 uw2453_std_synth[] = { + RF_CHANNEL( 1) = 0x47, + RF_CHANNEL( 2) = 0x47, + RF_CHANNEL( 3) = 0x67, + RF_CHANNEL( 4) = 0x67, + RF_CHANNEL( 5) = 0x67, + RF_CHANNEL( 6) = 0x67, + RF_CHANNEL( 7) = 0x57, + RF_CHANNEL( 8) = 0x57, + RF_CHANNEL( 9) = 0x57, + RF_CHANNEL(10) = 0x57, + RF_CHANNEL(11) = 0x77, + RF_CHANNEL(12) = 0x77, + RF_CHANNEL(13) = 0x77, + RF_CHANNEL(14) = 0x4f, +}; + +/* This table stores the synthesizer fractional divide ratio for *all* VCO + * configurations (both standard and autocal). These get written to register 2. + */ +static const u16 uw2453_synth_divide[] = { + RF_CHANNEL( 1) = 0x999, + RF_CHANNEL( 2) = 0x99b, + RF_CHANNEL( 3) = 0x998, + RF_CHANNEL( 4) = 0x99a, + RF_CHANNEL( 5) = 0x999, + RF_CHANNEL( 6) = 0x99b, + RF_CHANNEL( 7) = 0x998, + RF_CHANNEL( 8) = 0x99a, + RF_CHANNEL( 9) = 0x999, + RF_CHANNEL(10) = 0x99b, + RF_CHANNEL(11) = 0x998, + RF_CHANNEL(12) = 0x99a, + RF_CHANNEL(13) = 0x999, + RF_CHANNEL(14) = 0xccc, +}; + +/* Here is the data for all the standard VCO configurations. We shrink our + * table a little by observing that both channels in a consecutive pair share + * the same value. We also observe that the high 4 bits ([0:3] in the specs) + * are all 'Reserved' and are always set to 0x4 - we chop them off in the data + * below. */ +#define CHAN_TO_PAIRIDX(a) ((a - 1) / 2) +#define RF_CHANPAIR(a,b) [CHAN_TO_PAIRIDX(a)] +static const u16 uw2453_std_vco_cfg[][7] = { + { /* table 1 */ + RF_CHANPAIR( 1, 2) = 0x664d, + RF_CHANPAIR( 3, 4) = 0x604d, + RF_CHANPAIR( 5, 6) = 0x6675, + RF_CHANPAIR( 7, 8) = 0x6475, + RF_CHANPAIR( 9, 10) = 0x6655, + RF_CHANPAIR(11, 12) = 0x6455, + RF_CHANPAIR(13, 14) = 0x6665, + }, + { /* table 2 */ + RF_CHANPAIR( 1, 2) = 0x666d, + RF_CHANPAIR( 3, 4) = 0x606d, + RF_CHANPAIR( 5, 6) = 0x664d, + RF_CHANPAIR( 7, 8) = 0x644d, + RF_CHANPAIR( 9, 10) = 0x6675, + RF_CHANPAIR(11, 12) = 0x6475, + RF_CHANPAIR(13, 14) = 0x6655, + }, + { /* table 3 */ + RF_CHANPAIR( 1, 2) = 0x665d, + RF_CHANPAIR( 3, 4) = 0x605d, + RF_CHANPAIR( 5, 6) = 0x666d, + RF_CHANPAIR( 7, 8) = 0x646d, + RF_CHANPAIR( 9, 10) = 0x664d, + RF_CHANPAIR(11, 12) = 0x644d, + RF_CHANPAIR(13, 14) = 0x6675, + }, + { /* table 4 */ + RF_CHANPAIR( 1, 2) = 0x667d, + RF_CHANPAIR( 3, 4) = 0x607d, + RF_CHANPAIR( 5, 6) = 0x665d, + RF_CHANPAIR( 7, 8) = 0x645d, + RF_CHANPAIR( 9, 10) = 0x666d, + RF_CHANPAIR(11, 12) = 0x646d, + RF_CHANPAIR(13, 14) = 0x664d, + }, + { /* table 5 */ + RF_CHANPAIR( 1, 2) = 0x6643, + RF_CHANPAIR( 3, 4) = 0x6043, + RF_CHANPAIR( 5, 6) = 0x667d, + RF_CHANPAIR( 7, 8) = 0x647d, + RF_CHANPAIR( 9, 10) = 0x665d, + RF_CHANPAIR(11, 12) = 0x645d, + RF_CHANPAIR(13, 14) = 0x666d, + }, + { /* table 6 */ + RF_CHANPAIR( 1, 2) = 0x6663, + RF_CHANPAIR( 3, 4) = 0x6063, + RF_CHANPAIR( 5, 6) = 0x6643, + RF_CHANPAIR( 7, 8) = 0x6443, + RF_CHANPAIR( 9, 10) = 0x667d, + RF_CHANPAIR(11, 12) = 0x647d, + RF_CHANPAIR(13, 14) = 0x665d, + }, + { /* table 7 */ + RF_CHANPAIR( 1, 2) = 0x6653, + RF_CHANPAIR( 3, 4) = 0x6053, + RF_CHANPAIR( 5, 6) = 0x6663, + RF_CHANPAIR( 7, 8) = 0x6463, + RF_CHANPAIR( 9, 10) = 0x6643, + RF_CHANPAIR(11, 12) = 0x6443, + RF_CHANPAIR(13, 14) = 0x667d, + }, + { /* table 8 */ + RF_CHANPAIR( 1, 2) = 0x6673, + RF_CHANPAIR( 3, 4) = 0x6073, + RF_CHANPAIR( 5, 6) = 0x6653, + RF_CHANPAIR( 7, 8) = 0x6453, + RF_CHANPAIR( 9, 10) = 0x6663, + RF_CHANPAIR(11, 12) = 0x6463, + RF_CHANPAIR(13, 14) = 0x6643, + }, + { /* table 9 */ + RF_CHANPAIR( 1, 2) = 0x664b, + RF_CHANPAIR( 3, 4) = 0x604b, + RF_CHANPAIR( 5, 6) = 0x6673, + RF_CHANPAIR( 7, 8) = 0x6473, + RF_CHANPAIR( 9, 10) = 0x6653, + RF_CHANPAIR(11, 12) = 0x6453, + RF_CHANPAIR(13, 14) = 0x6663, + }, + { /* table 10 */ + RF_CHANPAIR( 1, 2) = 0x666b, + RF_CHANPAIR( 3, 4) = 0x606b, + RF_CHANPAIR( 5, 6) = 0x664b, + RF_CHANPAIR( 7, 8) = 0x644b, + RF_CHANPAIR( 9, 10) = 0x6673, + RF_CHANPAIR(11, 12) = 0x6473, + RF_CHANPAIR(13, 14) = 0x6653, + }, + { /* table 11 */ + RF_CHANPAIR( 1, 2) = 0x665b, + RF_CHANPAIR( 3, 4) = 0x605b, + RF_CHANPAIR( 5, 6) = 0x666b, + RF_CHANPAIR( 7, 8) = 0x646b, + RF_CHANPAIR( 9, 10) = 0x664b, + RF_CHANPAIR(11, 12) = 0x644b, + RF_CHANPAIR(13, 14) = 0x6673, + }, + +}; + +/* The per-channel synth values for autocal. These get written to register 1. */ +static const u16 uw2453_autocal_synth[] = { + RF_CHANNEL( 1) = 0x6847, + RF_CHANNEL( 2) = 0x6847, + RF_CHANNEL( 3) = 0x6867, + RF_CHANNEL( 4) = 0x6867, + RF_CHANNEL( 5) = 0x6867, + RF_CHANNEL( 6) = 0x6867, + RF_CHANNEL( 7) = 0x6857, + RF_CHANNEL( 8) = 0x6857, + RF_CHANNEL( 9) = 0x6857, + RF_CHANNEL(10) = 0x6857, + RF_CHANNEL(11) = 0x6877, + RF_CHANNEL(12) = 0x6877, + RF_CHANNEL(13) = 0x6877, + RF_CHANNEL(14) = 0x684f, +}; + +/* The VCO configuration for autocal (all channels) */ +static const u16 UW2453_AUTOCAL_VCO_CFG = 0x6662; + +/* TX gain settings. The array index corresponds to the TX power integration + * values found in the EEPROM. The values get written to register 7. */ +static u32 uw2453_txgain[] = { + [0x00] = 0x0e313, + [0x01] = 0x0fb13, + [0x02] = 0x0e093, + [0x03] = 0x0f893, + [0x04] = 0x0ea93, + [0x05] = 0x1f093, + [0x06] = 0x1f493, + [0x07] = 0x1f693, + [0x08] = 0x1f393, + [0x09] = 0x1f35b, + [0x0a] = 0x1e6db, + [0x0b] = 0x1ff3f, + [0x0c] = 0x1ffff, + [0x0d] = 0x361d7, + [0x0e] = 0x37fbf, + [0x0f] = 0x3ff8b, + [0x10] = 0x3ff33, + [0x11] = 0x3fb3f, + [0x12] = 0x3ffff, +}; + +/* RF-specific structure */ +struct uw2453_priv { + /* index into synth/VCO config tables where PLL lock was found + * -1 means autocal */ + int config; +}; + +#define UW2453_PRIV(rf) ((struct uw2453_priv *) (rf)->priv) + +static int uw2453_synth_set_channel(struct zd_chip *chip, int channel, + bool autocal) +{ + int r; + int idx = channel - 1; + u32 val; + + if (autocal) + val = UW2453_REGWRITE(1, uw2453_autocal_synth[idx]); + else + val = UW2453_REGWRITE(1, uw2453_std_synth[idx]); + + r = zd_rfwrite_locked(chip, val, RF_RV_BITS); + if (r) + return r; + + return zd_rfwrite_locked(chip, + UW2453_REGWRITE(2, uw2453_synth_divide[idx]), RF_RV_BITS); +} + +static int uw2453_write_vco_cfg(struct zd_chip *chip, u16 value) +{ + /* vendor driver always sets these upper bits even though the specs say + * they are reserved */ + u32 val = 0x40000 | value; + return zd_rfwrite_locked(chip, UW2453_REGWRITE(3, val), RF_RV_BITS); +} + +static int uw2453_init_mode(struct zd_chip *chip) +{ + static const u32 rv[] = { + UW2453_REGWRITE(0, 0x25f98), /* enter IDLE mode */ + UW2453_REGWRITE(0, 0x25f9a), /* enter CAL_VCO mode */ + UW2453_REGWRITE(0, 0x25f94), /* enter RX/TX mode */ + UW2453_REGWRITE(0, 0x27fd4), /* power down RSSI circuit */ + }; + + return zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS); +} + +static int uw2453_set_tx_gain_level(struct zd_chip *chip, int channel) +{ + u8 int_value = chip->pwr_int_values[channel - 1]; + + if (int_value >= ARRAY_SIZE(uw2453_txgain)) { + dev_dbg_f(zd_chip_dev(chip), "can't configure TX gain for " + "int value %x on channel %d\n", int_value, channel); + return 0; + } + + return zd_rfwrite_locked(chip, + UW2453_REGWRITE(7, uw2453_txgain[int_value]), RF_RV_BITS); +} + +static int uw2453_init_hw(struct zd_rf *rf) +{ + int i, r; + int found_config = -1; + u16 intr_status; + struct zd_chip *chip = zd_rf_to_chip(rf); + + static const struct zd_ioreq16 ioreqs[] = { + { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 }, + { ZD_CR17, 0x28 }, /* 6112 no change */ + { ZD_CR23, 0x38 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 }, + { ZD_CR27, 0x15 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 }, + { ZD_CR33, 0x28 }, { ZD_CR34, 0x30 }, + { ZD_CR35, 0x43 }, /* 6112 3e->43 */ + { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 }, + { ZD_CR46, 0x92 }, /* 6112 96->92 */ + { ZD_CR47, 0x1e }, + { ZD_CR48, 0x04 }, /* 5602 Roger */ + { ZD_CR49, 0xfa }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, + { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 }, + { ZD_CR91, 0x00 }, { ZD_CR92, 0x0a }, { ZD_CR98, 0x8d }, + { ZD_CR99, 0x28 }, { ZD_CR100, 0x02 }, + { ZD_CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */ + { ZD_CR102, 0x27 }, + { ZD_CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f + * 6221 1f->1c + */ + { ZD_CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */ + { ZD_CR109, 0x13 }, + { ZD_CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */ + { ZD_CR111, 0x13 }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 }, + { ZD_CR114, 0x23 }, /* 6221 27->23 */ + { ZD_CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */ + { ZD_CR116, 0x24 }, /* 6220 1c->24 */ + { ZD_CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */ + { ZD_CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */ + { ZD_CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */ + { ZD_CR120, 0x4f }, + { ZD_CR121, 0x1f }, /* 6220 4f->1f */ + { ZD_CR122, 0xf0 }, { ZD_CR123, 0x57 }, { ZD_CR125, 0xad }, + { ZD_CR126, 0x6c }, { ZD_CR127, 0x03 }, + { ZD_CR128, 0x14 }, /* 6302 12->11 */ + { ZD_CR129, 0x12 }, /* 6301 10->0f */ + { ZD_CR130, 0x10 }, { ZD_CR137, 0x50 }, { ZD_CR138, 0xa8 }, + { ZD_CR144, 0xac }, { ZD_CR146, 0x20 }, { ZD_CR252, 0xff }, + { ZD_CR253, 0xff }, + }; + + static const u32 rv[] = { + UW2453_REGWRITE(4, 0x2b), /* configure receiver gain */ + UW2453_REGWRITE(5, 0x19e4f), /* configure transmitter gain */ + UW2453_REGWRITE(6, 0xf81ad), /* enable RX/TX filter tuning */ + UW2453_REGWRITE(7, 0x3fffe), /* disable TX gain in test mode */ + + /* enter CAL_FIL mode, TX gain set by registers, RX gain set by pins, + * RSSI circuit powered down, reduced RSSI range */ + UW2453_REGWRITE(0, 0x25f9c), /* 5d01 cal_fil */ + + /* synthesizer configuration for channel 1 */ + UW2453_REGWRITE(1, 0x47), + UW2453_REGWRITE(2, 0x999), + + /* disable manual VCO band selection */ + UW2453_REGWRITE(3, 0x7602), + + /* enable manual VCO band selection, configure current level */ + UW2453_REGWRITE(3, 0x46063), + }; + + r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + if (r) + return r; + + r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS); + if (r) + return r; + + r = uw2453_init_mode(chip); + if (r) + return r; + + /* Try all standard VCO configuration settings on channel 1 */ + for (i = 0; i < ARRAY_SIZE(uw2453_std_vco_cfg) - 1; i++) { + /* Configure synthesizer for channel 1 */ + r = uw2453_synth_set_channel(chip, 1, false); + if (r) + return r; + + /* Write VCO config */ + r = uw2453_write_vco_cfg(chip, uw2453_std_vco_cfg[i][0]); + if (r) + return r; + + /* ack interrupt event */ + r = zd_iowrite16_locked(chip, 0x0f, UW2453_INTR_REG); + if (r) + return r; + + /* check interrupt status */ + r = zd_ioread16_locked(chip, &intr_status, UW2453_INTR_REG); + if (r) + return r; + + if (!(intr_status & 0xf)) { + dev_dbg_f(zd_chip_dev(chip), + "PLL locked on configuration %d\n", i); + found_config = i; + break; + } + } + + if (found_config == -1) { + /* autocal */ + dev_dbg_f(zd_chip_dev(chip), + "PLL did not lock, using autocal\n"); + + r = uw2453_synth_set_channel(chip, 1, true); + if (r) + return r; + + r = uw2453_write_vco_cfg(chip, UW2453_AUTOCAL_VCO_CFG); + if (r) + return r; + } + + /* To match the vendor driver behaviour, we use the configuration after + * the one that produced a lock. */ + UW2453_PRIV(rf)->config = found_config + 1; + + return zd_iowrite16_locked(chip, 0x06, ZD_CR203); +} + +static int uw2453_set_channel(struct zd_rf *rf, u8 channel) +{ + int r; + u16 vco_cfg; + int config = UW2453_PRIV(rf)->config; + bool autocal = (config == -1); + struct zd_chip *chip = zd_rf_to_chip(rf); + + static const struct zd_ioreq16 ioreqs[] = { + { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 }, + { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 }, + }; + + r = uw2453_synth_set_channel(chip, channel, autocal); + if (r) + return r; + + if (autocal) + vco_cfg = UW2453_AUTOCAL_VCO_CFG; + else + vco_cfg = uw2453_std_vco_cfg[config][CHAN_TO_PAIRIDX(channel)]; + + r = uw2453_write_vco_cfg(chip, vco_cfg); + if (r) + return r; + + r = uw2453_init_mode(chip); + if (r) + return r; + + r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); + if (r) + return r; + + r = uw2453_set_tx_gain_level(chip, channel); + if (r) + return r; + + return zd_iowrite16_locked(chip, 0x06, ZD_CR203); +} + +static int uw2453_switch_radio_on(struct zd_rf *rf) +{ + int r; + struct zd_chip *chip = zd_rf_to_chip(rf); + struct zd_ioreq16 ioreqs[] = { + { ZD_CR11, 0x00 }, { ZD_CR251, 0x3f }, + }; + + /* enter RXTX mode */ + r = zd_rfwrite_locked(chip, UW2453_REGWRITE(0, 0x25f94), RF_RV_BITS); + if (r) + return r; + + if (zd_chip_is_zd1211b(chip)) + ioreqs[1].value = 0x7f; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} + +static int uw2453_switch_radio_off(struct zd_rf *rf) +{ + int r; + struct zd_chip *chip = zd_rf_to_chip(rf); + static const struct zd_ioreq16 ioreqs[] = { + { ZD_CR11, 0x04 }, { ZD_CR251, 0x2f }, + }; + + /* enter IDLE mode */ + /* FIXME: shouldn't we go to SLEEP? sent email to zydas */ + r = zd_rfwrite_locked(chip, UW2453_REGWRITE(0, 0x25f90), RF_RV_BITS); + if (r) + return r; + + return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} + +static void uw2453_clear(struct zd_rf *rf) +{ + kfree(rf->priv); +} + +int zd_rf_init_uw2453(struct zd_rf *rf) +{ + rf->init_hw = uw2453_init_hw; + rf->set_channel = uw2453_set_channel; + rf->switch_radio_on = uw2453_switch_radio_on; + rf->switch_radio_off = uw2453_switch_radio_off; + rf->patch_6m_band_edge = zd_rf_generic_patch_6m; + rf->clear = uw2453_clear; + /* we have our own TX integration code */ + rf->update_channel_int = 0; + + rf->priv = kmalloc(sizeof(struct uw2453_priv), GFP_KERNEL); + if (rf->priv == NULL) + return -ENOMEM; + + return 0; +} + diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h deleted file mode 100644 index 0155a1584ed..00000000000 --- a/drivers/net/wireless/zd1211rw/zd_types.h +++ /dev/null @@ -1,71 +0,0 @@ -/* zd_types.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ZD_TYPES_H -#define _ZD_TYPES_H - -#include <linux/types.h> - -/* We have three register spaces mapped into the overall USB address space of - * 64K words (16-bit values). There is the control register space of - * double-word registers, the eeprom register space and the firmware register - * space. The control register space is byte mapped, the others are word - * mapped. - * - * For that reason, we are using byte offsets for control registers and word - * offsets for everything else. - */ - -typedef u32 __nocast zd_addr_t; - -enum { - ADDR_BASE_MASK = 0xff000000, - ADDR_OFFSET_MASK = 0x0000ffff, - ADDR_ZERO_MASK = 0x00ff0000, - NULL_BASE = 0x00000000, - USB_BASE = 0x01000000, - CR_BASE = 0x02000000, - CR_MAX_OFFSET = 0x0b30, - E2P_BASE = 0x03000000, - E2P_MAX_OFFSET = 0x007e, - FW_BASE = 0x04000000, - FW_MAX_OFFSET = 0x0005, -}; - -#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK) -#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK) - -#define ZD_ADDR(base, offset) \ - ((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK))) - -#define ZD_NULL_ADDR ((zd_addr_t)0) -#define USB_REG(offset) ZD_ADDR(USB_BASE, offset) /* word addressing */ -#define CTL_REG(offset) ZD_ADDR(CR_BASE, offset) /* byte addressing */ -#define E2P_REG(offset) ZD_ADDR(E2P_BASE, offset) /* word addressing */ -#define FW_REG(offset) ZD_ADDR(FW_BASE, offset) /* word addressing */ - -static inline zd_addr_t zd_inc_word(zd_addr_t addr) -{ - u32 base = ZD_ADDR_BASE(addr); - u32 offset = ZD_OFFSET(addr); - - offset += base == CR_BASE ? 2 : 1; - - return base | offset; -} - -#endif /* _ZD_TYPES_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 5c265ad0485..a912dc05111 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -1,4 +1,8 @@ -/* zd_usb.c +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> + * Copyright (C) 2006-2007 Michael Wu <flamingice@sourmilk.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,49 +15,89 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include <asm/unaligned.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/module.h> #include <linux/firmware.h> #include <linux/device.h> #include <linux/errno.h> +#include <linux/slab.h> #include <linux/skbuff.h> #include <linux/usb.h> #include <linux/workqueue.h> -#include <net/ieee80211.h> +#include <linux/module.h> +#include <net/mac80211.h> +#include <asm/unaligned.h> #include "zd_def.h" -#include "zd_netdev.h" #include "zd_mac.h" #include "zd_usb.h" -#include "zd_util.h" static struct usb_device_id usb_ids[] = { /* ZD1211 */ - { USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0ace, 0xa211), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x14ea, 0xab10), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 }, - { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 }, - { 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(0x157e, 0x3207), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, /* ZD1211B */ + { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0409, 0x0248), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x054c, 0x0257), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x083a, 0xe501), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0df6, 0x0036), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x13b1, 0x0024), .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(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x2019, 0xed01), .driver_info = DEVICE_ZD1211B }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, + { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, {} }; @@ -67,97 +111,11 @@ MODULE_DEVICE_TABLE(usb, usb_ids); #define FW_ZD1211_PREFIX "zd1211/zd1211_" #define FW_ZD1211B_PREFIX "zd1211/zd1211b_" -/* register address handling */ - -#ifdef DEBUG -static int check_addr(struct zd_usb *usb, zd_addr_t addr) -{ - u32 base = ZD_ADDR_BASE(addr); - u32 offset = ZD_OFFSET(addr); - - if ((u32)addr & ADDR_ZERO_MASK) - goto invalid_address; - switch (base) { - case USB_BASE: - break; - case CR_BASE: - if (offset > CR_MAX_OFFSET) { - dev_dbg(zd_usb_dev(usb), - "CR offset %#010x larger than" - " CR_MAX_OFFSET %#10x\n", - offset, CR_MAX_OFFSET); - goto invalid_address; - } - if (offset & 1) { - dev_dbg(zd_usb_dev(usb), - "CR offset %#010x is not a multiple of 2\n", - offset); - goto invalid_address; - } - break; - case E2P_BASE: - if (offset > E2P_MAX_OFFSET) { - dev_dbg(zd_usb_dev(usb), - "E2P offset %#010x larger than" - " E2P_MAX_OFFSET %#010x\n", - offset, E2P_MAX_OFFSET); - goto invalid_address; - } - break; - case FW_BASE: - if (!usb->fw_base_offset) { - dev_dbg(zd_usb_dev(usb), - "ERROR: fw base offset has not been set\n"); - return -EAGAIN; - } - if (offset > FW_MAX_OFFSET) { - dev_dbg(zd_usb_dev(usb), - "FW offset %#10x is larger than" - " FW_MAX_OFFSET %#010x\n", - offset, FW_MAX_OFFSET); - goto invalid_address; - } - break; - default: - dev_dbg(zd_usb_dev(usb), - "address has unsupported base %#010x\n", addr); - goto invalid_address; - } - - return 0; -invalid_address: - dev_dbg(zd_usb_dev(usb), - "ERROR: invalid address: %#010x\n", addr); - return -EINVAL; -} -#endif /* DEBUG */ - -static u16 usb_addr(struct zd_usb *usb, zd_addr_t addr) -{ - u32 base; - u16 offset; - - base = ZD_ADDR_BASE(addr); - offset = ZD_OFFSET(addr); - - ZD_ASSERT(check_addr(usb, addr) == 0); - - switch (base) { - case CR_BASE: - offset += CR_BASE_OFFSET; - break; - case E2P_BASE: - offset += E2P_BASE_OFFSET; - break; - case FW_BASE: - offset += usb->fw_base_offset; - break; - } - - return offset; -} +static bool check_read_regs(struct zd_usb *usb, struct usb_req_read_regs *req, + unsigned int count); /* USB device initialization */ +static void int_urb_complete(struct urb *urb); static int request_fw_file( const struct firmware **fw, const char *name, struct device *device) @@ -196,7 +154,6 @@ static int upload_code(struct usb_device *udev, */ p = kmalloc(MAX_TRANSFER_SIZE, GFP_KERNEL); if (!p) { - dev_err(&udev->dev, "out of memory\n"); r = -ENOMEM; goto error; } @@ -229,10 +186,11 @@ static int upload_code(struct usb_device *udev, if (flags & REBOOT) { u8 ret; + /* Use "DMA-aware" buffer. */ r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_REQ_FIRMWARE_CONFIRM, USB_DIR_IN | USB_TYPE_VENDOR, - 0, 0, &ret, sizeof(ret), 5000 /* ms */); + 0, 0, p, sizeof(ret), 5000 /* ms */); if (r != sizeof(ret)) { dev_err(&udev->dev, "control request firmeware confirmation failed." @@ -241,6 +199,7 @@ static int upload_code(struct usb_device *udev, r = -ENODEV; goto error; } + ret = p[0]; if (ret & 0x80) { dev_err(&udev->dev, "Internal error while downloading." @@ -265,38 +224,38 @@ static u16 get_word(const void *data, u16 offset) return le16_to_cpu(p[offset]); } -static char *get_fw_name(char *buffer, size_t size, u8 device_type, +static char *get_fw_name(struct zd_usb *usb, char *buffer, size_t size, const char* postfix) { scnprintf(buffer, size, "%s%s", - device_type == DEVICE_ZD1211B ? + usb->is_zd1211b ? FW_ZD1211B_PREFIX : FW_ZD1211_PREFIX, postfix); return buffer; } -static int handle_version_mismatch(struct usb_device *udev, u8 device_type, +static int handle_version_mismatch(struct zd_usb *usb, const struct firmware *ub_fw) { + struct usb_device *udev = zd_usb_to_usbdev(usb); const struct firmware *ur_fw = NULL; int offset; int r = 0; char fw_name[128]; r = request_fw_file(&ur_fw, - get_fw_name(fw_name, sizeof(fw_name), device_type, "ur"), + get_fw_name(usb, fw_name, sizeof(fw_name), "ur"), &udev->dev); if (r) goto error; - r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET, - REBOOT); + r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START, REBOOT); if (r) goto error; - offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16)); + offset = (E2P_BOOT_CODE_OFFSET * sizeof(u16)); r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset, - E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT); + E2P_START + E2P_BOOT_CODE_OFFSET, REBOOT); /* At this point, the vendor driver downloads the whole firmware * image, hacks around with version IDs, and uploads it again, @@ -308,11 +267,12 @@ error: return r; } -static int upload_firmware(struct usb_device *udev, u8 device_type) +static int upload_firmware(struct zd_usb *usb) { int r; u16 fw_bcdDevice; u16 bcdDevice; + struct usb_device *udev = zd_usb_to_usbdev(usb); const struct firmware *ub_fw = NULL; const struct firmware *uph_fw = NULL; char fw_name[128]; @@ -320,12 +280,12 @@ static int upload_firmware(struct usb_device *udev, u8 device_type) bcdDevice = get_bcdDevice(udev); r = request_fw_file(&ub_fw, - get_fw_name(fw_name, sizeof(fw_name), device_type, "ub"), + get_fw_name(usb, fw_name, sizeof(fw_name), "ub"), &udev->dev); if (r) goto error; - fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET); + fw_bcdDevice = get_word(ub_fw->data, E2P_DATA_OFFSET); if (fw_bcdDevice != bcdDevice) { dev_info(&udev->dev, @@ -335,7 +295,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type) dev_warn(&udev->dev, "device has old bootcode, please " "report success or failure\n"); - r = handle_version_mismatch(udev, device_type, ub_fw); + r = handle_version_mismatch(usb, ub_fw); if (r) goto error; } else { @@ -346,13 +306,12 @@ static int upload_firmware(struct usb_device *udev, u8 device_type) r = request_fw_file(&uph_fw, - get_fw_name(fw_name, sizeof(fw_name), device_type, "uphr"), + get_fw_name(usb, fw_name, sizeof(fw_name), "uphr"), &udev->dev); if (r) goto error; - r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET, - REBOOT); + r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START, REBOOT); if (r) { dev_err(&udev->dev, "Could not upload firmware code uph. Error number %d\n", @@ -366,52 +325,119 @@ error: return r; } -static void disable_read_regs_int(struct zd_usb *usb) +MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ur"); +MODULE_FIRMWARE(FW_ZD1211_PREFIX "ur"); +MODULE_FIRMWARE(FW_ZD1211B_PREFIX "ub"); +MODULE_FIRMWARE(FW_ZD1211_PREFIX "ub"); +MODULE_FIRMWARE(FW_ZD1211B_PREFIX "uphr"); +MODULE_FIRMWARE(FW_ZD1211_PREFIX "uphr"); + +/* Read data from device address space using "firmware interface" which does + * not require firmware to be loaded. */ +int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len) { + int r; + struct usb_device *udev = zd_usb_to_usbdev(usb); + u8 *buf; + + /* Use "DMA-aware" buffer. */ + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0, + buf, len, 5000); + if (r < 0) { + dev_err(&udev->dev, + "read over firmware interface failed: %d\n", r); + goto exit; + } else if (r != len) { + dev_err(&udev->dev, + "incomplete read over firmware interface: %d/%d\n", + r, len); + r = -EIO; + goto exit; + } + r = 0; + memcpy(data, buf, len); +exit: + kfree(buf); + return r; +} + +#define urb_dev(urb) (&(urb)->dev->dev) + +static inline void handle_regs_int_override(struct urb *urb) +{ + struct zd_usb *usb = urb->context; struct zd_usb_interrupt *intr = &usb->intr; spin_lock(&intr->lock); - intr->read_regs_enabled = 0; + if (atomic_read(&intr->read_regs_enabled)) { + atomic_set(&intr->read_regs_enabled, 0); + intr->read_regs_int_overridden = 1; + complete(&intr->read_regs.completion); + } spin_unlock(&intr->lock); } -#define urb_dev(urb) (&(urb)->dev->dev) - static inline void handle_regs_int(struct urb *urb) { struct zd_usb *usb = urb->context; struct zd_usb_interrupt *intr = &usb->intr; int len; + u16 int_num; ZD_ASSERT(in_interrupt()); spin_lock(&intr->lock); - if (intr->read_regs_enabled) { - intr->read_regs.length = len = urb->actual_length; - + int_num = le16_to_cpu(*(__le16 *)(urb->transfer_buffer+2)); + if (int_num == CR_INTERRUPT) { + struct zd_mac *mac = zd_hw_mac(zd_usb_to_hw(urb->context)); + spin_lock(&mac->lock); + memcpy(&mac->intr_buffer, urb->transfer_buffer, + USB_MAX_EP_INT_BUFFER); + spin_unlock(&mac->lock); + schedule_work(&mac->process_intr); + } else if (atomic_read(&intr->read_regs_enabled)) { + len = urb->actual_length; + intr->read_regs.length = urb->actual_length; if (len > sizeof(intr->read_regs.buffer)) len = sizeof(intr->read_regs.buffer); + memcpy(intr->read_regs.buffer, urb->transfer_buffer, len); - intr->read_regs_enabled = 0; + + /* Sometimes USB_INT_ID_REGS is not overridden, but comes after + * USB_INT_ID_RETRY_FAILED. Read-reg retry then gets this + * delayed USB_INT_ID_REGS, but leaves USB_INT_ID_REGS of + * retry unhandled. Next read-reg command then might catch + * this wrong USB_INT_ID_REGS. Fix by ignoring wrong reads. + */ + if (!check_read_regs(usb, intr->read_regs.req, + intr->read_regs.req_count)) + goto out; + + atomic_set(&intr->read_regs_enabled, 0); + intr->read_regs_int_overridden = 0; complete(&intr->read_regs.completion); + goto out; } - dev_dbg_f(urb_dev(urb), "regs interrupt ignored\n"); out: spin_unlock(&intr->lock); -} -static inline void handle_retry_failed_int(struct urb *urb) -{ - dev_dbg_f(urb_dev(urb), "retry failed interrupt\n"); + /* CR_INTERRUPT might override read_reg too. */ + if (int_num == CR_INTERRUPT && atomic_read(&intr->read_regs_enabled)) + handle_regs_int_override(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; + struct zd_usb *usb; + struct zd_usb_interrupt *intr; switch (urb->status) { case 0: @@ -422,8 +448,10 @@ static void int_urb_complete(struct urb *urb, struct pt_regs *pt_regs) case -ENOENT: case -ECONNRESET: case -EPIPE: - goto kfree; + dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); + return; default: + dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); goto resubmit; } @@ -438,12 +466,20 @@ static void int_urb_complete(struct urb *urb, struct pt_regs *pt_regs) goto resubmit; } + /* USB_INT_ID_RETRY_FAILED triggered by tx-urb submit can override + * pending USB_INT_ID_REGS causing read command timeout. + */ + usb = urb->context; + intr = &usb->intr; + if (hdr->id != USB_INT_ID_REGS && atomic_read(&intr->read_regs_enabled)) + handle_regs_int_override(urb); + switch (hdr->id) { case USB_INT_ID_REGS: handle_regs_int(urb); break; case USB_INT_ID_RETRY_FAILED: - handle_retry_failed_int(urb); + zd_mac_tx_failed(urb); break; default: dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb, @@ -454,12 +490,11 @@ static void int_urb_complete(struct urb *urb, struct pt_regs *pt_regs) resubmit: r = usb_submit_urb(urb, GFP_ATOMIC); if (r) { - dev_dbg_f(urb_dev(urb), "resubmit urb %p\n", urb); - goto kfree; + dev_dbg_f(urb_dev(urb), "error: resubmit urb %p err code %d\n", + urb, r); + /* TODO: add worker to reset intr->urb */ } return; -kfree: - kfree(urb->transfer_buffer); } static inline int int_urb_interval(struct usb_device *udev) @@ -490,14 +525,13 @@ static inline int usb_int_enabled(struct zd_usb *usb) int zd_usb_enable_int(struct zd_usb *usb) { int r; - struct usb_device *udev; + struct usb_device *udev = zd_usb_to_usbdev(usb); struct zd_usb_interrupt *intr = &usb->intr; - void *transfer_buffer = NULL; struct urb *urb; dev_dbg_f(zd_usb_dev(usb), "\n"); - urb = usb_alloc_urb(0, GFP_NOFS); + urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { r = -ENOMEM; goto out; @@ -513,23 +547,24 @@ int zd_usb_enable_int(struct zd_usb *usb) intr->urb = urb; spin_unlock_irq(&intr->lock); - /* TODO: make it a DMA buffer */ r = -ENOMEM; - transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_NOFS); - if (!transfer_buffer) { + intr->buffer = usb_alloc_coherent(udev, USB_MAX_EP_INT_BUFFER, + GFP_KERNEL, &intr->buffer_dma); + if (!intr->buffer) { dev_dbg_f(zd_usb_dev(usb), "couldn't allocate transfer_buffer\n"); goto error_set_urb_null; } - udev = zd_usb_to_usbdev(usb); usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, EP_INT_IN), - transfer_buffer, USB_MAX_EP_INT_BUFFER, + intr->buffer, USB_MAX_EP_INT_BUFFER, int_urb_complete, usb, intr->interval); + urb->transfer_dma = intr->buffer_dma; + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb); - r = usb_submit_urb(urb, GFP_NOFS); + r = usb_submit_urb(urb, GFP_KERNEL); if (r) { dev_dbg_f(zd_usb_dev(usb), "Couldn't submit urb. Error number %d\n", r); @@ -538,7 +573,8 @@ int zd_usb_enable_int(struct zd_usb *usb) return 0; error: - kfree(transfer_buffer); + usb_free_coherent(udev, USB_MAX_EP_INT_BUFFER, + intr->buffer, intr->buffer_dma); error_set_urb_null: spin_lock_irq(&intr->lock); intr->urb = NULL; @@ -552,8 +588,11 @@ out: void zd_usb_disable_int(struct zd_usb *usb) { unsigned long flags; + struct usb_device *udev = zd_usb_to_usbdev(usb); struct zd_usb_interrupt *intr = &usb->intr; struct urb *urb; + void *buffer; + dma_addr_t buffer_dma; spin_lock_irqsave(&intr->lock, flags); urb = intr->urb; @@ -562,22 +601,30 @@ void zd_usb_disable_int(struct zd_usb *usb) return; } intr->urb = NULL; + buffer = intr->buffer; + buffer_dma = intr->buffer_dma; + intr->buffer = NULL; spin_unlock_irqrestore(&intr->lock, flags); usb_kill_urb(urb); dev_dbg_f(zd_usb_dev(usb), "urb %p killed\n", urb); usb_free_urb(urb); + + if (buffer) + usb_free_coherent(udev, USB_MAX_EP_INT_BUFFER, + buffer, buffer_dma); } static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, unsigned int length) { int i; - struct zd_mac *mac = zd_usb_to_mac(usb); const struct rx_length_info *length_info; if (length < sizeof(struct rx_length_info)) { /* It's not a complete packet anyhow. */ + dev_dbg_f(zd_usb_dev(usb), "invalid, small RX packet : %d\n", + length); return; } length_info = (struct rx_length_info *) @@ -591,26 +638,29 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, * be padded. Unaligned access might also happen if the length_info * structure is not present. */ - if (get_unaligned(&length_info->tag) == cpu_to_le16(RX_LENGTH_INFO_TAG)) + if (get_unaligned_le16(&length_info->tag) == RX_LENGTH_INFO_TAG) { unsigned int l, k, n; for (i = 0, l = 0;; i++) { - k = le16_to_cpu(get_unaligned(&length_info->length[i])); + k = get_unaligned_le16(&length_info->length[i]); + if (k == 0) + return; n = l+k; if (n > length) return; - zd_mac_rx(mac, buffer+l, k); + zd_mac_rx(zd_usb_to_hw(usb), buffer+l, k); if (i >= 2) return; l = (n+3) & ~3; } } else { - zd_mac_rx(mac, buffer, length); + zd_mac_rx(zd_usb_to_hw(usb), buffer, length); } } -static void rx_urb_complete(struct urb *urb, struct pt_regs *pt_regs) +static void rx_urb_complete(struct urb *urb) { + int r; struct zd_usb *usb; struct zd_usb_rx *rx; const u8 *buffer; @@ -625,6 +675,7 @@ static void rx_urb_complete(struct urb *urb, struct pt_regs *pt_regs) case -ENOENT: case -ECONNRESET: case -EPIPE: + dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); return; default: dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); @@ -636,6 +687,8 @@ static void rx_urb_complete(struct urb *urb, struct pt_regs *pt_regs) usb = urb->context; rx = &usb->rx; + tasklet_schedule(&rx->reset_timer_tasklet); + if (length%rx->usb_packet_size > rx->usb_packet_size-4) { /* If there is an old first fragment, we don't care. */ dev_dbg_f(urb_dev(urb), "*** first fragment ***\n"); @@ -664,43 +717,45 @@ static void rx_urb_complete(struct urb *urb, struct pt_regs *pt_regs) } resubmit: - usb_submit_urb(urb, GFP_ATOMIC); + r = usb_submit_urb(urb, GFP_ATOMIC); + if (r) + dev_dbg_f(urb_dev(urb), "urb %p resubmit error %d\n", urb, r); } -static struct urb *alloc_urb(struct zd_usb *usb) +static struct urb *alloc_rx_urb(struct zd_usb *usb) { struct usb_device *udev = zd_usb_to_usbdev(usb); struct urb *urb; void *buffer; - urb = usb_alloc_urb(0, GFP_NOFS); + urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return NULL; - buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_NOFS, - &urb->transfer_dma); + buffer = usb_alloc_coherent(udev, USB_MAX_RX_SIZE, GFP_KERNEL, + &urb->transfer_dma); if (!buffer) { usb_free_urb(urb); return NULL; } usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_DATA_IN), - buffer, USB_MAX_RX_SIZE, + buffer, USB_MAX_RX_SIZE, rx_urb_complete, usb); urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; return urb; } -static void free_urb(struct urb *urb) +static void free_rx_urb(struct urb *urb) { if (!urb) return; - usb_buffer_free(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); + usb_free_coherent(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); usb_free_urb(urb); } -int zd_usb_enable_rx(struct zd_usb *usb) +static int __zd_usb_enable_rx(struct zd_usb *usb) { int i, r; struct zd_usb_rx *rx = &usb->rx; @@ -709,11 +764,11 @@ int zd_usb_enable_rx(struct zd_usb *usb) dev_dbg_f(zd_usb_dev(usb), "\n"); r = -ENOMEM; - urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS); + urbs = kcalloc(RX_URBS_COUNT, sizeof(struct urb *), GFP_KERNEL); if (!urbs) goto error; - for (i = 0; i < URBS_COUNT; i++) { - urbs[i] = alloc_urb(usb); + for (i = 0; i < RX_URBS_COUNT; i++) { + urbs[i] = alloc_rx_urb(usb); if (!urbs[i]) goto error; } @@ -726,18 +781,18 @@ int zd_usb_enable_rx(struct zd_usb *usb) goto error; } rx->urbs = urbs; - rx->urbs_count = URBS_COUNT; + rx->urbs_count = RX_URBS_COUNT; spin_unlock_irq(&rx->lock); - for (i = 0; i < URBS_COUNT; i++) { - r = usb_submit_urb(urbs[i], GFP_NOFS); + for (i = 0; i < RX_URBS_COUNT; i++) { + r = usb_submit_urb(urbs[i], GFP_KERNEL); if (r) goto error_submit; } return 0; error_submit: - for (i = 0; i < URBS_COUNT; i++) { + for (i = 0; i < RX_URBS_COUNT; i++) { usb_kill_urb(urbs[i]); } spin_lock_irq(&rx->lock); @@ -746,13 +801,27 @@ error_submit: spin_unlock_irq(&rx->lock); error: if (urbs) { - for (i = 0; i < URBS_COUNT; i++) - free_urb(urbs[i]); + for (i = 0; i < RX_URBS_COUNT; i++) + free_rx_urb(urbs[i]); } return r; } -void zd_usb_disable_rx(struct zd_usb *usb) +int zd_usb_enable_rx(struct zd_usb *usb) +{ + int r; + struct zd_usb_rx *rx = &usb->rx; + + mutex_lock(&rx->setup_mutex); + r = __zd_usb_enable_rx(usb); + mutex_unlock(&rx->setup_mutex); + + zd_usb_reset_rx_idle_timer(usb); + + return r; +} + +static void __zd_usb_disable_rx(struct zd_usb *usb) { int i; unsigned long flags; @@ -769,7 +838,7 @@ void zd_usb_disable_rx(struct zd_usb *usb) for (i = 0; i < count; i++) { usb_kill_urb(urbs[i]); - free_urb(urbs[i]); + free_rx_urb(urbs[i]); } kfree(urbs); @@ -779,9 +848,139 @@ 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) +void zd_usb_disable_rx(struct zd_usb *usb) +{ + struct zd_usb_rx *rx = &usb->rx; + + mutex_lock(&rx->setup_mutex); + __zd_usb_disable_rx(usb); + mutex_unlock(&rx->setup_mutex); + + tasklet_kill(&rx->reset_timer_tasklet); + cancel_delayed_work_sync(&rx->idle_work); +} + +static void zd_usb_reset_rx(struct zd_usb *usb) +{ + bool do_reset; + struct zd_usb_rx *rx = &usb->rx; + unsigned long flags; + + mutex_lock(&rx->setup_mutex); + + spin_lock_irqsave(&rx->lock, flags); + do_reset = rx->urbs != NULL; + spin_unlock_irqrestore(&rx->lock, flags); + + if (do_reset) { + __zd_usb_disable_rx(usb); + __zd_usb_enable_rx(usb); + } + + mutex_unlock(&rx->setup_mutex); + + if (do_reset) + zd_usb_reset_rx_idle_timer(usb); +} + +/** + * zd_usb_disable_tx - disable transmission + * @usb: the zd1211rw-private USB structure + * + * Frees all URBs in the free list and marks the transmission as disabled. + */ +void zd_usb_disable_tx(struct zd_usb *usb) +{ + struct zd_usb_tx *tx = &usb->tx; + unsigned long flags; + + atomic_set(&tx->enabled, 0); + + /* kill all submitted tx-urbs */ + usb_kill_anchored_urbs(&tx->submitted); + + spin_lock_irqsave(&tx->lock, flags); + WARN_ON(!skb_queue_empty(&tx->submitted_skbs)); + WARN_ON(tx->submitted_urbs != 0); + tx->submitted_urbs = 0; + spin_unlock_irqrestore(&tx->lock, flags); + + /* The stopped state is ignored, relying on ieee80211_wake_queues() + * in a potentionally following zd_usb_enable_tx(). + */ +} + +/** + * zd_usb_enable_tx - enables transmission + * @usb: a &struct zd_usb pointer + * + * This function enables transmission and prepares the &zd_usb_tx data + * structure. + */ +void zd_usb_enable_tx(struct zd_usb *usb) +{ + unsigned long flags; + struct zd_usb_tx *tx = &usb->tx; + + spin_lock_irqsave(&tx->lock, flags); + atomic_set(&tx->enabled, 1); + tx->submitted_urbs = 0; + ieee80211_wake_queues(zd_usb_to_hw(usb)); + tx->stopped = 0; + spin_unlock_irqrestore(&tx->lock, flags); +} + +static void tx_dec_submitted_urbs(struct zd_usb *usb) +{ + struct zd_usb_tx *tx = &usb->tx; + unsigned long flags; + + spin_lock_irqsave(&tx->lock, flags); + --tx->submitted_urbs; + if (tx->stopped && tx->submitted_urbs <= ZD_USB_TX_LOW) { + ieee80211_wake_queues(zd_usb_to_hw(usb)); + tx->stopped = 0; + } + spin_unlock_irqrestore(&tx->lock, flags); +} + +static void tx_inc_submitted_urbs(struct zd_usb *usb) +{ + struct zd_usb_tx *tx = &usb->tx; + unsigned long flags; + + spin_lock_irqsave(&tx->lock, flags); + ++tx->submitted_urbs; + if (!tx->stopped && tx->submitted_urbs > ZD_USB_TX_HIGH) { + ieee80211_stop_queues(zd_usb_to_hw(usb)); + tx->stopped = 1; + } + spin_unlock_irqrestore(&tx->lock, flags); +} + +/** + * tx_urb_complete - completes the execution of an URB + * @urb: a URB + * + * This function is called if the URB has been transferred to a device or an + * error has happened. + */ +static void tx_urb_complete(struct urb *urb) { int r; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + struct zd_usb *usb; + struct zd_usb_tx *tx; + + skb = (struct sk_buff *)urb->context; + info = IEEE80211_SKB_CB(skb); + /* + * grab 'usb' pointer before handing off the skb (since + * it might be freed by zd_mac_tx_to_dev or mac80211) + */ + usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb; + tx = &usb->tx; switch (urb->status) { case 0: @@ -799,59 +998,173 @@ static void tx_urb_complete(struct urb *urb, struct pt_regs *pt_regs) goto resubmit; } free_urb: - usb_buffer_free(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); + skb_unlink(skb, &usb->tx.submitted_skbs); + zd_mac_tx_to_dev(skb, urb->status); usb_free_urb(urb); + tx_dec_submitted_urbs(usb); return; resubmit: + usb_anchor_urb(urb, &tx->submitted); r = usb_submit_urb(urb, GFP_ATOMIC); if (r) { + usb_unanchor_urb(urb); dev_dbg_f(urb_dev(urb), "error resubmit urb %p %d\n", urb, r); goto free_urb; } } -/* Puts the frame on the USB endpoint. It doesn't wait for - * completion. The frame must contain the control set. +/** + * zd_usb_tx: initiates transfer of a frame of the device + * + * @usb: the zd1211rw-private USB structure + * @skb: a &struct sk_buff pointer + * + * This function tranmits a frame to the device. It doesn't wait for + * completion. The frame must contain the control set and have all the + * control set information available. + * + * The function returns 0 if the transfer has been successfully initiated. */ -int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length) +int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb) { int r; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct usb_device *udev = zd_usb_to_usbdev(usb); struct urb *urb; - void *buffer; + struct zd_usb_tx *tx = &usb->tx; - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - r = -ENOMEM; + if (!atomic_read(&tx->enabled)) { + r = -ENOENT; goto out; } - buffer = usb_buffer_alloc(zd_usb_to_usbdev(usb), length, GFP_ATOMIC, - &urb->transfer_dma); - if (!buffer) { + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { r = -ENOMEM; - goto error_free_urb; + goto out; } - memcpy(buffer, frame, length); usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT), - buffer, length, tx_urb_complete, NULL); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + skb->data, skb->len, tx_urb_complete, skb); + + info->rate_driver_data[1] = (void *)jiffies; + skb_queue_tail(&tx->submitted_skbs, skb); + usb_anchor_urb(urb, &tx->submitted); r = usb_submit_urb(urb, GFP_ATOMIC); - if (r) + if (r) { + dev_dbg_f(zd_usb_dev(usb), "error submit urb %p %d\n", urb, r); + usb_unanchor_urb(urb); + skb_unlink(skb, &tx->submitted_skbs); goto error; + } + tx_inc_submitted_urbs(usb); return 0; error: - usb_buffer_free(zd_usb_to_usbdev(usb), length, buffer, - urb->transfer_dma); -error_free_urb: usb_free_urb(urb); out: return r; } +static bool zd_tx_timeout(struct zd_usb *usb) +{ + struct zd_usb_tx *tx = &usb->tx; + struct sk_buff_head *q = &tx->submitted_skbs; + struct sk_buff *skb, *skbnext; + struct ieee80211_tx_info *info; + unsigned long flags, trans_start; + bool have_timedout = false; + + spin_lock_irqsave(&q->lock, flags); + skb_queue_walk_safe(q, skb, skbnext) { + info = IEEE80211_SKB_CB(skb); + trans_start = (unsigned long)info->rate_driver_data[1]; + + if (time_is_before_jiffies(trans_start + ZD_TX_TIMEOUT)) { + have_timedout = true; + break; + } + } + spin_unlock_irqrestore(&q->lock, flags); + + return have_timedout; +} + +static void zd_tx_watchdog_handler(struct work_struct *work) +{ + struct zd_usb *usb = + container_of(work, struct zd_usb, tx.watchdog_work.work); + struct zd_usb_tx *tx = &usb->tx; + + if (!atomic_read(&tx->enabled) || !tx->watchdog_enabled) + goto out; + if (!zd_tx_timeout(usb)) + goto out; + + /* TX halted, try reset */ + dev_warn(zd_usb_dev(usb), "TX-stall detected, resetting device..."); + + usb_queue_reset_device(usb->intf); + + /* reset will stop this worker, don't rearm */ + return; +out: + queue_delayed_work(zd_workqueue, &tx->watchdog_work, + ZD_TX_WATCHDOG_INTERVAL); +} + +void zd_tx_watchdog_enable(struct zd_usb *usb) +{ + struct zd_usb_tx *tx = &usb->tx; + + if (!tx->watchdog_enabled) { + dev_dbg_f(zd_usb_dev(usb), "\n"); + queue_delayed_work(zd_workqueue, &tx->watchdog_work, + ZD_TX_WATCHDOG_INTERVAL); + tx->watchdog_enabled = 1; + } +} + +void zd_tx_watchdog_disable(struct zd_usb *usb) +{ + struct zd_usb_tx *tx = &usb->tx; + + if (tx->watchdog_enabled) { + dev_dbg_f(zd_usb_dev(usb), "\n"); + tx->watchdog_enabled = 0; + cancel_delayed_work_sync(&tx->watchdog_work); + } +} + +static void zd_rx_idle_timer_handler(struct work_struct *work) +{ + struct zd_usb *usb = + container_of(work, struct zd_usb, rx.idle_work.work); + struct zd_mac *mac = zd_usb_to_mac(usb); + + if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags)) + return; + + dev_dbg_f(zd_usb_dev(usb), "\n"); + + /* 30 seconds since last rx, reset rx */ + zd_usb_reset_rx(usb); +} + +static void zd_usb_reset_rx_idle_timer_tasklet(unsigned long param) +{ + struct zd_usb *usb = (struct zd_usb *)param; + + zd_usb_reset_rx_idle_timer(usb); +} + +void zd_usb_reset_rx_idle_timer(struct zd_usb *usb) +{ + struct zd_usb_rx *rx = &usb->rx; + + mod_delayed_work(zd_workqueue, &rx->idle_work, ZD_RX_IDLE_INTERVAL); +} + static inline void init_usb_interrupt(struct zd_usb *usb) { struct zd_usb_interrupt *intr = &usb->intr; @@ -859,54 +1172,53 @@ static inline void init_usb_interrupt(struct zd_usb *usb) spin_lock_init(&intr->lock); intr->interval = int_urb_interval(zd_usb_to_usbdev(usb)); init_completion(&intr->read_regs.completion); - intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT)); + atomic_set(&intr->read_regs_enabled, 0); + intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT); } static inline void init_usb_rx(struct zd_usb *usb) { struct zd_usb_rx *rx = &usb->rx; + spin_lock_init(&rx->lock); + mutex_init(&rx->setup_mutex); if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH) { rx->usb_packet_size = 512; } else { rx->usb_packet_size = 64; } ZD_ASSERT(rx->fragment_length == 0); + INIT_DELAYED_WORK(&rx->idle_work, zd_rx_idle_timer_handler); + rx->reset_timer_tasklet.func = zd_usb_reset_rx_idle_timer_tasklet; + rx->reset_timer_tasklet.data = (unsigned long)usb; } static inline void init_usb_tx(struct zd_usb *usb) { - /* FIXME: at this point we will allocate a fixed number of urb's for - * use in a cyclic scheme */ + struct zd_usb_tx *tx = &usb->tx; + + spin_lock_init(&tx->lock); + atomic_set(&tx->enabled, 0); + tx->stopped = 0; + skb_queue_head_init(&tx->submitted_skbs); + init_usb_anchor(&tx->submitted); + tx->submitted_urbs = 0; + tx->watchdog_enabled = 0; + INIT_DELAYED_WORK(&tx->watchdog_work, zd_tx_watchdog_handler); } -void zd_usb_init(struct zd_usb *usb, struct net_device *netdev, +void zd_usb_init(struct zd_usb *usb, struct ieee80211_hw *hw, struct usb_interface *intf) { memset(usb, 0, sizeof(*usb)); usb->intf = usb_get_intf(intf); - usb_set_intfdata(usb->intf, netdev); + usb_set_intfdata(usb->intf, hw); + init_usb_anchor(&usb->submitted_cmds); init_usb_interrupt(usb); init_usb_tx(usb); init_usb_rx(usb); } -int zd_usb_init_hw(struct zd_usb *usb) -{ - int r; - struct zd_chip *chip = zd_usb_to_chip(usb); - - ZD_ASSERT(mutex_is_locked(&chip->mutex)); - r = zd_ioread16_locked(chip, &usb->fw_base_offset, - USB_REG((u16)FW_BASE_ADDR_OFFSET)); - if (r) - return r; - dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n", - usb->fw_base_offset); - - return 0; -} - void zd_usb_clear(struct zd_usb *usb) { usb_set_intfdata(usb->intf, NULL); @@ -967,12 +1279,15 @@ static int eject_installer(struct usb_interface *intf) int r; /* Find bulk out endpoint */ - endpoint = &iface_desc->endpoint[1].desc; - if ((endpoint->bEndpointAddress & USB_TYPE_MASK) == USB_DIR_OUT && - (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK) { - bulk_out_ep = endpoint->bEndpointAddress; - } else { + for (r = 1; r >= 0; r--) { + endpoint = &iface_desc->endpoint[r].desc; + if (usb_endpoint_dir_out(endpoint) && + usb_endpoint_xfer_bulk(endpoint)) { + bulk_out_ep = endpoint->bEndpointAddress; + break; + } + } + if (r == -1) { dev_err(&udev->dev, "zd1211rw: Could not find bulk out endpoint\n"); return -ENODEV; @@ -1006,11 +1321,44 @@ static int eject_installer(struct usb_interface *intf) return 0; } +int zd_usb_init_hw(struct zd_usb *usb) +{ + int r; + struct zd_mac *mac = zd_usb_to_mac(usb); + + dev_dbg_f(zd_usb_dev(usb), "\n"); + + r = upload_firmware(usb); + if (r) { + dev_err(zd_usb_dev(usb), + "couldn't load firmware. Error number %d\n", r); + return r; + } + + r = usb_reset_configuration(zd_usb_to_usbdev(usb)); + if (r) { + dev_dbg_f(zd_usb_dev(usb), + "couldn't reset configuration. Error number %d\n", r); + return r; + } + + r = zd_mac_init_hw(mac->hw); + if (r) { + dev_dbg_f(zd_usb_dev(usb), + "couldn't initialize mac. Error number %d\n", r); + return r; + } + + usb->initialized = 1; + return 0; +} + static int probe(struct usb_interface *intf, const struct usb_device_id *id) { int r; struct usb_device *udev = interface_to_usbdev(intf); - struct net_device *netdev = NULL; + struct zd_usb *usb; + struct ieee80211_hw *hw = NULL; print_id(udev); @@ -1028,70 +1376,68 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id) goto error; } - netdev = zd_netdev_alloc(intf); - if (netdev == NULL) { - r = -ENOMEM; - goto error; - } - - r = upload_firmware(udev, id->driver_info); + r = usb_reset_device(udev); if (r) { dev_err(&intf->dev, - "couldn't load firmware. Error number %d\n", r); + "couldn't reset usb device. Error number %d\n", r); goto error; } - r = usb_reset_configuration(udev); - if (r) { - dev_dbg_f(&intf->dev, - "couldn't reset configuration. Error number %d\n", r); + hw = zd_mac_alloc_hw(intf); + if (hw == NULL) { + r = -ENOMEM; goto error; } - /* At this point the interrupt endpoint is not generally enabled. We - * save the USB bandwidth until the network device is opened. But - * notify that the initialization of the MAC will require the - * interrupts to be temporary enabled. - */ - r = zd_mac_init_hw(zd_netdev_mac(netdev), id->driver_info); + usb = &zd_hw_mac(hw)->chip.usb; + usb->is_zd1211b = (id->driver_info == DEVICE_ZD1211B) != 0; + + r = zd_mac_preinit_hw(hw); if (r) { dev_dbg_f(&intf->dev, "couldn't initialize mac. Error number %d\n", r); goto error; } - r = register_netdev(netdev); + r = ieee80211_register_hw(hw); if (r) { dev_dbg_f(&intf->dev, - "couldn't register netdev. Error number %d\n", r); + "couldn't register device. Error number %d\n", r); goto error; } dev_dbg_f(&intf->dev, "successful\n"); - dev_info(&intf->dev,"%s\n", netdev->name); + dev_info(&intf->dev, "%s\n", wiphy_name(hw->wiphy)); return 0; error: usb_reset_device(interface_to_usbdev(intf)); - zd_netdev_free(netdev); + if (hw) { + zd_mac_clear(zd_hw_mac(hw)); + ieee80211_free_hw(hw); + } return r; } static void disconnect(struct usb_interface *intf) { - struct net_device *netdev = zd_intf_to_netdev(intf); - struct zd_mac *mac = zd_netdev_mac(netdev); - struct zd_usb *usb = &mac->chip.usb; + struct ieee80211_hw *hw = zd_intf_to_hw(intf); + struct zd_mac *mac; + struct zd_usb *usb; /* Either something really bad happened, or we're just dealing with * a DEVICE_INSTALLER. */ - if (netdev == NULL) + if (hw == NULL) return; + mac = zd_hw_mac(hw); + usb = &mac->chip.usb; + dev_dbg_f(zd_usb_dev(usb), "\n"); - zd_netdev_disconnect(netdev); + ieee80211_unregister_hw(hw); /* Just in case something has gone wrong! */ + zd_usb_disable_tx(usb); zd_usb_disable_rx(usb); zd_usb_disable_int(usb); @@ -1102,15 +1448,98 @@ static void disconnect(struct usb_interface *intf) */ usb_reset_device(interface_to_usbdev(intf)); - zd_netdev_free(netdev); + zd_mac_clear(mac); + ieee80211_free_hw(hw); dev_dbg(&intf->dev, "disconnected\n"); } +static void zd_usb_resume(struct zd_usb *usb) +{ + struct zd_mac *mac = zd_usb_to_mac(usb); + int r; + + dev_dbg_f(zd_usb_dev(usb), "\n"); + + r = zd_op_start(zd_usb_to_hw(usb)); + if (r < 0) { + dev_warn(zd_usb_dev(usb), "Device resume failed " + "with error code %d. Retrying...\n", r); + if (usb->was_running) + set_bit(ZD_DEVICE_RUNNING, &mac->flags); + usb_queue_reset_device(usb->intf); + return; + } + + if (mac->type != NL80211_IFTYPE_UNSPECIFIED) { + r = zd_restore_settings(mac); + if (r < 0) { + dev_dbg(zd_usb_dev(usb), + "failed to restore settings, %d\n", r); + return; + } + } +} + +static void zd_usb_stop(struct zd_usb *usb) +{ + dev_dbg_f(zd_usb_dev(usb), "\n"); + + zd_op_stop(zd_usb_to_hw(usb)); + + zd_usb_disable_tx(usb); + zd_usb_disable_rx(usb); + zd_usb_disable_int(usb); + + usb->initialized = 0; +} + +static int pre_reset(struct usb_interface *intf) +{ + struct ieee80211_hw *hw = usb_get_intfdata(intf); + struct zd_mac *mac; + struct zd_usb *usb; + + if (!hw || intf->condition != USB_INTERFACE_BOUND) + return 0; + + mac = zd_hw_mac(hw); + usb = &mac->chip.usb; + + usb->was_running = test_bit(ZD_DEVICE_RUNNING, &mac->flags); + + zd_usb_stop(usb); + + mutex_lock(&mac->chip.mutex); + return 0; +} + +static int post_reset(struct usb_interface *intf) +{ + struct ieee80211_hw *hw = usb_get_intfdata(intf); + struct zd_mac *mac; + struct zd_usb *usb; + + if (!hw || intf->condition != USB_INTERFACE_BOUND) + return 0; + + mac = zd_hw_mac(hw); + usb = &mac->chip.usb; + + mutex_unlock(&mac->chip.mutex); + + if (usb->was_running) + zd_usb_resume(usb); + return 0; +} + static struct usb_driver driver = { - .name = "zd1211rw", + .name = KBUILD_MODNAME, .id_table = usb_ids, .probe = probe, .disconnect = disconnect, + .pre_reset = pre_reset, + .post_reset = post_reset, + .disable_hub_initiated_lpm = 1, }; struct workqueue_struct *zd_workqueue; @@ -1119,27 +1548,29 @@ 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); + 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); + destroy_workqueue(zd_workqueue); + 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); } @@ -1147,33 +1578,67 @@ static void __exit usb_exit(void) module_init(usb_init); module_exit(usb_exit); +static int zd_ep_regs_out_msg(struct usb_device *udev, void *data, int len, + int *actual_length, int timeout) +{ + /* In USB 2.0 mode EP_REGS_OUT endpoint is interrupt type. However in + * USB 1.1 mode endpoint is bulk. Select correct type URB by endpoint + * descriptor. + */ + struct usb_host_endpoint *ep; + unsigned int pipe; + + pipe = usb_sndintpipe(udev, EP_REGS_OUT); + ep = usb_pipe_endpoint(udev, pipe); + if (!ep) + return -EINVAL; + + if (usb_endpoint_xfer_int(&ep->desc)) { + return usb_interrupt_msg(udev, pipe, data, len, + actual_length, timeout); + } else { + pipe = usb_sndbulkpipe(udev, EP_REGS_OUT); + return usb_bulk_msg(udev, pipe, data, len, actual_length, + timeout); + } +} + static int usb_int_regs_length(unsigned int count) { return sizeof(struct usb_int_regs) + count * sizeof(struct reg_data); } -static void prepare_read_regs_int(struct zd_usb *usb) +static void prepare_read_regs_int(struct zd_usb *usb, + struct usb_req_read_regs *req, + unsigned int count) { struct zd_usb_interrupt *intr = &usb->intr; - spin_lock(&intr->lock); - intr->read_regs_enabled = 1; - INIT_COMPLETION(intr->read_regs.completion); - spin_unlock(&intr->lock); + spin_lock_irq(&intr->lock); + atomic_set(&intr->read_regs_enabled, 1); + intr->read_regs.req = req; + intr->read_regs.req_count = count; + reinit_completion(&intr->read_regs.completion); + spin_unlock_irq(&intr->lock); } -static int get_results(struct zd_usb *usb, u16 *values, - struct usb_req_read_regs *req, unsigned int count) +static void disable_read_regs_int(struct zd_usb *usb) +{ + struct zd_usb_interrupt *intr = &usb->intr; + + spin_lock_irq(&intr->lock); + atomic_set(&intr->read_regs_enabled, 0); + spin_unlock_irq(&intr->lock); +} + +static bool check_read_regs(struct zd_usb *usb, struct usb_req_read_regs *req, + unsigned int count) { - int r; int i; struct zd_usb_interrupt *intr = &usb->intr; struct read_regs_int *rr = &intr->read_regs; struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer; - spin_lock(&intr->lock); - - r = -EIO; /* The created block size seems to be larger than expected. * However results appear to be correct. */ @@ -1181,13 +1646,14 @@ static int get_results(struct zd_usb *usb, u16 *values, dev_dbg_f(zd_usb_dev(usb), "error: actual length %d less than expected %d\n", rr->length, usb_int_regs_length(count)); - goto error_unlock; + return false; } + if (rr->length > sizeof(rr->buffer)) { dev_dbg_f(zd_usb_dev(usb), "error: actual length %d exceeds buffer size %zu\n", rr->length, sizeof(rr->buffer)); - goto error_unlock; + return false; } for (i = 0; i < count; i++) { @@ -1197,25 +1663,56 @@ static int get_results(struct zd_usb *usb, u16 *values, "rd[%d] addr %#06hx expected %#06hx\n", i, le16_to_cpu(rd->addr), le16_to_cpu(req->addr[i])); - goto error_unlock; + return false; } + } + + return true; +} + +static int get_results(struct zd_usb *usb, u16 *values, + struct usb_req_read_regs *req, unsigned int count, + bool *retry) +{ + int r; + int i; + struct zd_usb_interrupt *intr = &usb->intr; + struct read_regs_int *rr = &intr->read_regs; + struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer; + + spin_lock_irq(&intr->lock); + + r = -EIO; + + /* Read failed because firmware bug? */ + *retry = !!intr->read_regs_int_overridden; + if (*retry) + goto error_unlock; + + if (!check_read_regs(usb, req, count)) { + dev_dbg_f(zd_usb_dev(usb), "error: invalid read regs\n"); + goto error_unlock; + } + + for (i = 0; i < count; i++) { + struct reg_data *rd = ®s->regs[i]; values[i] = le16_to_cpu(rd->value); } r = 0; error_unlock: - spin_unlock(&intr->lock); + spin_unlock_irq(&intr->lock); return r; } int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, const zd_addr_t *addresses, unsigned int count) { - int r; - int i, req_len, actual_req_len; + int r, i, req_len, actual_req_len, try_count = 0; struct usb_device *udev; struct usb_req_read_regs *req = NULL; unsigned long timeout; + bool retry = false; if (count < 1) { dev_dbg_f(zd_usb_dev(usb), "error: count is zero\n"); @@ -1233,30 +1730,36 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, return -EWOULDBLOCK; } if (!usb_int_enabled(usb)) { - dev_dbg_f(zd_usb_dev(usb), + dev_dbg_f(zd_usb_dev(usb), "error: usb interrupt not enabled\n"); return -EWOULDBLOCK; } + ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); + BUILD_BUG_ON(sizeof(struct usb_req_read_regs) + USB_MAX_IOREAD16_COUNT * + sizeof(__le16) > sizeof(usb->req_buf)); + BUG_ON(sizeof(struct usb_req_read_regs) + count * sizeof(__le16) > + sizeof(usb->req_buf)); + req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16); - req = kmalloc(req_len, GFP_NOFS); - if (!req) - return -ENOMEM; + req = (void *)usb->req_buf; + req->id = cpu_to_le16(USB_REQ_READ_REGS); for (i = 0; i < count; i++) - req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i])); + req->addr[i] = cpu_to_le16((u16)addresses[i]); +retry_read: + try_count++; udev = zd_usb_to_usbdev(usb); - prepare_read_regs_int(usb); - r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT), - req, req_len, &actual_req_len, 1000 /* ms */); + prepare_read_regs_int(usb, req, count); + r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/); if (r) { dev_dbg_f(zd_usb_dev(usb), - "error in usb_bulk_msg(). Error number %d\n", r); + "error in zd_ep_regs_out_msg(). Error number %d\n", r); goto error; } if (req_len != actual_req_len) { - dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()\n" + dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()\n" " req_len %d != actual_req_len %d\n", req_len, actual_req_len); r = -EIO; @@ -1264,7 +1767,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, } timeout = wait_for_completion_timeout(&usb->intr.read_regs.completion, - msecs_to_jiffies(1000)); + msecs_to_jiffies(50)); if (!timeout) { disable_read_regs_int(usb); dev_dbg_f(zd_usb_dev(usb), "read timed out\n"); @@ -1272,19 +1775,117 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, goto error; } - r = get_results(usb, values, req, count); + r = get_results(usb, values, req, count, &retry); + if (retry && try_count < 20) { + dev_dbg_f(zd_usb_dev(usb), "read retry, tries so far: %d\n", + try_count); + goto retry_read; + } error: - kfree(req); return r; } -int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, - unsigned int count) +static void iowrite16v_urb_complete(struct urb *urb) +{ + struct zd_usb *usb = urb->context; + + if (urb->status && !usb->cmd_error) + usb->cmd_error = urb->status; + + if (!usb->cmd_error && + urb->actual_length != urb->transfer_buffer_length) + usb->cmd_error = -EIO; +} + +static int zd_submit_waiting_urb(struct zd_usb *usb, bool last) +{ + int r = 0; + struct urb *urb = usb->urb_async_waiting; + + if (!urb) + return 0; + + usb->urb_async_waiting = NULL; + + if (!last) + urb->transfer_flags |= URB_NO_INTERRUPT; + + usb_anchor_urb(urb, &usb->submitted_cmds); + r = usb_submit_urb(urb, GFP_KERNEL); + if (r) { + usb_unanchor_urb(urb); + dev_dbg_f(zd_usb_dev(usb), + "error in usb_submit_urb(). Error number %d\n", r); + goto error; + } + + /* fall-through with r == 0 */ +error: + usb_free_urb(urb); + return r; +} + +void zd_usb_iowrite16v_async_start(struct zd_usb *usb) +{ + ZD_ASSERT(usb_anchor_empty(&usb->submitted_cmds)); + ZD_ASSERT(usb->urb_async_waiting == NULL); + ZD_ASSERT(!usb->in_async); + + ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); + + usb->in_async = 1; + usb->cmd_error = 0; + usb->urb_async_waiting = NULL; +} + +int zd_usb_iowrite16v_async_end(struct zd_usb *usb, unsigned int timeout) +{ + int r; + + ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); + ZD_ASSERT(usb->in_async); + + /* Submit last iowrite16v URB */ + r = zd_submit_waiting_urb(usb, true); + if (r) { + dev_dbg_f(zd_usb_dev(usb), + "error in zd_submit_waiting_usb(). " + "Error number %d\n", r); + + usb_kill_anchored_urbs(&usb->submitted_cmds); + goto error; + } + + if (timeout) + timeout = usb_wait_anchor_empty_timeout(&usb->submitted_cmds, + timeout); + if (!timeout) { + usb_kill_anchored_urbs(&usb->submitted_cmds); + if (usb->cmd_error == -ENOENT) { + dev_dbg_f(zd_usb_dev(usb), "timed out"); + r = -ETIMEDOUT; + goto error; + } + } + + r = usb->cmd_error; +error: + usb->in_async = 0; + return r; +} + +int zd_usb_iowrite16v_async(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, + unsigned int count) { int r; struct usb_device *udev; struct usb_req_write_regs *req = NULL; - int i, req_len, actual_req_len; + int i, req_len; + struct urb *urb; + struct usb_host_endpoint *ep; + + ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); + ZD_ASSERT(usb->in_async); if (count == 0) return 0; @@ -1300,42 +1901,77 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, return -EWOULDBLOCK; } + udev = zd_usb_to_usbdev(usb); + + ep = usb_pipe_endpoint(udev, usb_sndintpipe(udev, EP_REGS_OUT)); + if (!ep) + return -ENOENT; + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return -ENOMEM; + req_len = sizeof(struct usb_req_write_regs) + count * sizeof(struct reg_data); - req = kmalloc(req_len, GFP_NOFS); - if (!req) - return -ENOMEM; + req = kmalloc(req_len, GFP_KERNEL); + if (!req) { + r = -ENOMEM; + goto error; + } req->id = cpu_to_le16(USB_REQ_WRITE_REGS); for (i = 0; i < count; i++) { struct reg_data *rw = &req->reg_writes[i]; - rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr)); + rw->addr = cpu_to_le16((u16)ioreqs[i].addr); rw->value = cpu_to_le16(ioreqs[i].value); } - udev = zd_usb_to_usbdev(usb); - r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT), - req, req_len, &actual_req_len, 1000 /* ms */); + /* In USB 2.0 mode endpoint is interrupt type. However in USB 1.1 mode + * endpoint is bulk. Select correct type URB by endpoint descriptor. + */ + if (usb_endpoint_xfer_int(&ep->desc)) + usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT), + req, req_len, iowrite16v_urb_complete, usb, + ep->desc.bInterval); + else + usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_REGS_OUT), + req, req_len, iowrite16v_urb_complete, usb); + + urb->transfer_flags |= URB_FREE_BUFFER; + + /* Submit previous URB */ + r = zd_submit_waiting_urb(usb, false); if (r) { dev_dbg_f(zd_usb_dev(usb), - "error in usb_bulk_msg(). Error number %d\n", r); - goto error; - } - if (req_len != actual_req_len) { - dev_dbg_f(zd_usb_dev(usb), - "error in usb_bulk_msg()" - " req_len %d != actual_req_len %d\n", - req_len, actual_req_len); - r = -EIO; + "error in zd_submit_waiting_usb(). " + "Error number %d\n", r); goto error; } - /* FALL-THROUGH with r == 0 */ + /* Delay submit so that URB_NO_INTERRUPT flag can be set for all URBs + * of currect batch except for very last. + */ + usb->urb_async_waiting = urb; + return 0; error: - kfree(req); + usb_free_urb(urb); return r; } +int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, + unsigned int count) +{ + int r; + + zd_usb_iowrite16v_async_start(usb); + r = zd_usb_iowrite16v_async(usb, ioreqs, count); + if (r) { + zd_usb_iowrite16v_async_end(usb, 0); + return r; + } + return zd_usb_iowrite16v_async_end(usb, 50 /* ms */); +} + int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) { int r; @@ -1373,18 +2009,23 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits); - r = zd_usb_ioread16(usb, &bit_value_template, CR203); + r = zd_usb_ioread16(usb, &bit_value_template, ZD_CR203); if (r) { dev_dbg_f(zd_usb_dev(usb), - "error %d: Couldn't read CR203\n", r); - goto out; + "error %d: Couldn't read ZD_CR203\n", r); + return r; } bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA); + ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); + BUILD_BUG_ON(sizeof(struct usb_req_rfwrite) + + USB_MAX_RFWRITE_BIT_COUNT * sizeof(__le16) > + sizeof(usb->req_buf)); + BUG_ON(sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16) > + sizeof(usb->req_buf)); + req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16); - req = kmalloc(req_len, GFP_NOFS); - if (!req) - return -ENOMEM; + req = (void *)usb->req_buf; req->id = cpu_to_le16(USB_REQ_WRITE_RF); /* 1: 3683a, but not used in ZYDAS driver */ @@ -1399,15 +2040,14 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) } udev = zd_usb_to_usbdev(usb); - r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT), - req, req_len, &actual_req_len, 1000 /* ms */); + r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/); if (r) { dev_dbg_f(zd_usb_dev(usb), - "error in usb_bulk_msg(). Error number %d\n", r); + "error in zd_ep_regs_out_msg(). Error number %d\n", r); goto out; } if (req_len != actual_req_len) { - dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()" + dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()" " req_len %d != actual_req_len %d\n", req_len, actual_req_len); r = -EIO; @@ -1416,6 +2056,5 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) /* FALL-THROUGH with r == 0 */ out: - kfree(req); return r; } diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index e81a2d3cfff..a9075f22517 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -1,4 +1,7 @@ -/* zd_usb.h: Header for USB interface implemented by ZD1211 chip +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,8 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #ifndef _ZD_USB_H @@ -25,7 +27,13 @@ #include <linux/usb.h> #include "zd_def.h" -#include "zd_types.h" + +#define ZD_USB_TX_HIGH 5 +#define ZD_USB_TX_LOW 2 + +#define ZD_TX_TIMEOUT (HZ * 5) +#define ZD_TX_WATCHDOG_INTERVAL round_jiffies_relative(HZ) +#define ZD_RX_IDLE_INTERVAL round_jiffies_relative(30 * HZ) enum devicetype { DEVICE_ZD1211 = 0, @@ -74,17 +82,17 @@ enum control_requests { struct usb_req_read_regs { __le16 id; __le16 addr[0]; -}; +} __packed; struct reg_data { __le16 addr; __le16 value; -}; +} __packed; struct usb_req_write_regs { __le16 id; struct reg_data reg_writes[0]; -}; +} __packed; enum { RF_IF_LE = 0x02, @@ -100,8 +108,8 @@ struct usb_req_rfwrite { __le16 bits; /* RF2595: 24 */ __le16 bit_values[0]; - /* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */ -}; + /* (ZD_CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */ +} __packed; /* USB interrupt */ @@ -118,12 +126,12 @@ enum usb_int_flags { struct usb_int_header { u8 type; /* must always be 1 */ u8 id; -}; +} __packed; struct usb_int_regs { struct usb_int_header hdr; struct reg_data regs[0]; -}; +} __packed; struct usb_int_retry_fail { struct usb_int_header hdr; @@ -131,10 +139,12 @@ struct usb_int_retry_fail { u8 _dummy; u8 addr[ETH_ALEN]; u8 ibss_wakeup_dest; -}; +} __packed; struct read_regs_int { struct completion completion; + struct usb_req_read_regs *req; + unsigned int req_count; /* Stores the USB int structure and contains the USB address of the * first requested register before request. */ @@ -157,8 +167,11 @@ struct zd_usb_interrupt { struct read_regs_int read_regs; spinlock_t lock; struct urb *urb; + void *buffer; + dma_addr_t buffer_dma; int interval; - u8 read_regs_enabled:1; + atomic_t read_regs_enabled; + u8 read_regs_int_overridden:1; }; static inline struct usb_int_regs *get_read_regs(struct zd_usb_interrupt *intr) @@ -166,30 +179,52 @@ static inline struct usb_int_regs *get_read_regs(struct zd_usb_interrupt *intr) return (struct usb_int_regs *)intr->read_regs.buffer; } -#define URBS_COUNT 5 +#define RX_URBS_COUNT 5 struct zd_usb_rx { spinlock_t lock; - u8 fragment[2*USB_MAX_RX_SIZE]; + struct mutex setup_mutex; + struct delayed_work idle_work; + struct tasklet_struct reset_timer_tasklet; + u8 fragment[2 * USB_MAX_RX_SIZE]; unsigned int fragment_length; unsigned int usb_packet_size; struct urb **urbs; int urbs_count; }; +/** + * struct zd_usb_tx - structure used for transmitting frames + * @enabled: atomic enabled flag, indicates whether tx is enabled + * @lock: lock for transmission + * @submitted: anchor for URBs sent to device + * @submitted_urbs: atomic integer that counts the URBs having sent to the + * device, which haven't been completed + * @stopped: indicates whether higher level tx queues are stopped + */ struct zd_usb_tx { + atomic_t enabled; spinlock_t lock; + struct delayed_work watchdog_work; + struct sk_buff_head submitted_skbs; + struct usb_anchor submitted; + int submitted_urbs; + u8 stopped:1, watchdog_enabled:1; }; -/* Contains the usb parts. The structure doesn't require a lock, because intf - * and fw_base_offset, will not be changed after initialization. +/* Contains the usb parts. The structure doesn't require a lock because intf + * will not be changed after initialization. */ struct zd_usb { struct zd_usb_interrupt intr; struct zd_usb_rx rx; struct zd_usb_tx tx; struct usb_interface *intf; - u16 fw_base_offset; + struct usb_anchor submitted_cmds; + struct urb *urb_async_waiting; + int cmd_error; + u8 req_buf[64]; /* zd_usb_iowrite16v needs 62 bytes */ + u8 is_zd1211b:1, initialized:1, was_running:1, in_async:1; }; #define zd_usb_dev(usb) (&usb->intf->dev) @@ -199,30 +234,38 @@ static inline struct usb_device *zd_usb_to_usbdev(struct zd_usb *usb) return interface_to_usbdev(usb->intf); } -static inline struct net_device *zd_intf_to_netdev(struct usb_interface *intf) +static inline struct ieee80211_hw *zd_intf_to_hw(struct usb_interface *intf) { return usb_get_intfdata(intf); } -static inline struct net_device *zd_usb_to_netdev(struct zd_usb *usb) +static inline struct ieee80211_hw *zd_usb_to_hw(struct zd_usb *usb) { - return zd_intf_to_netdev(usb->intf); + return zd_intf_to_hw(usb->intf); } -void zd_usb_init(struct zd_usb *usb, struct net_device *netdev, +void zd_usb_init(struct zd_usb *usb, struct ieee80211_hw *hw, struct usb_interface *intf); int zd_usb_init_hw(struct zd_usb *usb); void zd_usb_clear(struct zd_usb *usb); int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size); +void zd_tx_watchdog_enable(struct zd_usb *usb); +void zd_tx_watchdog_disable(struct zd_usb *usb); + int zd_usb_enable_int(struct zd_usb *usb); void zd_usb_disable_int(struct zd_usb *usb); int zd_usb_enable_rx(struct zd_usb *usb); void zd_usb_disable_rx(struct zd_usb *usb); -int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length); +void zd_usb_reset_rx_idle_timer(struct zd_usb *usb); + +void zd_usb_enable_tx(struct zd_usb *usb); +void zd_usb_disable_tx(struct zd_usb *usb); + +int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb); int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, const zd_addr_t *addresses, unsigned int count); @@ -230,14 +273,20 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, static inline int zd_usb_ioread16(struct zd_usb *usb, u16 *value, const zd_addr_t addr) { - return zd_usb_ioread16v(usb, value, (const zd_addr_t *)&addr, 1); + return zd_usb_ioread16v(usb, value, &addr, 1); } +void zd_usb_iowrite16v_async_start(struct zd_usb *usb); +int zd_usb_iowrite16v_async_end(struct zd_usb *usb, unsigned int timeout); +int zd_usb_iowrite16v_async(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, + unsigned int count); int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, unsigned int count); int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits); +int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len); + extern struct workqueue_struct *zd_workqueue; #endif /* _ZD_USB_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_util.c b/drivers/net/wireless/zd1211rw/zd_util.c deleted file mode 100644 index d20036c15d1..00000000000 --- a/drivers/net/wireless/zd1211rw/zd_util.c +++ /dev/null @@ -1,82 +0,0 @@ -/* zd_util.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Utility program - */ - -#include "zd_def.h" -#include "zd_util.h" - -#ifdef DEBUG -static char hex(u8 v) -{ - v &= 0xf; - return (v < 10 ? '0' : 'a' - 10) + v; -} - -static char hex_print(u8 c) -{ - return (0x20 <= c && c < 0x7f) ? c : '.'; -} - -static void dump_line(const u8 *bytes, size_t size) -{ - char c; - size_t i; - - size = size <= 8 ? size : 8; - printk(KERN_DEBUG "zd1211 %p ", bytes); - for (i = 0; i < 8; i++) { - switch (i) { - case 1: - case 5: - c = '.'; - break; - case 3: - c = ':'; - break; - default: - c = ' '; - } - if (i < size) { - printk("%c%c%c", hex(bytes[i] >> 4), hex(bytes[i]), c); - } else { - printk(" %c", c); - } - } - - for (i = 0; i < size; i++) - printk("%c", hex_print(bytes[i])); - printk("\n"); -} - -void zd_hexdump(const void *bytes, size_t size) -{ - size_t i = 0; - - do { - dump_line((u8 *)bytes + i, size-i); - i += 8; - } while (i < size); -} -#endif /* DEBUG */ - -void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size) -{ - if (buffer_size < tail_size) - return NULL; - return (u8 *)buffer + (buffer_size - tail_size); -} diff --git a/drivers/net/wireless/zd1211rw/zd_util.h b/drivers/net/wireless/zd1211rw/zd_util.h deleted file mode 100644 index ce26f7adea9..00000000000 --- a/drivers/net/wireless/zd1211rw/zd_util.h +++ /dev/null @@ -1,29 +0,0 @@ -/* zd_util.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ZD_UTIL_H -#define _ZD_UTIL_H - -void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size); - -#ifdef DEBUG -void zd_hexdump(const void *bytes, size_t size); -#else -#define zd_hexdump(bytes, size) -#endif /* DEBUG */ - -#endif /* _ZD_UTIL_H */ |
