mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
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>
This commit is contained in:
parent
0765af4493
commit
459c51ad6e
12 changed files with 1042 additions and 1702 deletions
|
@ -1,14 +1,13 @@
|
||||||
config ZD1211RW
|
config ZD1211RW
|
||||||
tristate "ZyDAS ZD1211/ZD1211B USB-wireless support"
|
tristate "ZyDAS ZD1211/ZD1211B USB-wireless support"
|
||||||
depends on USB && IEEE80211_SOFTMAC && WLAN_80211 && EXPERIMENTAL
|
depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL
|
||||||
select WIRELESS_EXT
|
|
||||||
select FW_LOADER
|
select FW_LOADER
|
||||||
---help---
|
---help---
|
||||||
This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless
|
This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless
|
||||||
chip, present in many USB-wireless adapters.
|
chip, present in many USB-wireless adapters.
|
||||||
|
|
||||||
Device firmware is required alongside this driver. You can download the
|
Device firmware is required alongside this driver. You can download
|
||||||
firmware distribution from http://zd1211.ath.cx/get-firmware
|
the firmware distribution from http://zd1211.ath.cx/get-firmware
|
||||||
|
|
||||||
config ZD1211RW_DEBUG
|
config ZD1211RW_DEBUG
|
||||||
bool "ZyDAS ZD1211 debugging"
|
bool "ZyDAS ZD1211 debugging"
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
obj-$(CONFIG_ZD1211RW) += zd1211rw.o
|
obj-$(CONFIG_ZD1211RW) += zd1211rw.o
|
||||||
|
|
||||||
zd1211rw-objs := zd_chip.o zd_ieee80211.o \
|
zd1211rw-objs := zd_chip.o zd_ieee80211.o zd_mac.o \
|
||||||
zd_mac.o zd_netdev.o \
|
|
||||||
zd_rf_al2230.o zd_rf_rf2959.o \
|
zd_rf_al2230.o zd_rf_rf2959.o \
|
||||||
zd_rf_al7230b.o zd_rf_uw2453.o \
|
zd_rf_al7230b.o zd_rf_uw2453.o \
|
||||||
zd_rf.o zd_usb.o
|
zd_rf.o zd_usb.o
|
||||||
|
|
|
@ -30,12 +30,12 @@
|
||||||
#include "zd_rf.h"
|
#include "zd_rf.h"
|
||||||
|
|
||||||
void zd_chip_init(struct zd_chip *chip,
|
void zd_chip_init(struct zd_chip *chip,
|
||||||
struct net_device *netdev,
|
struct ieee80211_hw *hw,
|
||||||
struct usb_interface *intf)
|
struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
memset(chip, 0, sizeof(*chip));
|
memset(chip, 0, sizeof(*chip));
|
||||||
mutex_init(&chip->mutex);
|
mutex_init(&chip->mutex);
|
||||||
zd_usb_init(&chip->usb, netdev, intf);
|
zd_usb_init(&chip->usb, hw, intf);
|
||||||
zd_rf_init(&chip->rf);
|
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)
|
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",
|
return scnprintf(buffer, size, "%02x-%02x-%02x",
|
||||||
addr[0], addr[1], addr[2]);
|
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);
|
DECLARE_MAC_BUF(mac);
|
||||||
|
|
||||||
|
if (mac_addr) {
|
||||||
reqs[0].value = (mac_addr[3] << 24)
|
reqs[0].value = (mac_addr[3] << 24)
|
||||||
| (mac_addr[2] << 16)
|
| (mac_addr[2] << 16)
|
||||||
| (mac_addr[1] << 8)
|
| (mac_addr[1] << 8)
|
||||||
| mac_addr[0];
|
| mac_addr[0];
|
||||||
reqs[1].value = (mac_addr[5] << 8)
|
reqs[1].value = (mac_addr[5] << 8)
|
||||||
| mac_addr[4];
|
| mac_addr[4];
|
||||||
|
|
||||||
dev_dbg_f(zd_chip_dev(chip),
|
dev_dbg_f(zd_chip_dev(chip),
|
||||||
"mac addr %s\n", print_mac(mac, mac_addr));
|
"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);
|
mutex_lock(&chip->mutex);
|
||||||
r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
|
r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
|
||||||
|
@ -980,7 +983,7 @@ static int print_fw_version(struct zd_chip *chip)
|
||||||
return 0;
|
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;
|
u32 rates;
|
||||||
ZD_ASSERT(mutex_is_locked(&chip->mutex));
|
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
|
* that the device is supporting. Until further notice we should try
|
||||||
* to support 802.11g also for full speed USB.
|
* to support 802.11g also for full speed USB.
|
||||||
*/
|
*/
|
||||||
switch (std) {
|
switch (mode) {
|
||||||
case IEEE80211B:
|
case MODE_IEEE80211B:
|
||||||
rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M;
|
rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M;
|
||||||
break;
|
break;
|
||||||
case IEEE80211G:
|
case MODE_IEEE80211G:
|
||||||
rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M|
|
rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M|
|
||||||
CR_RATE_6M|CR_RATE_12M|CR_RATE_24M;
|
CR_RATE_6M|CR_RATE_12M|CR_RATE_24M;
|
||||||
break;
|
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,
|
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;
|
u32 value = 0;
|
||||||
|
|
||||||
/* Modulation bit */
|
dev_dbg_f(zd_chip_dev(chip), "preamble=%x\n", preamble);
|
||||||
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;
|
|
||||||
value |= preamble << RTSCTS_SH_RTS_PMB_TYPE;
|
value |= preamble << RTSCTS_SH_RTS_PMB_TYPE;
|
||||||
value |= preamble << RTSCTS_SH_CTS_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_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_CTS_RATE;
|
||||||
value |= ZD_RX_CCK << RTSCTS_SH_CTS_MOD_TYPE;
|
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
|
* It might be discussed, whether we should suppport pure b mode for
|
||||||
* full speed USB.
|
* full speed USB.
|
||||||
*/
|
*/
|
||||||
r = set_mandatory_rates(chip, IEEE80211G);
|
r = set_mandatory_rates(chip, MODE_IEEE80211G);
|
||||||
if (r)
|
if (r)
|
||||||
goto out;
|
goto out;
|
||||||
/* Disabling interrupts is certainly a smart thing here.
|
/* Disabling interrupts is certainly a smart thing here.
|
||||||
|
@ -1320,12 +1316,17 @@ int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
|
||||||
return r;
|
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);
|
int r;
|
||||||
dev_dbg_f(zd_chip_dev(chip), "%x\n", cr_rates);
|
|
||||||
|
|
||||||
return zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL);
|
if (cr_rates & ~(CR_RATES_80211B|CR_RATES_80211G))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
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)
|
static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size)
|
||||||
|
@ -1473,51 +1474,39 @@ u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
|
||||||
cck_qual_percent(status->signal_quality_cck);
|
cck_qual_percent(status->signal_quality_cck);
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 zd_rx_strength_percent(u8 rssi)
|
/**
|
||||||
|
* 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)
|
||||||
{
|
{
|
||||||
int r = (rssi*100) / 41;
|
u8 zd_rate;
|
||||||
if (r > 100)
|
|
||||||
r = 100;
|
|
||||||
return (u8) r;
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 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;
|
|
||||||
if (status->frame_status & ZD_RX_OFDM) {
|
if (status->frame_status & ZD_RX_OFDM) {
|
||||||
/* Deals with PLCP OFDM rate (not zd_rates) */
|
zd_rate = zd_rate_from_ofdm_plcp_header(rx_frame);
|
||||||
u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame);
|
|
||||||
rate = ofdm_rates[ofdm_rate & 0xf];
|
|
||||||
} else {
|
} else {
|
||||||
switch (zd_cck_plcp_header_signal(rx_frame)) {
|
switch (zd_cck_plcp_header_signal(rx_frame)) {
|
||||||
case ZD_CCK_PLCP_SIGNAL_1M:
|
case ZD_CCK_PLCP_SIGNAL_1M:
|
||||||
rate = 10;
|
zd_rate = ZD_CCK_RATE_1M;
|
||||||
break;
|
break;
|
||||||
case ZD_CCK_PLCP_SIGNAL_2M:
|
case ZD_CCK_PLCP_SIGNAL_2M:
|
||||||
rate = 20;
|
zd_rate = ZD_CCK_RATE_2M;
|
||||||
break;
|
break;
|
||||||
case ZD_CCK_PLCP_SIGNAL_5M5:
|
case ZD_CCK_PLCP_SIGNAL_5M5:
|
||||||
rate = 55;
|
zd_rate = ZD_CCK_RATE_5_5M;
|
||||||
break;
|
break;
|
||||||
case ZD_CCK_PLCP_SIGNAL_11M:
|
case ZD_CCK_PLCP_SIGNAL_11M:
|
||||||
rate = 110;
|
zd_rate = ZD_CCK_RATE_11M;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rate = 0;
|
zd_rate = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rate;
|
return zd_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zd_chip_switch_radio_on(struct zd_chip *chip)
|
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);
|
mutex_unlock(&chip->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
int zd_chip_enable_rx(struct zd_chip *chip)
|
int zd_chip_enable_rxtx(struct zd_chip *chip)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
mutex_lock(&chip->mutex);
|
mutex_lock(&chip->mutex);
|
||||||
|
zd_usb_enable_tx(&chip->usb);
|
||||||
r = zd_usb_enable_rx(&chip->usb);
|
r = zd_usb_enable_rx(&chip->usb);
|
||||||
mutex_unlock(&chip->mutex);
|
mutex_unlock(&chip->mutex);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void zd_chip_disable_rx(struct zd_chip *chip)
|
void zd_chip_disable_rxtx(struct zd_chip *chip)
|
||||||
{
|
{
|
||||||
mutex_lock(&chip->mutex);
|
mutex_lock(&chip->mutex);
|
||||||
zd_usb_disable_rx(&chip->usb);
|
zd_usb_disable_rx(&chip->usb);
|
||||||
|
zd_usb_disable_tx(&chip->usb);
|
||||||
mutex_unlock(&chip->mutex);
|
mutex_unlock(&chip->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -433,9 +433,10 @@ enum {
|
||||||
#define CR_GROUP_HASH_P2 CTL_REG(0x0628)
|
#define CR_GROUP_HASH_P2 CTL_REG(0x0628)
|
||||||
|
|
||||||
#define CR_RX_TIMEOUT CTL_REG(0x062C)
|
#define CR_RX_TIMEOUT CTL_REG(0x062C)
|
||||||
|
|
||||||
/* Basic rates supported by the BSS. When producing ACK or CTS messages, the
|
/* 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
|
* 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_BASIC_RATE_TBL CTL_REG(0x0630)
|
||||||
#define CR_RATE_1M (1 << 0) /* 802.11b */
|
#define CR_RATE_1M (1 << 0) /* 802.11b */
|
||||||
#define CR_RATE_2M (1 << 1) /* 802.11b */
|
#define CR_RATE_2M (1 << 1) /* 802.11b */
|
||||||
|
@ -509,14 +510,37 @@ enum {
|
||||||
#define CR_UNDERRUN_CNT CTL_REG(0x0688)
|
#define CR_UNDERRUN_CNT CTL_REG(0x0688)
|
||||||
|
|
||||||
#define CR_RX_FILTER CTL_REG(0x068c)
|
#define CR_RX_FILTER CTL_REG(0x068c)
|
||||||
|
#define RX_FILTER_ASSOC_REQUEST (1 << 0)
|
||||||
#define RX_FILTER_ASSOC_RESPONSE (1 << 1)
|
#define RX_FILTER_ASSOC_RESPONSE (1 << 1)
|
||||||
|
#define RX_FILTER_REASSOC_REQUEST (1 << 2)
|
||||||
#define RX_FILTER_REASSOC_RESPONSE (1 << 3)
|
#define RX_FILTER_REASSOC_RESPONSE (1 << 3)
|
||||||
|
#define RX_FILTER_PROBE_REQUEST (1 << 4)
|
||||||
#define RX_FILTER_PROBE_RESPONSE (1 << 5)
|
#define RX_FILTER_PROBE_RESPONSE (1 << 5)
|
||||||
|
/* bits 6 and 7 reserved */
|
||||||
#define RX_FILTER_BEACON (1 << 8)
|
#define RX_FILTER_BEACON (1 << 8)
|
||||||
|
#define RX_FILTER_ATIM (1 << 9)
|
||||||
#define RX_FILTER_DISASSOC (1 << 10)
|
#define RX_FILTER_DISASSOC (1 << 10)
|
||||||
#define RX_FILTER_AUTH (1 << 11)
|
#define RX_FILTER_AUTH (1 << 11)
|
||||||
#define AP_RX_FILTER 0x0400feff
|
#define RX_FILTER_DEAUTH (1 << 12)
|
||||||
#define STA_RX_FILTER 0x0000ffff
|
#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 */
|
/* 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)
|
#define zd_chip_dev(chip) (&(chip)->usb.intf->dev)
|
||||||
|
|
||||||
void zd_chip_init(struct zd_chip *chip,
|
void zd_chip_init(struct zd_chip *chip,
|
||||||
struct net_device *netdev,
|
struct ieee80211_hw *hw,
|
||||||
struct usb_interface *intf);
|
struct usb_interface *intf);
|
||||||
void zd_chip_clear(struct zd_chip *chip);
|
void zd_chip_clear(struct zd_chip *chip);
|
||||||
int zd_chip_read_mac_addr_fw(struct zd_chip *chip, u8 *addr);
|
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_switch_radio_off(struct zd_chip *chip);
|
||||||
int zd_chip_enable_int(struct zd_chip *chip);
|
int zd_chip_enable_int(struct zd_chip *chip);
|
||||||
void zd_chip_disable_int(struct zd_chip *chip);
|
void zd_chip_disable_int(struct zd_chip *chip);
|
||||||
int zd_chip_enable_rx(struct zd_chip *chip);
|
int zd_chip_enable_rxtx(struct zd_chip *chip);
|
||||||
void zd_chip_disable_rx(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_enable_hwint(struct zd_chip *chip);
|
||||||
int zd_chip_disable_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_generic_patch_6m_band(struct zd_chip *chip, int channel);
|
||||||
|
int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, int preamble);
|
||||||
int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip,
|
|
||||||
u8 rts_rate, int preamble);
|
|
||||||
|
|
||||||
static inline int zd_get_encryption_type(struct zd_chip *chip, u32 *type)
|
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);
|
return zd_ioread16(chip, CR_BASIC_RATE_TBL, cr_rates);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
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_lock_phy_regs(struct zd_chip *chip);
|
int zd_chip_lock_phy_regs(struct zd_chip *chip);
|
||||||
int zd_chip_unlock_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,
|
u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
|
||||||
const struct rx_status *status);
|
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 {
|
struct zd_mc_hash {
|
||||||
u32 low;
|
u32 low;
|
||||||
|
|
|
@ -16,178 +16,85 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A lot of this code is generic and should be moved into the upper layers
|
* In the long term, we'll probably find a better way of handling regulatory
|
||||||
* at some point.
|
* requirements outside of the driver.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/errno.h>
|
|
||||||
#include <linux/wireless.h>
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <net/ieee80211.h>
|
#include <net/mac80211.h>
|
||||||
|
|
||||||
#include "zd_def.h"
|
|
||||||
#include "zd_ieee80211.h"
|
#include "zd_ieee80211.h"
|
||||||
#include "zd_mac.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[] = {
|
static const struct channel_range channel_ranges[] = {
|
||||||
[0] = { 0, 0},
|
{ ZD_REGDOMAIN_FCC, 1, 12 },
|
||||||
[ZD_REGDOMAIN_FCC] = { 1, 12},
|
{ ZD_REGDOMAIN_IC, 1, 12 },
|
||||||
[ZD_REGDOMAIN_IC] = { 1, 12},
|
{ ZD_REGDOMAIN_ETSI, 1, 14 },
|
||||||
[ZD_REGDOMAIN_ETSI] = { 1, 14},
|
{ ZD_REGDOMAIN_JAPAN, 1, 14 },
|
||||||
[ZD_REGDOMAIN_JAPAN] = { 1, 14},
|
{ ZD_REGDOMAIN_SPAIN, 1, 14 },
|
||||||
[ZD_REGDOMAIN_SPAIN] = { 1, 14},
|
{ ZD_REGDOMAIN_FRANCE, 1, 14 },
|
||||||
[ZD_REGDOMAIN_FRANCE] = { 1, 14},
|
|
||||||
|
|
||||||
/* Japan originally only had channel 14 available (see CHNL_ID 0x40 in
|
/* Japan originally only had channel 14 available (see CHNL_ID 0x40 in
|
||||||
* 802.11). However, in 2001 the range was extended to include channels
|
* 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
|
* 1-13. The ZyDAS devices still use the old region code but are
|
||||||
* designed to allow the extra channel access in Japan. */
|
* 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)
|
static 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->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;
|
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 NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHAN_TO_IDX(chan) ((chan) - 1)
|
||||||
|
|
||||||
|
static void unmask_bg_channels(struct ieee80211_hw *hw,
|
||||||
|
const struct channel_range *range,
|
||||||
|
struct ieee80211_hw_mode *mode)
|
||||||
|
{
|
||||||
u8 channel;
|
u8 channel;
|
||||||
|
|
||||||
dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)),
|
for (channel = range->start; channel < range->end; channel++) {
|
||||||
"regdomain %#04x\n", regdomain);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain)
|
||||||
|
{
|
||||||
|
struct zd_mac *mac = zd_hw_mac(hw);
|
||||||
|
const struct channel_range *range;
|
||||||
|
|
||||||
|
dev_dbg(zd_mac_dev(mac), "regdomain %#02x\n", regdomain);
|
||||||
|
|
||||||
range = zd_channel_range(regdomain);
|
range = zd_channel_range(regdomain);
|
||||||
if (range->start == 0) {
|
if (!range) {
|
||||||
dev_err(zd_mac_dev(zd_netdev_mac(ieee->dev)),
|
/* The vendor driver overrides the regulatory domain and
|
||||||
"zd1211 regdomain %#04x not supported\n",
|
* allowed channel registers and unconditionally restricts
|
||||||
regdomain);
|
* available channels to 1-11 everywhere. Match their
|
||||||
return -EINVAL;
|
* 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));
|
unmask_bg_channels(hw, range, &mac->modes[0]);
|
||||||
|
unmask_bg_channels(hw, range, &mac->modes[1]);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef _ZD_IEEE80211_H
|
#ifndef _ZD_IEEE80211_H
|
||||||
#define _ZD_IEEE80211_H
|
#define _ZD_IEEE80211_H
|
||||||
|
|
||||||
#include <net/ieee80211.h>
|
#include <net/mac80211.h>
|
||||||
|
|
||||||
/* Additional definitions from the standards.
|
/* Additional definitions from the standards.
|
||||||
*/
|
*/
|
||||||
|
@ -19,22 +19,7 @@ enum {
|
||||||
MAX_CHANNEL24 = 14,
|
MAX_CHANNEL24 = 14,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct channel_range {
|
void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain);
|
||||||
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
|
#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80
|
||||||
|
|
||||||
|
@ -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_5M5 0x37
|
||||||
#define ZD_CCK_PLCP_SIGNAL_11M 0x6e
|
#define ZD_CCK_PLCP_SIGNAL_11M 0x6e
|
||||||
|
|
||||||
enum ieee80211_std {
|
|
||||||
IEEE80211B = 0x01,
|
|
||||||
IEEE80211A = 0x02,
|
|
||||||
IEEE80211G = 0x04,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* _ZD_IEEE80211_H */
|
#endif /* _ZD_IEEE80211_H */
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,14 +18,11 @@
|
||||||
#ifndef _ZD_MAC_H
|
#ifndef _ZD_MAC_H
|
||||||
#define _ZD_MAC_H
|
#define _ZD_MAC_H
|
||||||
|
|
||||||
#include <linux/wireless.h>
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/workqueue.h>
|
#include <net/mac80211.h>
|
||||||
#include <net/ieee80211.h>
|
|
||||||
#include <net/ieee80211softmac.h>
|
|
||||||
|
|
||||||
#include "zd_chip.h"
|
#include "zd_chip.h"
|
||||||
#include "zd_netdev.h"
|
#include "zd_ieee80211.h"
|
||||||
|
|
||||||
struct zd_ctrlset {
|
struct zd_ctrlset {
|
||||||
u8 modulation;
|
u8 modulation;
|
||||||
|
@ -141,58 +138,68 @@ struct rx_status {
|
||||||
#define ZD_RX_CRC16_ERROR 0x40
|
#define ZD_RX_CRC16_ERROR 0x40
|
||||||
#define ZD_RX_ERROR 0x80
|
#define ZD_RX_ERROR 0x80
|
||||||
|
|
||||||
|
enum mac_flags {
|
||||||
|
MAC_FIXED_CHANNEL = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
struct housekeeping {
|
struct housekeeping {
|
||||||
struct delayed_work link_led_work;
|
struct delayed_work link_led_work;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct zd_tx_skb_control_block - control block for tx skbuffs
|
||||||
|
* @control: &struct ieee80211_tx_control pointer
|
||||||
|
* @context: context pointer
|
||||||
|
*
|
||||||
|
* This structure is used to fill the cb field in an &sk_buff to transmit.
|
||||||
|
* The control field is NULL, if there is no requirement from the mac80211
|
||||||
|
* stack to report about the packet ACK. This is the case if the flag
|
||||||
|
* IEEE80211_TXCTL_NO_ACK is not set in &struct ieee80211_tx_control.
|
||||||
|
*/
|
||||||
|
struct zd_tx_skb_control_block {
|
||||||
|
struct ieee80211_tx_control *control;
|
||||||
|
struct ieee80211_hw *hw;
|
||||||
|
void *context;
|
||||||
|
};
|
||||||
|
|
||||||
#define ZD_MAC_STATS_BUFFER_SIZE 16
|
#define ZD_MAC_STATS_BUFFER_SIZE 16
|
||||||
|
|
||||||
|
#define ZD_MAC_MAX_ACK_WAITERS 10
|
||||||
|
|
||||||
struct zd_mac {
|
struct zd_mac {
|
||||||
struct zd_chip chip;
|
struct zd_chip chip;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct net_device *netdev;
|
struct ieee80211_hw *hw;
|
||||||
|
|
||||||
/* Unlocked reading possible */
|
|
||||||
struct iw_statistics iw_stats;
|
|
||||||
|
|
||||||
struct housekeeping housekeeping;
|
struct housekeeping housekeeping;
|
||||||
struct work_struct set_multicast_hash_work;
|
struct work_struct set_multicast_hash_work;
|
||||||
|
struct work_struct set_rts_cts_work;
|
||||||
|
struct work_struct set_rx_filter_work;
|
||||||
struct zd_mc_hash multicast_hash;
|
struct zd_mc_hash multicast_hash;
|
||||||
struct delayed_work set_rts_cts_work;
|
|
||||||
struct delayed_work set_basic_rates_work;
|
|
||||||
|
|
||||||
struct tasklet_struct rx_tasklet;
|
|
||||||
struct sk_buff_head rx_queue;
|
|
||||||
|
|
||||||
unsigned int stats_count;
|
|
||||||
u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE];
|
|
||||||
u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE];
|
|
||||||
u8 regdomain;
|
u8 regdomain;
|
||||||
u8 default_regdomain;
|
u8 default_regdomain;
|
||||||
u8 requested_channel;
|
int type;
|
||||||
|
int associated;
|
||||||
/* A bitpattern of cr_rates */
|
struct sk_buff_head ack_wait_queue;
|
||||||
u16 basic_rates;
|
struct ieee80211_channel channels[14];
|
||||||
|
struct ieee80211_rate rates[12];
|
||||||
/* A zd_rate */
|
struct ieee80211_hw_mode modes[2];
|
||||||
u8 rts_rate;
|
|
||||||
|
|
||||||
/* Short preamble (used for RTS/CTS) */
|
/* Short preamble (used for RTS/CTS) */
|
||||||
unsigned int short_preamble:1;
|
unsigned int short_preamble:1;
|
||||||
|
|
||||||
/* flags to indicate update in progress */
|
/* flags to indicate update in progress */
|
||||||
unsigned int updating_rts_rate:1;
|
unsigned int updating_rts_rate:1;
|
||||||
unsigned int updating_basic_rates: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;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct ieee80211_device *zd_mac_to_ieee80211(struct zd_mac *mac)
|
static inline struct zd_mac *zd_hw_mac(struct ieee80211_hw *hw)
|
||||||
{
|
{
|
||||||
return zd_netdev_ieee80211(mac->netdev);
|
return hw->priv;
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct zd_mac *zd_netdev_mac(struct net_device *netdev)
|
|
||||||
{
|
|
||||||
return ieee80211softmac_priv(netdev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct zd_mac *zd_chip_to_mac(struct zd_chip *chip)
|
static inline struct zd_mac *zd_chip_to_mac(struct zd_chip *chip)
|
||||||
|
@ -205,35 +212,22 @@ static inline struct zd_mac *zd_usb_to_mac(struct zd_usb *usb)
|
||||||
return zd_chip_to_mac(zd_usb_to_chip(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))
|
#define zd_mac_dev(mac) (zd_chip_dev(&(mac)->chip))
|
||||||
|
|
||||||
int zd_mac_init(struct zd_mac *mac,
|
struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf);
|
||||||
struct net_device *netdev,
|
|
||||||
struct usb_interface *intf);
|
|
||||||
void zd_mac_clear(struct zd_mac *mac);
|
void zd_mac_clear(struct zd_mac *mac);
|
||||||
|
|
||||||
int zd_mac_preinit_hw(struct zd_mac *mac);
|
int zd_mac_preinit_hw(struct ieee80211_hw *hw);
|
||||||
int zd_mac_init_hw(struct zd_mac *mac);
|
int zd_mac_init_hw(struct ieee80211_hw *hw);
|
||||||
|
|
||||||
int zd_mac_open(struct net_device *netdev);
|
int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length);
|
||||||
int zd_mac_stop(struct net_device *netdev);
|
void zd_mac_tx_failed(struct ieee80211_hw *hw);
|
||||||
int zd_mac_set_mac_address(struct net_device *dev, void *p);
|
void zd_mac_tx_to_dev(struct sk_buff *skb, int error);
|
||||||
void zd_mac_set_multicast_list(struct net_device *netdev);
|
|
||||||
|
|
||||||
int zd_mac_rx_irq(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);
|
|
||||||
u8 zd_mac_get_channel(struct zd_mac *mac);
|
|
||||||
|
|
||||||
int zd_mac_set_mode(struct zd_mac *mac, u32 mode);
|
|
||||||
int zd_mac_get_mode(struct zd_mac *mac, u32 *mode);
|
|
||||||
|
|
||||||
int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range);
|
|
||||||
|
|
||||||
struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void zd_dump_rx_status(const struct rx_status *status);
|
void zd_dump_rx_status(const struct rx_status *status);
|
||||||
|
|
|
@ -1,264 +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)
|
|
||||||
{
|
|
||||||
struct zd_mac *mac = zd_netdev_mac(netdev);
|
|
||||||
struct iw_freq *freq = &req->freq;
|
|
||||||
|
|
||||||
return zd_channel_to_freq(freq, zd_mac_get_channel(mac));
|
|
||||||
}
|
|
||||||
|
|
||||||
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_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 = zd_mac_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);
|
|
||||||
}
|
|
|
@ -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 */
|
|
|
@ -17,18 +17,16 @@
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/usb.h>
|
#include <linux/usb.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <net/ieee80211.h>
|
#include <net/mac80211.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
#include "zd_def.h"
|
#include "zd_def.h"
|
||||||
#include "zd_netdev.h"
|
|
||||||
#include "zd_mac.h"
|
#include "zd_mac.h"
|
||||||
#include "zd_usb.h"
|
#include "zd_usb.h"
|
||||||
|
|
||||||
|
@ -353,18 +351,6 @@ static inline void handle_regs_int(struct urb *urb)
|
||||||
spin_unlock(&intr->lock);
|
spin_unlock(&intr->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void handle_retry_failed_int(struct urb *urb)
|
|
||||||
{
|
|
||||||
struct zd_usb *usb = urb->context;
|
|
||||||
struct zd_mac *mac = zd_usb_to_mac(usb);
|
|
||||||
struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
|
|
||||||
|
|
||||||
ieee->stats.tx_errors++;
|
|
||||||
ieee->ieee_stats.tx_retry_limit_exceeded++;
|
|
||||||
dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void int_urb_complete(struct urb *urb)
|
static void int_urb_complete(struct urb *urb)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
@ -400,7 +386,7 @@ static void int_urb_complete(struct urb *urb)
|
||||||
handle_regs_int(urb);
|
handle_regs_int(urb);
|
||||||
break;
|
break;
|
||||||
case USB_INT_ID_RETRY_FAILED:
|
case USB_INT_ID_RETRY_FAILED:
|
||||||
handle_retry_failed_int(urb);
|
zd_mac_tx_failed(zd_usb_to_hw(urb->context));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb,
|
dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb,
|
||||||
|
@ -530,14 +516,10 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
|
||||||
unsigned int length)
|
unsigned int length)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct zd_mac *mac = zd_usb_to_mac(usb);
|
|
||||||
const struct rx_length_info *length_info;
|
const struct rx_length_info *length_info;
|
||||||
|
|
||||||
if (length < sizeof(struct rx_length_info)) {
|
if (length < sizeof(struct rx_length_info)) {
|
||||||
/* It's not a complete packet anyhow. */
|
/* It's not a complete packet anyhow. */
|
||||||
struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
|
|
||||||
ieee->stats.rx_errors++;
|
|
||||||
ieee->stats.rx_length_errors++;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
length_info = (struct rx_length_info *)
|
length_info = (struct rx_length_info *)
|
||||||
|
@ -561,13 +543,13 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
|
||||||
n = l+k;
|
n = l+k;
|
||||||
if (n > length)
|
if (n > length)
|
||||||
return;
|
return;
|
||||||
zd_mac_rx_irq(mac, buffer+l, k);
|
zd_mac_rx(zd_usb_to_hw(usb), buffer+l, k);
|
||||||
if (i >= 2)
|
if (i >= 2)
|
||||||
return;
|
return;
|
||||||
l = (n+3) & ~3;
|
l = (n+3) & ~3;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
zd_mac_rx_irq(mac, buffer, length);
|
zd_mac_rx(zd_usb_to_hw(usb), buffer, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,7 +611,7 @@ static void rx_urb_complete(struct urb *urb)
|
||||||
usb_submit_urb(urb, GFP_ATOMIC);
|
usb_submit_urb(urb, GFP_ATOMIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 usb_device *udev = zd_usb_to_usbdev(usb);
|
||||||
struct urb *urb;
|
struct urb *urb;
|
||||||
|
@ -653,7 +635,7 @@ static struct urb *alloc_urb(struct zd_usb *usb)
|
||||||
return urb;
|
return urb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_urb(struct urb *urb)
|
static void free_rx_urb(struct urb *urb)
|
||||||
{
|
{
|
||||||
if (!urb)
|
if (!urb)
|
||||||
return;
|
return;
|
||||||
|
@ -671,11 +653,11 @@ int zd_usb_enable_rx(struct zd_usb *usb)
|
||||||
dev_dbg_f(zd_usb_dev(usb), "\n");
|
dev_dbg_f(zd_usb_dev(usb), "\n");
|
||||||
|
|
||||||
r = -ENOMEM;
|
r = -ENOMEM;
|
||||||
urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_KERNEL);
|
urbs = kcalloc(RX_URBS_COUNT, sizeof(struct urb *), GFP_KERNEL);
|
||||||
if (!urbs)
|
if (!urbs)
|
||||||
goto error;
|
goto error;
|
||||||
for (i = 0; i < URBS_COUNT; i++) {
|
for (i = 0; i < RX_URBS_COUNT; i++) {
|
||||||
urbs[i] = alloc_urb(usb);
|
urbs[i] = alloc_rx_urb(usb);
|
||||||
if (!urbs[i])
|
if (!urbs[i])
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -688,10 +670,10 @@ int zd_usb_enable_rx(struct zd_usb *usb)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
rx->urbs = urbs;
|
rx->urbs = urbs;
|
||||||
rx->urbs_count = URBS_COUNT;
|
rx->urbs_count = RX_URBS_COUNT;
|
||||||
spin_unlock_irq(&rx->lock);
|
spin_unlock_irq(&rx->lock);
|
||||||
|
|
||||||
for (i = 0; i < URBS_COUNT; i++) {
|
for (i = 0; i < RX_URBS_COUNT; i++) {
|
||||||
r = usb_submit_urb(urbs[i], GFP_KERNEL);
|
r = usb_submit_urb(urbs[i], GFP_KERNEL);
|
||||||
if (r)
|
if (r)
|
||||||
goto error_submit;
|
goto error_submit;
|
||||||
|
@ -699,7 +681,7 @@ int zd_usb_enable_rx(struct zd_usb *usb)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
error_submit:
|
error_submit:
|
||||||
for (i = 0; i < URBS_COUNT; i++) {
|
for (i = 0; i < RX_URBS_COUNT; i++) {
|
||||||
usb_kill_urb(urbs[i]);
|
usb_kill_urb(urbs[i]);
|
||||||
}
|
}
|
||||||
spin_lock_irq(&rx->lock);
|
spin_lock_irq(&rx->lock);
|
||||||
|
@ -708,8 +690,8 @@ int zd_usb_enable_rx(struct zd_usb *usb)
|
||||||
spin_unlock_irq(&rx->lock);
|
spin_unlock_irq(&rx->lock);
|
||||||
error:
|
error:
|
||||||
if (urbs) {
|
if (urbs) {
|
||||||
for (i = 0; i < URBS_COUNT; i++)
|
for (i = 0; i < RX_URBS_COUNT; i++)
|
||||||
free_urb(urbs[i]);
|
free_rx_urb(urbs[i]);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -731,7 +713,7 @@ void zd_usb_disable_rx(struct zd_usb *usb)
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
usb_kill_urb(urbs[i]);
|
usb_kill_urb(urbs[i]);
|
||||||
free_urb(urbs[i]);
|
free_rx_urb(urbs[i]);
|
||||||
}
|
}
|
||||||
kfree(urbs);
|
kfree(urbs);
|
||||||
|
|
||||||
|
@ -741,9 +723,142 @@ void zd_usb_disable_rx(struct zd_usb *usb)
|
||||||
spin_unlock_irqrestore(&rx->lock, flags);
|
spin_unlock_irqrestore(&rx->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
struct list_head *pos, *n;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&tx->lock, flags);
|
||||||
|
list_for_each_safe(pos, n, &tx->free_urb_list) {
|
||||||
|
list_del(pos);
|
||||||
|
usb_free_urb(list_entry(pos, struct urb, urb_list));
|
||||||
|
}
|
||||||
|
tx->enabled = 0;
|
||||||
|
tx->submitted_urbs = 0;
|
||||||
|
/* The stopped state is ignored, relying on ieee80211_wake_queues()
|
||||||
|
* in a potentionally following zd_usb_enable_tx().
|
||||||
|
*/
|
||||||
|
spin_unlock_irqrestore(&tx->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
tx->enabled = 1;
|
||||||
|
tx->submitted_urbs = 0;
|
||||||
|
ieee80211_wake_queues(zd_usb_to_hw(usb));
|
||||||
|
tx->stopped = 0;
|
||||||
|
spin_unlock_irqrestore(&tx->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* alloc_tx_urb - provides an tx URB
|
||||||
|
* @usb: a &struct zd_usb pointer
|
||||||
|
*
|
||||||
|
* Allocates a new URB. If possible takes the urb from the free list in
|
||||||
|
* usb->tx.
|
||||||
|
*/
|
||||||
|
static struct urb *alloc_tx_urb(struct zd_usb *usb)
|
||||||
|
{
|
||||||
|
struct zd_usb_tx *tx = &usb->tx;
|
||||||
|
unsigned long flags;
|
||||||
|
struct list_head *entry;
|
||||||
|
struct urb *urb;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&tx->lock, flags);
|
||||||
|
if (list_empty(&tx->free_urb_list)) {
|
||||||
|
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
entry = tx->free_urb_list.next;
|
||||||
|
list_del(entry);
|
||||||
|
urb = list_entry(entry, struct urb, urb_list);
|
||||||
|
out:
|
||||||
|
spin_unlock_irqrestore(&tx->lock, flags);
|
||||||
|
return urb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* free_tx_urb - frees a used tx URB
|
||||||
|
* @usb: a &struct zd_usb pointer
|
||||||
|
* @urb: URB to be freed
|
||||||
|
*
|
||||||
|
* Frees the the transmission URB, which means to put it on the free URB
|
||||||
|
* list.
|
||||||
|
*/
|
||||||
|
static void free_tx_urb(struct zd_usb *usb, struct urb *urb)
|
||||||
|
{
|
||||||
|
struct zd_usb_tx *tx = &usb->tx;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&tx->lock, flags);
|
||||||
|
if (!tx->enabled) {
|
||||||
|
usb_free_urb(urb);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
list_add(&urb->urb_list, &tx->free_urb_list);
|
||||||
|
out:
|
||||||
|
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)
|
static void tx_urb_complete(struct urb *urb)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
struct zd_tx_skb_control_block *cb;
|
||||||
|
struct zd_usb *usb;
|
||||||
|
|
||||||
switch (urb->status) {
|
switch (urb->status) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -761,9 +876,12 @@ static void tx_urb_complete(struct urb *urb)
|
||||||
goto resubmit;
|
goto resubmit;
|
||||||
}
|
}
|
||||||
free_urb:
|
free_urb:
|
||||||
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
|
skb = (struct sk_buff *)urb->context;
|
||||||
urb->transfer_buffer, urb->transfer_dma);
|
zd_mac_tx_to_dev(skb, urb->status);
|
||||||
usb_free_urb(urb);
|
cb = (struct zd_tx_skb_control_block *)skb->cb;
|
||||||
|
usb = &zd_hw_mac(cb->hw)->chip.usb;
|
||||||
|
free_tx_urb(usb, urb);
|
||||||
|
tx_dec_submitted_urbs(usb);
|
||||||
return;
|
return;
|
||||||
resubmit:
|
resubmit:
|
||||||
r = usb_submit_urb(urb, GFP_ATOMIC);
|
r = usb_submit_urb(urb, GFP_ATOMIC);
|
||||||
|
@ -773,43 +891,40 @@ static void tx_urb_complete(struct urb *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;
|
int r;
|
||||||
struct usb_device *udev = zd_usb_to_usbdev(usb);
|
struct usb_device *udev = zd_usb_to_usbdev(usb);
|
||||||
struct urb *urb;
|
struct urb *urb;
|
||||||
void *buffer;
|
|
||||||
|
|
||||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
urb = alloc_tx_urb(usb);
|
||||||
if (!urb) {
|
if (!urb) {
|
||||||
r = -ENOMEM;
|
r = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = usb_buffer_alloc(zd_usb_to_usbdev(usb), length, GFP_ATOMIC,
|
|
||||||
&urb->transfer_dma);
|
|
||||||
if (!buffer) {
|
|
||||||
r = -ENOMEM;
|
|
||||||
goto error_free_urb;
|
|
||||||
}
|
|
||||||
memcpy(buffer, frame, length);
|
|
||||||
|
|
||||||
usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
|
usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
|
||||||
buffer, length, tx_urb_complete, NULL);
|
skb->data, skb->len, tx_urb_complete, skb);
|
||||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
|
||||||
|
|
||||||
r = usb_submit_urb(urb, GFP_ATOMIC);
|
r = usb_submit_urb(urb, GFP_ATOMIC);
|
||||||
if (r)
|
if (r)
|
||||||
goto error;
|
goto error;
|
||||||
|
tx_inc_submitted_urbs(usb);
|
||||||
return 0;
|
return 0;
|
||||||
error:
|
error:
|
||||||
usb_buffer_free(zd_usb_to_usbdev(usb), length, buffer,
|
free_tx_urb(usb, urb);
|
||||||
urb->transfer_dma);
|
|
||||||
error_free_urb:
|
|
||||||
usb_free_urb(urb);
|
|
||||||
out:
|
out:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -838,16 +953,20 @@ static inline void init_usb_rx(struct zd_usb *usb)
|
||||||
|
|
||||||
static inline void init_usb_tx(struct zd_usb *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
|
struct zd_usb_tx *tx = &usb->tx;
|
||||||
* use in a cyclic scheme */
|
spin_lock_init(&tx->lock);
|
||||||
|
tx->enabled = 0;
|
||||||
|
tx->stopped = 0;
|
||||||
|
INIT_LIST_HEAD(&tx->free_urb_list);
|
||||||
|
tx->submitted_urbs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
memset(usb, 0, sizeof(*usb));
|
memset(usb, 0, sizeof(*usb));
|
||||||
usb->intf = usb_get_intf(intf);
|
usb->intf = usb_get_intf(intf);
|
||||||
usb_set_intfdata(usb->intf, netdev);
|
usb_set_intfdata(usb->intf, hw);
|
||||||
init_usb_interrupt(usb);
|
init_usb_interrupt(usb);
|
||||||
init_usb_tx(usb);
|
init_usb_tx(usb);
|
||||||
init_usb_rx(usb);
|
init_usb_rx(usb);
|
||||||
|
@ -973,7 +1092,7 @@ int zd_usb_init_hw(struct zd_usb *usb)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = zd_mac_init_hw(mac);
|
r = zd_mac_init_hw(mac->hw);
|
||||||
if (r) {
|
if (r) {
|
||||||
dev_dbg_f(zd_usb_dev(usb),
|
dev_dbg_f(zd_usb_dev(usb),
|
||||||
"couldn't initialize mac. Error number %d\n", r);
|
"couldn't initialize mac. Error number %d\n", r);
|
||||||
|
@ -987,9 +1106,9 @@ int zd_usb_init_hw(struct zd_usb *usb)
|
||||||
static int probe(struct usb_interface *intf, const struct usb_device_id *id)
|
static int probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
struct zd_usb *usb;
|
|
||||||
struct usb_device *udev = interface_to_usbdev(intf);
|
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);
|
print_id(udev);
|
||||||
|
|
||||||
|
@ -1007,57 +1126,65 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_reset_device(interface_to_usbdev(intf));
|
r = usb_reset_device(udev);
|
||||||
|
if (r) {
|
||||||
|
dev_err(&intf->dev,
|
||||||
|
"couldn't reset usb device. Error number %d\n", r);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
netdev = zd_netdev_alloc(intf);
|
hw = zd_mac_alloc_hw(intf);
|
||||||
if (netdev == NULL) {
|
if (hw == NULL) {
|
||||||
r = -ENOMEM;
|
r = -ENOMEM;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb = &zd_netdev_mac(netdev)->chip.usb;
|
usb = &zd_hw_mac(hw)->chip.usb;
|
||||||
usb->is_zd1211b = (id->driver_info == DEVICE_ZD1211B) != 0;
|
usb->is_zd1211b = (id->driver_info == DEVICE_ZD1211B) != 0;
|
||||||
|
|
||||||
r = zd_mac_preinit_hw(zd_netdev_mac(netdev));
|
r = zd_mac_preinit_hw(hw);
|
||||||
if (r) {
|
if (r) {
|
||||||
dev_dbg_f(&intf->dev,
|
dev_dbg_f(&intf->dev,
|
||||||
"couldn't initialize mac. Error number %d\n", r);
|
"couldn't initialize mac. Error number %d\n", r);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = register_netdev(netdev);
|
r = ieee80211_register_hw(hw);
|
||||||
if (r) {
|
if (r) {
|
||||||
dev_dbg_f(&intf->dev,
|
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;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg_f(&intf->dev, "successful\n");
|
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;
|
return 0;
|
||||||
error:
|
error:
|
||||||
usb_reset_device(interface_to_usbdev(intf));
|
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;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disconnect(struct usb_interface *intf)
|
static void disconnect(struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
struct net_device *netdev = zd_intf_to_netdev(intf);
|
struct ieee80211_hw *hw = zd_intf_to_hw(intf);
|
||||||
struct zd_mac *mac;
|
struct zd_mac *mac;
|
||||||
struct zd_usb *usb;
|
struct zd_usb *usb;
|
||||||
|
|
||||||
/* Either something really bad happened, or we're just dealing with
|
/* Either something really bad happened, or we're just dealing with
|
||||||
* a DEVICE_INSTALLER. */
|
* a DEVICE_INSTALLER. */
|
||||||
if (netdev == NULL)
|
if (hw == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mac = zd_netdev_mac(netdev);
|
mac = zd_hw_mac(hw);
|
||||||
usb = &mac->chip.usb;
|
usb = &mac->chip.usb;
|
||||||
|
|
||||||
dev_dbg_f(zd_usb_dev(usb), "\n");
|
dev_dbg_f(zd_usb_dev(usb), "\n");
|
||||||
|
|
||||||
zd_netdev_disconnect(netdev);
|
ieee80211_unregister_hw(hw);
|
||||||
|
|
||||||
/* Just in case something has gone wrong! */
|
/* Just in case something has gone wrong! */
|
||||||
zd_usb_disable_rx(usb);
|
zd_usb_disable_rx(usb);
|
||||||
|
@ -1070,12 +1197,13 @@ static void disconnect(struct usb_interface *intf)
|
||||||
*/
|
*/
|
||||||
usb_reset_device(interface_to_usbdev(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");
|
dev_dbg(&intf->dev, "disconnected\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct usb_driver driver = {
|
static struct usb_driver driver = {
|
||||||
.name = "zd1211rw",
|
.name = KBUILD_MODNAME,
|
||||||
.id_table = usb_ids,
|
.id_table = usb_ids,
|
||||||
.probe = probe,
|
.probe = probe,
|
||||||
.disconnect = disconnect,
|
.disconnect = disconnect,
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
|
|
||||||
#include "zd_def.h"
|
#include "zd_def.h"
|
||||||
|
|
||||||
|
#define ZD_USB_TX_HIGH 5
|
||||||
|
#define ZD_USB_TX_LOW 2
|
||||||
|
|
||||||
enum devicetype {
|
enum devicetype {
|
||||||
DEVICE_ZD1211 = 0,
|
DEVICE_ZD1211 = 0,
|
||||||
DEVICE_ZD1211B = 1,
|
DEVICE_ZD1211B = 1,
|
||||||
|
@ -165,7 +168,7 @@ static inline struct usb_int_regs *get_read_regs(struct zd_usb_interrupt *intr)
|
||||||
return (struct usb_int_regs *)intr->read_regs.buffer;
|
return (struct usb_int_regs *)intr->read_regs.buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define URBS_COUNT 5
|
#define RX_URBS_COUNT 5
|
||||||
|
|
||||||
struct zd_usb_rx {
|
struct zd_usb_rx {
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
@ -176,8 +179,21 @@ struct zd_usb_rx {
|
||||||
int urbs_count;
|
int urbs_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct zd_usb_tx - structure used for transmitting frames
|
||||||
|
* @lock: lock for transmission
|
||||||
|
* @free_urb_list: list of free URBs, contains all the URBs, which can be used
|
||||||
|
* @submitted_urbs: atomic integer that counts the URBs having sent to the
|
||||||
|
* device, which haven't been completed
|
||||||
|
* @enabled: enabled flag, indicates whether tx is enabled
|
||||||
|
* @stopped: indicates whether higher level tx queues are stopped
|
||||||
|
*/
|
||||||
struct zd_usb_tx {
|
struct zd_usb_tx {
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
struct list_head free_urb_list;
|
||||||
|
int submitted_urbs;
|
||||||
|
int enabled;
|
||||||
|
int stopped;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Contains the usb parts. The structure doesn't require a lock because intf
|
/* Contains the usb parts. The structure doesn't require a lock because intf
|
||||||
|
@ -198,17 +214,17 @@ static inline struct usb_device *zd_usb_to_usbdev(struct zd_usb *usb)
|
||||||
return interface_to_usbdev(usb->intf);
|
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);
|
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);
|
struct usb_interface *intf);
|
||||||
int zd_usb_init_hw(struct zd_usb *usb);
|
int zd_usb_init_hw(struct zd_usb *usb);
|
||||||
void zd_usb_clear(struct zd_usb *usb);
|
void zd_usb_clear(struct zd_usb *usb);
|
||||||
|
@ -221,7 +237,10 @@ void zd_usb_disable_int(struct zd_usb *usb);
|
||||||
int zd_usb_enable_rx(struct zd_usb *usb);
|
int zd_usb_enable_rx(struct zd_usb *usb);
|
||||||
void zd_usb_disable_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_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,
|
int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
|
||||||
const zd_addr_t *addresses, unsigned int count);
|
const zd_addr_t *addresses, unsigned int count);
|
||||||
|
|
Loading…
Reference in a new issue