usb/107642: [patch]Ralink Technology RT2501USB/RT2601USB chipset driver

Valery V.Chikalov valera at chikalov.dp.ua
Thu Feb 1 12:30:26 UTC 2007


The following reply was made to PR usb/107642; it has been noted by GNATS.

From: "Valery V.Chikalov" <valera at chikalov.dp.ua>
To: bug-followup at FreeBSD.org,  valera at chikalov.dp.ua
Cc:  
Subject: Re: usb/107642: [patch]Ralink Technology RT2501USB/RT2601USB chipset
 driver
Date: Thu, 01 Feb 2007 13:50:42 +0200

 This is a multi-part message in MIME format.
 --------------070401030006070808060902
 Content-Type: text/plain; charset=KOI8-R
 Content-Transfer-Encoding: 7bit
 
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 
 patch fixed, reworked to fit to CURRENT
 
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.5 (MingW32)
 Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
 
 iD8DBQFFwdP9760S3kDvEC4RAgXLAJ9sgZLzeFCjpw4Rcs2tWN3wNL0IYgCgvTum
 C77ikV7d5l0cIQIk7XUS0Zg=
 =S4Ye
 -----END PGP SIGNATURE-----
 
 --------------070401030006070808060902
 Content-Type: text/plain;
  name="rum.patch.txt"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline;
  filename="rum.patch.txt"
 
 ? sys/modules/rt2573/rum-rt2573
 Index: sys/dev/usb/if_rum.c
 ===================================================================
 RCS file: sys/dev/usb/if_rum.c
 diff -N sys/dev/usb/if_rum.c
 --- /dev/null	1 Jan 1970 00:00:00 -0000
 +++ sys/dev/usb/if_rum.c	1 Feb 2007 11:26:03 -0000
 @@ -0,0 +1,2315 @@
 +/*    $OpenBSD: if_rum.c,v 1.40 2006/09/18 16:20:20 damien Exp $    */
 +/*    $NetBSD: if_rum.c,v 1.2 2006/11/01 08:39:25 xtraeme Exp $    */
 +
 +/*-
 + * Copyright (c) 2005, 2006 Damien Bergamini <damien.bergamini at free.fr>
 + * Copyright (c) 2006 Niall O'Higgins <niallo at openbsd.org>
 + * Copyright (c) 2006, 2007 Valery V.Chikalov <valera at chikalov.dp.ua>
 + *
 + * Permission to use, copy, modify, and distribute this software for any
 + * purpose with or without fee is hereby granted, provided that the above
 + * copyright notice and this permission notice appear in all copies.
 + *
 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 + */
 +
 +/*-
 + * Ralink Technology RT2501USB/RT2601USB chipset driver
 + * http://www.ralinktech.com/
 + */
 +
 +#if defined(__NetBSD__)
 +#include "opt_ns.h"
 +#endif
 +#if defined(__NetBSD__)
 +#include "bpfilter.h"
 +#endif
 +#if defined(__FreeBSD__)
 +#define NBPFILTER   1
 +#endif
 +#if defined(__NetBSD__)
 +#include "rnd.h"
 +#endif
 +
 +#include <sys/param.h>
 +#include <sys/sysctl.h>
 +#include <sys/sockio.h>
 +#include <sys/mbuf.h>
 +#include <sys/kernel.h>
 +#include <sys/socket.h>
 +#include <sys/systm.h>
 +#include <sys/malloc.h>
 +#include <sys/module.h>
 +#include <sys/bus.h>
 +#include <sys/endian.h>
 +#include <sys/linker.h>
 +#include <sys/firmware.h>
 +
 +#include <machine/bus.h>
 +#include <machine/resource.h>
 +#include <machine/clock.h>
 +#include <sys/rman.h>
 +
 +#include <net/bpf.h>
 +#include <net/if.h>
 +#include <net/if_arp.h>
 +#include <net/ethernet.h>
 +#include <net/if_dl.h>
 +#include <net/if_media.h>
 +#include <net/if_types.h>
 +
 +#include <net80211/ieee80211_var.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 <dev/usb/usb.h>
 +#include <dev/usb/usbdi.h>
 +#include <dev/usb/usbdi_util.h>
 +#include "usbdevs.h"
 +
 +#include <dev/usb/if_rumreg.h>
 +#include <dev/usb/if_rumvar.h>
 +
 +#ifdef USB_DEBUG
 +#define RUM_DEBUG
 +#endif
 +
 +#ifdef RUM_DEBUG
 +#define DPRINTF(x)    do { if (rum_debug) logprintf x; } while (0)
 +#define DPRINTFN(n, x)    do { if (rum_debug >= (n)) logprintf x; } while (0)
 +int rum_debug = 0;
 +#else
 +#define DPRINTF(x)
 +#define DPRINTFN(n, x)
 +#endif
 +
 +/* various supported device vendors/products */
 +static const struct usb_devno rum_devs[] = {
 +    { USB_VENDOR_ABOCOM,        USB_PRODUCT_ABOCOM_RT2573 },
 +    { USB_VENDOR_ASUS,          USB_PRODUCT_ASUS_RT2573 },
 +    { USB_VENDOR_BELKIN,        USB_PRODUCT_BELKIN_F5D7050A },
 +    { USB_VENDOR_BELKIN,        USB_PRODUCT_BELKIN_F5D9050V3 },
 +    { USB_VENDOR_LINKSYS4,      USB_PRODUCT_LINKSYS4_WUSB54GC },
 +    { USB_VENDOR_CONCEPTRONIC2, USB_PRODUCT_CONCEPTRONIC2_C54RU2 },
 +    { USB_VENDOR_DICKSMITH,     USB_PRODUCT_DICKSMITH_CWD854F },
 +    { USB_VENDOR_DICKSMITH,     USB_PRODUCT_DICKSMITH_RT2573 },
 +    { USB_VENDOR_DLINK2,        USB_PRODUCT_DLINK2_DWLG122C1 },
 +    { USB_VENDOR_DLINK2,        USB_PRODUCT_DLINK2_WUA1340 },
 +    { USB_VENDOR_GIGABYTE,      USB_PRODUCT_GIGABYTE_GNWB01GS },
 +    { USB_VENDOR_GIGASET,       USB_PRODUCT_GIGASET_RT2573 },
 +    { USB_VENDOR_GOODWAY,       USB_PRODUCT_GOODWAY_RT2573 },
 +    { USB_VENDOR_HUAWEI3COM,    USB_PRODUCT_HUAWEI3COM_RT2573 },
 +    { USB_VENDOR_MSI,           USB_PRODUCT_MSI_RT2573 },
 +    { USB_VENDOR_MSI,           USB_PRODUCT_MSI_RT2573_2 },
 +    { USB_VENDOR_MSI,           USB_PRODUCT_MSI_RT2573_3 },
 +    { USB_VENDOR_PLANEX2,       USB_PRODUCT_PLANEX2_GWUSMM },
 +    { USB_VENDOR_QCOM,          USB_PRODUCT_QCOM_RT2573 },
 +    { USB_VENDOR_QCOM,          USB_PRODUCT_QCOM_RT2573_2 },
 +    { USB_VENDOR_RALINK,        USB_PRODUCT_RALINK_RT2573 },
 +    { USB_VENDOR_RALINK,        USB_PRODUCT_RALINK_RT2671 },
 +    { USB_VENDOR_SITECOMEU,     USB_PRODUCT_SITECOMEU_WL113R2 },
 +    { USB_VENDOR_SITECOMEU,     USB_PRODUCT_SITECOMEU_WL172 },
 +    { USB_VENDOR_SURECOM,       USB_PRODUCT_SURECOM_RT2573 }
 +};
 +
 +MODULE_DEPEND(rum, wlan,     1, 1, 1);
 +MODULE_DEPEND(rum, firmware, 1, 1, 1);
 +
 +static void        rum_attachhook(void *);
 +
 +static void        rum_start(struct ifnet *);
 +static void        rum_watchdog(struct ifnet *);
 +
 +static int         rum_ioctl(struct ifnet *, u_long, caddr_t);
 +
 +static int         rum_alloc_tx_list(struct rum_softc *);
 +static void        rum_free_tx_list(struct rum_softc *);
 +static int         rum_alloc_rx_list(struct rum_softc *);
 +static void        rum_free_rx_list(struct rum_softc *);
 +
 +static void        rum_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
 +static void        rum_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
 +
 +static int         rum_media_change(struct ifnet *);
 +static void        rum_task(void *);
 +static void        rum_next_scan(void *);
 +static int         rum_newstate(struct ieee80211com *, enum ieee80211_state, int);
 +static uint8_t     rum_rxrate(struct rum_rx_desc *);
 +static int         rum_ack_rate(struct ieee80211com *, int);
 +static uint16_t    rum_txtime(int, int, uint32_t);
 +static uint8_t     rum_plcp_signal(int);
 +static void        rum_setup_tx_desc(struct rum_softc *, struct rum_tx_desc *, uint32_t, uint16_t, int, int);
 +static int         rum_tx_mgt(struct rum_softc *, struct mbuf *, struct ieee80211_node *);
 +static int         rum_tx_data(struct rum_softc *, struct mbuf *, struct ieee80211_node *);
 +
 +static void        rum_read_eeprom(struct rum_softc *);
 +static void        rum_eeprom_read(struct rum_softc *, uint16_t, void *, int);
 +static uint32_t    rum_read(struct rum_softc *, uint16_t);
 +static void        rum_read_multi(struct rum_softc *, uint16_t, void *, int);
 +static void        rum_write(struct rum_softc *, uint16_t, uint32_t);
 +static void        rum_write_multi(struct rum_softc *, uint16_t, void *, size_t);
 +
 +static int         rum_bbp_init(struct rum_softc *);
 +static void        rum_bbp_write(struct rum_softc *, uint8_t, uint8_t);
 +static uint8_t     rum_bbp_read(struct rum_softc *, uint8_t);
 +
 +static const char  *rum_get_rf(int);
 +static void        rum_rf_write(struct rum_softc *, uint8_t, uint32_t);
 +static void        rum_select_antenna(struct rum_softc *);
 +static void        rum_enable_mrr(struct rum_softc *);
 +static void        rum_set_txpreamble(struct rum_softc *);
 +static void        rum_set_basicrates(struct rum_softc *);
 +static void        rum_select_band(struct rum_softc *, struct ieee80211_channel *);
 +static void        rum_set_chan(struct rum_softc *, struct ieee80211_channel *);
 +static void        rum_enable_tsf_sync(struct rum_softc *);
 +static void        rum_update_slot(struct rum_softc *);
 +static void        rum_set_bssid(struct rum_softc *, const uint8_t *);
 +static void        rum_set_macaddr(struct rum_softc *, const uint8_t *);
 +static void        rum_update_promisc(struct rum_softc *);
 +
 +static void        rum_init(void *);
 +static void        rum_stop(struct ifnet *);
 +static int         rum_load_microcode(struct rum_softc *, const u_char *, size_t);
 +static int         rum_prepare_beacon(struct rum_softc *);
 +
 +static void        rum_amrr_start(struct rum_softc *, struct ieee80211_node *);
 +static void        rum_amrr_timeout(void *);
 +static void        rum_amrr_update(usbd_xfer_handle, usbd_private_handle, usbd_status status);
 +static void        rum_ratectl(struct rum_amrr *, struct ieee80211_node *);
 +
 +/*
 + * Supported rates for 802.11a/b/g modes (in 500Kbps unit).
 + */
 +static const struct ieee80211_rateset rum_rateset_11a =
 +    { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } };
 +
 +static const struct ieee80211_rateset rum_rateset_11b =
 +    { 4, { 2, 4, 11, 22 } };
 +
 +static const struct ieee80211_rateset rum_rateset_11g =
 +    { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
 +
 +static const struct {
 +    uint32_t    reg;
 +    uint32_t    val;
 +} rum_def_mac[] = {
 +    RT2573_DEF_MAC
 +};
 +
 +static const struct {
 +    uint8_t    reg;
 +    uint8_t    val;
 +} rum_def_bbp[] = {
 +    RT2573_DEF_BBP
 +};
 +
 +static const struct rfprog {
 +    uint8_t        chan;
 +    uint32_t    r1, r2, r3, r4;
 +}  rum_rf5226[] = {
 +    RT2573_RF5226
 +}, rum_rf5225[] = {
 +    RT2573_RF5225
 +};
 +
 +USB_DECLARE_DRIVER(rum);
 +
 +USB_MATCH(rum)
 +{
 +    USB_MATCH_START(rum, uaa);
 +
 +    if (uaa->iface != NULL)
 +        return UMATCH_NONE;
 +
 +    return (usb_lookup(rum_devs, uaa->vendor, uaa->product) != NULL) ?
 +        UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
 +}
 +
 +static void
 +rum_attachhook(void *xsc)
 +{
 +    struct rum_softc *sc = xsc;
 +    const char *name = "rt2573";
 +    struct firmware *fp;
 +
 +    fp = firmware_get(name);
 +
 +    if (fp == NULL || fp->datasize == 0) {
 +        printf("%s: failed loadfirmware of file %s\n",
 +            device_get_nameunit(sc->sc_dev), name);
 +        return;
 +    } else {
 +        //MYDEBUG
 +        printf("%s: firmware loaded: name: %s, size:%d\n", device_get_nameunit(sc->sc_dev), fp->name, fp->datasize);
 +    }
 +
 +    if (rum_load_microcode(sc, fp->data, fp->datasize) != 0) {
 +        printf("%s: could not load 8051 microcode\n",
 +            device_get_nameunit(sc->sc_dev));
 +    }
 +
 +}
 +
 +USB_ATTACH(rum)
 +{
 +    USB_ATTACH_START(rum, sc, uaa);
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    struct ifnet *ifp = NULL;
 +    usb_interface_descriptor_t *id;
 +    usb_endpoint_descriptor_t *ed;
 +    usbd_status error;
 +    char devinfo[1024];
 +    int i, ntries;
 +    uint32_t tmp;
 +
 +    sc->sc_udev = uaa->device;
 +    sc->sc_flags = 0;
 +
 +    usbd_devinfo(sc->sc_udev, 0, devinfo);
 +    USB_ATTACH_SETUP;
 +    printf("%s: %s\n", device_get_nameunit(sc->sc_dev), devinfo);
 +
 +    if (usbd_set_config_no(sc->sc_udev, RT2573_CONFIG_NO, 0) != 0) {
 +        printf("%s: could not set configuration no\n",
 +            device_get_nameunit(sc->sc_dev));
 +        USB_ATTACH_ERROR_RETURN;
 +    }
 +
 +    /* get the first interface handle */
 +    error = usbd_device2interface_handle(sc->sc_udev, RT2573_IFACE_INDEX,
 +        &sc->sc_iface);
 +    if (error != 0) {
 +        printf("%s: could not get interface handle\n",
 +            device_get_nameunit(sc->sc_dev));
 +        USB_ATTACH_ERROR_RETURN;
 +    }
 +
 +    /*
 +     * Find endpoints.
 +     */
 +    id = usbd_get_interface_descriptor(sc->sc_iface);
 +
 +    sc->sc_rx_no = sc->sc_tx_no = -1;
 +    for (i = 0; i < id->bNumEndpoints; i++) {
 +        ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
 +        if (ed == NULL) {
 +            printf("%s: no endpoint descriptor for iface %d\n",
 +                device_get_nameunit(sc->sc_dev), i);
 +            USB_ATTACH_ERROR_RETURN;
 +        }
 +
 +        if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
 +            UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
 +            sc->sc_rx_no = ed->bEndpointAddress;
 +        else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
 +            UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
 +            sc->sc_tx_no = ed->bEndpointAddress;
 +    }
 +    if (sc->sc_rx_no == -1 || sc->sc_tx_no == -1) {
 +        printf("%s: missing endpoint\n", device_get_nameunit(sc->sc_dev));
 +        USB_ATTACH_ERROR_RETURN;
 +    }
 +
 +    usb_init_task(&sc->sc_task, rum_task, sc);
 +    callout_init(&sc->scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0);
 +    callout_init(&sc->amrr_ch, 0);
 +
 +    /* retrieve RT2573 rev. no */
 +    for (ntries = 0; ntries < 1000; ntries++) {
 +        if ((tmp = rum_read(sc, RT2573_MAC_CSR0)) != 0)
 +            break;
 +        DELAY(1000);
 +    }
 +    if (ntries == 1000) {
 +        printf("%s: timeout waiting for chip to settle\n",
 +            device_get_nameunit(sc->sc_dev));
 +        USB_ATTACH_ERROR_RETURN;
 +    }
 +
 +    /* retrieve MAC address and various other things from EEPROM */
 +    rum_read_eeprom(sc);
 +
 +    printf("%s: MAC/BBP RT%04x (rev 0x%05x), RF %s, address %s\n",
 +        device_get_nameunit(sc->sc_dev), sc->macbbp_rev, tmp,
 +        rum_get_rf(sc->rf_rev), ether_sprintf(ic->ic_myaddr));
 +
 +    ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
 +    if (ifp == NULL) {
 +        printf("%s: can not if_alloc()\n", device_get_nameunit(sc->sc_dev));
 +        USB_ATTACH_ERROR_RETURN;
 +    }
 +
 +#if 1
 +    rum_attachhook(sc);
 +#endif
 +
 +    ic->ic_ifp = ifp;
 +    ic->ic_phytype = IEEE80211_T_OFDM;    /* not only, but not used */
 +    ic->ic_opmode = IEEE80211_M_STA;    /* default to BSS mode */
 +    ic->ic_state = IEEE80211_S_INIT;
 +
 +    /* set device capabilities */
 +    ic->ic_caps =
 +        IEEE80211_C_IBSS |        /* IBSS mode supported */
 +        IEEE80211_C_MONITOR |    /* monitor mode supported */
 +        IEEE80211_C_HOSTAP |    /* HostAp mode supported */
 +        IEEE80211_C_TXPMGT |    /* tx power management */
 +        IEEE80211_C_SHPREAMBLE |    /* short preamble supported */
 +        IEEE80211_C_SHSLOT |    /* short slot time supported */
 +        IEEE80211_C_WPA;        /* 802.11i */
 +
 +    if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_5226) {
 +        /* set supported .11a rates */
 +        ic->ic_sup_rates[IEEE80211_MODE_11A] = rum_rateset_11a;
 +
 +        /* set supported .11a channels */
 +        for (i = 34; i <= 46; i += 4) {
 +            ic->ic_channels[i].ic_freq =
 +                ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
 +            ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
 +        }
 +        for (i = 36; i <= 64; i += 4) {
 +            ic->ic_channels[i].ic_freq =
 +                ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
 +            ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
 +        }
 +        for (i = 100; i <= 140; i += 4) {
 +            ic->ic_channels[i].ic_freq =
 +                ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
 +            ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
 +        }
 +        for (i = 149; i <= 165; i += 4) {
 +            ic->ic_channels[i].ic_freq =
 +                ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
 +            ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
 +        }
 +    }
 +
 +    /* set supported .11b and .11g rates */
 +    ic->ic_sup_rates[IEEE80211_MODE_11B] = rum_rateset_11b;
 +    ic->ic_sup_rates[IEEE80211_MODE_11G] = rum_rateset_11g;
 +
 +    /* set supported .11b and .11g channels (1 through 14) */
 +    for (i = 1; i <= 14; i++) {
 +        ic->ic_channels[i].ic_freq =
 +            ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
 +        ic->ic_channels[i].ic_flags =
 +            IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
 +            IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
 +    }
 +
 +    ifp->if_softc = sc;
 +    if_initname(ifp, "rum", device_get_unit(sc->sc_dev));
 +    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 +    ifp->if_init = rum_init;
 +    ifp->if_ioctl = rum_ioctl;
 +    ifp->if_start = rum_start;
 +    ifp->if_watchdog = rum_watchdog;
 +    IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
 +    IFQ_SET_READY(&ifp->if_snd);
 +
 +//    if_attach(ifp);
 +    ieee80211_ifattach(ic);
 +
 +    /* override state transition machine */
 +    sc->sc_newstate = ic->ic_newstate;
 +    ic->ic_newstate = rum_newstate;
 +    ieee80211_media_init(ic, rum_media_change, ieee80211_media_status);
 +
 +#if NBPFILTER > 0
 +    bpfattach2(ifp, DLT_IEEE802_11_RADIO,
 +        sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN, &sc->sc_drvbpf);
 +
 +    sc->sc_rxtap_len = sizeof sc->sc_rxtapu;
 +    sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
 +    sc->sc_rxtap.wr_ihdr.it_present = htole32(RT2573_RX_RADIOTAP_PRESENT);
 +
 +    sc->sc_txtap_len = sizeof sc->sc_txtapu;
 +    sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
 +    sc->sc_txtap.wt_ihdr.it_present = htole32(RT2573_TX_RADIOTAP_PRESENT);
 +#endif
 +
 +    ieee80211_announce(ic);
 +
 +    usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
 +        USBDEV(sc->sc_dev));
 +
 +    USB_ATTACH_SUCCESS_RETURN;
 +}
 +
 +USB_DETACH(rum)
 +{
 +    USB_DETACH_START(rum, sc);
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    struct ifnet *ifp = sc->sc_ifp;
 +    int s;
 +
 +    s = splusb();
 +
 +    rum_stop(ifp);
 +    usb_rem_task(sc->sc_udev, &sc->sc_task);
 +    callout_stop(&sc->scan_ch);
 +    callout_stop(&sc->amrr_ch);
 +
 +    if (sc->amrr_xfer != NULL) {
 +        usbd_free_xfer(sc->amrr_xfer);
 +        sc->amrr_xfer = NULL;
 +    }
 +
 +    if (sc->sc_rx_pipeh != NULL) {
 +        usbd_abort_pipe(sc->sc_rx_pipeh);
 +        usbd_close_pipe(sc->sc_rx_pipeh);
 +    }
 +
 +    if (sc->sc_tx_pipeh != NULL) {
 +        usbd_abort_pipe(sc->sc_tx_pipeh);
 +        usbd_close_pipe(sc->sc_tx_pipeh);
 +    }
 +
 +    rum_free_rx_list(sc);
 +    rum_free_tx_list(sc);
 +
 +#if NBPFILTER > 0
 +    bpfdetach(ifp);
 +#endif
 +    ieee80211_ifdetach(ic);    /* free all nodes */
 +    if_detach(ifp);
 +
 +    splx(s);
 +
 +    usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
 +        USBDEV(sc->sc_dev));
 +
 +    return 0;
 +}
 +
 +static int
 +rum_alloc_tx_list(struct rum_softc *sc)
 +{
 +    struct rum_tx_data *data;
 +    int i, error;
 +
 +    sc->tx_queued = 0;
 +
 +    for (i = 0; i < RT2573_TX_LIST_COUNT; i++) {
 +        data = &sc->tx_data[i];
 +
 +        data->sc = sc;
 +
 +        data->xfer = usbd_alloc_xfer(sc->sc_udev);
 +        if (data->xfer == NULL) {
 +            printf("%s: could not allocate tx xfer\n",
 +                device_get_nameunit(sc->sc_dev));
 +            error = ENOMEM;
 +            goto fail;
 +        }
 +
 +        data->buf = usbd_alloc_buffer(data->xfer,
 +            RT2573_TX_DESC_SIZE + MCLBYTES);
 +        if (data->buf == NULL) {
 +            printf("%s: could not allocate tx buffer\n",
 +                device_get_nameunit(sc->sc_dev));
 +            error = ENOMEM;
 +            goto fail;
 +        }
 +
 +        /* clean Tx descriptor */
 +        bzero(data->buf, RT2573_TX_DESC_SIZE);
 +    }
 +
 +    return 0;
 +
 +fail:    rum_free_tx_list(sc);
 +    return error;
 +}
 +
 +static void
 +rum_free_tx_list(struct rum_softc *sc)
 +{
 +    struct rum_tx_data *data;
 +    int i;
 +
 +    for (i = 0; i < RT2573_TX_LIST_COUNT; i++) {
 +        data = &sc->tx_data[i];
 +
 +        if (data->xfer != NULL) {
 +            usbd_free_xfer(data->xfer);
 +            data->xfer = NULL;
 +        }
 +
 +        if (data->ni != NULL) {
 +            ieee80211_free_node(data->ni);
 +            data->ni = NULL;
 +        }
 +    }
 +}
 +
 +static int
 +rum_alloc_rx_list(struct rum_softc *sc)
 +{
 +    struct rum_rx_data *data;
 +    int i, error;
 +
 +    for (i = 0; i < RT2573_RX_LIST_COUNT; i++) {
 +        data = &sc->rx_data[i];
 +
 +        data->sc = sc;
 +
 +        data->xfer = usbd_alloc_xfer(sc->sc_udev);
 +        if (data->xfer == NULL) {
 +            printf("%s: could not allocate rx xfer\n",
 +                device_get_nameunit(sc->sc_dev));
 +            error = ENOMEM;
 +            goto fail;
 +        }
 +
 +        if (usbd_alloc_buffer(data->xfer, MCLBYTES) == NULL) {
 +            printf("%s: could not allocate rx buffer\n",
 +                device_get_nameunit(sc->sc_dev));
 +            error = ENOMEM;
 +            goto fail;
 +        }
 +
 +        MGETHDR(data->m, M_DONTWAIT, MT_DATA);
 +        if (data->m == NULL) {
 +            printf("%s: could not allocate rx mbuf\n",
 +                device_get_nameunit(sc->sc_dev));
 +            error = ENOMEM;
 +            goto fail;
 +        }
 +
 +        MCLGET(data->m, M_DONTWAIT);
 +        if (!(data->m->m_flags & M_EXT)) {
 +            printf("%s: could not allocate rx mbuf cluster\n",
 +                device_get_nameunit(sc->sc_dev));
 +            error = ENOMEM;
 +            goto fail;
 +        }
 +
 +        data->buf = mtod(data->m, uint8_t *);
 +    }
 +
 +    return 0;
 +
 +fail:    rum_free_tx_list(sc);
 +    return error;
 +}
 +
 +static void
 +rum_free_rx_list(struct rum_softc *sc)
 +{
 +    struct rum_rx_data *data;
 +    int i;
 +
 +    for (i = 0; i < RT2573_RX_LIST_COUNT; i++) {
 +        data = &sc->rx_data[i];
 +
 +        if (data->xfer != NULL) {
 +            usbd_free_xfer(data->xfer);
 +            data->xfer = NULL;
 +        }
 +
 +        if (data->m != NULL) {
 +            m_freem(data->m);
 +            data->m = NULL;
 +        }
 +    }
 +}
 +
 +static int
 +rum_media_change(struct ifnet *ifp)
 +{
 +    struct rum_softc *sc = ifp->if_softc;
 +    int error;
 +
 +    error = ieee80211_media_change(ifp);
 +    if (error != ENETRESET)
 +        return error;
 +
 +	if ((ifp->if_flags & IFF_UP) &&
 +        (ifp->if_drv_flags & IFF_DRV_RUNNING))
 +        rum_init(sc);
 +
 +    return 0;
 +}
 +
 +/*
 + * This function is called periodically (every 200ms) during scanning to
 + * switch from one channel to another.
 + */
 +static void
 +rum_next_scan(void *arg)
 +{
 +    struct rum_softc *sc = arg;
 +    struct ieee80211com *ic = &sc->sc_ic;
 +
 +    if (ic->ic_state == IEEE80211_S_SCAN)
 +        ieee80211_next_scan(ic);
 +}
 +
 +static void
 +rum_task(void *arg)
 +{
 +    struct rum_softc *sc = arg;
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    enum ieee80211_state ostate;
 +    struct ieee80211_node *ni;
 +    uint32_t tmp;
 +
 +    ostate = ic->ic_state;
 +
 +    switch (sc->sc_state) {
 +    case IEEE80211_S_INIT:
 +        if (ostate == IEEE80211_S_RUN) {
 +            /* abort TSF synchronization */
 +            tmp = rum_read(sc, RT2573_TXRX_CSR9);
 +            rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff);
 +        }
 +        break;
 +
 +    case IEEE80211_S_SCAN:
 +        rum_set_chan(sc, ic->ic_curchan);
 +        callout_reset(&sc->scan_ch, hz / 5, rum_next_scan, sc);
 +        break;
 +
 +    case IEEE80211_S_AUTH:
 +        rum_set_chan(sc, ic->ic_curchan);
 +        break;
 +
 +    case IEEE80211_S_ASSOC:
 +        rum_set_chan(sc, ic->ic_curchan);
 +        break;
 +
 +    case IEEE80211_S_RUN:
 +        rum_set_chan(sc, ic->ic_curchan);
 +
 +        ni = ic->ic_bss;
 +
 +        if (ic->ic_opmode != IEEE80211_M_MONITOR) {
 +            rum_update_slot(sc);
 +            rum_enable_mrr(sc);
 +            rum_set_txpreamble(sc);
 +            rum_set_basicrates(sc);
 +            rum_set_bssid(sc, ni->ni_bssid);
 +        }
 +
 +        if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
 +            ic->ic_opmode == IEEE80211_M_IBSS)
 +            rum_prepare_beacon(sc);
 +
 +        if (ic->ic_opmode != IEEE80211_M_MONITOR)
 +            rum_enable_tsf_sync(sc);
 +
 +        /* enable automatic rate adaptation in STA mode */
 +        if (ic->ic_opmode == IEEE80211_M_STA &&
 +            ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
 +            rum_amrr_start(sc, ni);
 +
 +        break;
 +    }
 +
 +    sc->sc_newstate(ic, sc->sc_state, -1);
 +}
 +
 +static int
 +rum_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
 +{
 +    struct rum_softc *sc = ic->ic_ifp->if_softc;
 +
 +    usb_rem_task(sc->sc_udev, &sc->sc_task);
 +    callout_stop(&sc->scan_ch);
 +    callout_stop(&sc->amrr_ch);
 +
 +    /* do it in a process context */
 +    sc->sc_state = nstate;
 +    usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER);
 +
 +    return 0;
 +}
 +
 +/* quickly determine if a given rate is CCK or OFDM */
 +#define RUM_RATE_IS_OFDM(rate)    ((rate) >= 12 && (rate) != 22)
 +
 +#define RUM_ACK_SIZE    14    /* 10 + 4(FCS) */
 +#define RUM_CTS_SIZE    14    /* 10 + 4(FCS) */
 +
 +static void
 +rum_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
 +{
 +    struct rum_tx_data *data = priv;
 +    struct rum_softc *sc = data->sc;
 +    struct ifnet *ifp = sc->sc_ifp;
 +    int s;
 +
 +    if (status != USBD_NORMAL_COMPLETION) {
 +        if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
 +            return;
 +
 +        printf("%s: could not transmit buffer: %s\n",
 +            device_get_nameunit(sc->sc_dev), usbd_errstr(status));
 +
 +        if (status == USBD_STALLED)
 +            usbd_clear_endpoint_stall_async(sc->sc_tx_pipeh);
 +
 +        ifp->if_oerrors++;
 +        return;
 +    }
 +
 +    s = splnet();
 +
 +    m_freem(data->m);
 +    data->m = NULL;
 +    ieee80211_free_node(data->ni);
 +    data->ni = NULL;
 +
 +    sc->tx_queued--;
 +    ifp->if_opackets++;
 +
 +    DPRINTFN(10, ("tx done\n"));
 +
 +    sc->sc_tx_timer = 0;
 +    ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 +    rum_start(ifp);
 +
 +    splx(s);
 +}
 +
 +static void
 +rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
 +{
 +    struct rum_rx_data *data = priv;
 +    struct rum_softc *sc = data->sc;
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    struct ifnet *ifp = sc->sc_ifp;
 +    struct rum_rx_desc *desc;
 +    struct ieee80211_frame *wh;
 +    struct ieee80211_node *ni;
 +    struct mbuf *mnew, *m;
 +    int s, len;
 +
 +    if (status != USBD_NORMAL_COMPLETION) {
 +        if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
 +            return;
 +
 +        if (status == USBD_STALLED)
 +            usbd_clear_endpoint_stall_async(sc->sc_rx_pipeh);
 +        goto skip;
 +    }
 +
 +    usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
 +
 +    if (len < RT2573_RX_DESC_SIZE + sizeof (struct ieee80211_frame_min)) {
 +        DPRINTF(("%s: xfer too short %d\n", device_get_nameunit(sc->sc_dev),
 +            len));
 +        ifp->if_ierrors++;
 +        goto skip;
 +    }
 +
 +    desc = (struct rum_rx_desc *)data->buf;
 +
 +    if (le32toh(desc->flags) & RT2573_RX_CRC_ERROR) {
 +        /*
 +         * This should not happen since we did not request to receive
 +         * those frames when we filled RT2573_TXRX_CSR0.
 +         */
 +        DPRINTFN(5, ("CRC error\n"));
 +        ifp->if_ierrors++;
 +        goto skip;
 +    }
 +
 +    MGETHDR(mnew, M_DONTWAIT, MT_DATA);
 +    if (mnew == NULL) {
 +        printf("%s: could not allocate rx mbuf\n",
 +            device_get_nameunit(sc->sc_dev));
 +        ifp->if_ierrors++;
 +        goto skip;
 +    }
 +
 +    MCLGET(mnew, M_DONTWAIT);
 +    if (!(mnew->m_flags & M_EXT)) {
 +        printf("%s: could not allocate rx mbuf cluster\n",
 +            device_get_nameunit(sc->sc_dev));
 +        m_freem(mnew);
 +        ifp->if_ierrors++;
 +        goto skip;
 +    }
 +
 +    m = data->m;
 +    data->m = mnew;
 +    data->buf = mtod(data->m, uint8_t *);
 +
 +    /* finalize mbuf */
 +    m->m_pkthdr.rcvif = ifp;
 +    m->m_data = (caddr_t)(desc + 1);
 +    m->m_pkthdr.len = m->m_len = (le32toh(desc->flags) >> 16) & 0xfff;
 +
 +    s = splnet();
 +
 +    if (sc->sc_drvbpf != NULL) {
 +        struct rum_rx_radiotap_header *tap = &sc->sc_rxtap;
 +
 +        tap->wr_flags = IEEE80211_RADIOTAP_F_FCS;
 +        tap->wr_rate = rum_rxrate(desc);
 +        tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
 +        tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
 +        tap->wr_antenna = sc->rx_ant;
 +        tap->wr_antsignal = desc->rssi;
 +
 +        bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
 +    }
 +
 +    wh = mtod(m, struct ieee80211_frame *);
 +    ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
 +
 +    /* send the frame to the 802.11 layer */
 +    ieee80211_input(ic, m, ni, desc->rssi, 0);
 +
 +    /* node is no longer needed */
 +    ieee80211_free_node(ni);
 +
 +    splx(s);
 +
 +    DPRINTFN(15, ("rx done\n"));
 +
 +skip:    /* setup a new transfer */
 +    usbd_setup_xfer(xfer, sc->sc_rx_pipeh, data, data->buf, MCLBYTES,
 +        USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, rum_rxeof);
 +    usbd_transfer(xfer);
 +}
 +
 +/*
 + * This function is only used by the Rx radiotap code. It returns the rate at
 + * which a given frame was received.
 + */
 +static uint8_t
 +rum_rxrate(struct rum_rx_desc *desc)
 +{
 +    if (le32toh(desc->flags) & RT2573_RX_OFDM) {
 +        /* reverse function of rum_plcp_signal */
 +        switch (desc->rate) {
 +        case 0xb:    return 12;
 +        case 0xf:    return 18;
 +        case 0xa:    return 24;
 +        case 0xe:    return 36;
 +        case 0x9:    return 48;
 +        case 0xd:    return 72;
 +        case 0x8:    return 96;
 +        case 0xc:    return 108;
 +        }
 +    } else {
 +        if (desc->rate == 10)
 +            return 2;
 +        if (desc->rate == 20)
 +            return 4;
 +        if (desc->rate == 55)
 +            return 11;
 +        if (desc->rate == 110)
 +            return 22;
 +    }
 +    return 2;    /* should not get there */
 +}
 +
 +/*
 + * Return the expected ack rate for a frame transmitted at rate `rate'.
 + * XXX: this should depend on the destination node basic rate set.
 + */
 +static int
 +rum_ack_rate(struct ieee80211com *ic, int rate)
 +{
 +    switch (rate) {
 +    /* CCK rates */
 +    case 2:
 +        return 2;
 +    case 4:
 +    case 11:
 +    case 22:
 +        return (ic->ic_curmode == IEEE80211_MODE_11B) ? 4 : rate;
 +
 +    /* OFDM rates */
 +    case 12:
 +    case 18:
 +        return 12;
 +    case 24:
 +    case 36:
 +        return 24;
 +    case 48:
 +    case 72:
 +    case 96:
 +    case 108:
 +        return 48;
 +    }
 +
 +    /* default to 1Mbps */
 +    return 2;
 +}
 +
 +/*
 + * Compute the duration (in us) needed to transmit `len' bytes at rate `rate'.
 + * The function automatically determines the operating mode depending on the
 + * given rate. `flags' indicates whether short preamble is in use or not.
 + */
 +static uint16_t
 +rum_txtime(int len, int rate, uint32_t flags)
 +{
 +    uint16_t txtime;
 +
 +    if (RUM_RATE_IS_OFDM(rate)) {
 +        /* IEEE Std 802.11a-1999, pp. 37 */
 +        txtime = (8 + 4 * len + 3 + rate - 1) / rate;
 +        txtime = 16 + 4 + 4 * txtime + 6;
 +    } else {
 +        /* IEEE Std 802.11b-1999, pp. 28 */
 +        txtime = (16 * len + rate - 1) / rate;
 +        if (rate != 2 && (flags & IEEE80211_F_SHPREAMBLE))
 +            txtime +=  72 + 24;
 +        else
 +            txtime += 144 + 48;
 +    }
 +    return txtime;
 +}
 +
 +static uint8_t
 +rum_plcp_signal(int rate)
 +{
 +    switch (rate) {
 +    /* CCK rates (returned values are device-dependent) */
 +    case 2:        return 0x0;
 +    case 4:        return 0x1;
 +    case 11:    return 0x2;
 +    case 22:    return 0x3;
 +
 +    /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
 +    case 12:    return 0xb;
 +    case 18:    return 0xf;
 +    case 24:    return 0xa;
 +    case 36:    return 0xe;
 +    case 48:    return 0x9;
 +    case 72:    return 0xd;
 +    case 96:    return 0x8;
 +    case 108:    return 0xc;
 +
 +    /* unsupported rates (should not get there) */
 +    default:    return 0xff;
 +    }
 +}
 +
 +static void
 +rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc,
 +    uint32_t flags, uint16_t xflags, int len, int rate)
 +{
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    uint16_t plcp_length;
 +    int remainder;
 +
 +    desc->flags = htole32(flags);
 +    desc->flags |= htole32(RT2573_TX_VALID);
 +    desc->flags |= htole32(len << 16);
 +
 +    desc->xflags = htole16(xflags);
 +
 +    desc->wme = htole16(
 +        RT2573_QID(0) |
 +        RT2573_AIFSN(2) |
 +        RT2573_LOGCWMIN(4) |
 +        RT2573_LOGCWMAX(10));
 +
 +    /* setup PLCP fields */
 +    desc->plcp_signal  = rum_plcp_signal(rate);
 +    desc->plcp_service = 4;
 +
 +    len += IEEE80211_CRC_LEN;
 +    if (RUM_RATE_IS_OFDM(rate)) {
 +        desc->flags |= htole32(RT2573_TX_OFDM);
 +
 +        plcp_length = len & 0xfff;
 +        desc->plcp_length_hi = plcp_length >> 6;
 +        desc->plcp_length_lo = plcp_length & 0x3f;
 +    } else {
 +        plcp_length = (16 * len + rate - 1) / rate;
 +        if (rate == 22) {
 +            remainder = (16 * len) % 22;
 +            if (remainder != 0 && remainder < 7)
 +                desc->plcp_service |= RT2573_PLCP_LENGEXT;
 +        }
 +        desc->plcp_length_hi = plcp_length >> 8;
 +        desc->plcp_length_lo = plcp_length & 0xff;
 +
 +        if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
 +            desc->plcp_signal |= 0x08;
 +    }
 +}
 +
 +#define RUM_TX_TIMEOUT    5000
 +
 +static int
 +rum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
 +{
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    struct rum_tx_desc *desc;
 +    struct rum_tx_data *data;
 +    struct ieee80211_frame *wh;
 +    uint32_t flags = 0;
 +    uint16_t dur;
 +    usbd_status error;
 +    int xferlen, rate;
 +
 +    data = &sc->tx_data[0];
 +    desc = (struct rum_tx_desc *)data->buf;
 +
 +    rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2;
 +
 +    data->m = m0;
 +    data->ni = ni;
 +
 +    wh = mtod(m0, struct ieee80211_frame *);
 +
 +    if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
 +        flags |= RT2573_TX_ACK;
 +
 +        dur = rum_txtime(RUM_ACK_SIZE, rum_ack_rate(ic, rate),
 +            ic->ic_flags) + sc->sifs;
 +        *(uint16_t *)wh->i_dur = htole16(dur);
 +
 +        /* tell hardware to set timestamp in probe responses */
 +        if ((wh->i_fc[0] &
 +            (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
 +            (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
 +            flags |= RT2573_TX_TIMESTAMP;
 +    }
 +
 +#if NBPFILTER > 0
 +    if (sc->sc_drvbpf != NULL) {
 +        struct rum_tx_radiotap_header *tap = &sc->sc_txtap;
 +
 +        tap->wt_flags = 0;
 +        tap->wt_rate = rate;
 +        tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
 +        tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
 +        tap->wt_antenna = sc->tx_ant;
 +
 +        bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0);
 +    }
 +#endif
 +
 +    m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RT2573_TX_DESC_SIZE);
 +    rum_setup_tx_desc(sc, desc, flags, 0, m0->m_pkthdr.len, rate);
 +
 +    /* align end on a 4-bytes boundary */
 +    xferlen = (RT2573_TX_DESC_SIZE + m0->m_pkthdr.len + 3) & ~3;
 +
 +    /*
 +     * No space left in the last URB to store the extra 4 bytes, force
 +     * sending of another URB.
 +     */
 +    if ((xferlen % 64) == 0)
 +        xferlen += 4;
 +
 +    DPRINTFN(10, ("sending msg frame len=%u rate=%u xfer len=%u\n",
 +        m0->m_pkthdr.len + RT2573_TX_DESC_SIZE, rate, xferlen));
 +
 +    usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf, xferlen,
 +        USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RUM_TX_TIMEOUT, rum_txeof);
 +
 +    error = usbd_transfer(data->xfer);
 +    if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS) {
 +        m_freem(m0);
 +        return error;
 +    }
 +
 +    sc->tx_queued++;
 +
 +    return 0;
 +}
 +
 +static int
 +rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
 +{
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    struct rum_tx_desc *desc;
 +    struct rum_tx_data *data;
 +    struct ieee80211_frame *wh;
 +    struct ieee80211_key *k;
 +    uint32_t flags = 0;
 +    uint16_t dur;
 +    usbd_status error;
 +    int xferlen, rate;
 +
 +    wh = mtod(m0, struct ieee80211_frame *);
 +
 +    if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
 +        rate = ic->ic_bss->ni_rates.rs_rates[ic->ic_fixed_rate];
 +    else
 +        rate = ni->ni_rates.rs_rates[ni->ni_txrate];
 +    rate &= IEEE80211_RATE_VAL;
 +
 +    if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
 +        k = ieee80211_crypto_encap(ic, ni, m0);
 +        if (k == NULL) {
 +            m_freem(m0);
 +            return ENOBUFS;
 +        }
 +
 +        /* packet header may have moved, reset our local pointer */
 +        wh = mtod(m0, struct ieee80211_frame *);
 +    }
 +
 +    data = &sc->tx_data[0];
 +    desc = (struct rum_tx_desc *)data->buf;
 +
 +    data->m = m0;
 +    data->ni = ni;
 +
 +    if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
 +        flags |= RT2573_TX_ACK;
 +
 +        dur = rum_txtime(RUM_ACK_SIZE, rum_ack_rate(ic, rate),
 +            ic->ic_flags) + sc->sifs;
 +        *(uint16_t *)wh->i_dur = htole16(dur);
 +    }
 +
 +#if NBPFILTER > 0
 +    if (sc->sc_drvbpf != NULL) {
 +        struct rum_tx_radiotap_header *tap = &sc->sc_txtap;
 +
 +        tap->wt_flags = 0;
 +        tap->wt_rate = rate;
 +        tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
 +        tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
 +        tap->wt_antenna = sc->tx_ant;
 +
 +        bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0);
 +    }
 +#endif
 +
 +    m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RT2573_TX_DESC_SIZE);
 +    rum_setup_tx_desc(sc, desc, flags, 0, m0->m_pkthdr.len, rate);
 +
 +    /* align end on a 4-bytes boundary */
 +    xferlen = (RT2573_TX_DESC_SIZE + m0->m_pkthdr.len + 3) & ~3;
 +
 +    /*
 +     * No space left in the last URB to store the extra 4 bytes, force
 +     * sending of another URB.
 +     */
 +    if ((xferlen % 64) == 0)
 +        xferlen += 4;
 +
 +    DPRINTFN(10, ("sending data frame len=%u rate=%u xfer len=%u\n",
 +        m0->m_pkthdr.len + RT2573_TX_DESC_SIZE, rate, xferlen));
 +
 +    usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf, xferlen,
 +        USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RUM_TX_TIMEOUT, rum_txeof);
 +
 +    error = usbd_transfer(data->xfer);
 +    if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS) {
 +        m_freem(m0);
 +        return error;
 +    }
 +
 +    sc->tx_queued++;
 +
 +    return 0;
 +}
 +
 +static void
 +rum_start(struct ifnet *ifp)
 +{
 +    struct rum_softc *sc = ifp->if_softc;
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    struct mbuf *m0;
 +    struct ether_header *eh;
 +    struct ieee80211_node *ni;
 +
 +    for (;;) {
 +        IF_POLL(&ic->ic_mgtq, m0);
 +        if (m0 != NULL) {
 +            if (sc->tx_queued >= RT2573_TX_LIST_COUNT) {
 +                ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 +                break;
 +            }
 +            IF_DEQUEUE(&ic->ic_mgtq, m0);
 +
 +            ni = (struct ieee80211_node *)m0->m_pkthdr.rcvif;
 +            m0->m_pkthdr.rcvif = NULL;
 +
 +            if (ic->ic_rawbpf != NULL)
 +                bpf_mtap(ic->ic_rawbpf, m0);
 +
 +            if (rum_tx_mgt(sc, m0, ni) != 0)
 +                break;
 +
 +        } else {
 +            if (ic->ic_state != IEEE80211_S_RUN)
 +                break;
 +            IFQ_POLL(&ifp->if_snd, m0);
 +            if (m0 == NULL)
 +                break;
 +            if (sc->tx_queued >= RT2573_TX_LIST_COUNT) {
 +//FIXME
 +                ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 +                break;
 +            }
 +            IFQ_DEQUEUE(&ifp->if_snd, m0);
 +            if (m0->m_len < sizeof(struct ether_header) &&
 +                !(m0 = m_pullup(m0, sizeof(struct ether_header))))
 +                continue;
 +
 +            eh = mtod(m0, struct ether_header *);
 +            ni = ieee80211_find_txnode(ic, eh->ether_dhost);
 +            if (ni == NULL) {
 +                m_freem(m0);
 +                continue;
 +            }
 +            if (ifp->if_bpf != NULL)
 +                bpf_mtap(ifp->if_bpf, m0);
 +            m0 = ieee80211_encap(ic, m0, ni);
 +            if (m0 == NULL) {
 +                ieee80211_free_node(ni);
 +                continue;
 +            }
 +
 +            if (ic->ic_rawbpf != NULL)
 +                bpf_mtap(ic->ic_rawbpf, m0);
 +
 +            if (rum_tx_data(sc, m0, ni) != 0) {
 +                ieee80211_free_node(ni);
 +                ifp->if_oerrors++;
 +                break;
 +            }
 +        }
 +
 +        sc->sc_tx_timer = 5;
 +        ifp->if_timer = 1;
 +    }
 +}
 +
 +static void
 +rum_watchdog(struct ifnet *ifp)
 +{
 +    struct rum_softc *sc = ifp->if_softc;
 +    struct ieee80211com *ic = &sc->sc_ic;
 +
 +    ifp->if_timer = 0;
 +
 +    if (sc->sc_tx_timer > 0) {
 +        if (--sc->sc_tx_timer == 0) {
 +            printf("%s: device timeout\n", device_get_nameunit(sc->sc_dev));
 +            /*rum_init(ifp); XXX needs a process context! */
 +            ifp->if_oerrors++;
 +            return;
 +        }
 +        ifp->if_timer = 1;
 +    }
 +
 +    ieee80211_watchdog(ic);
 +}
 +
 +static int
 +rum_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 +{
 +    struct rum_softc *sc = ifp->if_softc;
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    int s, error = 0;
 +
 +    s = splnet();
 +
 +    switch (cmd) {
 +    case SIOCSIFFLAGS:
 +        if (ifp->if_flags & IFF_UP) {
 +            if (ifp->if_drv_flags & IFF_DRV_RUNNING)
 +                rum_update_promisc(sc);
 +            else
 +                rum_init(sc);
 +        } else {
 +            if (ifp->if_drv_flags & IFF_DRV_RUNNING)
 +                rum_stop(ifp);
 +        }
 +        break;
 +
 +    default:
 +        error = ieee80211_ioctl(ic, cmd, data);
 +    }
 +
 +    if (error == ENETRESET) {
 +	    if ((ifp->if_flags & IFF_UP) &&
 +            (ifp->if_drv_flags & IFF_DRV_RUNNING))
 +            rum_init(sc);
 +        error = 0;
 +    }
 +
 +    splx(s);
 +
 +    return error;
 +}
 +
 +static void
 +rum_eeprom_read(struct rum_softc *sc, uint16_t addr, void *buf, int len)
 +{
 +    usb_device_request_t req;
 +    usbd_status error;
 +
 +    req.bmRequestType = UT_READ_VENDOR_DEVICE;
 +    req.bRequest = RT2573_READ_EEPROM;
 +    USETW(req.wValue, 0);
 +    USETW(req.wIndex, addr);
 +    USETW(req.wLength, len);
 +
 +    error = usbd_do_request(sc->sc_udev, &req, buf);
 +    if (error != 0) {
 +        printf("%s: could not read EEPROM: %s\n",
 +            device_get_nameunit(sc->sc_dev), usbd_errstr(error));
 +    }
 +}
 +
 +static uint32_t
 +rum_read(struct rum_softc *sc, uint16_t reg)
 +{
 +    uint32_t val;
 +
 +    rum_read_multi(sc, reg, &val, sizeof val);
 +
 +    return le32toh(val);
 +}
 +
 +static void
 +rum_read_multi(struct rum_softc *sc, uint16_t reg, void *buf, int len)
 +{
 +    usb_device_request_t req;
 +    usbd_status error;
 +
 +    req.bmRequestType = UT_READ_VENDOR_DEVICE;
 +    req.bRequest = RT2573_READ_MULTI_MAC;
 +    USETW(req.wValue, 0);
 +    USETW(req.wIndex, reg);
 +    USETW(req.wLength, len);
 +
 +    error = usbd_do_request(sc->sc_udev, &req, buf);
 +    if (error != 0) {
 +        printf("%s: could not multi read MAC register: %s\n",
 +            device_get_nameunit(sc->sc_dev), usbd_errstr(error));
 +    }
 +}
 +
 +static void
 +rum_write(struct rum_softc *sc, uint16_t reg, uint32_t val)
 +{
 +    uint32_t tmp = htole32(val);
 +
 +    rum_write_multi(sc, reg, &tmp, sizeof tmp);
 +}
 +
 +static void
 +rum_write_multi(struct rum_softc *sc, uint16_t reg, void *buf, size_t len)
 +{
 +    usb_device_request_t req;
 +    usbd_status error;
 +
 +    req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
 +    req.bRequest = RT2573_WRITE_MULTI_MAC;
 +    USETW(req.wValue, 0);
 +    USETW(req.wIndex, reg);
 +    USETW(req.wLength, len);
 +
 +    error = usbd_do_request(sc->sc_udev, &req, buf);
 +    if (error != 0) {
 +        printf("%s: could not multi write MAC register: %s\n",
 +            device_get_nameunit(sc->sc_dev), usbd_errstr(error));
 +    }
 +}
 +
 +static void
 +rum_bbp_write(struct rum_softc *sc, uint8_t reg, uint8_t val)
 +{
 +    uint32_t tmp;
 +    int ntries;
 +
 +    for (ntries = 0; ntries < 5; ntries++) {
 +        if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY))
 +            break;
 +    }
 +    if (ntries == 5) {
 +        printf("%s: could not write to BBP\n", device_get_nameunit(sc->sc_dev));
 +        return;
 +    }
 +
 +    tmp = RT2573_BBP_BUSY | (reg & 0x7f) << 8 | val;
 +    rum_write(sc, RT2573_PHY_CSR3, tmp);
 +}
 +
 +static uint8_t
 +rum_bbp_read(struct rum_softc *sc, uint8_t reg)
 +{
 +    uint32_t val;
 +    int ntries;
 +
 +    for (ntries = 0; ntries < 5; ntries++) {
 +        if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY))
 +            break;
 +    }
 +    if (ntries == 5) {
 +        printf("%s: could not read BBP\n", device_get_nameunit(sc->sc_dev));
 +        return 0;
 +    }
 +
 +    val = RT2573_BBP_BUSY | RT2573_BBP_READ | reg << 8;
 +    rum_write(sc, RT2573_PHY_CSR3, val);
 +
 +    for (ntries = 0; ntries < 100; ntries++) {
 +        val = rum_read(sc, RT2573_PHY_CSR3);
 +        if (!(val & RT2573_BBP_BUSY))
 +            return val & 0xff;
 +        DELAY(1);
 +    }
 +
 +    printf("%s: could not read BBP\n", device_get_nameunit(sc->sc_dev));
 +    return 0;
 +}
 +
 +static void
 +rum_rf_write(struct rum_softc *sc, uint8_t reg, uint32_t val)
 +{
 +    uint32_t tmp;
 +    int ntries;
 +
 +    for (ntries = 0; ntries < 5; ntries++) {
 +        if (!(rum_read(sc, RT2573_PHY_CSR4) & RT2573_RF_BUSY))
 +            break;
 +    }
 +    if (ntries == 5) {
 +        printf("%s: could not write to RF\n", device_get_nameunit(sc->sc_dev));
 +        return;
 +    }
 +
 +    tmp = RT2573_RF_BUSY | RT2573_RF_20BIT | (val & 0xfffff) << 2 |
 +        (reg & 3);
 +    rum_write(sc, RT2573_PHY_CSR4, tmp);
 +
 +    /* remember last written value in sc */
 +    sc->rf_regs[reg] = val;
 +
 +    DPRINTFN(15, ("RF R[%u] <- 0x%05x\n", reg & 3, val & 0xfffff));
 +}
 +
 +static void
 +rum_select_antenna(struct rum_softc *sc)
 +{
 +    uint8_t bbp4, bbp77;
 +    uint32_t tmp;
 +
 +    bbp4  = rum_bbp_read(sc, 4);
 +    bbp77 = rum_bbp_read(sc, 77);
 +
 +    /* TBD */
 +
 +    /* make sure Rx is disabled before switching antenna */
 +    tmp = rum_read(sc, RT2573_TXRX_CSR0);
 +    rum_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX);
 +
 +    rum_bbp_write(sc,  4, bbp4);
 +    rum_bbp_write(sc, 77, bbp77);
 +
 +    rum_write(sc, RT2573_TXRX_CSR0, tmp);
 +}
 +
 +/*
 + * Enable multi-rate retries for frames sent at OFDM rates.
 + * In 802.11b/g mode, allow fallback to CCK rates.
 + */
 +static void
 +rum_enable_mrr(struct rum_softc *sc)
 +{
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    uint32_t tmp;
 +
 +    tmp = rum_read(sc, RT2573_TXRX_CSR4);
 +
 +    tmp &= ~RT2573_MRR_CCK_FALLBACK;
 +    if (!IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
 +        tmp |= RT2573_MRR_CCK_FALLBACK;
 +    tmp |= RT2573_MRR_ENABLED;
 +
 +    rum_write(sc, RT2573_TXRX_CSR4, tmp);
 +}
 +
 +static void
 +rum_set_txpreamble(struct rum_softc *sc)
 +{
 +    uint32_t tmp;
 +
 +    tmp = rum_read(sc, RT2573_TXRX_CSR4);
 +
 +    tmp &= ~RT2573_SHORT_PREAMBLE;
 +    if (sc->sc_ic.ic_flags & IEEE80211_F_SHPREAMBLE)
 +        tmp |= RT2573_SHORT_PREAMBLE;
 +
 +    rum_write(sc, RT2573_TXRX_CSR4, tmp);
 +}
 +
 +static void
 +rum_set_basicrates(struct rum_softc *sc)
 +{
 +    struct ieee80211com *ic = &sc->sc_ic;
 +
 +    /* update basic rate set */
 +    if (ic->ic_curmode == IEEE80211_MODE_11B) {
 +        /* 11b basic rates: 1, 2Mbps */
 +        rum_write(sc, RT2573_TXRX_CSR5, 0x3);
 +    } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->ni_chan)) {
 +        /* 11a basic rates: 6, 12, 24Mbps */
 +        rum_write(sc, RT2573_TXRX_CSR5, 0x150);
 +    } else {
 +        /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */
 +        rum_write(sc, RT2573_TXRX_CSR5, 0x15f);
 +    }
 +}
 +
 +/*
 + * Reprogram MAC/BBP to switch to a new band.  Values taken from the reference
 + * driver.
 + */
 +static void
 +rum_select_band(struct rum_softc *sc, struct ieee80211_channel *c)
 +{
 +    uint8_t bbp17, bbp35, bbp96, bbp97, bbp98, bbp104;
 +    uint32_t tmp;
 +
 +    /* update all BBP registers that depend on the band */
 +    bbp17 = 0x20; bbp96 = 0x48; bbp104 = 0x2c;
 +    bbp35 = 0x50; bbp97 = 0x48; bbp98  = 0x48;
 +    if (IEEE80211_IS_CHAN_5GHZ(c)) {
 +        bbp17 += 0x08; bbp96 += 0x10; bbp104 += 0x0c;
 +        bbp35 += 0x10; bbp97 += 0x10; bbp98  += 0x10;
 +    }
 +    if ((IEEE80211_IS_CHAN_2GHZ(c) && sc->ext_2ghz_lna) ||
 +        (IEEE80211_IS_CHAN_5GHZ(c) && sc->ext_5ghz_lna)) {
 +        bbp17 += 0x10; bbp96 += 0x10; bbp104 += 0x10;
 +    }
 +
 +    sc->bbp17 = bbp17;
 +    rum_bbp_write(sc,  17, bbp17);
 +    rum_bbp_write(sc,  96, bbp96);
 +    rum_bbp_write(sc, 104, bbp104);
 +
 +    if ((IEEE80211_IS_CHAN_2GHZ(c) && sc->ext_2ghz_lna) ||
 +        (IEEE80211_IS_CHAN_5GHZ(c) && sc->ext_5ghz_lna)) {
 +        rum_bbp_write(sc, 75, 0x80);
 +        rum_bbp_write(sc, 86, 0x80);
 +        rum_bbp_write(sc, 88, 0x80);
 +    }
 +
 +    rum_bbp_write(sc, 35, bbp35);
 +    rum_bbp_write(sc, 97, bbp97);
 +    rum_bbp_write(sc, 98, bbp98);
 +
 +    tmp = rum_read(sc, RT2573_PHY_CSR0);
 +    tmp &= ~(RT2573_PA_PE_2GHZ | RT2573_PA_PE_5GHZ);
 +    if (IEEE80211_IS_CHAN_2GHZ(c))
 +        tmp |= RT2573_PA_PE_2GHZ;
 +    else
 +        tmp |= RT2573_PA_PE_5GHZ;
 +    rum_write(sc, RT2573_PHY_CSR0, tmp);
 +
 +    /* 802.11a uses a 16 microseconds short interframe space */
 +    sc->sifs = IEEE80211_IS_CHAN_5GHZ(c) ? 16 : 10;
 +}
 +
 +static void
 +rum_set_chan(struct rum_softc *sc, struct ieee80211_channel *c)
 +{
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    const struct rfprog *rfprog;
 +    uint8_t bbp3, bbp94 = RT2573_BBPR94_DEFAULT;
 +    int8_t power;
 +    u_int i, chan;
 +
 +    chan = ieee80211_chan2ieee(ic, c);
 +    if (chan == 0 || chan == IEEE80211_CHAN_ANY)
 +        return;
 +
 +    /* select the appropriate RF settings based on what EEPROM says */
 +    rfprog = (sc->rf_rev == RT2573_RF_5225 ||
 +          sc->rf_rev == RT2573_RF_2527) ? rum_rf5225 : rum_rf5226;
 +
 +    /* find the settings for this channel (we know it exists) */
 +    for (i = 0; rfprog[i].chan != chan; i++);
 +
 +    power = sc->txpow[i];
 +    if (power < 0) {
 +        bbp94 += power;
 +        power = 0;
 +    } else if (power > 31) {
 +        bbp94 += power - 31;
 +        power = 31;
 +    }
 +
 +    /*
 +     * If we are switching from the 2GHz band to the 5GHz band or
 +     * vice-versa, BBP registers need to be reprogrammed.
 +     */
 +    if (c->ic_flags != ic->ic_curchan->ic_flags) {
 +        rum_select_band(sc, c);
 +        rum_select_antenna(sc);
 +    }
 +    ic->ic_curchan = c;
 +
 +    rum_rf_write(sc, RT2573_RF1, rfprog[i].r1);
 +    rum_rf_write(sc, RT2573_RF2, rfprog[i].r2);
 +    rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7);
 +    rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10);
 +
 +    rum_rf_write(sc, RT2573_RF1, rfprog[i].r1);
 +    rum_rf_write(sc, RT2573_RF2, rfprog[i].r2);
 +    rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7 | 1);
 +    rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10);
 +
 +    rum_rf_write(sc, RT2573_RF1, rfprog[i].r1);
 +    rum_rf_write(sc, RT2573_RF2, rfprog[i].r2);
 +    rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7);
 +    rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10);
 +
 +    DELAY(10);
 +
 +    /* enable smart mode for MIMO-capable RFs */
 +    bbp3 = rum_bbp_read(sc, 3);
 +
 +    bbp3 &= ~RT2573_SMART_MODE;
 +    if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_2527)
 +        bbp3 |= RT2573_SMART_MODE;
 +
 +    rum_bbp_write(sc, 3, bbp3);
 +
 +    if (bbp94 != RT2573_BBPR94_DEFAULT)
 +        rum_bbp_write(sc, 94, bbp94);
 +}
 +
 +/*
 + * Enable TSF synchronization and tell h/w to start sending beacons for IBSS
 + * and HostAP operating modes.
 + */
 +static void
 +rum_enable_tsf_sync(struct rum_softc *sc)
 +{
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    uint32_t tmp;
 +
 +    if (ic->ic_opmode != IEEE80211_M_STA) {
 +        /*
 +         * Change default 16ms TBTT adjustment to 8ms.
 +         * Must be done before enabling beacon generation.
 +         */
 +        rum_write(sc, RT2573_TXRX_CSR10, 1 << 12 | 8);
 +    }
 +
 +    tmp = rum_read(sc, RT2573_TXRX_CSR9) & 0xff000000;
 +
 +    /* set beacon interval (in 1/16ms unit) */
 +    tmp |= ic->ic_bss->ni_intval * 16;
 +
 +    tmp |= RT2573_TSF_TICKING | RT2573_ENABLE_TBTT;
 +    if (ic->ic_opmode == IEEE80211_M_STA)
 +        tmp |= RT2573_TSF_MODE(1);
 +    else
 +        tmp |= RT2573_TSF_MODE(2) | RT2573_GENERATE_BEACON;
 +
 +    rum_write(sc, RT2573_TXRX_CSR9, tmp);
 +}
 +
 +static void
 +rum_update_slot(struct rum_softc *sc)
 +{
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    uint8_t slottime;
 +    uint32_t tmp;
 +
 +    slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
 +
 +    tmp = rum_read(sc, RT2573_MAC_CSR9);
 +    tmp = (tmp & ~0xff) | slottime;
 +    rum_write(sc, RT2573_MAC_CSR9, tmp);
 +
 +    DPRINTF(("setting slot time to %uus\n", slottime));
 +}
 +
 +static void
 +rum_set_bssid(struct rum_softc *sc, const uint8_t *bssid)
 +{
 +    uint32_t tmp;
 +
 +    tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24;
 +    rum_write(sc, RT2573_MAC_CSR4, tmp);
 +
 +    tmp = bssid[4] | bssid[5] << 8 | RT2573_ONE_BSSID << 16;
 +    rum_write(sc, RT2573_MAC_CSR5, tmp);
 +}
 +
 +static void
 +rum_set_macaddr(struct rum_softc *sc, const uint8_t *addr)
 +{
 +    uint32_t tmp;
 +
 +    tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24;
 +    rum_write(sc, RT2573_MAC_CSR2, tmp);
 +
 +    tmp = addr[4] | addr[5] << 8 | 0xff << 16;
 +    rum_write(sc, RT2573_MAC_CSR3, tmp);
 +}
 +
 +static void
 +rum_update_promisc(struct rum_softc *sc)
 +{
 +    struct ifnet *ifp = sc->sc_ic.ic_ifp;
 +    uint32_t tmp;
 +
 +    tmp = rum_read(sc, RT2573_TXRX_CSR0);
 +
 +    tmp &= ~RT2573_DROP_NOT_TO_ME;
 +    if (!(ifp->if_flags & IFF_PROMISC))
 +        tmp |= RT2573_DROP_NOT_TO_ME;
 +
 +    rum_write(sc, RT2573_TXRX_CSR0, tmp);
 +
 +    DPRINTF(("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ?
 +        "entering" : "leaving"));
 +}
 +
 +static const char *
 +rum_get_rf(int rev)
 +{
 +    switch (rev) {
 +    case RT2573_RF_2527:    return "RT2527 (MIMO XR)";
 +    case RT2573_RF_2528:    return "RT2528";
 +    case RT2573_RF_5225:    return "RT5225 (MIMO XR)";
 +    case RT2573_RF_5226:    return "RT5226";
 +    default:        return "unknown";
 +    }
 +}
 +
 +static void
 +rum_read_eeprom(struct rum_softc *sc)
 +{
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    uint16_t val;
 +#ifdef RUM_DEBUG
 +    int i;
 +#endif
 +
 +    /* read MAC/BBP type */
 +    rum_eeprom_read(sc, RT2573_EEPROM_MACBBP, &val, 2);
 +    sc->macbbp_rev = le16toh(val);
 +
 +    /* read MAC address */
 +    rum_eeprom_read(sc, RT2573_EEPROM_ADDRESS, ic->ic_myaddr, 6);
 +
 +    rum_eeprom_read(sc, RT2573_EEPROM_ANTENNA, &val, 2);
 +    val = le16toh(val);
 +    sc->rf_rev =   (val >> 11) & 0x1f;
 +    sc->hw_radio = (val >> 10) & 0x1;
 +    sc->rx_ant =   (val >> 4)  & 0x3;
 +    sc->tx_ant =   (val >> 2)  & 0x3;
 +    sc->nb_ant =   val & 0x3;
 +
 +    DPRINTF(("RF revision=%d\n", sc->rf_rev));
 +
 +    rum_eeprom_read(sc, RT2573_EEPROM_CONFIG2, &val, 2);
 +    val = le16toh(val);
 +    sc->ext_5ghz_lna = (val >> 6) & 0x1;
 +    sc->ext_2ghz_lna = (val >> 4) & 0x1;
 +
 +    DPRINTF(("External 2GHz LNA=%d\nExternal 5GHz LNA=%d\n",
 +        sc->ext_2ghz_lna, sc->ext_5ghz_lna));
 +
 +    rum_eeprom_read(sc, RT2573_EEPROM_RSSI_2GHZ_OFFSET, &val, 2);
 +    val = le16toh(val);
 +    if ((val & 0xff) != 0xff)
 +        sc->rssi_2ghz_corr = (int8_t)(val & 0xff);    /* signed */
 +
 +    rum_eeprom_read(sc, RT2573_EEPROM_RSSI_5GHZ_OFFSET, &val, 2);
 +    val = le16toh(val);
 +    if ((val & 0xff) != 0xff)
 +        sc->rssi_5ghz_corr = (int8_t)(val & 0xff);    /* signed */
 +
 +    DPRINTF(("RSSI 2GHz corr=%d\nRSSI 5GHz corr=%d\n",
 +        sc->rssi_2ghz_corr, sc->rssi_5ghz_corr));
 +
 +    rum_eeprom_read(sc, RT2573_EEPROM_FREQ_OFFSET, &val, 2);
 +    val = le16toh(val);
 +    if ((val & 0xff) != 0xff)
 +        sc->rffreq = val & 0xff;
 +
 +    DPRINTF(("RF freq=%d\n", sc->rffreq));
 +
 +    /* read Tx power for all a/b/g channels */
 +    rum_eeprom_read(sc, RT2573_EEPROM_TXPOWER, sc->txpow, 14);
 +    /* XXX default Tx power for 802.11a channels */
 +    memset(sc->txpow + 14, 24, sizeof (sc->txpow) - 14);
 +#ifdef RUM_DEBUG
 +    for (i = 0; i < 14; i++)
 +        DPRINTF(("Channel=%d Tx power=%d\n", i + 1,  sc->txpow[i]));
 +#endif
 +
 +    /* read default values for BBP registers */
 +    rum_eeprom_read(sc, RT2573_EEPROM_BBP_BASE, sc->bbp_prom, 2 * 16);
 +#ifdef RUM_DEBUG
 +    for (i = 0; i < 14; i++) {
 +        if (sc->bbp_prom[i].reg == 0 || sc->bbp_prom[i].reg == 0xff)
 +            continue;
 +        DPRINTF(("BBP R%d=%02x\n", sc->bbp_prom[i].reg,
 +            sc->bbp_prom[i].val));
 +    }
 +#endif
 +}
 +
 +static int
 +rum_bbp_init(struct rum_softc *sc)
 +{
 +#define N(a)    (sizeof (a) / sizeof ((a)[0]))
 +    int i, ntries;
 +    uint8_t val;
 +
 +    /* wait for BBP to be ready */
 +    for (ntries = 0; ntries < 100; ntries++) {
 +        val = rum_bbp_read(sc, 0);
 +        if (val != 0 && val != 0xff)
 +            break;
 +        DELAY(1000);
 +    }
 +    if (ntries == 100) {
 +        printf("%s: timeout waiting for BBP\n",
 +            device_get_nameunit(sc->sc_dev));
 +        return EIO;
 +    }
 +
 +    /* initialize BBP registers to default values */
 +    for (i = 0; i < N(rum_def_bbp); i++)
 +        rum_bbp_write(sc, rum_def_bbp[i].reg, rum_def_bbp[i].val);
 +
 +    /* write vendor-specific BBP values (from EEPROM) */
 +    for (i = 0; i < 16; i++) {
 +        if (sc->bbp_prom[i].reg == 0 || sc->bbp_prom[i].reg == 0xff)
 +            continue;
 +        rum_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val);
 +    }
 +
 +    return 0;
 +#undef N
 +}
 +
 +static void
 +rum_init(void *priv)
 +{
 +#define N(a)    (sizeof (a) / sizeof ((a)[0]))
 +    struct rum_softc *sc = priv;
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    struct ifnet *ifp = ic->ic_ifp;
 +    struct rum_rx_data *data;
 +    uint32_t tmp;
 +    usbd_status error = 0;
 +    int i, ntries;
 +
 +//    if ((sc->sc_flags & RT2573_FWLOADED) == 0) {
 +//        rum_attachhook(sc);
 +//    }
 +
 +    rum_stop(ifp);
 +
 +    /* initialize MAC registers to default values */
 +    for (i = 0; i < N(rum_def_mac); i++)
 +        rum_write(sc, rum_def_mac[i].reg, rum_def_mac[i].val);
 +
 +    /* set host ready */
 +    rum_write(sc, RT2573_MAC_CSR1, 3);
 +    rum_write(sc, RT2573_MAC_CSR1, 0);
 +
 +    /* wait for BBP/RF to wakeup */
 +    for (ntries = 0; ntries < 1000; ntries++) {
 +        if (rum_read(sc, RT2573_MAC_CSR12) & 8)
 +            break;
 +        rum_write(sc, RT2573_MAC_CSR12, 4);    /* force wakeup */
 +        DELAY(1000);
 +    }
 +    if (ntries == 1000) {
 +        printf("%s: timeout waiting for BBP/RF to wakeup\n",
 +            device_get_nameunit(sc->sc_dev));
 +        goto fail;
 +    }
 +
 +    if ((error = rum_bbp_init(sc)) != 0)
 +        goto fail;
 +
 +    /* select default channel */
 +    rum_select_band(sc, ic->ic_curchan);
 +    rum_select_antenna(sc);
 +    rum_set_chan(sc, ic->ic_curchan);
 +
 +    /* clear STA registers */
 +    rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof sc->sta);
 +
 +    IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
 +    rum_set_macaddr(sc, ic->ic_myaddr);
 +
 +    /* initialize ASIC */
 +    rum_write(sc, RT2573_MAC_CSR1, 4);
 +
 +    /*
 +     * Allocate xfer for AMRR statistics requests.
 +     */
 +    sc->amrr_xfer = usbd_alloc_xfer(sc->sc_udev);
 +    if (sc->amrr_xfer == NULL) {
 +        printf("%s: could not allocate AMRR xfer\n",
 +            device_get_nameunit(sc->sc_dev));
 +        goto fail;
 +    }
 +
 +    /*
 +     * Open Tx and Rx USB bulk pipes.
 +     */
 +    error = usbd_open_pipe(sc->sc_iface, sc->sc_tx_no, USBD_EXCLUSIVE_USE,
 +        &sc->sc_tx_pipeh);
 +    if (error != 0) {
 +        printf("%s: could not open Tx pipe: %s\n",
 +            device_get_nameunit(sc->sc_dev), usbd_errstr(error));
 +        goto fail;
 +    }
 +
 +    error = usbd_open_pipe(sc->sc_iface, sc->sc_rx_no, USBD_EXCLUSIVE_USE,
 +        &sc->sc_rx_pipeh);
 +    if (error != 0) {
 +        printf("%s: could not open Rx pipe: %s\n",
 +            device_get_nameunit(sc->sc_dev), usbd_errstr(error));
 +        goto fail;
 +    }
 +
 +    /*
 +     * Allocate Tx and Rx xfer queues.
 +     */
 +    error = rum_alloc_tx_list(sc);
 +    if (error != 0) {
 +        printf("%s: could not allocate Tx list\n",
 +            device_get_nameunit(sc->sc_dev));
 +        goto fail;
 +    }
 +
 +    error = rum_alloc_rx_list(sc);
 +    if (error != 0) {
 +        printf("%s: could not allocate Rx list\n",
 +            device_get_nameunit(sc->sc_dev));
 +        goto fail;
 +    }
 +
 +    /*
 +     * Start up the receive pipe.
 +     */
 +    for (i = 0; i < RT2573_RX_LIST_COUNT; i++) {
 +        data = &sc->rx_data[i];
 +
 +        usbd_setup_xfer(data->xfer, sc->sc_rx_pipeh, data, data->buf,
 +            MCLBYTES, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, rum_rxeof);
 +        usbd_transfer(data->xfer);
 +    }
 +
 +    /* update Rx filter */
 +    tmp = rum_read(sc, RT2573_TXRX_CSR0) & 0xffff;
 +
 +    tmp |= RT2573_DROP_PHY_ERROR | RT2573_DROP_CRC_ERROR;
 +    if (ic->ic_opmode != IEEE80211_M_MONITOR) {
 +        tmp |= RT2573_DROP_CTL | RT2573_DROP_VER_ERROR |
 +               RT2573_DROP_ACKCTS;
 +        if (ic->ic_opmode != IEEE80211_M_HOSTAP)
 +            tmp |= RT2573_DROP_TODS;
 +        if (!(ifp->if_flags & IFF_PROMISC))
 +            tmp |= RT2573_DROP_NOT_TO_ME;
 +    }
 +    rum_write(sc, RT2573_TXRX_CSR0, tmp);
 +
 +    ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 +    ifp->if_drv_flags |= IFF_DRV_RUNNING;
 +
 +    if (ic->ic_opmode == IEEE80211_M_MONITOR)
 +        ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
 +    else
 +        ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
 +
 +    return;
 +
 +fail:    rum_stop(ifp);
 +    return;
 +#undef N
 +}
 +
 +static void
 +rum_stop(struct ifnet *ifp)
 +{
 +    struct rum_softc *sc = ifp->if_softc;
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    uint32_t tmp;
 +
 +    ieee80211_new_state(ic, IEEE80211_S_INIT, -1);    /* free all nodes */
 +
 +    sc->sc_tx_timer = 0;
 +    ifp->if_timer = 0;
 +    ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
 +
 +    /* disable Rx */
 +    tmp = rum_read(sc, RT2573_TXRX_CSR0);
 +    rum_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX);
 +
 +    /* reset ASIC */
 +    rum_write(sc, RT2573_MAC_CSR1, 3);
 +    rum_write(sc, RT2573_MAC_CSR1, 0);
 +
 +    if (sc->sc_rx_pipeh != NULL) {
 +        usbd_abort_pipe(sc->sc_rx_pipeh);
 +        usbd_close_pipe(sc->sc_rx_pipeh);
 +        sc->sc_rx_pipeh = NULL;
 +    }
 +
 +    if (sc->sc_tx_pipeh != NULL) {
 +        usbd_abort_pipe(sc->sc_tx_pipeh);
 +        usbd_close_pipe(sc->sc_tx_pipeh);
 +        sc->sc_tx_pipeh = NULL;
 +    }
 +
 +    rum_free_rx_list(sc);
 +    rum_free_tx_list(sc);
 +}
 +
 +static int
 +rum_load_microcode(struct rum_softc *sc, const u_char *ucode, size_t size)
 +{
 +    usb_device_request_t req;
 +    uint16_t reg = RT2573_MCU_CODE_BASE;
 +    usbd_status error;
 +
 +    /* copy firmware image into NIC */
 +    for (; size >= 4; reg += 4, ucode += 4, size -= 4)
 +        rum_write(sc, reg, UGETDW(ucode));
 +
 +    req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
 +    req.bRequest = RT2573_MCU_CNTL;
 +    USETW(req.wValue, RT2573_MCU_RUN);
 +    USETW(req.wIndex, 0);
 +    USETW(req.wLength, 0);
 +
 +    error = usbd_do_request(sc->sc_udev, &req, NULL);
 +    if (error != 0) {
 +        printf("%s: could not run firmware: %s\n",
 +            device_get_nameunit(sc->sc_dev), usbd_errstr(error));
 +    }
 +    return error;
 +}
 +
 +static int
 +rum_prepare_beacon(struct rum_softc *sc)
 +{
 +    struct ieee80211com *ic = &sc->sc_ic;
 +    struct rum_tx_desc desc;
 +    struct mbuf *m0;
 +    int rate;
 +
 +    m0 = ieee80211_beacon_alloc(ic, ic->ic_bss, &sc->sc_bo);
 +    if (m0 == NULL) {
 +        printf("%s: could not allocate beacon frame\n",
 +            device_get_nameunit(sc->sc_dev));
 +        return ENOBUFS;
 +    }
 +
 +    /* send beacons at the lowest available rate */
 +    rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2;
 +
 +    rum_setup_tx_desc(sc, &desc, RT2573_TX_TIMESTAMP, RT2573_TX_HWSEQ,
 +        m0->m_pkthdr.len, rate);
 +
 +    /* copy the first 24 bytes of Tx descriptor into NIC memory */
 +    rum_write_multi(sc, RT2573_HW_BEACON_BASE0, (uint8_t *)&desc, 24);
 +
 +    /* copy beacon header and payload into NIC memory */
 +    rum_write_multi(sc, RT2573_HW_BEACON_BASE0 + 24, mtod(m0, uint8_t *),
 +        m0->m_pkthdr.len);
 +
 +    m_freem(m0);
 +
 +    return 0;
 +}
 +
 +#define RUM_AMRR_MIN_SUCCESS_THRESHOLD  1
 +#define RUM_AMRR_MAX_SUCCESS_THRESHOLD 10
 +
 +static void
 +rum_amrr_start(struct rum_softc *sc, struct ieee80211_node *ni)
 +{
 +    struct rum_amrr *amrr = &sc->amrr;
 +    int i;
 +
 +    /* clear statistic registers (STA_CSR0 to STA_CSR5) */
 +    rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof sc->sta);
 +
 +    amrr->success = 0;
 +    amrr->recovery = 0;
 +    amrr->txcnt = amrr->retrycnt = 0;
 +    amrr->success_threshold = RUM_AMRR_MIN_SUCCESS_THRESHOLD;
 +
 +//    ieee80211_amrr_node_init(&sc->amrr, &sc->amn);
 +
 +    /* set rate to some reasonable initial value */
 +    for (i = ni->ni_rates.rs_nrates - 1;
 +         i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72;
 +         i--);
 +    ni->ni_txrate = i;
 +
 +    callout_reset(&sc->amrr_ch, hz, rum_amrr_timeout, sc);
 +}
 +
 +static void
 +rum_amrr_timeout(void *arg)
 +{
 +    struct rum_softc *sc = arg;
 +    usb_device_request_t req;
 +    int s;
 +
 +    s = splusb();
 +
 +    /*
 +     * Asynchronously read statistic registers (cleared by read).
 +     */
 +    req.bmRequestType = UT_READ_VENDOR_DEVICE;
 +    req.bRequest = RT2573_READ_MULTI_MAC;
 +    USETW(req.wValue, 0);
 +    USETW(req.wIndex, RT2573_STA_CSR0);
 +    USETW(req.wLength, sizeof sc->sta);
 +
 +    usbd_setup_default_xfer(sc->amrr_xfer, sc->sc_udev, sc,
 +        USBD_DEFAULT_TIMEOUT, &req, sc->sta, sizeof sc->sta, 0,
 +        rum_amrr_update);
 +    (void)usbd_transfer(sc->amrr_xfer);
 +
 +    splx(s);
 +}
 +
 +static void
 +rum_amrr_update(usbd_xfer_handle xfer, usbd_private_handle priv,
 +    usbd_status status)
 +{
 +        struct rum_softc *sc = (struct rum_softc *)priv;
 +        struct rum_amrr *amrr = &sc->amrr;
 +        struct ifnet *ifp = sc->sc_ifp; //FIXME1
 +
 +        if (status != USBD_NORMAL_COMPLETION) {
 +                device_printf(sc->sc_dev, "could not retrieve Tx statistics - "
 +                    "cancelling automatic rate control\n");
 +                return;
 +        }
 +
 +        /* count TX retry-fail as Tx errors */
 +        ifp->if_oerrors += le32toh(sc->sta[5]) >> 16;
 +
 +        amrr->retrycnt =
 +                (le32toh(sc->sta[4]) >> 16) +   /* TX one-retry ok count */
 +            (le32toh(sc->sta[5]) & 0xffff) +    /* TX more-retry ok count */
 +            (le32toh(sc->sta[5]) >> 16);        /* TX retry-fail count */
 +
 +        amrr->txcnt =
 +            amrr->retrycnt +
 +            (le32toh(sc->sta[4]) & 0xffff);             /* TX no-retry ok count */
 +
 +        rum_ratectl(amrr, sc->sc_ic.ic_bss);
 +
 +        callout_reset(&sc->amrr_ch, hz, rum_amrr_timeout, sc);
 +}
 +
 +/*-
 + * Naive implementation of the Adaptive Multi Rate Retry algorithm:
 + *     "IEEE 802.11 Rate Adaptation: A Practical Approach"
 + *     Mathieu Lacage, Hossein Manshaei, Thierry Turletti
 + *     INRIA Sophia - Projet Planete
 + *     http://www-sop.inria.fr/rapports/sophia/RR-5208.html
 + *
 + * This algorithm is particularly well suited for rum since it does not
 + * require per-frame retry statistics.  Note however that since h/w does
 + * not provide per-frame stats, we can't do per-node rate adaptation and
 + * thus automatic rate adaptation is only enabled in STA operating mode.
 + */
 +#define is_success(amrr)    \
 +    ((amrr)->retrycnt < (amrr)->txcnt / 10)
 +#define is_failure(amrr)    \
 +    ((amrr)->retrycnt > (amrr)->txcnt / 3)
 +#define is_enough(amrr)     \
 +    ((amrr)->txcnt > 10)
 +#define is_min_rate(ni)     \
 +    ((ni)->ni_txrate == 0)
 +#define is_max_rate(ni)     \
 +    ((ni)->ni_txrate == (ni)->ni_rates.rs_nrates - 1)
 +#define increase_rate(ni)   \
 +    ((ni)->ni_txrate++)
 +#define decrease_rate(ni)   \
 +    ((ni)->ni_txrate--)
 +#define reset_cnt(amrr)     \
 +    do { (amrr)->txcnt = (amrr)->retrycnt = 0; } while (0)
 +static void
 +rum_ratectl(struct rum_amrr *amrr, struct ieee80211_node *ni)
 +{
 +    int need_change = 0;
 +
 +    if (is_success(amrr) && is_enough(amrr)) {
 +        amrr->success++;
 +        if (amrr->success >= amrr->success_threshold &&
 +            !is_max_rate(ni)) {
 +            amrr->recovery = 1;
 +            amrr->success = 0;
 +            increase_rate(ni);
 +            need_change = 1;
 +        } else {
 +            amrr->recovery = 0;
 +        }
 +    } else if (is_failure(amrr)) {
 +        amrr->success = 0;
 +        if (!is_min_rate(ni)) {
 +            if (amrr->recovery) {
 +                amrr->success_threshold *= 2;
 +                if (amrr->success_threshold >
 +                    RUM_AMRR_MAX_SUCCESS_THRESHOLD)
 +                    amrr->success_threshold =
 +                        RUM_AMRR_MAX_SUCCESS_THRESHOLD;
 +            } else {
 +                amrr->success_threshold =
 +                    RUM_AMRR_MIN_SUCCESS_THRESHOLD;
 +            }
 +            decrease_rate(ni);
 +            need_change = 1;
 +        }
 +        amrr->recovery = 0; /* original paper was incorrect */
 +    }
 +
 +    if (is_enough(amrr) || need_change)
 +        reset_cnt(amrr);
 +}
 +
 +
 +/*
 +int
 +rum_activate(device_ptr_t self, enum devact act)
 +{
 +    switch (act) {
 +    case DVACT_ACTIVATE:
 +        return EOPNOTSUPP;
 +
 +    case DVACT_DEACTIVATE:
 +        //if_deactivate(&sc->sc_ic.ic_if);
 +        break;
 +    }
 +
 +    return 0;
 +}
 +*/
 +
 +DRIVER_MODULE(rum, uhub, rum_driver, rum_devclass, usbd_driver_load, 0);
 Index: sys/dev/usb/if_rumreg.h
 ===================================================================
 RCS file: sys/dev/usb/if_rumreg.h
 diff -N sys/dev/usb/if_rumreg.h
 --- /dev/null	1 Jan 1970 00:00:00 -0000
 +++ sys/dev/usb/if_rumreg.h	1 Feb 2007 11:26:03 -0000
 @@ -0,0 +1,390 @@
 +/*	$OpenBSD: if_rumreg.h,v 1.12 2006/08/09 08:21:08 damien Exp $	*/
 +
 +/*-
 + * Copyright (c) 2005, 2006 Damien Bergamini <damien.bergamini at free.fr>
 + * Copyright (c) 2006 Niall O'Higgins <niallo at openbsd.org>
 + *
 + * Permission to use, copy, modify, and distribute this software for any
 + * purpose with or without fee is hereby granted, provided that the above
 + * copyright notice and this permission notice appear in all copies.
 + *
 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 + */
 +
 +#define RT2573_TX_DESC_SIZE	(sizeof (struct rum_tx_desc))
 +#define RT2573_RX_DESC_SIZE	(sizeof (struct rum_rx_desc))
 +
 +#define RT2573_CONFIG_NO	1
 +#define RT2573_IFACE_INDEX	0
 +
 +#define RT2573_MCU_CNTL		0x01
 +#define RT2573_WRITE_MAC	0x02
 +#define RT2573_READ_MAC		0x03
 +#define RT2573_WRITE_MULTI_MAC	0x06
 +#define RT2573_READ_MULTI_MAC	0x07
 +#define RT2573_READ_EEPROM	0x09
 +#define RT2573_WRITE_LED	0x0a
 +
 +/*
 + * Control and status registers.
 + */
 +#define RT2573_AIFSN_CSR	0x0400
 +#define RT2573_CWMIN_CSR	0x0404
 +#define RT2573_CWMAX_CSR	0x0408
 +#define RT2573_MCU_CODE_BASE	0x0800
 +#define RT2573_HW_BEACON_BASE0	0x2400
 +#define RT2573_MAC_CSR0		0x3000
 +#define RT2573_MAC_CSR1		0x3004
 +#define RT2573_MAC_CSR2		0x3008
 +#define RT2573_MAC_CSR3		0x300c
 +#define RT2573_MAC_CSR4		0x3010
 +#define RT2573_MAC_CSR5		0x3014
 +#define RT2573_MAC_CSR6		0x3018
 +#define RT2573_MAC_CSR7		0x301c
 +#define RT2573_MAC_CSR8		0x3020
 +#define RT2573_MAC_CSR9		0x3024
 +#define RT2573_MAC_CSR10	0x3028
 +#define RT2573_MAC_CSR11	0x302c
 +#define RT2573_MAC_CSR12	0x3030
 +#define RT2573_MAC_CSR13	0x3034
 +#define RT2573_MAC_CSR14	0x3038
 +#define RT2573_MAC_CSR15	0x303c
 +#define RT2573_TXRX_CSR0	0x3040
 +#define RT2573_TXRX_CSR1	0x3044
 +#define RT2573_TXRX_CSR2	0x3048
 +#define RT2573_TXRX_CSR3	0x304c
 +#define RT2573_TXRX_CSR4	0x3050
 +#define RT2573_TXRX_CSR5	0x3054
 +#define RT2573_TXRX_CSR6	0x3058
 +#define RT2573_TXRX_CSR7	0x305c
 +#define RT2573_TXRX_CSR8	0x3060
 +#define RT2573_TXRX_CSR9	0x3064
 +#define RT2573_TXRX_CSR10	0x3068
 +#define RT2573_TXRX_CSR11	0x306c
 +#define RT2573_TXRX_CSR12	0x3070
 +#define RT2573_TXRX_CSR13	0x3074
 +#define RT2573_TXRX_CSR14	0x3078
 +#define RT2573_TXRX_CSR15	0x307c
 +#define RT2573_PHY_CSR0		0x3080
 +#define RT2573_PHY_CSR1		0x3084
 +#define RT2573_PHY_CSR2		0x3088
 +#define RT2573_PHY_CSR3		0x308c
 +#define RT2573_PHY_CSR4		0x3090
 +#define RT2573_PHY_CSR5		0x3094
 +#define RT2573_PHY_CSR6		0x3098
 +#define RT2573_PHY_CSR7		0x309c
 +#define RT2573_SEC_CSR0		0x30a0
 +#define RT2573_SEC_CSR1		0x30a4
 +#define RT2573_SEC_CSR2		0x30a8
 +#define RT2573_SEC_CSR3		0x30ac
 +#define RT2573_SEC_CSR4		0x30b0
 +#define RT2573_SEC_CSR5		0x30b4
 +#define RT2573_STA_CSR0		0x30c0
 +#define RT2573_STA_CSR1		0x30c4
 +#define RT2573_STA_CSR2		0x30c8
 +#define RT2573_STA_CSR3		0x30cc
 +#define RT2573_STA_CSR4		0x30d0
 +#define RT2573_STA_CSR5		0x30d4
 +
 +
 +/* possible flags for register RT2573_MAC_CSR1 */
 +#define RT2573_RESET_ASIC	(1 << 0)
 +#define RT2573_RESET_BBP	(1 << 1)
 +#define RT2573_HOST_READY	(1 << 2)
 +
 +/* possible flags for register MAC_CSR5 */
 +#define RT2573_ONE_BSSID	3
 +
 +/* possible flags for register TXRX_CSR0 */
 +/* Tx filter flags are in the low 16 bits */
 +#define RT2573_AUTO_TX_SEQ		(1 << 15)
 +/* Rx filter flags are in the high 16 bits */
 +#define RT2573_DISABLE_RX		(1 << 16)
 +#define RT2573_DROP_CRC_ERROR		(1 << 17)
 +#define RT2573_DROP_PHY_ERROR		(1 << 18)
 +#define RT2573_DROP_CTL			(1 << 19)
 +#define RT2573_DROP_NOT_TO_ME		(1 << 20)
 +#define RT2573_DROP_TODS		(1 << 21)
 +#define RT2573_DROP_VER_ERROR		(1 << 22)
 +#define RT2573_DROP_MULTICAST		(1 << 23)
 +#define RT2573_DROP_BROADCAST		(1 << 24)
 +#define RT2573_DROP_ACKCTS		(1 << 25)
 +
 +/* possible flags for register TXRX_CSR4 */
 +#define RT2573_SHORT_PREAMBLE	(1 << 18)
 +#define RT2573_MRR_ENABLED	(1 << 19)
 +#define RT2573_MRR_CCK_FALLBACK	(1 << 22)
 +
 +/* possible flags for register TXRX_CSR9 */
 +#define RT2573_TSF_TICKING	(1 << 16)
 +#define RT2573_TSF_MODE(x)	(((x) & 0x3) << 17)
 +/* TBTT stands for Target Beacon Transmission Time */
 +#define RT2573_ENABLE_TBTT	(1 << 19)
 +#define RT2573_GENERATE_BEACON	(1 << 20)
 +
 +/* possible flags for register PHY_CSR0 */
 +#define RT2573_PA_PE_2GHZ	(1 << 16)
 +#define RT2573_PA_PE_5GHZ	(1 << 17)
 +
 +/* possible flags for register PHY_CSR3 */
 +#define RT2573_BBP_READ	(1 << 15)
 +#define RT2573_BBP_BUSY	(1 << 16)
 +/* possible flags for register PHY_CSR4 */
 +#define RT2573_RF_20BIT	(20 << 24)
 +#define RT2573_RF_BUSY	(1 << 31)
 +
 +/* LED values */
 +#define RT2573_LED_RADIO	(1 << 8)
 +#define RT2573_LED_G		(1 << 9)
 +#define RT2573_LED_A		(1 << 10)
 +#define RT2573_LED_ON		0x1e1e
 +#define RT2573_LED_OFF		0x0
 +
 +#define RT2573_MCU_RUN	(1 << 3)
 +
 +#define RT2573_SMART_MODE	(1 << 0)
 +
 +#define RT2573_BBPR94_DEFAULT	6
 +
 +#define RT2573_BBP_WRITE	(1 << 15)
 +
 +/* dual-band RF */
 +#define RT2573_RF_5226	1
 +#define RT2573_RF_5225	3
 +/* single-band RF */
 +#define RT2573_RF_2528	2
 +#define RT2573_RF_2527	4
 +
 +#define RT2573_BBP_VERSION	0
 +
 +struct rum_tx_desc {
 +	uint32_t	flags;
 +#define RT2573_TX_BURST			(1 << 0)
 +#define RT2573_TX_VALID			(1 << 1)
 +#define RT2573_TX_MORE_FRAG		(1 << 2)
 +#define RT2573_TX_ACK			(1 << 3)
 +#define RT2573_TX_TIMESTAMP		(1 << 4)
 +#define RT2573_TX_OFDM			(1 << 5)
 +#define RT2573_TX_IFS_SIFS		(1 << 6)
 +#define RT2573_TX_LONG_RETRY		(1 << 7)
 +
 +	uint16_t	wme;
 +#define RT2573_QID(v)		(v)
 +#define RT2573_AIFSN(v)		((v) << 4)
 +#define RT2573_LOGCWMIN(v)	((v) << 8)
 +#define RT2573_LOGCWMAX(v)	((v) << 12)
 +
 +	uint16_t	xflags;
 +#define RT2573_TX_HWSEQ		(1 << 12)
 +
 +	uint8_t		plcp_signal;
 +	uint8_t		plcp_service;
 +#define RT2573_PLCP_LENGEXT	0x80
 +
 +	uint8_t		plcp_length_lo;
 +	uint8_t		plcp_length_hi;
 +
 +	uint32_t	iv;
 +	uint32_t	eiv;
 +
 +	uint8_t		offset;
 +	uint8_t		qid;
 +	uint8_t		txpower;
 +#define RT2573_DEFAULT_TXPOWER	0
 +
 +	uint8_t		reserved;
 +} __packed;
 +
 +struct rum_rx_desc {
 +	uint32_t	flags;
 +#define RT2573_RX_BUSY		(1 << 0)
 +#define RT2573_RX_DROP		(1 << 1)
 +#define RT2573_RX_CRC_ERROR	(1 << 6)
 +#define RT2573_RX_OFDM		(1 << 7)
 +
 +	uint8_t		rate;
 +	uint8_t		rssi;
 +	uint8_t		reserved1;
 +	uint8_t		offset;
 +	uint32_t	iv;
 +	uint32_t	eiv;
 +	uint32_t	reserved2[2];
 +} __packed;
 +
 +#define RT2573_RF1	0
 +#define RT2573_RF2	2
 +#define RT2573_RF3	1
 +#define RT2573_RF4	3
 +
 +#define RT2573_EEPROM_MACBBP		0x0000
 +#define RT2573_EEPROM_ADDRESS		0x0004
 +#define RT2573_EEPROM_ANTENNA		0x0020
 +#define RT2573_EEPROM_CONFIG2		0x0022
 +#define RT2573_EEPROM_BBP_BASE		0x0026
 +#define RT2573_EEPROM_TXPOWER		0x0046
 +#define RT2573_EEPROM_FREQ_OFFSET	0x005e
 +#define RT2573_EEPROM_RSSI_2GHZ_OFFSET	0x009a
 +#define RT2573_EEPROM_RSSI_5GHZ_OFFSET	0x009c
 +
 +/*
 + * Default values for MAC registers; values taken from the reference driver.
 + */
 +#define RT2573_DEF_MAC				\
 +	{ RT2573_TXRX_CSR0,  0x025fb032 },	\
 +	{ RT2573_TXRX_CSR1,  0x9eaa9eaf },	\
 +	{ RT2573_TXRX_CSR2,  0x8a8b8c8d },	\
 +	{ RT2573_TXRX_CSR3,  0x00858687 },	\
 +	{ RT2573_TXRX_CSR7,  0x2e31353b },	\
 +	{ RT2573_TXRX_CSR8,  0x2a2a2a2c },	\
 +	{ RT2573_TXRX_CSR15, 0x0000000f },	\
 +	{ RT2573_MAC_CSR6,   0x00000fff },	\
 +	{ RT2573_MAC_CSR8,   0x016c030a },	\
 +	{ RT2573_MAC_CSR10,  0x00000718 },	\
 +	{ RT2573_MAC_CSR12,  0x00000004 },	\
 +	{ RT2573_MAC_CSR13,  0x00007f00 },	\
 +	{ RT2573_SEC_CSR0,   0x00000000 },	\
 +	{ RT2573_SEC_CSR1,   0x00000000 },	\
 +	{ RT2573_SEC_CSR5,   0x00000000 },	\
 +	{ RT2573_PHY_CSR1,   0x000023b0 },	\
 +	{ RT2573_PHY_CSR5,   0x00040a06 },	\
 +	{ RT2573_PHY_CSR6,   0x00080606 },	\
 +	{ RT2573_PHY_CSR7,   0x00000408 },	\
 +	{ RT2573_AIFSN_CSR,  0x00002273 },	\
 +	{ RT2573_CWMIN_CSR,  0x00002344 },	\
 +	{ RT2573_CWMAX_CSR,  0x000034aa }
 +
 +/*
 + * Default values for BBP registers; values taken from the reference driver.
 + */
 +#define RT2573_DEF_BBP	\
 +	{   3, 0x80 },	\
 +	{  15, 0x30 },	\
 +	{  17, 0x20 },	\
 +	{  21, 0xc8 },	\
 +	{  22, 0x38 },	\
 +	{  23, 0x06 },	\
 +	{  24, 0xfe },	\
 +	{  25, 0x0a },	\
 +	{  26, 0x0d },	\
 +	{  32, 0x0b },	\
 +	{  34, 0x12 },	\
 +	{  37, 0x07 },	\
 +	{  39, 0xf8 },	\
 +	{  41, 0x60 },	\
 +	{  53, 0x10 },	\
 +	{  54, 0x18 },	\
 +	{  60, 0x10 },	\
 +	{  61, 0x04 },	\
 +	{  62, 0x04 },	\
 +	{  75, 0xfe },	\
 +	{  86, 0xfe },	\
 +	{  88, 0xfe },	\
 +	{  90, 0x0f },	\
 +	{  99, 0x00 },	\
 +	{ 102, 0x16 },	\
 +	{ 107, 0x04 }
 +
 +/*
 + * Default settings for RF registers; values taken from the reference driver.
 + */
 +#define RT2573_RF5226					\
 +	{   1, 0x00b03, 0x001e1, 0x1a014, 0x30282 },	\
 +	{   2, 0x00b03, 0x001e1, 0x1a014, 0x30287 },	\
 +	{   3, 0x00b03, 0x001e2, 0x1a014, 0x30282 },	\
 +	{   4, 0x00b03, 0x001e2, 0x1a014, 0x30287 },	\
 +	{   5, 0x00b03, 0x001e3, 0x1a014, 0x30282 },	\
 +	{   6, 0x00b03, 0x001e3, 0x1a014, 0x30287 },	\
 +	{   7, 0x00b03, 0x001e4, 0x1a014, 0x30282 },	\
 +	{   8, 0x00b03, 0x001e4, 0x1a014, 0x30287 },	\
 +	{   9, 0x00b03, 0x001e5, 0x1a014, 0x30282 },	\
 +	{  10, 0x00b03, 0x001e5, 0x1a014, 0x30287 },	\
 +	{  11, 0x00b03, 0x001e6, 0x1a014, 0x30282 },	\
 +	{  12, 0x00b03, 0x001e6, 0x1a014, 0x30287 },	\
 +	{  13, 0x00b03, 0x001e7, 0x1a014, 0x30282 },	\
 +	{  14, 0x00b03, 0x001e8, 0x1a014, 0x30284 },	\
 +							\
 +	{  34, 0x00b03, 0x20266, 0x36014, 0x30282 },	\
 +	{  38, 0x00b03, 0x20267, 0x36014, 0x30284 },	\
 +	{  42, 0x00b03, 0x20268, 0x36014, 0x30286 },	\
 +	{  46, 0x00b03, 0x20269, 0x36014, 0x30288 },	\
 +							\
 +	{  36, 0x00b03, 0x00266, 0x26014, 0x30288 },	\
 +	{  40, 0x00b03, 0x00268, 0x26014, 0x30280 },	\
 +	{  44, 0x00b03, 0x00269, 0x26014, 0x30282 },	\
 +	{  48, 0x00b03, 0x0026a, 0x26014, 0x30284 },	\
 +	{  52, 0x00b03, 0x0026b, 0x26014, 0x30286 },	\
 +	{  56, 0x00b03, 0x0026c, 0x26014, 0x30288 },	\
 +	{  60, 0x00b03, 0x0026e, 0x26014, 0x30280 },	\
 +	{  64, 0x00b03, 0x0026f, 0x26014, 0x30282 },	\
 +							\
 +	{ 100, 0x00b03, 0x0028a, 0x2e014, 0x30280 },	\
 +	{ 104, 0x00b03, 0x0028b, 0x2e014, 0x30282 },	\
 +	{ 108, 0x00b03, 0x0028c, 0x2e014, 0x30284 },	\
 +	{ 112, 0x00b03, 0x0028d, 0x2e014, 0x30286 },	\
 +	{ 116, 0x00b03, 0x0028e, 0x2e014, 0x30288 },	\
 +	{ 120, 0x00b03, 0x002a0, 0x2e014, 0x30280 },	\
 +	{ 124, 0x00b03, 0x002a1, 0x2e014, 0x30282 },	\
 +	{ 128, 0x00b03, 0x002a2, 0x2e014, 0x30284 },	\
 +	{ 132, 0x00b03, 0x002a3, 0x2e014, 0x30286 },	\
 +	{ 136, 0x00b03, 0x002a4, 0x2e014, 0x30288 },	\
 +	{ 140, 0x00b03, 0x002a6, 0x2e014, 0x30280 },	\
 +							\
 +	{ 149, 0x00b03, 0x002a8, 0x2e014, 0x30287 },	\
 +	{ 153, 0x00b03, 0x002a9, 0x2e014, 0x30289 },	\
 +	{ 157, 0x00b03, 0x002ab, 0x2e014, 0x30281 },	\
 +	{ 161, 0x00b03, 0x002ac, 0x2e014, 0x30283 },	\
 +	{ 165, 0x00b03, 0x002ad, 0x2e014, 0x30285 }
 +
 +#define RT2573_RF5225					\
 +	{   1, 0x00b33, 0x011e1, 0x1a014, 0x30282 },	\
 +	{   2, 0x00b33, 0x011e1, 0x1a014, 0x30287 },	\
 +	{   3, 0x00b33, 0x011e2, 0x1a014, 0x30282 },	\
 +	{   4, 0x00b33, 0x011e2, 0x1a014, 0x30287 },	\
 +	{   5, 0x00b33, 0x011e3, 0x1a014, 0x30282 },	\
 +	{   6, 0x00b33, 0x011e3, 0x1a014, 0x30287 },	\
 +	{   7, 0x00b33, 0x011e4, 0x1a014, 0x30282 },	\
 +	{   8, 0x00b33, 0x011e4, 0x1a014, 0x30287 },	\
 +	{   9, 0x00b33, 0x011e5, 0x1a014, 0x30282 },	\
 +	{  10, 0x00b33, 0x011e5, 0x1a014, 0x30287 },	\
 +	{  11, 0x00b33, 0x011e6, 0x1a014, 0x30282 },	\
 +	{  12, 0x00b33, 0x011e6, 0x1a014, 0x30287 },	\
 +	{  13, 0x00b33, 0x011e7, 0x1a014, 0x30282 },	\
 +	{  14, 0x00b33, 0x011e8, 0x1a014, 0x30284 },	\
 +							\
 +	{  34, 0x00b33, 0x01266, 0x26014, 0x30282 },	\
 +	{  38, 0x00b33, 0x01267, 0x26014, 0x30284 },	\
 +	{  42, 0x00b33, 0x01268, 0x26014, 0x30286 },	\
 +	{  46, 0x00b33, 0x01269, 0x26014, 0x30288 },	\
 +							\
 +	{  36, 0x00b33, 0x01266, 0x26014, 0x30288 },	\
 +	{  40, 0x00b33, 0x01268, 0x26014, 0x30280 },	\
 +	{  44, 0x00b33, 0x01269, 0x26014, 0x30282 },	\
 +	{  48, 0x00b33, 0x0126a, 0x26014, 0x30284 },	\
 +	{  52, 0x00b33, 0x0126b, 0x26014, 0x30286 },	\
 +	{  56, 0x00b33, 0x0126c, 0x26014, 0x30288 },	\
 +	{  60, 0x00b33, 0x0126e, 0x26014, 0x30280 },	\
 +	{  64, 0x00b33, 0x0126f, 0x26014, 0x30282 },	\
 +							\
 +	{ 100, 0x00b33, 0x0128a, 0x2e014, 0x30280 },	\
 +	{ 104, 0x00b33, 0x0128b, 0x2e014, 0x30282 },	\
 +	{ 108, 0x00b33, 0x0128c, 0x2e014, 0x30284 },	\
 +	{ 112, 0x00b33, 0x0128d, 0x2e014, 0x30286 },	\
 +	{ 116, 0x00b33, 0x0128e, 0x2e014, 0x30288 },	\
 +	{ 120, 0x00b33, 0x012a0, 0x2e014, 0x30280 },	\
 +	{ 124, 0x00b33, 0x012a1, 0x2e014, 0x30282 },	\
 +	{ 128, 0x00b33, 0x012a2, 0x2e014, 0x30284 },	\
 +	{ 132, 0x00b33, 0x012a3, 0x2e014, 0x30286 },	\
 +	{ 136, 0x00b33, 0x012a4, 0x2e014, 0x30288 },	\
 +	{ 140, 0x00b33, 0x012a6, 0x2e014, 0x30280 },	\
 +							\
 +	{ 149, 0x00b33, 0x012a8, 0x2e014, 0x30287 },	\
 +	{ 153, 0x00b33, 0x012a9, 0x2e014, 0x30289 },	\
 +	{ 157, 0x00b33, 0x012ab, 0x2e014, 0x30281 },	\
 +	{ 161, 0x00b33, 0x012ac, 0x2e014, 0x30283 },	\
 +	{ 165, 0x00b33, 0x012ad, 0x2e014, 0x30285 }
 Index: sys/dev/usb/if_rumvar.h
 ===================================================================
 RCS file: sys/dev/usb/if_rumvar.h
 diff -N sys/dev/usb/if_rumvar.h
 --- /dev/null	1 Jan 1970 00:00:00 -0000
 +++ sys/dev/usb/if_rumvar.h	1 Feb 2007 11:26:03 -0000
 @@ -0,0 +1,158 @@
 +/*	$OpenBSD: if_rumvar.h,v 1.6 2006/08/18 15:11:12 damien Exp $	*/
 +
 +/*-
 + * Copyright (c) 2005, 2006 Damien Bergamini <damien.bergamini at free.fr>
 + * Copyright (c) 2006 Niall O'Higgins <niallo at openbsd.org>
 + * Copyright (c) 2006, 2007 Valery V.Chikalov <valera at chikalov.dp.ua>
 + *
 + * Permission to use, copy, modify, and distribute this software for any
 + * purpose with or without fee is hereby granted, provided that the above
 + * copyright notice and this permission notice appear in all copies.
 + *
 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 + */
 +
 +#define RT2573_RX_LIST_COUNT	1
 +#define RT2573_TX_LIST_COUNT	1
 +
 +struct rum_rx_radiotap_header {
 +	struct ieee80211_radiotap_header wr_ihdr;
 +	uint8_t		wr_flags;
 +	uint8_t		wr_rate;
 +	uint16_t	wr_chan_freq;
 +	uint16_t	wr_chan_flags;
 +	uint8_t		wr_antenna;
 +	uint8_t		wr_antsignal;
 +} __packed;
 +
 +#define RT2573_RX_RADIOTAP_PRESENT					\
 +	((1 << IEEE80211_RADIOTAP_FLAGS) |				\
 +	 (1 << IEEE80211_RADIOTAP_RATE) |				\
 +	 (1 << IEEE80211_RADIOTAP_CHANNEL) |				\
 +	 (1 << IEEE80211_RADIOTAP_ANTENNA) |				\
 +	 (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL))
 +
 +struct rum_tx_radiotap_header {
 +	struct ieee80211_radiotap_header wt_ihdr;
 +	uint8_t		wt_flags;
 +	uint8_t		wt_rate;
 +	uint16_t	wt_chan_freq;
 +	uint16_t	wt_chan_flags;
 +	uint8_t		wt_antenna;
 +} __packed;
 +
 +#define RT2573_TX_RADIOTAP_PRESENT						\
 +	((1 << IEEE80211_RADIOTAP_FLAGS) |				\
 +	 (1 << IEEE80211_RADIOTAP_RATE) |				\
 +	 (1 << IEEE80211_RADIOTAP_CHANNEL) |				\
 +	 (1 << IEEE80211_RADIOTAP_ANTENNA))
 +
 +struct rum_softc;
 +
 +struct rum_tx_data {
 +	struct rum_softc	*sc;
 +	usbd_xfer_handle	xfer;
 +	uint8_t			*buf;
 +	struct mbuf		*m;
 +	struct ieee80211_node	*ni;
 +};
 +
 +struct rum_rx_data {
 +	struct rum_softc	*sc;
 +	usbd_xfer_handle	xfer;
 +	uint8_t			*buf;
 +	struct mbuf		*m;
 +};
 +
 +struct rum_amrr {
 +    int txcnt;
 +    int retrycnt;
 +    int success;
 +    int success_threshold;
 +    int recovery;
 +};
 +
 +struct rum_softc {
 +	device_t			    sc_dev;
 +	struct ifnet           *sc_ifp;
 +	struct ieee80211com		sc_ic;
 +	int				(*sc_newstate)(struct ieee80211com *,
 +					    enum ieee80211_state, int);
 +
 +	usbd_device_handle		sc_udev;
 +	usbd_interface_handle		sc_iface;
 +	int				sc_flags;
 +#define	RT2573_FWLOADED	(1 << 0)
 +
 +	struct ieee80211_channel	*sc_curchan;
 +
 +	int				sc_rx_no;
 +	int				sc_tx_no;
 +
 +	uint16_t			macbbp_rev;
 +	uint8_t				rf_rev;
 +	uint8_t				rffreq;
 +
 +	usbd_xfer_handle		amrr_xfer;
 +
 +	usbd_pipe_handle		sc_rx_pipeh;
 +	usbd_pipe_handle		sc_tx_pipeh;
 +
 +	enum ieee80211_state		sc_state;
 +	struct usb_task			sc_task;
 +
 +	struct rum_amrr        amrr;
 +
 +	struct rum_rx_data		rx_data[RT2573_RX_LIST_COUNT];
 +	struct rum_tx_data		tx_data[RT2573_TX_LIST_COUNT];
 +	int				tx_queued;
 +
 +	struct ieee80211_beacon_offsets	sc_bo;
 +
 +	struct callout			scan_ch;
 +	struct callout			amrr_ch;
 +
 +	int				sc_tx_timer;
 +
 +	uint32_t			sta[6];
 +	uint32_t			rf_regs[4];
 +	uint8_t				txpow[44];
 +
 +	struct {
 +		uint8_t	val;
 +		uint8_t	reg;
 +	} __packed			bbp_prom[16];
 +
 +	int				hw_radio;
 +	int				rx_ant;
 +	int				tx_ant;
 +	int				nb_ant;
 +	int				ext_2ghz_lna;
 +	int				ext_5ghz_lna;
 +	int				rssi_2ghz_corr;
 +	int				rssi_5ghz_corr;
 +	int				sifs;
 +	uint8_t				bbp17;
 +
 +	struct bpf_if      *sc_drvbpf;
 +
 +	union {
 +		struct rum_rx_radiotap_header th;
 +		uint8_t	pad[64];
 +	}				sc_rxtapu;
 +#define sc_rxtap	sc_rxtapu.th
 +	int				sc_rxtap_len;
 +
 +	union {
 +		struct rum_tx_radiotap_header th;
 +		uint8_t	pad[64];
 +	}				sc_txtapu;
 +#define sc_txtap	sc_txtapu.th
 +	int				sc_txtap_len;
 +};
 Index: sys/dev/usb/usbdevs
 ===================================================================
 RCS file: /home/ncvs/src/sys/dev/usb/usbdevs,v
 retrieving revision 1.285
 diff -u -r1.285 usbdevs
 --- sys/dev/usb/usbdevs	28 Jan 2007 10:46:32 -0000	1.285
 +++ sys/dev/usb/usbdevs	1 Feb 2007 11:26:05 -0000
 @@ -1,4 +1,4 @@
 -$FreeBSD: src/sys/dev/usb/usbdevs,v 1.285 2007/01/28 10:46:32 takawata Exp $
 +$FreeBSD: src/sys/dev/usb/usbdevs,v 1.232.2.16 2006/08/20 05:20:07 imp Exp $
  /* $NetBSD: usbdevs,v 1.392 2004/12/29 08:38:44 imp Exp $ */
  
  /*-
 @@ -355,6 +355,7 @@
  vendor DIGITALSTREAM	0x074e	Digital Stream
  vendor AUREAL		0x0755	Aureal
  vendor MIDIMAN		0x0763	Midiman
 +vendor SURECOM		0x0769	Surecom Technology
  vendor LINKSYS2		0x077b	Linksys
  vendor GRIFFIN		0x077d	Griffin
  vendor SANDISK		0x0781	SanDisk
 @@ -383,6 +384,7 @@
  vendor AVERMEDIA	0x07ca	AVerMedia
  vendor SIIG		0x07cc	SIIG
  vendor CASIO		0x07cf	CASIO
 +vendor DLINK2		0x07d1	D-Link
  vendor APTIO		0x07d2	Aptio
  vendor ARASAN		0x07da	Arasan
  vendor ALLIEDCABLE	0x07e6	Allied Cable
 @@ -486,6 +488,7 @@
  vendor ACDC		0x0d7e	ACDC
  vendor ABC		0x0d8c	ABC
  vendor CONCEPTRONIC	0x0d8e	Conceptronic
 +vendor SITECOMEU    0x0df6  Sitecom Europe
  vendor MSI		0x0db0	Micro Star International
  vendor HAWKING		0x0e66	Hawking
  vendor GMATE		0x0e7e	G.Mate, Inc
 @@ -515,9 +518,11 @@
  vendor BELKIN2		0x1293	Belkin
  vendor AINCOMM		0x12fd	Aincomm
  vendor MOBILITY		0x1342	Mobility
 +vendor DICKSMITH	0x1371	Dick Smith Electronics
  vendor LINKSYS4		0x13b1	Linksys
  vendor SHARK		0x13d2	Shark
  vendor RADIOSHACK	0x1453	Radio Shack
 +vendor HUAWEI3COM	0x1472	Huawei 3Com
  vendor SILICOM		0x1485	Silicom
  vendor RALINK		0x148f	Ralink Technology
  vendor IMAGINATION	0x149a	Imagination Technologies
 @@ -527,14 +532,17 @@
  vendor SOHOWARE		0x15e8	SOHOware
  vendor UMAX		0x1606	UMAX
  vendor INSIDEOUT	0x1608	Inside Out Networks
 +vendor GOODWAY      0x1631  Good Way Technology
  vendor ENTREGA		0x1645	Entrega
  vendor ACTIONTEC	0x1668	Actiontec
  vendor ATHEROS		0x168c	Atheros Communications
  vendor GIGASET		0x1690	Gigaset
  vendor GLOBALSUN	0x16ab	Global Sun Technology
  vendor CMOTECH		0x16d8	CMOTECH CO., LTD.
 +vendor QCOM         0x18e8  Qcom
  vendor LINKSYS3		0x1915	Linksys
  vendor DLINK		0x2001	D-Link
 +vendor PLANEX2      0x2019  Planex Communications
  vendor ERICSSON		0x2282	Ericsson
  vendor MOTOROLA2	0x22b8	Motorola
  vendor TRIPPLITE	0x2478	Tripp-Lite
 @@ -555,7 +563,7 @@
  vendor ONSPEC2		0x55aa	OnSpec
  vendor ZINWELL		0x5a57	Zinwell
  vendor SITECOM		0x6189	Sitecom
 -vendor ARKMICRO		0x6547	Arkmicro Technologies
 +vendor ARKMICRO     0x6547  Arkmicro Technologies
  vendor INTEL		0x8086	Intel
  vendor HP2		0xf003	Hewlett Packard
  
 @@ -590,6 +598,7 @@
  product ABOCOM XX8		0x4102	XX8
  product ABOCOM XX9		0x4104	XX9
  product ABOCOM XX10		0xabc1	XX10
 +product ABOCOM RT2573	0xb21d	RT2573
  
  /* Accton products */
  product ACCTON USB320_EC	0x1046	USB320-EC Ethernet
 @@ -688,7 +697,7 @@
  product APPLE IPODNANO		0x120a	iPod Nano
  
  /* Arkmicro Technologies */
 -product ARKMICRO ARK3116	0x0232	ARK3116 Serial
 +product ARKMICRO ARK3116      0x0232  ARK3116 Serial
  
  /* Asahi Optical products */
  product ASAHIOPTICAL OPTIO230	0x0004	Digital camera
 @@ -699,6 +708,7 @@
  
  /* ASUS products */
  product ASUS WL167G		0x1707	WL-167g wireless adapter
 +product ASUS RT2573		0x1723	RT2573
  
  /* ATen products */
  product ATEN UC1284		0x2001	Parallel printer
 @@ -736,9 +746,12 @@
  product BELKIN F5U109		0x0109	F5U109 Serial
  product BELKIN F5U208		0x0208	F5U208 VideoBus II
  product BELKIN F5U409		0x0409	F5U409 Serial
 -product BELKIN F6C550AVR	0x0551	F6C550-AVR UPS
 +product BELKIN F6C550AVR    0x0551  F6C550-AVR UPS
  product BELKIN F5U120		0x1203	F5U120-PC Hub
  product BELKIN F5D7050		0x7050	F5D7050 wireless adapter
 +product BELKIN F5D7050A		0x705a	F5D705A 54g USB Network Adapter
 +product BELKIN F5D9050V3	0x905b	F5D9050 ver 3
 +
  
  /* Billionton products */
  product BILLIONTON USB100	0x0986	USB100N 10/100 FastEthernet
 @@ -838,7 +851,7 @@
  /* Cypress Semiconductor products */
  product CYPRESS MOUSE		0x0001	mouse
  product CYPRESS THERMO		0x0002	thermometer
 -product CYPRESS WISPY		0x0bad	MetaGeek Wi-Spy
 +product CYPRESS WISPY         0x0bad  MetaGeek Wi-Spy
  product CYPRESS FMRADIO		0x1002	FM Radio
  product CYPRESS SLIM_HUB	0x6560	Slim Hub
  
 @@ -859,6 +872,10 @@
  /* Diamond products */
  product DIAMOND RIO500USB	0x0001	Rio 500 USB
  
 +/* Dick Smith Electronics (really C-Net) products */
 +product DICKSMITH RT2573	0x9022	RT2573
 +product DICKSMITH CWD854F	0x9032	C-Net CWD-854 rev F
 +
  /* Digi International products */
  product DIGI ACCELEPORT2	0x0002	AccelePort USB 2
  product DIGI ACCELEPORT4	0x0004	AccelePort USB 4
 @@ -884,6 +901,8 @@
  product DLINK DSB650TX3		0x400b	10/100 ethernet
  product DLINK DSB650TX2		0x4102	10/100 ethernet
  product DLINK DSB650		0xabc1	10/100 ethernet
 +product DLINK2 DWLG122C1	0x3c03	DWL-G122 rev C1
 +product DLINK2 WUA1340		0x3c04	WUA-1340
  
  /* EIZO products */
  product EIZO HUB		0x0000	hub
 @@ -941,11 +960,11 @@
  product EPSON 1670		0x011f	Perfection 1670 scanner
  product EPSON 1270		0x0120	Perfection 1270 scanner
  product EPSON 2480		0x0121  Perfection 2480 scanner
 -product EPSON 3590		0x0122	Perfection 3590 scanner
 -product EPSON 4990		0x012a	Perfection 4990 Photo scanner
 +product EPSON 3590            0x0122  Perfection 3590 scanner
 +product EPSON 4990            0x012a  Perfection 4990 Photo scanner
  product EPSON 3500		0x080e	CX-3500/3600/3650 MFP
  product EPSON RX425		0x080f	Stylus Photo RX425 scanner
 -product EPSON 4200		0x0820  CX4200 MP scanner
 +product EPSON 4200            0x0820  CX4200 MP scanner
  
  /* e-TEK Labs products */
  product ETEK 1COM		0x8007	Serial
 @@ -993,6 +1012,7 @@
  product GIGABYTE GNBR402W	0x8002	GN-BR402W
  product GIGABYTE GNWLBM101	0x8003	GN-WLBM101
  product GIGABYTE GNWBKG		0x8007	GN-WBKG
 +product GIGABYTE GNWB01GS   0x8008  GN-WB01GS
  
  /* Gigaset products */
  product GIGASET WLAN		0x0701	WLAN
 @@ -1083,6 +1103,12 @@
  /* HP products */
  product HP2 C500		0x6002	PhotoSmart C500
  
 +/* HUAWEI products */
 +product HUAWEI3COM RT2573	0x0009	RT2573
 +
 +/* Good Way Technology products */
 +product GOODWAY RT2573      0xc019  RT2573
 +
  /* IBM Corporation */
  product IBM USBCDROMDRIVE	0x4427	USB CD-ROM Drive
  
 @@ -1226,6 +1252,7 @@
  product LINKSYS4 WUSB54G	0x000d	WUSB54G wireless adapter
  product LINKSYS4 WUSB54GP	0x0011	WUSB54GP wireless adapter
  product LINKSYS4 HU200TS	0x001a	HU200TS wireless adapter
 +product LINKSYS4 WUSB54GC	0x0020	WUSB54GC
  
  /* Logitech products */
  product LOGITECH M2452		0x0203	M2452 keyboard
 @@ -1241,11 +1268,11 @@
  product LOGITECH WMMOUSE	0xc004	WingMan Gaming Mouse
  product LOGITECH BD58		0xc00c	BD58 mouse
  product LOGITECH UN58A		0xc030	iFeel Mouse
 -product LOGITECH UN53B		0xc032	iFeel MouseMan
 +product LOGITECH UN53B      0xc032  iFeel MouseMan
  product LOGITECH WMPAD		0xc208	WingMan GamePad Extreme
  product LOGITECH WMRPAD		0xc20a	WingMan RumblePad
  product LOGITECH WMJOY		0xc281	WingMan Force joystick
 -product LOGITECH BB13		0xc401	USB-PS/2 Trackball
 +product LOGITECH BB13       0xc401  USB-PS/2 Trackball
  product LOGITECH RK53		0xc501	Cordless mouse
  product LOGITECH RB6		0xc503	Cordless keyboard
  product LOGITECH MX700		0xc506	Cordless optical mouse
 @@ -1301,6 +1328,9 @@
  product MSI RT2570		0x6861	RT2570
  product MSI RT2570_2		0x6865	RT2570
  product MSI RT2570_3		0x6869	RT2570
 +product MSI RT2573		0x6877	RT2573
 +product MSI RT2573_2		0xa861	RT2573
 +product MSI RT2573_3		0xa874	RT2573
  
  /* Microsoft products */
  product MICROSOFT SIDEPREC	0x0008	SideWinder Precision Pro
 @@ -1387,7 +1417,7 @@
  
  /* Netgear products */
  product NETGEAR EA101		0x1001	Ethernet
 -product NETGEAR FA101		0x1020	Ethernet 10/100, USB1.1
 +product NETGEAR FA101         0x1020  Ethernet 10/100, USB1.1
  product NETGEAR FA120		0x1040	USB 2.0 Ethernet
  product NETGEAR3 WG111T		0x4250	WG111T
  product NETGEAR3 WG111T_NF	0x4251	WG111T (no firmware)
 @@ -1401,7 +1431,7 @@
  product NIKON LS40		0x4000	CoolScan LS40 ED
  
  /* NovaTech Products */
 -product NOVATECH NV902		0x9020  NovaTech NV-902W
 +product NOVATECH NV902                0x9020  NovaTech NV-902W
  
  /* Olympus products */
  product OLYMPUS C1		0x0102	C-1 Digital Camera
 @@ -1428,7 +1458,7 @@
  product PALM ZIRE		0x0070	Palm Zire
  
  /* Panasonic products */
 -product PANASONIC KXL840AN	0x0d01	CD-R Drive KXL-840AN
 +product PANASONIC KXL840AN    0x0d01  CD-R Drive KXL-840AN
  product PANASONIC KXLRW32AN	0x0d09	CD-R Drive KXL-RW32AN
  product PANASONIC KXLCB20AN	0x0d0a	CD-R Drive KXL-CB20AN
  product PANASONIC KXLCB35AN	0x0d0e	DVD-ROM & CD-R/RW
 @@ -1456,6 +1486,10 @@
  /* P.I. Engineering products */
  product PIENGINEERING PS2USB	0x020b	PS2 to Mac USB Adapter
  
 +/* Planex Communications products */
 +product PLANEX2 GWUSMM		0xed02	GW-USMM
 +
 +
  /* Plextor Corp. */
  product PLEXTOR 40_12_40U	0x0011	PlexWriter 40/12/40U
  
 @@ -1498,6 +1532,10 @@
  /* Putercom products */
  product PUTERCOM UPA100		0x047e	USB-1284 BRIDGE
  
 +/* Qcom products */
 +product QCOM RT2573		0x6196	RT2573
 +product QCOM RT2573_2		0x6229	RT2573
 +
  /* Qualcomm products */
  product QUALCOMM CDMA_MSM	0x3196	CDMA Technologies MSM modem
  product QUALCOMM2 CDMA_MSM	0x6000	CDMA Technologies MSM phone
 @@ -1517,6 +1555,8 @@
  /* Ralink Technology products */
  product RALINK RT2570		0x1706	RT2500USB wireless adapter
  product RALINK RT2570_2		0x2570	RT2500USB wireless adapter
 +product RALINK RT2573		0x2573	RT2573
 +product RALINK RT2671		0x2671	RT2671
  
  /* ReakTek products */
  product REALTEK USBKR100	0x8150	USBKR100 USB Ethernet (GREEN HOUSE)
 @@ -1589,7 +1629,7 @@
  product SIIG2 US2308		0x0421	Serial
  
  /* Silicom products */
 -product SILICOM GPE		0x0002	Psion Gold Port Ethernet
 +product SILICOM GPE           0x0002  Psion Gold Port Ethernet
  
  /* Silicon Portals Inc. */
  product SILICONPORTALS YAPPH_NF	0x0200	YAP Phone (no firmware)
 @@ -1602,6 +1642,11 @@
  product SITECOM LN029		0x182d	USB 2.0 Ethernet
  product SITECOM SERIAL		0x2068	USB to serial cable (v2)
  
 +/* Sitecom Europe products */
 +product SITECOMEU WL172		0x90ac	WL-172
 +product SITECOMEU WL113R2	0x9712	WL-113 rev 2
 +
 +
  /* SmartBridges products */
  product SMARTBRIDGES SMARTLINK	0x0001	SmartLink USB ethernet
  product SMARTBRIDGES SMARTNIC	0x0003	smartNIC 2 PnP ethernet
 @@ -1667,6 +1712,9 @@
  product DIAMOND2 RIO600USB	0x5001	Rio 600 USB
  product DIAMOND2 RIO800USB	0x5002	Rio 800 USB
  
 +/* Surecom Technology products */
 +product SURECOM RT2573		0x31f3	RT2573
 +
  /* System TALKS, Inc. */
  product SYSTEMTALKS SGCX2UL	0x1920	SGC-X2UL
  
 Index: sys/modules/rt2573/Makefile
 ===================================================================
 RCS file: sys/modules/rt2573/Makefile
 diff -N sys/modules/rt2573/Makefile
 --- /dev/null	1 Jan 1970 00:00:00 -0000
 +++ sys/modules/rt2573/Makefile	1 Feb 2007 11:26:11 -0000
 @@ -0,0 +1,3 @@
 +KMOD= rt2573
 +FIRMWS= rum-rt2573:rt2573:100
 +.include <bsd.kmod.mk>
 Index: sys/modules/rum/Makefile
 ===================================================================
 RCS file: sys/modules/rum/Makefile
 diff -N sys/modules/rum/Makefile
 --- /dev/null	1 Jan 1970 00:00:00 -0000
 +++ sys/modules/rum/Makefile	1 Feb 2007 11:26:11 -0000
 @@ -0,0 +1,8 @@
 +# $FreeBSD: src/sys/modules/ural/Makefile,v 1.1 2005/04/18 18:47:38 damien Exp $
 +
 +.PATH: ${.CURDIR}/../../dev/usb
 +
 +KMOD    = if_rum
 +SRCS    = if_rum.c opt_bdg.h opt_usb.h device_if.h bus_if.h usbdevs.h
 +
 +.include <bsd.kmod.mk>
 
 --------------070401030006070808060902--


More information about the freebsd-usb mailing list