if_rsu.c revision 262008
186764Sjlemon/*	$OpenBSD: if_rsu.c,v 1.17 2013/04/15 09:23:01 mglocker Exp $	*/
292275Srwatson
386764Sjlemon/*-
486764Sjlemon * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
586764Sjlemon *
686764Sjlemon * Permission to use, copy, modify, and distribute this software for any
786764Sjlemon * purpose with or without fee is hereby granted, provided that the above
886764Sjlemon * copyright notice and this permission notice appear in all copies.
986764Sjlemon *
1086764Sjlemon * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1186764Sjlemon * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1286764Sjlemon * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1386764Sjlemon * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1486764Sjlemon * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1586764Sjlemon * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1686764Sjlemon * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1786764Sjlemon */
1886764Sjlemon#include <sys/cdefs.h>
1986764Sjlemon__FBSDID("$FreeBSD: stable/10/sys/dev/usb/wlan/if_rsu.c 262008 2014-02-17 01:39:03Z kevlo $");
2086764Sjlemon
2186764Sjlemon/*
2286764Sjlemon * Driver for Realtek RTL8188SU/RTL8191SU/RTL8192SU.
2386764Sjlemon *
2486764Sjlemon * TODO:
2586764Sjlemon *   o 11n support
2686764Sjlemon *   o h/w crypto
2786764Sjlemon *   o hostap / ibss / mesh
2886764Sjlemon */
2986764Sjlemon#include <sys/param.h>
3086764Sjlemon#include <sys/endian.h>
3186764Sjlemon#include <sys/sockio.h>
3286764Sjlemon#include <sys/mbuf.h>
3386764Sjlemon#include <sys/kernel.h>
3486764Sjlemon#include <sys/socket.h>
3586764Sjlemon#include <sys/systm.h>
3686764Sjlemon#include <sys/conf.h>
37125680Sbms#include <sys/bus.h>
3886764Sjlemon#include <sys/rman.h>
3986764Sjlemon#include <sys/firmware.h>
40101106Srwatson#include <sys/module.h>
41118864Sharti
4286764Sjlemon#include <machine/bus.h>
4386764Sjlemon#include <machine/resource.h>
4486764Sjlemon
4586764Sjlemon#include <net/bpf.h>
4686764Sjlemon#include <net/if.h>
4786764Sjlemon#include <net/if_arp.h>
48101106Srwatson#include <net/if_dl.h>
4986764Sjlemon#include <net/if_media.h>
5086764Sjlemon#include <net/if_types.h>
5186764Sjlemon
5286764Sjlemon#include <netinet/in.h>
5386764Sjlemon#include <netinet/in_systm.h>
5486764Sjlemon#include <netinet/in_var.h>
5586764Sjlemon#include <netinet/if_ether.h>
5686764Sjlemon#include <netinet/ip.h>
5786764Sjlemon
5886764Sjlemon#include <net80211/ieee80211_var.h>
5986764Sjlemon#include <net80211/ieee80211_regdomain.h>
6086764Sjlemon#include <net80211/ieee80211_radiotap.h>
6186764Sjlemon
6286764Sjlemon#include <dev/usb/usb.h>
6386764Sjlemon#include <dev/usb/usbdi.h>
6486764Sjlemon#include "usbdevs.h"
6586764Sjlemon
6686764Sjlemon#define USB_DEBUG_VAR rsu_debug
6786764Sjlemon#include <dev/usb/usb_debug.h>
6886764Sjlemon
6986764Sjlemon#include <dev/usb/wlan/if_rsureg.h>
7086764Sjlemon
7186764Sjlemon#ifdef USB_DEBUG
7286764Sjlemonstatic int rsu_debug = 0;
73118864ShartiSYSCTL_NODE(_hw_usb, OID_AUTO, rsu, CTLFLAG_RW, 0, "USB rsu");
74118864ShartiSYSCTL_INT(_hw_usb_rsu, OID_AUTO, debug, CTLFLAG_RW, &rsu_debug, 0,
75118864Sharti    "Debug level");
7686764Sjlemon#endif
7786764Sjlemon
7886764Sjlemonstatic const STRUCT_USB_HOST_ID rsu_devs[] = {
7986764Sjlemon#define	RSU_HT_NOT_SUPPORTED 0
80118864Sharti#define	RSU_HT_SUPPORTED 1
81118864Sharti#define RSU_DEV_HT(v,p)  { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, \
82118864Sharti				   RSU_HT_SUPPORTED) }
8386764Sjlemon#define RSU_DEV(v,p)     { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, \
8486764Sjlemon				   RSU_HT_NOT_SUPPORTED) }
8586764Sjlemon	RSU_DEV(ASUS,			RTL8192SU),
8686764Sjlemon	RSU_DEV(AZUREWAVE,		RTL8192SU_4),
8786764Sjlemon	RSU_DEV_HT(ACCTON,		RTL8192SU),
8886764Sjlemon	RSU_DEV_HT(ASUS,		USBN10),
8986764Sjlemon	RSU_DEV_HT(AZUREWAVE,		RTL8192SU_1),
9086764Sjlemon	RSU_DEV_HT(AZUREWAVE,		RTL8192SU_2),
9186764Sjlemon	RSU_DEV_HT(AZUREWAVE,		RTL8192SU_3),
9286764Sjlemon	RSU_DEV_HT(AZUREWAVE,		RTL8192SU_5),
9386764Sjlemon	RSU_DEV_HT(BELKIN,		RTL8192SU_1),
94105199Ssam	RSU_DEV_HT(BELKIN,		RTL8192SU_2),
95105199Ssam	RSU_DEV_HT(BELKIN,		RTL8192SU_3),
96105199Ssam	RSU_DEV_HT(CONCEPTRONIC2,	RTL8192SU_1),
97105199Ssam	RSU_DEV_HT(CONCEPTRONIC2,	RTL8192SU_2),
98105199Ssam	RSU_DEV_HT(CONCEPTRONIC2,	RTL8192SU_3),
99105199Ssam	RSU_DEV_HT(COREGA,		RTL8192SU),
100105199Ssam	RSU_DEV_HT(DLINK2,		DWA131A1),
101105199Ssam	RSU_DEV_HT(DLINK2,		RTL8192SU_1),
10286764Sjlemon	RSU_DEV_HT(DLINK2,		RTL8192SU_2),
10392760Sjeff	RSU_DEV_HT(EDIMAX,		RTL8192SU_1),
10486764Sjlemon	RSU_DEV_HT(EDIMAX,		RTL8192SU_2),
10588180Sjlemon	RSU_DEV_HT(EDIMAX,		RTL8192SU_3),
10688180Sjlemon	RSU_DEV_HT(GUILLEMOT,		HWGUN54),
10788180Sjlemon	RSU_DEV_HT(GUILLEMOT,		HWNUM300),
10888180Sjlemon	RSU_DEV_HT(HAWKING,		RTL8192SU_1),
10988180Sjlemon	RSU_DEV_HT(HAWKING,		RTL8192SU_2),
11086764Sjlemon	RSU_DEV_HT(PLANEX2,		GWUSNANO),
11186764Sjlemon	RSU_DEV_HT(REALTEK,		RTL8171),
11288180Sjlemon	RSU_DEV_HT(REALTEK,		RTL8172),
11386764Sjlemon	RSU_DEV_HT(REALTEK,		RTL8173),
114118864Sharti	RSU_DEV_HT(REALTEK,		RTL8174),
115118864Sharti	RSU_DEV_HT(REALTEK,		RTL8192SU),
116118864Sharti	RSU_DEV_HT(REALTEK,		RTL8712),
11786764Sjlemon	RSU_DEV_HT(REALTEK,		RTL8713),
118118864Sharti	RSU_DEV_HT(SENAO,		RTL8192SU_1),
11996602Srwatson	RSU_DEV_HT(SENAO,		RTL8192SU_2),
12096602Srwatson	RSU_DEV_HT(SITECOMEU,		WL349V1),
12186764Sjlemon	RSU_DEV_HT(SITECOMEU,		WL353),
12288180Sjlemon	RSU_DEV_HT(SWEEX2,		LW154),
12388180Sjlemon#undef RSU_DEV_HT
12488180Sjlemon#undef RSU_DEV
12586764Sjlemon};
12686764Sjlemon
12786764Sjlemonstatic device_probe_t   rsu_match;
12886764Sjlemonstatic device_attach_t  rsu_attach;
12986764Sjlemonstatic device_detach_t  rsu_detach;
13086764Sjlemonstatic usb_callback_t   rsu_bulk_tx_callback;
13186764Sjlemonstatic usb_callback_t   rsu_bulk_rx_callback;
13286764Sjlemonstatic usb_error_t	rsu_do_request(struct rsu_softc *,
13386764Sjlemon			    struct usb_device_request *, void *);
13486764Sjlemonstatic struct ieee80211vap *
13586764Sjlemon		rsu_vap_create(struct ieee80211com *, const char name[],
13686764Sjlemon		    int, enum ieee80211_opmode, int, const uint8_t bssid[],
13786764Sjlemon		    const uint8_t mac[]);
13886764Sjlemonstatic void	rsu_vap_delete(struct ieee80211vap *);
13992760Sjeffstatic void	rsu_scan_start(struct ieee80211com *);
14086764Sjlemonstatic void	rsu_scan_end(struct ieee80211com *);
14186764Sjlemonstatic void	rsu_set_channel(struct ieee80211com *);
14286764Sjlemonstatic void	rsu_update_mcast(struct ifnet *);
14386764Sjlemonstatic int	rsu_alloc_rx_list(struct rsu_softc *);
14486764Sjlemonstatic void	rsu_free_rx_list(struct rsu_softc *);
14586764Sjlemonstatic int	rsu_alloc_tx_list(struct rsu_softc *);
14686764Sjlemonstatic void	rsu_free_tx_list(struct rsu_softc *);
14786764Sjlemonstatic void	rsu_free_list(struct rsu_softc *, struct rsu_data [], int);
14886764Sjlemonstatic struct rsu_data *_rsu_getbuf(struct rsu_softc *);
14986764Sjlemonstatic struct rsu_data *rsu_getbuf(struct rsu_softc *);
15086764Sjlemonstatic int	rsu_write_region_1(struct rsu_softc *, uint16_t, uint8_t *,
15186764Sjlemon		    int);
15286764Sjlemonstatic void	rsu_write_1(struct rsu_softc *, uint16_t, uint8_t);
15386764Sjlemonstatic void	rsu_write_2(struct rsu_softc *, uint16_t, uint16_t);
154121307Ssilbystatic void	rsu_write_4(struct rsu_softc *, uint16_t, uint32_t);
15586764Sjlemonstatic int	rsu_read_region_1(struct rsu_softc *, uint16_t, uint8_t *,
15686764Sjlemon		    int);
157121307Ssilbystatic uint8_t	rsu_read_1(struct rsu_softc *, uint16_t);
15886764Sjlemonstatic uint16_t	rsu_read_2(struct rsu_softc *, uint16_t);
15986764Sjlemonstatic uint32_t	rsu_read_4(struct rsu_softc *, uint16_t);
16086764Sjlemonstatic int	rsu_fw_iocmd(struct rsu_softc *, uint32_t);
16186764Sjlemonstatic uint8_t	rsu_efuse_read_1(struct rsu_softc *, uint16_t);
16286764Sjlemonstatic int	rsu_read_rom(struct rsu_softc *);
163121307Ssilbystatic int	rsu_fw_cmd(struct rsu_softc *, uint8_t, void *, int);
16486764Sjlemonstatic void	rsu_calib_task(void *, int);
16586764Sjlemonstatic int	rsu_newstate(struct ieee80211vap *, enum ieee80211_state, int);
16686764Sjlemon#ifdef notyet
16786764Sjlemonstatic void	rsu_set_key(struct rsu_softc *, const struct ieee80211_key *);
16886764Sjlemonstatic void	rsu_delete_key(struct rsu_softc *, const struct ieee80211_key *);
16986764Sjlemon#endif
17086764Sjlemonstatic int	rsu_site_survey(struct rsu_softc *, struct ieee80211vap *);
17186764Sjlemonstatic int	rsu_join_bss(struct rsu_softc *, struct ieee80211_node *);
17286764Sjlemonstatic int	rsu_disconnect(struct rsu_softc *);
17386764Sjlemonstatic void	rsu_event_survey(struct rsu_softc *, uint8_t *, int);
17486764Sjlemonstatic void	rsu_event_join_bss(struct rsu_softc *, uint8_t *, int);
17586764Sjlemonstatic void	rsu_rx_event(struct rsu_softc *, uint8_t, uint8_t *, int);
17686764Sjlemonstatic void	rsu_rx_multi_event(struct rsu_softc *, uint8_t *, int);
17786764Sjlemonstatic int8_t	rsu_get_rssi(struct rsu_softc *, int, void *);
17886764Sjlemonstatic struct mbuf *
17986764Sjlemon		rsu_rx_frame(struct rsu_softc *, uint8_t *, int, int *);
18086764Sjlemonstatic struct mbuf *
18186764Sjlemon		rsu_rx_multi_frame(struct rsu_softc *, uint8_t *, int, int *);
18286764Sjlemonstatic struct mbuf *
18386764Sjlemon		rsu_rxeof(struct usb_xfer *, struct rsu_data *, int *);
18489667Sjlemonstatic void	rsu_txeof(struct usb_xfer *, struct rsu_data *);
18586764Sjlemonstatic int	rsu_raw_xmit(struct ieee80211_node *, struct mbuf *,
18686764Sjlemon		    const struct ieee80211_bpf_params *);
18786764Sjlemonstatic void	rsu_init(void *);
18886764Sjlemonstatic void	rsu_init_locked(struct rsu_softc *);
18986764Sjlemonstatic void	rsu_watchdog(void *);
19086764Sjlemonstatic int	rsu_tx_start(struct rsu_softc *, struct ieee80211_node *,
19186764Sjlemon		    struct mbuf *, struct rsu_data *);
192106696Salfredstatic void	rsu_start(struct ifnet *);
193106696Salfredstatic void	rsu_start_locked(struct ifnet *);
194106696Salfredstatic int	rsu_ioctl(struct ifnet *, u_long, caddr_t);
195106696Salfredstatic void	rsu_stop(struct ifnet *, int);
196106696Salfredstatic void	rsu_stop_locked(struct ifnet *, int);
197106696Salfred
198106696Salfredstatic device_method_t rsu_methods[] = {
199106696Salfred	DEVMETHOD(device_probe,		rsu_match),
20086764Sjlemon	DEVMETHOD(device_attach,	rsu_attach),
20186764Sjlemon	DEVMETHOD(device_detach,	rsu_detach),
20286764Sjlemon
20386764Sjlemon	DEVMETHOD_END
20486764Sjlemon};
20586764Sjlemon
20686764Sjlemonstatic driver_t rsu_driver = {
207122922Sandre	.name = "rsu",
20892760Sjeff	.methods = rsu_methods,
20986764Sjlemon	.size = sizeof(struct rsu_softc)
21086764Sjlemon};
21186764Sjlemon
21286764Sjlemonstatic devclass_t rsu_devclass;
21386764Sjlemon
21486764SjlemonDRIVER_MODULE(rsu, uhub, rsu_driver, rsu_devclass, NULL, 0);
21586764SjlemonMODULE_DEPEND(rsu, wlan, 1, 1, 1);
21686764SjlemonMODULE_DEPEND(rsu, usb, 1, 1, 1);
21786764SjlemonMODULE_DEPEND(rsu, firmware, 1, 1, 1);
21886764SjlemonMODULE_VERSION(rsu, 1);
21986764Sjlemon
22086764Sjlemonstatic const struct usb_config rsu_config[RSU_N_TRANSFER] = {
22186764Sjlemon	[RSU_BULK_RX] = {
22286764Sjlemon		.type = UE_BULK,
22386764Sjlemon		.endpoint = UE_ADDR_ANY,
22486764Sjlemon		.direction = UE_DIR_IN,
22586764Sjlemon		.bufsize = RSU_RXBUFSZ,
22686764Sjlemon		.flags = {
22786764Sjlemon			.pipe_bof = 1,
22886764Sjlemon			.short_xfer_ok = 1
22986764Sjlemon		},
23086764Sjlemon		.callback = rsu_bulk_rx_callback
23186764Sjlemon	},
23286764Sjlemon	[RSU_BULK_TX_BE] = {
23386764Sjlemon		.type = UE_BULK,
23486764Sjlemon		.endpoint = 0x06,
23586764Sjlemon		.direction = UE_DIR_OUT,
23686764Sjlemon		.bufsize = RSU_TXBUFSZ,
23786764Sjlemon		.flags = {
23886764Sjlemon			.ext_buffer = 1,
239111119Simp			.pipe_bof = 1,
24086764Sjlemon			.force_short_xfer = 1
24186764Sjlemon		},
24286764Sjlemon		.callback = rsu_bulk_tx_callback,
24386764Sjlemon		.timeout = RSU_TX_TIMEOUT
24486764Sjlemon	},
24586764Sjlemon	[RSU_BULK_TX_BK] = {
24686764Sjlemon		.type = UE_BULK,
24786764Sjlemon		.endpoint = 0x06,
24886814Sbde		.direction = UE_DIR_OUT,
24986764Sjlemon		.bufsize = RSU_TXBUFSZ,
250122449Ssam		.flags = {
251122449Ssam			.ext_buffer = 1,
25286764Sjlemon			.pipe_bof = 1,
25386764Sjlemon			.force_short_xfer = 1
25486764Sjlemon		},
25586764Sjlemon		.callback = rsu_bulk_tx_callback,
25686764Sjlemon		.timeout = RSU_TX_TIMEOUT
25786764Sjlemon	},
25886764Sjlemon	[RSU_BULK_TX_VI] = {
25992760Sjeff		.type = UE_BULK,
26092760Sjeff		.endpoint = 0x04,
26192760Sjeff		.direction = UE_DIR_OUT,
262124848Sandre		.bufsize = RSU_TXBUFSZ,
26386764Sjlemon		.flags = {
26486764Sjlemon			.ext_buffer = 1,
26588180Sjlemon			.pipe_bof = 1,
26686764Sjlemon			.force_short_xfer = 1
26786764Sjlemon		},
26886764Sjlemon		.callback = rsu_bulk_tx_callback,
26986764Sjlemon		.timeout = RSU_TX_TIMEOUT
27086764Sjlemon	},
271122496Ssam	[RSU_BULK_TX_VO] = {
27286764Sjlemon		.type = UE_BULK,
273122496Ssam		.endpoint = 0x04,
274122496Ssam		.direction = UE_DIR_OUT,
27586764Sjlemon		.bufsize = RSU_TXBUFSZ,
27686764Sjlemon		.flags = {
27786764Sjlemon			.ext_buffer = 1,
27886764Sjlemon			.pipe_bof = 1,
27986764Sjlemon			.force_short_xfer = 1
28086764Sjlemon		},
28186764Sjlemon		.callback = rsu_bulk_tx_callback,
28286764Sjlemon		.timeout = RSU_TX_TIMEOUT
28386764Sjlemon	},
28488180Sjlemon};
28586764Sjlemon
28686764Sjlemonstatic int
28786764Sjlemonrsu_match(device_t self)
28886764Sjlemon{
28986764Sjlemon	struct usb_attach_arg *uaa = device_get_ivars(self);
29086764Sjlemon
29186764Sjlemon	if (uaa->usb_mode != USB_MODE_HOST ||
29286764Sjlemon	    uaa->info.bIfaceIndex != 0 ||
29386764Sjlemon	    uaa->info.bConfigIndex != 0)
29486764Sjlemon		return (ENXIO);
29586764Sjlemon
29686764Sjlemon	return (usbd_lookup_id_by_uaa(rsu_devs, sizeof(rsu_devs), uaa));
29786764Sjlemon}
29886764Sjlemon
29988180Sjlemonstatic int
30086764Sjlemonrsu_attach(device_t self)
30186764Sjlemon{
30286764Sjlemon	struct usb_attach_arg *uaa = device_get_ivars(self);
30386764Sjlemon	struct rsu_softc *sc = device_get_softc(self);
30486764Sjlemon	struct ifnet *ifp;
30586764Sjlemon	struct ieee80211com *ic;
30686764Sjlemon	int error;
30786764Sjlemon	uint8_t iface_index, bands;
30886764Sjlemon
30986764Sjlemon	device_set_usb_desc(self);
31086764Sjlemon	sc->sc_udev = uaa->device;
31186764Sjlemon	sc->sc_dev = self;
31286764Sjlemon
31386764Sjlemon	mtx_init(&sc->sc_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK,
31486764Sjlemon	    MTX_DEF);
31586764Sjlemon	TIMEOUT_TASK_INIT(taskqueue_thread, &sc->calib_task, 0,
31686764Sjlemon	    rsu_calib_task, sc);
31786764Sjlemon	callout_init(&sc->sc_watchdog_ch, 0);
31886764Sjlemon
319122496Ssam	iface_index = 0;
32086764Sjlemon	error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
32186764Sjlemon	    rsu_config, RSU_N_TRANSFER, sc, &sc->sc_mtx);
32286764Sjlemon	if (error) {
32386764Sjlemon		device_printf(sc->sc_dev,
32486764Sjlemon		    "could not allocate USB transfers, err=%s\n",
32586764Sjlemon		    usbd_errstr(error));
32686764Sjlemon		goto fail_usb;
32786764Sjlemon	}
32886764Sjlemon	RSU_LOCK(sc);
32986764Sjlemon	/* Read chip revision. */
33086764Sjlemon	sc->cut = MS(rsu_read_4(sc, R92S_PMC_FSM), R92S_PMC_FSM_CUT);
33186764Sjlemon	if (sc->cut != 3)
33286764Sjlemon		sc->cut = (sc->cut >> 1) + 1;
33386764Sjlemon	error = rsu_read_rom(sc);
33486764Sjlemon	if (error != 0) {
33586764Sjlemon		device_printf(self, "could not read ROM\n");
33686764Sjlemon		goto fail_rom;
33786764Sjlemon	}
33886764Sjlemon	RSU_UNLOCK(sc);
33986764Sjlemon	IEEE80211_ADDR_COPY(sc->sc_bssid, &sc->rom[0x12]);
34086764Sjlemon	device_printf(self, "MAC/BB RTL8712 cut %d\n", sc->cut);
34186764Sjlemon	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
34286764Sjlemon	if (ifp == NULL) {
34386764Sjlemon		device_printf(self, "cannot allocate interface\n");
34486764Sjlemon		goto fail_ifalloc;
34586764Sjlemon	}
34686764Sjlemon	ic = ifp->if_l2com;
34786764Sjlemon	ifp->if_softc = sc;
34886764Sjlemon	if_initname(ifp, "rsu", device_get_unit(self));
34986764Sjlemon	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
35086764Sjlemon	ifp->if_init = rsu_init;
35186764Sjlemon	ifp->if_ioctl = rsu_ioctl;
35286764Sjlemon	ifp->if_start = rsu_start;
35388195Sjlemon	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
35486764Sjlemon	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
35586764Sjlemon	IFQ_SET_READY(&ifp->if_snd);
35686764Sjlemon	ifp->if_capabilities |= IFCAP_RXCSUM;
357110737Shsu	ifp->if_capenable |= IFCAP_RXCSUM;
35886764Sjlemon	ifp->if_hwassist = CSUM_TCP;
35986764Sjlemon
360122496Ssam	ic->ic_ifp = ifp;
361122501Ssam	ic->ic_phytype = IEEE80211_T_OFDM;	/* Not only, but not used. */
36286764Sjlemon	ic->ic_opmode = IEEE80211_M_STA;	/* Default to BSS mode. */
36386764Sjlemon
36486764Sjlemon	/* Set device capabilities. */
36586764Sjlemon	ic->ic_caps =
36686764Sjlemon	    IEEE80211_C_STA |		/* station mode */
36786764Sjlemon	    IEEE80211_C_BGSCAN |	/* Background scan. */
36886764Sjlemon	    IEEE80211_C_SHPREAMBLE |	/* Short preamble supported. */
36986764Sjlemon	    IEEE80211_C_SHSLOT |	/* Short slot time supported. */
37086764Sjlemon	    IEEE80211_C_WPA;		/* WPA/RSN. */
37186764Sjlemon
37286764Sjlemon#if 0
37386764Sjlemon	/* Check if HT support is present. */
374108703Shsu	if (usb_lookup(rsu_devs_noht, uaa->vendor, uaa->product) == NULL) {
37598982Sjlemon		/* Set HT capabilities. */
37686764Sjlemon		ic->ic_htcaps =
37786764Sjlemon		    IEEE80211_HTCAP_CBW20_40 |
37886764Sjlemon		    IEEE80211_HTCAP_DSSSCCK40;
37986764Sjlemon		/* Set supported HT rates. */
38098982Sjlemon		for (i = 0; i < 2; i++)
38198982Sjlemon			ic->ic_sup_mcs[i] = 0xff;
38298982Sjlemon	}
38398982Sjlemon#endif
38498982Sjlemon
385118864Sharti	/* Set supported .11b and .11g rates. */
386118864Sharti	bands = 0;
387118864Sharti	setbit(&bands, IEEE80211_MODE_11B);
38886764Sjlemon	setbit(&bands, IEEE80211_MODE_11G);
389118864Sharti	ieee80211_init_channels(ic, NULL, &bands);
39098982Sjlemon
39186764Sjlemon	ieee80211_ifattach(ic, sc->sc_bssid);
39286764Sjlemon	ic->ic_raw_xmit = rsu_raw_xmit;
39386764Sjlemon	ic->ic_scan_start = rsu_scan_start;
39486764Sjlemon	ic->ic_scan_end = rsu_scan_end;
39586764Sjlemon	ic->ic_set_channel = rsu_set_channel;
39686764Sjlemon	ic->ic_vap_create = rsu_vap_create;
39786764Sjlemon	ic->ic_vap_delete = rsu_vap_delete;
398122501Ssam	ic->ic_update_mcast = rsu_update_mcast;
39986764Sjlemon
40086764Sjlemon	ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr,
40186764Sjlemon	    sizeof(sc->sc_txtap), RSU_TX_RADIOTAP_PRESENT,
40286764Sjlemon	    &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap),
40386764Sjlemon	    RSU_RX_RADIOTAP_PRESENT);
40486764Sjlemon
40586764Sjlemon	if (bootverbose)
40686764Sjlemon		ieee80211_announce(ic);
40786764Sjlemon
40886764Sjlemon	return (0);
40986764Sjlemon
41086764Sjlemonfail_ifalloc:
41186764Sjlemonfail_rom:
412122496Ssam	usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER);
413122496Ssamfail_usb:
41486764Sjlemon	mtx_destroy(&sc->sc_mtx);
41586764Sjlemon	return (ENXIO);
41686764Sjlemon}
41786764Sjlemon
41886764Sjlemonstatic int
41986764Sjlemonrsu_detach(device_t self)
420122496Ssam{
42186764Sjlemon	struct rsu_softc *sc = device_get_softc(self);
42286764Sjlemon	struct ifnet *ifp = sc->sc_ifp;
42386764Sjlemon	struct ieee80211com *ic = ifp->if_l2com;
42486764Sjlemon
42586764Sjlemon	if (!device_is_attached(self))
42686764Sjlemon		return (0);
42786764Sjlemon	rsu_stop(ifp, 1);
42886764Sjlemon	usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER);
42986764Sjlemon	ieee80211_ifdetach(ic);
43086764Sjlemon
43186764Sjlemon	callout_drain(&sc->sc_watchdog_ch);
43286764Sjlemon	taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task);
43386764Sjlemon
434122496Ssam	/* Free Tx/Rx buffers. */
43586764Sjlemon	rsu_free_tx_list(sc);
43686764Sjlemon	rsu_free_rx_list(sc);
43786764Sjlemon
43886764Sjlemon	if_free(ifp);
43986764Sjlemon	mtx_destroy(&sc->sc_mtx);
44086764Sjlemon
44186764Sjlemon	return (0);
44286764Sjlemon}
44386764Sjlemon
44486764Sjlemonstatic usb_error_t
44586764Sjlemonrsu_do_request(struct rsu_softc *sc, struct usb_device_request *req,
44686764Sjlemon    void *data)
44786764Sjlemon{
44886764Sjlemon	usb_error_t err;
44986764Sjlemon	int ntries = 10;
45086764Sjlemon
45186764Sjlemon	RSU_ASSERT_LOCKED(sc);
45286764Sjlemon
45386764Sjlemon	while (ntries--) {
454122496Ssam		err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx,
455122496Ssam		    req, data, 0, NULL, 250 /* ms */);
45686764Sjlemon		if (err == 0 || !device_is_attached(sc->sc_dev))
45786764Sjlemon			break;
45886764Sjlemon		DPRINTFN(1, "Control request failed, %s (retrying)\n",
45986764Sjlemon		    usbd_errstr(err));
46086764Sjlemon		usb_pause_mtx(&sc->sc_mtx, hz / 100);
46186764Sjlemon        }
46286764Sjlemon
46386764Sjlemon        return (err);
46486764Sjlemon}
46586764Sjlemon
46686764Sjlemonstatic struct ieee80211vap *
46786764Sjlemonrsu_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
46886764Sjlemon    enum ieee80211_opmode opmode, int flags,
46986764Sjlemon    const uint8_t bssid[IEEE80211_ADDR_LEN],
47086764Sjlemon    const uint8_t mac[IEEE80211_ADDR_LEN])
47186764Sjlemon{
47286764Sjlemon	struct rsu_vap *uvp;
47386764Sjlemon	struct ieee80211vap *vap;
47486764Sjlemon
47586764Sjlemon	if (!TAILQ_EMPTY(&ic->ic_vaps))         /* only one at a time */
47686764Sjlemon		return (NULL);
47786764Sjlemon
47886764Sjlemon	uvp = (struct rsu_vap *) malloc(sizeof(struct rsu_vap),
47986764Sjlemon	    M_80211_VAP, M_NOWAIT | M_ZERO);
48086764Sjlemon	if (uvp == NULL)
48186764Sjlemon		return (NULL);
48286764Sjlemon	vap = &uvp->vap;
48386764Sjlemon
48486764Sjlemon	if (ieee80211_vap_setup(ic, vap, name, unit, opmode,
48586764Sjlemon	    flags, bssid, mac) != 0) {
486122496Ssam		/* out of memory */
487122496Ssam		free(uvp, M_80211_VAP);
48886764Sjlemon		return (NULL);
48986764Sjlemon	}
49086764Sjlemon
49186764Sjlemon	/* override state transition machine */
49286764Sjlemon	uvp->newstate = vap->iv_newstate;
49386764Sjlemon	vap->iv_newstate = rsu_newstate;
49486764Sjlemon
49586764Sjlemon	/* complete setup */
49686764Sjlemon	ieee80211_vap_attach(vap, ieee80211_media_change,
49786764Sjlemon	    ieee80211_media_status);
49886764Sjlemon	ic->ic_opmode = opmode;
49986764Sjlemon
50086764Sjlemon	return (vap);
50186764Sjlemon}
50286764Sjlemon
503122496Ssamstatic void
504122496Ssamrsu_vap_delete(struct ieee80211vap *vap)
50586764Sjlemon{
50686764Sjlemon	struct rsu_vap *uvp = RSU_VAP(vap);
50786764Sjlemon
50886764Sjlemon	ieee80211_vap_detach(vap);
50986764Sjlemon	free(uvp, M_80211_VAP);
51086764Sjlemon}
51186764Sjlemon
51286764Sjlemonstatic void
51386764Sjlemonrsu_scan_start(struct ieee80211com *ic)
51486764Sjlemon{
51586764Sjlemon	int error;
51686764Sjlemon	struct ifnet *ifp = ic->ic_ifp;
51786764Sjlemon	struct rsu_softc *sc = ifp->if_softc;
51886764Sjlemon
51986764Sjlemon	/* Scanning is done by the firmware. */
52086764Sjlemon	RSU_LOCK(sc);
52186764Sjlemon	error = rsu_site_survey(sc, TAILQ_FIRST(&ic->ic_vaps));
52286764Sjlemon	RSU_UNLOCK(sc);
52386764Sjlemon	if (error != 0)
52486764Sjlemon		device_printf(sc->sc_dev,
52586764Sjlemon		    "could not send site survey command\n");
52686764Sjlemon}
52786764Sjlemon
52886764Sjlemonstatic void
52986764Sjlemonrsu_scan_end(struct ieee80211com *ic)
53086764Sjlemon{
53186764Sjlemon	/* Nothing to do here. */
53286764Sjlemon}
53386764Sjlemon
53496602Srwatsonstatic void
53586764Sjlemonrsu_set_channel(struct ieee80211com *ic __unused)
53686764Sjlemon{
53796602Srwatson	/* We are unable to switch channels, yet. */
53886764Sjlemon}
53986764Sjlemon
54086764Sjlemonstatic void
54186764Sjlemonrsu_update_mcast(struct ifnet *ifp)
54286764Sjlemon{
543122496Ssam        /* XXX do nothing?  */
544122496Ssam}
545122496Ssam
54686764Sjlemonstatic int
54786764Sjlemonrsu_alloc_list(struct rsu_softc *sc, struct rsu_data data[],
54886764Sjlemon    int ndata, int maxsz)
54986764Sjlemon{
55086764Sjlemon	int i, error;
55186764Sjlemon
55286764Sjlemon	for (i = 0; i < ndata; i++) {
55386764Sjlemon		struct rsu_data *dp = &data[i];
55486764Sjlemon		dp->sc = sc;
55586764Sjlemon		dp->m = NULL;
55686764Sjlemon		dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT);
55786764Sjlemon		if (dp->buf == NULL) {
55886764Sjlemon			device_printf(sc->sc_dev,
559122496Ssam			    "could not allocate buffer\n");
56086764Sjlemon			error = ENOMEM;
561101106Srwatson			goto fail;
562101106Srwatson		}
563101106Srwatson		dp->ni = NULL;
56486764Sjlemon	}
56586764Sjlemon
566122496Ssam	return (0);
56786764Sjlemonfail:
56886764Sjlemon	rsu_free_list(sc, data, ndata);
56986764Sjlemon	return (error);
57086764Sjlemon}
57191492Sume
57286764Sjlemonstatic int
57386764Sjlemonrsu_alloc_rx_list(struct rsu_softc *sc)
57486764Sjlemon{
57586764Sjlemon        int error, i;
57686764Sjlemon
57786764Sjlemon	error = rsu_alloc_list(sc, sc->sc_rx, RSU_RX_LIST_COUNT,
57886764Sjlemon	    RSU_RXBUFSZ);
57986764Sjlemon	if (error != 0)
58086764Sjlemon		return (error);
58186764Sjlemon
58286764Sjlemon	STAILQ_INIT(&sc->sc_rx_active);
58386764Sjlemon	STAILQ_INIT(&sc->sc_rx_inactive);
58486764Sjlemon
58586764Sjlemon	for (i = 0; i < RSU_RX_LIST_COUNT; i++)
58686764Sjlemon		STAILQ_INSERT_HEAD(&sc->sc_rx_inactive, &sc->sc_rx[i], next);
58786764Sjlemon
58886764Sjlemon	return (0);
58986764Sjlemon}
59086764Sjlemon
59186764Sjlemonstatic int
59286764Sjlemonrsu_alloc_tx_list(struct rsu_softc *sc)
59386764Sjlemon{
59486764Sjlemon	int error, i;
59586764Sjlemon
59686764Sjlemon	error = rsu_alloc_list(sc, sc->sc_tx, RSU_TX_LIST_COUNT,
59786764Sjlemon	    RSU_TXBUFSZ);
59886764Sjlemon	if (error != 0)
59986764Sjlemon		return (error);
600122062Sume
601122062Sume	STAILQ_INIT(&sc->sc_tx_active);
602122062Sume	STAILQ_INIT(&sc->sc_tx_inactive);
603122062Sume	STAILQ_INIT(&sc->sc_tx_pending);
604122062Sume
60586764Sjlemon	for (i = 0; i < RSU_TX_LIST_COUNT; i++) {
60686764Sjlemon		STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i], next);
60786764Sjlemon	}
60886764Sjlemon
60986764Sjlemon	return (0);
61086764Sjlemon}
61186764Sjlemon
612124847Sandrestatic void
61386764Sjlemonrsu_free_tx_list(struct rsu_softc *sc)
61486764Sjlemon{
61586764Sjlemon	rsu_free_list(sc, sc->sc_tx, RSU_TX_LIST_COUNT);
61686764Sjlemon}
61786764Sjlemon
61886764Sjlemonstatic void
61986764Sjlemonrsu_free_rx_list(struct rsu_softc *sc)
62086764Sjlemon{
62186764Sjlemon	rsu_free_list(sc, sc->sc_rx, RSU_RX_LIST_COUNT);
62286764Sjlemon}
62386764Sjlemon
62486764Sjlemonstatic void
62586764Sjlemonrsu_free_list(struct rsu_softc *sc, struct rsu_data data[], int ndata)
62686764Sjlemon{
627124847Sandre	int i;
628124847Sandre
629124847Sandre	for (i = 0; i < ndata; i++) {
630124847Sandre		struct rsu_data *dp = &data[i];
631124847Sandre
63286764Sjlemon		if (dp->buf != NULL) {
63386764Sjlemon			free(dp->buf, M_USBDEV);
63486764Sjlemon			dp->buf = NULL;
635124847Sandre		}
63686764Sjlemon		if (dp->ni != NULL) {
63786764Sjlemon			ieee80211_free_node(dp->ni);
63886764Sjlemon			dp->ni = NULL;
63986764Sjlemon		}
64086764Sjlemon	}
64186764Sjlemon}
64286764Sjlemon
643124847Sandrestatic struct rsu_data *
64486764Sjlemon_rsu_getbuf(struct rsu_softc *sc)
64586764Sjlemon{
64686764Sjlemon	struct rsu_data *bf;
64786764Sjlemon
64886764Sjlemon	bf = STAILQ_FIRST(&sc->sc_tx_inactive);
64986764Sjlemon	if (bf != NULL)
65086764Sjlemon		STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next);
651124847Sandre	else
652124847Sandre		bf = NULL;
653124847Sandre	if (bf == NULL)
654124847Sandre		DPRINTF("out of xmit buffers\n");
655124847Sandre        return (bf);
65686764Sjlemon}
65786764Sjlemon
65886764Sjlemonstatic struct rsu_data *
659124847Sandrersu_getbuf(struct rsu_softc *sc)
66086764Sjlemon{
66186764Sjlemon	struct rsu_data *bf;
66286764Sjlemon
66386764Sjlemon	RSU_ASSERT_LOCKED(sc);
66486764Sjlemon
66586764Sjlemon	bf = _rsu_getbuf(sc);
66686764Sjlemon	if (bf == NULL) {
66786764Sjlemon		struct ifnet *ifp = sc->sc_ifp;
66886764Sjlemon		DPRINTF("stop queue\n");
66986764Sjlemon		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
67086764Sjlemon	}
67186764Sjlemon	return (bf);
67286764Sjlemon}
67386764Sjlemon
67486764Sjlemonstatic int
67586764Sjlemonrsu_write_region_1(struct rsu_softc *sc, uint16_t addr, uint8_t *buf,
67690982Sjlemon    int len)
67786764Sjlemon{
67886764Sjlemon	usb_device_request_t req;
67986764Sjlemon
68086764Sjlemon	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
68186764Sjlemon	req.bRequest = R92S_REQ_REGS;
68286764Sjlemon	USETW(req.wValue, addr);
68386764Sjlemon	USETW(req.wIndex, 0);
68486764Sjlemon	USETW(req.wLength, len);
68586764Sjlemon
68686764Sjlemon	return (rsu_do_request(sc, &req, buf));
68786764Sjlemon}
68886764Sjlemon
68986764Sjlemonstatic void
69086764Sjlemonrsu_write_1(struct rsu_softc *sc, uint16_t addr, uint8_t val)
69186764Sjlemon{
69286764Sjlemon	rsu_write_region_1(sc, addr, &val, 1);
69386764Sjlemon}
69486764Sjlemon
69586764Sjlemonstatic void
69686764Sjlemonrsu_write_2(struct rsu_softc *sc, uint16_t addr, uint16_t val)
69786764Sjlemon{
69886764Sjlemon	val = htole16(val);
699125680Sbms	rsu_write_region_1(sc, addr, (uint8_t *)&val, 2);
700125680Sbms}
701125680Sbms
702125783Sbmsstatic void
70386764Sjlemonrsu_write_4(struct rsu_softc *sc, uint16_t addr, uint32_t val)
704122922Sandre{
705122922Sandre	val = htole32(val);
706122922Sandre	rsu_write_region_1(sc, addr, (uint8_t *)&val, 4);
707122922Sandre}
70886764Sjlemon
70986764Sjlemonstatic int
71086764Sjlemonrsu_read_region_1(struct rsu_softc *sc, uint16_t addr, uint8_t *buf,
71186764Sjlemon    int len)
71286764Sjlemon{
71386764Sjlemon	usb_device_request_t req;
71486764Sjlemon
71586764Sjlemon	req.bmRequestType = UT_READ_VENDOR_DEVICE;
71686764Sjlemon	req.bRequest = R92S_REQ_REGS;
717122496Ssam	USETW(req.wValue, addr);
718122496Ssam	USETW(req.wIndex, 0);
71986764Sjlemon	USETW(req.wLength, len);
72086764Sjlemon
72186764Sjlemon	return (rsu_do_request(sc, &req, buf));
72286764Sjlemon}
723122496Ssam
724122496Ssamstatic uint8_t
72586764Sjlemonrsu_read_1(struct rsu_softc *sc, uint16_t addr)
72686764Sjlemon{
72786764Sjlemon	uint8_t val;
72886764Sjlemon
72986764Sjlemon	if (rsu_read_region_1(sc, addr, &val, 1) != 0)
73086764Sjlemon		return (0xff);
73186764Sjlemon	return (val);
73286764Sjlemon}
73386764Sjlemon
73486764Sjlemonstatic uint16_t
73586764Sjlemonrsu_read_2(struct rsu_softc *sc, uint16_t addr)
73686764Sjlemon{
73786764Sjlemon	uint16_t val;
73886764Sjlemon
73986764Sjlemon	if (rsu_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0)
74086764Sjlemon		return (0xffff);
74186764Sjlemon	return (le16toh(val));
74286764Sjlemon}
74386764Sjlemon
74486764Sjlemonstatic uint32_t
74586764Sjlemonrsu_read_4(struct rsu_softc *sc, uint16_t addr)
74686764Sjlemon{
74786764Sjlemon	uint32_t val;
748122496Ssam
749122496Ssam	if (rsu_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0)
75086764Sjlemon		return (0xffffffff);
75188180Sjlemon	return (le32toh(val));
75288180Sjlemon}
75388180Sjlemon
75488180Sjlemonstatic int
75588180Sjlemonrsu_fw_iocmd(struct rsu_softc *sc, uint32_t iocmd)
75688180Sjlemon{
75788180Sjlemon	int ntries;
75888180Sjlemon
75988180Sjlemon	rsu_write_4(sc, R92S_IOCMD_CTRL, iocmd);
76088180Sjlemon	DELAY(100);
76188180Sjlemon	for (ntries = 0; ntries < 50; ntries++) {
76288180Sjlemon		if (rsu_read_4(sc, R92S_IOCMD_CTRL) == 0)
76388180Sjlemon			return (0);
76488180Sjlemon		DELAY(10);
76588180Sjlemon	}
76688180Sjlemon	return (ETIMEDOUT);
76788180Sjlemon}
76888180Sjlemon
76986764Sjlemonstatic uint8_t
77086764Sjlemonrsu_efuse_read_1(struct rsu_softc *sc, uint16_t addr)
77186764Sjlemon{
77286764Sjlemon	uint32_t reg;
77386764Sjlemon	int ntries;
77486764Sjlemon
77586764Sjlemon	reg = rsu_read_4(sc, R92S_EFUSE_CTRL);
77696602Srwatson	reg = RW(reg, R92S_EFUSE_CTRL_ADDR, addr);
77786764Sjlemon	reg &= ~R92S_EFUSE_CTRL_VALID;
77886764Sjlemon	rsu_write_4(sc, R92S_EFUSE_CTRL, reg);
77986764Sjlemon	/* Wait for read operation to complete. */
78086764Sjlemon	for (ntries = 0; ntries < 100; ntries++) {
78186764Sjlemon		reg = rsu_read_4(sc, R92S_EFUSE_CTRL);
78286764Sjlemon		if (reg & R92S_EFUSE_CTRL_VALID)
78386764Sjlemon			return (MS(reg, R92S_EFUSE_CTRL_DATA));
78486764Sjlemon		DELAY(5);
78586764Sjlemon	}
786122922Sandre	device_printf(sc->sc_dev,
78786764Sjlemon	    "could not read efuse byte at address 0x%x\n", addr);
788122922Sandre	return (0xff);
78986764Sjlemon}
79086764Sjlemon
79186764Sjlemonstatic int
79286764Sjlemonrsu_read_rom(struct rsu_softc *sc)
79386764Sjlemon{
79486764Sjlemon	uint8_t *rom = sc->rom;
79586764Sjlemon	uint16_t addr = 0;
79686764Sjlemon	uint32_t reg;
79786764Sjlemon	uint8_t off, msk;
79886764Sjlemon	int i;
79986764Sjlemon
80086764Sjlemon	/* Make sure that ROM type is eFuse and that autoload succeeded. */
80186764Sjlemon	reg = rsu_read_1(sc, R92S_EE_9346CR);
80286764Sjlemon	if ((reg & (R92S_9356SEL | R92S_EEPROM_EN)) != R92S_EEPROM_EN)
80386764Sjlemon		return (EIO);
80486764Sjlemon
80586764Sjlemon	/* Turn on 2.5V to prevent eFuse leakage. */
80686764Sjlemon	reg = rsu_read_1(sc, R92S_EFUSE_TEST + 3);
80786764Sjlemon	rsu_write_1(sc, R92S_EFUSE_TEST + 3, reg | 0x80);
80886764Sjlemon	DELAY(1000);
80986764Sjlemon	rsu_write_1(sc, R92S_EFUSE_TEST + 3, reg & ~0x80);
81086764Sjlemon
81186764Sjlemon	/* Read full ROM image. */
81286764Sjlemon	memset(&sc->rom, 0xff, sizeof(sc->rom));
81386764Sjlemon	while (addr < 512) {
81486764Sjlemon		reg = rsu_efuse_read_1(sc, addr);
81586764Sjlemon		if (reg == 0xff)
81686764Sjlemon			break;
81786764Sjlemon		addr++;
81886764Sjlemon		off = reg >> 4;
81986764Sjlemon		msk = reg & 0xf;
82086764Sjlemon		for (i = 0; i < 4; i++) {
82186764Sjlemon			if (msk & (1 << i))
82286764Sjlemon				continue;
823122922Sandre			rom[off * 8 + i * 2 + 0] =
824122496Ssam			    rsu_efuse_read_1(sc, addr);
82586764Sjlemon			addr++;
826122496Ssam			rom[off * 8 + i * 2 + 1] =
827122496Ssam			    rsu_efuse_read_1(sc, addr);
82886764Sjlemon			addr++;
82986764Sjlemon		}
830122922Sandre	}
83186764Sjlemon#ifdef USB_DEBUG
83286764Sjlemon	if (rsu_debug >= 5) {
83386764Sjlemon		/* Dump ROM content. */
83486764Sjlemon		printf("\n");
83586764Sjlemon		for (i = 0; i < sizeof(sc->rom); i++)
83686764Sjlemon			printf("%02x:", rom[i]);
83786764Sjlemon		printf("\n");
83886764Sjlemon	}
83986764Sjlemon#endif
84086764Sjlemon	return (0);
84186764Sjlemon}
84286764Sjlemon
84386764Sjlemonstatic int
84486764Sjlemonrsu_fw_cmd(struct rsu_softc *sc, uint8_t code, void *buf, int len)
84586764Sjlemon{
84686764Sjlemon	struct rsu_data *data;
84786764Sjlemon	struct r92s_tx_desc *txd;
84886764Sjlemon	struct r92s_fw_cmd_hdr *cmd;
84986764Sjlemon	int cmdsz, xferlen;
85086764Sjlemon
85186764Sjlemon	data = rsu_getbuf(sc);
85286764Sjlemon	if (data == NULL)
85386764Sjlemon		return (ENOMEM);
85486764Sjlemon
85586764Sjlemon	/* Round-up command length to a multiple of 8 bytes. */
85686764Sjlemon	cmdsz = (len + 7) & ~7;
85786764Sjlemon
85886764Sjlemon	xferlen = sizeof(*txd) + sizeof(*cmd) + cmdsz;
85986764Sjlemon	KASSERT(xferlen <= RSU_TXBUFSZ, ("%s: invalid length", __func__));
86086764Sjlemon	memset(data->buf, 0, xferlen);
86186764Sjlemon
86286764Sjlemon	/* Setup Tx descriptor. */
86386764Sjlemon	txd = (struct r92s_tx_desc *)data->buf;
86486764Sjlemon	txd->txdw0 = htole32(
86590556Sjlemon	    SM(R92S_TXDW0_OFFSET, sizeof(*txd)) |
86690556Sjlemon	    SM(R92S_TXDW0_PKTLEN, sizeof(*cmd) + cmdsz) |
86790556Sjlemon	    R92S_TXDW0_OWN | R92S_TXDW0_FSG | R92S_TXDW0_LSG);
86890556Sjlemon	txd->txdw1 = htole32(SM(R92S_TXDW1_QSEL, R92S_TXDW1_QSEL_H2C));
86990556Sjlemon
870118864Sharti	/* Setup command header. */
871118864Sharti	cmd = (struct r92s_fw_cmd_hdr *)&txd[1];
872118864Sharti	cmd->len = htole16(cmdsz);
87386764Sjlemon	cmd->code = code;
874118864Sharti	cmd->seq = sc->cmd_seq;
875122496Ssam	sc->cmd_seq = (sc->cmd_seq + 1) & 0x7f;
87686764Sjlemon
87786764Sjlemon	/* Copy command payload. */
87886764Sjlemon	memcpy(&cmd[1], buf, len);
87986764Sjlemon
88086764Sjlemon	DPRINTFN(2, "Tx cmd code=0x%x len=0x%x\n", code, cmdsz);
88186764Sjlemon	data->buflen = xferlen;
88286764Sjlemon	STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
88386764Sjlemon	usbd_transfer_start(sc->sc_xfer[RSU_BULK_TX_VO]);
88486764Sjlemon
88586764Sjlemon	return (0);
88692760Sjeff}
88786764Sjlemon
88886764Sjlemon/* ARGSUSED */
88986764Sjlemonstatic void
89086764Sjlemonrsu_calib_task(void *arg, int pending __unused)
89186764Sjlemon{
89286764Sjlemon	struct rsu_softc *sc = arg;
893122496Ssam	uint32_t reg;
89486764Sjlemon
89586764Sjlemon	DPRINTFN(6, "running calibration task\n");
89686764Sjlemon	RSU_LOCK(sc);
89786764Sjlemon#ifdef notyet
89886764Sjlemon	/* Read WPS PBC status. */
89988180Sjlemon	rsu_write_1(sc, R92S_MAC_PINMUX_CTRL,
90086764Sjlemon	    R92S_GPIOMUX_EN | SM(R92S_GPIOSEL_GPIO, R92S_GPIOSEL_GPIO_JTAG));
90186764Sjlemon	rsu_write_1(sc, R92S_GPIO_IO_SEL,
90292760Sjeff	    rsu_read_1(sc, R92S_GPIO_IO_SEL) & ~R92S_GPIO_WPS);
90386764Sjlemon	reg = rsu_read_1(sc, R92S_GPIO_CTRL);
90486764Sjlemon	if (reg != 0xff && (reg & R92S_GPIO_WPS))
90586764Sjlemon		DPRINTF(("WPS PBC is pushed\n"));
90686764Sjlemon#endif
90786764Sjlemon	/* Read current signal level. */
90886764Sjlemon	if (rsu_fw_iocmd(sc, 0xf4000001) == 0) {
90986764Sjlemon		reg = rsu_read_4(sc, R92S_IOCMD_DATA);
91086764Sjlemon		DPRINTFN(8, "RSSI=%d%%\n", reg >> 4);
91186764Sjlemon	}
91286764Sjlemon	if (sc->sc_calibrating) {
91386958Stanimura		RSU_UNLOCK(sc);
91486764Sjlemon		taskqueue_enqueue_timeout(taskqueue_thread, &sc->calib_task,
91586764Sjlemon		    hz * 2);
91686764Sjlemon	} else
91786764Sjlemon		RSU_UNLOCK(sc);
91886764Sjlemon}
91986764Sjlemon
92086764Sjlemonstatic int
92186764Sjlemonrsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
92286764Sjlemon{
92386764Sjlemon	struct rsu_vap *uvp = RSU_VAP(vap);
92486764Sjlemon	struct ieee80211com *ic = vap->iv_ic;
92586764Sjlemon	struct rsu_softc *sc = ic->ic_ifp->if_softc;
92686764Sjlemon	struct ieee80211_node *ni;
92786764Sjlemon	struct ieee80211_rateset *rs;
92886764Sjlemon	enum ieee80211_state ostate;
92986764Sjlemon	int error, startcal = 0;
93086764Sjlemon
931110023Ssilby	ostate = vap->iv_state;
932110023Ssilby	DPRINTF("%s -> %s\n", ieee80211_state_name[ostate],
93388330Sjlemon	    ieee80211_state_name[nstate]);
93488330Sjlemon
93588330Sjlemon	IEEE80211_UNLOCK(ic);
93688330Sjlemon	if (ostate == IEEE80211_S_RUN) {
93786764Sjlemon		RSU_LOCK(sc);
93886764Sjlemon		/* Stop calibration. */
93986764Sjlemon		sc->sc_calibrating = 0;
94086764Sjlemon		RSU_UNLOCK(sc);
94186764Sjlemon		taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task);
94286764Sjlemon		/* Disassociate from our current BSS. */
94386764Sjlemon		RSU_LOCK(sc);
94486764Sjlemon		rsu_disconnect(sc);
94586764Sjlemon	} else
94686764Sjlemon		RSU_LOCK(sc);
94786764Sjlemon	switch (nstate) {
94886764Sjlemon	case IEEE80211_S_INIT:
94986764Sjlemon		break;
95086764Sjlemon	case IEEE80211_S_AUTH:
95186764Sjlemon		ni = ieee80211_ref_node(vap->iv_bss);
95286764Sjlemon		error = rsu_join_bss(sc, ni);
95386764Sjlemon		ieee80211_free_node(ni);
95486764Sjlemon		if (error != 0) {
95586764Sjlemon			device_printf(sc->sc_dev,
95686764Sjlemon			    "could not send join command\n");
95786764Sjlemon		}
95886764Sjlemon		break;
95986764Sjlemon	case IEEE80211_S_RUN:
96086764Sjlemon		ni = ieee80211_ref_node(vap->iv_bss);
96186764Sjlemon		rs = &ni->ni_rates;
96286764Sjlemon		/* Indicate highest supported rate. */
96386764Sjlemon		ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1];
96486764Sjlemon		ieee80211_free_node(ni);
96586764Sjlemon		startcal = 1;
96686764Sjlemon		break;
96786764Sjlemon	default:
96886764Sjlemon		break;
96986764Sjlemon	}
97086764Sjlemon	sc->sc_calibrating = 1;
97186764Sjlemon	RSU_UNLOCK(sc);
97286764Sjlemon	IEEE80211_LOCK(ic);
97386764Sjlemon	/* Start periodic calibration. */
97486764Sjlemon	taskqueue_enqueue_timeout(taskqueue_thread, &sc->calib_task, hz * 2);
97586764Sjlemon
97686764Sjlemon	return (uvp->newstate(vap, nstate, arg));
97786764Sjlemon}
978125680Sbms
979125680Sbms#ifdef notyet
980125680Sbmsstatic void
981125680Sbmsrsu_set_key(struct rsu_softc *sc, const struct ieee80211_key *k)
982125680Sbms{
983125680Sbms	struct r92s_fw_cmd_set_key key;
984125680Sbms
985125680Sbms	memset(&key, 0, sizeof(key));
986125680Sbms	/* Map net80211 cipher to HW crypto algorithm. */
987125680Sbms	switch (k->wk_cipher->ic_cipher) {
988125783Sbms	case IEEE80211_CIPHER_WEP:
98986764Sjlemon		if (k->wk_keylen < 8)
99086764Sjlemon			key.algo = R92S_KEY_ALGO_WEP40;
99186764Sjlemon		else
99286764Sjlemon			key.algo = R92S_KEY_ALGO_WEP104;
99386764Sjlemon		break;
99486764Sjlemon	case IEEE80211_CIPHER_TKIP:
99586764Sjlemon		key.algo = R92S_KEY_ALGO_TKIP;
99686764Sjlemon		break;
99786764Sjlemon	case IEEE80211_CIPHER_AES_CCM:
99886764Sjlemon		key.algo = R92S_KEY_ALGO_AES;
99986764Sjlemon		break;
100086764Sjlemon	default:
100186764Sjlemon		return;
100286764Sjlemon	}
100386764Sjlemon	key.id = k->wk_keyix;
100486764Sjlemon	key.grpkey = (k->wk_flags & IEEE80211_KEY_GROUP) != 0;
100586764Sjlemon	memcpy(key.key, k->wk_key, MIN(k->wk_keylen, sizeof(key.key)));
100686764Sjlemon	(void)rsu_fw_cmd(sc, R92S_CMD_SET_KEY, &key, sizeof(key));
100786764Sjlemon}
100886764Sjlemon
100986764Sjlemonstatic void
101086764Sjlemonrsu_delete_key(struct rsu_softc *sc, const struct ieee80211_key *k)
1011122922Sandre{
1012122922Sandre	struct r92s_fw_cmd_set_key key;
1013122922Sandre
101486764Sjlemon	memset(&key, 0, sizeof(key));
101586764Sjlemon	key.id = k->wk_keyix;
1016122922Sandre	(void)rsu_fw_cmd(sc, R92S_CMD_SET_KEY, &key, sizeof(key));
1017122922Sandre}
101886764Sjlemon#endif
101996602Srwatson
102086764Sjlemonstatic int
1021122922Sandrersu_site_survey(struct rsu_softc *sc, struct ieee80211vap *vap)
1022122922Sandre{
1023122922Sandre	struct r92s_fw_cmd_sitesurvey cmd;
102486764Sjlemon	struct ifnet *ifp = sc->sc_ifp;
102586764Sjlemon	struct ieee80211com *ic = ifp->if_l2com;
102686764Sjlemon
102786764Sjlemon	memset(&cmd, 0, sizeof(cmd));
102886764Sjlemon	if ((ic->ic_flags & IEEE80211_F_ASCAN) || sc->scan_pass == 1)
102986764Sjlemon		cmd.active = htole32(1);
103086764Sjlemon	cmd.limit = htole32(48);
103186764Sjlemon	if (sc->scan_pass == 1 && vap->iv_des_nssid > 0) {
103286764Sjlemon		/* Do a directed scan for second pass. */
1033122922Sandre		cmd.ssidlen = htole32(vap->iv_des_ssid[0].len);
1034122922Sandre		memcpy(cmd.ssid, vap->iv_des_ssid[0].ssid,
1035122922Sandre		    vap->iv_des_ssid[0].len);
1036122922Sandre
1037122922Sandre	}
103886764Sjlemon	DPRINTF("sending site survey command, pass=%d\n", sc->scan_pass);
1039122922Sandre	return (rsu_fw_cmd(sc, R92S_CMD_SITE_SURVEY, &cmd, sizeof(cmd)));
104086764Sjlemon}
104186764Sjlemon
104286764Sjlemonstatic int
104386764Sjlemonrsu_join_bss(struct rsu_softc *sc, struct ieee80211_node *ni)
1044118864Sharti{
1045118864Sharti	struct ifnet *ifp = sc->sc_ifp;
1046118864Sharti	struct ieee80211com *ic = ifp->if_l2com;
104788180Sjlemon	struct ieee80211vap *vap = ni->ni_vap;
1048118864Sharti	struct ndis_wlan_bssid_ex *bss;
104988180Sjlemon	struct ndis_802_11_fixed_ies *fixed;
105088180Sjlemon	struct r92s_fw_cmd_auth auth;
105188180Sjlemon	uint8_t buf[sizeof(*bss) + 128], *frm;
105286764Sjlemon	uint8_t opmode;
105386764Sjlemon	int error;
105488180Sjlemon
105586764Sjlemon	/* Let the FW decide the opmode based on the capinfo field. */
105686764Sjlemon	opmode = NDIS802_11AUTOUNKNOWN;
105786764Sjlemon	DPRINTF("setting operating mode to %d\n", opmode);
105886764Sjlemon	error = rsu_fw_cmd(sc, R92S_CMD_SET_OPMODE, &opmode, sizeof(opmode));
105986764Sjlemon	if (error != 0)
1060118864Sharti		return (error);
106186764Sjlemon
1062118864Sharti	memset(&auth, 0, sizeof(auth));
1063118864Sharti	if (vap->iv_flags & IEEE80211_F_WPA) {
1064118864Sharti		auth.mode = R92S_AUTHMODE_WPA;
1065118864Sharti		auth.dot1x = ni->ni_authmode == IEEE80211_AUTH_8021X;
1066118864Sharti	} else
1067118864Sharti		auth.mode = R92S_AUTHMODE_OPEN;
106886764Sjlemon	DPRINTF("setting auth mode to %d\n", auth.mode);
106986764Sjlemon	error = rsu_fw_cmd(sc, R92S_CMD_SET_AUTH, &auth, sizeof(auth));
107086764Sjlemon	if (error != 0)
1071118864Sharti		return (error);
107286764Sjlemon
107386764Sjlemon	memset(buf, 0, sizeof(buf));
107486764Sjlemon	bss = (struct ndis_wlan_bssid_ex *)buf;
107586764Sjlemon	IEEE80211_ADDR_COPY(bss->macaddr, ni->ni_bssid);
107686764Sjlemon	bss->ssid.ssidlen = htole32(ni->ni_esslen);
107786764Sjlemon	memcpy(bss->ssid.ssid, ni->ni_essid, ni->ni_esslen);
1078122496Ssam	if (vap->iv_flags & (IEEE80211_F_PRIVACY | IEEE80211_F_WPA))
107986764Sjlemon		bss->privacy = htole32(1);
108086764Sjlemon	bss->rssi = htole32(ni->ni_avgrssi);
108186764Sjlemon	if (ic->ic_curmode == IEEE80211_MODE_11B)
108286764Sjlemon		bss->networktype = htole32(NDIS802_11DS);
1083122922Sandre	else
108486764Sjlemon		bss->networktype = htole32(NDIS802_11OFDM24);
1085122922Sandre	bss->config.len = htole32(sizeof(bss->config));
108686764Sjlemon	bss->config.bintval = htole32(ni->ni_intval);
1087122922Sandre	bss->config.dsconfig = htole32(ieee80211_chan2ieee(ic, ni->ni_chan));
108886764Sjlemon	bss->inframode = htole32(NDIS802_11INFRASTRUCTURE);
1089122922Sandre	memcpy(bss->supprates, ni->ni_rates.rs_rates,
1090122922Sandre	    ni->ni_rates.rs_nrates);
1091122922Sandre	/* Write the fixed fields of the beacon frame. */
1092122922Sandre	fixed = (struct ndis_802_11_fixed_ies *)&bss[1];
1093122922Sandre	memcpy(&fixed->tstamp, ni->ni_tstamp.data, 8);
109486764Sjlemon	fixed->bintval = htole16(ni->ni_intval);
109586764Sjlemon	fixed->capabilities = htole16(ni->ni_capinfo);
109686764Sjlemon	/* Write IEs to be included in the association request. */
109786764Sjlemon	frm = (uint8_t *)&fixed[1];
109886764Sjlemon	frm = ieee80211_add_rsn(frm, vap);
109986764Sjlemon	frm = ieee80211_add_wpa(frm, vap);
110086764Sjlemon	frm = ieee80211_add_qos(frm, ni);
110186764Sjlemon	if (ni->ni_flags & IEEE80211_NODE_HT)
1102125680Sbms		frm = ieee80211_add_htcap(frm, ni);
1103125783Sbms	bss->ieslen = htole32(frm - (uint8_t *)fixed);
1104125783Sbms	bss->len = htole32(((frm - buf) + 3) & ~3);
1105125783Sbms	DPRINTF("sending join bss command to %s chan %d\n",
110686764Sjlemon	    ether_sprintf(bss->macaddr), le32toh(bss->config.dsconfig));
110786764Sjlemon	return (rsu_fw_cmd(sc, R92S_CMD_JOIN_BSS, buf, sizeof(buf)));
110886764Sjlemon}
110986764Sjlemon
111086764Sjlemonstatic int
111186764Sjlemonrsu_disconnect(struct rsu_softc *sc)
111286764Sjlemon{
111386764Sjlemon	uint32_t zero = 0;	/* :-) */
111486764Sjlemon
111586764Sjlemon	/* Disassociate from our current BSS. */
111686764Sjlemon	DPRINTF("sending disconnect command\n");
111786764Sjlemon	return (rsu_fw_cmd(sc, R92S_CMD_DISCONNECT, &zero, sizeof(zero)));
111886764Sjlemon}
111986764Sjlemon
112086764Sjlemonstatic void
112186764Sjlemonrsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len)
1122111119Simp{
112386764Sjlemon	struct ifnet *ifp = sc->sc_ifp;
112486764Sjlemon	struct ieee80211com *ic = ifp->if_l2com;
112586764Sjlemon	struct ieee80211_frame *wh;
112686764Sjlemon	struct ieee80211_channel *c;
112786764Sjlemon	struct ndis_wlan_bssid_ex *bss;
112886764Sjlemon	struct mbuf *m;
1129122496Ssam	int pktlen;
1130122496Ssam
1131101106Srwatson	if (__predict_false(len < sizeof(*bss)))
1132122496Ssam		return;
1133101106Srwatson	bss = (struct ndis_wlan_bssid_ex *)buf;
113486764Sjlemon	if (__predict_false(len < sizeof(*bss) + le32toh(bss->ieslen)))
113586764Sjlemon		return;
113686764Sjlemon
113786764Sjlemon	DPRINTFN(2, "found BSS %s: len=%d chan=%d inframode=%d "
113886764Sjlemon	    "networktype=%d privacy=%d\n",
113986764Sjlemon	    ether_sprintf(bss->macaddr), le32toh(bss->len),
114086764Sjlemon	    le32toh(bss->config.dsconfig), le32toh(bss->inframode),
114186764Sjlemon	    le32toh(bss->networktype), le32toh(bss->privacy));
114286764Sjlemon
114386764Sjlemon	/* Build a fake beacon frame to let net80211 do all the parsing. */
114486764Sjlemon	pktlen = sizeof(*wh) + le32toh(bss->ieslen);
114586764Sjlemon	if (__predict_false(pktlen > MCLBYTES))
114686764Sjlemon		return;
114786764Sjlemon	MGETHDR(m, M_NOWAIT, MT_DATA);
114886764Sjlemon	if (__predict_false(m == NULL))
114986764Sjlemon		return;
115086764Sjlemon	if (pktlen > MHLEN) {
115186764Sjlemon		MCLGET(m, M_NOWAIT);
115286764Sjlemon		if (!(m->m_flags & M_EXT)) {
115386764Sjlemon			m_free(m);
115486764Sjlemon			return;
115586764Sjlemon		}
115686764Sjlemon	}
115786764Sjlemon	wh = mtod(m, struct ieee80211_frame *);
115886764Sjlemon	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
115986764Sjlemon	    IEEE80211_FC0_SUBTYPE_BEACON;
1160122496Ssam	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
1161122496Ssam	USETW(wh->i_dur, 0);
116286764Sjlemon	IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr);
116398204Ssilby	IEEE80211_ADDR_COPY(wh->i_addr2, bss->macaddr);
1164108125Shsu	IEEE80211_ADDR_COPY(wh->i_addr3, bss->macaddr);
1165108125Shsu	*(uint16_t *)wh->i_seq = 0;
1166101405Ssilby	memcpy(&wh[1], (uint8_t *)&bss[1], le32toh(bss->ieslen));
1167101405Ssilby
1168101405Ssilby	/* Finalize mbuf. */
116998204Ssilby	m->m_pkthdr.len = m->m_len = pktlen;
1170108125Shsu	m->m_pkthdr.rcvif = ifp;
117198204Ssilby	/* Fix the channel. */
117298204Ssilby	c = ieee80211_find_channel_byieee(ic,
117386764Sjlemon	    le32toh(bss->config.dsconfig),
117486764Sjlemon	    IEEE80211_CHAN_G);
117586764Sjlemon	if (c) {
117686764Sjlemon		ic->ic_curchan = c;
117786764Sjlemon		ieee80211_radiotap_chan_change(ic);
117886764Sjlemon	}
117986764Sjlemon	/* XXX avoid a LOR */
118086764Sjlemon	RSU_UNLOCK(sc);
118186764Sjlemon	ieee80211_input_all(ic, m, le32toh(bss->rssi), 0);
118286764Sjlemon	RSU_LOCK(sc);
118386764Sjlemon}
118486764Sjlemon
118586764Sjlemonstatic void
118686764Sjlemonrsu_event_join_bss(struct rsu_softc *sc, uint8_t *buf, int len)
1187108125Shsu{
1188108125Shsu	struct ifnet *ifp = sc->sc_ifp;
1189108125Shsu	struct ieee80211com *ic = ifp->if_l2com;
1190108125Shsu	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
1191108125Shsu	struct ieee80211_node *ni = vap->iv_bss;
1192108125Shsu	struct r92s_event_join_bss *rsp;
119386764Sjlemon	int res;
1194108125Shsu
1195108125Shsu	if (__predict_false(len < sizeof(*rsp)))
1196108125Shsu		return;
1197108125Shsu	rsp = (struct r92s_event_join_bss *)buf;
1198108125Shsu	res = (int)le32toh(rsp->join_res);
1199108125Shsu
120086764Sjlemon	DPRINTF("Rx join BSS event len=%d res=%d\n", len, res);
1201108125Shsu	if (res <= 0) {
1202108125Shsu		RSU_UNLOCK(sc);
120386764Sjlemon		ieee80211_new_state(vap, IEEE80211_S_SCAN, -1);
1204108125Shsu		RSU_LOCK(sc);
1205108125Shsu		return;
1206108125Shsu	}
1207108125Shsu	DPRINTF("associated with %s associd=%d\n",
1208108125Shsu	    ether_sprintf(rsp->bss.macaddr), le32toh(rsp->associd));
1209108125Shsu	ni->ni_associd = le32toh(rsp->associd) | 0xc000;
121086764Sjlemon	RSU_UNLOCK(sc);
1211108125Shsu	ieee80211_new_state(vap, IEEE80211_S_RUN,
1212108125Shsu	    IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
1213108125Shsu	RSU_LOCK(sc);
1214108125Shsu}
1215108125Shsu
121686764Sjlemonstatic void
1217108125Shsursu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len)
1218108125Shsu{
1219108125Shsu	struct ifnet *ifp = sc->sc_ifp;
1220108125Shsu	struct ieee80211com *ic = ifp->if_l2com;
1221108125Shsu	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
1222108125Shsu
1223125680Sbms	DPRINTFN(4, "Rx event code=%d len=%d\n", code, len);
1224125680Sbms	switch (code) {
1225125680Sbms	case R92S_EVT_SURVEY:
1226125680Sbms		if (vap->iv_state == IEEE80211_S_SCAN)
1227125680Sbms			rsu_event_survey(sc, buf, len);
1228125680Sbms		break;
1229125680Sbms	case R92S_EVT_SURVEY_DONE:
1230125680Sbms		DPRINTF("site survey pass %d done, found %d BSS\n",
1231125680Sbms		    sc->scan_pass, le32toh(*(uint32_t *)buf));
1232125680Sbms		if (vap->iv_state != IEEE80211_S_SCAN)
1233125680Sbms			break;	/* Ignore if not scanning. */
1234125680Sbms		if (sc->scan_pass == 0 && vap->iv_des_nssid != 0) {
1235125680Sbms			/* Schedule a directed scan for hidden APs. */
1236125783Sbms			sc->scan_pass = 1;
1237125680Sbms			RSU_UNLOCK(sc);
1238125680Sbms			ieee80211_new_state(vap, IEEE80211_S_SCAN, -1);
1239125680Sbms			RSU_LOCK(sc);
1240125680Sbms			break;
1241125680Sbms		}
1242125680Sbms		sc->scan_pass = 0;
124386764Sjlemon		break;
124486764Sjlemon	case R92S_EVT_JOIN_BSS:
124586764Sjlemon		if (vap->iv_state == IEEE80211_S_AUTH)
124686764Sjlemon			rsu_event_join_bss(sc, buf, len);
124786764Sjlemon		break;
124886764Sjlemon	case R92S_EVT_DEL_STA:
1249122922Sandre		DPRINTF("disassociated from %s\n", ether_sprintf(buf));
1250122922Sandre		if (vap->iv_state == IEEE80211_S_RUN &&
125186764Sjlemon		    IEEE80211_ADDR_EQ(vap->iv_bss->ni_bssid, buf)) {
125286764Sjlemon			RSU_UNLOCK(sc);
125386764Sjlemon			ieee80211_new_state(vap, IEEE80211_S_SCAN, -1);
125486764Sjlemon			RSU_LOCK(sc);
125586764Sjlemon		}
125686764Sjlemon		break;
125786764Sjlemon	case R92S_EVT_WPS_PBC:
1258118864Sharti		DPRINTF("WPS PBC pushed.\n");
1259118864Sharti		break;
1260118864Sharti	case R92S_EVT_FWDBG:
1261118864Sharti		if (ifp->if_flags & IFF_DEBUG) {
1262118864Sharti			buf[60] = '\0';
1263118864Sharti			printf("FWDBG: %s\n", (char *)buf);
1264118864Sharti		}
1265118864Sharti		break;
1266118864Sharti	}
1267118864Sharti}
1268122922Sandre
126986764Sjlemonstatic void
1270122496Ssamrsu_rx_multi_event(struct rsu_softc *sc, uint8_t *buf, int len)
127186764Sjlemon{
127286764Sjlemon	struct r92s_fw_cmd_hdr *cmd;
127388180Sjlemon	int cmdsz;
127488180Sjlemon
127588180Sjlemon	DPRINTFN(6, "Rx events len=%d\n", len);
127688180Sjlemon
127788180Sjlemon	/* Skip Rx status. */
127888180Sjlemon	buf += sizeof(struct r92s_rx_stat);
1279111405Ssilby	len -= sizeof(struct r92s_rx_stat);
128088180Sjlemon
128188180Sjlemon	/* Process all events. */
128288180Sjlemon	for (;;) {
128388180Sjlemon		/* Check that command header fits. */
128488180Sjlemon		if (__predict_false(len < sizeof(*cmd)))
128588180Sjlemon			break;
1286111338Ssilby		cmd = (struct r92s_fw_cmd_hdr *)buf;
128788180Sjlemon		/* Check that command payload fits. */
128888180Sjlemon		cmdsz = le16toh(cmd->len);
1289111338Ssilby		if (__predict_false(len < sizeof(*cmd) + cmdsz))
1290111338Ssilby			break;
129188180Sjlemon
129288180Sjlemon		/* Process firmware event. */
1293111338Ssilby		rsu_rx_event(sc, cmd->code, (uint8_t *)&cmd[1], cmdsz);
129488180Sjlemon
129588180Sjlemon		if (!(cmd->seq & R92S_FW_CMD_MORE))
129688180Sjlemon			break;
129788180Sjlemon		buf += sizeof(*cmd) + cmdsz;
129888180Sjlemon		len -= sizeof(*cmd) + cmdsz;
1299111338Ssilby	}
130088180Sjlemon}
130188180Sjlemon
130288180Sjlemonstatic int8_t
130388180Sjlemonrsu_get_rssi(struct rsu_softc *sc, int rate, void *physt)
130488180Sjlemon{
130588180Sjlemon	static const int8_t cckoff[] = { 14, -2, -20, -40 };
130688180Sjlemon	struct r92s_rx_phystat *phy;
130788180Sjlemon	struct r92s_rx_cck *cck;
130888180Sjlemon	uint8_t rpt;
1309111338Ssilby	int8_t rssi;
1310111338Ssilby
1311111338Ssilby	if (rate <= 3) {
1312111338Ssilby		cck = (struct r92s_rx_cck *)physt;
1313111338Ssilby		rpt = (cck->agc_rpt >> 6) & 0x3;
1314111338Ssilby		rssi = cck->agc_rpt & 0x3e;
1315111338Ssilby		rssi = cckoff[rpt] - rssi;
1316111338Ssilby	} else {	/* OFDM/HT. */
1317111338Ssilby		phy = (struct r92s_rx_phystat *)physt;
1318111338Ssilby		rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 106;
131988180Sjlemon	}
132088180Sjlemon	return (rssi);
132188180Sjlemon}
132288180Sjlemon
132388180Sjlemonstatic struct mbuf *
132488180Sjlemonrsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen, int *rssi)
132588180Sjlemon{
132688180Sjlemon	struct ifnet *ifp = sc->sc_ifp;
132788180Sjlemon	struct ieee80211com *ic = ifp->if_l2com;
132888180Sjlemon	struct ieee80211_frame *wh;
132988180Sjlemon	struct r92s_rx_stat *stat;
133088180Sjlemon	uint32_t rxdw0, rxdw3;
133188180Sjlemon	struct mbuf *m;
133288180Sjlemon	uint8_t rate;
133388180Sjlemon	int infosz;
1334111338Ssilby
1335111338Ssilby	stat = (struct r92s_rx_stat *)buf;
133688180Sjlemon	rxdw0 = le32toh(stat->rxdw0);
1337122496Ssam	rxdw3 = le32toh(stat->rxdw3);
1338122496Ssam
1339111338Ssilby	if (__predict_false(rxdw0 & R92S_RXDW0_CRCERR)) {
134088180Sjlemon		ifp->if_ierrors++;
1341111338Ssilby		return NULL;
1342111338Ssilby	}
134388180Sjlemon	if (__predict_false(pktlen < sizeof(*wh) || pktlen > MCLBYTES)) {
134488180Sjlemon		ifp->if_ierrors++;
134588180Sjlemon		return NULL;
134688180Sjlemon	}
134788180Sjlemon
1348111338Ssilby	rate = MS(rxdw3, R92S_RXDW3_RATE);
134988180Sjlemon	infosz = MS(rxdw0, R92S_RXDW0_INFOSZ) * 8;
135088180Sjlemon
135188180Sjlemon	/* Get RSSI from PHY status descriptor if present. */
135288180Sjlemon	if (infosz != 0)
135388180Sjlemon		*rssi = rsu_get_rssi(sc, rate, &stat[1]);
135488180Sjlemon	else
1355111338Ssilby		*rssi = 0;
1356111338Ssilby
135788180Sjlemon	DPRINTFN(5, "Rx frame len=%d rate=%d infosz=%d rssi=%d\n",
135888180Sjlemon	    pktlen, rate, infosz, *rssi);
135988180Sjlemon
1360111338Ssilby	MGETHDR(m, M_NOWAIT, MT_DATA);
1361111338Ssilby	if (__predict_false(m == NULL)) {
136288180Sjlemon		ifp->if_ierrors++;
1363111338Ssilby		return NULL;
1364111338Ssilby	}
1365111338Ssilby	if (pktlen > MHLEN) {
1366111338Ssilby		MCLGET(m, M_NOWAIT);
1367111338Ssilby		if (__predict_false(!(m->m_flags & M_EXT))) {
1368111338Ssilby			ifp->if_ierrors++;
1369111338Ssilby			m_freem(m);
137088180Sjlemon			return NULL;
1371111338Ssilby		}
137288180Sjlemon	}
137388180Sjlemon	/* Finalize mbuf. */
137488180Sjlemon	m->m_pkthdr.rcvif = ifp;
137588180Sjlemon	/* Hardware does Rx TCP checksum offload. */
137688180Sjlemon	if (rxdw3 & R92S_RXDW3_TCPCHKVALID) {
137788180Sjlemon		if (__predict_true(rxdw3 & R92S_RXDW3_TCPCHKRPT))
137888180Sjlemon			m->m_pkthdr.csum_flags |= CSUM_DATA_VALID;
137988180Sjlemon	}
138088180Sjlemon	wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz);
138188180Sjlemon	memcpy(mtod(m, uint8_t *), wh, pktlen);
138288180Sjlemon	m->m_pkthdr.len = m->m_len = pktlen;
138388180Sjlemon
138488180Sjlemon	if (ieee80211_radiotap_active(ic)) {
1385111338Ssilby		struct rsu_rx_radiotap_header *tap = &sc->sc_rxtap;
138688180Sjlemon
1387122496Ssam		/* Map HW rate index to 802.11 rate. */
1388122496Ssam		tap->wr_flags = 2;
138988180Sjlemon		if (!(rxdw3 & R92S_RXDW3_HTC)) {
1390111338Ssilby			switch (rate) {
139188180Sjlemon			/* CCK. */
139288180Sjlemon			case  0: tap->wr_rate =   2; break;
139388180Sjlemon			case  1: tap->wr_rate =   4; break;
139488180Sjlemon			case  2: tap->wr_rate =  11; break;
139588180Sjlemon			case  3: tap->wr_rate =  22; break;
139688180Sjlemon			/* OFDM. */
139788180Sjlemon			case  4: tap->wr_rate =  12; break;
139888180Sjlemon			case  5: tap->wr_rate =  18; break;
1399111338Ssilby			case  6: tap->wr_rate =  24; break;
1400111338Ssilby			case  7: tap->wr_rate =  36; break;
140188180Sjlemon			case  8: tap->wr_rate =  48; break;
140288180Sjlemon			case  9: tap->wr_rate =  72; break;
140388180Sjlemon			case 10: tap->wr_rate =  96; break;
1404111338Ssilby			case 11: tap->wr_rate = 108; break;
1405111338Ssilby			}
140688180Sjlemon		} else if (rate >= 12) {	/* MCS0~15. */
1407111338Ssilby			/* Bit 7 set means HT MCS instead of rate. */
1408111338Ssilby			tap->wr_rate = 0x80 | (rate - 12);
1409111338Ssilby		}
1410111338Ssilby		tap->wr_dbm_antsignal = *rssi;
1411111338Ssilby		tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
1412111338Ssilby		tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
1413111338Ssilby	}
141488180Sjlemon
1415111338Ssilby	return (m);
141688180Sjlemon}
141788180Sjlemon
141888180Sjlemonstatic struct mbuf *
141988180Sjlemonrsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf, int len, int *rssi)
142092760Sjeff{
142188180Sjlemon	struct r92s_rx_stat *stat;
142288180Sjlemon	uint32_t rxdw0;
142388180Sjlemon	int totlen, pktlen, infosz, npkts;
142488180Sjlemon	struct mbuf *m, *m0 = NULL, *prevm = NULL;
142588180Sjlemon
142688180Sjlemon	/* Get the number of encapsulated frames. */
142788180Sjlemon	stat = (struct r92s_rx_stat *)buf;
142888180Sjlemon	npkts = MS(le32toh(stat->rxdw2), R92S_RXDW2_PKTCNT);
142988180Sjlemon	DPRINTFN(6, "Rx %d frames in one chunk\n", npkts);
143088180Sjlemon
143188180Sjlemon	/* Process all of them. */
143288180Sjlemon	while (npkts-- > 0) {
143388180Sjlemon		if (__predict_false(len < sizeof(*stat)))
143488180Sjlemon			break;
143588180Sjlemon		stat = (struct r92s_rx_stat *)buf;
143688180Sjlemon		rxdw0 = le32toh(stat->rxdw0);
143788180Sjlemon
143888180Sjlemon		pktlen = MS(rxdw0, R92S_RXDW0_PKTLEN);
143988180Sjlemon		if (__predict_false(pktlen == 0))
144088180Sjlemon			break;
144188180Sjlemon
144288180Sjlemon		infosz = MS(rxdw0, R92S_RXDW0_INFOSZ) * 8;
144388180Sjlemon
144488180Sjlemon		/* Make sure everything fits in xfer. */
144588180Sjlemon		totlen = sizeof(*stat) + infosz + pktlen;
144688180Sjlemon		if (__predict_false(totlen > len))
144788180Sjlemon			break;
144888180Sjlemon
144988180Sjlemon		/* Process 802.11 frame. */
145088180Sjlemon		m = rsu_rx_frame(sc, buf, pktlen, rssi);
145188180Sjlemon		if (m0 == NULL)
1452			m0 = m;
1453		if (prevm == NULL)
1454			prevm = m;
1455		else {
1456			prevm->m_next = m;
1457			prevm = m;
1458		}
1459		/* Next chunk is 128-byte aligned. */
1460		totlen = (totlen + 127) & ~127;
1461		buf += totlen;
1462		len -= totlen;
1463	}
1464
1465	return (m0);
1466}
1467
1468static struct mbuf *
1469rsu_rxeof(struct usb_xfer *xfer, struct rsu_data *data, int *rssi)
1470{
1471	struct rsu_softc *sc = data->sc;
1472	struct r92s_rx_stat *stat;
1473	int len;
1474
1475	usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
1476
1477	if (__predict_false(len < sizeof(*stat))) {
1478		DPRINTF("xfer too short %d\n", len);
1479		sc->sc_ifp->if_ierrors++;
1480		return (NULL);
1481	}
1482	/* Determine if it is a firmware C2H event or an 802.11 frame. */
1483	stat = (struct r92s_rx_stat *)data->buf;
1484	if ((le32toh(stat->rxdw1) & 0x1ff) == 0x1ff) {
1485		rsu_rx_multi_event(sc, data->buf, len);
1486		/* No packets to process. */
1487		return (NULL);
1488	} else
1489		return (rsu_rx_multi_frame(sc, data->buf, len, rssi));
1490}
1491
1492static void
1493rsu_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
1494{
1495	struct rsu_softc *sc = usbd_xfer_softc(xfer);
1496	struct ifnet *ifp = sc->sc_ifp;
1497	struct ieee80211com *ic = ifp->if_l2com;
1498	struct ieee80211_frame *wh;
1499	struct ieee80211_node *ni;
1500	struct mbuf *m = NULL, *next;
1501	struct rsu_data *data;
1502	int rssi = 1;
1503
1504	RSU_ASSERT_LOCKED(sc);
1505
1506	switch (USB_GET_STATE(xfer)) {
1507	case USB_ST_TRANSFERRED:
1508		data = STAILQ_FIRST(&sc->sc_rx_active);
1509		if (data == NULL)
1510			goto tr_setup;
1511		STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next);
1512		m = rsu_rxeof(xfer, data, &rssi);
1513		STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next);
1514		/* FALLTHROUGH */
1515	case USB_ST_SETUP:
1516tr_setup:
1517		data = STAILQ_FIRST(&sc->sc_rx_inactive);
1518		if (data == NULL) {
1519			KASSERT(m == NULL, ("mbuf isn't NULL"));
1520			return;
1521		}
1522		STAILQ_REMOVE_HEAD(&sc->sc_rx_inactive, next);
1523		STAILQ_INSERT_TAIL(&sc->sc_rx_active, data, next);
1524		usbd_xfer_set_frame_data(xfer, 0, data->buf,
1525		    usbd_xfer_max_len(xfer));
1526		usbd_transfer_submit(xfer);
1527		/*
1528		 * To avoid LOR we should unlock our private mutex here to call
1529		 * ieee80211_input() because here is at the end of a USB
1530		 * callback and safe to unlock.
1531		 */
1532		RSU_UNLOCK(sc);
1533		while (m != NULL) {
1534			next = m->m_next;
1535			m->m_next = NULL;
1536			wh = mtod(m, struct ieee80211_frame *);
1537			ni = ieee80211_find_rxnode(ic,
1538			    (struct ieee80211_frame_min *)wh);
1539			if (ni != NULL) {
1540				(void)ieee80211_input(ni, m, rssi, 0);
1541				ieee80211_free_node(ni);
1542			} else
1543				(void)ieee80211_input_all(ic, m, rssi, 0);
1544			m = next;
1545		}
1546		RSU_LOCK(sc);
1547		break;
1548	default:
1549		/* needs it to the inactive queue due to a error. */
1550		data = STAILQ_FIRST(&sc->sc_rx_active);
1551		if (data != NULL) {
1552			STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next);
1553			STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next);
1554		}
1555		if (error != USB_ERR_CANCELLED) {
1556			usbd_xfer_set_stall(xfer);
1557			ifp->if_ierrors++;
1558			goto tr_setup;
1559		}
1560		break;
1561	}
1562
1563}
1564
1565
1566static void
1567rsu_txeof(struct usb_xfer *xfer, struct rsu_data *data)
1568{
1569	struct rsu_softc *sc = usbd_xfer_softc(xfer);
1570	struct ifnet *ifp = sc->sc_ifp;
1571	struct mbuf *m;
1572
1573	RSU_ASSERT_LOCKED(sc);
1574
1575	/*
1576	 * Do any tx complete callback.  Note this must be done before releasing
1577	 * the node reference.
1578	 */
1579	if (data->m) {
1580		m = data->m;
1581		if (m->m_flags & M_TXCB) {
1582			/* XXX status? */
1583			ieee80211_process_callback(data->ni, m, 0);
1584		}
1585		m_freem(m);
1586		data->m = NULL;
1587	}
1588	if (data->ni) {
1589		ieee80211_free_node(data->ni);
1590		data->ni = NULL;
1591	}
1592	sc->sc_tx_timer = 0;
1593	ifp->if_opackets++;
1594	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1595}
1596
1597static void
1598rsu_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error)
1599{
1600	struct rsu_softc *sc = usbd_xfer_softc(xfer);
1601	struct ifnet *ifp = sc->sc_ifp;
1602	struct rsu_data *data;
1603
1604	RSU_ASSERT_LOCKED(sc);
1605
1606	switch (USB_GET_STATE(xfer)) {
1607	case USB_ST_TRANSFERRED:
1608		data = STAILQ_FIRST(&sc->sc_tx_active);
1609		if (data == NULL)
1610			goto tr_setup;
1611		DPRINTF("transfer done %p\n", data);
1612		STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next);
1613		rsu_txeof(xfer, data);
1614		STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next);
1615		/* FALLTHROUGH */
1616	case USB_ST_SETUP:
1617tr_setup:
1618		data = STAILQ_FIRST(&sc->sc_tx_pending);
1619		if (data == NULL) {
1620			DPRINTF("empty pending queue sc %p\n", sc);
1621			return;
1622		}
1623		STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next);
1624		STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next);
1625		usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen);
1626		DPRINTF("submitting transfer %p\n", data);
1627		usbd_transfer_submit(xfer);
1628		rsu_start_locked(ifp);
1629		break;
1630	default:
1631		data = STAILQ_FIRST(&sc->sc_tx_active);
1632		if (data == NULL)
1633			goto tr_setup;
1634		if (data->ni != NULL) {
1635			ieee80211_free_node(data->ni);
1636			data->ni = NULL;
1637			ifp->if_oerrors++;
1638		}
1639		if (error != USB_ERR_CANCELLED) {
1640			usbd_xfer_set_stall(xfer);
1641			goto tr_setup;
1642		}
1643		break;
1644	}
1645}
1646
1647static int
1648rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni,
1649    struct mbuf *m0, struct rsu_data *data)
1650{
1651	struct ifnet *ifp = sc->sc_ifp;
1652	struct ieee80211com *ic = ifp->if_l2com;
1653        struct ieee80211vap *vap = ni->ni_vap;
1654	struct ieee80211_frame *wh;
1655	struct ieee80211_key *k = NULL;
1656	struct r92s_tx_desc *txd;
1657	struct usb_xfer *xfer;
1658	uint8_t type, tid = 0;
1659	int hasqos, xferlen;
1660	struct usb_xfer *rsu_pipes[4] = {
1661		sc->sc_xfer[RSU_BULK_TX_BE],
1662		sc->sc_xfer[RSU_BULK_TX_BK],
1663		sc->sc_xfer[RSU_BULK_TX_VI],
1664		sc->sc_xfer[RSU_BULK_TX_VO]
1665	};
1666
1667	RSU_ASSERT_LOCKED(sc);
1668
1669	wh = mtod(m0, struct ieee80211_frame *);
1670	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
1671
1672	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
1673		k = ieee80211_crypto_encap(ni, m0);
1674		if (k == NULL) {
1675			device_printf(sc->sc_dev,
1676			    "ieee80211_crypto_encap returns NULL.\n");
1677			/* XXX we don't expect the fragmented frames */
1678			m_freem(m0);
1679			return (ENOBUFS);
1680		}
1681		wh = mtod(m0, struct ieee80211_frame *);
1682	}
1683	switch (type) {
1684	case IEEE80211_FC0_TYPE_CTL:
1685	case IEEE80211_FC0_TYPE_MGT:
1686		xfer = sc->sc_xfer[RSU_BULK_TX_VO];
1687		break;
1688	default:
1689		KASSERT(M_WME_GETAC(m0) < 4,
1690		    ("unsupported WME pipe %d", M_WME_GETAC(m0)));
1691		xfer = rsu_pipes[M_WME_GETAC(m0)];
1692		break;
1693	}
1694	hasqos = 0;
1695
1696	/* Fill Tx descriptor. */
1697	txd = (struct r92s_tx_desc *)data->buf;
1698	memset(txd, 0, sizeof(*txd));
1699
1700	txd->txdw0 |= htole32(
1701	    SM(R92S_TXDW0_PKTLEN, m0->m_pkthdr.len) |
1702	    SM(R92S_TXDW0_OFFSET, sizeof(*txd)) |
1703	    R92S_TXDW0_OWN | R92S_TXDW0_FSG | R92S_TXDW0_LSG);
1704
1705	txd->txdw1 |= htole32(
1706	    SM(R92S_TXDW1_MACID, R92S_MACID_BSS) |
1707	    SM(R92S_TXDW1_QSEL, R92S_TXDW1_QSEL_BE));
1708	if (!hasqos)
1709		txd->txdw1 |= htole32(R92S_TXDW1_NONQOS);
1710#ifdef notyet
1711	if (k != NULL) {
1712		switch (k->wk_cipher->ic_cipher) {
1713		case IEEE80211_CIPHER_WEP:
1714			cipher = R92S_TXDW1_CIPHER_WEP;
1715			break;
1716		case IEEE80211_CIPHER_TKIP:
1717			cipher = R92S_TXDW1_CIPHER_TKIP;
1718			break;
1719		case IEEE80211_CIPHER_AES_CCM:
1720			cipher = R92S_TXDW1_CIPHER_AES;
1721			break;
1722		default:
1723			cipher = R92S_TXDW1_CIPHER_NONE;
1724		}
1725		txd->txdw1 |= htole32(
1726		    SM(R92S_TXDW1_CIPHER, cipher) |
1727		    SM(R92S_TXDW1_KEYIDX, k->k_id));
1728	}
1729#endif
1730	txd->txdw2 |= htole32(R92S_TXDW2_BK);
1731	if (IEEE80211_IS_MULTICAST(wh->i_addr1))
1732		txd->txdw2 |= htole32(R92S_TXDW2_BMCAST);
1733	/*
1734	 * Firmware will use and increment the sequence number for the
1735	 * specified TID.
1736	 */
1737	txd->txdw3 |= htole32(SM(R92S_TXDW3_SEQ, tid));
1738
1739	if (ieee80211_radiotap_active_vap(vap)) {
1740		struct rsu_tx_radiotap_header *tap = &sc->sc_txtap;
1741
1742		tap->wt_flags = 0;
1743		tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
1744		tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
1745		ieee80211_radiotap_tx(vap, m0);
1746	}
1747	xferlen = sizeof(*txd) + m0->m_pkthdr.len;
1748	m_copydata(m0, 0, m0->m_pkthdr.len, (caddr_t)&txd[1]);
1749
1750	data->buflen = xferlen;
1751	data->ni = ni;
1752	data->m = m0;
1753	STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
1754	usbd_transfer_start(xfer);
1755
1756	return (0);
1757}
1758
1759static void
1760rsu_start(struct ifnet *ifp)
1761{
1762	struct rsu_softc *sc = ifp->if_softc;
1763
1764	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
1765		return;
1766
1767	RSU_LOCK(sc);
1768	rsu_start_locked(ifp);
1769	RSU_UNLOCK(sc);
1770}
1771
1772static void
1773rsu_start_locked(struct ifnet *ifp)
1774{
1775	struct rsu_softc *sc = ifp->if_softc;
1776	struct ieee80211_node *ni;
1777	struct mbuf *m;
1778	struct rsu_data *bf;
1779
1780	RSU_ASSERT_LOCKED(sc);
1781
1782	for (;;) {
1783		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
1784		if (m == NULL)
1785			break;
1786		bf = rsu_getbuf(sc);
1787		if (bf == NULL) {
1788			IFQ_DRV_PREPEND(&ifp->if_snd, m);
1789			break;
1790		}
1791		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
1792		m->m_pkthdr.rcvif = NULL;
1793
1794		if (rsu_tx_start(sc, ni, m, bf) != 0) {
1795			ifp->if_oerrors++;
1796			STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
1797			ieee80211_free_node(ni);
1798			break;
1799		}
1800		sc->sc_tx_timer = 5;
1801		callout_reset(&sc->sc_watchdog_ch, hz, rsu_watchdog, sc);
1802	}
1803}
1804
1805static void
1806rsu_watchdog(void *arg)
1807{
1808	struct rsu_softc *sc = arg;
1809	struct ifnet *ifp = sc->sc_ifp;
1810
1811	if (sc->sc_tx_timer > 0) {
1812		if (--sc->sc_tx_timer == 0) {
1813			device_printf(sc->sc_dev, "device timeout\n");
1814			/* rsu_init(ifp); XXX needs a process context! */
1815			ifp->if_oerrors++;
1816			return;
1817		}
1818		callout_reset(&sc->sc_watchdog_ch, hz, rsu_watchdog, sc);
1819	}
1820}
1821
1822static int
1823rsu_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1824{
1825	struct ieee80211com *ic = ifp->if_l2com;
1826	struct ifreq *ifr = (struct ifreq *) data;
1827	int error = 0, startall = 0;
1828
1829	switch (cmd) {
1830	case SIOCSIFFLAGS:
1831		if (ifp->if_flags & IFF_UP) {
1832			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
1833				rsu_init(ifp->if_softc);
1834				startall = 1;
1835			}
1836		} else {
1837			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1838				rsu_stop(ifp, 1);
1839		}
1840		if (startall)
1841			ieee80211_start_all(ic);
1842		break;
1843	case SIOCGIFMEDIA:
1844		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
1845		break;
1846	case SIOCGIFADDR:
1847		error = ether_ioctl(ifp, cmd, data);
1848		break;
1849	default:
1850		error = EINVAL;
1851		break;
1852	}
1853
1854	return (error);
1855}
1856
1857/*
1858 * Power on sequence for A-cut adapters.
1859 */
1860static void
1861rsu_power_on_acut(struct rsu_softc *sc)
1862{
1863	uint32_t reg;
1864
1865	rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x53);
1866	rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x57);
1867
1868	/* Enable AFE macro block's bandgap and Mbias. */
1869	rsu_write_1(sc, R92S_AFE_MISC,
1870	    rsu_read_1(sc, R92S_AFE_MISC) |
1871	    R92S_AFE_MISC_BGEN | R92S_AFE_MISC_MBEN);
1872	/* Enable LDOA15 block. */
1873	rsu_write_1(sc, R92S_LDOA15_CTRL,
1874	    rsu_read_1(sc, R92S_LDOA15_CTRL) | R92S_LDA15_EN);
1875
1876	rsu_write_1(sc, R92S_SPS1_CTRL,
1877	    rsu_read_1(sc, R92S_SPS1_CTRL) | R92S_SPS1_LDEN);
1878	usb_pause_mtx(&sc->sc_mtx, 2 * hz);
1879	/* Enable switch regulator block. */
1880	rsu_write_1(sc, R92S_SPS1_CTRL,
1881	    rsu_read_1(sc, R92S_SPS1_CTRL) | R92S_SPS1_SWEN);
1882
1883	rsu_write_4(sc, R92S_SPS1_CTRL, 0x00a7b267);
1884
1885	rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1,
1886	    rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) | 0x08);
1887
1888	rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
1889	    rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x20);
1890
1891	rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1,
1892	    rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) & ~0x90);
1893
1894	/* Enable AFE clock. */
1895	rsu_write_1(sc, R92S_AFE_XTAL_CTRL + 1,
1896	    rsu_read_1(sc, R92S_AFE_XTAL_CTRL + 1) & ~0x04);
1897	/* Enable AFE PLL macro block. */
1898	rsu_write_1(sc, R92S_AFE_PLL_CTRL,
1899	    rsu_read_1(sc, R92S_AFE_PLL_CTRL) | 0x11);
1900	/* Attach AFE PLL to MACTOP/BB. */
1901	rsu_write_1(sc, R92S_SYS_ISO_CTRL,
1902	    rsu_read_1(sc, R92S_SYS_ISO_CTRL) & ~0x11);
1903
1904	/* Switch to 40MHz clock instead of 80MHz. */
1905	rsu_write_2(sc, R92S_SYS_CLKR,
1906	    rsu_read_2(sc, R92S_SYS_CLKR) & ~R92S_SYS_CLKSEL);
1907
1908	/* Enable MAC clock. */
1909	rsu_write_2(sc, R92S_SYS_CLKR,
1910	    rsu_read_2(sc, R92S_SYS_CLKR) |
1911	    R92S_MAC_CLK_EN | R92S_SYS_CLK_EN);
1912
1913	rsu_write_1(sc, R92S_PMC_FSM, 0x02);
1914
1915	/* Enable digital core and IOREG R/W. */
1916	rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
1917	    rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x08);
1918
1919	rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
1920	    rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x80);
1921
1922	/* Switch the control path to firmware. */
1923	reg = rsu_read_2(sc, R92S_SYS_CLKR);
1924	reg = (reg & ~R92S_SWHW_SEL) | R92S_FWHW_SEL;
1925	rsu_write_2(sc, R92S_SYS_CLKR, reg);
1926
1927	rsu_write_2(sc, R92S_CR, 0x37fc);
1928
1929	/* Fix USB RX FIFO issue. */
1930	rsu_write_1(sc, 0xfe5c,
1931	    rsu_read_1(sc, 0xfe5c) | 0x80);
1932	rsu_write_1(sc, 0x00ab,
1933	    rsu_read_1(sc, 0x00ab) | 0xc0);
1934
1935	rsu_write_1(sc, R92S_SYS_CLKR,
1936	    rsu_read_1(sc, R92S_SYS_CLKR) & ~R92S_SYS_CPU_CLKSEL);
1937}
1938
1939/*
1940 * Power on sequence for B-cut and C-cut adapters.
1941 */
1942static void
1943rsu_power_on_bcut(struct rsu_softc *sc)
1944{
1945	uint32_t reg;
1946	int ntries;
1947
1948	/* Prevent eFuse leakage. */
1949	rsu_write_1(sc, 0x37, 0xb0);
1950	usb_pause_mtx(&sc->sc_mtx, 10);
1951	rsu_write_1(sc, 0x37, 0x30);
1952
1953	/* Switch the control path to hardware. */
1954	reg = rsu_read_2(sc, R92S_SYS_CLKR);
1955	if (reg & R92S_FWHW_SEL) {
1956		rsu_write_2(sc, R92S_SYS_CLKR,
1957		    reg & ~(R92S_SWHW_SEL | R92S_FWHW_SEL));
1958	}
1959	rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
1960	    rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) & ~0x8c);
1961	DELAY(1000);
1962
1963	rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x53);
1964	rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x57);
1965
1966	reg = rsu_read_1(sc, R92S_AFE_MISC);
1967	rsu_write_1(sc, R92S_AFE_MISC, reg | R92S_AFE_MISC_BGEN);
1968	rsu_write_1(sc, R92S_AFE_MISC, reg | R92S_AFE_MISC_BGEN |
1969	    R92S_AFE_MISC_MBEN | R92S_AFE_MISC_I32_EN);
1970
1971	/* Enable PLL. */
1972	rsu_write_1(sc, R92S_LDOA15_CTRL,
1973	    rsu_read_1(sc, R92S_LDOA15_CTRL) | R92S_LDA15_EN);
1974
1975	rsu_write_1(sc, R92S_LDOV12D_CTRL,
1976	    rsu_read_1(sc, R92S_LDOV12D_CTRL) | R92S_LDV12_EN);
1977
1978	rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1,
1979	    rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) | 0x08);
1980
1981	rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
1982	    rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x20);
1983
1984	/* Support 64KB IMEM. */
1985	rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1,
1986	    rsu_read_1(sc, R92S_SYS_ISO_CTRL + 1) & ~0x97);
1987
1988	/* Enable AFE clock. */
1989	rsu_write_1(sc, R92S_AFE_XTAL_CTRL + 1,
1990	    rsu_read_1(sc, R92S_AFE_XTAL_CTRL + 1) & ~0x04);
1991	/* Enable AFE PLL macro block. */
1992	reg = rsu_read_1(sc, R92S_AFE_PLL_CTRL);
1993	rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x11);
1994	DELAY(500);
1995	rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x51);
1996	DELAY(500);
1997	rsu_write_1(sc, R92S_AFE_PLL_CTRL, reg | 0x11);
1998	DELAY(500);
1999
2000	/* Attach AFE PLL to MACTOP/BB. */
2001	rsu_write_1(sc, R92S_SYS_ISO_CTRL,
2002	    rsu_read_1(sc, R92S_SYS_ISO_CTRL) & ~0x11);
2003
2004	/* Switch to 40MHz clock. */
2005	rsu_write_1(sc, R92S_SYS_CLKR, 0x00);
2006	/* Disable CPU clock and 80MHz SSC. */
2007	rsu_write_1(sc, R92S_SYS_CLKR,
2008	    rsu_read_1(sc, R92S_SYS_CLKR) | 0xa0);
2009	/* Enable MAC clock. */
2010	rsu_write_2(sc, R92S_SYS_CLKR,
2011	    rsu_read_2(sc, R92S_SYS_CLKR) |
2012	    R92S_MAC_CLK_EN | R92S_SYS_CLK_EN);
2013
2014	rsu_write_1(sc, R92S_PMC_FSM, 0x02);
2015
2016	/* Enable digital core and IOREG R/W. */
2017	rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
2018	    rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x08);
2019
2020	rsu_write_1(sc, R92S_SYS_FUNC_EN + 1,
2021	    rsu_read_1(sc, R92S_SYS_FUNC_EN + 1) | 0x80);
2022
2023	/* Switch the control path to firmware. */
2024	reg = rsu_read_2(sc, R92S_SYS_CLKR);
2025	reg = (reg & ~R92S_SWHW_SEL) | R92S_FWHW_SEL;
2026	rsu_write_2(sc, R92S_SYS_CLKR, reg);
2027
2028	rsu_write_2(sc, R92S_CR, 0x37fc);
2029
2030	/* Fix USB RX FIFO issue. */
2031	rsu_write_1(sc, 0xfe5c,
2032	    rsu_read_1(sc, 0xfe5c) | 0x80);
2033
2034	rsu_write_1(sc, R92S_SYS_CLKR,
2035	    rsu_read_1(sc, R92S_SYS_CLKR) & ~R92S_SYS_CPU_CLKSEL);
2036
2037	rsu_write_1(sc, 0xfe1c, 0x80);
2038
2039	/* Make sure TxDMA is ready to download firmware. */
2040	for (ntries = 0; ntries < 20; ntries++) {
2041		reg = rsu_read_1(sc, R92S_TCR);
2042		if ((reg & (R92S_TCR_IMEM_CHK_RPT | R92S_TCR_EMEM_CHK_RPT)) ==
2043		    (R92S_TCR_IMEM_CHK_RPT | R92S_TCR_EMEM_CHK_RPT))
2044			break;
2045		DELAY(5);
2046	}
2047	if (ntries == 20) {
2048		DPRINTF("TxDMA is not ready\n");
2049		/* Reset TxDMA. */
2050		reg = rsu_read_1(sc, R92S_CR);
2051		rsu_write_1(sc, R92S_CR, reg & ~R92S_CR_TXDMA_EN);
2052		DELAY(2);
2053		rsu_write_1(sc, R92S_CR, reg | R92S_CR_TXDMA_EN);
2054	}
2055}
2056
2057static void
2058rsu_power_off(struct rsu_softc *sc)
2059{
2060	/* Turn RF off. */
2061	rsu_write_1(sc, R92S_RF_CTRL, 0x00);
2062	usb_pause_mtx(&sc->sc_mtx, 5);
2063
2064	/* Turn MAC off. */
2065	/* Switch control path. */
2066	rsu_write_1(sc, R92S_SYS_CLKR + 1, 0x38);
2067	/* Reset MACTOP. */
2068	rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 0x70);
2069	rsu_write_1(sc, R92S_PMC_FSM, 0x06);
2070	rsu_write_1(sc, R92S_SYS_ISO_CTRL + 0, 0xf9);
2071	rsu_write_1(sc, R92S_SYS_ISO_CTRL + 1, 0xe8);
2072
2073	/* Disable AFE PLL. */
2074	rsu_write_1(sc, R92S_AFE_PLL_CTRL, 0x00);
2075	/* Disable A15V. */
2076	rsu_write_1(sc, R92S_LDOA15_CTRL, 0x54);
2077	/* Disable eFuse 1.2V. */
2078	rsu_write_1(sc, R92S_SYS_FUNC_EN + 1, 0x50);
2079	rsu_write_1(sc, R92S_LDOV12D_CTRL, 0x24);
2080	/* Enable AFE macro block's bandgap and Mbias. */
2081	rsu_write_1(sc, R92S_AFE_MISC, 0x30);
2082	/* Disable 1.6V LDO. */
2083	rsu_write_1(sc, R92S_SPS0_CTRL + 0, 0x56);
2084	rsu_write_1(sc, R92S_SPS0_CTRL + 1, 0x43);
2085}
2086
2087static int
2088rsu_fw_loadsection(struct rsu_softc *sc, const uint8_t *buf, int len)
2089{
2090	struct rsu_data *data;
2091	struct r92s_tx_desc *txd;
2092	int mlen;
2093
2094	while (len > 0) {
2095		data = rsu_getbuf(sc);
2096		if (data == NULL)
2097			return (ENOMEM);
2098		txd = (struct r92s_tx_desc *)data->buf;
2099		memset(txd, 0, sizeof(*txd));
2100		if (len <= RSU_TXBUFSZ - sizeof(*txd)) {
2101			/* Last chunk. */
2102			txd->txdw0 |= htole32(R92S_TXDW0_LINIP);
2103			mlen = len;
2104		} else
2105			mlen = RSU_TXBUFSZ - sizeof(*txd);
2106		txd->txdw0 |= htole32(SM(R92S_TXDW0_PKTLEN, mlen));
2107		memcpy(&txd[1], buf, mlen);
2108		data->buflen = sizeof(*txd) + mlen;
2109		DPRINTF("starting transfer %p\n", data);
2110		STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next);
2111		buf += mlen;
2112		len -= mlen;
2113	}
2114	usbd_transfer_start(sc->sc_xfer[RSU_BULK_TX_VO]);
2115
2116	return (0);
2117}
2118
2119static int
2120rsu_load_firmware(struct rsu_softc *sc)
2121{
2122	const struct r92s_fw_hdr *hdr;
2123	struct r92s_fw_priv *dmem;
2124	const uint8_t *imem, *emem;
2125	int imemsz, ememsz;
2126	const struct firmware *fw;
2127	size_t size;
2128	uint32_t reg;
2129	int ntries, error;
2130
2131	RSU_UNLOCK(sc);
2132	/* Read firmware image from the filesystem. */
2133	if ((fw = firmware_get("rsu-rtl8712fw")) == NULL) {
2134		device_printf(sc->sc_dev,
2135		    "%s: failed load firmware of file rsu-rtl8712fw\n",
2136		    __func__);
2137		RSU_LOCK(sc);
2138		return (ENXIO);
2139	}
2140	RSU_LOCK(sc);
2141	size = fw->datasize;
2142	if (size < sizeof(*hdr)) {
2143		device_printf(sc->sc_dev, "firmware too short\n");
2144		error = EINVAL;
2145		goto fail;
2146	}
2147	hdr = (const struct r92s_fw_hdr *)fw->data;
2148	if (hdr->signature != htole16(0x8712) &&
2149	    hdr->signature != htole16(0x8192)) {
2150		device_printf(sc->sc_dev,
2151		    "invalid firmware signature 0x%x\n",
2152		    le16toh(hdr->signature));
2153		error = EINVAL;
2154		goto fail;
2155	}
2156	DPRINTF("FW V%d %02x-%02x %02x:%02x\n", le16toh(hdr->version),
2157	    hdr->month, hdr->day, hdr->hour, hdr->minute);
2158
2159	/* Make sure that driver and firmware are in sync. */
2160	if (hdr->privsz != htole32(sizeof(*dmem))) {
2161		device_printf(sc->sc_dev, "unsupported firmware image\n");
2162		error = EINVAL;
2163		goto fail;
2164	}
2165	/* Get FW sections sizes. */
2166	imemsz = le32toh(hdr->imemsz);
2167	ememsz = le32toh(hdr->sramsz);
2168	/* Check that all FW sections fit in image. */
2169	if (size < sizeof(*hdr) + imemsz + ememsz) {
2170		device_printf(sc->sc_dev, "firmware too short\n");
2171		error = EINVAL;
2172		goto fail;
2173	}
2174	imem = (const uint8_t *)&hdr[1];
2175	emem = imem + imemsz;
2176
2177	/* Load IMEM section. */
2178	error = rsu_fw_loadsection(sc, imem, imemsz);
2179	if (error != 0) {
2180		device_printf(sc->sc_dev,
2181		    "could not load firmware section %s\n", "IMEM");
2182		goto fail;
2183	}
2184	/* Wait for load to complete. */
2185	for (ntries = 0; ntries < 10; ntries++) {
2186		usb_pause_mtx(&sc->sc_mtx, 10);
2187		reg = rsu_read_2(sc, R92S_TCR);
2188		if (reg & R92S_TCR_IMEM_CODE_DONE)
2189			break;
2190	}
2191	if (ntries == 10 || !(reg & R92S_TCR_IMEM_CHK_RPT)) {
2192		device_printf(sc->sc_dev, "timeout waiting for %s transfer\n",
2193		    "IMEM");
2194		error = ETIMEDOUT;
2195		goto fail;
2196	}
2197
2198	/* Load EMEM section. */
2199	error = rsu_fw_loadsection(sc, emem, ememsz);
2200	if (error != 0) {
2201		device_printf(sc->sc_dev,
2202		    "could not load firmware section %s\n", "EMEM");
2203		goto fail;
2204	}
2205	/* Wait for load to complete. */
2206	for (ntries = 0; ntries < 10; ntries++) {
2207		usb_pause_mtx(&sc->sc_mtx, 10);
2208		reg = rsu_read_2(sc, R92S_TCR);
2209		if (reg & R92S_TCR_EMEM_CODE_DONE)
2210			break;
2211	}
2212	if (ntries == 10 || !(reg & R92S_TCR_EMEM_CHK_RPT)) {
2213		device_printf(sc->sc_dev, "timeout waiting for %s transfer\n",
2214		    "EMEM");
2215		error = ETIMEDOUT;
2216		goto fail;
2217	}
2218
2219	/* Enable CPU. */
2220	rsu_write_1(sc, R92S_SYS_CLKR,
2221	    rsu_read_1(sc, R92S_SYS_CLKR) | R92S_SYS_CPU_CLKSEL);
2222	if (!(rsu_read_1(sc, R92S_SYS_CLKR) & R92S_SYS_CPU_CLKSEL)) {
2223		device_printf(sc->sc_dev, "could not enable system clock\n");
2224		error = EIO;
2225		goto fail;
2226	}
2227	rsu_write_2(sc, R92S_SYS_FUNC_EN,
2228	    rsu_read_2(sc, R92S_SYS_FUNC_EN) | R92S_FEN_CPUEN);
2229	if (!(rsu_read_2(sc, R92S_SYS_FUNC_EN) & R92S_FEN_CPUEN)) {
2230		device_printf(sc->sc_dev,
2231		    "could not enable microcontroller\n");
2232		error = EIO;
2233		goto fail;
2234	}
2235	/* Wait for CPU to initialize. */
2236	for (ntries = 0; ntries < 100; ntries++) {
2237		if (rsu_read_2(sc, R92S_TCR) & R92S_TCR_IMEM_RDY)
2238			break;
2239		DELAY(1000);
2240	}
2241	if (ntries == 100) {
2242		device_printf(sc->sc_dev,
2243		    "timeout waiting for microcontroller\n");
2244		error = ETIMEDOUT;
2245		goto fail;
2246	}
2247
2248	/* Update DMEM section before loading. */
2249	dmem = __DECONST(struct r92s_fw_priv *, &hdr->priv);
2250	memset(dmem, 0, sizeof(*dmem));
2251	dmem->hci_sel = R92S_HCI_SEL_USB | R92S_HCI_SEL_8172;
2252	dmem->nendpoints = sc->npipes;
2253	dmem->rf_config = 0x12;	/* 1T2R */
2254	dmem->vcs_type = R92S_VCS_TYPE_AUTO;
2255	dmem->vcs_mode = R92S_VCS_MODE_RTS_CTS;
2256#ifdef notyet
2257	dmem->bw40_en = (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40) != 0;
2258#endif
2259	dmem->turbo_mode = 1;
2260	/* Load DMEM section. */
2261	error = rsu_fw_loadsection(sc, (uint8_t *)dmem, sizeof(*dmem));
2262	if (error != 0) {
2263		device_printf(sc->sc_dev,
2264		    "could not load firmware section %s\n", "DMEM");
2265		goto fail;
2266	}
2267	/* Wait for load to complete. */
2268	for (ntries = 0; ntries < 100; ntries++) {
2269		if (rsu_read_2(sc, R92S_TCR) & R92S_TCR_DMEM_CODE_DONE)
2270			break;
2271		DELAY(1000);
2272	}
2273	if (ntries == 100) {
2274		device_printf(sc->sc_dev, "timeout waiting for %s transfer\n",
2275		    "DMEM");
2276		error = ETIMEDOUT;
2277		goto fail;
2278	}
2279	/* Wait for firmware readiness. */
2280	for (ntries = 0; ntries < 60; ntries++) {
2281		if (!(rsu_read_2(sc, R92S_TCR) & R92S_TCR_FWRDY))
2282			break;
2283		DELAY(1000);
2284	}
2285	if (ntries == 60) {
2286		device_printf(sc->sc_dev,
2287		    "timeout waiting for firmware readiness\n");
2288		error = ETIMEDOUT;
2289		goto fail;
2290	}
2291 fail:
2292	firmware_put(fw, FIRMWARE_UNLOAD);
2293	return (error);
2294}
2295
2296
2297static int
2298rsu_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
2299    const struct ieee80211_bpf_params *params)
2300{
2301	struct ieee80211com *ic = ni->ni_ic;
2302	struct ifnet *ifp = ic->ic_ifp;
2303	struct rsu_softc *sc = ifp->if_softc;
2304	struct rsu_data *bf;
2305
2306	/* prevent management frames from being sent if we're not ready */
2307	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
2308		m_freem(m);
2309		ieee80211_free_node(ni);
2310		return (ENETDOWN);
2311	}
2312	RSU_LOCK(sc);
2313	bf = rsu_getbuf(sc);
2314	if (bf == NULL) {
2315		ieee80211_free_node(ni);
2316		m_freem(m);
2317		RSU_UNLOCK(sc);
2318		return (ENOBUFS);
2319	}
2320	ifp->if_opackets++;
2321	if (rsu_tx_start(sc, ni, m, bf) != 0) {
2322		ieee80211_free_node(ni);
2323		ifp->if_oerrors++;
2324		STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next);
2325		RSU_UNLOCK(sc);
2326		return (EIO);
2327	}
2328	RSU_UNLOCK(sc);
2329	sc->sc_tx_timer = 5;
2330
2331	return (0);
2332}
2333
2334static void
2335rsu_init(void *arg)
2336{
2337	struct rsu_softc *sc = arg;
2338
2339	RSU_LOCK(sc);
2340	rsu_init_locked(arg);
2341	RSU_UNLOCK(sc);
2342}
2343
2344static void
2345rsu_init_locked(struct rsu_softc *sc)
2346{
2347	struct ifnet *ifp = sc->sc_ifp;
2348	struct r92s_set_pwr_mode cmd;
2349	int error;
2350
2351	/* Init host async commands ring. */
2352	sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0;
2353
2354	/* Allocate Tx/Rx buffers. */
2355	error = rsu_alloc_rx_list(sc);
2356	if (error != 0) {
2357		device_printf(sc->sc_dev, "could not allocate Rx buffers\n");
2358		return;
2359	}
2360	error = rsu_alloc_tx_list(sc);
2361	if (error != 0) {
2362		device_printf(sc->sc_dev, "could not allocate Tx buffers\n");
2363		rsu_free_rx_list(sc);
2364		return;
2365	}
2366	/* Power on adapter. */
2367	if (sc->cut == 1)
2368		rsu_power_on_acut(sc);
2369	else
2370		rsu_power_on_bcut(sc);
2371	/* Load firmware. */
2372	error = rsu_load_firmware(sc);
2373	if (error != 0)
2374		goto fail;
2375
2376	/* Enable Rx TCP checksum offload. */
2377	rsu_write_4(sc, R92S_RCR,
2378	    rsu_read_4(sc, R92S_RCR) | 0x04000000);
2379	/* Append PHY status. */
2380	rsu_write_4(sc, R92S_RCR,
2381	    rsu_read_4(sc, R92S_RCR) | 0x02000000);
2382
2383	rsu_write_4(sc, R92S_CR,
2384	    rsu_read_4(sc, R92S_CR) & ~0xff000000);
2385
2386	/* Use 128 bytes pages. */
2387	rsu_write_1(sc, 0x00b5,
2388	    rsu_read_1(sc, 0x00b5) | 0x01);
2389	/* Enable USB Rx aggregation. */
2390	rsu_write_1(sc, 0x00bd,
2391	    rsu_read_1(sc, 0x00bd) | 0x80);
2392	/* Set USB Rx aggregation threshold. */
2393	rsu_write_1(sc, 0x00d9, 0x01);
2394	/* Set USB Rx aggregation timeout (1.7ms/4). */
2395	rsu_write_1(sc, 0xfe5b, 0x04);
2396	/* Fix USB Rx FIFO issue. */
2397	rsu_write_1(sc, 0xfe5c,
2398	    rsu_read_1(sc, 0xfe5c) | 0x80);
2399
2400	/* Set MAC address. */
2401	rsu_write_region_1(sc, R92S_MACID, IF_LLADDR(ifp),
2402	    IEEE80211_ADDR_LEN);
2403
2404	/* NB: it really takes that long for firmware to boot. */
2405	usb_pause_mtx(&sc->sc_mtx, 1500);
2406
2407	DPRINTF("setting MAC address to %s\n", ether_sprintf(IF_LLADDR(ifp)));
2408	error = rsu_fw_cmd(sc, R92S_CMD_SET_MAC_ADDRESS, IF_LLADDR(ifp),
2409	    IEEE80211_ADDR_LEN);
2410	if (error != 0) {
2411		device_printf(sc->sc_dev, "could not set MAC address\n");
2412		goto fail;
2413	}
2414
2415	rsu_write_1(sc, R92S_USB_HRPWM,
2416	    R92S_USB_HRPWM_PS_ST_ACTIVE | R92S_USB_HRPWM_PS_ALL_ON);
2417
2418	memset(&cmd, 0, sizeof(cmd));
2419	cmd.mode = R92S_PS_MODE_ACTIVE;
2420	DPRINTF("setting ps mode to %d\n", cmd.mode);
2421	error = rsu_fw_cmd(sc, R92S_CMD_SET_PWR_MODE, &cmd, sizeof(cmd));
2422	if (error != 0) {
2423		device_printf(sc->sc_dev, "could not set PS mode\n");
2424		goto fail;
2425	}
2426
2427#if 0
2428	if (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40) {
2429		/* Enable 40MHz mode. */
2430		error = rsu_fw_iocmd(sc,
2431		    SM(R92S_IOCMD_CLASS, 0xf4) |
2432		    SM(R92S_IOCMD_INDEX, 0x00) |
2433		    SM(R92S_IOCMD_VALUE, 0x0007));
2434		if (error != 0) {
2435			device_printf(sc->sc_dev,
2436			    "could not enable 40MHz mode\n");
2437			goto fail;
2438		}
2439	}
2440
2441	/* Set default channel. */
2442	ic->ic_bss->ni_chan = ic->ic_ibss_chan;
2443#endif
2444	sc->scan_pass = 0;
2445	usbd_transfer_start(sc->sc_xfer[RSU_BULK_RX]);
2446
2447	/* We're ready to go. */
2448	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
2449	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2450
2451	callout_reset(&sc->sc_watchdog_ch, hz, rsu_watchdog, sc);
2452
2453	return;
2454fail:
2455	rsu_free_rx_list(sc);
2456	rsu_free_tx_list(sc);
2457	return;
2458}
2459
2460static void
2461rsu_stop(struct ifnet *ifp, int disable)
2462{
2463	struct rsu_softc *sc = ifp->if_softc;
2464
2465	RSU_LOCK(sc);
2466	rsu_stop_locked(ifp, disable);
2467	RSU_UNLOCK(sc);
2468}
2469
2470static void
2471rsu_stop_locked(struct ifnet *ifp, int disable __unused)
2472{
2473	struct rsu_softc *sc = ifp->if_softc;
2474	int i;
2475
2476	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
2477	callout_stop(&sc->sc_watchdog_ch);
2478	sc->sc_calibrating = 0;
2479	taskqueue_cancel_timeout(taskqueue_thread, &sc->calib_task, NULL);
2480
2481	/* Power off adapter. */
2482	rsu_power_off(sc);
2483
2484	for (i = 0; i < RSU_N_TRANSFER; i++)
2485		usbd_transfer_stop(sc->sc_xfer[i]);
2486}
2487
2488