PERFORCE change 132316 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Wed Jan 2 10:03:19 PST 2008
http://perforce.freebsd.org/chv.cgi?CH=132316
Change 132316 by hselasky at hselasky_laptop001 on 2008/01/02 18:02:18
Merge if_zyd.c from FreeBSD P4 head. The driver has been
tested and confirmed to work. Additional bugfixes:
o receive frame length was not correctly adjusted
o added length check for incoming USB frames
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/if_zyd.c#30 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/if_zyd.c#30 (text+ko) ====
@@ -1,11 +1,9 @@
-#if 0
+/* $OpenBSD: if_zyd.c,v 1.52 2007/02/11 00:08:04 jsg Exp $ */
+/* $NetBSD: if_zyd.c,v 1.7 2007/06/21 04:04:29 kiyohara Exp $ */
+/* $FreeBSD: src/sys/dev/usb/if_zyd.c,v 1.11 2007/12/01 08:53:03 kevlo Exp $ */
-XXX this driver needs to be updated !
- XXX-- hps
-
-/* $OpenBSD: if_zyd.c,v 1.27 2006/09/23 22:28:43 mglocker Exp $ */
-
-/*
+/*-
+ * Copyright (c) 2006 by Damien Bergamini <damien.bergamini at free.fr>
* Copyright (c) 2006 by Florian Stoehr <ich at florian-stoehr.de>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -22,10 +20,10 @@
*/
#include <sys/cdefs.h>
- __FBSDID("$FreeBSD: src/sys/dev/usb/if_zyd.c $");
+__FBSDID("$FreeBSD: src/sys/dev/usb/if_zyd.c $");
/*
- * ZyDAS ZD1211 USB WLAN driver
+ * ZyDAS ZD1211/ZD1211B USB WLAN driver
*
* NOTE: all function names beginning like "zyd_cfg_" can only
* be called from within the config thread function !
@@ -49,13 +47,11 @@
#include <net/if_types.h>
#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_radiotap.h>
-
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/in_var.h>
-#include <netinet/ip.h>
-#include <netinet/if_ether.h>
+#include <net80211/ieee80211_proto.h>
+#include <net80211/ieee80211_node.h>
+#include <net80211/ieee80211_regdomain.h>
#define usbd_config_td_cc zyd_config_copy
#define usbd_config_td_softc zyd_softc
@@ -84,6 +80,9 @@
#define DPRINTF(...)
#endif
+#undef INDEXES
+#define INDEXES(a) (sizeof(a) / sizeof((a)[0]))
+
struct mq { /* mini-queue */
struct mbuf *ifq_head;
struct mbuf *ifq_tail;
@@ -112,133 +111,132 @@
static usbd_config_td_command_t zyd_cfg_pre_stop;
static usbd_config_td_command_t zyd_cfg_stop;
static usbd_config_td_command_t zyd_config_copy;
+static usbd_config_td_command_t zyd_cfg_scan_start;
+static usbd_config_td_command_t zyd_cfg_scan_end;
+static usbd_config_td_command_t zyd_cfg_set_rxfilter;
+static usbd_config_td_command_t zyd_cfg_amrr_timeout;
-static uint16_t zyd_getrealaddr(struct zyd_softc *sc, uint32_t mangled_addr);
-static void zyd_cfg_usbrequest(struct zyd_softc *sc, uint8_t type, uint8_t request, uint16_t value, uint16_t index, uint16_t length, uint8_t *data);
-static void zyd_cfg_usbrequestzc(struct zyd_softc *sc, struct zyd_control *zc);
-static void zyd_cfg_reset(struct zyd_softc *sc);
+static uint8_t zyd_plcp2ieee(uint8_t signal, uint8_t isofdm);
+static struct ieee80211_node * zyd_node_alloc_cb(struct ieee80211_node_table *nt);
+static void zyd_cfg_usbrequest(struct zyd_softc *sc, usb_device_request_t *req, uint8_t *data);
static void zyd_cfg_usb_intr_read(struct zyd_softc *sc, void *data, uint32_t size);
-static void zyd_cfg_usb_intr_write(struct zyd_softc *sc, void *data, uint32_t size);
-static uint32_t zyd_addrinc(uint32_t addr);
-static void zyd_cfg_read16(struct zyd_softc *sc, uint32_t addr, uint16_t *value);
-static void zyd_cfg_read32(struct zyd_softc *sc, uint32_t addr, uint32_t *value);
-static void zyd_cfg_read16_multi(struct zyd_softc *sc, const uint32_t *addrs, uint16_t *data, uint8_t usecount);
-static void zyd_cfg_read32_multi(struct zyd_softc *sc, const uint32_t *addrs, uint32_t *data, uint8_t usecount);
-static void zyd_cfg_write16(struct zyd_softc *sc, uint32_t addr, uint16_t value);
-static void zyd_cfg_write32(struct zyd_softc *sc, uint32_t addr, uint32_t value);
-static void zyd_cfg_write16_multi(struct zyd_softc *sc, const uint32_t *addrs, uint16_t *data, uint8_t usecount);
-static void zyd_cfg_write32_multi(struct zyd_softc *sc, const uint32_t *addrs, uint32_t *data, uint8_t usecount);
-static void zyd_cfg_write16_batch(struct zyd_softc *sc, const struct zyd_adpairs16 *data, uint32_t count);
-static void zyd_cfg_write32_batch(struct zyd_softc *sc, const struct zyd_adpairs32 *data, uint32_t count);
-static void zyd_cfg_rfwrite(struct zyd_softc *sc, uint32_t value, uint8_t bits);
-static void zyd_cfg_stateoutput(struct zyd_softc *sc);
-static void zyd_rxframeproc(struct usbd_xfer *xfer, struct mq *mq, uint16_t offset, uint16_t len);
-static uint8_t zyd_cfg_uploadfirmware(struct zyd_softc *sc);
+static void zyd_cfg_usb_intr_write(struct zyd_softc *sc, const void *data, uint16_t code, uint32_t size);
+static void zyd_cfg_read16(struct zyd_softc *sc, uint16_t addr, uint16_t *value);
+static void zyd_cfg_read32(struct zyd_softc *sc, uint16_t addr, uint32_t *value);
+static void zyd_cfg_write16(struct zyd_softc *sc, uint16_t addr, uint16_t value);
+static void zyd_cfg_write32(struct zyd_softc *sc, uint16_t addr, uint32_t value);
+static void zyd_cfg_rfwrite(struct zyd_softc *sc, uint32_t value);
+static uint8_t zyd_cfg_uploadfirmware(struct zyd_softc *sc, const uint8_t *fw_ptr, uint32_t fw_len);
static void zyd_cfg_lock_phy(struct zyd_softc *sc);
static void zyd_cfg_unlock_phy(struct zyd_softc *sc);
-static void zyd_cfg_get_aw_pt_bi(struct zyd_softc *sc, struct zyd_aw_pt_bi *s);
-static void zyd_cfg_set_aw_pt_bi(struct zyd_softc *sc, struct zyd_aw_pt_bi *s);
static void zyd_cfg_set_beacon_interval(struct zyd_softc *sc, uint32_t interval);
static const char *zyd_rf_name(uint8_t type);
-static void zyd_cfg_read_rf_pa_types(struct zyd_softc *sc, uint8_t *rf_type, uint8_t *pa_type);
static void zyd_cfg_rf_rfmd_init(struct zyd_softc *sc, struct zyd_rf *rf);
-static void zyd_cfg_rf_rfmd_switchradio(struct zyd_softc *sc, uint8_t onoff);
+static void zyd_cfg_rf_rfmd_switch_radio(struct zyd_softc *sc, uint8_t onoff);
static void zyd_cfg_rf_rfmd_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, uint8_t channel);
-static void zyd_cfg_rf_al2230_switchradio(struct zyd_softc *sc, uint8_t onoff);
+static void zyd_cfg_rf_al2230_switch_radio(struct zyd_softc *sc, uint8_t onoff);
static void zyd_cfg_rf_al2230_init(struct zyd_softc *sc, struct zyd_rf *rf);
+static void zyd_cfg_rf_al2230_init_b(struct zyd_softc *sc, struct zyd_rf *rf);
static void zyd_cfg_rf_al2230_set_channel(struct zyd_softc *sc, struct zyd_rf *rf, uint8_t channel);
-static uint8_t zyd_cfg_rf_init_hw(struct zyd_softc *sc, struct zyd_rf *rf, uint8_t type);
+static uint8_t zyd_cfg_rf_init_hw(struct zyd_softc *sc, struct zyd_rf *rf);
static uint8_t zyd_cfg_hw_init(struct zyd_softc *sc, struct ieee80211com *ic);
-static void zyd_cfg_get_e2p_mac_addr(struct zyd_softc *sc, struct zyd_macaddr *mac_addr);
static void zyd_cfg_set_mac_addr(struct zyd_softc *sc, const uint8_t *addr);
-static void zyd_cfg_read_regdomain(struct zyd_softc *sc, uint8_t *regdomain);
-static uint8_t zyd_regdomain_supported(uint8_t regdomain);
-static void zyd_cfg_tblreader(struct zyd_softc *sc, uint8_t *values, size_t count, uint32_t e2p_addr, uint32_t guard);
-static void zyd_cfg_readcaltables(struct zyd_softc *sc);
-static uint8_t zyd_reset_channel(struct zyd_softc *sc);
-static void zyd_cfg_set_encryption_type(struct zyd_softc *sc, uint32_t type);
static void zyd_cfg_switch_radio(struct zyd_softc *sc, uint8_t onoff);
-static void zyd_cfg_enable_hwint(struct zyd_softc *sc);
-static void zyd_cfg_disable_hwint(struct zyd_softc *sc);
-static void zyd_cfg_set_basic_rates(struct zyd_softc *sc, int mode);
-static void zyd_cfg_set_mandatory_rates(struct zyd_softc *sc, int mode);
-static void zyd_cfg_reset_mode(struct zyd_softc *sc);
static void zyd_cfg_set_bssid(struct zyd_softc *sc, uint8_t *addr);
static int zyd_media_change_cb(struct ifnet *ifp);
static int zyd_newstate_cb(struct ieee80211com *ic, enum ieee80211_state nstate, int arg);
-static uint16_t zyd_txtime(uint16_t len, uint8_t rate, uint32_t flags);
static uint8_t zyd_plcp_signal(uint8_t rate);
-static uint16_t zyd_calc_useclen(uint8_t rate, uint16_t len, uint8_t *service);
-static void zyd_setup_tx_desc(struct usbd_xfer *xfer, struct mbuf *m, uint16_t rate);
-static void zyd_cfg_dump_fw_registers(struct zyd_softc *sc);
-static uint8_t zyd_tx_frame(struct usbd_xfer *xfer, struct mbuf *m0, struct ieee80211_node *ni, uint8_t rate);
static void zyd_start_transfers(struct zyd_softc *sc);
static void zyd_start_cb(struct ifnet *ifp);
static void zyd_init_cb(void *arg);
-static int zyd_reset_cb(struct ifnet *ifp);
static int zyd_ioctl_cb(struct ifnet *ifp, u_long command, caddr_t data);
static void zyd_watchdog(void *arg);
-static void zyd_next_scan(void *arg);
static void zyd_end_of_commands(struct zyd_softc *sc);
+static void zyd_newassoc_cb(struct ieee80211_node *ni, int isnew);
+static void zyd_scan_start_cb(struct ieee80211com *ic);
+static void zyd_scan_end_cb(struct ieee80211com *ic);
+static void zyd_set_channel_cb(struct ieee80211com *ic);
+static void zyd_cfg_set_led(struct zyd_softc *sc, uint32_t which, uint8_t on);
-static const struct usb_devno zyd_devs[] = {
- {USB_VENDOR_3COM2, USB_PRODUCT_3COM2_3CRUSB10075},
- {USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_WL54},
- {USB_VENDOR_ASUS, USB_PRODUCT_ASUS_WL159G},
- {USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D7050C},
- {USB_VENDOR_CYBERTAN, USB_PRODUCT_CYBERTAN_TG54USB},
- {USB_VENDOR_DRAYTEK, USB_PRODUCT_DRAYTEK_VIGOR550},
- {USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS54GZL},
- {USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GWUS54MINI},
- {USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_XG760A},
- {USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL113},
- {USB_VENDOR_SWEEX, USB_PRODUCT_SWEEX_ZD1211},
- {USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_QUICKWLAN},
- {USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_ZD1211},
- {USB_VENDOR_TWINMOS, USB_PRODUCT_TWINMOS_G240},
- {USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_TEW429UB_A},
- {USB_VENDOR_UMEDIA, USB_PRODUCT_UMEDIA_TEW429UB},
- {USB_VENDOR_WISTRONNEWEB, USB_PRODUCT_WISTRONNEWEB_UR055G},
- {USB_VENDOR_ZYDAS, USB_PRODUCT_ZYDAS_ZD1211},
- {USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_ZYAIRG220}
-};
+static const struct zyd_phy_pair zyd_def_phy[] = ZYD_DEF_PHY;
+static const struct zyd_phy_pair zyd_def_phyB[] = ZYD_DEF_PHYB;
-/* Device, regardless of RF */
-static const struct zyd_adpairs16 zyd_def_cr[] = {
- ZYD_DEF_CR
-};
+/* various supported device vendors/products */
+#define ZYD_ZD1211_DEV(v, p) \
+ { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, ZYD_ZD1211 }
+#define ZYD_ZD1211B_DEV(v, p) \
+ { { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, ZYD_ZD1211B }
+static const struct zyd_type {
+ struct usb_devno dev;
+ uint8_t rev;
+#define ZYD_ZD1211 0
+#define ZYD_ZD1211B 1
+} zyd_devs[] = {
+ ZYD_ZD1211_DEV(3COM2, 3CRUSB10075),
+ ZYD_ZD1211_DEV(ABOCOM, WL54),
+ ZYD_ZD1211_DEV(ASUS, WL159G),
+ ZYD_ZD1211_DEV(CYBERTAN, TG54USB),
+ ZYD_ZD1211_DEV(DRAYTEK, VIGOR550),
+ ZYD_ZD1211_DEV(PLANEX2, GWUS54GD),
+ ZYD_ZD1211_DEV(PLANEX2, GWUS54GZL),
+ ZYD_ZD1211_DEV(PLANEX3, GWUS54GZ),
+ ZYD_ZD1211_DEV(PLANEX3, GWUS54MINI),
+ ZYD_ZD1211_DEV(SAGEM, XG760A),
+ ZYD_ZD1211_DEV(SENAO, NUB8301),
+ ZYD_ZD1211_DEV(SITECOMEU, WL113),
+ ZYD_ZD1211_DEV(SWEEX, ZD1211),
+ ZYD_ZD1211_DEV(TEKRAM, QUICKWLAN),
+ ZYD_ZD1211_DEV(TEKRAM, ZD1211_1),
+ ZYD_ZD1211_DEV(TEKRAM, ZD1211_2),
+ ZYD_ZD1211_DEV(TWINMOS, G240),
+ ZYD_ZD1211_DEV(UMEDIA, ALL0298V2),
+ ZYD_ZD1211_DEV(UMEDIA, TEW429UB_A),
+ ZYD_ZD1211_DEV(UMEDIA, TEW429UB),
+ ZYD_ZD1211_DEV(WISTRONNEWEB, UR055G),
+ ZYD_ZD1211_DEV(ZCOM, ZD1211),
+ ZYD_ZD1211_DEV(ZYDAS, ZD1211),
+ ZYD_ZD1211_DEV(ZYXEL, AG225H),
+ ZYD_ZD1211_DEV(ZYXEL, ZYAIRG220),
+ ZYD_ZD1211_DEV(ZYXEL, G200V2),
-static const struct zyd_adpairs32 zyd_def_mac[] = {
- ZYD_DEF_MAC
+ ZYD_ZD1211B_DEV(ACCTON, SMCWUSBG),
+ ZYD_ZD1211B_DEV(ACCTON, ZD1211B),
+ ZYD_ZD1211B_DEV(ASUS, A9T_WIFI),
+ ZYD_ZD1211B_DEV(BELKIN, F5D7050_V4000),
+ ZYD_ZD1211B_DEV(BELKIN, ZD1211B),
+ ZYD_ZD1211B_DEV(CISCOLINKSYS, WUSBF54G),
+ ZYD_ZD1211B_DEV(FIBERLINE, WL430U),
+ ZYD_ZD1211B_DEV(MELCO, KG54L),
+ ZYD_ZD1211B_DEV(PHILIPS, SNU5600),
+ ZYD_ZD1211B_DEV(PLANEX2, GW_US54GXS),
+ ZYD_ZD1211B_DEV(SAGEM, XG76NA),
+ ZYD_ZD1211B_DEV(SITECOMEU, ZD1211B),
+ ZYD_ZD1211B_DEV(UMEDIA, TEW429UBC1),
+#if 0 /* Shall we needs? */
+ ZYD_ZD1211B_DEV(UNKNOWN1, ZD1211B_1),
+ ZYD_ZD1211B_DEV(UNKNOWN1, ZD1211B_2),
+ ZYD_ZD1211B_DEV(UNKNOWN2, ZD1211B),
+ ZYD_ZD1211B_DEV(UNKNOWN3, ZD1211B),
+#endif
+ ZYD_ZD1211B_DEV(USR, USR5423),
+ ZYD_ZD1211B_DEV(VTECH, ZD1211B),
+ ZYD_ZD1211B_DEV(ZCOM, ZD1211B),
+ ZYD_ZD1211B_DEV(ZYDAS, ZD1211B),
+ ZYD_ZD1211B_DEV(ZYXEL, M202),
+ ZYD_ZD1211B_DEV(ZYXEL, G220V2),
};
+#define zyd_lookup(v, p) \
+ ((const struct zyd_type *)usb_lookup(zyd_devs, v, p))
-/* RF2959 */
-static const struct zyd_adpairs16 zyd_rfmd_cr[] = {
- ZYD_RFMD_CR
-};
-
-static const uint32_t zyd_rfmd_rf[] = {
- ZYD_RFMD_RF
-};
-
-/* AL2230 */
-static const struct zyd_adpairs16 zyd_al2230_cr[] = {
- ZYD_AL2230_CR
-};
-
-static const uint32_t zyd_al2230_rf[] = {
- ZYD_AL2230_RF
-};
-
-static const struct usbd_config zyd_config[ZYD_TR_MAX] = {
+static const struct usbd_config zyd_config[ZYD_N_TRANSFER] = {
[ZYD_TR_BULK_DT_WR] = {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
- .bufsize = (MCLBYTES + sizeof(struct zyd_controlsetformat) + 1),
+ .bufsize = ZYD_MAX_TXBUFSZ,
.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
.mh.callback = &zyd_bulk_write_callback,
- .index = 0,
+ .ep_index = 0,
.mh.timeout = 10000, /* 10 seconds */
},
@@ -246,10 +244,10 @@
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_IN,
- .bufsize = (MAX(MCLBYTES, 2312) + sizeof(struct zyd_rxleninfoapp)),
+ .bufsize = ZYX_MAX_RXBUFSZ,
.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
.mh.callback = &zyd_bulk_read_callback,
- .index = 0,
+ .ep_index = 0,
},
[ZYD_TR_BULK_CS_WR] = {
@@ -278,22 +276,21 @@
.type = UE_BULK_INTR,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
- .bufsize = ZYD_INTR_BUF_SIZE,
+ .bufsize = sizeof(struct zyd_cmd),
.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
.mh.callback = &zyd_intr_write_callback,
.mh.timeout = 1000, /* 1 second */
- .index = 1,
+ .ep_index = 1,
},
[ZYD_TR_INTR_DT_RD] = {
.type = UE_BULK_INTR,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_IN,
- .bufsize = ZYD_INTR_BUF_SIZE,
+ .bufsize = sizeof(struct zyd_cmd),
.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
.mh.callback = &zyd_intr_read_callback,
- .mh.timeout = 1000, /* 1 second */
- .index = 1,
+ .ep_index = 1,
},
[ZYD_TR_INTR_CS_WR] = {
@@ -337,111 +334,61 @@
DRIVER_MODULE(zyd, uhub, zyd_driver, zyd_devclass, usbd_driver_load, 0);
MODULE_DEPEND(zyd, usb, 1, 1, 1);
MODULE_DEPEND(zyd, wlan, 1, 1, 1);
+MODULE_DEPEND(zyd, wlan_amrr, 1, 1, 1);
-/*
- * Get the real address from a range-mangled address
- */
-static uint16_t
-zyd_getrealaddr(struct zyd_softc *sc, uint32_t mangled_addr)
+static uint8_t
+zyd_plcp2ieee(uint8_t signal, uint8_t isofdm)
{
- uint16_t add;
- uint16_t res;
+ if (isofdm) {
+ static const uint8_t ofdmrates[16] =
+ { 0, 0, 0, 0, 0, 0, 0, 96, 48, 24, 12, 108, 72, 36, 18 };
+ return ofdmrates[signal & 0xf];
+ } else {
+ static const uint8_t cckrates[16] =
+ { 0, 0, 0, 0, 4, 0, 0, 11, 0, 0, 2, 0, 0, 0, 22, 0 };
+ return cckrates[signal & 0xf];
+ }
+}
- add = 0;
-
- switch (ZYD_GET_RANGE(mangled_addr)) {
- case ZYD_RANGE_USB:
- break;
-
- case ZYD_RANGE_CTL:
- add = ZYD_CTRL_START_ADDR;
- break;
-
- case ZYD_RANGE_E2P:
- add = ZYD_E2P_START_ADDR;
- break;
-
- case ZYD_RANGE_FW:
- add = sc->sc_firmware_base;
- break;
- }
-
- res = (add + ZYD_GET_OFFS(mangled_addr));
-
- return (res);
+/* ARGUSED */
+static struct ieee80211_node *
+zyd_node_alloc_cb(struct ieee80211_node_table *nt __unused)
+{
+ struct zyd_node *zn;
+ zn = malloc(sizeof(struct zyd_node), M_80211_NODE, M_WAITOK | M_ZERO);
+ return ((zn != NULL) ? (&zn->ni) : NULL);
}
-
/*
* USB request basic wrapper
*/
static void
-zyd_cfg_usbrequest(struct zyd_softc *sc, uint8_t type, uint8_t request,
- uint16_t value, uint16_t index, uint16_t length, uint8_t *data)
+zyd_cfg_usbrequest(struct zyd_softc *sc, usb_device_request_t *req, uint8_t *data)
{
- usb_device_request_t req;
usbd_status_t err;
-
- req.bmRequestType = type;
- req.bRequest = request;
- USETW(req.wValue, value);
- USETW(req.wIndex, index);
- USETW(req.wLength, length);
+ uint16_t length;
- DPRINTF(sc, 20, "req=%02x val=%02x ind=%02x "
- "len=%02x\n", request,
- value, index, length);
-
if (usbd_config_td_is_gone(&(sc->sc_config_td))) {
goto error;
}
err = usbd_do_request_flags
- (sc->sc_udev, &(sc->sc_mtx), &req, data, 0, NULL, 10000);
+ (sc->sc_udev, &(sc->sc_mtx), req, data, 0, NULL, 1000);
if (err) {
- printf("%s: device request failed, err=%s "
- "(ignored)\n", sc->sc_name, usbd_errstr(err));
+ DPRINTF(sc, -1, "%s: device request failed, err=%s "
+ "(ignored)\n", sc->sc_name, usbd_errstr(err));
error:
- length = UGETW(req.wLength);
+ length = UGETW(req->wLength);
- if ((req.bmRequestType & UT_READ) && length) {
+ if ((req->bmRequestType & UT_READ) && length) {
bzero(data, length);
}
}
return;
}
-/*
- * Same, higher level
- */
-static void
-zyd_cfg_usbrequestzc(struct zyd_softc *sc, struct zyd_control *zc)
-{
- return (zyd_cfg_usbrequest(sc, zc->type, zc->id, zc->value,
- zc->index, zc->length, zc->data));
-}
-
-/*
- * Issue a SET_CONFIGURATION command, which will reset the device.
- */
-static void
-zyd_cfg_reset(struct zyd_softc *sc)
-{
- usbd_status_t err;
-
- err = usbreq_set_config(sc->sc_udev, &(sc->sc_mtx), ZYD_CONFIG_NO);
-
- if (err) {
- DPRINTF(sc, 0, "reset failed (ignored)\n");
- }
- /* Wait a little while for the chip to get its brains in order. */
- err = usbd_config_td_sleep(&(sc->sc_config_td), hz / 10);
-
- return;
-}
-
static void
zyd_intr_read_clear_stall_callback(struct usbd_xfer *xfer)
{
@@ -463,47 +410,148 @@
zyd_intr_read_callback(struct usbd_xfer *xfer)
{
struct zyd_softc *sc = xfer->priv_sc;
+ struct zyd_cmd *cmd = &(sc->sc_intr_ibuf);
+ uint32_t actlen;
+ uint32_t x;
switch (USBD_GET_STATE(xfer)) {
case USBD_ST_TRANSFERRED:
- DPRINTF(sc, 2, "length=%d\n", xfer->actlen);
+ actlen = xfer->actlen;
+
+ DPRINTF(sc, 2, "length=%d\n", actlen);
+
+ if (actlen > sizeof(sc->sc_intr_ibuf)) {
+ actlen = sizeof(sc->sc_intr_ibuf);
+ }
+ usbd_copy_out(xfer->frbuffers + 0, 0,
+ &(sc->sc_intr_ibuf), actlen);
- if (xfer->actlen > sizeof(sc->sc_intr_ibuf)) {
- xfer->actlen = sizeof(sc->sc_intr_ibuf);
+ switch(cmd->code) {
+ case htole16(ZYD_NOTIF_RETRYSTATUS):
+ goto handle_notif_retrystatus;
+ case htole16(ZYD_NOTIF_IORD):
+ goto handle_notif_iord;
+ default:
+ DPRINTF(sc, 1, "unknown indication: 0x%04x\n",
+ le16toh(cmd->code));
}
- usbd_copy_out(xfer->frbuffers + 0, 0, &(sc->sc_intr_ibuf),
- xfer->actlen);
- goto wakeup;
+
+ /* fallthrough */
case USBD_ST_SETUP:
-
+ tr_setup:
if (sc->sc_flags & ZYD_FLAG_INTR_READ_STALL) {
usbd_transfer_start(sc->sc_xfer[ZYD_TR_INTR_CS_RD]);
- goto wakeup;
- }
- if (sc->sc_intr_iwakeup) {
- xfer->frlengths[0] = xfer->max_data_length;
- usbd_start_hardware(xfer);
+ break;
}
- return;
-wakeup:
- sc->sc_intr_iwakeup = 0;
- wakeup(&(sc->sc_intr_iwakeup));
- return;
+ xfer->frlengths[0] = xfer->max_data_length;
+ usbd_start_hardware(xfer);
+ break;
default: /* Error */
- DPRINTF(sc, 2, "error=%d\n", xfer->error);
+ DPRINTF(sc, 2, "error = %s\n",
+ usbd_errstr(xfer->error));
if (xfer->error != USBD_CANCELLED) {
/* try to clear stall first */
sc->sc_flags |= ZYD_FLAG_INTR_READ_STALL;
usbd_transfer_start(sc->sc_xfer[ZYD_TR_INTR_CS_RD]);
+ } else {
+ /* tearing down */
+ if (sc->sc_intr_iwakeup) {
+ bzero(sc->sc_intr_ibuf.data, sc->sc_intr_ilen);
+ wakeup(&(sc->sc_intr_iwakeup));
+ }
}
- goto wakeup;
+ break;
+ }
+ return;
+
+handle_notif_retrystatus: {
+
+ struct zyd_notif_retry *retry = (void *)(cmd->data);
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211_node *ni;
+
+ DPRINTF(sc, 0, "retry intr: rate=0x%x "
+ "addr=%02x:%02x:%02x:%02x:%02x:%02x count=%d (0x%x)\n",
+ le16toh(retry->rate), retry->macaddr[0], retry->macaddr[1],
+ retry->macaddr[2], retry->macaddr[3], retry->macaddr[4],
+ retry->macaddr[5], le16toh(retry->count) & 0xff,
+ le16toh(retry->count));
+
+ /*
+ * Find the node to which the packet was sent and update its
+ * retry statistics. In BSS mode, this node is the AP we're
+ * associated to so no lookup is actually needed.
+ */
+ if (ic->ic_opmode != IEEE80211_M_STA) {
+ ni = ieee80211_find_node(&ic->ic_sta, retry->macaddr);
+ } else {
+ ni = ic->ic_bss;
+ }
+ if (ni == NULL) {
+ goto tr_setup;
+ }
+
+ ((struct zyd_node *)ni)->amn.amn_retrycnt++;
+ if (retry->count & htole16(0x100)) {
+ ifp->if_oerrors++; /* too many retries */
}
+ goto tr_setup;
+}
+
+handle_notif_iord:
+
+ if (*(uint16_t *)cmd->data == htole16(ZYD_CR_INTERRUPT)) {
+ goto tr_setup; /* HMAC interrupt */
+ }
+
+ if (actlen < 4) {
+ goto tr_setup; /* too short */
+ }
+
+ actlen -= 4;
+
+ if (actlen != sc->sc_intr_ilen) {
+ DPRINTF(sc, -1, "unexpected length %u != %u\n",
+ actlen, sc->sc_intr_ilen);
+ goto tr_setup; /* invalid length */
+ }
+
+ actlen /= 4;
+
+ /* verify register values */
+ for (x = 0; x != actlen; x++) {
+ if (sc->sc_intr_obuf.data[(2*x)] !=
+ sc->sc_intr_ibuf.data[(4*x)]) {
+ /* invalid register */
+ DPRINTF(sc, 0, "Invalid register (1)!\n");
+ goto tr_setup;
+ }
+ if (sc->sc_intr_obuf.data[(2*x) + 1] !=
+ sc->sc_intr_ibuf.data[(4*x) + 1]) {
+ /* invalid register */
+ DPRINTF(sc, 0, "Invalid register (2)!\n");
+ goto tr_setup;
+ }
+ }
+
+ if (sc->sc_intr_iwakeup) {
+ sc->sc_intr_iwakeup = 0;
+ wakeup(&(sc->sc_intr_iwakeup));
+ } else {
+ sc->sc_intr_iwakeup = 1;
+ }
+ /*
+ * We pause reading data from the interrupt endpoint until
+ * the data has been picked up!
+ */
+ return;
}
/*
@@ -512,28 +560,48 @@
static void
zyd_cfg_usb_intr_read(struct zyd_softc *sc, void *data, uint32_t size)
{
- int error;
-
- if (size > sizeof(sc->sc_intr_ibuf)) {
- DPRINTF(sc, 0, "truncating transfer size!\n");
- size = sizeof(sc->sc_intr_ibuf);
+ if (size > sizeof(sc->sc_intr_ibuf.data)) {
+ DPRINTF(sc, -1, "truncating transfer size!\n");
+ size = sizeof(sc->sc_intr_ibuf.data);
}
if (usbd_config_td_is_gone(&(sc->sc_config_td))) {
bzero(data, size);
goto done;
}
+
+ if (sc->sc_intr_iwakeup) {
+ DPRINTF(sc, 0, "got data already!\n");
+ sc->sc_intr_iwakeup = 0;
+ goto got_data;
+ }
+
+ /* else wait for data */
+
sc->sc_intr_iwakeup = 1;
+ sc->sc_intr_ilen = size;
- bzero(&(sc->sc_intr_ibuf), size);
-
usbd_transfer_start(sc->sc_xfer[ZYD_TR_INTR_DT_RD]);
- if (sc->sc_intr_iwakeup) {
- error = mtx_sleep(&(sc->sc_intr_iwakeup), &(sc->sc_mtx), 0,
- "zyd isleep", 0);
+ while (sc->sc_intr_iwakeup) {
+ if (mtx_sleep(&(sc->sc_intr_iwakeup), &(sc->sc_mtx), 0,
+ "zyd-ird", hz/2)) {
+ /* should not happen */
+ }
+ if (usbd_config_td_is_gone(&(sc->sc_config_td))) {
+ sc->sc_intr_iwakeup = 0;
+ bzero(data, size);
+ goto done;
+ }
}
- bcopy(&(sc->sc_intr_ibuf), data, size);
+
+got_data:
+ bcopy(sc->sc_intr_ibuf.data, data, size);
+ /*
+ * We have fetched the data from the shared buffer and it is
+ * safe to restart the interrupt transfer!
+ */
+ usbd_transfer_start(sc->sc_xfer[ZYD_TR_INTR_DT_RD]);
done:
return;
}
@@ -575,15 +643,11 @@
xfer->frlengths[0] = sc->sc_intr_olen;
usbd_start_hardware(xfer);
}
- return;
+ break;
-wakeup:
- sc->sc_intr_owakeup = 0;
- wakeup(&(sc->sc_intr_owakeup));
- return;
-
default: /* Error */
- DPRINTF(sc, 2, "error=%d\n", xfer->error);
+ DPRINTF(sc, 2, "error = %s\n",
+ usbd_errstr(xfer->error));
if (xfer->error != USBD_CANCELLED) {
/* try to clear stall first */
@@ -591,8 +655,15 @@
usbd_transfer_start(sc->sc_xfer[ZYD_TR_INTR_CS_WR]);
}
goto wakeup;
+ }
+ return;
+wakeup:
+ if (sc->sc_intr_owakeup) {
+ sc->sc_intr_owakeup = 0;
+ wakeup(&(sc->sc_intr_owakeup));
}
+ return;
}
/*
@@ -602,431 +673,222 @@
* full speed mode, EP4 is bulk out, not interrupt out.
*/
static void
-zyd_cfg_usb_intr_write(struct zyd_softc *sc, void *data, uint32_t size)
+zyd_cfg_usb_intr_write(struct zyd_softc *sc, const void *data,
+uint16_t code, uint32_t size)
{
- int error;
-
- if (size > sizeof(sc->sc_intr_obuf)) {
- DPRINTF(sc, 0, "truncating transfer size!\n");
- size = sizeof(sc->sc_intr_obuf);
+ if (size > sizeof(sc->sc_intr_obuf.data)) {
+ DPRINTF(sc, -1, "truncating transfer size!\n");
+ size = sizeof(sc->sc_intr_obuf.data);
}
if (usbd_config_td_is_gone(&(sc->sc_config_td))) {
goto done;
}
- sc->sc_intr_olen = size;
+ sc->sc_intr_olen = size + 2;
sc->sc_intr_owakeup = 1;
- bcopy(data, sc->sc_intr_obuf, size);
+ sc->sc_intr_obuf.code = htole16(code);
+ bcopy(data, sc->sc_intr_obuf.data, size);
usbd_transfer_start(sc->sc_xfer[ZYD_TR_INTR_DT_WR]);
- if (sc->sc_intr_owakeup) {
- error = mtx_sleep(&(sc->sc_intr_owakeup), &(sc->sc_mtx), 0,
- "zyd osleep", 0);
+ while (sc->sc_intr_owakeup) {
+ if (mtx_sleep(&(sc->sc_intr_owakeup), &(sc->sc_mtx), 0,
+ "zyd-iwr", hz/2)) {
+ }
+
+ if (usbd_config_td_is_gone(&(sc->sc_config_td))) {
+ sc->sc_intr_owakeup = 0;
+ goto done;
+ }
}
done:
return;
}
-/*
- * Offset correction (all ranges except CTL use word addressing)
- */
-static uint32_t
-zyd_addrinc(uint32_t addr)
-{
- uint32_t range = ZYD_GET_RANGE(addr);
- uint32_t offs = ZYD_GET_OFFS(addr);
-
- offs += (range == ZYD_RANGE_CTL) ? 2 : 1;
-
- return (range | offs);
-}
-
-/*
- * Read a single 16-bit register
- */
static void
-zyd_cfg_read16(struct zyd_softc *sc, uint32_t addr, uint16_t *value)
+zyd_cfg_cmd(struct zyd_softc *sc, uint16_t code, const void *idata, uint16_t ilen,
+ void *odata, uint16_t olen, uint16_t flags)
{
- zyd_cfg_read16_multi(sc, &addr, value, 1);
- return;
-}
+ zyd_cfg_usb_intr_write(sc, idata, code, ilen);
-/*
- * Read a single 32-bit register
- */
-static void
-zyd_cfg_read32(struct zyd_softc *sc, uint32_t addr, uint32_t *value)
-{
- zyd_cfg_read32_multi(sc, &addr, value, 1);
+ if (flags & ZYD_CMD_FLAG_READ) {
+ zyd_cfg_usb_intr_read(sc, odata, olen);
+ }
return;
}
-/*
- * Read up to 15 16-bit registers (newer firmware versions)
- */
static void
-zyd_cfg_read16_multi(struct zyd_softc *sc, const uint32_t *addrs, uint16_t *data,
- uint8_t usecount)
+zyd_cfg_read16(struct zyd_softc *sc, uint16_t addr, uint16_t *value)
{
- struct zyd_intoutmultiread in;
- struct zyd_intinmultioutput op;
- uint8_t i;
-
- memset(&in, 0, sizeof(struct zyd_intoutmultiread));
- memset(&op, 0, sizeof(struct zyd_intinmultioutput));
-
- USETW(in.id, ZYD_CMD_IORDREQ);
-
- for (i = 0; i < usecount; i++)
- USETW(in.addr[i], zyd_getrealaddr(sc, addrs[i]));
-
- zyd_cfg_usb_intr_write(sc, &in, (2 + (usecount * 2)));
- zyd_cfg_usb_intr_read(sc, &op, (2 + (usecount * 4)));
-
- for (i = 0; i < usecount; i++) {
- data[i] = UGETW(op.registers[i].data);
- }
+ struct zyd_pair tmp[1];
+ addr = htole16(addr);
+ zyd_cfg_cmd(sc, ZYD_CMD_IORD, &addr, sizeof(addr),
+ tmp, sizeof(tmp), ZYD_CMD_FLAG_READ);
+ *value = le16toh(tmp[0].val);
return;
}
-/*
- * Read up to 7 32-bit registers (newer firmware versions)
- */
static void
-zyd_cfg_read32_multi(struct zyd_softc *sc, const uint32_t *addrs, uint32_t *data,
- uint8_t usecount)
+zyd_cfg_read32(struct zyd_softc *sc, uint16_t addr, uint32_t *value)
{
- struct zyd_intoutmultiread in;
- struct zyd_intinmultioutput op;
- uint8_t i;
- uint8_t realcount;
+ struct zyd_pair tmp[2];
+ uint16_t regs[2];
- realcount = usecount * 2;
+ regs[0] = ZYD_REG32_HI(addr);
+ regs[1] = ZYD_REG32_LO(addr);
+ regs[0] = htole16(regs[0]);
+ regs[1] = htole16(regs[1]);
- memset(&in, 0, sizeof(struct zyd_intoutmultiread));
- memset(&op, 0, sizeof(struct zyd_intinmultioutput));
-
- USETW(in.id, ZYD_CMD_IORDREQ);
-
- for (i = 0; i < usecount; i++) {
- /* high word is first */
- USETW(in.addr[i * 2], zyd_getrealaddr(sc, zyd_addrinc(addrs[i])));
- USETW(in.addr[(i * 2) + 1], zyd_getrealaddr(sc, addrs[i]));
- }
-
- zyd_cfg_usb_intr_write(sc, &in, (2 + (realcount * 2)));
- zyd_cfg_usb_intr_read(sc, &op, (2 + (realcount * 4)));
-
- for (i = 0; i < usecount; i++) {
- data[i] =
- (UGETW(op.registers[i * 2].data) << 16) |
- UGETW(op.registers[(i * 2) + 1].data);
- }
+ zyd_cfg_cmd(sc, ZYD_CMD_IORD, regs, sizeof(regs),
+ tmp, sizeof(tmp), ZYD_CMD_FLAG_READ);
+ *value = (le16toh(tmp[0].val) << 16) | le16toh(tmp[1].val);
return;
}
-/*
- * Write a single 16-bit register
- */
static void
-zyd_cfg_write16(struct zyd_softc *sc, uint32_t addr, uint16_t value)
+zyd_cfg_write16(struct zyd_softc *sc, uint16_t reg, uint16_t val)
{
- zyd_cfg_write16_multi(sc, &addr, &value, 1);
- return;
-}
+ struct zyd_pair pair[1];
-/*
- * Write a single 32-bit register
- */
-static void
-zyd_cfg_write32(struct zyd_softc *sc, uint32_t addr, uint32_t value)
-{
- zyd_cfg_write32_multi(sc, &addr, &value, 1);
- return;
-}
+ pair[0].reg = htole16(reg);
+ pair[0].val = htole16(val);
-/*
- * Write up to 15 16-bit registers (newer firmware versions)
- */
-static void
-zyd_cfg_write16_multi(struct zyd_softc *sc, const uint32_t *addrs, uint16_t *data,
- uint8_t usecount)
-{
- struct zyd_intoutmultiwrite mw;
- uint8_t i;
-
- memset(&mw, 0, sizeof(struct zyd_intoutmultiwrite));
-
- USETW(mw.id, ZYD_CMD_IOWRREQ);
-
- for (i = 0; i < usecount; i++) {
- USETW(mw.registers[i].addr, zyd_getrealaddr(sc, addrs[i]));
- USETW(mw.registers[i].data, data[i]);
- }
-
- zyd_cfg_usb_intr_write(sc, &mw, (2 + (usecount * 4)));
+ zyd_cfg_cmd(sc, ZYD_CMD_IOWR, pair, sizeof(pair), NULL, 0, 0);
return;
}
-/*
- * Write up to 7 32-bit registers (newer firmware versions)
- */
static void
-zyd_cfg_write32_multi(struct zyd_softc *sc, const uint32_t *addrs, uint32_t *data,
- uint8_t usecount)
+zyd_cfg_write32(struct zyd_softc *sc, uint16_t reg, uint32_t val)
{
- struct zyd_intoutmultiwrite mw;
- uint8_t i;
- uint8_t realcount;
+ struct zyd_pair pair[2];
- realcount = usecount * 2;
+ pair[0].reg = htole16(ZYD_REG32_HI(reg));
+ pair[0].val = htole16(val >> 16);
+ pair[1].reg = htole16(ZYD_REG32_LO(reg));
+ pair[1].val = htole16(val & 0xffff);
- memset(&mw, 0, sizeof(struct zyd_intoutmultiwrite));
-
- USETW(mw.id, ZYD_CMD_IOWRREQ);
-
- for (i = 0; i < usecount; i++) {
- /* high word is first */
- USETW(mw.registers[i * 2].addr, zyd_getrealaddr(sc, zyd_addrinc(addrs[i])));
- USETW(mw.registers[i * 2].data, (*data >> 16));
-
- USETW(mw.registers[(i * 2) + 1].addr, zyd_getrealaddr(sc, addrs[i]));
- USETW(mw.registers[(i * 2) + 1].data, (*data));
- }
-
- zyd_cfg_usb_intr_write(sc, &mw, (2 + (realcount * 4)));
+ zyd_cfg_cmd(sc, ZYD_CMD_IOWR, pair, sizeof(pair), NULL, 0, 0);
return;
}
-/*
- * Batch write 16-bit data
- */
+/*------------------------------------------------------------------------*
+ * zyd_cfg_rfwrite - write RF registers
+ *------------------------------------------------------------------------*/
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list