aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDaniel Drake <dsd@gentoo.org>2007-11-19 15:00:29 +0000
committerDavid S. Miller <davem@davemloft.net>2008-01-28 15:04:47 -0800
commit459c51ad6e1fc19e91a53798358433d3c08cd09d (patch)
treefb86feacf1b229cb4ab6b36b4d1deaf4983b1e45 /drivers
parent0765af4493193149505f118d04d9300f0a15c8f5 (diff)
zd1211rw: port to mac80211
This seems to be working smoothly now. Let's not hold back the mac80211 transition any further. This patch ports the existing driver from softmac to mac80211. Many thanks to everyone who helped out with the porting efforts. Signed-off-by: Daniel Drake <dsd@gentoo.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/zd1211rw/Kconfig7
-rw-r--r--drivers/net/wireless/zd1211rw/Makefile3
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c121
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h55
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.c191
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.h29
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c1536
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h112
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.c264
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.h45
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c282
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h31
12 files changed, 1008 insertions, 1668 deletions
diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig
index d1ab24a9563..74b31eafe72 100644
--- a/drivers/net/wireless/zd1211rw/Kconfig
+++ b/drivers/net/wireless/zd1211rw/Kconfig
@@ -1,14 +1,13 @@
config ZD1211RW
tristate "ZyDAS ZD1211/ZD1211B USB-wireless support"
- depends on USB && IEEE80211_SOFTMAC && WLAN_80211 && EXPERIMENTAL
- select WIRELESS_EXT
+ depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL
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 7a2f2a98eda..cc36126cee8 100644
--- a/drivers/net/wireless/zd1211rw/Makefile
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -1,7 +1,6 @@
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_ieee80211.o zd_mac.o \
zd_rf_al2230.o zd_rf_rf2959.o \
zd_rf_al7230b.o zd_rf_uw2453.o \
zd_rf.o zd_usb.o
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index f831b68f1b9..ef9527c978b 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -30,12 +30,12 @@
#include "zd_rf.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);
}
@@ -50,7 +50,7 @@ void zd_chip_clear(struct zd_chip *chip)
static int scnprint_mac_oui(struct zd_chip *chip, char *buffer, size_t size)
{
- u8 *addr = zd_usb_to_netdev(&chip->usb)->dev_addr;
+ 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]);
}
@@ -378,15 +378,18 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
};
DECLARE_MAC_BUF(mac);
- 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),
- "mac addr %s\n", print_mac(mac, mac_addr));
+ 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),
+ "mac addr %s\n", print_mac(mac, mac_addr));
+ } else {
+ dev_dbg_f(zd_chip_dev(chip), "set NULL mac\n");
+ }
mutex_lock(&chip->mutex);
r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
@@ -980,7 +983,7 @@ static int print_fw_version(struct zd_chip *chip)
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 mode)
{
u32 rates;
ZD_ASSERT(mutex_is_locked(&chip->mutex));
@@ -988,11 +991,11 @@ 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:
+ switch (mode) {
+ case MODE_IEEE80211B:
rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M;
break;
- case IEEE80211G:
+ case MODE_IEEE80211G:
rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M|
CR_RATE_6M|CR_RATE_12M|CR_RATE_24M;
break;
@@ -1003,24 +1006,17 @@ static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std)
}
int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip,
- u8 rts_rate, int preamble)
+ int preamble)
{
- int rts_mod = ZD_RX_CCK;
u32 value = 0;
- /* Modulation bit */
- if (ZD_MODULATION_TYPE(rts_rate) == ZD_OFDM)
- rts_mod = ZD_RX_OFDM;
-
- dev_dbg_f(zd_chip_dev(chip), "rts_rate=%x preamble=%x\n",
- rts_rate, preamble);
-
- value |= ZD_PURE_RATE(rts_rate) << RTSCTS_SH_RTS_RATE;
- value |= rts_mod << RTSCTS_SH_RTS_MOD_TYPE;
+ 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 self-CTS messages, like the vendor driver. */
+ /* 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;
@@ -1109,7 +1105,7 @@ int zd_chip_init_hw(struct zd_chip *chip)
* It might be discussed, whether we should suppport pure b mode for
* full speed USB.
*/
- r = set_mandatory_rates(chip, IEEE80211G);
+ r = set_mandatory_rates(chip, MODE_IEEE80211G);
if (r)
goto out;
/* Disabling interrupts is certainly a smart thing here.
@@ -1320,12 +1316,17 @@ out:
return r;
}
-int zd_chip_set_basic_rates_locked(struct zd_chip *chip, u16 cr_rates)
+int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
{
- ZD_ASSERT((cr_rates & ~(CR_RATES_80211B | CR_RATES_80211G)) == 0);
- dev_dbg_f(zd_chip_dev(chip), "%x\n", cr_rates);
+ int r;
+
+ if (cr_rates & ~(CR_RATES_80211B|CR_RATES_80211G))
+ return -EINVAL;
- return zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL);
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL);
+ mutex_unlock(&chip->mutex);
+ return r;
}
static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size)
@@ -1468,56 +1469,44 @@ u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
{
return (status->frame_status&ZD_RX_OFDM) ?
ofdm_qual_percent(status->signal_quality_ofdm,
- zd_rate_from_ofdm_plcp_header(rx_frame),
+ zd_rate_from_ofdm_plcp_header(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_PLCP_RATE_6M] = 60,
- [ZD_OFDM_PLCP_RATE_9M] = 90,
- [ZD_OFDM_PLCP_RATE_12M] = 120,
- [ZD_OFDM_PLCP_RATE_18M] = 180,
- [ZD_OFDM_PLCP_RATE_24M] = 240,
- [ZD_OFDM_PLCP_RATE_36M] = 360,
- [ZD_OFDM_PLCP_RATE_48M] = 480,
- [ZD_OFDM_PLCP_RATE_54M] = 540,
- };
- u16 rate;
+ u8 zd_rate;
if (status->frame_status & ZD_RX_OFDM) {
- /* Deals with PLCP OFDM rate (not zd_rates) */
- 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 {
switch (zd_cck_plcp_header_signal(rx_frame)) {
case ZD_CCK_PLCP_SIGNAL_1M:
- rate = 10;
+ zd_rate = ZD_CCK_RATE_1M;
break;
case ZD_CCK_PLCP_SIGNAL_2M:
- rate = 20;
+ zd_rate = ZD_CCK_RATE_2M;
break;
case ZD_CCK_PLCP_SIGNAL_5M5:
- rate = 55;
+ zd_rate = ZD_CCK_RATE_5_5M;
break;
case ZD_CCK_PLCP_SIGNAL_11M:
- rate = 110;
+ 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)
@@ -1557,20 +1546,22 @@ void zd_chip_disable_int(struct zd_chip *chip)
mutex_unlock(&chip->mutex);
}
-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);
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_usb_disable_rx(&chip->usb);
+ zd_usb_disable_tx(&chip->usb);
mutex_unlock(&chip->mutex);
}
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 8009b70213e..a88a5693223 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -433,9 +433,10 @@ enum {
#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 (1 << 0) /* 802.11b */
#define CR_RATE_2M (1 << 1) /* 802.11b */
@@ -509,14 +510,37 @@ enum {
#define CR_UNDERRUN_CNT CTL_REG(0x0688)
#define CR_RX_FILTER CTL_REG(0x068c)
+#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 AP_RX_FILTER 0x0400feff
-#define STA_RX_FILTER 0x0000ffff
+#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)
/* Monitor mode sets filter to 0xfffff */
@@ -730,7 +754,7 @@ 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_read_mac_addr_fw(struct zd_chip *chip, u8 *addr);
@@ -835,14 +859,12 @@ 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,
- u8 rts_rate, int preamble);
+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)
{
@@ -859,17 +881,7 @@ static inline int zd_chip_get_basic_rates(struct zd_chip *chip, u16 *cr_rates)
return zd_ioread16(chip, CR_BASIC_RATE_TBL, cr_rates);
}
-int zd_chip_set_basic_rates_locked(struct zd_chip *chip, u16 cr_rates);
-
-static inline int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
-{
- int r;
-
- mutex_lock(&chip->mutex);
- r = zd_chip_set_basic_rates_locked(chip, cr_rates);
- mutex_unlock(&chip->mutex);
- return r;
-}
+int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates);
int zd_chip_lock_phy_regs(struct zd_chip *chip);
int zd_chip_unlock_phy_regs(struct zd_chip *chip);
@@ -893,9 +905,8 @@ 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);
-u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
+u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
struct zd_mc_hash {
u32 low;
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c
index 189160efd2a..77cfe5e7823 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.c
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.c
@@ -16,178 +16,85 @@
*/
/*
- * A lot of this code is generic and should be moved into the upper layers
- * at some point.
+ * In the long term, we'll probably find a better way of handling regulatory
+ * requirements outside of the driver.
*/
-#include <linux/errno.h>
-#include <linux/wireless.h>
#include <linux/kernel.h>
-#include <net/ieee80211.h>
+#include <net/mac80211.h>
-#include "zd_def.h"
#include "zd_ieee80211.h"
#include "zd_mac.h"
+struct channel_range {
+ u8 regdomain;
+ u8 start;
+ u8 end; /* exclusive (channel must be less than end) */
+};
+
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_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 },
/* Japan originally only had channel 14 available (see CHNL_ID 0x40 in
* 802.11). However, in 2001 the range was extended to include channels
* 1-13. The ZyDAS devices still use the old region code but are
* designed to allow the extra channel access in Japan. */
- [ZD_REGDOMAIN_JAPAN_ADD] = { 1, 15},
+ { ZD_REGDOMAIN_JAPAN_ADD, 1, 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)
+static const struct channel_range *zd_channel_range(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;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(channel_ranges); i++) {
+ const struct channel_range *range = &channel_ranges[i];
+ if (range->regdomain == regdomain)
+ return range;
}
- return compute_freq(freq, channel_frequencies[channel-1], 0);
+ return NULL;
}
-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;
-}
+#define CHAN_TO_IDX(chan) ((chan) - 1)
-int zd_find_channel(u8 *channel, const struct iw_freq *freq)
+static void unmask_bg_channels(struct ieee80211_hw *hw,
+ const struct channel_range *range,
+ struct ieee80211_hw_mode *mode)
{
- int i, r;
- u32 mhz;
-
- 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;
+ u8 channel;
- for (i = 0; i < NUM_CHANNELS; i++) {
- if (mhz == channel_frequencies[i]) {
- *channel = i+1;
- return 1;
- }
+ for (channel = range->start; channel < range->end; channel++) {
+ struct ieee80211_channel *chan =
+ &mode->channels[CHAN_TO_IDX(channel)];
+ chan->flag |= IEEE80211_CHAN_W_SCAN |
+ IEEE80211_CHAN_W_ACTIVE_SCAN |
+ IEEE80211_CHAN_W_IBSS;
}
-
- return -EINVAL;
}
-int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain)
+void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain)
{
- struct ieee80211_geo geo;
+ struct zd_mac *mac = zd_hw_mac(hw);
const struct channel_range *range;
- int i;
- u8 channel;
- dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)),
- "regdomain %#04x\n", regdomain);
+ dev_dbg(zd_mac_dev(mac), "regdomain %#02x\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;
+ if (!range) {
+ /* The vendor driver overrides the regulatory domain and
+ * allowed channel registers and unconditionally restricts
+ * available channels to 1-11 everywhere. Match their
+ * questionable behaviour only for regdomains which we don't
+ * recognise. */
+ dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: "
+ "%#02x. Defaulting to FCC.\n", regdomain);
+ range = zd_channel_range(ZD_REGDOMAIN_FCC);
}
- 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;
+ unmask_bg_channels(hw, range, &mac->modes[0]);
+ unmask_bg_channels(hw, range, &mac->modes[1]);
}
+
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
index fbf6491dce7..98b87cfe874 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -1,7 +1,7 @@
#ifndef _ZD_IEEE80211_H
#define _ZD_IEEE80211_H
-#include <net/ieee80211.h>
+#include <net/mac80211.h>
/* Additional definitions from the standards.
*/
@@ -19,22 +19,7 @@ enum {
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);
+void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain);
#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80
@@ -54,8 +39,8 @@ static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header)
*
* 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_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
@@ -87,10 +72,4 @@ static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header)
#define ZD_CCK_PLCP_SIGNAL_5M5 0x37
#define ZD_CCK_PLCP_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 5298a8bf112..aaffd081b1b 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -1,5 +1,7 @@
/* zd_mac.c
*
+ * Copyright (c) 2007 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
* the Free Software Foundation; either version 2 of the License, or
@@ -17,7 +19,6 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/wireless.h>
#include <linux/usb.h>
#include <linux/jiffies.h>
#include <net/ieee80211_radiotap.h>
@@ -26,81 +27,105 @@
#include "zd_chip.h"
#include "zd_mac.h"
#include "zd_ieee80211.h"
-#include "zd_netdev.h"
#include "zd_rf.h"
-static void ieee_init(struct ieee80211_device *ieee);
-static void softmac_init(struct ieee80211softmac_device *sm);
-static void set_rts_cts_work(struct work_struct *work);
-static void set_basic_rates_work(struct work_struct *work);
+/* This table contains the hardware specific values for the modulation rates. */
+static const struct ieee80211_rate zd_rates[] = {
+ { .rate = 10,
+ .val = ZD_CCK_RATE_1M,
+ .flags = IEEE80211_RATE_CCK },
+ { .rate = 20,
+ .val = ZD_CCK_RATE_2M,
+ .val2 = ZD_CCK_RATE_2M | ZD_CCK_PREA_SHORT,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 55,
+ .val = ZD_CCK_RATE_5_5M,
+ .val2 = ZD_CCK_RATE_5_5M | ZD_CCK_PREA_SHORT,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 110,
+ .val = ZD_CCK_RATE_11M,
+ .val2 = ZD_CCK_RATE_11M | ZD_CCK_PREA_SHORT,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 60,
+ .val = ZD_OFDM_RATE_6M,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 90,
+ .val = ZD_OFDM_RATE_9M,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 120,
+ .val = ZD_OFDM_RATE_12M,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 180,
+ .val = ZD_OFDM_RATE_18M,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 240,
+ .val = ZD_OFDM_RATE_24M,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 360,
+ .val = ZD_OFDM_RATE_36M,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 480,
+ .val = ZD_OFDM_RATE_48M,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 540,
+ .val = ZD_OFDM_RATE_54M,
+ .flags = IEEE80211_RATE_OFDM },
+};
+
+static const struct ieee80211_channel zd_channels[] = {
+ { .chan = 1,
+ .freq = 2412},
+ { .chan = 2,
+ .freq = 2417},
+ { .chan = 3,
+ .freq = 2422},
+ { .chan = 4,
+ .freq = 2427},
+ { .chan = 5,
+ .freq = 2432},
+ { .chan = 6,
+ .freq = 2437},
+ { .chan = 7,
+ .freq = 2442},
+ { .chan = 8,
+ .freq = 2447},
+ { .chan = 9,
+ .freq = 2452},
+ { .chan = 10,
+ .freq = 2457},
+ { .chan = 11,
+ .freq = 2462},
+ { .chan = 12,
+ .freq = 2467},
+ { .chan = 13,
+ .freq = 2472},
+ { .chan = 14,
+ .freq = 2484}
+};
static void housekeeping_init(struct zd_mac *mac);
static void housekeeping_enable(struct zd_mac *mac);
static void housekeeping_disable(struct zd_mac *mac);
-static void set_multicast_hash_handler(struct work_struct *work);
-
-static void do_rx(unsigned long mac_ptr);
-
-int zd_mac_init(struct zd_mac *mac,
- struct net_device *netdev,
- struct usb_interface *intf)
-{
- struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev);
-
- memset(mac, 0, sizeof(*mac));
- spin_lock_init(&mac->lock);
- mac->netdev = netdev;
- INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work);
- INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work);
-
- skb_queue_head_init(&mac->rx_queue);
- tasklet_init(&mac->rx_tasklet, do_rx, (unsigned long)mac);
- tasklet_disable(&mac->rx_tasklet);
-
- ieee_init(ieee);
- softmac_init(ieee80211_priv(netdev));
- zd_chip_init(&mac->chip, netdev, intf);
- housekeeping_init(mac);
- INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler);
- return 0;
-}
-
-static int reset_channel(struct zd_mac *mac)
-{
- int r;
- unsigned long flags;
- const struct channel_range *range;
-
- 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;
-}
-
-int zd_mac_preinit_hw(struct zd_mac *mac)
+int zd_mac_preinit_hw(struct ieee80211_hw *hw)
{
int r;
u8 addr[ETH_ALEN];
+ struct zd_mac *mac = zd_hw_mac(hw);
r = zd_chip_read_mac_addr_fw(&mac->chip, addr);
if (r)
return r;
- memcpy(mac->netdev->dev_addr, addr, ETH_ALEN);
+ SET_IEEE80211_PERM_ADDR(hw, addr);
+
return 0;
}
-int zd_mac_init_hw(struct zd_mac *mac)
+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 default_regdomain;
@@ -116,22 +141,9 @@ int zd_mac_init_hw(struct zd_mac *mac)
r = zd_read_regdomain(chip, &default_regdomain);
if (r)
goto disable_int;
- if (!zd_regdomain_supported(default_regdomain)) {
- /* The vendor driver overrides the regulatory domain and
- * allowed channel registers and unconditionally restricts
- * available channels to 1-11 everywhere. Match their
- * questionable behaviour only for regdomains which we don't
- * recognise. */
- dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: "
- "%#04x. Defaulting to FCC.\n", default_regdomain);
- default_regdomain = ZD_REGDOMAIN_FCC;
- }
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. */
@@ -139,9 +151,7 @@ int zd_mac_init_hw(struct zd_mac *mac)
if (r)
goto disable_int;
- r = zd_geo_init(zd_mac_to_ieee80211(mac), mac->regdomain);
- if (r)
- goto disable_int;
+ zd_geo_init(hw, mac->regdomain);
r = 0;
disable_int:
@@ -153,8 +163,6 @@ out:
void zd_mac_clear(struct zd_mac *mac)
{
flush_workqueue(zd_workqueue);
- skb_queue_purge(&mac->rx_queue);
- tasklet_kill(&mac->rx_tasklet);
zd_chip_clear(&mac->chip);
ZD_ASSERT(!spin_is_locked(&mac->lock));
ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
@@ -162,34 +170,27 @@ void zd_mac_clear(struct zd_mac *mac)
static int set_rx_filter(struct zd_mac *mac)
{
- struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
- u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER;
- return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
-}
+ unsigned long flags;
+ u32 filter = STA_RX_FILTER;
-static int set_sniffer(struct zd_mac *mac)
-{
- struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
- return zd_iowrite32(&mac->chip, CR_SNIFFER_ON,
- ieee->iw_mode == IW_MODE_MONITOR ? 1 : 0);
- return 0;
+ spin_lock_irqsave(&mac->lock, flags);
+ if (mac->pass_ctrl)
+ filter |= RX_FILTER_CTRL;
+ spin_unlock_irqrestore(&mac->lock, flags);
+
+ return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
}
static int set_mc_hash(struct zd_mac *mac)
{
struct zd_mc_hash hash;
- struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-
zd_mc_clear(&hash);
- if (ieee->iw_mode == IW_MODE_MONITOR)
- zd_mc_add_all(&hash);
-
return zd_chip_set_multicast_hash(&mac->chip, &hash);
}
-int zd_mac_open(struct net_device *netdev)
+static int zd_op_start(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 zd_usb *usb = &chip->usb;
int r;
@@ -200,46 +201,33 @@ int zd_mac_open(struct net_device *netdev)
goto out;
}
- tasklet_enable(&mac->rx_tasklet);
-
r = zd_chip_enable_int(chip);
if (r < 0)
goto out;
- r = zd_write_mac_addr(chip, netdev->dev_addr);
- if (r)
- goto disable_int;
-
r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);
if (r < 0)
goto disable_int;
r = set_rx_filter(mac);
if (r)
goto disable_int;
- r = set_sniffer(mac);
- if (r)
- goto disable_int;
r = set_mc_hash(mac);
if (r)
goto disable_int;
r = zd_chip_switch_radio_on(chip);
if (r < 0)
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);
return 0;
-disable_rx:
- zd_chip_disable_rx(chip);
+disable_rxtx:
+ zd_chip_dis