14c1d81b2Sjmcneill /* $OpenBSD: if_rum.c,v 1.40 2006/09/18 16:20:20 damien Exp $ */
2*481d3881Srin /* $NetBSD: if_rum.c,v 1.71 2024/07/05 04:31:52 rin Exp $ */
3fc0bc19fSjoerg
4fc0bc19fSjoerg /*-
53bf7c476Skiyohara * Copyright (c) 2005-2007 Damien Bergamini <damien.bergamini@free.fr>
6fc0bc19fSjoerg * Copyright (c) 2006 Niall O'Higgins <niallo@openbsd.org>
7fc0bc19fSjoerg *
8fc0bc19fSjoerg * Permission to use, copy, modify, and distribute this software for any
9fc0bc19fSjoerg * purpose with or without fee is hereby granted, provided that the above
10fc0bc19fSjoerg * copyright notice and this permission notice appear in all copies.
11fc0bc19fSjoerg *
12fc0bc19fSjoerg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13fc0bc19fSjoerg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14fc0bc19fSjoerg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15fc0bc19fSjoerg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16fc0bc19fSjoerg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17fc0bc19fSjoerg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18fc0bc19fSjoerg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19fc0bc19fSjoerg */
20fc0bc19fSjoerg
21fc0bc19fSjoerg /*-
22fc0bc19fSjoerg * Ralink Technology RT2501USB/RT2601USB chipset driver
233bf7c476Skiyohara * http://www.ralinktech.com.tw/
24fc0bc19fSjoerg */
25fc0bc19fSjoerg
26c671ada8Sxtraeme #include <sys/cdefs.h>
27*481d3881Srin __KERNEL_RCSID(0, "$NetBSD: if_rum.c,v 1.71 2024/07/05 04:31:52 rin Exp $");
28a7c71d30Sskrll
29a7c71d30Sskrll #ifdef _KERNEL_OPT
30a7c71d30Sskrll #include "opt_usb.h"
31a7c71d30Sskrll #endif
32fc0bc19fSjoerg
33fc0bc19fSjoerg #include <sys/param.h>
34fc0bc19fSjoerg #include <sys/sockio.h>
35fc0bc19fSjoerg #include <sys/sysctl.h>
36fc0bc19fSjoerg #include <sys/mbuf.h>
37fc0bc19fSjoerg #include <sys/kernel.h>
38fc0bc19fSjoerg #include <sys/socket.h>
39fc0bc19fSjoerg #include <sys/systm.h>
4075c5b198Spgoyette #include <sys/module.h>
41fc0bc19fSjoerg #include <sys/conf.h>
42fc0bc19fSjoerg #include <sys/device.h>
43fc0bc19fSjoerg
44a2a38285Sad #include <sys/bus.h>
45fc0bc19fSjoerg #include <machine/endian.h>
46a2a38285Sad #include <sys/intr.h>
47fc0bc19fSjoerg
48fc0bc19fSjoerg #include <net/bpf.h>
49fc0bc19fSjoerg #include <net/if.h>
50fc0bc19fSjoerg #include <net/if_arp.h>
51fc0bc19fSjoerg #include <net/if_dl.h>
52fc0bc19fSjoerg #include <net/if_ether.h>
53fc0bc19fSjoerg #include <net/if_media.h>
54fc0bc19fSjoerg #include <net/if_types.h>
55fc0bc19fSjoerg
56fc0bc19fSjoerg #include <netinet/in.h>
57fc0bc19fSjoerg #include <netinet/in_systm.h>
58fc0bc19fSjoerg #include <netinet/in_var.h>
59fc0bc19fSjoerg #include <netinet/ip.h>
60fc0bc19fSjoerg
61fc0bc19fSjoerg #include <net80211/ieee80211_netbsd.h>
62fc0bc19fSjoerg #include <net80211/ieee80211_var.h>
63fc0bc19fSjoerg #include <net80211/ieee80211_amrr.h>
64fc0bc19fSjoerg #include <net80211/ieee80211_radiotap.h>
65fc0bc19fSjoerg
66fc0bc19fSjoerg #include <dev/firmload.h>
67fc0bc19fSjoerg
68fc0bc19fSjoerg #include <dev/usb/usb.h>
69fc0bc19fSjoerg #include <dev/usb/usbdi.h>
70fc0bc19fSjoerg #include <dev/usb/usbdi_util.h>
71fc0bc19fSjoerg #include <dev/usb/usbdevs.h>
72fc0bc19fSjoerg
73fc0bc19fSjoerg #include <dev/usb/if_rumreg.h>
74fc0bc19fSjoerg #include <dev/usb/if_rumvar.h>
75fc0bc19fSjoerg
76fc0bc19fSjoerg #ifdef RUM_DEBUG
7768c8418cSdyoung #define DPRINTF(x) do { if (rum_debug) printf x; } while (0)
7868c8418cSdyoung #define DPRINTFN(n, x) do { if (rum_debug >= (n)) printf x; } while (0)
790a7a89a5Sxtraeme int rum_debug = 1;
80fc0bc19fSjoerg #else
81fc0bc19fSjoerg #define DPRINTF(x)
82fc0bc19fSjoerg #define DPRINTFN(n, x)
83fc0bc19fSjoerg #endif
84fc0bc19fSjoerg
85fc0bc19fSjoerg /* various supported device vendors/products */
86fc0bc19fSjoerg static const struct usb_devno rum_devs[] = {
870a7a89a5Sxtraeme { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_HWU54DM },
880a7a89a5Sxtraeme { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2573_2 },
890a7a89a5Sxtraeme { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2573_3 },
900a7a89a5Sxtraeme { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2573_4 },
913bf7c476Skiyohara { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_WUG2700 },
920a7a89a5Sxtraeme { USB_VENDOR_AMIT, USB_PRODUCT_AMIT_CGWLUSB2GO },
930065b980Sxtraeme { USB_VENDOR_ASUSTEK, USB_PRODUCT_ASUSTEK_WL167G_2 },
940a7a89a5Sxtraeme { USB_VENDOR_ASUSTEK, USB_PRODUCT_ASUSTEK_WL167G_3 },
95fc0bc19fSjoerg { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D7050A },
96fc0bc19fSjoerg { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D9050V3 },
97bd1aea20Schs { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D9050C },
98bd1aea20Schs { USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSB200 },
99fc0bc19fSjoerg { USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSB54GC },
1000a7a89a5Sxtraeme { USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_WUSB54GR },
101fc0bc19fSjoerg { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_C54RU2 },
102bd1aea20Schs { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_RT2573 },
1033bf7c476Skiyohara { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_CGWLUSB2GL },
1043caafa96Sjun { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_CGWLUSB2GPX },
105fc0bc19fSjoerg { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_CWD854F },
106fc0bc19fSjoerg { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_RT2573 },
107fc0bc19fSjoerg { USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWLG122C1 },
108fc0bc19fSjoerg { USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_WUA1340 },
10907ba3f91Schristos { USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWA110 },
1107c544ae1Spooka { USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DWA111 },
111bd1aea20Schs { USB_VENDOR_EDIMAX, USB_PRODUCT_EDIMAX_EW7318 },
112bd1aea20Schs { USB_VENDOR_EDIMAX, USB_PRODUCT_EDIMAX_EW7618 },
113fc0bc19fSjoerg { USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWB01GS },
1140a7a89a5Sxtraeme { USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWI05GS },
115fc0bc19fSjoerg { USB_VENDOR_GIGASET, USB_PRODUCT_GIGASET_RT2573 },
116fc0bc19fSjoerg { USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_RT2573 },
1170a7a89a5Sxtraeme { USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWGUSB254LB },
1180a7a89a5Sxtraeme { USB_VENDOR_GUILLEMOT, USB_PRODUCT_GUILLEMOT_HWGUSB254V2AP },
119fc0bc19fSjoerg { USB_VENDOR_HUAWEI3COM, USB_PRODUCT_HUAWEI3COM_RT2573 },
1200a7a89a5Sxtraeme { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_G54HP },
121b5f35499Selad { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_SG54HP },
122bd1aea20Schs { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_SG54HG },
123591b8c1eStshiozak { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_WLIUCG },
124fc0bc19fSjoerg { USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2573 },
125fc0bc19fSjoerg { USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2573_2 },
126fc0bc19fSjoerg { USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2573_3 },
1270a7a89a5Sxtraeme { USB_VENDOR_MSI, USB_PRODUCT_MSI_RT2573_4 },
1280a7a89a5Sxtraeme { USB_VENDOR_NOVATECH, USB_PRODUCT_NOVATECH_RT2573 },
1290a7a89a5Sxtraeme { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS54HP },
130b5f35499Selad { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUS54MINI2 },
131fc0bc19fSjoerg { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GWUSMM },
132fc0bc19fSjoerg { USB_VENDOR_QCOM, USB_PRODUCT_QCOM_RT2573 },
133fc0bc19fSjoerg { USB_VENDOR_QCOM, USB_PRODUCT_QCOM_RT2573_2 },
13436662bbcSuebayasi { USB_VENDOR_QCOM, USB_PRODUCT_QCOM_RT2573_3 },
135fc0bc19fSjoerg { USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2573 },
136fc0bc19fSjoerg { USB_VENDOR_RALINK, USB_PRODUCT_RALINK_RT2671 },
137fc0bc19fSjoerg { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL113R2 },
138fc0bc19fSjoerg { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_WL172 },
139bd1aea20Schs { USB_VENDOR_SPARKLAN, USB_PRODUCT_SPARKLAN_RT2573 },
140bd1aea20Schs { USB_VENDOR_SURECOM, USB_PRODUCT_SURECOM_RT2573 },
141c55f55c6Skhorben { USB_VENDOR_SYNET, USB_PRODUCT_SYNET_MWP54SS },
142bd1aea20Schs { USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_RT2573 }
143fc0bc19fSjoerg };
144fc0bc19fSjoerg
14587931599Sjmcneill static int rum_attachhook(void *);
14687931599Sjmcneill static int rum_alloc_tx_list(struct rum_softc *);
14787931599Sjmcneill static void rum_free_tx_list(struct rum_softc *);
14887931599Sjmcneill static int rum_alloc_rx_list(struct rum_softc *);
14987931599Sjmcneill static void rum_free_rx_list(struct rum_softc *);
15087931599Sjmcneill static int rum_media_change(struct ifnet *);
15187931599Sjmcneill static void rum_next_scan(void *);
15287931599Sjmcneill static void rum_task(void *);
15387931599Sjmcneill static int rum_newstate(struct ieee80211com *,
154fc0bc19fSjoerg enum ieee80211_state, int);
1554e8e6643Sskrll static void rum_txeof(struct usbd_xfer *, void *,
156fc0bc19fSjoerg usbd_status);
1574e8e6643Sskrll static void rum_rxeof(struct usbd_xfer *, void *,
158fc0bc19fSjoerg usbd_status);
15987931599Sjmcneill static uint8_t rum_rxrate(const struct rum_rx_desc *);
16087931599Sjmcneill static int rum_ack_rate(struct ieee80211com *, int);
16187931599Sjmcneill static uint16_t rum_txtime(int, int, uint32_t);
16287931599Sjmcneill static uint8_t rum_plcp_signal(int);
16387931599Sjmcneill static void rum_setup_tx_desc(struct rum_softc *,
164fc0bc19fSjoerg struct rum_tx_desc *, uint32_t, uint16_t, int,
165fc0bc19fSjoerg int);
16687931599Sjmcneill static int rum_tx_data(struct rum_softc *, struct mbuf *,
167fc0bc19fSjoerg struct ieee80211_node *);
16887931599Sjmcneill static void rum_start(struct ifnet *);
16987931599Sjmcneill static void rum_watchdog(struct ifnet *);
17087931599Sjmcneill static int rum_ioctl(struct ifnet *, u_long, void *);
17187931599Sjmcneill static void rum_eeprom_read(struct rum_softc *, uint16_t, void *,
172fc0bc19fSjoerg int);
17387931599Sjmcneill static uint32_t rum_read(struct rum_softc *, uint16_t);
17487931599Sjmcneill static void rum_read_multi(struct rum_softc *, uint16_t, void *,
175fc0bc19fSjoerg int);
17687931599Sjmcneill static void rum_write(struct rum_softc *, uint16_t, uint32_t);
17787931599Sjmcneill static void rum_write_multi(struct rum_softc *, uint16_t, void *,
178fc0bc19fSjoerg size_t);
17987931599Sjmcneill static void rum_bbp_write(struct rum_softc *, uint8_t, uint8_t);
18087931599Sjmcneill static uint8_t rum_bbp_read(struct rum_softc *, uint8_t);
18187931599Sjmcneill static void rum_rf_write(struct rum_softc *, uint8_t, uint32_t);
18287931599Sjmcneill static void rum_select_antenna(struct rum_softc *);
18387931599Sjmcneill static void rum_enable_mrr(struct rum_softc *);
18487931599Sjmcneill static void rum_set_txpreamble(struct rum_softc *);
18587931599Sjmcneill static void rum_set_basicrates(struct rum_softc *);
18687931599Sjmcneill static void rum_select_band(struct rum_softc *,
187fc0bc19fSjoerg struct ieee80211_channel *);
18887931599Sjmcneill static void rum_set_chan(struct rum_softc *,
189fc0bc19fSjoerg struct ieee80211_channel *);
19087931599Sjmcneill static void rum_enable_tsf_sync(struct rum_softc *);
19187931599Sjmcneill static void rum_update_slot(struct rum_softc *);
19287931599Sjmcneill static void rum_set_bssid(struct rum_softc *, const uint8_t *);
19387931599Sjmcneill static void rum_set_macaddr(struct rum_softc *, const uint8_t *);
19487931599Sjmcneill static void rum_update_promisc(struct rum_softc *);
19587931599Sjmcneill static const char *rum_get_rf(int);
19687931599Sjmcneill static void rum_read_eeprom(struct rum_softc *);
19787931599Sjmcneill static int rum_bbp_init(struct rum_softc *);
19887931599Sjmcneill static int rum_init(struct ifnet *);
19987931599Sjmcneill static void rum_stop(struct ifnet *, int);
20087931599Sjmcneill static int rum_load_microcode(struct rum_softc *, const u_char *,
201fc0bc19fSjoerg size_t);
20287931599Sjmcneill static int rum_prepare_beacon(struct rum_softc *);
20387931599Sjmcneill static void rum_newassoc(struct ieee80211_node *, int);
20487931599Sjmcneill static void rum_amrr_start(struct rum_softc *,
205fc0bc19fSjoerg struct ieee80211_node *);
20687931599Sjmcneill static void rum_amrr_timeout(void *);
2074e8e6643Sskrll static void rum_amrr_update(struct usbd_xfer *, void *,
2084e8e6643Sskrll usbd_status);
209fc0bc19fSjoerg
210fc0bc19fSjoerg static const struct {
211fc0bc19fSjoerg uint32_t reg;
212fc0bc19fSjoerg uint32_t val;
213fc0bc19fSjoerg } rum_def_mac[] = {
214fc0bc19fSjoerg RT2573_DEF_MAC
215fc0bc19fSjoerg };
216fc0bc19fSjoerg
217fc0bc19fSjoerg static const struct {
218fc0bc19fSjoerg uint8_t reg;
219fc0bc19fSjoerg uint8_t val;
220fc0bc19fSjoerg } rum_def_bbp[] = {
221fc0bc19fSjoerg RT2573_DEF_BBP
222fc0bc19fSjoerg };
223fc0bc19fSjoerg
224fc0bc19fSjoerg static const struct rfprog {
225fc0bc19fSjoerg uint8_t chan;
226fc0bc19fSjoerg uint32_t r1, r2, r3, r4;
227fc0bc19fSjoerg } rum_rf5226[] = {
228fc0bc19fSjoerg RT2573_RF5226
229fc0bc19fSjoerg }, rum_rf5225[] = {
230fc0bc19fSjoerg RT2573_RF5225
231fc0bc19fSjoerg };
232fc0bc19fSjoerg
23387931599Sjmcneill static int rum_match(device_t, cfdata_t, void *);
23487931599Sjmcneill static void rum_attach(device_t, device_t, void *);
23587931599Sjmcneill static int rum_detach(device_t, int);
23687931599Sjmcneill static int rum_activate(device_t, enum devact);
2373b24a134Smrg
23868c8418cSdyoung CFATTACH_DECL_NEW(rum, sizeof(struct rum_softc), rum_match, rum_attach,
23968c8418cSdyoung rum_detach, rum_activate);
240fc0bc19fSjoerg
24187931599Sjmcneill static int
rum_match(device_t parent,cfdata_t match,void * aux)24268c8418cSdyoung rum_match(device_t parent, cfdata_t match, void *aux)
243fc0bc19fSjoerg {
24468c8418cSdyoung struct usb_attach_arg *uaa = aux;
245fc0bc19fSjoerg
2464e8e6643Sskrll return (usb_lookup(rum_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL) ?
247fc0bc19fSjoerg UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
248fc0bc19fSjoerg }
249fc0bc19fSjoerg
25087931599Sjmcneill static int
rum_attachhook(void * xsc)251fc0bc19fSjoerg rum_attachhook(void *xsc)
252fc0bc19fSjoerg {
253fc0bc19fSjoerg struct rum_softc *sc = xsc;
254fc0bc19fSjoerg firmware_handle_t fwh;
255fc0bc19fSjoerg const char *name = "rum-rt2573";
256fc0bc19fSjoerg u_char *ucode;
257fc0bc19fSjoerg size_t size;
258fc0bc19fSjoerg int error;
259fc0bc19fSjoerg
260fc0bc19fSjoerg if ((error = firmware_open("rum", name, &fwh)) != 0) {
261ef8ca4bcSryoon printf("%s: failed firmware_open of file %s (error %d)\n",
26268c8418cSdyoung device_xname(sc->sc_dev), name, error);
263fc0bc19fSjoerg return error;
264fc0bc19fSjoerg }
265fc0bc19fSjoerg size = firmware_get_size(fwh);
266fc0bc19fSjoerg ucode = firmware_malloc(size);
267fc0bc19fSjoerg if (ucode == NULL) {
268fc0bc19fSjoerg printf("%s: failed to allocate firmware memory\n",
26968c8418cSdyoung device_xname(sc->sc_dev));
270fc0bc19fSjoerg firmware_close(fwh);
271b1fea837Syamt return ENOMEM;
272fc0bc19fSjoerg }
273fc0bc19fSjoerg error = firmware_read(fwh, 0, ucode, size);
274fc0bc19fSjoerg firmware_close(fwh);
275fc0bc19fSjoerg if (error != 0) {
276fc0bc19fSjoerg printf("%s: failed to read firmware (error %d)\n",
27768c8418cSdyoung device_xname(sc->sc_dev), error);
2783cde4cbcSozaki-r firmware_free(ucode, size);
279fc0bc19fSjoerg return error;
280fc0bc19fSjoerg }
281fc0bc19fSjoerg
282fc0bc19fSjoerg if (rum_load_microcode(sc, ucode, size) != 0) {
283fc0bc19fSjoerg printf("%s: could not load 8051 microcode\n",
28468c8418cSdyoung device_xname(sc->sc_dev));
2853cde4cbcSozaki-r firmware_free(ucode, size);
286fc0bc19fSjoerg return ENXIO;
287fc0bc19fSjoerg }
288fc0bc19fSjoerg
2893cde4cbcSozaki-r firmware_free(ucode, size);
290fc0bc19fSjoerg sc->sc_flags |= RT2573_FWLOADED;
291fc0bc19fSjoerg
292fc0bc19fSjoerg return 0;
293fc0bc19fSjoerg }
294fc0bc19fSjoerg
29587931599Sjmcneill static void
rum_attach(device_t parent,device_t self,void * aux)29668c8418cSdyoung rum_attach(device_t parent, device_t self, void *aux)
297fc0bc19fSjoerg {
29868c8418cSdyoung struct rum_softc *sc = device_private(self);
29968c8418cSdyoung struct usb_attach_arg *uaa = aux;
300fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
301fc0bc19fSjoerg struct ifnet *ifp = &sc->sc_if;
302fc0bc19fSjoerg usb_interface_descriptor_t *id;
303fc0bc19fSjoerg usb_endpoint_descriptor_t *ed;
304fc0bc19fSjoerg usbd_status error;
305fc0bc19fSjoerg char *devinfop;
306fc0bc19fSjoerg int i, ntries;
307fc0bc19fSjoerg uint32_t tmp;
308fc0bc19fSjoerg
3093624455eScube sc->sc_dev = self;
3104e8e6643Sskrll sc->sc_udev = uaa->uaa_device;
311fc0bc19fSjoerg sc->sc_flags = 0;
312fc0bc19fSjoerg
3135fab894cSplunky aprint_naive("\n");
3145fab894cSplunky aprint_normal("\n");
3155fab894cSplunky
316fc0bc19fSjoerg devinfop = usbd_devinfo_alloc(sc->sc_udev, 0);
3173624455eScube aprint_normal_dev(self, "%s\n", devinfop);
318fc0bc19fSjoerg usbd_devinfo_free(devinfop);
319fc0bc19fSjoerg
320897388eaSskrll error = usbd_set_config_no(sc->sc_udev, RT2573_CONFIG_NO, 0);
321897388eaSskrll if (error != 0) {
322897388eaSskrll aprint_error_dev(self, "failed to set configuration"
323897388eaSskrll ", err=%s\n", usbd_errstr(error));
32468c8418cSdyoung return;
325fc0bc19fSjoerg }
326fc0bc19fSjoerg
327fc0bc19fSjoerg /* get the first interface handle */
328fc0bc19fSjoerg error = usbd_device2interface_handle(sc->sc_udev, RT2573_IFACE_INDEX,
329fc0bc19fSjoerg &sc->sc_iface);
330fc0bc19fSjoerg if (error != 0) {
3313624455eScube aprint_error_dev(self, "could not get interface handle\n");
33268c8418cSdyoung return;
333fc0bc19fSjoerg }
334fc0bc19fSjoerg
335fc0bc19fSjoerg /*
336fc0bc19fSjoerg * Find endpoints.
337fc0bc19fSjoerg */
338fc0bc19fSjoerg id = usbd_get_interface_descriptor(sc->sc_iface);
339fc0bc19fSjoerg
340fc0bc19fSjoerg sc->sc_rx_no = sc->sc_tx_no = -1;
341fc0bc19fSjoerg for (i = 0; i < id->bNumEndpoints; i++) {
342fc0bc19fSjoerg ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
343fc0bc19fSjoerg if (ed == NULL) {
3443624455eScube aprint_error_dev(self,
3453624455eScube "no endpoint descriptor for iface %d\n", i);
34668c8418cSdyoung return;
347fc0bc19fSjoerg }
348fc0bc19fSjoerg
349fc0bc19fSjoerg if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
350fc0bc19fSjoerg UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
351fc0bc19fSjoerg sc->sc_rx_no = ed->bEndpointAddress;
352fc0bc19fSjoerg else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
353fc0bc19fSjoerg UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
354fc0bc19fSjoerg sc->sc_tx_no = ed->bEndpointAddress;
355fc0bc19fSjoerg }
356fc0bc19fSjoerg if (sc->sc_rx_no == -1 || sc->sc_tx_no == -1) {
3573624455eScube aprint_error_dev(self, "missing endpoint\n");
35868c8418cSdyoung return;
359fc0bc19fSjoerg }
360fc0bc19fSjoerg
3617c64a30eSjmcneill usb_init_task(&sc->sc_task, rum_task, sc, 0);
36268c8418cSdyoung callout_init(&sc->sc_scan_ch, 0);
363fc0bc19fSjoerg
364fc0bc19fSjoerg sc->amrr.amrr_min_success_threshold = 1;
365fc0bc19fSjoerg sc->amrr.amrr_max_success_threshold = 10;
36668c8418cSdyoung callout_init(&sc->sc_amrr_ch, 0);
367fc0bc19fSjoerg
368fc0bc19fSjoerg /* retrieve RT2573 rev. no */
369fc0bc19fSjoerg for (ntries = 0; ntries < 1000; ntries++) {
370fc0bc19fSjoerg if ((tmp = rum_read(sc, RT2573_MAC_CSR0)) != 0)
371fc0bc19fSjoerg break;
372fc0bc19fSjoerg DELAY(1000);
373fc0bc19fSjoerg }
374fc0bc19fSjoerg if (ntries == 1000) {
3753624455eScube aprint_error_dev(self, "timeout waiting for chip to settle\n");
37668c8418cSdyoung return;
377fc0bc19fSjoerg }
378fc0bc19fSjoerg
379fc0bc19fSjoerg /* retrieve MAC address and various other things from EEPROM */
380fc0bc19fSjoerg rum_read_eeprom(sc);
381fc0bc19fSjoerg
3823624455eScube aprint_normal_dev(self,
383aa3d6ec1Schristos "MAC/BBP RT%04x (rev 0x%05x), RF %s, address %s\n",
3843624455eScube sc->macbbp_rev, tmp,
385fc0bc19fSjoerg rum_get_rf(sc->rf_rev), ether_sprintf(ic->ic_myaddr));
386fc0bc19fSjoerg
387fc0bc19fSjoerg ic->ic_ifp = ifp;
388fc0bc19fSjoerg ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
389fc0bc19fSjoerg ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
390fc0bc19fSjoerg ic->ic_state = IEEE80211_S_INIT;
391fc0bc19fSjoerg
392fc0bc19fSjoerg /* set device capabilities */
393fc0bc19fSjoerg ic->ic_caps =
394fc0bc19fSjoerg IEEE80211_C_IBSS | /* IBSS mode supported */
395fc0bc19fSjoerg IEEE80211_C_MONITOR | /* monitor mode supported */
396fc0bc19fSjoerg IEEE80211_C_HOSTAP | /* HostAp mode supported */
397fc0bc19fSjoerg IEEE80211_C_TXPMGT | /* tx power management */
398fc0bc19fSjoerg IEEE80211_C_SHPREAMBLE | /* short preamble supported */
399fc0bc19fSjoerg IEEE80211_C_SHSLOT | /* short slot time supported */
400fc0bc19fSjoerg IEEE80211_C_WPA; /* 802.11i */
401fc0bc19fSjoerg
402fc0bc19fSjoerg if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_5226) {
403fc0bc19fSjoerg /* set supported .11a rates */
404eddea7afSmaya ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a;
405fc0bc19fSjoerg
406fc0bc19fSjoerg /* set supported .11a channels */
407fc0bc19fSjoerg for (i = 34; i <= 46; i += 4) {
408fc0bc19fSjoerg ic->ic_channels[i].ic_freq =
409fc0bc19fSjoerg ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
410fc0bc19fSjoerg ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
411fc0bc19fSjoerg }
412fc0bc19fSjoerg for (i = 36; i <= 64; i += 4) {
413fc0bc19fSjoerg ic->ic_channels[i].ic_freq =
414fc0bc19fSjoerg ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
415fc0bc19fSjoerg ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
416fc0bc19fSjoerg }
417fc0bc19fSjoerg for (i = 100; i <= 140; i += 4) {
418fc0bc19fSjoerg ic->ic_channels[i].ic_freq =
419fc0bc19fSjoerg ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
420fc0bc19fSjoerg ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
421fc0bc19fSjoerg }
422fc0bc19fSjoerg for (i = 149; i <= 165; i += 4) {
423fc0bc19fSjoerg ic->ic_channels[i].ic_freq =
424fc0bc19fSjoerg ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
425fc0bc19fSjoerg ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
426fc0bc19fSjoerg }
427fc0bc19fSjoerg }
428fc0bc19fSjoerg
429fc0bc19fSjoerg /* set supported .11b and .11g rates */
430eddea7afSmaya ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
431eddea7afSmaya ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
432fc0bc19fSjoerg
433fc0bc19fSjoerg /* set supported .11b and .11g channels (1 through 14) */
434fc0bc19fSjoerg for (i = 1; i <= 14; i++) {
435fc0bc19fSjoerg ic->ic_channels[i].ic_freq =
436fc0bc19fSjoerg ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
437fc0bc19fSjoerg ic->ic_channels[i].ic_flags =
438fc0bc19fSjoerg IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
439fc0bc19fSjoerg IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
440fc0bc19fSjoerg }
441fc0bc19fSjoerg
442fc0bc19fSjoerg ifp->if_softc = sc;
443fc0bc19fSjoerg ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
444fc0bc19fSjoerg ifp->if_init = rum_init;
445fc0bc19fSjoerg ifp->if_ioctl = rum_ioctl;
446fc0bc19fSjoerg ifp->if_start = rum_start;
447fc0bc19fSjoerg ifp->if_watchdog = rum_watchdog;
448fc0bc19fSjoerg IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
449fc0bc19fSjoerg IFQ_SET_READY(&ifp->if_snd);
45068c8418cSdyoung memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
451fc0bc19fSjoerg
452fc0bc19fSjoerg if_attach(ifp);
453fc0bc19fSjoerg ieee80211_ifattach(ic);
4543bf7c476Skiyohara ic->ic_newassoc = rum_newassoc;
455fc0bc19fSjoerg
456fc0bc19fSjoerg /* override state transition machine */
457fc0bc19fSjoerg sc->sc_newstate = ic->ic_newstate;
458fc0bc19fSjoerg ic->ic_newstate = rum_newstate;
4597a9a30c5Sthorpej
4607a9a30c5Sthorpej /* XXX media locking needs revisiting */
4617a9a30c5Sthorpej mutex_init(&sc->sc_media_mtx, MUTEX_DEFAULT, IPL_SOFTUSB);
4627a9a30c5Sthorpej ieee80211_media_init_with_lock(ic,
4637a9a30c5Sthorpej rum_media_change, ieee80211_media_status, &sc->sc_media_mtx);
464fc0bc19fSjoerg
46558e86755Sjoerg bpf_attach2(ifp, DLT_IEEE802_11_RADIO,
46610fe49d7Spooka sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN,
46710fe49d7Spooka &sc->sc_drvbpf);
468fc0bc19fSjoerg
4694e8e6643Sskrll sc->sc_rxtap_len = sizeof(sc->sc_rxtapu);
470fc0bc19fSjoerg sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
471fc0bc19fSjoerg sc->sc_rxtap.wr_ihdr.it_present = htole32(RT2573_RX_RADIOTAP_PRESENT);
472fc0bc19fSjoerg
4734e8e6643Sskrll sc->sc_txtap_len = sizeof(sc->sc_txtapu);
474fc0bc19fSjoerg sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
475fc0bc19fSjoerg sc->sc_txtap.wt_ihdr.it_present = htole32(RT2573_TX_RADIOTAP_PRESENT);
476fc0bc19fSjoerg
477fc0bc19fSjoerg ieee80211_announce(ic);
478fc0bc19fSjoerg
4798bc54e5bSmsaitoh usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev);
480fc0bc19fSjoerg
481959874c5Snonaka if (!pmf_device_register(self, NULL, NULL))
482959874c5Snonaka aprint_error_dev(self, "couldn't establish power handler\n");
483959874c5Snonaka
48468c8418cSdyoung return;
485fc0bc19fSjoerg }
486fc0bc19fSjoerg
48787931599Sjmcneill static int
rum_detach(device_t self,int flags)48868c8418cSdyoung rum_detach(device_t self, int flags)
489fc0bc19fSjoerg {
49068c8418cSdyoung struct rum_softc *sc = device_private(self);
491fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
492fc0bc19fSjoerg struct ifnet *ifp = &sc->sc_if;
493fc0bc19fSjoerg int s;
494fc0bc19fSjoerg
495e2da0057Sdrochner if (!ifp->if_softc)
496e2da0057Sdrochner return 0;
497e2da0057Sdrochner
498959874c5Snonaka pmf_device_deregister(self);
499959874c5Snonaka
500fc0bc19fSjoerg s = splusb();
501fc0bc19fSjoerg
502fc0bc19fSjoerg rum_stop(ifp, 1);
5030449a44dSriastradh callout_halt(&sc->sc_scan_ch, NULL);
5040449a44dSriastradh callout_halt(&sc->sc_amrr_ch, NULL);
505a1de0147Sriastradh usb_rem_task_wait(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER, NULL);
506fc0bc19fSjoerg
50758e86755Sjoerg bpf_detach(ifp);
508fc0bc19fSjoerg ieee80211_ifdetach(ic); /* free all nodes */
509fc0bc19fSjoerg if_detach(ifp);
510fc0bc19fSjoerg
511fc0bc19fSjoerg splx(s);
512fc0bc19fSjoerg
51368c8418cSdyoung usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev);
514fc0bc19fSjoerg
515fc0bc19fSjoerg return 0;
516fc0bc19fSjoerg }
517fc0bc19fSjoerg
51887931599Sjmcneill static int
rum_alloc_tx_list(struct rum_softc * sc)519fc0bc19fSjoerg rum_alloc_tx_list(struct rum_softc *sc)
520fc0bc19fSjoerg {
521fc0bc19fSjoerg struct rum_tx_data *data;
522fc0bc19fSjoerg int i, error;
523fc0bc19fSjoerg
52487931599Sjmcneill sc->tx_cur = sc->tx_queued = 0;
525fc0bc19fSjoerg
5263bf7c476Skiyohara for (i = 0; i < RUM_TX_LIST_COUNT; i++) {
527fc0bc19fSjoerg data = &sc->tx_data[i];
528fc0bc19fSjoerg
529fc0bc19fSjoerg data->sc = sc;
530fc0bc19fSjoerg
5314e8e6643Sskrll error = usbd_create_xfer(sc->sc_tx_pipeh,
5324e8e6643Sskrll RT2573_TX_DESC_SIZE + IEEE80211_MAX_LEN,
5334e8e6643Sskrll USBD_FORCE_SHORT_XFER, 0, &data->xfer);
5344e8e6643Sskrll if (error) {
535fc0bc19fSjoerg printf("%s: could not allocate tx xfer\n",
53668c8418cSdyoung device_xname(sc->sc_dev));
537fc0bc19fSjoerg goto fail;
538fc0bc19fSjoerg }
5394e8e6643Sskrll data->buf = usbd_get_buffer(data->xfer);
540fc0bc19fSjoerg
541fc0bc19fSjoerg /* clean Tx descriptor */
542c363a9cbScegger memset(data->buf, 0, RT2573_TX_DESC_SIZE);
543fc0bc19fSjoerg }
544fc0bc19fSjoerg
545fc0bc19fSjoerg return 0;
546fc0bc19fSjoerg
547fc0bc19fSjoerg fail: rum_free_tx_list(sc);
548fc0bc19fSjoerg return error;
549fc0bc19fSjoerg }
550fc0bc19fSjoerg
55187931599Sjmcneill static void
rum_free_tx_list(struct rum_softc * sc)552fc0bc19fSjoerg rum_free_tx_list(struct rum_softc *sc)
553fc0bc19fSjoerg {
554fc0bc19fSjoerg struct rum_tx_data *data;
555fc0bc19fSjoerg int i;
556fc0bc19fSjoerg
5573bf7c476Skiyohara for (i = 0; i < RUM_TX_LIST_COUNT; i++) {
558fc0bc19fSjoerg data = &sc->tx_data[i];
559fc0bc19fSjoerg
560fc0bc19fSjoerg if (data->xfer != NULL) {
5614e8e6643Sskrll usbd_destroy_xfer(data->xfer);
562fc0bc19fSjoerg data->xfer = NULL;
563fc0bc19fSjoerg }
564fc0bc19fSjoerg
565fc0bc19fSjoerg if (data->ni != NULL) {
566fc0bc19fSjoerg ieee80211_free_node(data->ni);
567fc0bc19fSjoerg data->ni = NULL;
568fc0bc19fSjoerg }
569fc0bc19fSjoerg }
570fc0bc19fSjoerg }
571fc0bc19fSjoerg
57287931599Sjmcneill static int
rum_alloc_rx_list(struct rum_softc * sc)573fc0bc19fSjoerg rum_alloc_rx_list(struct rum_softc *sc)
574fc0bc19fSjoerg {
575fc0bc19fSjoerg struct rum_rx_data *data;
576fc0bc19fSjoerg int i, error;
577fc0bc19fSjoerg
5783bf7c476Skiyohara for (i = 0; i < RUM_RX_LIST_COUNT; i++) {
579fc0bc19fSjoerg data = &sc->rx_data[i];
580fc0bc19fSjoerg
581fc0bc19fSjoerg data->sc = sc;
582fc0bc19fSjoerg
5834e8e6643Sskrll error = usbd_create_xfer(sc->sc_rx_pipeh, MCLBYTES,
584b8421611Sskrll 0, 0, &data->xfer);
5854e8e6643Sskrll if (error) {
586fc0bc19fSjoerg printf("%s: could not allocate rx xfer\n",
58768c8418cSdyoung device_xname(sc->sc_dev));
588fc0bc19fSjoerg goto fail;
589fc0bc19fSjoerg }
590fc0bc19fSjoerg
591fc0bc19fSjoerg MGETHDR(data->m, M_DONTWAIT, MT_DATA);
592fc0bc19fSjoerg if (data->m == NULL) {
593fc0bc19fSjoerg printf("%s: could not allocate rx mbuf\n",
59468c8418cSdyoung device_xname(sc->sc_dev));
595fc0bc19fSjoerg error = ENOMEM;
596fc0bc19fSjoerg goto fail;
597fc0bc19fSjoerg }
598fc0bc19fSjoerg
599fc0bc19fSjoerg MCLGET(data->m, M_DONTWAIT);
600fc0bc19fSjoerg if (!(data->m->m_flags & M_EXT)) {
601fc0bc19fSjoerg printf("%s: could not allocate rx mbuf cluster\n",
60268c8418cSdyoung device_xname(sc->sc_dev));
603fc0bc19fSjoerg error = ENOMEM;
604fc0bc19fSjoerg goto fail;
605fc0bc19fSjoerg }
606fc0bc19fSjoerg
607fc0bc19fSjoerg data->buf = mtod(data->m, uint8_t *);
608fc0bc19fSjoerg }
609fc0bc19fSjoerg
610fc0bc19fSjoerg return 0;
611fc0bc19fSjoerg
61274af1ccaSdholland fail: rum_free_rx_list(sc);
613fc0bc19fSjoerg return error;
614fc0bc19fSjoerg }
615fc0bc19fSjoerg
61687931599Sjmcneill static void
rum_free_rx_list(struct rum_softc * sc)617fc0bc19fSjoerg rum_free_rx_list(struct rum_softc *sc)
618fc0bc19fSjoerg {
619fc0bc19fSjoerg struct rum_rx_data *data;
620fc0bc19fSjoerg int i;
621fc0bc19fSjoerg
6223bf7c476Skiyohara for (i = 0; i < RUM_RX_LIST_COUNT; i++) {
623fc0bc19fSjoerg data = &sc->rx_data[i];
624fc0bc19fSjoerg
625fc0bc19fSjoerg if (data->xfer != NULL) {
6264e8e6643Sskrll usbd_destroy_xfer(data->xfer);
627fc0bc19fSjoerg data->xfer = NULL;
628fc0bc19fSjoerg }
629fc0bc19fSjoerg
630fc0bc19fSjoerg m_freem(data->m);
631fc0bc19fSjoerg data->m = NULL;
632fc0bc19fSjoerg }
633fc0bc19fSjoerg }
634fc0bc19fSjoerg
63587931599Sjmcneill static int
rum_media_change(struct ifnet * ifp)636fc0bc19fSjoerg rum_media_change(struct ifnet *ifp)
637fc0bc19fSjoerg {
638fc0bc19fSjoerg int error;
639fc0bc19fSjoerg
640fc0bc19fSjoerg error = ieee80211_media_change(ifp);
641fc0bc19fSjoerg if (error != ENETRESET)
642fc0bc19fSjoerg return error;
643fc0bc19fSjoerg
644fc0bc19fSjoerg if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
645fc0bc19fSjoerg rum_init(ifp);
646fc0bc19fSjoerg
647fc0bc19fSjoerg return 0;
648fc0bc19fSjoerg }
649fc0bc19fSjoerg
650fc0bc19fSjoerg /*
651fc0bc19fSjoerg * This function is called periodically (every 200ms) during scanning to
652fc0bc19fSjoerg * switch from one channel to another.
653fc0bc19fSjoerg */
65487931599Sjmcneill static void
rum_next_scan(void * arg)655fc0bc19fSjoerg rum_next_scan(void *arg)
656fc0bc19fSjoerg {
657fc0bc19fSjoerg struct rum_softc *sc = arg;
658fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
65987931599Sjmcneill int s;
660fc0bc19fSjoerg
66187931599Sjmcneill s = splnet();
662fc0bc19fSjoerg if (ic->ic_state == IEEE80211_S_SCAN)
663fc0bc19fSjoerg ieee80211_next_scan(ic);
66487931599Sjmcneill splx(s);
665fc0bc19fSjoerg }
666fc0bc19fSjoerg
66787931599Sjmcneill static void
rum_task(void * arg)668fc0bc19fSjoerg rum_task(void *arg)
669fc0bc19fSjoerg {
670fc0bc19fSjoerg struct rum_softc *sc = arg;
671fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
672fc0bc19fSjoerg enum ieee80211_state ostate;
673fc0bc19fSjoerg struct ieee80211_node *ni;
674fc0bc19fSjoerg uint32_t tmp;
675fc0bc19fSjoerg
676fc0bc19fSjoerg ostate = ic->ic_state;
677fc0bc19fSjoerg
678fc0bc19fSjoerg switch (sc->sc_state) {
679fc0bc19fSjoerg case IEEE80211_S_INIT:
680fc0bc19fSjoerg if (ostate == IEEE80211_S_RUN) {
681fc0bc19fSjoerg /* abort TSF synchronization */
682fc0bc19fSjoerg tmp = rum_read(sc, RT2573_TXRX_CSR9);
683fc0bc19fSjoerg rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff);
684fc0bc19fSjoerg }
685fc0bc19fSjoerg break;
686fc0bc19fSjoerg
687fc0bc19fSjoerg case IEEE80211_S_SCAN:
688fc0bc19fSjoerg rum_set_chan(sc, ic->ic_curchan);
68968c8418cSdyoung callout_reset(&sc->sc_scan_ch, hz / 5, rum_next_scan, sc);
690fc0bc19fSjoerg break;
691fc0bc19fSjoerg
692fc0bc19fSjoerg case IEEE80211_S_AUTH:
693fc0bc19fSjoerg rum_set_chan(sc, ic->ic_curchan);
694fc0bc19fSjoerg break;
695fc0bc19fSjoerg
696fc0bc19fSjoerg case IEEE80211_S_ASSOC:
697fc0bc19fSjoerg rum_set_chan(sc, ic->ic_curchan);
698fc0bc19fSjoerg break;
699fc0bc19fSjoerg
700fc0bc19fSjoerg case IEEE80211_S_RUN:
701fc0bc19fSjoerg rum_set_chan(sc, ic->ic_curchan);
702fc0bc19fSjoerg
703fc0bc19fSjoerg ni = ic->ic_bss;
704fc0bc19fSjoerg
705fc0bc19fSjoerg if (ic->ic_opmode != IEEE80211_M_MONITOR) {
706fc0bc19fSjoerg rum_update_slot(sc);
707fc0bc19fSjoerg rum_enable_mrr(sc);
708fc0bc19fSjoerg rum_set_txpreamble(sc);
709fc0bc19fSjoerg rum_set_basicrates(sc);
710fc0bc19fSjoerg rum_set_bssid(sc, ni->ni_bssid);
711fc0bc19fSjoerg }
712fc0bc19fSjoerg
713fc0bc19fSjoerg if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
714fc0bc19fSjoerg ic->ic_opmode == IEEE80211_M_IBSS)
715fc0bc19fSjoerg rum_prepare_beacon(sc);
716fc0bc19fSjoerg
717fc0bc19fSjoerg if (ic->ic_opmode != IEEE80211_M_MONITOR)
718fc0bc19fSjoerg rum_enable_tsf_sync(sc);
719fc0bc19fSjoerg
7203bf7c476Skiyohara if (ic->ic_opmode == IEEE80211_M_STA) {
7213bf7c476Skiyohara /* fake a join to init the tx rate */
7223bf7c476Skiyohara rum_newassoc(ic->ic_bss, 1);
7233bf7c476Skiyohara
724fc0bc19fSjoerg /* enable automatic rate adaptation in STA mode */
7253bf7c476Skiyohara if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
726fc0bc19fSjoerg rum_amrr_start(sc, ni);
7273bf7c476Skiyohara }
728fc0bc19fSjoerg
729fc0bc19fSjoerg break;
730fc0bc19fSjoerg }
731fc0bc19fSjoerg
73287931599Sjmcneill sc->sc_newstate(ic, sc->sc_state, sc->sc_arg);
733fc0bc19fSjoerg }
734fc0bc19fSjoerg
73587931599Sjmcneill static int
rum_newstate(struct ieee80211com * ic,enum ieee80211_state nstate,int arg)736fc0bc19fSjoerg rum_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
737fc0bc19fSjoerg {
738fc0bc19fSjoerg struct rum_softc *sc = ic->ic_ifp->if_softc;
739fc0bc19fSjoerg
7400449a44dSriastradh /*
7410449a44dSriastradh * XXXSMP: This does not wait for the task, if it is in flight,
7420449a44dSriastradh * to complete. If this code works at all, it must rely on the
7430449a44dSriastradh * kernel lock to serialize with the USB task thread.
7440449a44dSriastradh */
745fc0bc19fSjoerg usb_rem_task(sc->sc_udev, &sc->sc_task);
74668c8418cSdyoung callout_stop(&sc->sc_scan_ch);
74768c8418cSdyoung callout_stop(&sc->sc_amrr_ch);
748fc0bc19fSjoerg
749fc0bc19fSjoerg /* do it in a process context */
750fc0bc19fSjoerg sc->sc_state = nstate;
75187931599Sjmcneill sc->sc_arg = arg;
752fc0bc19fSjoerg usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER);
753fc0bc19fSjoerg
754fc0bc19fSjoerg return 0;
755fc0bc19fSjoerg }
756fc0bc19fSjoerg
757fc0bc19fSjoerg /* quickly determine if a given rate is CCK or OFDM */
758fc0bc19fSjoerg #define RUM_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22)
759fc0bc19fSjoerg
760fc0bc19fSjoerg #define RUM_ACK_SIZE 14 /* 10 + 4(FCS) */
761fc0bc19fSjoerg #define RUM_CTS_SIZE 14 /* 10 + 4(FCS) */
762fc0bc19fSjoerg
76387931599Sjmcneill static void
rum_txeof(struct usbd_xfer * xfer,void * priv,usbd_status status)7644e8e6643Sskrll rum_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
765fc0bc19fSjoerg {
766fc0bc19fSjoerg struct rum_tx_data *data = priv;
767fc0bc19fSjoerg struct rum_softc *sc = data->sc;
768fc0bc19fSjoerg struct ifnet *ifp = &sc->sc_if;
769fc0bc19fSjoerg int s;
770fc0bc19fSjoerg
771fc0bc19fSjoerg if (status != USBD_NORMAL_COMPLETION) {
772fc0bc19fSjoerg if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
773fc0bc19fSjoerg return;
774fc0bc19fSjoerg
775fc0bc19fSjoerg printf("%s: could not transmit buffer: %s\n",
77668c8418cSdyoung device_xname(sc->sc_dev), usbd_errstr(status));
777fc0bc19fSjoerg
778fc0bc19fSjoerg if (status == USBD_STALLED)
779fc0bc19fSjoerg usbd_clear_endpoint_stall_async(sc->sc_tx_pipeh);
780fc0bc19fSjoerg
781cdaa0e91Sthorpej if_statinc(ifp, if_oerrors);
782fc0bc19fSjoerg return;
783fc0bc19fSjoerg }
784fc0bc19fSjoerg
785fc0bc19fSjoerg s = splnet();
786fc0bc19fSjoerg
787fc0bc19fSjoerg ieee80211_free_node(data->ni);
788fc0bc19fSjoerg data->ni = NULL;
789fc0bc19fSjoerg
790fc0bc19fSjoerg sc->tx_queued--;
791cdaa0e91Sthorpej if_statinc(ifp, if_opackets);
792fc0bc19fSjoerg
793fc0bc19fSjoerg DPRINTFN(10, ("tx done\n"));
794fc0bc19fSjoerg
795fc0bc19fSjoerg sc->sc_tx_timer = 0;
796fc0bc19fSjoerg ifp->if_flags &= ~IFF_OACTIVE;
797fc0bc19fSjoerg rum_start(ifp);
798fc0bc19fSjoerg
799fc0bc19fSjoerg splx(s);
800fc0bc19fSjoerg }
801fc0bc19fSjoerg
80287931599Sjmcneill static void
rum_rxeof(struct usbd_xfer * xfer,void * priv,usbd_status status)8034e8e6643Sskrll rum_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
804fc0bc19fSjoerg {
805fc0bc19fSjoerg struct rum_rx_data *data = priv;
806fc0bc19fSjoerg struct rum_softc *sc = data->sc;
807fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
808fc0bc19fSjoerg struct ifnet *ifp = &sc->sc_if;
809fc0bc19fSjoerg struct rum_rx_desc *desc;
810fc0bc19fSjoerg struct ieee80211_frame *wh;
811fc0bc19fSjoerg struct ieee80211_node *ni;
812fc0bc19fSjoerg struct mbuf *mnew, *m;
813fc0bc19fSjoerg int s, len;
814fc0bc19fSjoerg
815fc0bc19fSjoerg if (status != USBD_NORMAL_COMPLETION) {
816fc0bc19fSjoerg if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
817fc0bc19fSjoerg return;
818fc0bc19fSjoerg
819fc0bc19fSjoerg if (status == USBD_STALLED)
820fc0bc19fSjoerg usbd_clear_endpoint_stall_async(sc->sc_rx_pipeh);
821fc0bc19fSjoerg goto skip;
822fc0bc19fSjoerg }
823fc0bc19fSjoerg
824fc0bc19fSjoerg usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
825fc0bc19fSjoerg
8263016e043Spgoyette if (len < (int)(RT2573_RX_DESC_SIZE +
8273016e043Spgoyette sizeof(struct ieee80211_frame_min))) {
82868c8418cSdyoung DPRINTF(("%s: xfer too short %d\n", device_xname(sc->sc_dev),
829fc0bc19fSjoerg len));
830cdaa0e91Sthorpej if_statinc(ifp, if_ierrors);
831fc0bc19fSjoerg goto skip;
832fc0bc19fSjoerg }
833fc0bc19fSjoerg
834fc0bc19fSjoerg desc = (struct rum_rx_desc *)data->buf;
835fc0bc19fSjoerg
836fc0bc19fSjoerg if (le32toh(desc->flags) & RT2573_RX_CRC_ERROR) {
837fc0bc19fSjoerg /*
838fc0bc19fSjoerg * This should not happen since we did not request to receive
839fc0bc19fSjoerg * those frames when we filled RT2573_TXRX_CSR0.
840fc0bc19fSjoerg */
841fc0bc19fSjoerg DPRINTFN(5, ("CRC error\n"));
842cdaa0e91Sthorpej if_statinc(ifp, if_ierrors);
843fc0bc19fSjoerg goto skip;
844fc0bc19fSjoerg }
845fc0bc19fSjoerg
846fc0bc19fSjoerg MGETHDR(mnew, M_DONTWAIT, MT_DATA);
847fc0bc19fSjoerg if (mnew == NULL) {
848fc0bc19fSjoerg printf("%s: could not allocate rx mbuf\n",
84968c8418cSdyoung device_xname(sc->sc_dev));
850cdaa0e91Sthorpej if_statinc(ifp, if_ierrors);
851fc0bc19fSjoerg goto skip;
852fc0bc19fSjoerg }
853fc0bc19fSjoerg
854fc0bc19fSjoerg MCLGET(mnew, M_DONTWAIT);
855fc0bc19fSjoerg if (!(mnew->m_flags & M_EXT)) {
856fc0bc19fSjoerg printf("%s: could not allocate rx mbuf cluster\n",
85768c8418cSdyoung device_xname(sc->sc_dev));
858fc0bc19fSjoerg m_freem(mnew);
859cdaa0e91Sthorpej if_statinc(ifp, if_ierrors);
860fc0bc19fSjoerg goto skip;
861fc0bc19fSjoerg }
862fc0bc19fSjoerg
863fc0bc19fSjoerg m = data->m;
864fc0bc19fSjoerg data->m = mnew;
865fc0bc19fSjoerg data->buf = mtod(data->m, uint8_t *);
866fc0bc19fSjoerg
867fc0bc19fSjoerg /* finalize mbuf */
868d938d837Sozaki-r m_set_rcvif(m, ifp);
86953524e44Schristos m->m_data = (void *)(desc + 1);
870fc0bc19fSjoerg m->m_pkthdr.len = m->m_len = (le32toh(desc->flags) >> 16) & 0xfff;
871fc0bc19fSjoerg
872fc0bc19fSjoerg s = splnet();
873fc0bc19fSjoerg
874fc0bc19fSjoerg if (sc->sc_drvbpf != NULL) {
875fc0bc19fSjoerg struct rum_rx_radiotap_header *tap = &sc->sc_rxtap;
876fc0bc19fSjoerg
877fc0bc19fSjoerg tap->wr_flags = IEEE80211_RADIOTAP_F_FCS;
878fc0bc19fSjoerg tap->wr_rate = rum_rxrate(desc);
879fc0bc19fSjoerg tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
880fc0bc19fSjoerg tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
881fc0bc19fSjoerg tap->wr_antenna = sc->rx_ant;
882fc0bc19fSjoerg tap->wr_antsignal = desc->rssi;
883fc0bc19fSjoerg
8843cd62456Smsaitoh bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m, BPF_D_IN);
885fc0bc19fSjoerg }
886fc0bc19fSjoerg
887fc0bc19fSjoerg wh = mtod(m, struct ieee80211_frame *);
888fc0bc19fSjoerg ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
889fc0bc19fSjoerg
890fc0bc19fSjoerg /* send the frame to the 802.11 layer */
891fc0bc19fSjoerg ieee80211_input(ic, m, ni, desc->rssi, 0);
892fc0bc19fSjoerg
893fc0bc19fSjoerg /* node is no longer needed */
894fc0bc19fSjoerg ieee80211_free_node(ni);
895fc0bc19fSjoerg
896fc0bc19fSjoerg splx(s);
897fc0bc19fSjoerg
898fc0bc19fSjoerg DPRINTFN(15, ("rx done\n"));
899fc0bc19fSjoerg
900fc0bc19fSjoerg skip: /* setup a new transfer */
9014e8e6643Sskrll usbd_setup_xfer(xfer, data, data->buf, MCLBYTES, USBD_SHORT_XFER_OK,
9024e8e6643Sskrll USBD_NO_TIMEOUT, rum_rxeof);
903fc0bc19fSjoerg usbd_transfer(xfer);
904fc0bc19fSjoerg }
905fc0bc19fSjoerg
906fc0bc19fSjoerg /*
907fc0bc19fSjoerg * This function is only used by the Rx radiotap code. It returns the rate at
908fc0bc19fSjoerg * which a given frame was received.
909fc0bc19fSjoerg */
91087931599Sjmcneill static uint8_t
rum_rxrate(const struct rum_rx_desc * desc)9113bf7c476Skiyohara rum_rxrate(const struct rum_rx_desc *desc)
912fc0bc19fSjoerg {
913fc0bc19fSjoerg if (le32toh(desc->flags) & RT2573_RX_OFDM) {
914fc0bc19fSjoerg /* reverse function of rum_plcp_signal */
915fc0bc19fSjoerg switch (desc->rate) {
916fc0bc19fSjoerg case 0xb: return 12;
917fc0bc19fSjoerg case 0xf: return 18;
918fc0bc19fSjoerg case 0xa: return 24;
919fc0bc19fSjoerg case 0xe: return 36;
920fc0bc19fSjoerg case 0x9: return 48;
921fc0bc19fSjoerg case 0xd: return 72;
922fc0bc19fSjoerg case 0x8: return 96;
923fc0bc19fSjoerg case 0xc: return 108;
924fc0bc19fSjoerg }
925fc0bc19fSjoerg } else {
926fc0bc19fSjoerg if (desc->rate == 10)
927fc0bc19fSjoerg return 2;
928fc0bc19fSjoerg if (desc->rate == 20)
929fc0bc19fSjoerg return 4;
930fc0bc19fSjoerg if (desc->rate == 55)
931fc0bc19fSjoerg return 11;
932fc0bc19fSjoerg if (desc->rate == 110)
933fc0bc19fSjoerg return 22;
934fc0bc19fSjoerg }
935fc0bc19fSjoerg return 2; /* should not get there */
936fc0bc19fSjoerg }
937fc0bc19fSjoerg
938fc0bc19fSjoerg /*
939fc0bc19fSjoerg * Return the expected ack rate for a frame transmitted at rate `rate'.
940fc0bc19fSjoerg * XXX: this should depend on the destination node basic rate set.
941fc0bc19fSjoerg */
94287931599Sjmcneill static int
rum_ack_rate(struct ieee80211com * ic,int rate)943fc0bc19fSjoerg rum_ack_rate(struct ieee80211com *ic, int rate)
944fc0bc19fSjoerg {
945fc0bc19fSjoerg switch (rate) {
946fc0bc19fSjoerg /* CCK rates */
947fc0bc19fSjoerg case 2:
948fc0bc19fSjoerg return 2;
949fc0bc19fSjoerg case 4:
950fc0bc19fSjoerg case 11:
951fc0bc19fSjoerg case 22:
952fc0bc19fSjoerg return (ic->ic_curmode == IEEE80211_MODE_11B) ? 4 : rate;
953fc0bc19fSjoerg
954fc0bc19fSjoerg /* OFDM rates */
955fc0bc19fSjoerg case 12:
956fc0bc19fSjoerg case 18:
957fc0bc19fSjoerg return 12;
958fc0bc19fSjoerg case 24:
959fc0bc19fSjoerg case 36:
960fc0bc19fSjoerg return 24;
961fc0bc19fSjoerg case 48:
962fc0bc19fSjoerg case 72:
963fc0bc19fSjoerg case 96:
964fc0bc19fSjoerg case 108:
965fc0bc19fSjoerg return 48;
966fc0bc19fSjoerg }
967fc0bc19fSjoerg
968fc0bc19fSjoerg /* default to 1Mbps */
969fc0bc19fSjoerg return 2;
970fc0bc19fSjoerg }
971fc0bc19fSjoerg
972fc0bc19fSjoerg /*
973fc0bc19fSjoerg * Compute the duration (in us) needed to transmit `len' bytes at rate `rate'.
974fc0bc19fSjoerg * The function automatically determines the operating mode depending on the
975fc0bc19fSjoerg * given rate. `flags' indicates whether short preamble is in use or not.
976fc0bc19fSjoerg */
97787931599Sjmcneill static uint16_t
rum_txtime(int len,int rate,uint32_t flags)978fc0bc19fSjoerg rum_txtime(int len, int rate, uint32_t flags)
979fc0bc19fSjoerg {
980fc0bc19fSjoerg uint16_t txtime;
981fc0bc19fSjoerg
982fc0bc19fSjoerg if (RUM_RATE_IS_OFDM(rate)) {
983fc0bc19fSjoerg /* IEEE Std 802.11a-1999, pp. 37 */
984fc0bc19fSjoerg txtime = (8 + 4 * len + 3 + rate - 1) / rate;
985fc0bc19fSjoerg txtime = 16 + 4 + 4 * txtime + 6;
986fc0bc19fSjoerg } else {
987fc0bc19fSjoerg /* IEEE Std 802.11b-1999, pp. 28 */
988fc0bc19fSjoerg txtime = (16 * len + rate - 1) / rate;
989fc0bc19fSjoerg if (rate != 2 && (flags & IEEE80211_F_SHPREAMBLE))
990fc0bc19fSjoerg txtime += 72 + 24;
991fc0bc19fSjoerg else
992fc0bc19fSjoerg txtime += 144 + 48;
993fc0bc19fSjoerg }
994fc0bc19fSjoerg return txtime;
995fc0bc19fSjoerg }
996fc0bc19fSjoerg
99787931599Sjmcneill static uint8_t
rum_plcp_signal(int rate)998fc0bc19fSjoerg rum_plcp_signal(int rate)
999fc0bc19fSjoerg {
1000fc0bc19fSjoerg switch (rate) {
1001fc0bc19fSjoerg /* CCK rates (returned values are device-dependent) */
1002fc0bc19fSjoerg case 2: return 0x0;
1003fc0bc19fSjoerg case 4: return 0x1;
1004fc0bc19fSjoerg case 11: return 0x2;
1005fc0bc19fSjoerg case 22: return 0x3;
1006fc0bc19fSjoerg
1007fc0bc19fSjoerg /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
1008fc0bc19fSjoerg case 12: return 0xb;
1009fc0bc19fSjoerg case 18: return 0xf;
1010fc0bc19fSjoerg case 24: return 0xa;
1011fc0bc19fSjoerg case 36: return 0xe;
1012fc0bc19fSjoerg case 48: return 0x9;
1013fc0bc19fSjoerg case 72: return 0xd;
1014fc0bc19fSjoerg case 96: return 0x8;
1015fc0bc19fSjoerg case 108: return 0xc;
1016fc0bc19fSjoerg
1017fc0bc19fSjoerg /* unsupported rates (should not get there) */
1018fc0bc19fSjoerg default: return 0xff;
1019fc0bc19fSjoerg }
1020fc0bc19fSjoerg }
1021fc0bc19fSjoerg
102287931599Sjmcneill static void
rum_setup_tx_desc(struct rum_softc * sc,struct rum_tx_desc * desc,uint32_t flags,uint16_t xflags,int len,int rate)1023fc0bc19fSjoerg rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc,
1024fc0bc19fSjoerg uint32_t flags, uint16_t xflags, int len, int rate)
1025fc0bc19fSjoerg {
1026fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
1027fc0bc19fSjoerg uint16_t plcp_length;
1028fc0bc19fSjoerg int remainder;
1029fc0bc19fSjoerg
1030fc0bc19fSjoerg desc->flags = htole32(flags);
1031fc0bc19fSjoerg desc->flags |= htole32(RT2573_TX_VALID);
1032fc0bc19fSjoerg desc->flags |= htole32(len << 16);
1033fc0bc19fSjoerg
1034fc0bc19fSjoerg desc->xflags = htole16(xflags);
1035fc0bc19fSjoerg
1036fc0bc19fSjoerg desc->wme = htole16(
1037fc0bc19fSjoerg RT2573_QID(0) |
1038fc0bc19fSjoerg RT2573_AIFSN(2) |
1039fc0bc19fSjoerg RT2573_LOGCWMIN(4) |
1040fc0bc19fSjoerg RT2573_LOGCWMAX(10));
1041fc0bc19fSjoerg
1042fc0bc19fSjoerg /* setup PLCP fields */
1043fc0bc19fSjoerg desc->plcp_signal = rum_plcp_signal(rate);
1044fc0bc19fSjoerg desc->plcp_service = 4;
1045fc0bc19fSjoerg
1046fc0bc19fSjoerg len += IEEE80211_CRC_LEN;
1047fc0bc19fSjoerg if (RUM_RATE_IS_OFDM(rate)) {
1048fc0bc19fSjoerg desc->flags |= htole32(RT2573_TX_OFDM);
1049fc0bc19fSjoerg
1050fc0bc19fSjoerg plcp_length = len & 0xfff;
1051fc0bc19fSjoerg desc->plcp_length_hi = plcp_length >> 6;
1052fc0bc19fSjoerg desc->plcp_length_lo = plcp_length & 0x3f;
1053fc0bc19fSjoerg } else {
1054fc0bc19fSjoerg plcp_length = (16 * len + rate - 1) / rate;
1055fc0bc19fSjoerg if (rate == 22) {
1056fc0bc19fSjoerg remainder = (16 * len) % 22;
1057fc0bc19fSjoerg if (remainder != 0 && remainder < 7)
1058fc0bc19fSjoerg desc->plcp_service |= RT2573_PLCP_LENGEXT;
1059fc0bc19fSjoerg }
1060fc0bc19fSjoerg desc->plcp_length_hi = plcp_length >> 8;
1061fc0bc19fSjoerg desc->plcp_length_lo = plcp_length & 0xff;
1062fc0bc19fSjoerg
1063fc0bc19fSjoerg if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
1064fc0bc19fSjoerg desc->plcp_signal |= 0x08;
1065fc0bc19fSjoerg }
1066fc0bc19fSjoerg }
1067fc0bc19fSjoerg
1068fc0bc19fSjoerg #define RUM_TX_TIMEOUT 5000
1069fc0bc19fSjoerg
107087931599Sjmcneill static int
rum_tx_data(struct rum_softc * sc,struct mbuf * m0,struct ieee80211_node * ni)107187931599Sjmcneill rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
1072fc0bc19fSjoerg {
1073fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
1074fc0bc19fSjoerg struct rum_tx_desc *desc;
1075fc0bc19fSjoerg struct rum_tx_data *data;
1076fc0bc19fSjoerg struct ieee80211_frame *wh;
10770e9691e3Sdegroote struct ieee80211_key *k;
1078fc0bc19fSjoerg uint32_t flags = 0;
1079fc0bc19fSjoerg uint16_t dur;
1080fc0bc19fSjoerg usbd_status error;
108187931599Sjmcneill int rate, xferlen, pktlen, needrts = 0, needcts = 0;
1082fc0bc19fSjoerg
1083fc0bc19fSjoerg wh = mtod(m0, struct ieee80211_frame *);
1084fc0bc19fSjoerg
10850e9691e3Sdegroote if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
10860e9691e3Sdegroote k = ieee80211_crypto_encap(ic, ni, m0);
10870e9691e3Sdegroote if (k == NULL) {
10880e9691e3Sdegroote m_freem(m0);
10890e9691e3Sdegroote return ENOBUFS;
10900e9691e3Sdegroote }
109187931599Sjmcneill
109287931599Sjmcneill /* packet header may have moved, reset our local pointer */
109387931599Sjmcneill wh = mtod(m0, struct ieee80211_frame *);
10940e9691e3Sdegroote }
10950e9691e3Sdegroote
109687931599Sjmcneill /* compute actual packet length (including CRC and crypto overhead) */
109787931599Sjmcneill pktlen = m0->m_pkthdr.len + IEEE80211_CRC_LEN;
109887931599Sjmcneill
109987931599Sjmcneill /* pickup a rate */
110087931599Sjmcneill if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
110187931599Sjmcneill ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
110287931599Sjmcneill IEEE80211_FC0_TYPE_MGT)) {
110387931599Sjmcneill /* mgmt/multicast frames are sent at the lowest avail. rate */
110487931599Sjmcneill rate = ni->ni_rates.rs_rates[0];
110587931599Sjmcneill } else if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
110687931599Sjmcneill rate = ic->ic_bss->ni_rates.rs_rates[ic->ic_fixed_rate];
110787931599Sjmcneill } else
110887931599Sjmcneill rate = ni->ni_rates.rs_rates[ni->ni_txrate];
110987931599Sjmcneill if (rate == 0)
111087931599Sjmcneill rate = 2; /* XXX should not happen */
111187931599Sjmcneill rate &= IEEE80211_RATE_VAL;
111287931599Sjmcneill
111387931599Sjmcneill /* check if RTS/CTS or CTS-to-self protection must be used */
111487931599Sjmcneill if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
111587931599Sjmcneill /* multicast frames are not sent at OFDM rates in 802.11b/g */
111687931599Sjmcneill if (pktlen > ic->ic_rtsthreshold) {
111787931599Sjmcneill needrts = 1; /* RTS/CTS based on frame length */
111887931599Sjmcneill } else if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
111987931599Sjmcneill RUM_RATE_IS_OFDM(rate)) {
112087931599Sjmcneill if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
112187931599Sjmcneill needcts = 1; /* CTS-to-self */
112287931599Sjmcneill else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
112387931599Sjmcneill needrts = 1; /* RTS/CTS */
112487931599Sjmcneill }
112587931599Sjmcneill }
112687931599Sjmcneill if (needrts || needcts) {
112787931599Sjmcneill struct mbuf *mprot;
112887931599Sjmcneill int protrate, ackrate;
112987931599Sjmcneill
113087931599Sjmcneill protrate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 2;
113187931599Sjmcneill ackrate = rum_ack_rate(ic, rate);
113287931599Sjmcneill
113387931599Sjmcneill dur = rum_txtime(pktlen, rate, ic->ic_flags) +
113487931599Sjmcneill rum_txtime(RUM_ACK_SIZE, ackrate, ic->ic_flags) +
113587931599Sjmcneill 2 * sc->sifs;
113687931599Sjmcneill if (needrts) {
113787931599Sjmcneill dur += rum_txtime(RUM_CTS_SIZE, rum_ack_rate(ic,
113887931599Sjmcneill protrate), ic->ic_flags) + sc->sifs;
113987931599Sjmcneill mprot = ieee80211_get_rts(ic, wh, dur);
114087931599Sjmcneill } else {
114187931599Sjmcneill mprot = ieee80211_get_cts_to_self(ic, dur);
114287931599Sjmcneill }
114387931599Sjmcneill if (mprot == NULL) {
114487931599Sjmcneill aprint_error_dev(sc->sc_dev,
114587931599Sjmcneill "couldn't allocate protection frame\n");
114687931599Sjmcneill m_freem(m0);
114787931599Sjmcneill return ENOBUFS;
114887931599Sjmcneill }
114987931599Sjmcneill
115087931599Sjmcneill data = &sc->tx_data[sc->tx_cur];
115187931599Sjmcneill desc = (struct rum_tx_desc *)data->buf;
115287931599Sjmcneill
115387931599Sjmcneill /* avoid multiple free() of the same node for each fragment */
115487931599Sjmcneill data->ni = ieee80211_ref_node(ni);
115587931599Sjmcneill
115687931599Sjmcneill m_copydata(mprot, 0, mprot->m_pkthdr.len,
115787931599Sjmcneill data->buf + RT2573_TX_DESC_SIZE);
115887931599Sjmcneill rum_setup_tx_desc(sc, desc,
115987931599Sjmcneill (needrts ? RT2573_TX_NEED_ACK : 0) | RT2573_TX_MORE_FRAG,
116087931599Sjmcneill 0, mprot->m_pkthdr.len, protrate);
116187931599Sjmcneill
116287931599Sjmcneill /* no roundup necessary here */
116387931599Sjmcneill xferlen = RT2573_TX_DESC_SIZE + mprot->m_pkthdr.len;
116487931599Sjmcneill
116587931599Sjmcneill /* XXX may want to pass the protection frame to BPF */
116687931599Sjmcneill
116787931599Sjmcneill /* mbuf is no longer needed */
116887931599Sjmcneill m_freem(mprot);
116987931599Sjmcneill
11704e8e6643Sskrll usbd_setup_xfer(data->xfer, data, data->buf,
11714e8e6643Sskrll xferlen, USBD_FORCE_SHORT_XFER,
117287931599Sjmcneill RUM_TX_TIMEOUT, rum_txeof);
117387931599Sjmcneill error = usbd_transfer(data->xfer);
117487931599Sjmcneill if (error != USBD_NORMAL_COMPLETION &&
117587931599Sjmcneill error != USBD_IN_PROGRESS) {
117687931599Sjmcneill m_freem(m0);
117787931599Sjmcneill return error;
117887931599Sjmcneill }
117987931599Sjmcneill
118087931599Sjmcneill sc->tx_queued++;
118187931599Sjmcneill sc->tx_cur = (sc->tx_cur + 1) % RUM_TX_LIST_COUNT;
118287931599Sjmcneill
118387931599Sjmcneill flags |= RT2573_TX_LONG_RETRY | RT2573_TX_IFS_SIFS;
118487931599Sjmcneill }
118587931599Sjmcneill
118687931599Sjmcneill data = &sc->tx_data[sc->tx_cur];
118787931599Sjmcneill desc = (struct rum_tx_desc *)data->buf;
118887931599Sjmcneill
118987931599Sjmcneill data->ni = ni;
11900e9691e3Sdegroote
1191fc0bc19fSjoerg if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
11923bf7c476Skiyohara flags |= RT2573_TX_NEED_ACK;
1193fc0bc19fSjoerg
1194fc0bc19fSjoerg dur = rum_txtime(RUM_ACK_SIZE, rum_ack_rate(ic, rate),
1195fc0bc19fSjoerg ic->ic_flags) + sc->sifs;
1196fc0bc19fSjoerg *(uint16_t *)wh->i_dur = htole16(dur);
1197fc0bc19fSjoerg
1198fc0bc19fSjoerg /* tell hardware to set timestamp in probe responses */
1199fc0bc19fSjoerg if ((wh->i_fc[0] &
1200fc0bc19fSjoerg (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
1201fc0bc19fSjoerg (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP))
1202fc0bc19fSjoerg flags |= RT2573_TX_TIMESTAMP;
1203fc0bc19fSjoerg }
1204fc0bc19fSjoerg
1205fc0bc19fSjoerg if (sc->sc_drvbpf != NULL) {
1206fc0bc19fSjoerg struct rum_tx_radiotap_header *tap = &sc->sc_txtap;
1207fc0bc19fSjoerg
1208fc0bc19fSjoerg tap->wt_flags = 0;
1209fc0bc19fSjoerg tap->wt_rate = rate;
1210fc0bc19fSjoerg tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq);
1211fc0bc19fSjoerg tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags);
1212fc0bc19fSjoerg tap->wt_antenna = sc->tx_ant;
1213fc0bc19fSjoerg
12143cd62456Smsaitoh bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0, BPF_D_OUT);
1215fc0bc19fSjoerg }
1216fc0bc19fSjoerg
1217fc0bc19fSjoerg m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RT2573_TX_DESC_SIZE);
1218fc0bc19fSjoerg rum_setup_tx_desc(sc, desc, flags, 0, m0->m_pkthdr.len, rate);
1219fc0bc19fSjoerg
1220fc0bc19fSjoerg /* align end on a 4-bytes boundary */
1221fc0bc19fSjoerg xferlen = (RT2573_TX_DESC_SIZE + m0->m_pkthdr.len + 3) & ~3;
1222fc0bc19fSjoerg
1223fc0bc19fSjoerg /*
1224fc0bc19fSjoerg * No space left in the last URB to store the extra 4 bytes, force
1225fc0bc19fSjoerg * sending of another URB.
1226fc0bc19fSjoerg */
1227fc0bc19fSjoerg if ((xferlen % 64) == 0)
1228fc0bc19fSjoerg xferlen += 4;
1229fc0bc19fSjoerg
123099fe08f4Smlelstv DPRINTFN(10, ("sending data frame len=%zu rate=%u xfer len=%u\n",
123199fe08f4Smlelstv (size_t)m0->m_pkthdr.len + RT2573_TX_DESC_SIZE,
12325c09ab21Swiz rate, xferlen));
1233fc0bc19fSjoerg
12343bf7c476Skiyohara /* mbuf is no longer needed */
12353bf7c476Skiyohara m_freem(m0);
12363bf7c476Skiyohara
12374e8e6643Sskrll usbd_setup_xfer(data->xfer, data, data->buf, xferlen,
12384e8e6643Sskrll USBD_FORCE_SHORT_XFER, RUM_TX_TIMEOUT, rum_txeof);
1239fc0bc19fSjoerg error = usbd_transfer(data->xfer);
12403bf7c476Skiyohara if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
1241fc0bc19fSjoerg return error;
1242fc0bc19fSjoerg
1243fc0bc19fSjoerg sc->tx_queued++;
124487931599Sjmcneill sc->tx_cur = (sc->tx_cur + 1) % RUM_TX_LIST_COUNT;
1245fc0bc19fSjoerg
1246fc0bc19fSjoerg return 0;
1247fc0bc19fSjoerg }
1248fc0bc19fSjoerg
124987931599Sjmcneill static void
rum_start(struct ifnet * ifp)1250fc0bc19fSjoerg rum_start(struct ifnet *ifp)
1251fc0bc19fSjoerg {
1252fc0bc19fSjoerg struct rum_softc *sc = ifp->if_softc;
1253fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
1254fc0bc19fSjoerg struct ether_header *eh;
1255fc0bc19fSjoerg struct ieee80211_node *ni;
1256fc0bc19fSjoerg struct mbuf *m0;
1257fc0bc19fSjoerg
125887931599Sjmcneill if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
125987931599Sjmcneill return;
126087931599Sjmcneill
1261fc0bc19fSjoerg for (;;) {
1262fc0bc19fSjoerg IF_POLL(&ic->ic_mgtq, m0);
1263fc0bc19fSjoerg if (m0 != NULL) {
126487931599Sjmcneill if (sc->tx_queued >= RUM_TX_LIST_COUNT - 1) {
1265fc0bc19fSjoerg ifp->if_flags |= IFF_OACTIVE;
1266fc0bc19fSjoerg break;
1267fc0bc19fSjoerg }
1268fc0bc19fSjoerg IF_DEQUEUE(&ic->ic_mgtq, m0);
1269fc0bc19fSjoerg
1270ea0349e7Sozaki-r ni = M_GETCTX(m0, struct ieee80211_node *);
12716bbd2477Sozaki-r M_CLEARCTX(m0);
12723cd62456Smsaitoh bpf_mtap3(ic->ic_rawbpf, m0, BPF_D_OUT);
127387931599Sjmcneill if (rum_tx_data(sc, m0, ni) != 0)
1274fc0bc19fSjoerg break;
1275fc0bc19fSjoerg
1276fc0bc19fSjoerg } else {
1277fc0bc19fSjoerg if (ic->ic_state != IEEE80211_S_RUN)
1278fc0bc19fSjoerg break;
1279fc0bc19fSjoerg IFQ_POLL(&ifp->if_snd, m0);
1280fc0bc19fSjoerg if (m0 == NULL)
1281fc0bc19fSjoerg break;
128287931599Sjmcneill if (sc->tx_queued >= RUM_TX_LIST_COUNT - 1) {
1283fc0bc19fSjoerg ifp->if_flags |= IFF_OACTIVE;
1284fc0bc19fSjoerg break;
1285fc0bc19fSjoerg }
1286fc0bc19fSjoerg IFQ_DEQUEUE(&ifp->if_snd, m0);
12873016e043Spgoyette if (m0->m_len < (int)sizeof(struct ether_header) &&
1288fc0bc19fSjoerg !(m0 = m_pullup(m0, sizeof(struct ether_header))))
1289fc0bc19fSjoerg continue;
1290fc0bc19fSjoerg
1291fc0bc19fSjoerg eh = mtod(m0, struct ether_header *);
1292fc0bc19fSjoerg ni = ieee80211_find_txnode(ic, eh->ether_dhost);
1293fc0bc19fSjoerg if (ni == NULL) {
1294fc0bc19fSjoerg m_freem(m0);
1295fc0bc19fSjoerg continue;
1296fc0bc19fSjoerg }
12973cd62456Smsaitoh bpf_mtap(ifp, m0, BPF_D_OUT);
1298fc0bc19fSjoerg m0 = ieee80211_encap(ic, m0, ni);
1299fc0bc19fSjoerg if (m0 == NULL) {
1300fc0bc19fSjoerg ieee80211_free_node(ni);
1301fc0bc19fSjoerg continue;
1302fc0bc19fSjoerg }
13033cd62456Smsaitoh bpf_mtap3(ic->ic_rawbpf, m0, BPF_D_OUT);
1304fc0bc19fSjoerg if (rum_tx_data(sc, m0, ni) != 0) {
1305fc0bc19fSjoerg ieee80211_free_node(ni);
1306cdaa0e91Sthorpej if_statinc(ifp, if_oerrors);
1307fc0bc19fSjoerg break;
1308fc0bc19fSjoerg }
1309fc0bc19fSjoerg }
1310fc0bc19fSjoerg
1311fc0bc19fSjoerg sc->sc_tx_timer = 5;
1312fc0bc19fSjoerg ifp->if_timer = 1;
1313fc0bc19fSjoerg }
1314fc0bc19fSjoerg }
1315fc0bc19fSjoerg
131687931599Sjmcneill static void
rum_watchdog(struct ifnet * ifp)1317fc0bc19fSjoerg rum_watchdog(struct ifnet *ifp)
1318fc0bc19fSjoerg {
1319fc0bc19fSjoerg struct rum_softc *sc = ifp->if_softc;
1320fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
1321fc0bc19fSjoerg
1322fc0bc19fSjoerg ifp->if_timer = 0;
1323fc0bc19fSjoerg
1324fc0bc19fSjoerg if (sc->sc_tx_timer > 0) {
1325fc0bc19fSjoerg if (--sc->sc_tx_timer == 0) {
132668c8418cSdyoung printf("%s: device timeout\n", device_xname(sc->sc_dev));
1327fc0bc19fSjoerg /*rum_init(ifp); XXX needs a process context! */
1328cdaa0e91Sthorpej if_statinc(ifp, if_oerrors);
1329fc0bc19fSjoerg return;
1330fc0bc19fSjoerg }
1331fc0bc19fSjoerg ifp->if_timer = 1;
1332fc0bc19fSjoerg }
1333fc0bc19fSjoerg
1334fc0bc19fSjoerg ieee80211_watchdog(ic);
1335fc0bc19fSjoerg }
1336fc0bc19fSjoerg
133787931599Sjmcneill static int
rum_ioctl(struct ifnet * ifp,u_long cmd,void * data)133853524e44Schristos rum_ioctl(struct ifnet *ifp, u_long cmd, void *data)
1339fc0bc19fSjoerg {
13409f8d6eb8Sjmcneill #define IS_RUNNING(ifp) \
13419f8d6eb8Sjmcneill (((ifp)->if_flags & IFF_UP) && ((ifp)->if_flags & IFF_RUNNING))
13429f8d6eb8Sjmcneill
1343fc0bc19fSjoerg struct rum_softc *sc = ifp->if_softc;
1344fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
1345fc0bc19fSjoerg int s, error = 0;
1346fc0bc19fSjoerg
1347fc0bc19fSjoerg s = splnet();
1348fc0bc19fSjoerg
1349fc0bc19fSjoerg switch (cmd) {
1350fc0bc19fSjoerg case SIOCSIFFLAGS:
1351de87fe67Sdyoung if ((error = ifioctl_common(ifp, cmd, data)) != 0)
1352de87fe67Sdyoung break;
1353de87fe67Sdyoung switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
1354de87fe67Sdyoung case IFF_UP|IFF_RUNNING:
1355fc0bc19fSjoerg rum_update_promisc(sc);
1356de87fe67Sdyoung break;
1357de87fe67Sdyoung case IFF_UP:
1358fc0bc19fSjoerg rum_init(ifp);
1359de87fe67Sdyoung break;
1360de87fe67Sdyoung case IFF_RUNNING:
1361fc0bc19fSjoerg rum_stop(ifp, 1);
1362de87fe67Sdyoung break;
1363de87fe67Sdyoung case 0:
1364de87fe67Sdyoung break;
1365fc0bc19fSjoerg }
1366fc0bc19fSjoerg break;
1367fc0bc19fSjoerg
13689f8d6eb8Sjmcneill case SIOCADDMULTI:
13699f8d6eb8Sjmcneill case SIOCDELMULTI:
13709f8d6eb8Sjmcneill if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
13719f8d6eb8Sjmcneill error = 0;
13729f8d6eb8Sjmcneill }
13739f8d6eb8Sjmcneill break;
13749f8d6eb8Sjmcneill
1375fc0bc19fSjoerg default:
1376fc0bc19fSjoerg error = ieee80211_ioctl(ic, cmd, data);
1377fc0bc19fSjoerg }
1378fc0bc19fSjoerg
1379fc0bc19fSjoerg if (error == ENETRESET) {
13809f8d6eb8Sjmcneill if (IS_RUNNING(ifp) &&
13819f8d6eb8Sjmcneill (ic->ic_roaming != IEEE80211_ROAMING_MANUAL))
1382fc0bc19fSjoerg rum_init(ifp);
1383fc0bc19fSjoerg error = 0;
1384fc0bc19fSjoerg }
1385fc0bc19fSjoerg
1386fc0bc19fSjoerg splx(s);
1387fc0bc19fSjoerg
1388fc0bc19fSjoerg return error;
13899f8d6eb8Sjmcneill #undef IS_RUNNING
1390fc0bc19fSjoerg }
1391fc0bc19fSjoerg
139287931599Sjmcneill static void
rum_eeprom_read(struct rum_softc * sc,uint16_t addr,void * buf,int len)1393fc0bc19fSjoerg rum_eeprom_read(struct rum_softc *sc, uint16_t addr, void *buf, int len)
1394fc0bc19fSjoerg {
1395fc0bc19fSjoerg usb_device_request_t req;
1396fc0bc19fSjoerg usbd_status error;
1397fc0bc19fSjoerg
1398fc0bc19fSjoerg req.bmRequestType = UT_READ_VENDOR_DEVICE;
1399fc0bc19fSjoerg req.bRequest = RT2573_READ_EEPROM;
1400fc0bc19fSjoerg USETW(req.wValue, 0);
1401fc0bc19fSjoerg USETW(req.wIndex, addr);
1402fc0bc19fSjoerg USETW(req.wLength, len);
1403fc0bc19fSjoerg
1404fc0bc19fSjoerg error = usbd_do_request(sc->sc_udev, &req, buf);
1405fc0bc19fSjoerg if (error != 0) {
1406fc0bc19fSjoerg printf("%s: could not read EEPROM: %s\n",
140768c8418cSdyoung device_xname(sc->sc_dev), usbd_errstr(error));
14083259e3c9Sriastradh memset(buf, 0, len);
1409fc0bc19fSjoerg }
1410fc0bc19fSjoerg }
1411fc0bc19fSjoerg
141287931599Sjmcneill static uint32_t
rum_read(struct rum_softc * sc,uint16_t reg)1413fc0bc19fSjoerg rum_read(struct rum_softc *sc, uint16_t reg)
1414fc0bc19fSjoerg {
1415fc0bc19fSjoerg uint32_t val;
1416fc0bc19fSjoerg
14174e8e6643Sskrll rum_read_multi(sc, reg, &val, sizeof(val));
1418fc0bc19fSjoerg
1419fc0bc19fSjoerg return le32toh(val);
1420fc0bc19fSjoerg }
1421fc0bc19fSjoerg
142287931599Sjmcneill static void
rum_read_multi(struct rum_softc * sc,uint16_t reg,void * buf,int len)1423fc0bc19fSjoerg rum_read_multi(struct rum_softc *sc, uint16_t reg, void *buf, int len)
1424fc0bc19fSjoerg {
1425fc0bc19fSjoerg usb_device_request_t req;
1426fc0bc19fSjoerg usbd_status error;
1427fc0bc19fSjoerg
1428fc0bc19fSjoerg req.bmRequestType = UT_READ_VENDOR_DEVICE;
1429fc0bc19fSjoerg req.bRequest = RT2573_READ_MULTI_MAC;
1430fc0bc19fSjoerg USETW(req.wValue, 0);
1431fc0bc19fSjoerg USETW(req.wIndex, reg);
1432fc0bc19fSjoerg USETW(req.wLength, len);
1433fc0bc19fSjoerg
1434fc0bc19fSjoerg error = usbd_do_request(sc->sc_udev, &req, buf);
1435fc0bc19fSjoerg if (error != 0) {
1436fc0bc19fSjoerg printf("%s: could not multi read MAC register: %s\n",
143768c8418cSdyoung device_xname(sc->sc_dev), usbd_errstr(error));
14383259e3c9Sriastradh memset(buf, 0, len);
1439fc0bc19fSjoerg }
1440fc0bc19fSjoerg }
1441fc0bc19fSjoerg
144287931599Sjmcneill static void
rum_write(struct rum_softc * sc,uint16_t reg,uint32_t val)1443fc0bc19fSjoerg rum_write(struct rum_softc *sc, uint16_t reg, uint32_t val)
1444fc0bc19fSjoerg {
1445fc0bc19fSjoerg uint32_t tmp = htole32(val);
1446fc0bc19fSjoerg
14474e8e6643Sskrll rum_write_multi(sc, reg, &tmp, sizeof(tmp));
1448fc0bc19fSjoerg }
1449fc0bc19fSjoerg
145087931599Sjmcneill static void
rum_write_multi(struct rum_softc * sc,uint16_t reg,void * buf,size_t len)1451fc0bc19fSjoerg rum_write_multi(struct rum_softc *sc, uint16_t reg, void *buf, size_t len)
1452fc0bc19fSjoerg {
1453fc0bc19fSjoerg usb_device_request_t req;
1454fc0bc19fSjoerg usbd_status error;
1455b79dc957Szafer int offset;
1456fc0bc19fSjoerg
1457fc0bc19fSjoerg req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1458fc0bc19fSjoerg req.bRequest = RT2573_WRITE_MULTI_MAC;
1459fc0bc19fSjoerg USETW(req.wValue, 0);
1460fc0bc19fSjoerg
1461b79dc957Szafer /* write at most 64 bytes at a time */
1462b79dc957Szafer for (offset = 0; offset < len; offset += 64) {
1463b79dc957Szafer USETW(req.wIndex, reg + offset);
1464b79dc957Szafer USETW(req.wLength, MIN(len - offset, 64));
1465b79dc957Szafer
1466b79dc957Szafer error = usbd_do_request(sc->sc_udev, &req, (char *)buf + offset);
1467fc0bc19fSjoerg if (error != 0) {
1468fc0bc19fSjoerg printf("%s: could not multi write MAC register: %s\n",
146968c8418cSdyoung device_xname(sc->sc_dev), usbd_errstr(error));
1470fc0bc19fSjoerg }
1471fc0bc19fSjoerg }
1472b79dc957Szafer }
1473fc0bc19fSjoerg
147487931599Sjmcneill static void
rum_bbp_write(struct rum_softc * sc,uint8_t reg,uint8_t val)1475fc0bc19fSjoerg rum_bbp_write(struct rum_softc *sc, uint8_t reg, uint8_t val)
1476fc0bc19fSjoerg {
1477fc0bc19fSjoerg uint32_t tmp;
1478fc0bc19fSjoerg int ntries;
1479fc0bc19fSjoerg
1480fc0bc19fSjoerg for (ntries = 0; ntries < 5; ntries++) {
1481fc0bc19fSjoerg if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY))
1482fc0bc19fSjoerg break;
1483fc0bc19fSjoerg }
1484fc0bc19fSjoerg if (ntries == 5) {
148568c8418cSdyoung printf("%s: could not write to BBP\n", device_xname(sc->sc_dev));
1486fc0bc19fSjoerg return;
1487fc0bc19fSjoerg }
1488fc0bc19fSjoerg
1489fc0bc19fSjoerg tmp = RT2573_BBP_BUSY | (reg & 0x7f) << 8 | val;
1490fc0bc19fSjoerg rum_write(sc, RT2573_PHY_CSR3, tmp);
1491fc0bc19fSjoerg }
1492fc0bc19fSjoerg
149387931599Sjmcneill static uint8_t
rum_bbp_read(struct rum_softc * sc,uint8_t reg)1494fc0bc19fSjoerg rum_bbp_read(struct rum_softc *sc, uint8_t reg)
1495fc0bc19fSjoerg {
1496fc0bc19fSjoerg uint32_t val;
1497fc0bc19fSjoerg int ntries;
1498fc0bc19fSjoerg
1499fc0bc19fSjoerg for (ntries = 0; ntries < 5; ntries++) {
1500fc0bc19fSjoerg if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY))
1501fc0bc19fSjoerg break;
1502fc0bc19fSjoerg }
1503fc0bc19fSjoerg if (ntries == 5) {
150468c8418cSdyoung printf("%s: could not read BBP\n", device_xname(sc->sc_dev));
1505fc0bc19fSjoerg return 0;
1506fc0bc19fSjoerg }
1507fc0bc19fSjoerg
1508fc0bc19fSjoerg val = RT2573_BBP_BUSY | RT2573_BBP_READ | reg << 8;
1509fc0bc19fSjoerg rum_write(sc, RT2573_PHY_CSR3, val);
1510fc0bc19fSjoerg
1511fc0bc19fSjoerg for (ntries = 0; ntries < 100; ntries++) {
1512fc0bc19fSjoerg val = rum_read(sc, RT2573_PHY_CSR3);
1513fc0bc19fSjoerg if (!(val & RT2573_BBP_BUSY))
1514fc0bc19fSjoerg return val & 0xff;
1515fc0bc19fSjoerg DELAY(1);
1516fc0bc19fSjoerg }
1517fc0bc19fSjoerg
151868c8418cSdyoung printf("%s: could not read BBP\n", device_xname(sc->sc_dev));
1519fc0bc19fSjoerg return 0;
1520fc0bc19fSjoerg }
1521fc0bc19fSjoerg
152287931599Sjmcneill static void
rum_rf_write(struct rum_softc * sc,uint8_t reg,uint32_t val)1523fc0bc19fSjoerg rum_rf_write(struct rum_softc *sc, uint8_t reg, uint32_t val)
1524fc0bc19fSjoerg {
1525fc0bc19fSjoerg uint32_t tmp;
1526fc0bc19fSjoerg int ntries;
1527fc0bc19fSjoerg
1528fc0bc19fSjoerg for (ntries = 0; ntries < 5; ntries++) {
1529fc0bc19fSjoerg if (!(rum_read(sc, RT2573_PHY_CSR4) & RT2573_RF_BUSY))
1530fc0bc19fSjoerg break;
1531fc0bc19fSjoerg }
1532fc0bc19fSjoerg if (ntries == 5) {
153368c8418cSdyoung printf("%s: could not write to RF\n", device_xname(sc->sc_dev));
1534fc0bc19fSjoerg return;
1535fc0bc19fSjoerg }
1536fc0bc19fSjoerg
1537fc0bc19fSjoerg tmp = RT2573_RF_BUSY | RT2573_RF_20BIT | (val & 0xfffff) << 2 |
1538fc0bc19fSjoerg (reg & 3);
1539fc0bc19fSjoerg rum_write(sc, RT2573_PHY_CSR4, tmp);
1540fc0bc19fSjoerg
1541fc0bc19fSjoerg /* remember last written value in sc */
1542fc0bc19fSjoerg sc->rf_regs[reg] = val;
1543fc0bc19fSjoerg
1544aa3d6ec1Schristos DPRINTFN(15, ("RF R[%u] <- 0x%05x\n", reg & 3, val & 0xfffff));
1545fc0bc19fSjoerg }
1546fc0bc19fSjoerg
154787931599Sjmcneill static void
rum_select_antenna(struct rum_softc * sc)1548fc0bc19fSjoerg rum_select_antenna(struct rum_softc *sc)
1549fc0bc19fSjoerg {
1550fc0bc19fSjoerg uint8_t bbp4, bbp77;
1551fc0bc19fSjoerg uint32_t tmp;
1552fc0bc19fSjoerg
1553fc0bc19fSjoerg bbp4 = rum_bbp_read(sc, 4);
1554fc0bc19fSjoerg bbp77 = rum_bbp_read(sc, 77);
1555fc0bc19fSjoerg
1556fc0bc19fSjoerg /* TBD */
1557fc0bc19fSjoerg
1558fc0bc19fSjoerg /* make sure Rx is disabled before switching antenna */
1559fc0bc19fSjoerg tmp = rum_read(sc, RT2573_TXRX_CSR0);
1560fc0bc19fSjoerg rum_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX);
1561fc0bc19fSjoerg
1562fc0bc19fSjoerg rum_bbp_write(sc, 4, bbp4);
1563fc0bc19fSjoerg rum_bbp_write(sc, 77, bbp77);
1564fc0bc19fSjoerg
1565fc0bc19fSjoerg rum_write(sc, RT2573_TXRX_CSR0, tmp);
1566fc0bc19fSjoerg }
1567fc0bc19fSjoerg
1568fc0bc19fSjoerg /*
1569fc0bc19fSjoerg * Enable multi-rate retries for frames sent at OFDM rates.
1570fc0bc19fSjoerg * In 802.11b/g mode, allow fallback to CCK rates.
1571fc0bc19fSjoerg */
157287931599Sjmcneill static void
rum_enable_mrr(struct rum_softc * sc)1573fc0bc19fSjoerg rum_enable_mrr(struct rum_softc *sc)
1574fc0bc19fSjoerg {
1575fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
1576fc0bc19fSjoerg uint32_t tmp;
1577fc0bc19fSjoerg
1578fc0bc19fSjoerg tmp = rum_read(sc, RT2573_TXRX_CSR4);
1579fc0bc19fSjoerg
1580fc0bc19fSjoerg tmp &= ~RT2573_MRR_CCK_FALLBACK;
1581fc0bc19fSjoerg if (!IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
1582fc0bc19fSjoerg tmp |= RT2573_MRR_CCK_FALLBACK;
1583fc0bc19fSjoerg tmp |= RT2573_MRR_ENABLED;
1584fc0bc19fSjoerg
1585fc0bc19fSjoerg rum_write(sc, RT2573_TXRX_CSR4, tmp);
1586fc0bc19fSjoerg }
1587fc0bc19fSjoerg
158887931599Sjmcneill static void
rum_set_txpreamble(struct rum_softc * sc)1589fc0bc19fSjoerg rum_set_txpreamble(struct rum_softc *sc)
1590fc0bc19fSjoerg {
1591fc0bc19fSjoerg uint32_t tmp;
1592fc0bc19fSjoerg
1593fc0bc19fSjoerg tmp = rum_read(sc, RT2573_TXRX_CSR4);
1594fc0bc19fSjoerg
1595fc0bc19fSjoerg tmp &= ~RT2573_SHORT_PREAMBLE;
1596fc0bc19fSjoerg if (sc->sc_ic.ic_flags & IEEE80211_F_SHPREAMBLE)
1597fc0bc19fSjoerg tmp |= RT2573_SHORT_PREAMBLE;
1598fc0bc19fSjoerg
1599fc0bc19fSjoerg rum_write(sc, RT2573_TXRX_CSR4, tmp);
1600fc0bc19fSjoerg }
1601fc0bc19fSjoerg
160287931599Sjmcneill static void
rum_set_basicrates(struct rum_softc * sc)1603fc0bc19fSjoerg rum_set_basicrates(struct rum_softc *sc)
1604fc0bc19fSjoerg {
1605fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
1606fc0bc19fSjoerg
1607fc0bc19fSjoerg /* update basic rate set */
1608fc0bc19fSjoerg if (ic->ic_curmode == IEEE80211_MODE_11B) {
1609fc0bc19fSjoerg /* 11b basic rates: 1, 2Mbps */
1610fc0bc19fSjoerg rum_write(sc, RT2573_TXRX_CSR5, 0x3);
16113bf7c476Skiyohara } else if (ic->ic_curmode == IEEE80211_MODE_11A) {
1612fc0bc19fSjoerg /* 11a basic rates: 6, 12, 24Mbps */
1613fc0bc19fSjoerg rum_write(sc, RT2573_TXRX_CSR5, 0x150);
1614fc0bc19fSjoerg } else {
16153bf7c476Skiyohara /* 11b/g basic rates: 1, 2, 5.5, 11Mbps */
16163bf7c476Skiyohara rum_write(sc, RT2573_TXRX_CSR5, 0xf);
1617fc0bc19fSjoerg }
1618fc0bc19fSjoerg }
1619fc0bc19fSjoerg
1620fc0bc19fSjoerg /*
1621fc0bc19fSjoerg * Reprogram MAC/BBP to switch to a new band. Values taken from the reference
1622fc0bc19fSjoerg * driver.
1623fc0bc19fSjoerg */
162487931599Sjmcneill static void
rum_select_band(struct rum_softc * sc,struct ieee80211_channel * c)1625fc0bc19fSjoerg rum_select_band(struct rum_softc *sc, struct ieee80211_channel *c)
1626fc0bc19fSjoerg {
1627fc0bc19fSjoerg uint8_t bbp17, bbp35, bbp96, bbp97, bbp98, bbp104;
1628fc0bc19fSjoerg uint32_t tmp;
1629fc0bc19fSjoerg
1630fc0bc19fSjoerg /* update all BBP registers that depend on the band */
1631fc0bc19fSjoerg bbp17 = 0x20; bbp96 = 0x48; bbp104 = 0x2c;
1632fc0bc19fSjoerg bbp35 = 0x50; bbp97 = 0x48; bbp98 = 0x48;
1633fc0bc19fSjoerg if (IEEE80211_IS_CHAN_5GHZ(c)) {
1634fc0bc19fSjoerg bbp17 += 0x08; bbp96 += 0x10; bbp104 += 0x0c;
1635fc0bc19fSjoerg bbp35 += 0x10; bbp97 += 0x10; bbp98 += 0x10;
1636fc0bc19fSjoerg }
1637fc0bc19fSjoerg if ((IEEE80211_IS_CHAN_2GHZ(c) && sc->ext_2ghz_lna) ||
1638fc0bc19fSjoerg (IEEE80211_IS_CHAN_5GHZ(c) && sc->ext_5ghz_lna)) {
1639fc0bc19fSjoerg bbp17 += 0x10; bbp96 += 0x10; bbp104 += 0x10;
1640fc0bc19fSjoerg }
1641fc0bc19fSjoerg
1642fc0bc19fSjoerg sc->bbp17 = bbp17;
1643fc0bc19fSjoerg rum_bbp_write(sc, 17, bbp17);
1644fc0bc19fSjoerg rum_bbp_write(sc, 96, bbp96);
1645fc0bc19fSjoerg rum_bbp_write(sc, 104, bbp104);
1646fc0bc19fSjoerg
1647fc0bc19fSjoerg if ((IEEE80211_IS_CHAN_2GHZ(c) && sc->ext_2ghz_lna) ||
1648fc0bc19fSjoerg (IEEE80211_IS_CHAN_5GHZ(c) && sc->ext_5ghz_lna)) {
1649fc0bc19fSjoerg rum_bbp_write(sc, 75, 0x80);
1650fc0bc19fSjoerg rum_bbp_write(sc, 86, 0x80);
1651fc0bc19fSjoerg rum_bbp_write(sc, 88, 0x80);
1652fc0bc19fSjoerg }
1653fc0bc19fSjoerg
1654fc0bc19fSjoerg rum_bbp_write(sc, 35, bbp35);
1655fc0bc19fSjoerg rum_bbp_write(sc, 97, bbp97);
1656fc0bc19fSjoerg rum_bbp_write(sc, 98, bbp98);
1657fc0bc19fSjoerg
1658fc0bc19fSjoerg tmp = rum_read(sc, RT2573_PHY_CSR0);
1659fc0bc19fSjoerg tmp &= ~(RT2573_PA_PE_2GHZ | RT2573_PA_PE_5GHZ);
1660fc0bc19fSjoerg if (IEEE80211_IS_CHAN_2GHZ(c))
1661fc0bc19fSjoerg tmp |= RT2573_PA_PE_2GHZ;
1662fc0bc19fSjoerg else
1663fc0bc19fSjoerg tmp |= RT2573_PA_PE_5GHZ;
1664fc0bc19fSjoerg rum_write(sc, RT2573_PHY_CSR0, tmp);
1665fc0bc19fSjoerg
1666fc0bc19fSjoerg /* 802.11a uses a 16 microseconds short interframe space */
1667fc0bc19fSjoerg sc->sifs = IEEE80211_IS_CHAN_5GHZ(c) ? 16 : 10;
1668fc0bc19fSjoerg }
1669fc0bc19fSjoerg
167087931599Sjmcneill static void
rum_set_chan(struct rum_softc * sc,struct ieee80211_channel * c)1671fc0bc19fSjoerg rum_set_chan(struct rum_softc *sc, struct ieee80211_channel *c)
1672fc0bc19fSjoerg {
1673fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
1674fc0bc19fSjoerg const struct rfprog *rfprog;
1675fc0bc19fSjoerg uint8_t bbp3, bbp94 = RT2573_BBPR94_DEFAULT;
1676fc0bc19fSjoerg int8_t power;
1677fc0bc19fSjoerg u_int i, chan;
1678fc0bc19fSjoerg
1679fc0bc19fSjoerg chan = ieee80211_chan2ieee(ic, c);
1680fc0bc19fSjoerg if (chan == 0 || chan == IEEE80211_CHAN_ANY)
1681fc0bc19fSjoerg return;
1682fc0bc19fSjoerg
1683fc0bc19fSjoerg /* select the appropriate RF settings based on what EEPROM says */
1684fc0bc19fSjoerg rfprog = (sc->rf_rev == RT2573_RF_5225 ||
1685fc0bc19fSjoerg sc->rf_rev == RT2573_RF_2527) ? rum_rf5225 : rum_rf5226;
1686fc0bc19fSjoerg
1687fc0bc19fSjoerg /* find the settings for this channel (we know it exists) */
1688fc0bc19fSjoerg for (i = 0; rfprog[i].chan != chan; i++);
1689fc0bc19fSjoerg
1690fc0bc19fSjoerg power = sc->txpow[i];
1691fc0bc19fSjoerg if (power < 0) {
1692fc0bc19fSjoerg bbp94 += power;
1693fc0bc19fSjoerg power = 0;
1694fc0bc19fSjoerg } else if (power > 31) {
1695fc0bc19fSjoerg bbp94 += power - 31;
1696fc0bc19fSjoerg power = 31;
1697fc0bc19fSjoerg }
1698fc0bc19fSjoerg
1699fc0bc19fSjoerg /*
1700fc0bc19fSjoerg * If we are switching from the 2GHz band to the 5GHz band or
1701fc0bc19fSjoerg * vice-versa, BBP registers need to be reprogrammed.
1702fc0bc19fSjoerg */
1703fc0bc19fSjoerg if (c->ic_flags != ic->ic_curchan->ic_flags) {
1704fc0bc19fSjoerg rum_select_band(sc, c);
1705fc0bc19fSjoerg rum_select_antenna(sc);
1706fc0bc19fSjoerg }
1707fc0bc19fSjoerg ic->ic_curchan = c;
1708fc0bc19fSjoerg
1709fc0bc19fSjoerg rum_rf_write(sc, RT2573_RF1, rfprog[i].r1);
1710fc0bc19fSjoerg rum_rf_write(sc, RT2573_RF2, rfprog[i].r2);
1711fc0bc19fSjoerg rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7);
1712fc0bc19fSjoerg rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10);
1713fc0bc19fSjoerg
1714fc0bc19fSjoerg rum_rf_write(sc, RT2573_RF1, rfprog[i].r1);
1715fc0bc19fSjoerg rum_rf_write(sc, RT2573_RF2, rfprog[i].r2);
1716fc0bc19fSjoerg rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7 | 1);
1717fc0bc19fSjoerg rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10);
1718fc0bc19fSjoerg
1719fc0bc19fSjoerg rum_rf_write(sc, RT2573_RF1, rfprog[i].r1);
1720fc0bc19fSjoerg rum_rf_write(sc, RT2573_RF2, rfprog[i].r2);
1721fc0bc19fSjoerg rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7);
1722fc0bc19fSjoerg rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10);
1723fc0bc19fSjoerg
1724fc0bc19fSjoerg DELAY(10);
1725fc0bc19fSjoerg
1726fc0bc19fSjoerg /* enable smart mode for MIMO-capable RFs */
1727fc0bc19fSjoerg bbp3 = rum_bbp_read(sc, 3);
1728fc0bc19fSjoerg
1729fc0bc19fSjoerg bbp3 &= ~RT2573_SMART_MODE;
1730fc0bc19fSjoerg if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_2527)
1731fc0bc19fSjoerg bbp3 |= RT2573_SMART_MODE;
1732fc0bc19fSjoerg
1733fc0bc19fSjoerg rum_bbp_write(sc, 3, bbp3);
1734fc0bc19fSjoerg
1735fc0bc19fSjoerg if (bbp94 != RT2573_BBPR94_DEFAULT)
1736fc0bc19fSjoerg rum_bbp_write(sc, 94, bbp94);
1737fc0bc19fSjoerg }
1738fc0bc19fSjoerg
1739fc0bc19fSjoerg /*
1740fc0bc19fSjoerg * Enable TSF synchronization and tell h/w to start sending beacons for IBSS
1741fc0bc19fSjoerg * and HostAP operating modes.
1742fc0bc19fSjoerg */
174387931599Sjmcneill static void
rum_enable_tsf_sync(struct rum_softc * sc)1744fc0bc19fSjoerg rum_enable_tsf_sync(struct rum_softc *sc)
1745fc0bc19fSjoerg {
1746fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
1747fc0bc19fSjoerg uint32_t tmp;
1748fc0bc19fSjoerg
1749fc0bc19fSjoerg if (ic->ic_opmode != IEEE80211_M_STA) {
1750fc0bc19fSjoerg /*
1751fc0bc19fSjoerg * Change default 16ms TBTT adjustment to 8ms.
1752fc0bc19fSjoerg * Must be done before enabling beacon generation.
1753fc0bc19fSjoerg */
1754fc0bc19fSjoerg rum_write(sc, RT2573_TXRX_CSR10, 1 << 12 | 8);
1755fc0bc19fSjoerg }
1756fc0bc19fSjoerg
1757fc0bc19fSjoerg tmp = rum_read(sc, RT2573_TXRX_CSR9) & 0xff000000;
1758fc0bc19fSjoerg
1759fc0bc19fSjoerg /* set beacon interval (in 1/16ms unit) */
1760fc0bc19fSjoerg tmp |= ic->ic_bss->ni_intval * 16;
1761fc0bc19fSjoerg
1762fc0bc19fSjoerg tmp |= RT2573_TSF_TICKING | RT2573_ENABLE_TBTT;
1763fc0bc19fSjoerg if (ic->ic_opmode == IEEE80211_M_STA)
1764fc0bc19fSjoerg tmp |= RT2573_TSF_MODE(1);
1765fc0bc19fSjoerg else
1766fc0bc19fSjoerg tmp |= RT2573_TSF_MODE(2) | RT2573_GENERATE_BEACON;
1767fc0bc19fSjoerg
1768fc0bc19fSjoerg rum_write(sc, RT2573_TXRX_CSR9, tmp);
1769fc0bc19fSjoerg }
1770fc0bc19fSjoerg
177187931599Sjmcneill static void
rum_update_slot(struct rum_softc * sc)1772fc0bc19fSjoerg rum_update_slot(struct rum_softc *sc)
1773fc0bc19fSjoerg {
1774fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
1775fc0bc19fSjoerg uint8_t slottime;
1776fc0bc19fSjoerg uint32_t tmp;
1777fc0bc19fSjoerg
1778fc0bc19fSjoerg slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
1779fc0bc19fSjoerg
1780fc0bc19fSjoerg tmp = rum_read(sc, RT2573_MAC_CSR9);
1781fc0bc19fSjoerg tmp = (tmp & ~0xff) | slottime;
1782fc0bc19fSjoerg rum_write(sc, RT2573_MAC_CSR9, tmp);
1783fc0bc19fSjoerg
1784fc0bc19fSjoerg DPRINTF(("setting slot time to %uus\n", slottime));
1785fc0bc19fSjoerg }
1786fc0bc19fSjoerg
178787931599Sjmcneill static void
rum_set_bssid(struct rum_softc * sc,const uint8_t * bssid)1788fc0bc19fSjoerg rum_set_bssid(struct rum_softc *sc, const uint8_t *bssid)
1789fc0bc19fSjoerg {
1790fc0bc19fSjoerg uint32_t tmp;
1791fc0bc19fSjoerg
1792fc0bc19fSjoerg tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24;
1793fc0bc19fSjoerg rum_write(sc, RT2573_MAC_CSR4, tmp);
1794fc0bc19fSjoerg
1795fc0bc19fSjoerg tmp = bssid[4] | bssid[5] << 8 | RT2573_ONE_BSSID << 16;
1796fc0bc19fSjoerg rum_write(sc, RT2573_MAC_CSR5, tmp);
1797fc0bc19fSjoerg }
1798fc0bc19fSjoerg
179987931599Sjmcneill static void
rum_set_macaddr(struct rum_softc * sc,const uint8_t * addr)1800fc0bc19fSjoerg rum_set_macaddr(struct rum_softc *sc, const uint8_t *addr)
1801fc0bc19fSjoerg {
1802fc0bc19fSjoerg uint32_t tmp;
1803fc0bc19fSjoerg
1804fc0bc19fSjoerg tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24;
1805fc0bc19fSjoerg rum_write(sc, RT2573_MAC_CSR2, tmp);
1806fc0bc19fSjoerg
1807fc0bc19fSjoerg tmp = addr[4] | addr[5] << 8 | 0xff << 16;
1808fc0bc19fSjoerg rum_write(sc, RT2573_MAC_CSR3, tmp);
1809fc0bc19fSjoerg }
1810fc0bc19fSjoerg
181187931599Sjmcneill static void
rum_update_promisc(struct rum_softc * sc)1812fc0bc19fSjoerg rum_update_promisc(struct rum_softc *sc)
1813fc0bc19fSjoerg {
1814fc0bc19fSjoerg struct ifnet *ifp = sc->sc_ic.ic_ifp;
1815fc0bc19fSjoerg uint32_t tmp;
1816fc0bc19fSjoerg
1817fc0bc19fSjoerg tmp = rum_read(sc, RT2573_TXRX_CSR0);
1818fc0bc19fSjoerg
1819fc0bc19fSjoerg tmp &= ~RT2573_DROP_NOT_TO_ME;
1820fc0bc19fSjoerg if (!(ifp->if_flags & IFF_PROMISC))
1821fc0bc19fSjoerg tmp |= RT2573_DROP_NOT_TO_ME;
1822fc0bc19fSjoerg
1823fc0bc19fSjoerg rum_write(sc, RT2573_TXRX_CSR0, tmp);
1824fc0bc19fSjoerg
1825fc0bc19fSjoerg DPRINTF(("%s promiscuous mode\n", (ifp->if_flags & IFF_PROMISC) ?
1826fc0bc19fSjoerg "entering" : "leaving"));
1827fc0bc19fSjoerg }
1828fc0bc19fSjoerg
182987931599Sjmcneill static const char *
rum_get_rf(int rev)1830fc0bc19fSjoerg rum_get_rf(int rev)
1831fc0bc19fSjoerg {
1832fc0bc19fSjoerg switch (rev) {
1833fc0bc19fSjoerg case RT2573_RF_2527: return "RT2527 (MIMO XR)";
1834fc0bc19fSjoerg case RT2573_RF_2528: return "RT2528";
1835fc0bc19fSjoerg case RT2573_RF_5225: return "RT5225 (MIMO XR)";
1836fc0bc19fSjoerg case RT2573_RF_5226: return "RT5226";
1837fc0bc19fSjoerg default: return "unknown";
1838fc0bc19fSjoerg }
1839fc0bc19fSjoerg }
1840fc0bc19fSjoerg
184187931599Sjmcneill static void
rum_read_eeprom(struct rum_softc * sc)1842fc0bc19fSjoerg rum_read_eeprom(struct rum_softc *sc)
1843fc0bc19fSjoerg {
1844fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
1845fc0bc19fSjoerg uint16_t val;
1846fc0bc19fSjoerg #ifdef RUM_DEBUG
1847fc0bc19fSjoerg int i;
1848fc0bc19fSjoerg #endif
1849fc0bc19fSjoerg
1850fc0bc19fSjoerg /* read MAC/BBP type */
1851fc0bc19fSjoerg rum_eeprom_read(sc, RT2573_EEPROM_MACBBP, &val, 2);
1852fc0bc19fSjoerg sc->macbbp_rev = le16toh(val);
1853fc0bc19fSjoerg
1854fc0bc19fSjoerg /* read MAC address */
1855fc0bc19fSjoerg rum_eeprom_read(sc, RT2573_EEPROM_ADDRESS, ic->ic_myaddr, 6);
1856fc0bc19fSjoerg
1857fc0bc19fSjoerg rum_eeprom_read(sc, RT2573_EEPROM_ANTENNA, &val, 2);
1858fc0bc19fSjoerg val = le16toh(val);
1859fc0bc19fSjoerg sc->rf_rev = (val >> 11) & 0x1f;
1860fc0bc19fSjoerg sc->hw_radio = (val >> 10) & 0x1;
1861fc0bc19fSjoerg sc->rx_ant = (val >> 4) & 0x3;
1862fc0bc19fSjoerg sc->tx_ant = (val >> 2) & 0x3;
1863fc0bc19fSjoerg sc->nb_ant = val & 0x3;
1864fc0bc19fSjoerg
1865fc0bc19fSjoerg DPRINTF(("RF revision=%d\n", sc->rf_rev));
1866fc0bc19fSjoerg
1867fc0bc19fSjoerg rum_eeprom_read(sc, RT2573_EEPROM_CONFIG2, &val, 2);
1868fc0bc19fSjoerg val = le16toh(val);
1869fc0bc19fSjoerg sc->ext_5ghz_lna = (val >> 6) & 0x1;
1870fc0bc19fSjoerg sc->ext_2ghz_lna = (val >> 4) & 0x1;
1871fc0bc19fSjoerg
1872fc0bc19fSjoerg DPRINTF(("External 2GHz LNA=%d\nExternal 5GHz LNA=%d\n",
1873fc0bc19fSjoerg sc->ext_2ghz_lna, sc->ext_5ghz_lna));
1874fc0bc19fSjoerg
1875fc0bc19fSjoerg rum_eeprom_read(sc, RT2573_EEPROM_RSSI_2GHZ_OFFSET, &val, 2);
1876fc0bc19fSjoerg val = le16toh(val);
1877fc0bc19fSjoerg if ((val & 0xff) != 0xff)
1878fc0bc19fSjoerg sc->rssi_2ghz_corr = (int8_t)(val & 0xff); /* signed */
1879fc0bc19fSjoerg
1880fc0bc19fSjoerg rum_eeprom_read(sc, RT2573_EEPROM_RSSI_5GHZ_OFFSET, &val, 2);
1881fc0bc19fSjoerg val = le16toh(val);
1882fc0bc19fSjoerg if ((val & 0xff) != 0xff)
1883fc0bc19fSjoerg sc->rssi_5ghz_corr = (int8_t)(val & 0xff); /* signed */
1884fc0bc19fSjoerg
1885fc0bc19fSjoerg DPRINTF(("RSSI 2GHz corr=%d\nRSSI 5GHz corr=%d\n",
1886fc0bc19fSjoerg sc->rssi_2ghz_corr, sc->rssi_5ghz_corr));
1887fc0bc19fSjoerg
1888fc0bc19fSjoerg rum_eeprom_read(sc, RT2573_EEPROM_FREQ_OFFSET, &val, 2);
1889fc0bc19fSjoerg val = le16toh(val);
1890fc0bc19fSjoerg if ((val & 0xff) != 0xff)
1891fc0bc19fSjoerg sc->rffreq = val & 0xff;
1892fc0bc19fSjoerg
1893fc0bc19fSjoerg DPRINTF(("RF freq=%d\n", sc->rffreq));
1894fc0bc19fSjoerg
1895fc0bc19fSjoerg /* read Tx power for all a/b/g channels */
1896fc0bc19fSjoerg rum_eeprom_read(sc, RT2573_EEPROM_TXPOWER, sc->txpow, 14);
1897fc0bc19fSjoerg /* XXX default Tx power for 802.11a channels */
1898fc0bc19fSjoerg memset(sc->txpow + 14, 24, sizeof(sc->txpow) - 14);
1899fc0bc19fSjoerg #ifdef RUM_DEBUG
1900fc0bc19fSjoerg for (i = 0; i < 14; i++)
1901fc0bc19fSjoerg DPRINTF(("Channel=%d Tx power=%d\n", i + 1, sc->txpow[i]));
1902fc0bc19fSjoerg #endif
1903fc0bc19fSjoerg
1904fc0bc19fSjoerg /* read default values for BBP registers */
1905fc0bc19fSjoerg rum_eeprom_read(sc, RT2573_EEPROM_BBP_BASE, sc->bbp_prom, 2 * 16);
1906fc0bc19fSjoerg #ifdef RUM_DEBUG
1907fc0bc19fSjoerg for (i = 0; i < 14; i++) {
1908fc0bc19fSjoerg if (sc->bbp_prom[i].reg == 0 || sc->bbp_prom[i].reg == 0xff)
1909fc0bc19fSjoerg continue;
1910fc0bc19fSjoerg DPRINTF(("BBP R%d=%02x\n", sc->bbp_prom[i].reg,
1911fc0bc19fSjoerg sc->bbp_prom[i].val));
1912fc0bc19fSjoerg }
1913fc0bc19fSjoerg #endif
1914fc0bc19fSjoerg }
1915fc0bc19fSjoerg
191687931599Sjmcneill static int
rum_bbp_init(struct rum_softc * sc)1917fc0bc19fSjoerg rum_bbp_init(struct rum_softc *sc)
1918fc0bc19fSjoerg {
19193016e043Spgoyette unsigned int i, ntries;
1920fc0bc19fSjoerg uint8_t val;
1921fc0bc19fSjoerg
1922fc0bc19fSjoerg /* wait for BBP to be ready */
1923fc0bc19fSjoerg for (ntries = 0; ntries < 100; ntries++) {
1924fc0bc19fSjoerg val = rum_bbp_read(sc, 0);
1925fc0bc19fSjoerg if (val != 0 && val != 0xff)
1926fc0bc19fSjoerg break;
1927fc0bc19fSjoerg DELAY(1000);
1928fc0bc19fSjoerg }
1929fc0bc19fSjoerg if (ntries == 100) {
1930fc0bc19fSjoerg printf("%s: timeout waiting for BBP\n",
193168c8418cSdyoung device_xname(sc->sc_dev));
1932fc0bc19fSjoerg return EIO;
1933fc0bc19fSjoerg }
1934fc0bc19fSjoerg
1935fc0bc19fSjoerg /* initialize BBP registers to default values */
19364e8e6643Sskrll for (i = 0; i < __arraycount(rum_def_bbp); i++)
1937fc0bc19fSjoerg rum_bbp_write(sc, rum_def_bbp[i].reg, rum_def_bbp[i].val);
1938fc0bc19fSjoerg
1939fc0bc19fSjoerg /* write vendor-specific BBP values (from EEPROM) */
1940fc0bc19fSjoerg for (i = 0; i < 16; i++) {
1941fc0bc19fSjoerg if (sc->bbp_prom[i].reg == 0 || sc->bbp_prom[i].reg == 0xff)
1942fc0bc19fSjoerg continue;
1943fc0bc19fSjoerg rum_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val);
1944fc0bc19fSjoerg }
1945fc0bc19fSjoerg
1946fc0bc19fSjoerg return 0;
1947fc0bc19fSjoerg }
1948fc0bc19fSjoerg
194987931599Sjmcneill static int
rum_init(struct ifnet * ifp)1950fc0bc19fSjoerg rum_init(struct ifnet *ifp)
1951fc0bc19fSjoerg {
1952fc0bc19fSjoerg struct rum_softc *sc = ifp->if_softc;
1953fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
1954fc0bc19fSjoerg uint32_t tmp;
1955fc0bc19fSjoerg usbd_status error = 0;
19563016e043Spgoyette unsigned int i, ntries;
1957fc0bc19fSjoerg
1958fc0bc19fSjoerg if ((sc->sc_flags & RT2573_FWLOADED) == 0) {
1959fc0bc19fSjoerg if (rum_attachhook(sc))
1960fc0bc19fSjoerg goto fail;
1961fc0bc19fSjoerg }
1962fc0bc19fSjoerg
1963fc0bc19fSjoerg rum_stop(ifp, 0);
1964fc0bc19fSjoerg
1965fc0bc19fSjoerg /* initialize MAC registers to default values */
19664e8e6643Sskrll for (i = 0; i < __arraycount(rum_def_mac); i++)
1967fc0bc19fSjoerg rum_write(sc, rum_def_mac[i].reg, rum_def_mac[i].val);
1968fc0bc19fSjoerg
1969fc0bc19fSjoerg /* set host ready */
1970fc0bc19fSjoerg rum_write(sc, RT2573_MAC_CSR1, 3);
1971fc0bc19fSjoerg rum_write(sc, RT2573_MAC_CSR1, 0);
1972fc0bc19fSjoerg
1973fc0bc19fSjoerg /* wait for BBP/RF to wakeup */
1974fc0bc19fSjoerg for (ntries = 0; ntries < 1000; ntries++) {
1975fc0bc19fSjoerg if (rum_read(sc, RT2573_MAC_CSR12) & 8)
1976fc0bc19fSjoerg break;
1977fc0bc19fSjoerg rum_write(sc, RT2573_MAC_CSR12, 4); /* force wakeup */
1978fc0bc19fSjoerg DELAY(1000);
1979fc0bc19fSjoerg }
1980fc0bc19fSjoerg if (ntries == 1000) {
1981fc0bc19fSjoerg printf("%s: timeout waiting for BBP/RF to wakeup\n",
198268c8418cSdyoung device_xname(sc->sc_dev));
1983fc0bc19fSjoerg goto fail;
1984fc0bc19fSjoerg }
1985fc0bc19fSjoerg
1986fc0bc19fSjoerg if ((error = rum_bbp_init(sc)) != 0)
1987fc0bc19fSjoerg goto fail;
1988fc0bc19fSjoerg
1989fc0bc19fSjoerg /* select default channel */
1990fc0bc19fSjoerg rum_select_band(sc, ic->ic_curchan);
1991fc0bc19fSjoerg rum_select_antenna(sc);
1992fc0bc19fSjoerg rum_set_chan(sc, ic->ic_curchan);
1993fc0bc19fSjoerg
1994fc0bc19fSjoerg /* clear STA registers */
19954e8e6643Sskrll rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof(sc->sta));
1996fc0bc19fSjoerg
199771e77a61Sdyoung IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl));
1998fc0bc19fSjoerg rum_set_macaddr(sc, ic->ic_myaddr);
1999fc0bc19fSjoerg
2000fc0bc19fSjoerg /* initialize ASIC */
2001fc0bc19fSjoerg rum_write(sc, RT2573_MAC_CSR1, 4);
2002fc0bc19fSjoerg
2003fc0bc19fSjoerg /*
2004fc0bc19fSjoerg * Allocate xfer for AMRR statistics requests.
2005fc0bc19fSjoerg */
20064e8e6643Sskrll struct usbd_pipe *pipe0 = usbd_get_pipe0(sc->sc_udev);
20074e8e6643Sskrll error = usbd_create_xfer(pipe0, sizeof(sc->sta), 0, 0,
20084e8e6643Sskrll &sc->amrr_xfer);
20094e8e6643Sskrll if (error) {
2010fc0bc19fSjoerg printf("%s: could not allocate AMRR xfer\n",
201168c8418cSdyoung device_xname(sc->sc_dev));
2012fc0bc19fSjoerg goto fail;
2013fc0bc19fSjoerg }
2014fc0bc19fSjoerg
2015fc0bc19fSjoerg /*
2016fc0bc19fSjoerg * Open Tx and Rx USB bulk pipes.
2017fc0bc19fSjoerg */
2018fc0bc19fSjoerg error = usbd_open_pipe(sc->sc_iface, sc->sc_tx_no, USBD_EXCLUSIVE_USE,
2019fc0bc19fSjoerg &sc->sc_tx_pipeh);
2020fc0bc19fSjoerg if (error != 0) {
2021fc0bc19fSjoerg printf("%s: could not open Tx pipe: %s\n",
202268c8418cSdyoung device_xname(sc->sc_dev), usbd_errstr(error));
2023fc0bc19fSjoerg goto fail;
2024fc0bc19fSjoerg }
2025fc0bc19fSjoerg
2026fc0bc19fSjoerg error = usbd_open_pipe(sc->sc_iface, sc->sc_rx_no, USBD_EXCLUSIVE_USE,
2027fc0bc19fSjoerg &sc->sc_rx_pipeh);
2028fc0bc19fSjoerg if (error != 0) {
2029fc0bc19fSjoerg printf("%s: could not open Rx pipe: %s\n",
203068c8418cSdyoung device_xname(sc->sc_dev), usbd_errstr(error));
2031fc0bc19fSjoerg goto fail;
2032fc0bc19fSjoerg }
2033fc0bc19fSjoerg
2034fc0bc19fSjoerg /*
2035fc0bc19fSjoerg * Allocate Tx and Rx xfer queues.
2036fc0bc19fSjoerg */
2037fc0bc19fSjoerg error = rum_alloc_tx_list(sc);
2038fc0bc19fSjoerg if (error != 0) {
2039fc0bc19fSjoerg printf("%s: could not allocate Tx list\n",
204068c8418cSdyoung device_xname(sc->sc_dev));
2041fc0bc19fSjoerg goto fail;
2042fc0bc19fSjoerg }
2043fc0bc19fSjoerg
2044fc0bc19fSjoerg error = rum_alloc_rx_list(sc);
2045fc0bc19fSjoerg if (error != 0) {
2046fc0bc19fSjoerg printf("%s: could not allocate Rx list\n",
204768c8418cSdyoung device_xname(sc->sc_dev));
2048fc0bc19fSjoerg goto fail;
2049fc0bc19fSjoerg }
2050fc0bc19fSjoerg
2051fc0bc19fSjoerg /*
2052fc0bc19fSjoerg * Start up the receive pipe.
2053fc0bc19fSjoerg */
20543bf7c476Skiyohara for (i = 0; i < RUM_RX_LIST_COUNT; i++) {
20554e8e6643Sskrll struct rum_rx_data *data;
20564e8e6643Sskrll
2057fc0bc19fSjoerg data = &sc->rx_data[i];
2058fc0bc19fSjoerg
20594e8e6643Sskrll usbd_setup_xfer(data->xfer, data, data->buf, MCLBYTES,
20604e8e6643Sskrll USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, rum_rxeof);
20613bf7c476Skiyohara error = usbd_transfer(data->xfer);
20623bf7c476Skiyohara if (error != USBD_NORMAL_COMPLETION &&
20633bf7c476Skiyohara error != USBD_IN_PROGRESS) {
20643bf7c476Skiyohara printf("%s: could not queue Rx transfer\n",
206568c8418cSdyoung device_xname(sc->sc_dev));
20663bf7c476Skiyohara goto fail;
20673bf7c476Skiyohara }
2068fc0bc19fSjoerg }
2069fc0bc19fSjoerg
2070fc0bc19fSjoerg /* update Rx filter */
2071fc0bc19fSjoerg tmp = rum_read(sc, RT2573_TXRX_CSR0) & 0xffff;
2072fc0bc19fSjoerg
2073fc0bc19fSjoerg tmp |= RT2573_DROP_PHY_ERROR | RT2573_DROP_CRC_ERROR;
2074fc0bc19fSjoerg if (ic->ic_opmode != IEEE80211_M_MONITOR) {
2075fc0bc19fSjoerg tmp |= RT2573_DROP_CTL | RT2573_DROP_VER_ERROR |
2076fc0bc19fSjoerg RT2573_DROP_ACKCTS;
2077fc0bc19fSjoerg if (ic->ic_opmode != IEEE80211_M_HOSTAP)
2078fc0bc19fSjoerg tmp |= RT2573_DROP_TODS;
2079fc0bc19fSjoerg if (!(ifp->if_flags & IFF_PROMISC))
2080fc0bc19fSjoerg tmp |= RT2573_DROP_NOT_TO_ME;
2081fc0bc19fSjoerg }
2082fc0bc19fSjoerg rum_write(sc, RT2573_TXRX_CSR0, tmp);
2083fc0bc19fSjoerg
2084fc0bc19fSjoerg ifp->if_flags &= ~IFF_OACTIVE;
2085fc0bc19fSjoerg ifp->if_flags |= IFF_RUNNING;
2086fc0bc19fSjoerg
2087fc0bc19fSjoerg if (ic->ic_opmode == IEEE80211_M_MONITOR)
2088fc0bc19fSjoerg ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
2089fc0bc19fSjoerg else
2090fc0bc19fSjoerg ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2091fc0bc19fSjoerg
2092fc0bc19fSjoerg return 0;
2093fc0bc19fSjoerg
2094fc0bc19fSjoerg fail: rum_stop(ifp, 1);
2095fc0bc19fSjoerg return error;
2096fc0bc19fSjoerg }
2097fc0bc19fSjoerg
209887931599Sjmcneill static void
rum_stop(struct ifnet * ifp,int disable)2099fc0bc19fSjoerg rum_stop(struct ifnet *ifp, int disable)
2100fc0bc19fSjoerg {
2101fc0bc19fSjoerg struct rum_softc *sc = ifp->if_softc;
2102fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
2103fc0bc19fSjoerg uint32_t tmp;
2104fc0bc19fSjoerg
2105fc0bc19fSjoerg ieee80211_new_state(ic, IEEE80211_S_INIT, -1); /* free all nodes */
2106fc0bc19fSjoerg
2107fc0bc19fSjoerg sc->sc_tx_timer = 0;
2108fc0bc19fSjoerg ifp->if_timer = 0;
2109fc0bc19fSjoerg ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
2110fc0bc19fSjoerg
2111fc0bc19fSjoerg /* disable Rx */
2112fc0bc19fSjoerg tmp = rum_read(sc, RT2573_TXRX_CSR0);
2113fc0bc19fSjoerg rum_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX);
2114fc0bc19fSjoerg
2115fc0bc19fSjoerg /* reset ASIC */
2116fc0bc19fSjoerg rum_write(sc, RT2573_MAC_CSR1, 3);
2117fc0bc19fSjoerg rum_write(sc, RT2573_MAC_CSR1, 0);
2118fc0bc19fSjoerg
211987931599Sjmcneill if (sc->amrr_xfer != NULL) {
21204e8e6643Sskrll usbd_destroy_xfer(sc->amrr_xfer);
212187931599Sjmcneill sc->amrr_xfer = NULL;
212287931599Sjmcneill }
212387931599Sjmcneill
2124fc0bc19fSjoerg if (sc->sc_rx_pipeh != NULL) {
2125fc0bc19fSjoerg usbd_abort_pipe(sc->sc_rx_pipeh);
21264e8e6643Sskrll }
21274e8e6643Sskrll
21284e8e6643Sskrll if (sc->sc_tx_pipeh != NULL) {
21294e8e6643Sskrll usbd_abort_pipe(sc->sc_tx_pipeh);
21304e8e6643Sskrll }
21314e8e6643Sskrll
21324e8e6643Sskrll rum_free_rx_list(sc);
21334e8e6643Sskrll rum_free_tx_list(sc);
21344e8e6643Sskrll
21354e8e6643Sskrll if (sc->sc_rx_pipeh != NULL) {
2136fc0bc19fSjoerg usbd_close_pipe(sc->sc_rx_pipeh);
2137fc0bc19fSjoerg sc->sc_rx_pipeh = NULL;
2138fc0bc19fSjoerg }
2139fc0bc19fSjoerg
2140fc0bc19fSjoerg if (sc->sc_tx_pipeh != NULL) {
2141fc0bc19fSjoerg usbd_close_pipe(sc->sc_tx_pipeh);
2142fc0bc19fSjoerg sc->sc_tx_pipeh = NULL;
2143fc0bc19fSjoerg }
2144fc0bc19fSjoerg }
2145fc0bc19fSjoerg
214687931599Sjmcneill static int
rum_load_microcode(struct rum_softc * sc,const u_char * ucode,size_t size)2147fc0bc19fSjoerg rum_load_microcode(struct rum_softc *sc, const u_char *ucode, size_t size)
2148fc0bc19fSjoerg {
2149fc0bc19fSjoerg usb_device_request_t req;
2150fc0bc19fSjoerg uint16_t reg = RT2573_MCU_CODE_BASE;
2151fc0bc19fSjoerg usbd_status error;
2152fc0bc19fSjoerg
2153fc0bc19fSjoerg /* copy firmware image into NIC */
2154fc0bc19fSjoerg for (; size >= 4; reg += 4, ucode += 4, size -= 4)
2155fc0bc19fSjoerg rum_write(sc, reg, UGETDW(ucode));
2156fc0bc19fSjoerg
2157fc0bc19fSjoerg req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
2158fc0bc19fSjoerg req.bRequest = RT2573_MCU_CNTL;
2159fc0bc19fSjoerg USETW(req.wValue, RT2573_MCU_RUN);
2160fc0bc19fSjoerg USETW(req.wIndex, 0);
2161fc0bc19fSjoerg USETW(req.wLength, 0);
2162fc0bc19fSjoerg
2163fc0bc19fSjoerg error = usbd_do_request(sc->sc_udev, &req, NULL);
2164fc0bc19fSjoerg if (error != 0) {
2165fc0bc19fSjoerg printf("%s: could not run firmware: %s\n",
216668c8418cSdyoung device_xname(sc->sc_dev), usbd_errstr(error));
2167fc0bc19fSjoerg }
2168fc0bc19fSjoerg return error;
2169fc0bc19fSjoerg }
2170fc0bc19fSjoerg
217187931599Sjmcneill static int
rum_prepare_beacon(struct rum_softc * sc)2172fc0bc19fSjoerg rum_prepare_beacon(struct rum_softc *sc)
2173fc0bc19fSjoerg {
2174fc0bc19fSjoerg struct ieee80211com *ic = &sc->sc_ic;
2175fc0bc19fSjoerg struct rum_tx_desc desc;
2176fc0bc19fSjoerg struct mbuf *m0;
2177fc0bc19fSjoerg int rate;
2178fc0bc19fSjoerg
2179fc0bc19fSjoerg m0 = ieee80211_beacon_alloc(ic, ic->ic_bss, &sc->sc_bo);
2180fc0bc19fSjoerg if (m0 == NULL) {
21813624455eScube aprint_error_dev(sc->sc_dev,
21823624455eScube "could not allocate beacon frame\n");
2183fc0bc19fSjoerg return ENOBUFS;
2184fc0bc19fSjoerg }
2185fc0bc19fSjoerg
2186fc0bc19fSjoerg /* send beacons at the lowest available rate */
2187fc0bc19fSjoerg rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2;
2188fc0bc19fSjoerg
2189fc0bc19fSjoerg rum_setup_tx_desc(sc, &desc, RT2573_TX_TIMESTAMP, RT2573_TX_HWSEQ,
2190fc0bc19fSjoerg m0->m_pkthdr.len, rate);
2191fc0bc19fSjoerg
2192fc0bc19fSjoerg /* copy the first 24 bytes of Tx descriptor into NIC memory */
2193fc0bc19fSjoerg rum_write_multi(sc, RT2573_HW_BEACON_BASE0, (uint8_t *)&desc, 24);
2194fc0bc19fSjoerg
2195fc0bc19fSjoerg /* copy beacon header and payload into NIC memory */
2196fc0bc19fSjoerg rum_write_multi(sc, RT2573_HW_BEACON_BASE0 + 24, mtod(m0, uint8_t *),
2197fc0bc19fSjoerg m0->m_pkthdr.len);
2198fc0bc19fSjoerg
2199fc0bc19fSjoerg m_freem(m0);
2200fc0bc19fSjoerg
2201fc0bc19fSjoerg return 0;
2202fc0bc19fSjoerg }
2203fc0bc19fSjoerg
220487931599Sjmcneill static void
rum_newassoc(struct ieee80211_node * ni,int isnew)22053bf7c476Skiyohara rum_newassoc(struct ieee80211_node *ni, int isnew)
22063bf7c476Skiyohara {
22073bf7c476Skiyohara /* start with lowest Tx rate */
22083bf7c476Skiyohara ni->ni_txrate = 0;
22093bf7c476Skiyohara }
22103bf7c476Skiyohara
221187931599Sjmcneill static void
rum_amrr_start(struct rum_softc * sc,struct ieee80211_node * ni)2212fc0bc19fSjoerg rum_amrr_start(struct rum_softc *sc, struct ieee80211_node *ni)
2213fc0bc19fSjoerg {
2214fc0bc19fSjoerg int i;
2215fc0bc19fSjoerg
2216fc0bc19fSjoerg /* clear statistic registers (STA_CSR0 to STA_CSR5) */
22174e8e6643Sskrll rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof(sc->sta));
2218fc0bc19fSjoerg
2219fc0bc19fSjoerg ieee80211_amrr_node_init(&sc->amrr, &sc->amn);
2220fc0bc19fSjoerg
2221fc0bc19fSjoerg /* set rate to some reasonable initial value */
2222fc0bc19fSjoerg for (i = ni->ni_rates.rs_nrates - 1;
2223fc0bc19fSjoerg i > 0 && (ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL) > 72;
2224fc0bc19fSjoerg i--);
2225fc0bc19fSjoerg ni->ni_txrate = i;
2226fc0bc19fSjoerg
222768c8418cSdyoung callout_reset(&sc->sc_amrr_ch, hz, rum_amrr_timeout, sc);
2228fc0bc19fSjoerg }
2229fc0bc19fSjoerg
223087931599Sjmcneill static void
rum_amrr_timeout(void * arg)2231fc0bc19fSjoerg rum_amrr_timeout(void *arg)
2232fc0bc19fSjoerg {
2233fc0bc19fSjoerg struct rum_softc *sc = arg;
2234fc0bc19fSjoerg usb_device_request_t req;
2235fc0bc19fSjoerg
2236fc0bc19fSjoerg /*
2237fc0bc19fSjoerg * Asynchronously read statistic registers (cleared by read).
2238fc0bc19fSjoerg */
2239fc0bc19fSjoerg req.bmRequestType = UT_READ_VENDOR_DEVICE;
2240fc0bc19fSjoerg req.bRequest = RT2573_READ_MULTI_MAC;
2241fc0bc19fSjoerg USETW(req.wValue, 0);
2242fc0bc19fSjoerg USETW(req.wIndex, RT2573_STA_CSR0);
22434e8e6643Sskrll USETW(req.wLength, sizeof(sc->sta));
2244fc0bc19fSjoerg
2245fc0bc19fSjoerg usbd_setup_default_xfer(sc->amrr_xfer, sc->sc_udev, sc,
22464e8e6643Sskrll USBD_DEFAULT_TIMEOUT, &req, sc->sta, sizeof(sc->sta), 0,
2247fc0bc19fSjoerg rum_amrr_update);
2248fc0bc19fSjoerg (void)usbd_transfer(sc->amrr_xfer);
2249fc0bc19fSjoerg }
2250fc0bc19fSjoerg
225187931599Sjmcneill static void
rum_amrr_update(struct usbd_xfer * xfer,void * priv,usbd_status status)22524e8e6643Sskrll rum_amrr_update(struct usbd_xfer *xfer, void *priv,
2253fc0bc19fSjoerg usbd_status status)
2254fc0bc19fSjoerg {
2255fc0bc19fSjoerg struct rum_softc *sc = (struct rum_softc *)priv;
2256fc0bc19fSjoerg struct ifnet *ifp = sc->sc_ic.ic_ifp;
2257fc0bc19fSjoerg
2258fc0bc19fSjoerg if (status != USBD_NORMAL_COMPLETION) {
2259fc0bc19fSjoerg printf("%s: could not retrieve Tx statistics - cancelling "
226068c8418cSdyoung "automatic rate control\n", device_xname(sc->sc_dev));
2261fc0bc19fSjoerg return;
2262fc0bc19fSjoerg }
2263fc0bc19fSjoerg
2264fc0bc19fSjoerg /* count TX retry-fail as Tx errors */
2265cdaa0e91Sthorpej if_statadd(ifp, if_oerrors, le32toh(sc->sta[5]) >> 16);
2266fc0bc19fSjoerg
2267fc0bc19fSjoerg sc->amn.amn_retrycnt =
2268fc0bc19fSjoerg (le32toh(sc->sta[4]) >> 16) + /* TX one-retry ok count */
2269fc0bc19fSjoerg (le32toh(sc->sta[5]) & 0xffff) + /* TX more-retry ok count */
2270fc0bc19fSjoerg (le32toh(sc->sta[5]) >> 16); /* TX retry-fail count */
2271fc0bc19fSjoerg
2272fc0bc19fSjoerg sc->amn.amn_txcnt =
2273fc0bc19fSjoerg sc->amn.amn_retrycnt +
2274fc0bc19fSjoerg (le32toh(sc->sta[4]) & 0xffff); /* TX no-retry ok count */
2275fc0bc19fSjoerg
2276fc0bc19fSjoerg ieee80211_amrr_choose(&sc->amrr, sc->sc_ic.ic_bss, &sc->amn);
2277fc0bc19fSjoerg
227868c8418cSdyoung callout_reset(&sc->sc_amrr_ch, hz, rum_amrr_timeout, sc);
2279fc0bc19fSjoerg }
2280fc0bc19fSjoerg
228187931599Sjmcneill static int
rum_activate(device_t self,enum devact act)228268c8418cSdyoung rum_activate(device_t self, enum devact act)
2283fc0bc19fSjoerg {
2284fc0bc19fSjoerg switch (act) {
2285fc0bc19fSjoerg case DVACT_DEACTIVATE:
2286fc0bc19fSjoerg /*if_deactivate(&sc->sc_ic.ic_if);*/
2287fc0bc19fSjoerg return 0;
2288110a4ba3Sdyoung default:
228987931599Sjmcneill return 0;
2290110a4ba3Sdyoung }
2291fc0bc19fSjoerg }
229275c5b198Spgoyette
229360d3fae6Schristos MODULE(MODULE_CLASS_DRIVER, if_rum, NULL);
229475c5b198Spgoyette
229575c5b198Spgoyette #ifdef _MODULE
229675c5b198Spgoyette #include "ioconf.c"
229775c5b198Spgoyette #endif
229875c5b198Spgoyette
229975c5b198Spgoyette static int
if_rum_modcmd(modcmd_t cmd,void * aux)230075c5b198Spgoyette if_rum_modcmd(modcmd_t cmd, void *aux)
230175c5b198Spgoyette {
230275c5b198Spgoyette int error = 0;
230375c5b198Spgoyette
230475c5b198Spgoyette switch (cmd) {
230575c5b198Spgoyette case MODULE_CMD_INIT:
230675c5b198Spgoyette #ifdef _MODULE
2307a4ebf89bSpgoyette error = config_init_component(cfdriver_ioconf_rum,
2308a4ebf89bSpgoyette cfattach_ioconf_rum, cfdata_ioconf_rum);
230975c5b198Spgoyette #endif
231075c5b198Spgoyette return error;
231175c5b198Spgoyette case MODULE_CMD_FINI:
231275c5b198Spgoyette #ifdef _MODULE
2313a4ebf89bSpgoyette error = config_fini_component(cfdriver_ioconf_rum,
2314a4ebf89bSpgoyette cfattach_ioconf_rum, cfdata_ioconf_rum);
231575c5b198Spgoyette #endif
231675c5b198Spgoyette return error;
231775c5b198Spgoyette default:
231875c5b198Spgoyette return ENOTTY;
231975c5b198Spgoyette }
232075c5b198Spgoyette }
2321