Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 16 Dec 2013 08:10:39 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r259453 - in stable/10: share/man/man4 sys/dev/usb sys/dev/usb/wlan
Message-ID:  <201312160810.rBG8Adg4030099@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Mon Dec 16 08:10:38 2013
New Revision: 259453
URL: http://svnweb.freebsd.org/changeset/base/259453

Log:
  MFC r238274, r246752, r256720, r256721, r256722, r256955, r257409
   r257429, r257435, r257712, r257732, r257743, r257748, r257955
   r257957, r257958, r258082, r258641, r258643, r258732, r258733,
   r258840, r258919, r258921, r259029, r259030, r259031, r259032 and r259046:
  
  - Add support for the MediaTek/Ralink RT5370/RT5372 chipset.
  - Various minor USB WLAN fixes and improvements.
  
  PR:     usb/182936

Modified:
  stable/10/share/man/man4/run.4
  stable/10/share/man/man4/runfw.4
  stable/10/sys/dev/usb/usbdevs
  stable/10/sys/dev/usb/wlan/if_rsu.c
  stable/10/sys/dev/usb/wlan/if_rum.c
  stable/10/sys/dev/usb/wlan/if_run.c
  stable/10/sys/dev/usb/wlan/if_runreg.h
  stable/10/sys/dev/usb/wlan/if_runvar.h
  stable/10/sys/dev/usb/wlan/if_uath.c
  stable/10/sys/dev/usb/wlan/if_upgt.c
  stable/10/sys/dev/usb/wlan/if_ural.c
  stable/10/sys/dev/usb/wlan/if_urtw.c
  stable/10/sys/dev/usb/wlan/if_urtwn.c
  stable/10/sys/dev/usb/wlan/if_zyd.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/share/man/man4/run.4
==============================================================================
--- stable/10/share/man/man4/run.4	Mon Dec 16 06:56:38 2013	(r259452)
+++ stable/10/share/man/man4/run.4	Mon Dec 16 08:10:38 2013	(r259453)
@@ -16,7 +16,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd July 9, 2012
+.Dd November 11, 2013
 .Dt RUN 4
 .Os
 .Sh NAME
@@ -52,7 +52,7 @@ runfw_load="YES"
 The
 .Nm
 driver supports USB 2.0 wireless adapters based on the Ralink RT2700U,
-RT2800U and RT3000U chipsets.
+RT2800U, RT3000U and RT3900E chipsets.
 .Pp
 The RT2700U chipset consists of two integrated chips, an RT2770 MAC/BBP and
 an RT2720 (1T2R) or RT2750 (dual-band 1T2R) radio transceiver.
@@ -64,6 +64,9 @@ The RT3000U is a single-chip solution ba
 an RT3020 (1T1R), RT3021 (1T2R) or RT3022 (2T2R) single-band radio
 transceiver.
 .Pp
+The RT3900E is a single-chip solution based on an RT5390 MAC/BBP and
+an RT5370 (1T1R) or RT5372 (2T2R) single-band radio transceiver.
+.Pp
 These are the modes the
 .Nm
 driver can operate in:
@@ -129,7 +132,8 @@ driver supports the following wireless a
 .It Corega CG-WLUSB300AGN
 .It Corega CG-WLUSB300GNM
 .It D-Link DWA-130 rev B1
-.It D-Link DWA-140 rev B1, B2
+.It D-Link DWA-140 rev B1, B2, B3
+.It D-Link DWA-160 rev B2
 .It DrayTek Vigor N61
 .It Edimax EW-7711UAn
 .It Edimax EW-7711UTn
@@ -156,6 +160,8 @@ driver supports the following wireless a
 .It SMC SMCWUSBS-N2
 .It Sweex LW303
 .It Sweex LW313
+.It TP-LINK TL-WDN3200
+.It TP-LINK TL-WN727N v3
 .It Unex DNUR-81
 .It Unex DNUR-82
 .It ZyXEL NWD210N

Modified: stable/10/share/man/man4/runfw.4
==============================================================================
--- stable/10/share/man/man4/runfw.4	Mon Dec 16 06:56:38 2013	(r259452)
+++ stable/10/share/man/man4/runfw.4	Mon Dec 16 08:10:38 2013	(r259453)
@@ -18,7 +18,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 12, 2011
+.Dd November 11, 2013
 .Dt RUNFW 4
 .Os
 .Sh NAME
@@ -43,7 +43,7 @@ runfw_load="YES"
 .Ed
 .Sh DESCRIPTION
 This module provides firmware sets for the Ralink RT2700U,
-RT2800U and RT3000U chip based USB WiFi adapters.
+RT2800U, RT3000U and RT3900E chip based USB WiFi adapters.
 Please read Ralink's license, src/sys/contrib/dev/run/LICENSE.
 .Sh SEE ALSO
 .Xr run 4 ,

Modified: stable/10/sys/dev/usb/usbdevs
==============================================================================
--- stable/10/sys/dev/usb/usbdevs	Mon Dec 16 06:56:38 2013	(r259452)
+++ stable/10/sys/dev/usb/usbdevs	Mon Dec 16 08:10:38 2013	(r259453)
@@ -1549,6 +1549,8 @@ product DLINK DWLG122		0x3c00	DWL-G122 b
 product DLINK DUBE100B1		0x3c05	DUB-E100 rev B1
 product DLINK RT2870		0x3c09	RT2870
 product DLINK RT3072		0x3c0a	RT3072
+product DLINK DWA140B3		0x3c15	DWA-140 rev B3
+product DLINK DWA160B2		0x3c1a	DWA-160 rev B2
 product DLINK DWA127		0x3c1b	DWA-127 Wireless Adapter
 product DLINK DSB650C		0x4000	10Mbps Ethernet
 product DLINK DSB650TX1		0x4001	10/100 Ethernet
@@ -3572,6 +3574,7 @@ product RALINK RT3072		0x3072	RT3072
 product RALINK RT3370		0x3370	RT3370
 product RALINK RT3572		0x3572	RT3572
 product RALINK RT5370		0x5370	RT5370
+product RALINK RT5572		0x5572	RT5572
 product RALINK RT8070		0x8070	RT8070
 product RALINK RT2570_3		0x9020	RT2500USB Wireless Adapter
 product RALINK RT2573_2		0x9021	RT2501USB Wireless Adapter

Modified: stable/10/sys/dev/usb/wlan/if_rsu.c
==============================================================================
--- stable/10/sys/dev/usb/wlan/if_rsu.c	Mon Dec 16 06:56:38 2013	(r259452)
+++ stable/10/sys/dev/usb/wlan/if_rsu.c	Mon Dec 16 08:10:38 2013	(r259453)
@@ -480,8 +480,13 @@ rsu_vap_create(struct ieee80211com *ic, 
 	if (uvp == NULL)
 		return (NULL);
 	vap = &uvp->vap;
-	ieee80211_vap_setup(ic, vap, name, unit, opmode,
-	    flags, bssid, mac);
+
+	if (ieee80211_vap_setup(ic, vap, name, unit, opmode,
+	    flags, bssid, mac) != 0) {
+		/* out of memory */
+		free(uvp, M_80211_VAP);
+		return (NULL);
+	}
 
 	/* override state transition machine */
 	uvp->newstate = vap->iv_newstate;
@@ -1153,7 +1158,7 @@ rsu_event_survey(struct rsu_softc *sc, u
 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
 	    IEEE80211_FC0_SUBTYPE_BEACON;
 	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
-	*(uint16_t *)wh->i_dur = 0;
+	USETW(wh->i_dur, 0);
 	IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr);
 	IEEE80211_ADDR_COPY(wh->i_addr2, bss->macaddr);
 	IEEE80211_ADDR_COPY(wh->i_addr3, bss->macaddr);

Modified: stable/10/sys/dev/usb/wlan/if_rum.c
==============================================================================
--- stable/10/sys/dev/usb/wlan/if_rum.c	Mon Dec 16 06:56:38 2013	(r259452)
+++ stable/10/sys/dev/usb/wlan/if_rum.c	Mon Dec 16 08:10:38 2013	(r259453)
@@ -604,8 +604,13 @@ rum_vap_create(struct ieee80211com *ic, 
 		return NULL;
 	vap = &rvp->vap;
 	/* enable s/w bmiss handling for sta mode */
-	ieee80211_vap_setup(ic, vap, name, unit, opmode,
-	    flags | IEEE80211_CLONE_NOBEACONS, bssid, mac);
+
+	if (ieee80211_vap_setup(ic, vap, name, unit, opmode,
+	    flags | IEEE80211_CLONE_NOBEACONS, bssid, mac) != 0) {
+		/* out of memory */
+		free(rvp, M_80211_VAP);
+		return (NULL);
+	}
 
 	/* override state transition machine */
 	rvp->newstate = vap->iv_newstate;
@@ -1131,7 +1136,7 @@ rum_tx_mgt(struct rum_softc *sc, struct 
 
 		dur = ieee80211_ack_duration(ic->ic_rt, tp->mgmtrate, 
 		    ic->ic_flags & IEEE80211_F_SHPREAMBLE);
-		*(uint16_t *)wh->i_dur = htole16(dur);
+		USETW(wh->i_dur, dur);
 
 		/* tell hardware to add timestamp for probe responses */
 		if ((wh->i_fc[0] &
@@ -1275,7 +1280,7 @@ rum_tx_data(struct rum_softc *sc, struct
 
 		dur = ieee80211_ack_duration(ic->ic_rt, rate, 
 		    ic->ic_flags & IEEE80211_F_SHPREAMBLE);
-		*(uint16_t *)wh->i_dur = htole16(dur);
+		USETW(wh->i_dur, dur);
 	}
 
 	rum_setup_tx_desc(sc, &data->desc, flags, 0, m0->m_pkthdr.len, rate);

Modified: stable/10/sys/dev/usb/wlan/if_run.c
==============================================================================
--- stable/10/sys/dev/usb/wlan/if_run.c	Mon Dec 16 06:56:38 2013	(r259452)
+++ stable/10/sys/dev/usb/wlan/if_run.c	Mon Dec 16 08:10:38 2013	(r259453)
@@ -2,6 +2,7 @@
  * Copyright (c) 2008,2010 Damien Bergamini <damien.bergamini@free.fr>
  * ported to FreeBSD by Akinori Furukoshi <moonlightakkiy@yahoo.ca>
  * USB Consulting, Hans Petter Selasky <hselasky@freebsd.org>
+ * Copyright (c) 2013 Kevin Lo
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -20,7 +21,7 @@
 __FBSDID("$FreeBSD$");
 
 /*-
- * Ralink Technology RT2700U/RT2800U/RT3000U chipset driver.
+ * Ralink Technology RT2700U/RT2800U/RT3000U/RT3900E chipset driver.
  * http://www.ralinktech.com/
  */
 
@@ -74,8 +75,6 @@ __FBSDID("$FreeBSD$");
 #include <dev/usb/wlan/if_runreg.h>
 #include <dev/usb/wlan/if_runvar.h>
 
-#define	N(_a) ((int)(sizeof((_a)) / sizeof((_a)[0])))
-
 #ifdef	USB_DEBUG
 #define RUN_DEBUG
 #endif
@@ -173,6 +172,8 @@ static const STRUCT_USB_HOST_ID run_devs
     RUN_DEV(DLINK,		RT2870),
     RUN_DEV(DLINK,		RT3072),
     RUN_DEV(DLINK,		DWA127),
+    RUN_DEV(DLINK,		DWA140B3),
+    RUN_DEV(DLINK,		DWA160B2),
     RUN_DEV(DLINK2,		DWA130),
     RUN_DEV(DLINK2,		RT2870_1),
     RUN_DEV(DLINK2,		RT2870_2),
@@ -256,6 +257,8 @@ static const STRUCT_USB_HOST_ID run_devs
     RUN_DEV(RALINK,		RT3072),
     RUN_DEV(RALINK,		RT3370),
     RUN_DEV(RALINK,		RT3572),
+    RUN_DEV(RALINK,		RT5370),
+    RUN_DEV(RALINK,		RT5572),
     RUN_DEV(RALINK,		RT8070),
     RUN_DEV(SAMSUNG,		WIS09ABGN),
     RUN_DEV(SAMSUNG2,		RT2870_1),
@@ -319,7 +322,7 @@ static usb_callback_t	run_bulk_tx_callba
 static usb_callback_t	run_bulk_tx_callback5;
 
 static void	run_bulk_tx_callbackN(struct usb_xfer *xfer,
-		    usb_error_t error, unsigned int index);
+		    usb_error_t error, u_int index);
 static struct ieee80211vap *run_vap_create(struct ieee80211com *,
 		    const char [IFNAMSIZ], int, enum ieee80211_opmode, int,
 		    const uint8_t [IEEE80211_ADDR_LEN],
@@ -343,13 +346,13 @@ static int	run_write_region_1(struct run
 static int	run_set_region_4(struct run_softc *, uint16_t, uint32_t, int);
 static int	run_efuse_read_2(struct run_softc *, uint16_t, uint16_t *);
 static int	run_eeprom_read_2(struct run_softc *, uint16_t, uint16_t *);
-static int	run_rt2870_rf_write(struct run_softc *, uint8_t, uint32_t);
+static int	run_rt2870_rf_write(struct run_softc *, uint32_t);
 static int	run_rt3070_rf_read(struct run_softc *, uint8_t, uint8_t *);
 static int	run_rt3070_rf_write(struct run_softc *, uint8_t, uint8_t);
 static int	run_bbp_read(struct run_softc *, uint8_t, uint8_t *);
 static int	run_bbp_write(struct run_softc *, uint8_t, uint8_t);
 static int	run_mcu_cmd(struct run_softc *, uint8_t, uint16_t);
-static const char *run_get_rf(int);
+static const char *run_get_rf(uint16_t);
 static int	run_read_eeprom(struct run_softc *);
 static struct ieee80211_node *run_node_alloc(struct ieee80211vap *,
 			    const uint8_t mac[IEEE80211_ADDR_LEN]);
@@ -361,7 +364,7 @@ static void	run_key_update_begin(struct 
 static void	run_key_update_end(struct ieee80211vap *);
 static void	run_key_set_cb(void *);
 static int	run_key_set(struct ieee80211vap *, struct ieee80211_key *,
-			    const uint8_t mac[IEEE80211_ADDR_LEN]);
+		    const uint8_t mac[IEEE80211_ADDR_LEN]);
 static void	run_key_delete_cb(void *);
 static int	run_key_delete(struct ieee80211vap *, struct ieee80211_key *);
 static void	run_ratectl_to(void *);
@@ -393,6 +396,8 @@ static void	run_set_rx_antenna(struct ru
 static void	run_rt2870_set_chan(struct run_softc *, u_int);
 static void	run_rt3070_set_chan(struct run_softc *, u_int);
 static void	run_rt3572_set_chan(struct run_softc *, u_int);
+static void	run_rt5390_set_chan(struct run_softc *, u_int);
+static void	run_rt5592_set_chan(struct run_softc *, u_int);
 static int	run_set_chan(struct run_softc *, struct ieee80211_channel *);
 static void	run_set_channel(struct ieee80211com *);
 static void	run_scan_start(struct ieee80211com *);
@@ -416,16 +421,19 @@ static void	run_update_mcast(struct ifne
 static int8_t	run_rssi2dbm(struct run_softc *, uint8_t, uint8_t);
 static void	run_update_promisc_locked(struct ifnet *);
 static void	run_update_promisc(struct ifnet *);
+static void	run_rt5390_bbp_init(struct run_softc *);
 static int	run_bbp_init(struct run_softc *);
 static int	run_rt3070_rf_init(struct run_softc *);
+static void	run_rt5390_rf_init(struct run_softc *);
 static int	run_rt3070_filter_calib(struct run_softc *, uint8_t, uint8_t,
 		    uint8_t *);
 static void	run_rt3070_rf_setup(struct run_softc *);
 static int	run_txrx_enable(struct run_softc *);
+static void	run_adjust_freq_offset(struct run_softc *);
 static void	run_init(void *);
 static void	run_init_locked(struct run_softc *);
 static void	run_stop(void *);
-static void	run_delay(struct run_softc *, unsigned int);
+static void	run_delay(struct run_softc *, u_int);
 
 static const struct {
 	uint16_t	reg;
@@ -439,6 +447,25 @@ static const struct {
 	uint8_t	val;
 } rt2860_def_bbp[] = {
 	RT2860_DEF_BBP
+},rt5390_def_bbp[] = {
+	RT5390_DEF_BBP
+},rt5592_def_bbp[] = {
+	RT5592_DEF_BBP
+};
+
+/* 
+ * Default values for BBP register R196 for RT5592.
+ */
+static const uint8_t rt5592_bbp_r196[] = {
+	0xe0, 0x1f, 0x38, 0x32, 0x08, 0x28, 0x19, 0x0a, 0xff, 0x00,
+	0x16, 0x10, 0x10, 0x0b, 0x36, 0x2c, 0x26, 0x24, 0x42, 0x36,
+	0x30, 0x2d, 0x4c, 0x46, 0x3d, 0x40, 0x3e, 0x42, 0x3d, 0x40,
+	0x3c, 0x34, 0x2c, 0x2f, 0x3c, 0x35, 0x2e, 0x2a, 0x49, 0x41,
+	0x36, 0x31, 0x30, 0x30, 0x0e, 0x0d, 0x28, 0x21, 0x1c, 0x16,
+	0x50, 0x4a, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x7d, 0x14, 0x32, 0x2c, 0x36, 0x4c, 0x43, 0x2c,
+	0x2e, 0x36, 0x30, 0x6e
 };
 
 static const struct rfprog {
@@ -454,6 +481,15 @@ struct {
 	RT3070_RF3052
 };
 
+static const struct rt5592_freqs {
+	uint16_t	n;
+	uint8_t		k, m, r;
+} rt5592_freqs_20mhz[] = {
+	RT5592_RF5592_20MHZ
+},rt5592_freqs_40mhz[] = {
+	RT5592_RF5592_40MHZ
+};
+
 static const struct {
 	uint8_t	reg;
 	uint8_t	val;
@@ -461,6 +497,25 @@ static const struct {
 	RT3070_DEF_RF
 },rt3572_def_rf[] = {
 	RT3572_DEF_RF
+},rt5390_def_rf[] = {
+	RT5390_DEF_RF
+},rt5392_def_rf[] = {
+	RT5392_DEF_RF
+},rt5592_def_rf[] = {
+	RT5592_DEF_RF
+},rt5592_2ghz_def_rf[] = {
+	RT5592_2GHZ_DEF_RF
+},rt5592_5ghz_def_rf[] = {
+	RT5592_5GHZ_DEF_RF
+};
+
+static const struct {
+	u_int	firstchan;
+	u_int	lastchan;
+	uint8_t	reg;
+	uint8_t	val;
+} rt5592_chan_5ghz[] = {
+	RT5592_CHAN_5GHZ
 };
 
 static const struct usb_config run_config[RUN_N_XFER] = {
@@ -557,7 +612,7 @@ run_attach(device_t self)
 	struct ieee80211com *ic;
 	struct ifnet *ifp;
 	uint32_t ver;
-	int i, ntries, error;
+	int ntries, error;
 	uint8_t iface_index, bands;
 
 	device_set_usb_desc(self);
@@ -654,27 +709,11 @@ run_attach(device_t self)
 	bands = 0;
 	setbit(&bands, IEEE80211_MODE_11B);
 	setbit(&bands, IEEE80211_MODE_11G);
+	if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 ||
+	    sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT5592_RF_5592)
+		setbit(&bands, IEEE80211_MODE_11A);
 	ieee80211_init_channels(ic, NULL, &bands);
 
-	/*
-	 * Do this by own because h/w supports
-	 * more channels than ieee80211_init_channels()
-	 */
-	if (sc->rf_rev == RT2860_RF_2750 ||
-	    sc->rf_rev == RT2860_RF_2850 ||
-	    sc->rf_rev == RT3070_RF_3052) {
-		/* set supported .11a rates */
-		for (i = 14; i < N(rt2860_rf2850); i++) {
-			uint8_t chan = rt2860_rf2850[i].chan;
-			ic->ic_channels[ic->ic_nchans].ic_freq =
-			    ieee80211_ieee2mhz(chan, IEEE80211_CHAN_A);
-			ic->ic_channels[ic->ic_nchans].ic_ieee = chan;
-			ic->ic_channels[ic->ic_nchans].ic_flags = IEEE80211_CHAN_A;
-			ic->ic_channels[ic->ic_nchans].ic_extieee = 0;
-			ic->ic_nchans++;
-		}
-	}
-
 	ieee80211_ifattach(ic, sc->sc_bssid);
 
 	ic->ic_scan_start = run_scan_start;
@@ -699,7 +738,7 @@ run_attach(device_t self)
 
 	TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc);
 	TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc);
-	callout_init((struct callout *)&sc->ratectl_ch, 1);
+	usb_callout_init_mtx(&sc->ratectl_ch, &sc->sc_mtx, 0);
 
 	if (bootverbose)
 		ieee80211_announce(ic);
@@ -803,7 +842,13 @@ run_vap_create(struct ieee80211com *ic, 
 	if (rvp == NULL)
 		return (NULL);
 	vap = &rvp->vap;
-	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
+
+	if (ieee80211_vap_setup(ic, vap, name, unit,
+	    opmode, flags, bssid, mac) != 0) {
+		/* out of memory */
+		free(rvp, M_80211_VAP);
+		return (NULL);
+	}
 
 	vap->iv_key_update_begin = run_key_update_begin;
 	vap->iv_key_update_end = run_key_update_end;
@@ -1009,13 +1054,12 @@ run_load_microcode(struct run_softc *sc)
 	/* cheap sanity check */
 	temp = fw->data;
 	bytes = *temp;
-	if (bytes != be64toh(0xffffff0210280210)) {
+	if (bytes != be64toh(0xffffff0210280210ULL)) {
 		device_printf(sc->sc_dev, "firmware checksum failed\n");
 		error = EINVAL;
 		goto fail;
 	}
 
-	run_read(sc, RT2860_ASIC_VER_ID, &tmp);
 	/* write microcode image */
 	run_write_region_1(sc, RT2870_FW_BASE, base, 4096);
 	run_write(sc, RT2860_H2M_MAILBOX_CID, 0xffffffff);
@@ -1062,7 +1106,7 @@ fail:
 	return (error);
 }
 
-int
+static int
 run_reset(struct run_softc *sc)
 {
 	usb_device_request_t req;
@@ -1164,13 +1208,32 @@ run_write_region_1(struct run_softc *sc,
 	return (error);
 #else
 	usb_device_request_t req;
+	int error = 0;
 
-	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
-	req.bRequest = RT2870_WRITE_REGION_1;
-	USETW(req.wValue, 0);
-	USETW(req.wIndex, reg);
-	USETW(req.wLength, len);
-	return (run_do_request(sc, &req, buf));
+	/*
+	 * NOTE: It appears the WRITE_REGION_1 command cannot be
+	 * passed a huge amount of data, which will crash the
+	 * firmware. Limit amount of data passed to 64-bytes at a
+	 * time.
+	 */
+	while (len > 0) {
+		int delta = 64;
+		if (delta > len)
+			delta = len;
+
+		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+		req.bRequest = RT2870_WRITE_REGION_1;
+		USETW(req.wValue, 0);
+		USETW(req.wIndex, reg);
+		USETW(req.wLength, delta);
+		error = run_do_request(sc, &req, __DECONST(uint8_t *, buf));
+		if (error != 0)
+			break;
+		reg += delta;
+		buf += delta;
+		len -= delta;
+	}
+	return (error);
 #endif
 }
 
@@ -1260,7 +1323,7 @@ run_srom_read(struct run_softc *sc, uint
 }
 
 static int
-run_rt2870_rf_write(struct run_softc *sc, uint8_t reg, uint32_t val)
+run_rt2870_rf_write(struct run_softc *sc, uint32_t val)
 {
 	uint32_t tmp;
 	int error, ntries;
@@ -1274,10 +1337,7 @@ run_rt2870_rf_write(struct run_softc *sc
 	if (ntries == 10)
 		return (ETIMEDOUT);
 
-	/* RF registers are 24-bit on the RT2860 */
-	tmp = RT2860_RF_REG_CTRL | 24 << RT2860_RF_REG_WIDTH_SHIFT |
-	    (val & 0x3fffff) << 2 | (reg & 3);
-	return (run_write(sc, RT2860_RF_CSR_CFG0, tmp));
+	return (run_write(sc, RT2860_RF_CSR_CFG0, val));
 }
 
 static int
@@ -1428,7 +1488,7 @@ b4inc(uint32_t b32, int8_t delta)
 }
 
 static const char *
-run_get_rf(int rev)
+run_get_rf(uint16_t rev)
 {
 	switch (rev) {
 	case RT2860_RF_2820:	return "RT2820";
@@ -1440,11 +1500,14 @@ run_get_rf(int rev)
 	case RT3070_RF_3021:	return "RT3021";
 	case RT3070_RF_3022:	return "RT3022";
 	case RT3070_RF_3052:	return "RT3052";
+	case RT5592_RF_5592:	return "RT5592";
+	case RT5390_RF_5370:	return "RT5370";
+	case RT5390_RF_5372:	return "RT5372";
 	}
 	return ("unknown");
 }
 
-int
+static int
 run_read_eeprom(struct run_softc *sc)
 {
 	int8_t delta_2ghz, delta_5ghz;
@@ -1476,21 +1539,25 @@ run_read_eeprom(struct run_softc *sc)
 	sc->sc_bssid[4] = val & 0xff;
 	sc->sc_bssid[5] = val >> 8;
 
-	/* read vender BBP settings */
-	for (i = 0; i < 10; i++) {
-		run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
-		sc->bbp[i].val = val & 0xff;
-		sc->bbp[i].reg = val >> 8;
-		DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg, sc->bbp[i].val);
-	}
-	if (sc->mac_ver >= 0x3071) {
-		/* read vendor RF settings */
+	if (sc->mac_ver < 0x5390) {
+		/* read vender BBP settings */
 		for (i = 0; i < 10; i++) {
-			run_srom_read(sc, RT3071_EEPROM_RF_BASE + i, &val);
-			sc->rf[i].val = val & 0xff;
-			sc->rf[i].reg = val >> 8;
-			DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg,
-			    sc->rf[i].val);
+			run_srom_read(sc, RT2860_EEPROM_BBP_BASE + i, &val);
+			sc->bbp[i].val = val & 0xff;
+			sc->bbp[i].reg = val >> 8;
+			DPRINTF("BBP%d=0x%02x\n", sc->bbp[i].reg,
+			    sc->bbp[i].val);
+		}
+		if (sc->mac_ver >= 0x3071) {
+			/* read vendor RF settings */
+			for (i = 0; i < 10; i++) {
+				run_srom_read(sc, RT3071_EEPROM_RF_BASE + i,
+				   &val);
+				sc->rf[i].val = val & 0xff;
+				sc->rf[i].reg = val >> 8;
+				DPRINTF("RF%d=0x%02x\n", sc->rf[i].reg,
+				    sc->rf[i].val);
+			}
 		}
 	}
 
@@ -1516,7 +1583,11 @@ run_read_eeprom(struct run_softc *sc)
 	    sc->leds, sc->led[0], sc->led[1], sc->led[2]);
 
 	/* read RF information */
-	run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
+	if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392)
+		run_srom_read(sc, 0x00, &val);
+	else
+		run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
+
 	if (val == 0xffff) {
 		DPRINTF("invalid EEPROM antenna info, using default\n");
 		if (sc->mac_ver == 0x3572) {
@@ -1536,11 +1607,15 @@ run_read_eeprom(struct run_softc *sc)
 			sc->nrxchains = 2;
 		}
 	} else {
-		sc->rf_rev = (val >> 8) & 0xf;
+		if (sc->mac_ver == 0x5390 || sc->mac_ver ==0x5392) {
+			sc->rf_rev = val;
+			run_srom_read(sc, RT2860_EEPROM_ANTENNA, &val);
+		} else
+			sc->rf_rev = (val >> 8) & 0xf;
 		sc->ntxchains = (val >> 4) & 0xf;
 		sc->nrxchains = val & 0xf;
 	}
-	DPRINTF("EEPROM RF rev=0x%02x chains=%dT%dR\n",
+	DPRINTF("EEPROM RF rev=0x%04x chains=%dT%dR\n",
 	    sc->rf_rev, sc->ntxchains, sc->nrxchains);
 
 	/* check if RF supports automatic Tx access gain control */
@@ -1564,16 +1639,29 @@ run_read_eeprom(struct run_softc *sc)
 		sc->txpow1[i + 0] = (int8_t)(val & 0xff);
 		sc->txpow1[i + 1] = (int8_t)(val >> 8);
 
-		run_srom_read(sc, RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
-		sc->txpow2[i + 0] = (int8_t)(val & 0xff);
-		sc->txpow2[i + 1] = (int8_t)(val >> 8);
+		if (sc->mac_ver != 0x5390) {
+			run_srom_read(sc,
+			    RT2860_EEPROM_PWR2GHZ_BASE2 + i / 2, &val);
+			sc->txpow2[i + 0] = (int8_t)(val & 0xff);
+			sc->txpow2[i + 1] = (int8_t)(val >> 8);
+		}
 	}
 	/* fix broken Tx power entries */
 	for (i = 0; i < 14; i++) {
-		if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
-			sc->txpow1[i] = 5;
-		if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
-			sc->txpow2[i] = 5;
+		if (sc->mac_ver >= 0x5390) {
+			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 27)
+				sc->txpow1[i] = 5;
+		} else {
+			if (sc->txpow1[i] < 0 || sc->txpow1[i] > 31)
+				sc->txpow1[i] = 5;
+		}
+		if (sc->mac_ver > 0x5390) {
+			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 27)
+				sc->txpow2[i] = 5;
+		} else if (sc->mac_ver < 0x5390) {
+			if (sc->txpow2[i] < 0 || sc->txpow2[i] > 31)
+				sc->txpow2[i] = 5;
+		}
 		DPRINTF("chan %d: power1=%d, power2=%d\n",
 		    rt2860_rf2850[i].chan, sc->txpow1[i], sc->txpow2[i]);
 	}
@@ -1588,11 +1676,13 @@ run_read_eeprom(struct run_softc *sc)
 		sc->txpow2[i + 15] = (int8_t)(val >> 8);
 	}
 	/* fix broken Tx power entries */
-	for (i = 0; i < 40; i++) {
-		if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
-			sc->txpow1[14 + i] = 5;
-		if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
-			sc->txpow2[14 + i] = 5;
+	for (i = 0; i < 40; i++ ) {
+		if (sc->mac_ver != 0x5592) {
+			if (sc->txpow1[14 + i] < -7 || sc->txpow1[14 + i] > 15)
+				sc->txpow1[14 + i] = 5;
+			if (sc->txpow2[14 + i] < -7 || sc->txpow2[14 + i] > 15)
+				sc->txpow2[14 + i] = 5;
+		}
 		DPRINTF("chan %d: power1=%d, power2=%d\n",
 		    rt2860_rf2850[14 + i].chan, sc->txpow1[14 + i],
 		    sc->txpow2[14 + i]);
@@ -2236,8 +2326,10 @@ run_ratectl_cb(void *arg, int pending)
 		ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc);
 	}
 
+	RUN_LOCK(sc);
 	if(sc->ratectl_run != RUN_RATECTL_OFF)
 		usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc);
+	RUN_UNLOCK(sc);
 }
 
 static void
@@ -2472,12 +2564,15 @@ run_rx_frame(struct run_softc *sc, struc
 	struct rt2870_rxd *rxd;
 	struct rt2860_rxwi *rxwi;
 	uint32_t flags;
-	uint16_t len, phy;
+	uint16_t len, rxwisize;
 	uint8_t ant, rssi;
 	int8_t nf;
 
 	rxwi = mtod(m, struct rt2860_rxwi *);
 	len = le16toh(rxwi->len) & 0xfff;
+	rxwisize = (sc->mac_ver == 0x5592) ?
+	    sizeof(struct rt2860_rxwi) + sizeof(uint64_t) :
+	    sizeof(struct rt2860_rxwi);
 	if (__predict_false(len > dmalen)) {
 		m_freem(m);
 		ifp->if_ierrors++;
@@ -2495,8 +2590,8 @@ run_rx_frame(struct run_softc *sc, struc
 		return;
 	}
 
-	m->m_data += sizeof(struct rt2860_rxwi);
-	m->m_pkthdr.len = m->m_len -= sizeof(struct rt2860_rxwi);
+	m->m_data += rxwisize;
+	m->m_pkthdr.len = m->m_len -= rxwisize;
 
 	wh = mtod(m, struct ieee80211_frame *);
 
@@ -2516,7 +2611,8 @@ run_rx_frame(struct run_softc *sc, struc
 	if (__predict_false(flags & RT2860_RX_MICERR)) {
 		/* report MIC failures to net80211 for TKIP */
 		if (ni != NULL)
-			ieee80211_notify_michael_failure(ni->ni_vap, wh, rxwi->keyidx);
+			ieee80211_notify_michael_failure(ni->ni_vap, wh,
+			    rxwi->keyidx);
 		m_freem(m);
 		ifp->if_ierrors++;
 		DPRINTF("MIC error. Someone is lying.\n");
@@ -2539,6 +2635,7 @@ run_rx_frame(struct run_softc *sc, struc
 
 	if (__predict_false(ieee80211_radiotap_active(ic))) {
 		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
+		uint16_t phy;
 
 		tap->wr_flags = 0;
 		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
@@ -2583,8 +2680,13 @@ run_bulk_rx_callback(struct usb_xfer *xf
 	struct mbuf *m = NULL;
 	struct mbuf *m0;
 	uint32_t dmalen;
+	uint16_t rxwisize;
 	int xferlen;
 
+	rxwisize = (sc->mac_ver == 0x5592) ?
+	    sizeof(struct rt2860_rxwi) + sizeof(uint64_t) :
+	    sizeof(struct rt2860_rxwi);
+
 	usbd_xfer_status(xfer, &xferlen, NULL, NULL, NULL);
 
 	switch (USB_GET_STATE(xfer)) {
@@ -2592,8 +2694,8 @@ run_bulk_rx_callback(struct usb_xfer *xf
 
 		DPRINTFN(15, "rx done, actlen=%d\n", xferlen);
 
-		if (xferlen < (int)(sizeof(uint32_t) +
-		    sizeof(struct rt2860_rxwi) + sizeof(struct rt2870_rxd))) {
+		if (xferlen < (int)(sizeof(uint32_t) + rxwisize +
+		    sizeof(struct rt2870_rxd))) {
 			DPRINTF("xfer too short %d\n", xferlen);
 			goto tr_setup;
 		}
@@ -2675,6 +2777,7 @@ tr_setup:
 			m->m_data += 4;
 			m->m_pkthdr.len = m->m_len -= 4;
 			run_rx_frame(sc, m, dmalen);
+			m = NULL;	/* don't free source buffer */
 			break;
 		}
 
@@ -2696,6 +2799,9 @@ tr_setup:
 		m->m_pkthdr.len = m->m_len -= dmalen + 8;
 	}
 
+	/* make sure we free the source buffer, if any */
+	m_freem(m);
+
 	RUN_LOCK(sc);
 }
 
@@ -2723,7 +2829,7 @@ run_tx_free(struct run_endpoint_queue *p
 }
 
 static void
-run_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, unsigned int index)
+run_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, u_int index)
 {
 	struct run_softc *sc = usbd_xfer_softc(xfer);
 	struct ifnet *ifp = sc->sc_ifp;
@@ -2763,8 +2869,10 @@ tr_setup:
 		STAILQ_REMOVE_HEAD(&pq->tx_qh, next);
 
 		m = data->m;
+		size = (sc->mac_ver == 0x5592) ? 
+		    RUN_MAX_TXSZ + sizeof(uint32_t) : RUN_MAX_TXSZ;
 		if ((m->m_pkthdr.len +
-		    sizeof(data->desc) + 3 + 8) > RUN_MAX_TXSZ) {
+		    sizeof(data->desc) + 3 + 8) > size) {
 			DPRINTF("data overflow, %u bytes\n",
 			    m->m_pkthdr.len);
 
@@ -2776,7 +2884,8 @@ tr_setup:
 		}
 
 		pc = usbd_xfer_get_frame(xfer, 0);
-		size = sizeof(data->desc);
+		size = (sc->mac_ver == 0x5592) ?
+		    sizeof(data->desc) + sizeof(uint32_t) : sizeof(data->desc);
 		usbd_copy_in(pc, 0, &data->desc, size);
 		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
 		size += m->m_pkthdr.len;
@@ -2791,9 +2900,8 @@ tr_setup:
 		vap = data->ni->ni_vap;
 		if (ieee80211_radiotap_active_vap(vap)) {
 			struct run_tx_radiotap_header *tap = &sc->sc_txtap;
-			struct rt2860_txwi *txwi =
+			struct rt2860_txwi *txwi = 
 			    (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd));
-
 			tap->wt_flags = 0;
 			tap->wt_rate = rt2860_rates[data->ridx].rate;
 			tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
@@ -2903,7 +3011,7 @@ run_set_tx_desc(struct run_softc *sc, st
 	struct ieee80211_frame *wh;
 	struct rt2870_txd *txd;
 	struct rt2860_txwi *txwi;
-	uint16_t xferlen;
+	uint16_t xferlen, txwisize;
 	uint16_t mcs;
 	uint8_t ridx = data->ridx;
 	uint8_t pad;
@@ -2911,7 +3019,9 @@ run_set_tx_desc(struct run_softc *sc, st
 	/* get MCS code from rate index */
 	mcs = rt2860_rates[ridx].mcs;
 
-	xferlen = sizeof(*txwi) + m->m_pkthdr.len;
+	txwisize = (sc->mac_ver == 0x5592) ?
+	    sizeof(*txwi) + sizeof(uint32_t) : sizeof(*txwi);
+	xferlen = txwisize + m->m_pkthdr.len;
 
 	/* roundup to 32-bit alignment */
 	xferlen = (xferlen + 3) & ~3;
@@ -3037,7 +3147,7 @@ run_tx(struct run_softc *sc, struct mbuf
 			dur = rt2860_rates[ctl_ridx].sp_ack_dur;
 		else
 			dur = rt2860_rates[ctl_ridx].lp_ack_dur;
-		*(uint16_t *)wh->i_dur = htole16(dur);
+		USETW(wh->i_dur, dur);
 	}
 
 	/* reserve slots for mgmt packets, just in case */
@@ -3054,12 +3164,12 @@ run_tx(struct run_softc *sc, struct mbuf
 	txd->flags = qflags;
 	txwi = (struct rt2860_txwi *)(txd + 1);
 	txwi->xflags = xflags;
-	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
 		txwi->wcid = 0;
-	} else {
+	else
 		txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
 		    1 : RUN_AID2WCID(ni->ni_associd);
-	}
+
 	/* clear leftover garbage bits */
 	txwi->flags = 0;
 	txwi->txop = 0;
@@ -3117,9 +3227,9 @@ run_tx(struct run_softc *sc, struct mbuf
 
 	usbd_transfer_start(sc->sc_xfer[qid]);
 
-	DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n", m->m_pkthdr.len +
-	    (int)(sizeof (struct rt2870_txd) + sizeof (struct rt2860_rxwi)),
-	    rt2860_rates[ridx].rate, qid);
+	DPRINTFN(8, "sending data frame len=%d rate=%d qid=%d\n",
+	    m->m_pkthdr.len + (int)(sizeof(struct rt2870_txd) +
+	    sizeof(struct rt2860_txwi)), rt2860_rates[ridx].rate, qid);
 
 	return (0);
 }
@@ -3156,7 +3266,7 @@ run_tx_mgt(struct run_softc *sc, struct 
 
 		dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate, 
 		    ic->ic_flags & IEEE80211_F_SHPREAMBLE);
-		*(uint16_t *)wh->i_dur = htole16(dur);
+		USETW(wh->i_dur, dur);
 	}
 
 	if (sc->sc_epq[0].tx_nfree == 0) {
@@ -3183,7 +3293,7 @@ run_tx_mgt(struct run_softc *sc, struct 
 	run_set_tx_desc(sc, data);
 
 	DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len +
-	    (int)(sizeof (struct rt2870_txd) + sizeof (struct rt2860_rxwi)),
+	    (int)(sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)),
 	    rt2860_rates[ridx].rate);
 
 	STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next);
@@ -3513,18 +3623,63 @@ run_select_chan_group(struct run_softc *
 	run_bbp_write(sc, 62, 0x37 - sc->lna[group]);
 	run_bbp_write(sc, 63, 0x37 - sc->lna[group]);
 	run_bbp_write(sc, 64, 0x37 - sc->lna[group]);
-	run_bbp_write(sc, 86, 0x00);
+	if (sc->mac_ver < 0x3572)
+		run_bbp_write(sc, 86, 0x00);
 
 	if (group == 0) {
 		if (sc->ext_2ghz_lna) {
-			run_bbp_write(sc, 82, 0x62);
-			run_bbp_write(sc, 75, 0x46);
+			if (sc->mac_ver >= 0x5390)
+				run_bbp_write(sc, 75, 0x52);
+			else {
+				run_bbp_write(sc, 82, 0x62);
+				run_bbp_write(sc, 75, 0x46);
+			}
 		} else {
-			run_bbp_write(sc, 82, 0x84);
-			run_bbp_write(sc, 75, 0x50);
+			if (sc->mac_ver == 0x5592) {
+				run_bbp_write(sc, 79, 0x1c);
+				run_bbp_write(sc, 80, 0x0e);
+				run_bbp_write(sc, 81, 0x3a);
+				run_bbp_write(sc, 82, 0x62);
+
+				run_bbp_write(sc, 195, 0x80);
+				run_bbp_write(sc, 196, 0xe0);
+				run_bbp_write(sc, 195, 0x81);
+				run_bbp_write(sc, 196, 0x1f);
+				run_bbp_write(sc, 195, 0x82);
+				run_bbp_write(sc, 196, 0x38);
+				run_bbp_write(sc, 195, 0x83);
+				run_bbp_write(sc, 196, 0x32);
+				run_bbp_write(sc, 195, 0x85);
+				run_bbp_write(sc, 196, 0x28);
+				run_bbp_write(sc, 195, 0x86);
+				run_bbp_write(sc, 196, 0x19);
+			} else if (sc->mac_ver >= 0x5390)
+				run_bbp_write(sc, 75, 0x50);
+			else {
+				run_bbp_write(sc, 82, 0x84);
+				run_bbp_write(sc, 75, 0x50);
+			}
 		}
 	} else {
-		if (sc->mac_ver == 0x3572)
+		if (sc->mac_ver == 0x5592) {
+			run_bbp_write(sc, 79, 0x18);
+			run_bbp_write(sc, 80, 0x08);
+			run_bbp_write(sc, 81, 0x38);
+			run_bbp_write(sc, 82, 0x92);
+
+			run_bbp_write(sc, 195, 0x80);
+			run_bbp_write(sc, 196, 0xf0);
+			run_bbp_write(sc, 195, 0x81);
+			run_bbp_write(sc, 196, 0x1e);
+			run_bbp_write(sc, 195, 0x82);
+			run_bbp_write(sc, 196, 0x28);
+			run_bbp_write(sc, 195, 0x83);
+			run_bbp_write(sc, 196, 0x20);
+			run_bbp_write(sc, 195, 0x85);
+			run_bbp_write(sc, 196, 0x7f);
+			run_bbp_write(sc, 195, 0x86);
+			run_bbp_write(sc, 196, 0x7f);
+		} else if (sc->mac_ver == 0x3572)
 			run_bbp_write(sc, 82, 0x94);
 		else
 			run_bbp_write(sc, 82, 0xf2);
@@ -3559,6 +3714,11 @@ run_select_chan_group(struct run_softc *
 	} else
 		run_write(sc, RT2860_TX_PIN_CFG, tmp);
 
+	if (sc->mac_ver == 0x5592) {
+		run_bbp_write(sc, 195, 0x8d);
+		run_bbp_write(sc, 196, 0x1a);
+	}
+
 	/* set initial AGC value */
 	if (group == 0) {	/* 2GHz band */
 		if (sc->mac_ver >= 0x3070)
@@ -3566,7 +3726,9 @@ run_select_chan_group(struct run_softc *
 		else
 			agc = 0x2e + sc->lna[0];
 	} else {		/* 5GHz band */
-		if (sc->mac_ver == 0x3572)
+		if (sc->mac_ver == 0x5592)
+			agc = 0x24 + sc->lna[group] * 2;
+		else if (sc->mac_ver == 0x3572)
 			agc = 0x22 + (sc->lna[group] * 5) / 3;
 		else
 			agc = 0x32 + (sc->lna[group] * 5) / 3;
@@ -3575,7 +3737,7 @@ run_select_chan_group(struct run_softc *
 }
 
 static void
-run_rt2870_set_chan(struct run_softc *sc, uint32_t chan)
+run_rt2870_set_chan(struct run_softc *sc, u_int chan)
 {
 	const struct rfprog *rfprog = rt2860_rf2850;
 	uint32_t r2, r3, r4;
@@ -3587,58 +3749,71 @@ run_rt2870_set_chan(struct run_softc *sc
 
 	r2 = rfprog[i].r2;
 	if (sc->ntxchains == 1)
-		r2 |= 1 << 12;		/* 1T: disable Tx chain 2 */
+		r2 |= 1 << 14;		/* 1T: disable Tx chain 2 */
 	if (sc->nrxchains == 1)
-		r2 |= 1 << 15 | 1 << 4;	/* 1R: disable Rx chains 2 & 3 */
+		r2 |= 1 << 17 | 1 << 6;	/* 1R: disable Rx chains 2 & 3 */
 	else if (sc->nrxchains == 2)
-		r2 |= 1 << 4;		/* 2R: disable Rx chain 3 */
+		r2 |= 1 << 6;		/* 2R: disable Rx chain 3 */
 
 	/* use Tx power values from EEPROM */
 	txpow1 = sc->txpow1[i];
 	txpow2 = sc->txpow2[i];
+
+	/* Initialize RF R3 and R4. */
+	r3 = rfprog[i].r3 & 0xffffc1ff;
+	r4 = (rfprog[i].r4 & ~(0x001f87c0)) | (sc->freq << 15);
 	if (chan > 14) {
-		if (txpow1 >= 0)
-			txpow1 = txpow1 << 1 | 1;
-		else
-			txpow1 = (7 + txpow1) << 1;
-		if (txpow2 >= 0)
-			txpow2 = txpow2 << 1 | 1;
-		else
-			txpow2 = (7 + txpow2) << 1;
+		if (txpow1 >= 0) {
+			txpow1 = (txpow1 > 0xf) ? (0xf) : (txpow1);
+			r3 |= (txpow1 << 10) | (1 << 9);
+		} else {
+			txpow1 += 7;
+
+			/* txpow1 is not possible larger than 15. */
+			r3 |= (txpow1 << 10);
+		}
+		if (txpow2 >= 0) {
+			txpow2 = (txpow2 > 0xf) ? (0xf) : (txpow2);
+			r4 |= (txpow2 << 7) | (1 << 6);
+		} else {
+			txpow2 += 7;
+			r4 |= (txpow2 << 7);
+		}
+	} else {
+		/* Set Tx0 power. */
+		r3 |= (txpow1 << 9);
+
+		/* Set frequency offset and Tx1 power. */
+		r4 |= (txpow2 << 6);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201312160810.rBG8Adg4030099>