Date: Wed, 2 Jan 2008 18:03:18 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 132316 for review Message-ID: <200801021803.m02I3Ih1075720@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=132316 Change 132316 by hselasky@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@free.fr> * Copyright (c) 2006 by Florian Stoehr <ich@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) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200801021803.m02I3Ih1075720>