187c96ac5SQuaker Fang /* 2*0dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 387c96ac5SQuaker Fang * Use is subject to license terms. 487c96ac5SQuaker Fang */ 587c96ac5SQuaker Fang 687c96ac5SQuaker Fang /* 787c96ac5SQuaker Fang * Copyright (c) 2005-2007 Damien Bergamini <damien.bergamini@free.fr> 887c96ac5SQuaker Fang * Copyright (c) 2006 Niall O'Higgins <niallo@openbsd.org> 987c96ac5SQuaker Fang * 1087c96ac5SQuaker Fang * Permission to use, copy, modify, and distribute this software for any 1187c96ac5SQuaker Fang * purpose with or without fee is hereby granted, provided that the above 1287c96ac5SQuaker Fang * copyright notice and this permission notice appear in all copies. 1387c96ac5SQuaker Fang * 1487c96ac5SQuaker Fang * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1587c96ac5SQuaker Fang * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1687c96ac5SQuaker Fang * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1787c96ac5SQuaker Fang * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1887c96ac5SQuaker Fang * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1987c96ac5SQuaker Fang * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 2087c96ac5SQuaker Fang * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2187c96ac5SQuaker Fang */ 2287c96ac5SQuaker Fang 2387c96ac5SQuaker Fang /* 2487c96ac5SQuaker Fang * Ralink Technology RT2501USB/RT2601USB chipset driver 2587c96ac5SQuaker Fang * http://www.ralinktech.com.tw/ 2687c96ac5SQuaker Fang */ 2787c96ac5SQuaker Fang #include <sys/types.h> 2887c96ac5SQuaker Fang #include <sys/cmn_err.h> 2987c96ac5SQuaker Fang #include <sys/strsubr.h> 3087c96ac5SQuaker Fang #include <sys/modctl.h> 3187c96ac5SQuaker Fang #include <sys/devops.h> 32da14cebeSEric Cheng #include <sys/mac_provider.h> 3387c96ac5SQuaker Fang #include <sys/mac_wifi.h> 3487c96ac5SQuaker Fang #include <sys/net80211.h> 35*0dc2366fSVenugopal Iyer #include <sys/byteorder.h> 3687c96ac5SQuaker Fang 3787c96ac5SQuaker Fang #define USBDRV_MAJOR_VER 2 3887c96ac5SQuaker Fang #define USBDRV_MINOR_VER 0 3987c96ac5SQuaker Fang #include <sys/usb/usba.h> 401a932f2eSQuaker Fang #include <sys/usb/usba/usba_types.h> 4187c96ac5SQuaker Fang 4287c96ac5SQuaker Fang #include "rum_reg.h" 4387c96ac5SQuaker Fang #include "rum_var.h" 4487c96ac5SQuaker Fang #include "rt2573_ucode.h" 4587c96ac5SQuaker Fang 4687c96ac5SQuaker Fang static void *rum_soft_state_p = NULL; 4787c96ac5SQuaker Fang 4887c96ac5SQuaker Fang #define RAL_TXBUF_SIZE (IEEE80211_MAX_LEN) 4987c96ac5SQuaker Fang #define RAL_RXBUF_SIZE (IEEE80211_MAX_LEN) 5087c96ac5SQuaker Fang 5187c96ac5SQuaker Fang /* quickly determine if a given rate is CCK or OFDM */ 5287c96ac5SQuaker Fang #define RUM_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22) 5387c96ac5SQuaker Fang #define RUM_ACK_SIZE 14 /* 10 + 4(FCS) */ 5487c96ac5SQuaker Fang #define RUM_CTS_SIZE 14 /* 10 + 4(FCS) */ 5587c96ac5SQuaker Fang 5687c96ac5SQuaker Fang #define RUM_N(a) (sizeof (a) / sizeof ((a)[0])) 5787c96ac5SQuaker Fang 5887c96ac5SQuaker Fang /* 5987c96ac5SQuaker Fang * Supported rates for 802.11a/b/g modes (in 500Kbps unit). 6087c96ac5SQuaker Fang */ 6187c96ac5SQuaker Fang static const struct ieee80211_rateset rum_rateset_11a = 6287c96ac5SQuaker Fang { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } }; 6387c96ac5SQuaker Fang 6487c96ac5SQuaker Fang static const struct ieee80211_rateset rum_rateset_11b = 6587c96ac5SQuaker Fang { 4, { 2, 4, 11, 22 } }; 6687c96ac5SQuaker Fang 6787c96ac5SQuaker Fang static const struct ieee80211_rateset rum_rateset_11g = 6887c96ac5SQuaker Fang { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; 6987c96ac5SQuaker Fang 7087c96ac5SQuaker Fang static const struct { 7187c96ac5SQuaker Fang uint32_t reg; 7287c96ac5SQuaker Fang uint32_t val; 7387c96ac5SQuaker Fang } rum_def_mac[] = { 7487c96ac5SQuaker Fang { RT2573_TXRX_CSR0, 0x025fb032 }, 7587c96ac5SQuaker Fang { RT2573_TXRX_CSR1, 0x9eaa9eaf }, 7687c96ac5SQuaker Fang { RT2573_TXRX_CSR2, 0x8a8b8c8d }, 7787c96ac5SQuaker Fang { RT2573_TXRX_CSR3, 0x00858687 }, 7887c96ac5SQuaker Fang { RT2573_TXRX_CSR7, 0x2e31353b }, 7987c96ac5SQuaker Fang { RT2573_TXRX_CSR8, 0x2a2a2a2c }, 8087c96ac5SQuaker Fang { RT2573_TXRX_CSR15, 0x0000000f }, 8187c96ac5SQuaker Fang { RT2573_MAC_CSR6, 0x00000fff }, 8287c96ac5SQuaker Fang { RT2573_MAC_CSR8, 0x016c030a }, 8387c96ac5SQuaker Fang { RT2573_MAC_CSR10, 0x00000718 }, 8487c96ac5SQuaker Fang { RT2573_MAC_CSR12, 0x00000004 }, 8587c96ac5SQuaker Fang { RT2573_MAC_CSR13, 0x00007f00 }, 8687c96ac5SQuaker Fang { RT2573_SEC_CSR0, 0x00000000 }, 8787c96ac5SQuaker Fang { RT2573_SEC_CSR1, 0x00000000 }, 8887c96ac5SQuaker Fang { RT2573_SEC_CSR5, 0x00000000 }, 8987c96ac5SQuaker Fang { RT2573_PHY_CSR1, 0x000023b0 }, 9087c96ac5SQuaker Fang { RT2573_PHY_CSR5, 0x00040a06 }, 9187c96ac5SQuaker Fang { RT2573_PHY_CSR6, 0x00080606 }, 9287c96ac5SQuaker Fang { RT2573_PHY_CSR7, 0x00000408 }, 9387c96ac5SQuaker Fang { RT2573_AIFSN_CSR, 0x00002273 }, 9487c96ac5SQuaker Fang { RT2573_CWMIN_CSR, 0x00002344 }, 9587c96ac5SQuaker Fang { RT2573_CWMAX_CSR, 0x000034aa } 9687c96ac5SQuaker Fang }; 9787c96ac5SQuaker Fang 9887c96ac5SQuaker Fang static const struct { 9987c96ac5SQuaker Fang uint8_t reg; 10087c96ac5SQuaker Fang uint8_t val; 10187c96ac5SQuaker Fang } rum_def_bbp[] = { 10287c96ac5SQuaker Fang { 3, 0x80 }, 10387c96ac5SQuaker Fang { 15, 0x30 }, 10487c96ac5SQuaker Fang { 17, 0x20 }, 10587c96ac5SQuaker Fang { 21, 0xc8 }, 10687c96ac5SQuaker Fang { 22, 0x38 }, 10787c96ac5SQuaker Fang { 23, 0x06 }, 10887c96ac5SQuaker Fang { 24, 0xfe }, 10987c96ac5SQuaker Fang { 25, 0x0a }, 11087c96ac5SQuaker Fang { 26, 0x0d }, 11187c96ac5SQuaker Fang { 32, 0x0b }, 11287c96ac5SQuaker Fang { 34, 0x12 }, 11387c96ac5SQuaker Fang { 37, 0x07 }, 11487c96ac5SQuaker Fang { 39, 0xf8 }, 11587c96ac5SQuaker Fang { 41, 0x60 }, 11687c96ac5SQuaker Fang { 53, 0x10 }, 11787c96ac5SQuaker Fang { 54, 0x18 }, 11887c96ac5SQuaker Fang { 60, 0x10 }, 11987c96ac5SQuaker Fang { 61, 0x04 }, 12087c96ac5SQuaker Fang { 62, 0x04 }, 12187c96ac5SQuaker Fang { 75, 0xfe }, 12287c96ac5SQuaker Fang { 86, 0xfe }, 12387c96ac5SQuaker Fang { 88, 0xfe }, 12487c96ac5SQuaker Fang { 90, 0x0f }, 12587c96ac5SQuaker Fang { 99, 0x00 }, 12687c96ac5SQuaker Fang { 102, 0x16 }, 12787c96ac5SQuaker Fang { 107, 0x04 } 12887c96ac5SQuaker Fang }; 12987c96ac5SQuaker Fang 13087c96ac5SQuaker Fang static const struct rfprog { 13187c96ac5SQuaker Fang uint8_t chan; 13287c96ac5SQuaker Fang uint32_t r1, r2, r3, r4; 13387c96ac5SQuaker Fang } rum_rf5226[] = { 13487c96ac5SQuaker Fang { 1, 0x00b03, 0x001e1, 0x1a014, 0x30282 }, 13587c96ac5SQuaker Fang { 2, 0x00b03, 0x001e1, 0x1a014, 0x30287 }, 13687c96ac5SQuaker Fang { 3, 0x00b03, 0x001e2, 0x1a014, 0x30282 }, 13787c96ac5SQuaker Fang { 4, 0x00b03, 0x001e2, 0x1a014, 0x30287 }, 13887c96ac5SQuaker Fang { 5, 0x00b03, 0x001e3, 0x1a014, 0x30282 }, 13987c96ac5SQuaker Fang { 6, 0x00b03, 0x001e3, 0x1a014, 0x30287 }, 14087c96ac5SQuaker Fang { 7, 0x00b03, 0x001e4, 0x1a014, 0x30282 }, 14187c96ac5SQuaker Fang { 8, 0x00b03, 0x001e4, 0x1a014, 0x30287 }, 14287c96ac5SQuaker Fang { 9, 0x00b03, 0x001e5, 0x1a014, 0x30282 }, 14387c96ac5SQuaker Fang { 10, 0x00b03, 0x001e5, 0x1a014, 0x30287 }, 14487c96ac5SQuaker Fang { 11, 0x00b03, 0x001e6, 0x1a014, 0x30282 }, 14587c96ac5SQuaker Fang { 12, 0x00b03, 0x001e6, 0x1a014, 0x30287 }, 14687c96ac5SQuaker Fang { 13, 0x00b03, 0x001e7, 0x1a014, 0x30282 }, 14787c96ac5SQuaker Fang { 14, 0x00b03, 0x001e8, 0x1a014, 0x30284 }, 14887c96ac5SQuaker Fang 14987c96ac5SQuaker Fang { 34, 0x00b03, 0x20266, 0x36014, 0x30282 }, 15087c96ac5SQuaker Fang { 38, 0x00b03, 0x20267, 0x36014, 0x30284 }, 15187c96ac5SQuaker Fang { 42, 0x00b03, 0x20268, 0x36014, 0x30286 }, 15287c96ac5SQuaker Fang { 46, 0x00b03, 0x20269, 0x36014, 0x30288 }, 15387c96ac5SQuaker Fang 15487c96ac5SQuaker Fang { 36, 0x00b03, 0x00266, 0x26014, 0x30288 }, 15587c96ac5SQuaker Fang { 40, 0x00b03, 0x00268, 0x26014, 0x30280 }, 15687c96ac5SQuaker Fang { 44, 0x00b03, 0x00269, 0x26014, 0x30282 }, 15787c96ac5SQuaker Fang { 48, 0x00b03, 0x0026a, 0x26014, 0x30284 }, 15887c96ac5SQuaker Fang { 52, 0x00b03, 0x0026b, 0x26014, 0x30286 }, 15987c96ac5SQuaker Fang { 56, 0x00b03, 0x0026c, 0x26014, 0x30288 }, 16087c96ac5SQuaker Fang { 60, 0x00b03, 0x0026e, 0x26014, 0x30280 }, 16187c96ac5SQuaker Fang { 64, 0x00b03, 0x0026f, 0x26014, 0x30282 }, 16287c96ac5SQuaker Fang 16387c96ac5SQuaker Fang { 100, 0x00b03, 0x0028a, 0x2e014, 0x30280 }, 16487c96ac5SQuaker Fang { 104, 0x00b03, 0x0028b, 0x2e014, 0x30282 }, 16587c96ac5SQuaker Fang { 108, 0x00b03, 0x0028c, 0x2e014, 0x30284 }, 16687c96ac5SQuaker Fang { 112, 0x00b03, 0x0028d, 0x2e014, 0x30286 }, 16787c96ac5SQuaker Fang { 116, 0x00b03, 0x0028e, 0x2e014, 0x30288 }, 16887c96ac5SQuaker Fang { 120, 0x00b03, 0x002a0, 0x2e014, 0x30280 }, 16987c96ac5SQuaker Fang { 124, 0x00b03, 0x002a1, 0x2e014, 0x30282 }, 17087c96ac5SQuaker Fang { 128, 0x00b03, 0x002a2, 0x2e014, 0x30284 }, 17187c96ac5SQuaker Fang { 132, 0x00b03, 0x002a3, 0x2e014, 0x30286 }, 17287c96ac5SQuaker Fang { 136, 0x00b03, 0x002a4, 0x2e014, 0x30288 }, 17387c96ac5SQuaker Fang { 140, 0x00b03, 0x002a6, 0x2e014, 0x30280 }, 17487c96ac5SQuaker Fang 17587c96ac5SQuaker Fang { 149, 0x00b03, 0x002a8, 0x2e014, 0x30287 }, 17687c96ac5SQuaker Fang { 153, 0x00b03, 0x002a9, 0x2e014, 0x30289 }, 17787c96ac5SQuaker Fang { 157, 0x00b03, 0x002ab, 0x2e014, 0x30281 }, 17887c96ac5SQuaker Fang { 161, 0x00b03, 0x002ac, 0x2e014, 0x30283 }, 17987c96ac5SQuaker Fang { 165, 0x00b03, 0x002ad, 0x2e014, 0x30285 } 18087c96ac5SQuaker Fang }, rum_rf5225[] = { 18187c96ac5SQuaker Fang { 1, 0x00b33, 0x011e1, 0x1a014, 0x30282 }, 18287c96ac5SQuaker Fang { 2, 0x00b33, 0x011e1, 0x1a014, 0x30287 }, 18387c96ac5SQuaker Fang { 3, 0x00b33, 0x011e2, 0x1a014, 0x30282 }, 18487c96ac5SQuaker Fang { 4, 0x00b33, 0x011e2, 0x1a014, 0x30287 }, 18587c96ac5SQuaker Fang { 5, 0x00b33, 0x011e3, 0x1a014, 0x30282 }, 18687c96ac5SQuaker Fang { 6, 0x00b33, 0x011e3, 0x1a014, 0x30287 }, 18787c96ac5SQuaker Fang { 7, 0x00b33, 0x011e4, 0x1a014, 0x30282 }, 18887c96ac5SQuaker Fang { 8, 0x00b33, 0x011e4, 0x1a014, 0x30287 }, 18987c96ac5SQuaker Fang { 9, 0x00b33, 0x011e5, 0x1a014, 0x30282 }, 19087c96ac5SQuaker Fang { 10, 0x00b33, 0x011e5, 0x1a014, 0x30287 }, 19187c96ac5SQuaker Fang { 11, 0x00b33, 0x011e6, 0x1a014, 0x30282 }, 19287c96ac5SQuaker Fang { 12, 0x00b33, 0x011e6, 0x1a014, 0x30287 }, 19387c96ac5SQuaker Fang { 13, 0x00b33, 0x011e7, 0x1a014, 0x30282 }, 19487c96ac5SQuaker Fang { 14, 0x00b33, 0x011e8, 0x1a014, 0x30284 }, 19587c96ac5SQuaker Fang 19687c96ac5SQuaker Fang { 34, 0x00b33, 0x01266, 0x26014, 0x30282 }, 19787c96ac5SQuaker Fang { 38, 0x00b33, 0x01267, 0x26014, 0x30284 }, 19887c96ac5SQuaker Fang { 42, 0x00b33, 0x01268, 0x26014, 0x30286 }, 19987c96ac5SQuaker Fang { 46, 0x00b33, 0x01269, 0x26014, 0x30288 }, 20087c96ac5SQuaker Fang 20187c96ac5SQuaker Fang { 36, 0x00b33, 0x01266, 0x26014, 0x30288 }, 20287c96ac5SQuaker Fang { 40, 0x00b33, 0x01268, 0x26014, 0x30280 }, 20387c96ac5SQuaker Fang { 44, 0x00b33, 0x01269, 0x26014, 0x30282 }, 20487c96ac5SQuaker Fang { 48, 0x00b33, 0x0126a, 0x26014, 0x30284 }, 20587c96ac5SQuaker Fang { 52, 0x00b33, 0x0126b, 0x26014, 0x30286 }, 20687c96ac5SQuaker Fang { 56, 0x00b33, 0x0126c, 0x26014, 0x30288 }, 20787c96ac5SQuaker Fang { 60, 0x00b33, 0x0126e, 0x26014, 0x30280 }, 20887c96ac5SQuaker Fang { 64, 0x00b33, 0x0126f, 0x26014, 0x30282 }, 20987c96ac5SQuaker Fang 21087c96ac5SQuaker Fang { 100, 0x00b33, 0x0128a, 0x2e014, 0x30280 }, 21187c96ac5SQuaker Fang { 104, 0x00b33, 0x0128b, 0x2e014, 0x30282 }, 21287c96ac5SQuaker Fang { 108, 0x00b33, 0x0128c, 0x2e014, 0x30284 }, 21387c96ac5SQuaker Fang { 112, 0x00b33, 0x0128d, 0x2e014, 0x30286 }, 21487c96ac5SQuaker Fang { 116, 0x00b33, 0x0128e, 0x2e014, 0x30288 }, 21587c96ac5SQuaker Fang { 120, 0x00b33, 0x012a0, 0x2e014, 0x30280 }, 21687c96ac5SQuaker Fang { 124, 0x00b33, 0x012a1, 0x2e014, 0x30282 }, 21787c96ac5SQuaker Fang { 128, 0x00b33, 0x012a2, 0x2e014, 0x30284 }, 21887c96ac5SQuaker Fang { 132, 0x00b33, 0x012a3, 0x2e014, 0x30286 }, 21987c96ac5SQuaker Fang { 136, 0x00b33, 0x012a4, 0x2e014, 0x30288 }, 22087c96ac5SQuaker Fang { 140, 0x00b33, 0x012a6, 0x2e014, 0x30280 }, 22187c96ac5SQuaker Fang 22287c96ac5SQuaker Fang { 149, 0x00b33, 0x012a8, 0x2e014, 0x30287 }, 22387c96ac5SQuaker Fang { 153, 0x00b33, 0x012a9, 0x2e014, 0x30289 }, 22487c96ac5SQuaker Fang { 157, 0x00b33, 0x012ab, 0x2e014, 0x30281 }, 22587c96ac5SQuaker Fang { 161, 0x00b33, 0x012ac, 0x2e014, 0x30283 }, 22687c96ac5SQuaker Fang { 165, 0x00b33, 0x012ad, 0x2e014, 0x30285 } 22787c96ac5SQuaker Fang }; 22887c96ac5SQuaker Fang 22987c96ac5SQuaker Fang /* 23087c96ac5SQuaker Fang * device operations 23187c96ac5SQuaker Fang */ 23287c96ac5SQuaker Fang static int rum_attach(dev_info_t *, ddi_attach_cmd_t); 23387c96ac5SQuaker Fang static int rum_detach(dev_info_t *, ddi_detach_cmd_t); 23487c96ac5SQuaker Fang 23587c96ac5SQuaker Fang /* 23687c96ac5SQuaker Fang * Module Loading Data & Entry Points 23787c96ac5SQuaker Fang */ 23887c96ac5SQuaker Fang DDI_DEFINE_STREAM_OPS(rum_dev_ops, nulldev, nulldev, rum_attach, 23987c96ac5SQuaker Fang rum_detach, nodev, NULL, D_MP, NULL, ddi_quiesce_not_needed); 24087c96ac5SQuaker Fang 24187c96ac5SQuaker Fang static struct modldrv rum_modldrv = { 24287c96ac5SQuaker Fang &mod_driverops, /* Type of module. This one is a driver */ 2431a932f2eSQuaker Fang "rum driver v1.2", /* short description */ 24487c96ac5SQuaker Fang &rum_dev_ops /* driver specific ops */ 24587c96ac5SQuaker Fang }; 24687c96ac5SQuaker Fang 24787c96ac5SQuaker Fang static struct modlinkage modlinkage = { 24887c96ac5SQuaker Fang MODREV_1, 24987c96ac5SQuaker Fang (void *)&rum_modldrv, 25087c96ac5SQuaker Fang NULL 25187c96ac5SQuaker Fang }; 25287c96ac5SQuaker Fang 25387c96ac5SQuaker Fang static int rum_m_stat(void *, uint_t, uint64_t *); 25487c96ac5SQuaker Fang static int rum_m_start(void *); 25587c96ac5SQuaker Fang static void rum_m_stop(void *); 25687c96ac5SQuaker Fang static int rum_m_promisc(void *, boolean_t); 25787c96ac5SQuaker Fang static int rum_m_multicst(void *, boolean_t, const uint8_t *); 25887c96ac5SQuaker Fang static int rum_m_unicst(void *, const uint8_t *); 25987c96ac5SQuaker Fang static mblk_t *rum_m_tx(void *, mblk_t *); 26087c96ac5SQuaker Fang static void rum_m_ioctl(void *, queue_t *, mblk_t *); 26187c96ac5SQuaker Fang static int rum_m_setprop(void *, const char *, mac_prop_id_t, 26287c96ac5SQuaker Fang uint_t, const void *); 26387c96ac5SQuaker Fang static int rum_m_getprop(void *, const char *, mac_prop_id_t, 264*0dc2366fSVenugopal Iyer uint_t, void *); 265*0dc2366fSVenugopal Iyer static void rum_m_propinfo(void *, const char *, mac_prop_id_t, 266*0dc2366fSVenugopal Iyer mac_prop_info_handle_t); 26787c96ac5SQuaker Fang 26887c96ac5SQuaker Fang static mac_callbacks_t rum_m_callbacks = { 269*0dc2366fSVenugopal Iyer MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO, 27087c96ac5SQuaker Fang rum_m_stat, 27187c96ac5SQuaker Fang rum_m_start, 27287c96ac5SQuaker Fang rum_m_stop, 27387c96ac5SQuaker Fang rum_m_promisc, 27487c96ac5SQuaker Fang rum_m_multicst, 27587c96ac5SQuaker Fang rum_m_unicst, 27687c96ac5SQuaker Fang rum_m_tx, 277*0dc2366fSVenugopal Iyer NULL, 27887c96ac5SQuaker Fang rum_m_ioctl, 27987c96ac5SQuaker Fang NULL, /* mc_getcapab */ 28087c96ac5SQuaker Fang NULL, 28187c96ac5SQuaker Fang NULL, 28287c96ac5SQuaker Fang rum_m_setprop, 283*0dc2366fSVenugopal Iyer rum_m_getprop, 284*0dc2366fSVenugopal Iyer rum_m_propinfo 28587c96ac5SQuaker Fang }; 28687c96ac5SQuaker Fang 28787c96ac5SQuaker Fang static void rum_amrr_start(struct rum_softc *, struct ieee80211_node *); 28887c96ac5SQuaker Fang static int rum_tx_trigger(struct rum_softc *, mblk_t *); 28987c96ac5SQuaker Fang static int rum_rx_trigger(struct rum_softc *); 29087c96ac5SQuaker Fang 29187c96ac5SQuaker Fang uint32_t rum_dbg_flags = 0; 29287c96ac5SQuaker Fang 29387c96ac5SQuaker Fang void 29487c96ac5SQuaker Fang ral_debug(uint32_t dbg_flags, const int8_t *fmt, ...) 29587c96ac5SQuaker Fang { 29687c96ac5SQuaker Fang va_list args; 29787c96ac5SQuaker Fang 29887c96ac5SQuaker Fang if (dbg_flags & rum_dbg_flags) { 29987c96ac5SQuaker Fang va_start(args, fmt); 30087c96ac5SQuaker Fang vcmn_err(CE_CONT, fmt, args); 30187c96ac5SQuaker Fang va_end(args); 30287c96ac5SQuaker Fang } 30387c96ac5SQuaker Fang } 30487c96ac5SQuaker Fang 30587c96ac5SQuaker Fang static void 30687c96ac5SQuaker Fang rum_read_multi(struct rum_softc *sc, uint16_t reg, void *buf, int len) 30787c96ac5SQuaker Fang { 30887c96ac5SQuaker Fang usb_ctrl_setup_t req; 30987c96ac5SQuaker Fang usb_cr_t cr; 31087c96ac5SQuaker Fang usb_cb_flags_t cf; 31187c96ac5SQuaker Fang mblk_t *mp; 31287c96ac5SQuaker Fang int err; 31387c96ac5SQuaker Fang 31487c96ac5SQuaker Fang bzero(&req, sizeof (req)); 31587c96ac5SQuaker Fang req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_DEV_TO_HOST; 31687c96ac5SQuaker Fang req.bRequest = RT2573_READ_MULTI_MAC; 31787c96ac5SQuaker Fang req.wValue = 0; 31887c96ac5SQuaker Fang req.wIndex = reg; 31987c96ac5SQuaker Fang req.wLength = (uint16_t)len; 32087c96ac5SQuaker Fang req.attrs = USB_ATTRS_AUTOCLEARING; 32187c96ac5SQuaker Fang 32287c96ac5SQuaker Fang mp = NULL; 32387c96ac5SQuaker Fang err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp, 32487c96ac5SQuaker Fang &cr, &cf, 0); 32587c96ac5SQuaker Fang 32687c96ac5SQuaker Fang if (err != USB_SUCCESS) { 3271a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 32887c96ac5SQuaker Fang "rum_read_multi(): could not read MAC register:" 32987c96ac5SQuaker Fang "cr:%s(%d), cf:(%x)\n", 33087c96ac5SQuaker Fang usb_str_cr(cr), cr, cf); 33187c96ac5SQuaker Fang return; 33287c96ac5SQuaker Fang } 33387c96ac5SQuaker Fang 33487c96ac5SQuaker Fang bcopy(mp->b_rptr, buf, len); 33587c96ac5SQuaker Fang freemsg(mp); 33687c96ac5SQuaker Fang } 33787c96ac5SQuaker Fang 33887c96ac5SQuaker Fang static uint32_t 33987c96ac5SQuaker Fang rum_read(struct rum_softc *sc, uint16_t reg) 34087c96ac5SQuaker Fang { 34187c96ac5SQuaker Fang uint32_t val; 34287c96ac5SQuaker Fang 34387c96ac5SQuaker Fang rum_read_multi(sc, reg, &val, sizeof (val)); 34487c96ac5SQuaker Fang 34587c96ac5SQuaker Fang return (LE_32(val)); 34687c96ac5SQuaker Fang } 34787c96ac5SQuaker Fang 34887c96ac5SQuaker Fang static void 34987c96ac5SQuaker Fang rum_write_multi(struct rum_softc *sc, uint16_t reg, void *buf, size_t len) 35087c96ac5SQuaker Fang { 35187c96ac5SQuaker Fang usb_ctrl_setup_t req; 35287c96ac5SQuaker Fang usb_cr_t cr; 35387c96ac5SQuaker Fang usb_cb_flags_t cf; 35487c96ac5SQuaker Fang mblk_t *mp; 35587c96ac5SQuaker Fang int err; 35687c96ac5SQuaker Fang 35787c96ac5SQuaker Fang bzero(&req, sizeof (req)); 35887c96ac5SQuaker Fang req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_HOST_TO_DEV; 35987c96ac5SQuaker Fang req.bRequest = RT2573_WRITE_MULTI_MAC; 36087c96ac5SQuaker Fang req.wValue = 0; 36187c96ac5SQuaker Fang req.wIndex = reg; 36287c96ac5SQuaker Fang req.wLength = (uint16_t)len; 36387c96ac5SQuaker Fang req.attrs = USB_ATTRS_NONE; 36487c96ac5SQuaker Fang 36587c96ac5SQuaker Fang if ((mp = allocb(len, BPRI_HI)) == NULL) { 3661a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "rum_write_multi(): failed alloc mblk."); 36787c96ac5SQuaker Fang return; 36887c96ac5SQuaker Fang } 36987c96ac5SQuaker Fang 37087c96ac5SQuaker Fang bcopy(buf, mp->b_wptr, len); 37187c96ac5SQuaker Fang mp->b_wptr += len; 37287c96ac5SQuaker Fang 37387c96ac5SQuaker Fang err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp, 37487c96ac5SQuaker Fang &cr, &cf, 0); 37587c96ac5SQuaker Fang 37687c96ac5SQuaker Fang if (err != USB_SUCCESS) { 3771a932f2eSQuaker Fang ral_debug(RAL_DBG_USB, 37887c96ac5SQuaker Fang "rum_write_multi(): could not write MAC register:" 37987c96ac5SQuaker Fang "cr:%s(%d), cf:(%x)\n", 38087c96ac5SQuaker Fang usb_str_cr(cr), cr, cf); 38187c96ac5SQuaker Fang } 38287c96ac5SQuaker Fang 38387c96ac5SQuaker Fang freemsg(mp); 38487c96ac5SQuaker Fang } 38587c96ac5SQuaker Fang 38687c96ac5SQuaker Fang static void 38787c96ac5SQuaker Fang rum_write(struct rum_softc *sc, uint16_t reg, uint32_t val) 38887c96ac5SQuaker Fang { 38987c96ac5SQuaker Fang uint32_t tmp = LE_32(val); 39087c96ac5SQuaker Fang 39187c96ac5SQuaker Fang rum_write_multi(sc, reg, &tmp, sizeof (tmp)); 39287c96ac5SQuaker Fang } 39387c96ac5SQuaker Fang 39487c96ac5SQuaker Fang #define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24)) 39587c96ac5SQuaker Fang 39687c96ac5SQuaker Fang static int 39787c96ac5SQuaker Fang rum_load_microcode(struct rum_softc *sc) 39887c96ac5SQuaker Fang { 39987c96ac5SQuaker Fang usb_ctrl_setup_t req; 40087c96ac5SQuaker Fang usb_cr_t cr; 40187c96ac5SQuaker Fang usb_cb_flags_t cf; 40287c96ac5SQuaker Fang int err; 40387c96ac5SQuaker Fang 40487c96ac5SQuaker Fang const uint8_t *ucode; 40587c96ac5SQuaker Fang int size; 40687c96ac5SQuaker Fang uint16_t reg = RT2573_MCU_CODE_BASE; 40787c96ac5SQuaker Fang 40887c96ac5SQuaker Fang ucode = rt2573_ucode; 40987c96ac5SQuaker Fang size = sizeof (rt2573_ucode); 41087c96ac5SQuaker Fang 41187c96ac5SQuaker Fang /* copy firmware image into NIC */ 41287c96ac5SQuaker Fang for (; size >= 4; reg += 4, ucode += 4, size -= 4) { 41387c96ac5SQuaker Fang rum_write(sc, reg, UGETDW(ucode)); 41487c96ac5SQuaker Fang /* rum_write(sc, reg, *(uint32_t *)(ucode)); */ 41587c96ac5SQuaker Fang } 41687c96ac5SQuaker Fang 41787c96ac5SQuaker Fang bzero(&req, sizeof (req)); 41887c96ac5SQuaker Fang req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_HOST_TO_DEV; 41987c96ac5SQuaker Fang req.bRequest = RT2573_MCU_CNTL; 42087c96ac5SQuaker Fang req.wValue = RT2573_MCU_RUN; 42187c96ac5SQuaker Fang req.wIndex = 0; 42287c96ac5SQuaker Fang req.wLength = 0; 42387c96ac5SQuaker Fang req.attrs = USB_ATTRS_NONE; 42487c96ac5SQuaker Fang 42587c96ac5SQuaker Fang err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, NULL, 42687c96ac5SQuaker Fang &cr, &cf, 0); 42787c96ac5SQuaker Fang 42887c96ac5SQuaker Fang if (err != USB_SUCCESS) { 4291a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 43087c96ac5SQuaker Fang "rum_load_microcode(): could not run firmware: " 43187c96ac5SQuaker Fang "cr:%s(%d), cf:(%x)\n", 43287c96ac5SQuaker Fang usb_str_cr(cr), cr, cf); 43387c96ac5SQuaker Fang } 43487c96ac5SQuaker Fang 4351a932f2eSQuaker Fang ral_debug(RAL_DBG_MSG, 43687c96ac5SQuaker Fang "rum_load_microcode(%d): done\n", sizeof (rt2573_ucode)); 43787c96ac5SQuaker Fang 43887c96ac5SQuaker Fang return (err); 43987c96ac5SQuaker Fang } 44087c96ac5SQuaker Fang 44187c96ac5SQuaker Fang static void 44287c96ac5SQuaker Fang rum_eeprom_read(struct rum_softc *sc, uint16_t addr, void *buf, int len) 44387c96ac5SQuaker Fang { 44487c96ac5SQuaker Fang usb_ctrl_setup_t req; 44587c96ac5SQuaker Fang usb_cr_t cr; 44687c96ac5SQuaker Fang usb_cb_flags_t cf; 44787c96ac5SQuaker Fang mblk_t *mp; 44887c96ac5SQuaker Fang int err; 44987c96ac5SQuaker Fang 45087c96ac5SQuaker Fang bzero(&req, sizeof (req)); 45187c96ac5SQuaker Fang req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_DEV_TO_HOST; 45287c96ac5SQuaker Fang req.bRequest = RT2573_READ_EEPROM; 45387c96ac5SQuaker Fang req.wValue = 0; 45487c96ac5SQuaker Fang req.wIndex = addr; 45587c96ac5SQuaker Fang req.wLength = (uint16_t)len; 45687c96ac5SQuaker Fang 45787c96ac5SQuaker Fang mp = NULL; 45887c96ac5SQuaker Fang err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp, 45987c96ac5SQuaker Fang &cr, &cf, 0); 46087c96ac5SQuaker Fang 46187c96ac5SQuaker Fang if (err != USB_SUCCESS) { 4621a932f2eSQuaker Fang ral_debug(RAL_DBG_USB, 46387c96ac5SQuaker Fang "rum_eeprom_read(): could not read EEPROM:" 46487c96ac5SQuaker Fang "cr:%s(%d), cf:(%x)\n", 46587c96ac5SQuaker Fang usb_str_cr(cr), cr, cf); 46687c96ac5SQuaker Fang return; 46787c96ac5SQuaker Fang } 46887c96ac5SQuaker Fang 46987c96ac5SQuaker Fang bcopy(mp->b_rptr, buf, len); 47087c96ac5SQuaker Fang freemsg(mp); 47187c96ac5SQuaker Fang } 47287c96ac5SQuaker Fang 47387c96ac5SQuaker Fang /* ARGSUSED */ 47487c96ac5SQuaker Fang static void 47587c96ac5SQuaker Fang rum_txeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 47687c96ac5SQuaker Fang { 47787c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)req->bulk_client_private; 47887c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 47987c96ac5SQuaker Fang 4801a932f2eSQuaker Fang ral_debug(RAL_DBG_TX, 48187c96ac5SQuaker Fang "rum_txeof(): cr:%s(%d), flags:0x%x, tx_queued:%d", 48287c96ac5SQuaker Fang usb_str_cr(req->bulk_completion_reason), 48387c96ac5SQuaker Fang req->bulk_completion_reason, 48487c96ac5SQuaker Fang req->bulk_cb_flags, 48587c96ac5SQuaker Fang sc->tx_queued); 48687c96ac5SQuaker Fang 48787c96ac5SQuaker Fang if (req->bulk_completion_reason != USB_CR_OK) 48887c96ac5SQuaker Fang sc->sc_tx_err++; 48987c96ac5SQuaker Fang 49087c96ac5SQuaker Fang mutex_enter(&sc->tx_lock); 49187c96ac5SQuaker Fang 49287c96ac5SQuaker Fang sc->tx_queued--; 49387c96ac5SQuaker Fang sc->sc_tx_timer = 0; 49487c96ac5SQuaker Fang 49587c96ac5SQuaker Fang if (sc->sc_need_sched) { 49687c96ac5SQuaker Fang sc->sc_need_sched = 0; 49787c96ac5SQuaker Fang mac_tx_update(ic->ic_mach); 49887c96ac5SQuaker Fang } 49987c96ac5SQuaker Fang 50087c96ac5SQuaker Fang mutex_exit(&sc->tx_lock); 50187c96ac5SQuaker Fang usb_free_bulk_req(req); 50287c96ac5SQuaker Fang } 50387c96ac5SQuaker Fang 50487c96ac5SQuaker Fang /* ARGSUSED */ 50587c96ac5SQuaker Fang static void 50687c96ac5SQuaker Fang rum_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 50787c96ac5SQuaker Fang { 50887c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)req->bulk_client_private; 50987c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 51087c96ac5SQuaker Fang 51187c96ac5SQuaker Fang struct rum_rx_desc *desc; 51287c96ac5SQuaker Fang struct ieee80211_frame *wh; 51387c96ac5SQuaker Fang struct ieee80211_node *ni; 51487c96ac5SQuaker Fang 51587c96ac5SQuaker Fang mblk_t *m, *mp; 51687c96ac5SQuaker Fang int len, pktlen; 51787c96ac5SQuaker Fang char *rxbuf; 51887c96ac5SQuaker Fang 51987c96ac5SQuaker Fang mp = req->bulk_data; 52087c96ac5SQuaker Fang req->bulk_data = NULL; 52187c96ac5SQuaker Fang 5221a932f2eSQuaker Fang ral_debug(RAL_DBG_RX, 52387c96ac5SQuaker Fang "rum_rxeof(): cr:%s(%d), flags:0x%x, rx_queued:%d", 52487c96ac5SQuaker Fang usb_str_cr(req->bulk_completion_reason), 52587c96ac5SQuaker Fang req->bulk_completion_reason, 52687c96ac5SQuaker Fang req->bulk_cb_flags, 52787c96ac5SQuaker Fang sc->rx_queued); 52887c96ac5SQuaker Fang 52987c96ac5SQuaker Fang if (req->bulk_completion_reason != USB_CR_OK) { 53087c96ac5SQuaker Fang sc->sc_rx_err++; 53187c96ac5SQuaker Fang goto fail; 53287c96ac5SQuaker Fang } 53387c96ac5SQuaker Fang 53487c96ac5SQuaker Fang len = msgdsize(mp); 53587c96ac5SQuaker Fang rxbuf = (char *)mp->b_rptr; 53687c96ac5SQuaker Fang 53787c96ac5SQuaker Fang 53887c96ac5SQuaker Fang if (len < RT2573_RX_DESC_SIZE + sizeof (struct ieee80211_frame_min)) { 5391a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 54087c96ac5SQuaker Fang "rum_rxeof(): xfer too short %d\n", len); 54187c96ac5SQuaker Fang sc->sc_rx_err++; 54287c96ac5SQuaker Fang goto fail; 54387c96ac5SQuaker Fang } 54487c96ac5SQuaker Fang 54587c96ac5SQuaker Fang /* rx descriptor is located at the head, different from RT2500USB */ 54687c96ac5SQuaker Fang desc = (struct rum_rx_desc *)rxbuf; 54787c96ac5SQuaker Fang 54887c96ac5SQuaker Fang if (LE_32(desc->flags) & RT2573_RX_CRC_ERROR) { 54987c96ac5SQuaker Fang /* 55087c96ac5SQuaker Fang * This should not happen since we did not request to receive 55187c96ac5SQuaker Fang * those frames when we filled RT2573_TXRX_CSR0. 55287c96ac5SQuaker Fang */ 5531a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "CRC error\n"); 55487c96ac5SQuaker Fang sc->sc_rx_err++; 55587c96ac5SQuaker Fang goto fail; 55687c96ac5SQuaker Fang } 55787c96ac5SQuaker Fang 55887c96ac5SQuaker Fang pktlen = (LE_32(desc->flags) >> 16) & 0xfff; 55987c96ac5SQuaker Fang 56087c96ac5SQuaker Fang if (pktlen > (len - RT2573_RX_DESC_SIZE)) { 5611a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 56287c96ac5SQuaker Fang "rum_rxeof(): pktlen mismatch <%d, %d>.\n", pktlen, len); 56387c96ac5SQuaker Fang goto fail; 56487c96ac5SQuaker Fang } 56587c96ac5SQuaker Fang 56687c96ac5SQuaker Fang if ((m = allocb(pktlen, BPRI_MED)) == NULL) { 5671a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 56887c96ac5SQuaker Fang "rum_rxeof(): allocate mblk failed.\n"); 56987c96ac5SQuaker Fang sc->sc_rx_nobuf++; 57087c96ac5SQuaker Fang goto fail; 57187c96ac5SQuaker Fang } 57287c96ac5SQuaker Fang 57387c96ac5SQuaker Fang bcopy(rxbuf + RT2573_RX_DESC_SIZE, m->b_rptr, pktlen); 57487c96ac5SQuaker Fang m->b_wptr += pktlen; 57587c96ac5SQuaker Fang 57687c96ac5SQuaker Fang wh = (struct ieee80211_frame *)m->b_rptr; 57787c96ac5SQuaker Fang ni = ieee80211_find_rxnode(ic, wh); 57887c96ac5SQuaker Fang 57987c96ac5SQuaker Fang /* send the frame to the 802.11 layer */ 58087c96ac5SQuaker Fang (void) ieee80211_input(ic, m, ni, desc->rssi, 0); 58187c96ac5SQuaker Fang 58287c96ac5SQuaker Fang /* node is no longer needed */ 58387c96ac5SQuaker Fang ieee80211_free_node(ni); 58487c96ac5SQuaker Fang 58587c96ac5SQuaker Fang fail: 58687c96ac5SQuaker Fang mutex_enter(&sc->rx_lock); 58787c96ac5SQuaker Fang sc->rx_queued--; 58887c96ac5SQuaker Fang mutex_exit(&sc->rx_lock); 58987c96ac5SQuaker Fang 59087c96ac5SQuaker Fang freemsg(mp); 59187c96ac5SQuaker Fang usb_free_bulk_req(req); 59287c96ac5SQuaker Fang 59387c96ac5SQuaker Fang if (RAL_IS_RUNNING(sc)) 59487c96ac5SQuaker Fang (void) rum_rx_trigger(sc); 59587c96ac5SQuaker Fang } 59687c96ac5SQuaker Fang 59787c96ac5SQuaker Fang /* 59887c96ac5SQuaker Fang * Return the expected ack rate for a frame transmitted at rate `rate'. 59987c96ac5SQuaker Fang */ 60087c96ac5SQuaker Fang static int 60187c96ac5SQuaker Fang rum_ack_rate(struct ieee80211com *ic, int rate) 60287c96ac5SQuaker Fang { 60387c96ac5SQuaker Fang switch (rate) { 60487c96ac5SQuaker Fang /* CCK rates */ 60587c96ac5SQuaker Fang case 2: 60687c96ac5SQuaker Fang return (2); 60787c96ac5SQuaker Fang case 4: 60887c96ac5SQuaker Fang case 11: 60987c96ac5SQuaker Fang case 22: 61087c96ac5SQuaker Fang return ((ic->ic_curmode == IEEE80211_MODE_11B) ? 4 : rate); 61187c96ac5SQuaker Fang 61287c96ac5SQuaker Fang /* OFDM rates */ 61387c96ac5SQuaker Fang case 12: 61487c96ac5SQuaker Fang case 18: 61587c96ac5SQuaker Fang return (12); 61687c96ac5SQuaker Fang case 24: 61787c96ac5SQuaker Fang case 36: 61887c96ac5SQuaker Fang return (24); 61987c96ac5SQuaker Fang case 48: 62087c96ac5SQuaker Fang case 72: 62187c96ac5SQuaker Fang case 96: 62287c96ac5SQuaker Fang case 108: 62387c96ac5SQuaker Fang return (48); 62487c96ac5SQuaker Fang } 62587c96ac5SQuaker Fang 62687c96ac5SQuaker Fang /* default to 1Mbps */ 62787c96ac5SQuaker Fang return (2); 62887c96ac5SQuaker Fang } 62987c96ac5SQuaker Fang 63087c96ac5SQuaker Fang /* 63187c96ac5SQuaker Fang * Compute the duration (in us) needed to transmit `len' bytes at rate `rate'. 63287c96ac5SQuaker Fang * The function automatically determines the operating mode depending on the 63387c96ac5SQuaker Fang * given rate. `flags' indicates whether short preamble is in use or not. 63487c96ac5SQuaker Fang */ 63587c96ac5SQuaker Fang static uint16_t 63687c96ac5SQuaker Fang rum_txtime(int len, int rate, uint32_t flags) 63787c96ac5SQuaker Fang { 63887c96ac5SQuaker Fang uint16_t txtime; 63987c96ac5SQuaker Fang 64087c96ac5SQuaker Fang if (RUM_RATE_IS_OFDM(rate)) { 64187c96ac5SQuaker Fang /* IEEE Std 802.11a-1999, pp. 37 */ 64287c96ac5SQuaker Fang txtime = (8 + 4 * len + 3 + rate - 1) / rate; 64387c96ac5SQuaker Fang txtime = 16 + 4 + 4 * txtime + 6; 64487c96ac5SQuaker Fang } else { 64587c96ac5SQuaker Fang /* IEEE Std 802.11b-1999, pp. 28 */ 64687c96ac5SQuaker Fang txtime = (16 * len + rate - 1) / rate; 64787c96ac5SQuaker Fang if (rate != 2 && (flags & IEEE80211_F_SHPREAMBLE)) 64887c96ac5SQuaker Fang txtime += 72 + 24; 64987c96ac5SQuaker Fang else 65087c96ac5SQuaker Fang txtime += 144 + 48; 65187c96ac5SQuaker Fang } 65287c96ac5SQuaker Fang return (txtime); 65387c96ac5SQuaker Fang } 65487c96ac5SQuaker Fang 65587c96ac5SQuaker Fang static uint8_t 65687c96ac5SQuaker Fang rum_plcp_signal(int rate) 65787c96ac5SQuaker Fang { 65887c96ac5SQuaker Fang switch (rate) { 65987c96ac5SQuaker Fang /* CCK rates (returned values are device-dependent) */ 66087c96ac5SQuaker Fang case 2: return (0x0); 66187c96ac5SQuaker Fang case 4: return (0x1); 66287c96ac5SQuaker Fang case 11: return (0x2); 66387c96ac5SQuaker Fang case 22: return (0x3); 66487c96ac5SQuaker Fang 66587c96ac5SQuaker Fang /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 66687c96ac5SQuaker Fang case 12: return (0xb); 66787c96ac5SQuaker Fang case 18: return (0xf); 66887c96ac5SQuaker Fang case 24: return (0xa); 66987c96ac5SQuaker Fang case 36: return (0xe); 67087c96ac5SQuaker Fang case 48: return (0x9); 67187c96ac5SQuaker Fang case 72: return (0xd); 67287c96ac5SQuaker Fang case 96: return (0x8); 67387c96ac5SQuaker Fang case 108: return (0xc); 67487c96ac5SQuaker Fang 67587c96ac5SQuaker Fang /* unsupported rates (should not get there) */ 67687c96ac5SQuaker Fang default: return (0xff); 67787c96ac5SQuaker Fang } 67887c96ac5SQuaker Fang } 67987c96ac5SQuaker Fang 68087c96ac5SQuaker Fang static void 68187c96ac5SQuaker Fang rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc, 68287c96ac5SQuaker Fang uint32_t flags, uint16_t xflags, int len, int rate) 68387c96ac5SQuaker Fang { 68487c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 68587c96ac5SQuaker Fang uint16_t plcp_length; 68687c96ac5SQuaker Fang int remainder; 68787c96ac5SQuaker Fang 68887c96ac5SQuaker Fang desc->flags = LE_32(flags); 68987c96ac5SQuaker Fang desc->flags |= LE_32(RT2573_TX_VALID); 69087c96ac5SQuaker Fang desc->flags |= LE_32(len << 16); 69187c96ac5SQuaker Fang 69287c96ac5SQuaker Fang desc->xflags = LE_16(xflags); 69387c96ac5SQuaker Fang 69487c96ac5SQuaker Fang desc->wme = LE_16(RT2573_QID(0) | RT2573_AIFSN(2) | 69587c96ac5SQuaker Fang RT2573_LOGCWMIN(4) | RT2573_LOGCWMAX(10)); 69687c96ac5SQuaker Fang 69787c96ac5SQuaker Fang /* setup PLCP fields */ 69887c96ac5SQuaker Fang desc->plcp_signal = rum_plcp_signal(rate); 69987c96ac5SQuaker Fang desc->plcp_service = 4; 70087c96ac5SQuaker Fang 70187c96ac5SQuaker Fang len += IEEE80211_CRC_LEN; 70287c96ac5SQuaker Fang if (RUM_RATE_IS_OFDM(rate)) { 70387c96ac5SQuaker Fang desc->flags |= LE_32(RT2573_TX_OFDM); 70487c96ac5SQuaker Fang 70587c96ac5SQuaker Fang plcp_length = len & 0xfff; 70687c96ac5SQuaker Fang desc->plcp_length_hi = plcp_length >> 6; 70787c96ac5SQuaker Fang desc->plcp_length_lo = plcp_length & 0x3f; 70887c96ac5SQuaker Fang } else { 70987c96ac5SQuaker Fang plcp_length = (16 * len + rate - 1) / rate; 71087c96ac5SQuaker Fang if (rate == 22) { 71187c96ac5SQuaker Fang remainder = (16 * len) % 22; 71287c96ac5SQuaker Fang if (remainder != 0 && remainder < 7) 71387c96ac5SQuaker Fang desc->plcp_service |= RT2573_PLCP_LENGEXT; 71487c96ac5SQuaker Fang } 71587c96ac5SQuaker Fang desc->plcp_length_hi = plcp_length >> 8; 71687c96ac5SQuaker Fang desc->plcp_length_lo = plcp_length & 0xff; 71787c96ac5SQuaker Fang 71887c96ac5SQuaker Fang if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) 71987c96ac5SQuaker Fang desc->plcp_signal |= 0x08; 72087c96ac5SQuaker Fang } 72187c96ac5SQuaker Fang } 72287c96ac5SQuaker Fang 72387c96ac5SQuaker Fang #define RUM_TX_TIMEOUT 5 72487c96ac5SQuaker Fang 72587c96ac5SQuaker Fang static int 72687c96ac5SQuaker Fang rum_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type) 72787c96ac5SQuaker Fang { 72887c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)ic; 72987c96ac5SQuaker Fang struct rum_tx_desc *desc; 73087c96ac5SQuaker Fang 73187c96ac5SQuaker Fang struct ieee80211_frame *wh; 73287c96ac5SQuaker Fang struct ieee80211_key *k; 73387c96ac5SQuaker Fang 73487c96ac5SQuaker Fang uint16_t dur; 73587c96ac5SQuaker Fang uint32_t flags = 0; 73687c96ac5SQuaker Fang int rate, err = DDI_SUCCESS, rv; 73787c96ac5SQuaker Fang 73887c96ac5SQuaker Fang struct ieee80211_node *ni = NULL; 73987c96ac5SQuaker Fang mblk_t *m, *m0; 74087c96ac5SQuaker Fang int off, mblen, pktlen, xferlen; 74187c96ac5SQuaker Fang 7421a932f2eSQuaker Fang /* discard packets while suspending or not inited */ 7431a932f2eSQuaker Fang if (!RAL_IS_RUNNING(sc)) { 7441a932f2eSQuaker Fang freemsg(mp); 7451a932f2eSQuaker Fang return (ENXIO); 7461a932f2eSQuaker Fang } 74787c96ac5SQuaker Fang 74887c96ac5SQuaker Fang mutex_enter(&sc->tx_lock); 74987c96ac5SQuaker Fang 75087c96ac5SQuaker Fang if (sc->tx_queued > RAL_TX_LIST_COUNT) { 7511a932f2eSQuaker Fang ral_debug(RAL_DBG_TX, "rum_send(): " 75287c96ac5SQuaker Fang "no TX buffer available!\n"); 75387c96ac5SQuaker Fang if ((type & IEEE80211_FC0_TYPE_MASK) == 75487c96ac5SQuaker Fang IEEE80211_FC0_TYPE_DATA) { 75587c96ac5SQuaker Fang sc->sc_need_sched = 1; 75687c96ac5SQuaker Fang } 75787c96ac5SQuaker Fang sc->sc_tx_nobuf++; 75887c96ac5SQuaker Fang err = ENOMEM; 75987c96ac5SQuaker Fang goto fail; 76087c96ac5SQuaker Fang } 76187c96ac5SQuaker Fang 76287c96ac5SQuaker Fang m = allocb(RAL_TXBUF_SIZE + RT2573_TX_DESC_SIZE, BPRI_MED); 76387c96ac5SQuaker Fang if (m == NULL) { 7641a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "rum_send(): can't alloc mblk.\n"); 76587c96ac5SQuaker Fang err = DDI_FAILURE; 76687c96ac5SQuaker Fang goto fail; 76787c96ac5SQuaker Fang } 76887c96ac5SQuaker Fang 76987c96ac5SQuaker Fang m->b_rptr += RT2573_TX_DESC_SIZE; /* skip TX descriptor */ 77087c96ac5SQuaker Fang m->b_wptr += RT2573_TX_DESC_SIZE; 77187c96ac5SQuaker Fang 77287c96ac5SQuaker Fang for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) { 77387c96ac5SQuaker Fang mblen = (uintptr_t)m0->b_wptr - (uintptr_t)m0->b_rptr; 77487c96ac5SQuaker Fang (void) memcpy(m->b_rptr + off, m0->b_rptr, mblen); 77587c96ac5SQuaker Fang off += mblen; 77687c96ac5SQuaker Fang } 77787c96ac5SQuaker Fang m->b_wptr += off; 77887c96ac5SQuaker Fang 77987c96ac5SQuaker Fang wh = (struct ieee80211_frame *)m->b_rptr; 78087c96ac5SQuaker Fang 78187c96ac5SQuaker Fang ni = ieee80211_find_txnode(ic, wh->i_addr1); 78287c96ac5SQuaker Fang if (ni == NULL) { 78387c96ac5SQuaker Fang err = DDI_FAILURE; 78487c96ac5SQuaker Fang sc->sc_tx_err++; 78587c96ac5SQuaker Fang freemsg(m); 78687c96ac5SQuaker Fang goto fail; 78787c96ac5SQuaker Fang } 78887c96ac5SQuaker Fang 78987c96ac5SQuaker Fang if ((type & IEEE80211_FC0_TYPE_MASK) == 79087c96ac5SQuaker Fang IEEE80211_FC0_TYPE_DATA) { 79187c96ac5SQuaker Fang (void) ieee80211_encap(ic, m, ni); 79287c96ac5SQuaker Fang } 79387c96ac5SQuaker Fang 79487c96ac5SQuaker Fang if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 79587c96ac5SQuaker Fang k = ieee80211_crypto_encap(ic, m); 79687c96ac5SQuaker Fang if (k == NULL) { 79787c96ac5SQuaker Fang sc->sc_tx_err++; 79887c96ac5SQuaker Fang err = DDI_FAILURE; 79987c96ac5SQuaker Fang freemsg(m); 80087c96ac5SQuaker Fang goto fail; 80187c96ac5SQuaker Fang } 80287c96ac5SQuaker Fang /* packet header may have moved, reset our local pointer */ 80387c96ac5SQuaker Fang wh = (struct ieee80211_frame *)m->b_rptr; 80487c96ac5SQuaker Fang } 80587c96ac5SQuaker Fang 80687c96ac5SQuaker Fang m->b_rptr -= RT2573_TX_DESC_SIZE; /* restore */ 80787c96ac5SQuaker Fang desc = (struct rum_tx_desc *)m->b_rptr; 80887c96ac5SQuaker Fang 80987c96ac5SQuaker Fang if ((type & IEEE80211_FC0_TYPE_MASK) == 81087c96ac5SQuaker Fang IEEE80211_FC0_TYPE_DATA) { /* DATA */ 81187c96ac5SQuaker Fang if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) 81287c96ac5SQuaker Fang rate = ic->ic_bss->in_rates.ir_rates[ic->ic_fixed_rate]; 81387c96ac5SQuaker Fang else 81487c96ac5SQuaker Fang rate = ni->in_rates.ir_rates[ni->in_txrate]; 81587c96ac5SQuaker Fang 81687c96ac5SQuaker Fang rate &= IEEE80211_RATE_VAL; 81787c96ac5SQuaker Fang if (rate <= 0) { 81887c96ac5SQuaker Fang rate = 2; /* basic rate */ 81987c96ac5SQuaker Fang } 82087c96ac5SQuaker Fang 82187c96ac5SQuaker Fang 82287c96ac5SQuaker Fang if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 82387c96ac5SQuaker Fang flags |= RT2573_TX_NEED_ACK; 82487c96ac5SQuaker Fang flags |= RT2573_TX_MORE_FRAG; 82587c96ac5SQuaker Fang 82687c96ac5SQuaker Fang dur = rum_txtime(RUM_ACK_SIZE, rum_ack_rate(ic, rate), 82787c96ac5SQuaker Fang ic->ic_flags) + sc->sifs; 82887c96ac5SQuaker Fang *(uint16_t *)(uintptr_t)wh->i_dur = LE_16(dur); 82987c96ac5SQuaker Fang } 83087c96ac5SQuaker Fang } else { /* MGMT */ 83187c96ac5SQuaker Fang rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2; 83287c96ac5SQuaker Fang 83387c96ac5SQuaker Fang if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 83487c96ac5SQuaker Fang flags |= RT2573_TX_NEED_ACK; 83587c96ac5SQuaker Fang 83687c96ac5SQuaker Fang dur = rum_txtime(RUM_ACK_SIZE, rum_ack_rate(ic, rate), 83787c96ac5SQuaker Fang ic->ic_flags) + sc->sifs; 83887c96ac5SQuaker Fang *(uint16_t *)(uintptr_t)wh->i_dur = LE_16(dur); 83987c96ac5SQuaker Fang 84087c96ac5SQuaker Fang /* tell hardware to add timestamp for probe responses */ 84187c96ac5SQuaker Fang if ((wh->i_fc[0] & 84287c96ac5SQuaker Fang (IEEE80211_FC0_TYPE_MASK | 84387c96ac5SQuaker Fang IEEE80211_FC0_SUBTYPE_MASK)) == 84487c96ac5SQuaker Fang (IEEE80211_FC0_TYPE_MGT | 84587c96ac5SQuaker Fang IEEE80211_FC0_SUBTYPE_PROBE_RESP)) 84687c96ac5SQuaker Fang flags |= RT2573_TX_TIMESTAMP; 84787c96ac5SQuaker Fang } 84887c96ac5SQuaker Fang } 84987c96ac5SQuaker Fang 85087c96ac5SQuaker Fang pktlen = msgdsize(m) - RT2573_TX_DESC_SIZE; 85187c96ac5SQuaker Fang rum_setup_tx_desc(sc, desc, flags, 0, pktlen, rate); 85287c96ac5SQuaker Fang 85387c96ac5SQuaker Fang /* align end on a 4-bytes boundary */ 85487c96ac5SQuaker Fang xferlen = (RT2573_TX_DESC_SIZE + pktlen + 3) & ~3; 85587c96ac5SQuaker Fang 85687c96ac5SQuaker Fang /* 85787c96ac5SQuaker Fang * No space left in the last URB to store the extra 4 bytes, force 85887c96ac5SQuaker Fang * sending of another URB. 85987c96ac5SQuaker Fang */ 86087c96ac5SQuaker Fang if ((xferlen % 64) == 0) 86187c96ac5SQuaker Fang xferlen += 4; 86287c96ac5SQuaker Fang 86387c96ac5SQuaker Fang m->b_wptr = m->b_rptr + xferlen; 86487c96ac5SQuaker Fang 8651a932f2eSQuaker Fang ral_debug(RAL_DBG_TX, "sending data frame len=%u rate=%u xfer len=%u\n", 86687c96ac5SQuaker Fang pktlen, rate, xferlen); 86787c96ac5SQuaker Fang 86887c96ac5SQuaker Fang rv = rum_tx_trigger(sc, m); 86987c96ac5SQuaker Fang 87087c96ac5SQuaker Fang if (rv == 0) { 87187c96ac5SQuaker Fang ic->ic_stats.is_tx_frags++; 87287c96ac5SQuaker Fang ic->ic_stats.is_tx_bytes += pktlen; 87387c96ac5SQuaker Fang } 87487c96ac5SQuaker Fang 87587c96ac5SQuaker Fang fail: 87687c96ac5SQuaker Fang if (ni != NULL) 87787c96ac5SQuaker Fang ieee80211_free_node(ni); 87887c96ac5SQuaker Fang 87987c96ac5SQuaker Fang if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA || 88087c96ac5SQuaker Fang err == 0) { 88187c96ac5SQuaker Fang freemsg(mp); 88287c96ac5SQuaker Fang } 88387c96ac5SQuaker Fang 88487c96ac5SQuaker Fang mutex_exit(&sc->tx_lock); 88587c96ac5SQuaker Fang 88687c96ac5SQuaker Fang return (err); 88787c96ac5SQuaker Fang } 88887c96ac5SQuaker Fang 88987c96ac5SQuaker Fang static mblk_t * 89087c96ac5SQuaker Fang rum_m_tx(void *arg, mblk_t *mp) 89187c96ac5SQuaker Fang { 89287c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)arg; 89387c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 89487c96ac5SQuaker Fang mblk_t *next; 89587c96ac5SQuaker Fang 89687c96ac5SQuaker Fang /* 89787c96ac5SQuaker Fang * No data frames go out unless we're associated; this 89887c96ac5SQuaker Fang * should not happen as the 802.11 layer does not enable 89987c96ac5SQuaker Fang * the xmit queue until we enter the RUN state. 90087c96ac5SQuaker Fang */ 90187c96ac5SQuaker Fang if (ic->ic_state != IEEE80211_S_RUN) { 9021a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "rum_m_tx(): " 90387c96ac5SQuaker Fang "discard, state %u\n", ic->ic_state); 90487c96ac5SQuaker Fang freemsgchain(mp); 90587c96ac5SQuaker Fang return (NULL); 90687c96ac5SQuaker Fang } 90787c96ac5SQuaker Fang 90887c96ac5SQuaker Fang while (mp != NULL) { 90987c96ac5SQuaker Fang next = mp->b_next; 91087c96ac5SQuaker Fang mp->b_next = NULL; 91187c96ac5SQuaker Fang if (rum_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != DDI_SUCCESS) { 91287c96ac5SQuaker Fang mp->b_next = next; 91387c96ac5SQuaker Fang freemsgchain(mp); 91487c96ac5SQuaker Fang return (NULL); 91587c96ac5SQuaker Fang } 91687c96ac5SQuaker Fang mp = next; 91787c96ac5SQuaker Fang } 91887c96ac5SQuaker Fang return (mp); 91987c96ac5SQuaker Fang } 92087c96ac5SQuaker Fang 92187c96ac5SQuaker Fang static void 92287c96ac5SQuaker Fang rum_bbp_write(struct rum_softc *sc, uint8_t reg, uint8_t val) 92387c96ac5SQuaker Fang { 92487c96ac5SQuaker Fang uint32_t tmp; 92587c96ac5SQuaker Fang int ntries; 92687c96ac5SQuaker Fang 92787c96ac5SQuaker Fang for (ntries = 0; ntries < 5; ntries++) { 92887c96ac5SQuaker Fang if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY)) 92987c96ac5SQuaker Fang break; 93087c96ac5SQuaker Fang } 93187c96ac5SQuaker Fang if (ntries == 5) { 9321a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 93387c96ac5SQuaker Fang "rum_bbp_write(): could not write to BBP\n"); 93487c96ac5SQuaker Fang return; 93587c96ac5SQuaker Fang } 93687c96ac5SQuaker Fang 93787c96ac5SQuaker Fang tmp = RT2573_BBP_BUSY | (reg & 0x7f) << 8 | val; 93887c96ac5SQuaker Fang rum_write(sc, RT2573_PHY_CSR3, tmp); 93987c96ac5SQuaker Fang } 94087c96ac5SQuaker Fang 94187c96ac5SQuaker Fang static uint8_t 94287c96ac5SQuaker Fang rum_bbp_read(struct rum_softc *sc, uint8_t reg) 94387c96ac5SQuaker Fang { 94487c96ac5SQuaker Fang uint32_t val; 94587c96ac5SQuaker Fang int ntries; 94687c96ac5SQuaker Fang 94787c96ac5SQuaker Fang for (ntries = 0; ntries < 5; ntries++) { 94887c96ac5SQuaker Fang if (!(rum_read(sc, RT2573_PHY_CSR3) & RT2573_BBP_BUSY)) 94987c96ac5SQuaker Fang break; 95087c96ac5SQuaker Fang } 95187c96ac5SQuaker Fang if (ntries == 5) { 9521a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "rum_bbp_read(): could not read BBP\n"); 95387c96ac5SQuaker Fang return (0); 95487c96ac5SQuaker Fang } 95587c96ac5SQuaker Fang 95687c96ac5SQuaker Fang val = RT2573_BBP_BUSY | RT2573_BBP_READ | reg << 8; 95787c96ac5SQuaker Fang rum_write(sc, RT2573_PHY_CSR3, val); 95887c96ac5SQuaker Fang 95987c96ac5SQuaker Fang for (ntries = 0; ntries < 100; ntries++) { 96087c96ac5SQuaker Fang val = rum_read(sc, RT2573_PHY_CSR3); 96187c96ac5SQuaker Fang if (!(val & RT2573_BBP_BUSY)) 96287c96ac5SQuaker Fang return (val & 0xff); 96387c96ac5SQuaker Fang drv_usecwait(1); 96487c96ac5SQuaker Fang } 96587c96ac5SQuaker Fang 9661a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "rum_bbp_read(): could not read BBP\n"); 96787c96ac5SQuaker Fang return (0); 96887c96ac5SQuaker Fang } 96987c96ac5SQuaker Fang 97087c96ac5SQuaker Fang static void 97187c96ac5SQuaker Fang rum_rf_write(struct rum_softc *sc, uint8_t reg, uint32_t val) 97287c96ac5SQuaker Fang { 97387c96ac5SQuaker Fang uint32_t tmp; 97487c96ac5SQuaker Fang int ntries; 97587c96ac5SQuaker Fang 97687c96ac5SQuaker Fang for (ntries = 0; ntries < 5; ntries++) { 97787c96ac5SQuaker Fang if (!(rum_read(sc, RT2573_PHY_CSR4) & RT2573_RF_BUSY)) 97887c96ac5SQuaker Fang break; 97987c96ac5SQuaker Fang } 98087c96ac5SQuaker Fang if (ntries == 5) { 9811a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 98287c96ac5SQuaker Fang "rum_rf_write(): could not write to RF\n"); 98387c96ac5SQuaker Fang return; 98487c96ac5SQuaker Fang } 98587c96ac5SQuaker Fang 98687c96ac5SQuaker Fang tmp = RT2573_RF_BUSY | RT2573_RF_20BIT | (val & 0xfffff) << 2 | 98787c96ac5SQuaker Fang (reg & 3); 98887c96ac5SQuaker Fang rum_write(sc, RT2573_PHY_CSR4, tmp); 98987c96ac5SQuaker Fang 99087c96ac5SQuaker Fang /* remember last written value in sc */ 99187c96ac5SQuaker Fang sc->rf_regs[reg] = val; 99287c96ac5SQuaker Fang 9931a932f2eSQuaker Fang ral_debug(RAL_DBG_HW, "RF R[%u] <- 0x%05x\n", reg & 3, val & 0xfffff); 99487c96ac5SQuaker Fang } 99587c96ac5SQuaker Fang 99687c96ac5SQuaker Fang static void 99787c96ac5SQuaker Fang rum_select_antenna(struct rum_softc *sc) 99887c96ac5SQuaker Fang { 99987c96ac5SQuaker Fang uint8_t bbp4, bbp77; 100087c96ac5SQuaker Fang uint32_t tmp; 100187c96ac5SQuaker Fang 100287c96ac5SQuaker Fang bbp4 = rum_bbp_read(sc, 4); 100387c96ac5SQuaker Fang bbp77 = rum_bbp_read(sc, 77); 100487c96ac5SQuaker Fang 100587c96ac5SQuaker Fang /* make sure Rx is disabled before switching antenna */ 100687c96ac5SQuaker Fang tmp = rum_read(sc, RT2573_TXRX_CSR0); 100787c96ac5SQuaker Fang rum_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX); 100887c96ac5SQuaker Fang 100987c96ac5SQuaker Fang rum_bbp_write(sc, 4, bbp4); 101087c96ac5SQuaker Fang rum_bbp_write(sc, 77, bbp77); 101187c96ac5SQuaker Fang 101287c96ac5SQuaker Fang rum_write(sc, RT2573_TXRX_CSR0, tmp); 101387c96ac5SQuaker Fang } 101487c96ac5SQuaker Fang 101587c96ac5SQuaker Fang /* 101687c96ac5SQuaker Fang * Enable multi-rate retries for frames sent at OFDM rates. 101787c96ac5SQuaker Fang * In 802.11b/g mode, allow fallback to CCK rates. 101887c96ac5SQuaker Fang */ 101987c96ac5SQuaker Fang static void 102087c96ac5SQuaker Fang rum_enable_mrr(struct rum_softc *sc) 102187c96ac5SQuaker Fang { 102287c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 102387c96ac5SQuaker Fang uint32_t tmp; 102487c96ac5SQuaker Fang 102587c96ac5SQuaker Fang tmp = rum_read(sc, RT2573_TXRX_CSR4); 102687c96ac5SQuaker Fang 102787c96ac5SQuaker Fang tmp &= ~RT2573_MRR_CCK_FALLBACK; 102887c96ac5SQuaker Fang if (!IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) 102987c96ac5SQuaker Fang tmp |= RT2573_MRR_CCK_FALLBACK; 103087c96ac5SQuaker Fang tmp |= RT2573_MRR_ENABLED; 103187c96ac5SQuaker Fang 103287c96ac5SQuaker Fang rum_write(sc, RT2573_TXRX_CSR4, tmp); 103387c96ac5SQuaker Fang } 103487c96ac5SQuaker Fang 103587c96ac5SQuaker Fang static void 103687c96ac5SQuaker Fang rum_set_txpreamble(struct rum_softc *sc) 103787c96ac5SQuaker Fang { 103887c96ac5SQuaker Fang uint32_t tmp; 103987c96ac5SQuaker Fang 104087c96ac5SQuaker Fang tmp = rum_read(sc, RT2573_TXRX_CSR4); 104187c96ac5SQuaker Fang 104287c96ac5SQuaker Fang tmp &= ~RT2573_SHORT_PREAMBLE; 104387c96ac5SQuaker Fang if (sc->sc_ic.ic_flags & IEEE80211_F_SHPREAMBLE) 104487c96ac5SQuaker Fang tmp |= RT2573_SHORT_PREAMBLE; 104587c96ac5SQuaker Fang 104687c96ac5SQuaker Fang rum_write(sc, RT2573_TXRX_CSR4, tmp); 104787c96ac5SQuaker Fang } 104887c96ac5SQuaker Fang 104987c96ac5SQuaker Fang static void 105087c96ac5SQuaker Fang rum_set_basicrates(struct rum_softc *sc) 105187c96ac5SQuaker Fang { 105287c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 105387c96ac5SQuaker Fang 105487c96ac5SQuaker Fang /* update basic rate set */ 105587c96ac5SQuaker Fang if (ic->ic_curmode == IEEE80211_MODE_11B) { 105687c96ac5SQuaker Fang /* 11b basic rates: 1, 2Mbps */ 105787c96ac5SQuaker Fang rum_write(sc, RT2573_TXRX_CSR5, 0x3); 105887c96ac5SQuaker Fang } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->in_chan)) { 105987c96ac5SQuaker Fang /* 11a basic rates: 6, 12, 24Mbps */ 106087c96ac5SQuaker Fang rum_write(sc, RT2573_TXRX_CSR5, 0x150); 106187c96ac5SQuaker Fang } else { 106287c96ac5SQuaker Fang /* 11b/g basic rates: 1, 2, 5.5, 11Mbps */ 106387c96ac5SQuaker Fang rum_write(sc, RT2573_TXRX_CSR5, 0xf); 106487c96ac5SQuaker Fang } 106587c96ac5SQuaker Fang } 106687c96ac5SQuaker Fang 106787c96ac5SQuaker Fang /* 106887c96ac5SQuaker Fang * Reprogram MAC/BBP to switch to a new band. Values taken from the reference 106987c96ac5SQuaker Fang * driver. 107087c96ac5SQuaker Fang */ 107187c96ac5SQuaker Fang static void 107287c96ac5SQuaker Fang rum_select_band(struct rum_softc *sc, struct ieee80211_channel *c) 107387c96ac5SQuaker Fang { 107487c96ac5SQuaker Fang uint8_t bbp17, bbp35, bbp96, bbp97, bbp98, bbp104; 107587c96ac5SQuaker Fang uint32_t tmp; 107687c96ac5SQuaker Fang 107787c96ac5SQuaker Fang /* update all BBP registers that depend on the band */ 107887c96ac5SQuaker Fang bbp17 = 0x20; bbp96 = 0x48; bbp104 = 0x2c; 107987c96ac5SQuaker Fang bbp35 = 0x50; bbp97 = 0x48; bbp98 = 0x48; 108087c96ac5SQuaker Fang if (IEEE80211_IS_CHAN_5GHZ(c)) { 108187c96ac5SQuaker Fang bbp17 += 0x08; bbp96 += 0x10; bbp104 += 0x0c; 108287c96ac5SQuaker Fang bbp35 += 0x10; bbp97 += 0x10; bbp98 += 0x10; 108387c96ac5SQuaker Fang } 108487c96ac5SQuaker Fang if ((IEEE80211_IS_CHAN_2GHZ(c) && sc->ext_2ghz_lna) || 108587c96ac5SQuaker Fang (IEEE80211_IS_CHAN_5GHZ(c) && sc->ext_5ghz_lna)) { 108687c96ac5SQuaker Fang bbp17 += 0x10; bbp96 += 0x10; bbp104 += 0x10; 108787c96ac5SQuaker Fang } 108887c96ac5SQuaker Fang 108987c96ac5SQuaker Fang sc->bbp17 = bbp17; 109087c96ac5SQuaker Fang rum_bbp_write(sc, 17, bbp17); 109187c96ac5SQuaker Fang rum_bbp_write(sc, 96, bbp96); 109287c96ac5SQuaker Fang rum_bbp_write(sc, 104, bbp104); 109387c96ac5SQuaker Fang 109487c96ac5SQuaker Fang if ((IEEE80211_IS_CHAN_2GHZ(c) && sc->ext_2ghz_lna) || 109587c96ac5SQuaker Fang (IEEE80211_IS_CHAN_5GHZ(c) && sc->ext_5ghz_lna)) { 109687c96ac5SQuaker Fang rum_bbp_write(sc, 75, 0x80); 109787c96ac5SQuaker Fang rum_bbp_write(sc, 86, 0x80); 109887c96ac5SQuaker Fang rum_bbp_write(sc, 88, 0x80); 109987c96ac5SQuaker Fang } 110087c96ac5SQuaker Fang 110187c96ac5SQuaker Fang rum_bbp_write(sc, 35, bbp35); 110287c96ac5SQuaker Fang rum_bbp_write(sc, 97, bbp97); 110387c96ac5SQuaker Fang rum_bbp_write(sc, 98, bbp98); 110487c96ac5SQuaker Fang 110587c96ac5SQuaker Fang tmp = rum_read(sc, RT2573_PHY_CSR0); 110687c96ac5SQuaker Fang tmp &= ~(RT2573_PA_PE_2GHZ | RT2573_PA_PE_5GHZ); 110787c96ac5SQuaker Fang if (IEEE80211_IS_CHAN_2GHZ(c)) 110887c96ac5SQuaker Fang tmp |= RT2573_PA_PE_2GHZ; 110987c96ac5SQuaker Fang else 111087c96ac5SQuaker Fang tmp |= RT2573_PA_PE_5GHZ; 111187c96ac5SQuaker Fang rum_write(sc, RT2573_PHY_CSR0, tmp); 111287c96ac5SQuaker Fang 111387c96ac5SQuaker Fang /* 802.11a uses a 16 microseconds short interframe space */ 111487c96ac5SQuaker Fang sc->sifs = IEEE80211_IS_CHAN_5GHZ(c) ? 16 : 10; 111587c96ac5SQuaker Fang } 111687c96ac5SQuaker Fang 111787c96ac5SQuaker Fang static void 111887c96ac5SQuaker Fang rum_set_chan(struct rum_softc *sc, struct ieee80211_channel *c) 111987c96ac5SQuaker Fang { 112087c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 112187c96ac5SQuaker Fang const struct rfprog *rfprog; 112287c96ac5SQuaker Fang uint8_t bbp3, bbp94 = RT2573_BBPR94_DEFAULT; 112387c96ac5SQuaker Fang int8_t power; 112487c96ac5SQuaker Fang uint_t i, chan; 112587c96ac5SQuaker Fang 112687c96ac5SQuaker Fang chan = ieee80211_chan2ieee(ic, c); 112787c96ac5SQuaker Fang if (chan == 0 || chan == IEEE80211_CHAN_ANY) 112887c96ac5SQuaker Fang return; 112987c96ac5SQuaker Fang 113087c96ac5SQuaker Fang /* select the appropriate RF settings based on what EEPROM says */ 113187c96ac5SQuaker Fang rfprog = (sc->rf_rev == RT2573_RF_5225 || 113287c96ac5SQuaker Fang sc->rf_rev == RT2573_RF_2527) ? rum_rf5225 : rum_rf5226; 113387c96ac5SQuaker Fang 113487c96ac5SQuaker Fang /* find the settings for this channel (we know it exists) */ 113587c96ac5SQuaker Fang for (i = 0; rfprog[i].chan != chan; i++) { 113687c96ac5SQuaker Fang } 113787c96ac5SQuaker Fang 113887c96ac5SQuaker Fang power = sc->txpow[i]; 113987c96ac5SQuaker Fang if (power < 0) { 114087c96ac5SQuaker Fang bbp94 += power; 114187c96ac5SQuaker Fang power = 0; 114287c96ac5SQuaker Fang } else if (power > 31) { 114387c96ac5SQuaker Fang bbp94 += power - 31; 114487c96ac5SQuaker Fang power = 31; 114587c96ac5SQuaker Fang } 114687c96ac5SQuaker Fang 114787c96ac5SQuaker Fang /* 114887c96ac5SQuaker Fang * If we are switching from the 2GHz band to the 5GHz band or 114987c96ac5SQuaker Fang * vice-versa, BBP registers need to be reprogrammed. 115087c96ac5SQuaker Fang */ 115187c96ac5SQuaker Fang if (c->ich_flags != ic->ic_curchan->ich_flags) { 115287c96ac5SQuaker Fang rum_select_band(sc, c); 115387c96ac5SQuaker Fang rum_select_antenna(sc); 115487c96ac5SQuaker Fang } 115587c96ac5SQuaker Fang ic->ic_curchan = c; 115687c96ac5SQuaker Fang 115787c96ac5SQuaker Fang rum_rf_write(sc, RT2573_RF1, rfprog[i].r1); 115887c96ac5SQuaker Fang rum_rf_write(sc, RT2573_RF2, rfprog[i].r2); 115987c96ac5SQuaker Fang rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7); 116087c96ac5SQuaker Fang rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10); 116187c96ac5SQuaker Fang 116287c96ac5SQuaker Fang rum_rf_write(sc, RT2573_RF1, rfprog[i].r1); 116387c96ac5SQuaker Fang rum_rf_write(sc, RT2573_RF2, rfprog[i].r2); 116487c96ac5SQuaker Fang rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7 | 1); 116587c96ac5SQuaker Fang rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10); 116687c96ac5SQuaker Fang 116787c96ac5SQuaker Fang rum_rf_write(sc, RT2573_RF1, rfprog[i].r1); 116887c96ac5SQuaker Fang rum_rf_write(sc, RT2573_RF2, rfprog[i].r2); 116987c96ac5SQuaker Fang rum_rf_write(sc, RT2573_RF3, rfprog[i].r3 | power << 7); 117087c96ac5SQuaker Fang rum_rf_write(sc, RT2573_RF4, rfprog[i].r4 | sc->rffreq << 10); 117187c96ac5SQuaker Fang 117287c96ac5SQuaker Fang drv_usecwait(10); 117387c96ac5SQuaker Fang 117487c96ac5SQuaker Fang /* enable smart mode for MIMO-capable RFs */ 117587c96ac5SQuaker Fang bbp3 = rum_bbp_read(sc, 3); 117687c96ac5SQuaker Fang 117787c96ac5SQuaker Fang bbp3 &= ~RT2573_SMART_MODE; 117887c96ac5SQuaker Fang if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_2527) 117987c96ac5SQuaker Fang bbp3 |= RT2573_SMART_MODE; 118087c96ac5SQuaker Fang 118187c96ac5SQuaker Fang rum_bbp_write(sc, 3, bbp3); 118287c96ac5SQuaker Fang 118387c96ac5SQuaker Fang if (bbp94 != RT2573_BBPR94_DEFAULT) 118487c96ac5SQuaker Fang rum_bbp_write(sc, 94, bbp94); 118587c96ac5SQuaker Fang } 118687c96ac5SQuaker Fang 118787c96ac5SQuaker Fang /* 118887c96ac5SQuaker Fang * Enable TSF synchronization and tell h/w to start sending beacons for IBSS 118987c96ac5SQuaker Fang * and HostAP operating modes. 119087c96ac5SQuaker Fang */ 119187c96ac5SQuaker Fang static void 119287c96ac5SQuaker Fang rum_enable_tsf_sync(struct rum_softc *sc) 119387c96ac5SQuaker Fang { 119487c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 119587c96ac5SQuaker Fang uint32_t tmp; 119687c96ac5SQuaker Fang 119787c96ac5SQuaker Fang if (ic->ic_opmode != IEEE80211_M_STA) { 119887c96ac5SQuaker Fang /* 119987c96ac5SQuaker Fang * Change default 16ms TBTT adjustment to 8ms. 120087c96ac5SQuaker Fang * Must be done before enabling beacon generation. 120187c96ac5SQuaker Fang */ 120287c96ac5SQuaker Fang rum_write(sc, RT2573_TXRX_CSR10, 1 << 12 | 8); 120387c96ac5SQuaker Fang } 120487c96ac5SQuaker Fang 120587c96ac5SQuaker Fang tmp = rum_read(sc, RT2573_TXRX_CSR9) & 0xff000000; 120687c96ac5SQuaker Fang 120787c96ac5SQuaker Fang /* set beacon interval (in 1/16ms unit) */ 120887c96ac5SQuaker Fang tmp |= ic->ic_bss->in_intval * 16; 120987c96ac5SQuaker Fang 121087c96ac5SQuaker Fang tmp |= RT2573_TSF_TICKING | RT2573_ENABLE_TBTT; 121187c96ac5SQuaker Fang if (ic->ic_opmode == IEEE80211_M_STA) 121287c96ac5SQuaker Fang tmp |= RT2573_TSF_MODE(1); 121387c96ac5SQuaker Fang else 121487c96ac5SQuaker Fang tmp |= RT2573_TSF_MODE(2) | RT2573_GENERATE_BEACON; 121587c96ac5SQuaker Fang 121687c96ac5SQuaker Fang rum_write(sc, RT2573_TXRX_CSR9, tmp); 121787c96ac5SQuaker Fang } 121887c96ac5SQuaker Fang 121987c96ac5SQuaker Fang /* ARGSUSED */ 122087c96ac5SQuaker Fang static void 122187c96ac5SQuaker Fang rum_update_slot(struct ieee80211com *ic, int onoff) 122287c96ac5SQuaker Fang { 122387c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)ic; 122487c96ac5SQuaker Fang uint8_t slottime; 122587c96ac5SQuaker Fang uint32_t tmp; 122687c96ac5SQuaker Fang 122787c96ac5SQuaker Fang slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; 122887c96ac5SQuaker Fang 122987c96ac5SQuaker Fang tmp = rum_read(sc, RT2573_MAC_CSR9); 123087c96ac5SQuaker Fang tmp = (tmp & ~0xff) | slottime; 123187c96ac5SQuaker Fang rum_write(sc, RT2573_MAC_CSR9, tmp); 123287c96ac5SQuaker Fang 12331a932f2eSQuaker Fang ral_debug(RAL_DBG_HW, "setting slot time to %uus\n", slottime); 123487c96ac5SQuaker Fang } 123587c96ac5SQuaker Fang 123687c96ac5SQuaker Fang static void 123787c96ac5SQuaker Fang rum_set_bssid(struct rum_softc *sc, const uint8_t *bssid) 123887c96ac5SQuaker Fang { 123987c96ac5SQuaker Fang uint32_t tmp; 124087c96ac5SQuaker Fang 124187c96ac5SQuaker Fang tmp = bssid[0] | bssid[1] << 8 | bssid[2] << 16 | bssid[3] << 24; 124287c96ac5SQuaker Fang rum_write(sc, RT2573_MAC_CSR4, tmp); 124387c96ac5SQuaker Fang 124487c96ac5SQuaker Fang tmp = bssid[4] | bssid[5] << 8 | RT2573_ONE_BSSID << 16; 124587c96ac5SQuaker Fang rum_write(sc, RT2573_MAC_CSR5, tmp); 124687c96ac5SQuaker Fang } 124787c96ac5SQuaker Fang 124887c96ac5SQuaker Fang static void 124987c96ac5SQuaker Fang rum_set_macaddr(struct rum_softc *sc, const uint8_t *addr) 125087c96ac5SQuaker Fang { 125187c96ac5SQuaker Fang uint32_t tmp; 125287c96ac5SQuaker Fang 125387c96ac5SQuaker Fang tmp = addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24; 125487c96ac5SQuaker Fang rum_write(sc, RT2573_MAC_CSR2, tmp); 125587c96ac5SQuaker Fang 125687c96ac5SQuaker Fang tmp = addr[4] | addr[5] << 8 | 0xff << 16; 125787c96ac5SQuaker Fang rum_write(sc, RT2573_MAC_CSR3, tmp); 125887c96ac5SQuaker Fang 12591a932f2eSQuaker Fang ral_debug(RAL_DBG_HW, 126087c96ac5SQuaker Fang "setting MAC address to " MACSTR "\n", MAC2STR(addr)); 126187c96ac5SQuaker Fang } 126287c96ac5SQuaker Fang 126387c96ac5SQuaker Fang static void 126487c96ac5SQuaker Fang rum_update_promisc(struct rum_softc *sc) 126587c96ac5SQuaker Fang { 126687c96ac5SQuaker Fang uint32_t tmp; 126787c96ac5SQuaker Fang 126887c96ac5SQuaker Fang tmp = rum_read(sc, RT2573_TXRX_CSR0); 126987c96ac5SQuaker Fang 127087c96ac5SQuaker Fang tmp &= ~RT2573_DROP_NOT_TO_ME; 127187c96ac5SQuaker Fang if (!(sc->sc_rcr & RAL_RCR_PROMISC)) 127287c96ac5SQuaker Fang tmp |= RT2573_DROP_NOT_TO_ME; 127387c96ac5SQuaker Fang 127487c96ac5SQuaker Fang rum_write(sc, RT2573_TXRX_CSR0, tmp); 127587c96ac5SQuaker Fang 12761a932f2eSQuaker Fang ral_debug(RAL_DBG_HW, "%s promiscuous mode\n", 127787c96ac5SQuaker Fang (sc->sc_rcr & RAL_RCR_PROMISC) ? "entering" : "leaving"); 127887c96ac5SQuaker Fang } 127987c96ac5SQuaker Fang 128087c96ac5SQuaker Fang static const char * 128187c96ac5SQuaker Fang rum_get_rf(int rev) 128287c96ac5SQuaker Fang { 128387c96ac5SQuaker Fang switch (rev) { 128487c96ac5SQuaker Fang case RT2573_RF_2527: return ("RT2527 (MIMO XR)"); 128587c96ac5SQuaker Fang case RT2573_RF_2528: return ("RT2528"); 128687c96ac5SQuaker Fang case RT2573_RF_5225: return ("RT5225 (MIMO XR)"); 128787c96ac5SQuaker Fang case RT2573_RF_5226: return ("RT5226"); 128887c96ac5SQuaker Fang default: return ("unknown"); 128987c96ac5SQuaker Fang } 129087c96ac5SQuaker Fang } 129187c96ac5SQuaker Fang 129287c96ac5SQuaker Fang static void 129387c96ac5SQuaker Fang rum_read_eeprom(struct rum_softc *sc) 129487c96ac5SQuaker Fang { 129587c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 129687c96ac5SQuaker Fang uint16_t val; 129787c96ac5SQuaker Fang 129887c96ac5SQuaker Fang /* read MAC address */ 129987c96ac5SQuaker Fang rum_eeprom_read(sc, RT2573_EEPROM_ADDRESS, ic->ic_macaddr, 6); 130087c96ac5SQuaker Fang 130187c96ac5SQuaker Fang rum_eeprom_read(sc, RT2573_EEPROM_ANTENNA, &val, 2); 130287c96ac5SQuaker Fang val = LE_16(val); 130387c96ac5SQuaker Fang sc->rf_rev = (val >> 11) & 0x1f; 130487c96ac5SQuaker Fang sc->hw_radio = (val >> 10) & 0x1; 130587c96ac5SQuaker Fang sc->rx_ant = (val >> 4) & 0x3; 130687c96ac5SQuaker Fang sc->tx_ant = (val >> 2) & 0x3; 130787c96ac5SQuaker Fang sc->nb_ant = val & 0x3; 130887c96ac5SQuaker Fang 13091a932f2eSQuaker Fang ral_debug(RAL_DBG_HW, "RF revision=%d\n", sc->rf_rev); 131087c96ac5SQuaker Fang 131187c96ac5SQuaker Fang rum_eeprom_read(sc, RT2573_EEPROM_CONFIG2, &val, 2); 131287c96ac5SQuaker Fang val = LE_16(val); 131387c96ac5SQuaker Fang sc->ext_5ghz_lna = (val >> 6) & 0x1; 131487c96ac5SQuaker Fang sc->ext_2ghz_lna = (val >> 4) & 0x1; 131587c96ac5SQuaker Fang 13161a932f2eSQuaker Fang ral_debug(RAL_DBG_HW, "External 2GHz LNA=%d\nExternal 5GHz LNA=%d\n", 131787c96ac5SQuaker Fang sc->ext_2ghz_lna, sc->ext_5ghz_lna); 131887c96ac5SQuaker Fang 131987c96ac5SQuaker Fang rum_eeprom_read(sc, RT2573_EEPROM_RSSI_2GHZ_OFFSET, &val, 2); 132087c96ac5SQuaker Fang val = LE_16(val); 132187c96ac5SQuaker Fang if ((val & 0xff) != 0xff) 132287c96ac5SQuaker Fang sc->rssi_2ghz_corr = (int8_t)(val & 0xff); /* signed */ 132387c96ac5SQuaker Fang 132487c96ac5SQuaker Fang rum_eeprom_read(sc, RT2573_EEPROM_RSSI_5GHZ_OFFSET, &val, 2); 132587c96ac5SQuaker Fang val = LE_16(val); 132687c96ac5SQuaker Fang if ((val & 0xff) != 0xff) 132787c96ac5SQuaker Fang sc->rssi_5ghz_corr = (int8_t)(val & 0xff); /* signed */ 132887c96ac5SQuaker Fang 13291a932f2eSQuaker Fang ral_debug(RAL_DBG_HW, "RSSI 2GHz corr=%d\nRSSI 5GHz corr=%d\n", 133087c96ac5SQuaker Fang sc->rssi_2ghz_corr, sc->rssi_5ghz_corr); 133187c96ac5SQuaker Fang 133287c96ac5SQuaker Fang rum_eeprom_read(sc, RT2573_EEPROM_FREQ_OFFSET, &val, 2); 133387c96ac5SQuaker Fang val = LE_16(val); 133487c96ac5SQuaker Fang if ((val & 0xff) != 0xff) 133587c96ac5SQuaker Fang sc->rffreq = val & 0xff; 133687c96ac5SQuaker Fang 13371a932f2eSQuaker Fang ral_debug(RAL_DBG_HW, "RF freq=%d\n", sc->rffreq); 133887c96ac5SQuaker Fang 133987c96ac5SQuaker Fang /* read Tx power for all a/b/g channels */ 134087c96ac5SQuaker Fang rum_eeprom_read(sc, RT2573_EEPROM_TXPOWER, sc->txpow, 14); 134187c96ac5SQuaker Fang /* default Tx power for 802.11a channels */ 134287c96ac5SQuaker Fang (void) memset(sc->txpow + 14, 24, sizeof (sc->txpow) - 14); 134387c96ac5SQuaker Fang 134487c96ac5SQuaker Fang /* read default values for BBP registers */ 134587c96ac5SQuaker Fang rum_eeprom_read(sc, RT2573_EEPROM_BBP_BASE, sc->bbp_prom, 2 * 16); 134687c96ac5SQuaker Fang } 134787c96ac5SQuaker Fang 134887c96ac5SQuaker Fang static int 134987c96ac5SQuaker Fang rum_bbp_init(struct rum_softc *sc) 135087c96ac5SQuaker Fang { 135187c96ac5SQuaker Fang int i, ntries; 135287c96ac5SQuaker Fang 135387c96ac5SQuaker Fang /* wait for BBP to be ready */ 135487c96ac5SQuaker Fang for (ntries = 0; ntries < 100; ntries++) { 135587c96ac5SQuaker Fang const uint8_t val = rum_bbp_read(sc, 0); 135687c96ac5SQuaker Fang if (val != 0 && val != 0xff) 135787c96ac5SQuaker Fang break; 135887c96ac5SQuaker Fang drv_usecwait(1000); 135987c96ac5SQuaker Fang } 136087c96ac5SQuaker Fang if (ntries == 100) { 13611a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "timeout waiting for BBP\n"); 136287c96ac5SQuaker Fang return (EIO); 136387c96ac5SQuaker Fang } 136487c96ac5SQuaker Fang 136587c96ac5SQuaker Fang /* initialize BBP registers to default values */ 136687c96ac5SQuaker Fang for (i = 0; i < RUM_N(rum_def_bbp); i++) 136787c96ac5SQuaker Fang rum_bbp_write(sc, rum_def_bbp[i].reg, rum_def_bbp[i].val); 136887c96ac5SQuaker Fang 136987c96ac5SQuaker Fang /* write vendor-specific BBP values (from EEPROM) */ 137087c96ac5SQuaker Fang for (i = 0; i < 16; i++) { 137187c96ac5SQuaker Fang if (sc->bbp_prom[i].reg == 0 || sc->bbp_prom[i].reg == 0xff) 137287c96ac5SQuaker Fang continue; 137387c96ac5SQuaker Fang rum_bbp_write(sc, sc->bbp_prom[i].reg, sc->bbp_prom[i].val); 137487c96ac5SQuaker Fang } 137587c96ac5SQuaker Fang 137687c96ac5SQuaker Fang return (0); 137787c96ac5SQuaker Fang } 137887c96ac5SQuaker Fang 137987c96ac5SQuaker Fang /* 138087c96ac5SQuaker Fang * This function is called periodically (every 200ms) during scanning to 138187c96ac5SQuaker Fang * switch from one channel to another. 138287c96ac5SQuaker Fang */ 138387c96ac5SQuaker Fang static void 138487c96ac5SQuaker Fang rum_next_scan(void *arg) 138587c96ac5SQuaker Fang { 138687c96ac5SQuaker Fang struct rum_softc *sc = arg; 138787c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 138887c96ac5SQuaker Fang 138987c96ac5SQuaker Fang if (ic->ic_state == IEEE80211_S_SCAN) 139087c96ac5SQuaker Fang ieee80211_next_scan(ic); 139187c96ac5SQuaker Fang } 139287c96ac5SQuaker Fang 139387c96ac5SQuaker Fang static int 139487c96ac5SQuaker Fang rum_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 139587c96ac5SQuaker Fang { 139687c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)ic; 139787c96ac5SQuaker Fang enum ieee80211_state ostate; 139887c96ac5SQuaker Fang struct ieee80211_node *ni; 139987c96ac5SQuaker Fang int err; 140087c96ac5SQuaker Fang uint32_t tmp; 140187c96ac5SQuaker Fang 140287c96ac5SQuaker Fang RAL_LOCK(sc); 140387c96ac5SQuaker Fang 140487c96ac5SQuaker Fang ostate = ic->ic_state; 140587c96ac5SQuaker Fang 140687c96ac5SQuaker Fang if (sc->sc_scan_id != 0) { 140787c96ac5SQuaker Fang (void) untimeout(sc->sc_scan_id); 140887c96ac5SQuaker Fang sc->sc_scan_id = 0; 140987c96ac5SQuaker Fang } 141087c96ac5SQuaker Fang 141187c96ac5SQuaker Fang if (sc->sc_amrr_id != 0) { 141287c96ac5SQuaker Fang (void) untimeout(sc->sc_amrr_id); 141387c96ac5SQuaker Fang sc->sc_amrr_id = 0; 141487c96ac5SQuaker Fang } 141587c96ac5SQuaker Fang 141687c96ac5SQuaker Fang switch (nstate) { 141787c96ac5SQuaker Fang case IEEE80211_S_INIT: 141887c96ac5SQuaker Fang if (ostate == IEEE80211_S_RUN) { 141987c96ac5SQuaker Fang /* abort TSF synchronization */ 142087c96ac5SQuaker Fang tmp = rum_read(sc, RT2573_TXRX_CSR9); 142187c96ac5SQuaker Fang rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff); 142287c96ac5SQuaker Fang } 142387c96ac5SQuaker Fang break; 142487c96ac5SQuaker Fang 142587c96ac5SQuaker Fang case IEEE80211_S_SCAN: 142687c96ac5SQuaker Fang rum_set_chan(sc, ic->ic_curchan); 142787c96ac5SQuaker Fang sc->sc_scan_id = timeout(rum_next_scan, (void *)sc, 142887c96ac5SQuaker Fang drv_usectohz(sc->dwelltime * 1000)); 142987c96ac5SQuaker Fang break; 143087c96ac5SQuaker Fang 143187c96ac5SQuaker Fang case IEEE80211_S_AUTH: 143287c96ac5SQuaker Fang rum_set_chan(sc, ic->ic_curchan); 143387c96ac5SQuaker Fang break; 143487c96ac5SQuaker Fang 143587c96ac5SQuaker Fang case IEEE80211_S_ASSOC: 143687c96ac5SQuaker Fang rum_set_chan(sc, ic->ic_curchan); 143787c96ac5SQuaker Fang break; 143887c96ac5SQuaker Fang 143987c96ac5SQuaker Fang case IEEE80211_S_RUN: 144087c96ac5SQuaker Fang rum_set_chan(sc, ic->ic_curchan); 144187c96ac5SQuaker Fang 144287c96ac5SQuaker Fang ni = ic->ic_bss; 144387c96ac5SQuaker Fang 144487c96ac5SQuaker Fang if (ic->ic_opmode != IEEE80211_M_MONITOR) { 144587c96ac5SQuaker Fang rum_update_slot(ic, 1); 144687c96ac5SQuaker Fang rum_enable_mrr(sc); 144787c96ac5SQuaker Fang rum_set_txpreamble(sc); 144887c96ac5SQuaker Fang rum_set_basicrates(sc); 144987c96ac5SQuaker Fang rum_set_bssid(sc, ni->in_bssid); 145087c96ac5SQuaker Fang } 145187c96ac5SQuaker Fang 145287c96ac5SQuaker Fang if (ic->ic_opmode != IEEE80211_M_MONITOR) 145387c96ac5SQuaker Fang rum_enable_tsf_sync(sc); 145487c96ac5SQuaker Fang 145587c96ac5SQuaker Fang /* enable automatic rate adaptation in STA mode */ 145687c96ac5SQuaker Fang if (ic->ic_opmode == IEEE80211_M_STA && 145787c96ac5SQuaker Fang ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) 145887c96ac5SQuaker Fang rum_amrr_start(sc, ni); 145987c96ac5SQuaker Fang break; 146087c96ac5SQuaker Fang } 146187c96ac5SQuaker Fang 146287c96ac5SQuaker Fang RAL_UNLOCK(sc); 146387c96ac5SQuaker Fang 146487c96ac5SQuaker Fang err = sc->sc_newstate(ic, nstate, arg); 146587c96ac5SQuaker Fang /* 146687c96ac5SQuaker Fang * Finally, start any timers. 146787c96ac5SQuaker Fang */ 146887c96ac5SQuaker Fang if (nstate == IEEE80211_S_RUN) 146987c96ac5SQuaker Fang ieee80211_start_watchdog(ic, 1); 147087c96ac5SQuaker Fang 147187c96ac5SQuaker Fang return (err); 147287c96ac5SQuaker Fang } 147387c96ac5SQuaker Fang 147487c96ac5SQuaker Fang static void 147587c96ac5SQuaker Fang rum_close_pipes(struct rum_softc *sc) 147687c96ac5SQuaker Fang { 147787c96ac5SQuaker Fang usb_flags_t flags = USB_FLAGS_SLEEP; 147887c96ac5SQuaker Fang 147987c96ac5SQuaker Fang if (sc->sc_rx_pipeh != NULL) { 148087c96ac5SQuaker Fang usb_pipe_reset(sc->sc_dev, sc->sc_rx_pipeh, flags, NULL, 0); 148187c96ac5SQuaker Fang usb_pipe_close(sc->sc_dev, sc->sc_rx_pipeh, flags, NULL, 0); 148287c96ac5SQuaker Fang sc->sc_rx_pipeh = NULL; 148387c96ac5SQuaker Fang } 148487c96ac5SQuaker Fang 148587c96ac5SQuaker Fang if (sc->sc_tx_pipeh != NULL) { 148687c96ac5SQuaker Fang usb_pipe_reset(sc->sc_dev, sc->sc_tx_pipeh, flags, NULL, 0); 148787c96ac5SQuaker Fang usb_pipe_close(sc->sc_dev, sc->sc_tx_pipeh, flags, NULL, 0); 148887c96ac5SQuaker Fang sc->sc_tx_pipeh = NULL; 148987c96ac5SQuaker Fang } 149087c96ac5SQuaker Fang } 149187c96ac5SQuaker Fang 149287c96ac5SQuaker Fang static int 149387c96ac5SQuaker Fang rum_open_pipes(struct rum_softc *sc) 149487c96ac5SQuaker Fang { 149587c96ac5SQuaker Fang usb_ep_data_t *ep_node; 149687c96ac5SQuaker Fang usb_pipe_policy_t policy; 149787c96ac5SQuaker Fang int err; 149887c96ac5SQuaker Fang 149987c96ac5SQuaker Fang ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0, 0, 150087c96ac5SQuaker Fang USB_EP_ATTR_BULK, USB_EP_DIR_OUT); 150187c96ac5SQuaker Fang 150287c96ac5SQuaker Fang bzero(&policy, sizeof (usb_pipe_policy_t)); 150387c96ac5SQuaker Fang policy.pp_max_async_reqs = RAL_TX_LIST_COUNT; 150487c96ac5SQuaker Fang 150587c96ac5SQuaker Fang if ((err = usb_pipe_open(sc->sc_dev, 150687c96ac5SQuaker Fang &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP, 150787c96ac5SQuaker Fang &sc->sc_tx_pipeh)) != USB_SUCCESS) { 15081a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 150987c96ac5SQuaker Fang "rum_open_pipes(): %x failed to open tx pipe\n", err); 151087c96ac5SQuaker Fang goto fail; 151187c96ac5SQuaker Fang } 151287c96ac5SQuaker Fang 151387c96ac5SQuaker Fang ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0, 0, 151487c96ac5SQuaker Fang USB_EP_ATTR_BULK, USB_EP_DIR_IN); 151587c96ac5SQuaker Fang 151687c96ac5SQuaker Fang bzero(&policy, sizeof (usb_pipe_policy_t)); 151787c96ac5SQuaker Fang policy.pp_max_async_reqs = RAL_RX_LIST_COUNT + 32; 151887c96ac5SQuaker Fang 151987c96ac5SQuaker Fang if ((err = usb_pipe_open(sc->sc_dev, 152087c96ac5SQuaker Fang &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP, 152187c96ac5SQuaker Fang &sc->sc_rx_pipeh)) != USB_SUCCESS) { 15221a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 152387c96ac5SQuaker Fang "rum_open_pipes(): %x failed to open rx pipe\n", err); 152487c96ac5SQuaker Fang goto fail; 152587c96ac5SQuaker Fang } 152687c96ac5SQuaker Fang 152787c96ac5SQuaker Fang return (USB_SUCCESS); 152887c96ac5SQuaker Fang 152987c96ac5SQuaker Fang fail: 153087c96ac5SQuaker Fang if (sc->sc_rx_pipeh != NULL) { 153187c96ac5SQuaker Fang usb_pipe_close(sc->sc_dev, sc->sc_rx_pipeh, 153287c96ac5SQuaker Fang USB_FLAGS_SLEEP, NULL, 0); 153387c96ac5SQuaker Fang sc->sc_rx_pipeh = NULL; 153487c96ac5SQuaker Fang } 153587c96ac5SQuaker Fang 153687c96ac5SQuaker Fang if (sc->sc_tx_pipeh != NULL) { 153787c96ac5SQuaker Fang usb_pipe_close(sc->sc_dev, sc->sc_tx_pipeh, 153887c96ac5SQuaker Fang USB_FLAGS_SLEEP, NULL, 0); 153987c96ac5SQuaker Fang sc->sc_tx_pipeh = NULL; 154087c96ac5SQuaker Fang } 154187c96ac5SQuaker Fang 154287c96ac5SQuaker Fang return (USB_FAILURE); 154387c96ac5SQuaker Fang } 154487c96ac5SQuaker Fang 154587c96ac5SQuaker Fang static int 154687c96ac5SQuaker Fang rum_tx_trigger(struct rum_softc *sc, mblk_t *mp) 154787c96ac5SQuaker Fang { 154887c96ac5SQuaker Fang usb_bulk_req_t *req; 154987c96ac5SQuaker Fang int err; 155087c96ac5SQuaker Fang 155187c96ac5SQuaker Fang sc->sc_tx_timer = RUM_TX_TIMEOUT; 155287c96ac5SQuaker Fang 155387c96ac5SQuaker Fang req = usb_alloc_bulk_req(sc->sc_dev, 0, USB_FLAGS_SLEEP); 155487c96ac5SQuaker Fang if (req == NULL) { 15551a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 155687c96ac5SQuaker Fang "rum_tx_trigger(): failed to allocate req"); 155787c96ac5SQuaker Fang freemsg(mp); 155887c96ac5SQuaker Fang return (-1); 155987c96ac5SQuaker Fang } 156087c96ac5SQuaker Fang 156187c96ac5SQuaker Fang req->bulk_len = msgdsize(mp); 156287c96ac5SQuaker Fang req->bulk_data = mp; 156387c96ac5SQuaker Fang req->bulk_client_private = (usb_opaque_t)sc; 156487c96ac5SQuaker Fang req->bulk_timeout = RUM_TX_TIMEOUT; 156587c96ac5SQuaker Fang req->bulk_attributes = USB_ATTRS_AUTOCLEARING; 156687c96ac5SQuaker Fang req->bulk_cb = rum_txeof; 156787c96ac5SQuaker Fang req->bulk_exc_cb = rum_txeof; 156887c96ac5SQuaker Fang req->bulk_completion_reason = 0; 156987c96ac5SQuaker Fang req->bulk_cb_flags = 0; 157087c96ac5SQuaker Fang 157187c96ac5SQuaker Fang if ((err = usb_pipe_bulk_xfer(sc->sc_tx_pipeh, req, 0)) 157287c96ac5SQuaker Fang != USB_SUCCESS) { 157387c96ac5SQuaker Fang 15741a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "rum_tx_trigger(): " 157587c96ac5SQuaker Fang "failed to do tx xfer, %d", err); 157687c96ac5SQuaker Fang usb_free_bulk_req(req); 157787c96ac5SQuaker Fang return (-1); 157887c96ac5SQuaker Fang } 157987c96ac5SQuaker Fang 158087c96ac5SQuaker Fang sc->tx_queued++; 158187c96ac5SQuaker Fang 158287c96ac5SQuaker Fang return (0); 158387c96ac5SQuaker Fang } 158487c96ac5SQuaker Fang 158587c96ac5SQuaker Fang static int 158687c96ac5SQuaker Fang rum_rx_trigger(struct rum_softc *sc) 158787c96ac5SQuaker Fang { 158887c96ac5SQuaker Fang usb_bulk_req_t *req; 158987c96ac5SQuaker Fang int err; 159087c96ac5SQuaker Fang 159187c96ac5SQuaker Fang req = usb_alloc_bulk_req(sc->sc_dev, RAL_RXBUF_SIZE, USB_FLAGS_SLEEP); 159287c96ac5SQuaker Fang if (req == NULL) { 15931a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 159487c96ac5SQuaker Fang "rum_rx_trigger(): failed to allocate req"); 159587c96ac5SQuaker Fang return (-1); 159687c96ac5SQuaker Fang } 159787c96ac5SQuaker Fang 159887c96ac5SQuaker Fang req->bulk_len = RAL_RXBUF_SIZE; 159987c96ac5SQuaker Fang req->bulk_client_private = (usb_opaque_t)sc; 160087c96ac5SQuaker Fang req->bulk_timeout = 0; 160187c96ac5SQuaker Fang req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK 160287c96ac5SQuaker Fang | USB_ATTRS_AUTOCLEARING; 160387c96ac5SQuaker Fang req->bulk_cb = rum_rxeof; 160487c96ac5SQuaker Fang req->bulk_exc_cb = rum_rxeof; 160587c96ac5SQuaker Fang req->bulk_completion_reason = 0; 160687c96ac5SQuaker Fang req->bulk_cb_flags = 0; 160787c96ac5SQuaker Fang 160887c96ac5SQuaker Fang err = usb_pipe_bulk_xfer(sc->sc_rx_pipeh, req, 0); 160987c96ac5SQuaker Fang 161087c96ac5SQuaker Fang if (err != USB_SUCCESS) { 16111a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "rum_rx_trigger(): " 161287c96ac5SQuaker Fang "failed to do rx xfer, %d", err); 161387c96ac5SQuaker Fang usb_free_bulk_req(req); 161487c96ac5SQuaker Fang 161587c96ac5SQuaker Fang return (-1); 161687c96ac5SQuaker Fang } 161787c96ac5SQuaker Fang 161887c96ac5SQuaker Fang mutex_enter(&sc->rx_lock); 161987c96ac5SQuaker Fang sc->rx_queued++; 162087c96ac5SQuaker Fang mutex_exit(&sc->rx_lock); 162187c96ac5SQuaker Fang 162287c96ac5SQuaker Fang return (0); 162387c96ac5SQuaker Fang } 162487c96ac5SQuaker Fang 162587c96ac5SQuaker Fang static void 162687c96ac5SQuaker Fang rum_init_tx_queue(struct rum_softc *sc) 162787c96ac5SQuaker Fang { 162887c96ac5SQuaker Fang sc->tx_queued = 0; 162987c96ac5SQuaker Fang } 163087c96ac5SQuaker Fang 163187c96ac5SQuaker Fang static int 163287c96ac5SQuaker Fang rum_init_rx_queue(struct rum_softc *sc) 163387c96ac5SQuaker Fang { 163487c96ac5SQuaker Fang int i; 163587c96ac5SQuaker Fang 163687c96ac5SQuaker Fang sc->rx_queued = 0; 163787c96ac5SQuaker Fang 163887c96ac5SQuaker Fang for (i = 0; i < RAL_RX_LIST_COUNT; i++) { 163987c96ac5SQuaker Fang if (rum_rx_trigger(sc) != 0) { 164087c96ac5SQuaker Fang return (USB_FAILURE); 164187c96ac5SQuaker Fang } 164287c96ac5SQuaker Fang } 164387c96ac5SQuaker Fang 164487c96ac5SQuaker Fang return (USB_SUCCESS); 164587c96ac5SQuaker Fang } 164687c96ac5SQuaker Fang 164787c96ac5SQuaker Fang static void 164887c96ac5SQuaker Fang rum_stop(struct rum_softc *sc) 164987c96ac5SQuaker Fang { 165087c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 165187c96ac5SQuaker Fang uint32_t tmp; 165287c96ac5SQuaker Fang 165387c96ac5SQuaker Fang ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 165487c96ac5SQuaker Fang ieee80211_stop_watchdog(ic); /* stop the watchdog */ 165587c96ac5SQuaker Fang 165687c96ac5SQuaker Fang RAL_LOCK(sc); 165787c96ac5SQuaker Fang 165887c96ac5SQuaker Fang sc->sc_tx_timer = 0; 165987c96ac5SQuaker Fang sc->sc_flags &= ~RAL_FLAG_RUNNING; /* STOP */ 166087c96ac5SQuaker Fang 166187c96ac5SQuaker Fang /* disable Rx */ 166287c96ac5SQuaker Fang tmp = rum_read(sc, RT2573_TXRX_CSR0); 166387c96ac5SQuaker Fang rum_write(sc, RT2573_TXRX_CSR0, tmp | RT2573_DISABLE_RX); 166487c96ac5SQuaker Fang 166587c96ac5SQuaker Fang /* reset ASIC */ 166687c96ac5SQuaker Fang rum_write(sc, RT2573_MAC_CSR1, 3); 166787c96ac5SQuaker Fang rum_write(sc, RT2573_MAC_CSR1, 0); 166887c96ac5SQuaker Fang 166987c96ac5SQuaker Fang rum_close_pipes(sc); 167087c96ac5SQuaker Fang 167187c96ac5SQuaker Fang RAL_UNLOCK(sc); 167287c96ac5SQuaker Fang } 167387c96ac5SQuaker Fang 167487c96ac5SQuaker Fang static int 167587c96ac5SQuaker Fang rum_init(struct rum_softc *sc) 167687c96ac5SQuaker Fang { 167787c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 167887c96ac5SQuaker Fang uint32_t tmp; 167987c96ac5SQuaker Fang int i, ntries; 168087c96ac5SQuaker Fang 168187c96ac5SQuaker Fang rum_stop(sc); 168287c96ac5SQuaker Fang 168387c96ac5SQuaker Fang /* initialize MAC registers to default values */ 168487c96ac5SQuaker Fang for (i = 0; i < RUM_N(rum_def_mac); i++) 168587c96ac5SQuaker Fang rum_write(sc, rum_def_mac[i].reg, rum_def_mac[i].val); 168687c96ac5SQuaker Fang 168787c96ac5SQuaker Fang /* set host ready */ 168887c96ac5SQuaker Fang rum_write(sc, RT2573_MAC_CSR1, 3); 168987c96ac5SQuaker Fang rum_write(sc, RT2573_MAC_CSR1, 0); 169087c96ac5SQuaker Fang 169187c96ac5SQuaker Fang /* wait for BBP/RF to wakeup */ 169287c96ac5SQuaker Fang for (ntries = 0; ntries < 1000; ntries++) { 169387c96ac5SQuaker Fang if (rum_read(sc, RT2573_MAC_CSR12) & 8) 169487c96ac5SQuaker Fang break; 169587c96ac5SQuaker Fang rum_write(sc, RT2573_MAC_CSR12, 4); /* force wakeup */ 169687c96ac5SQuaker Fang drv_usecwait(1000); 169787c96ac5SQuaker Fang } 169887c96ac5SQuaker Fang if (ntries == 1000) { 16991a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 170087c96ac5SQuaker Fang "rum_init(): timeout waiting for BBP/RF to wakeup\n"); 170187c96ac5SQuaker Fang goto fail; 170287c96ac5SQuaker Fang } 170387c96ac5SQuaker Fang 170487c96ac5SQuaker Fang if (rum_bbp_init(sc) != 0) 170587c96ac5SQuaker Fang goto fail; 170687c96ac5SQuaker Fang 170787c96ac5SQuaker Fang /* select default channel */ 170887c96ac5SQuaker Fang rum_select_band(sc, ic->ic_curchan); 170987c96ac5SQuaker Fang rum_select_antenna(sc); 171087c96ac5SQuaker Fang rum_set_chan(sc, ic->ic_curchan); 171187c96ac5SQuaker Fang 171287c96ac5SQuaker Fang /* clear STA registers */ 171387c96ac5SQuaker Fang rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof (sc->sta)); 171487c96ac5SQuaker Fang 171587c96ac5SQuaker Fang rum_set_macaddr(sc, ic->ic_macaddr); 171687c96ac5SQuaker Fang 171787c96ac5SQuaker Fang /* initialize ASIC */ 171887c96ac5SQuaker Fang rum_write(sc, RT2573_MAC_CSR1, 4); 171987c96ac5SQuaker Fang 172087c96ac5SQuaker Fang if (rum_open_pipes(sc) != USB_SUCCESS) { 17211a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "rum_init(): " 172287c96ac5SQuaker Fang "could not open pipes.\n"); 172387c96ac5SQuaker Fang goto fail; 172487c96ac5SQuaker Fang } 172587c96ac5SQuaker Fang 172687c96ac5SQuaker Fang rum_init_tx_queue(sc); 172787c96ac5SQuaker Fang 172887c96ac5SQuaker Fang if (rum_init_rx_queue(sc) != USB_SUCCESS) 172987c96ac5SQuaker Fang goto fail; 173087c96ac5SQuaker Fang 173187c96ac5SQuaker Fang /* update Rx filter */ 173287c96ac5SQuaker Fang tmp = rum_read(sc, RT2573_TXRX_CSR0) & 0xffff; 173387c96ac5SQuaker Fang tmp |= RT2573_DROP_PHY_ERROR | RT2573_DROP_CRC_ERROR; 173487c96ac5SQuaker Fang if (ic->ic_opmode != IEEE80211_M_MONITOR) { 173587c96ac5SQuaker Fang tmp |= RT2573_DROP_CTL | RT2573_DROP_VER_ERROR | 173687c96ac5SQuaker Fang RT2573_DROP_ACKCTS; 173787c96ac5SQuaker Fang if (ic->ic_opmode != IEEE80211_M_HOSTAP) 173887c96ac5SQuaker Fang tmp |= RT2573_DROP_TODS; 173987c96ac5SQuaker Fang if (!(sc->sc_rcr & RAL_RCR_PROMISC)) 174087c96ac5SQuaker Fang tmp |= RT2573_DROP_NOT_TO_ME; 174187c96ac5SQuaker Fang } 174287c96ac5SQuaker Fang 174387c96ac5SQuaker Fang rum_write(sc, RT2573_TXRX_CSR0, tmp); 174487c96ac5SQuaker Fang sc->sc_flags |= RAL_FLAG_RUNNING; /* RUNNING */ 174587c96ac5SQuaker Fang 174687c96ac5SQuaker Fang return (DDI_SUCCESS); 174787c96ac5SQuaker Fang fail: 174887c96ac5SQuaker Fang rum_stop(sc); 174987c96ac5SQuaker Fang return (DDI_FAILURE); 175087c96ac5SQuaker Fang } 175187c96ac5SQuaker Fang 175287c96ac5SQuaker Fang static int 175387c96ac5SQuaker Fang rum_disconnect(dev_info_t *devinfo) 175487c96ac5SQuaker Fang { 175587c96ac5SQuaker Fang struct rum_softc *sc; 175687c96ac5SQuaker Fang struct ieee80211com *ic; 175787c96ac5SQuaker Fang 175887c96ac5SQuaker Fang /* 175987c96ac5SQuaker Fang * We can't call rum_stop() here, since the hardware is removed, 176087c96ac5SQuaker Fang * we can't access the register anymore. 176187c96ac5SQuaker Fang */ 176287c96ac5SQuaker Fang sc = ddi_get_soft_state(rum_soft_state_p, ddi_get_instance(devinfo)); 17631a932f2eSQuaker Fang ASSERT(sc != NULL); 176487c96ac5SQuaker Fang 17651a932f2eSQuaker Fang if (!RAL_IS_RUNNING(sc)) /* different device or not inited */ 17661a932f2eSQuaker Fang return (DDI_SUCCESS); 17671a932f2eSQuaker Fang 17681a932f2eSQuaker Fang ic = &sc->sc_ic; 176987c96ac5SQuaker Fang ieee80211_new_state(ic, IEEE80211_S_INIT, -1); 177087c96ac5SQuaker Fang ieee80211_stop_watchdog(ic); /* stop the watchdog */ 177187c96ac5SQuaker Fang 177287c96ac5SQuaker Fang RAL_LOCK(sc); 177387c96ac5SQuaker Fang 177487c96ac5SQuaker Fang sc->sc_tx_timer = 0; 177587c96ac5SQuaker Fang sc->sc_flags &= ~RAL_FLAG_RUNNING; /* STOP */ 177687c96ac5SQuaker Fang 177787c96ac5SQuaker Fang rum_close_pipes(sc); 177887c96ac5SQuaker Fang 177987c96ac5SQuaker Fang RAL_UNLOCK(sc); 178087c96ac5SQuaker Fang 178187c96ac5SQuaker Fang return (DDI_SUCCESS); 178287c96ac5SQuaker Fang } 178387c96ac5SQuaker Fang 178487c96ac5SQuaker Fang static int 178587c96ac5SQuaker Fang rum_reconnect(dev_info_t *devinfo) 178687c96ac5SQuaker Fang { 178787c96ac5SQuaker Fang struct rum_softc *sc; 178887c96ac5SQuaker Fang int err; 178987c96ac5SQuaker Fang 179087c96ac5SQuaker Fang sc = ddi_get_soft_state(rum_soft_state_p, ddi_get_instance(devinfo)); 17911a932f2eSQuaker Fang ASSERT(sc != NULL); 17921a932f2eSQuaker Fang 17931a932f2eSQuaker Fang /* check device changes after disconnect */ 17941a932f2eSQuaker Fang if (usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1, 17951a932f2eSQuaker Fang USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) { 17961a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "different device connected\n"); 17971a932f2eSQuaker Fang return (DDI_FAILURE); 17981a932f2eSQuaker Fang } 179987c96ac5SQuaker Fang 180087c96ac5SQuaker Fang err = rum_load_microcode(sc); 180187c96ac5SQuaker Fang if (err != USB_SUCCESS) { 18021a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "could not load 8051 microcode\n"); 180387c96ac5SQuaker Fang goto fail; 180487c96ac5SQuaker Fang } 180587c96ac5SQuaker Fang 180687c96ac5SQuaker Fang err = rum_init(sc); 180787c96ac5SQuaker Fang fail: 180887c96ac5SQuaker Fang return (err); 180987c96ac5SQuaker Fang } 181087c96ac5SQuaker Fang 18111a932f2eSQuaker Fang static void 18121a932f2eSQuaker Fang rum_resume(struct rum_softc *sc) 18131a932f2eSQuaker Fang { 18141a932f2eSQuaker Fang int err; 18151a932f2eSQuaker Fang 18161a932f2eSQuaker Fang /* check device changes after suspend */ 18171a932f2eSQuaker Fang if (usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1, 18181a932f2eSQuaker Fang USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) { 18191a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "no or different device connected\n"); 18201a932f2eSQuaker Fang return; 18211a932f2eSQuaker Fang } 18221a932f2eSQuaker Fang 18231a932f2eSQuaker Fang err = rum_load_microcode(sc); 18241a932f2eSQuaker Fang if (err != USB_SUCCESS) { 18251a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "could not load 8051 microcode\n"); 18261a932f2eSQuaker Fang return; 18271a932f2eSQuaker Fang } 18281a932f2eSQuaker Fang 18291a932f2eSQuaker Fang (void) rum_init(sc); 18301a932f2eSQuaker Fang } 18311a932f2eSQuaker Fang 183287c96ac5SQuaker Fang #define RUM_AMRR_MIN_SUCCESS_THRESHOLD 1 183387c96ac5SQuaker Fang #define RUM_AMRR_MAX_SUCCESS_THRESHOLD 10 183487c96ac5SQuaker Fang 183587c96ac5SQuaker Fang /* 183687c96ac5SQuaker Fang * Naive implementation of the Adaptive Multi Rate Retry algorithm: 183787c96ac5SQuaker Fang * "IEEE 802.11 Rate Adaptation: A Practical Approach" 183887c96ac5SQuaker Fang * Mathieu Lacage, Hossein Manshaei, Thierry Turletti 183987c96ac5SQuaker Fang * INRIA Sophia - Projet Planete 184087c96ac5SQuaker Fang * http://www-sop.inria.fr/rapports/sophia/RR-5208.html 184187c96ac5SQuaker Fang * 184287c96ac5SQuaker Fang * This algorithm is particularly well suited for rum since it does not 184387c96ac5SQuaker Fang * require per-frame retry statistics. Note however that since h/w does 184487c96ac5SQuaker Fang * not provide per-frame stats, we can't do per-node rate adaptation and 184587c96ac5SQuaker Fang * thus automatic rate adaptation is only enabled in STA operating mode. 184687c96ac5SQuaker Fang */ 184787c96ac5SQuaker Fang #define is_success(amrr) \ 184887c96ac5SQuaker Fang ((amrr)->retrycnt < (amrr)->txcnt / 10) 184987c96ac5SQuaker Fang #define is_failure(amrr) \ 185087c96ac5SQuaker Fang ((amrr)->retrycnt > (amrr)->txcnt / 3) 185187c96ac5SQuaker Fang #define is_enough(amrr) \ 185287c96ac5SQuaker Fang ((amrr)->txcnt > 10) 185387c96ac5SQuaker Fang #define is_min_rate(ni) \ 185487c96ac5SQuaker Fang ((ni)->in_txrate == 0) 185587c96ac5SQuaker Fang #define is_max_rate(ni) \ 185687c96ac5SQuaker Fang ((ni)->in_txrate == (ni)->in_rates.ir_nrates - 1) 185787c96ac5SQuaker Fang #define increase_rate(ni) \ 185887c96ac5SQuaker Fang ((ni)->in_txrate++) 185987c96ac5SQuaker Fang #define decrease_rate(ni) \ 186087c96ac5SQuaker Fang ((ni)->in_txrate--) 186187c96ac5SQuaker Fang #define reset_cnt(amrr) do { \ 186287c96ac5SQuaker Fang (amrr)->txcnt = (amrr)->retrycnt = 0; \ 186387c96ac5SQuaker Fang _NOTE(CONSTCOND) \ 186487c96ac5SQuaker Fang } while (/* CONSTCOND */0) 186587c96ac5SQuaker Fang 186687c96ac5SQuaker Fang static void 186787c96ac5SQuaker Fang rum_ratectl(struct rum_amrr *amrr, struct ieee80211_node *ni) 186887c96ac5SQuaker Fang { 186987c96ac5SQuaker Fang int need_change = 0; 187087c96ac5SQuaker Fang 187187c96ac5SQuaker Fang if (is_success(amrr) && is_enough(amrr)) { 187287c96ac5SQuaker Fang amrr->success++; 187387c96ac5SQuaker Fang if (amrr->success >= amrr->success_threshold && 187487c96ac5SQuaker Fang !is_max_rate(ni)) { 187587c96ac5SQuaker Fang amrr->recovery = 1; 187687c96ac5SQuaker Fang amrr->success = 0; 187787c96ac5SQuaker Fang increase_rate(ni); 187887c96ac5SQuaker Fang need_change = 1; 187987c96ac5SQuaker Fang } else { 188087c96ac5SQuaker Fang amrr->recovery = 0; 188187c96ac5SQuaker Fang } 188287c96ac5SQuaker Fang } else if (is_failure(amrr)) { 188387c96ac5SQuaker Fang amrr->success = 0; 188487c96ac5SQuaker Fang if (!is_min_rate(ni)) { 188587c96ac5SQuaker Fang if (amrr->recovery) { 188687c96ac5SQuaker Fang amrr->success_threshold *= 2; 188787c96ac5SQuaker Fang if (amrr->success_threshold > 188887c96ac5SQuaker Fang RUM_AMRR_MAX_SUCCESS_THRESHOLD) 188987c96ac5SQuaker Fang amrr->success_threshold = 189087c96ac5SQuaker Fang RUM_AMRR_MAX_SUCCESS_THRESHOLD; 189187c96ac5SQuaker Fang } else { 189287c96ac5SQuaker Fang amrr->success_threshold = 189387c96ac5SQuaker Fang RUM_AMRR_MIN_SUCCESS_THRESHOLD; 189487c96ac5SQuaker Fang } 189587c96ac5SQuaker Fang decrease_rate(ni); 189687c96ac5SQuaker Fang need_change = 1; 189787c96ac5SQuaker Fang } 189887c96ac5SQuaker Fang amrr->recovery = 0; /* original paper was incorrect */ 189987c96ac5SQuaker Fang } 190087c96ac5SQuaker Fang 190187c96ac5SQuaker Fang if (is_enough(amrr) || need_change) 190287c96ac5SQuaker Fang reset_cnt(amrr); 190387c96ac5SQuaker Fang } 190487c96ac5SQuaker Fang 190587c96ac5SQuaker Fang static void 190687c96ac5SQuaker Fang rum_amrr_timeout(void *arg) 190787c96ac5SQuaker Fang { 190887c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)arg; 190987c96ac5SQuaker Fang struct rum_amrr *amrr = &sc->amrr; 191087c96ac5SQuaker Fang 191187c96ac5SQuaker Fang rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof (sc->sta)); 191287c96ac5SQuaker Fang 191387c96ac5SQuaker Fang /* count TX retry-fail as Tx errors */ 191487c96ac5SQuaker Fang sc->sc_tx_err += LE_32(sc->sta[5]) >> 16; 191587c96ac5SQuaker Fang sc->sc_tx_retries += ((LE_32(sc->sta[4]) >> 16) + 191687c96ac5SQuaker Fang (LE_32(sc->sta[5]) & 0xffff)); 191787c96ac5SQuaker Fang 191887c96ac5SQuaker Fang amrr->retrycnt = 191987c96ac5SQuaker Fang (LE_32(sc->sta[4]) >> 16) + /* TX one-retry ok count */ 192087c96ac5SQuaker Fang (LE_32(sc->sta[5]) & 0xffff) + /* TX more-retry ok count */ 192187c96ac5SQuaker Fang (LE_32(sc->sta[5]) >> 16); /* TX retry-fail count */ 192287c96ac5SQuaker Fang 192387c96ac5SQuaker Fang amrr->txcnt = 192487c96ac5SQuaker Fang amrr->retrycnt + 192587c96ac5SQuaker Fang (LE_32(sc->sta[4]) & 0xffff); /* TX no-retry ok count */ 192687c96ac5SQuaker Fang 192787c96ac5SQuaker Fang rum_ratectl(amrr, sc->sc_ic.ic_bss); 192887c96ac5SQuaker Fang 192987c96ac5SQuaker Fang sc->sc_amrr_id = timeout(rum_amrr_timeout, (void *)sc, 193087c96ac5SQuaker Fang drv_usectohz(1000 * 1000)); /* 1 second */ 193187c96ac5SQuaker Fang } 193287c96ac5SQuaker Fang 193387c96ac5SQuaker Fang static void 193487c96ac5SQuaker Fang rum_amrr_start(struct rum_softc *sc, struct ieee80211_node *ni) 193587c96ac5SQuaker Fang { 193687c96ac5SQuaker Fang struct rum_amrr *amrr = &sc->amrr; 193787c96ac5SQuaker Fang int i; 193887c96ac5SQuaker Fang 193987c96ac5SQuaker Fang /* clear statistic registers (STA_CSR0 to STA_CSR5) */ 194087c96ac5SQuaker Fang rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof (sc->sta)); 194187c96ac5SQuaker Fang 194287c96ac5SQuaker Fang amrr->success = 0; 194387c96ac5SQuaker Fang amrr->recovery = 0; 194487c96ac5SQuaker Fang amrr->txcnt = amrr->retrycnt = 0; 194587c96ac5SQuaker Fang amrr->success_threshold = RUM_AMRR_MIN_SUCCESS_THRESHOLD; 194687c96ac5SQuaker Fang 194787c96ac5SQuaker Fang /* set rate to some reasonable initial value */ 194887c96ac5SQuaker Fang for (i = ni->in_rates.ir_nrates - 1; 194987c96ac5SQuaker Fang i > 0 && (ni->in_rates.ir_rates[i] & IEEE80211_RATE_VAL) > 72; 195087c96ac5SQuaker Fang i--) { 195187c96ac5SQuaker Fang } 195287c96ac5SQuaker Fang 195387c96ac5SQuaker Fang ni->in_txrate = i; 195487c96ac5SQuaker Fang 195587c96ac5SQuaker Fang sc->sc_amrr_id = timeout(rum_amrr_timeout, (void *)sc, 195687c96ac5SQuaker Fang drv_usectohz(1000 * 1000)); /* 1 second */ 195787c96ac5SQuaker Fang } 195887c96ac5SQuaker Fang 195987c96ac5SQuaker Fang void 196087c96ac5SQuaker Fang rum_watchdog(void *arg) 196187c96ac5SQuaker Fang { 196287c96ac5SQuaker Fang struct rum_softc *sc = arg; 196387c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 196487c96ac5SQuaker Fang int ntimer = 0; 196587c96ac5SQuaker Fang 196687c96ac5SQuaker Fang RAL_LOCK(sc); 196787c96ac5SQuaker Fang ic->ic_watchdog_timer = 0; 196887c96ac5SQuaker Fang 196987c96ac5SQuaker Fang if (!RAL_IS_RUNNING(sc)) { 197087c96ac5SQuaker Fang RAL_UNLOCK(sc); 197187c96ac5SQuaker Fang return; 197287c96ac5SQuaker Fang } 197387c96ac5SQuaker Fang 197487c96ac5SQuaker Fang if (sc->sc_tx_timer > 0) { 197587c96ac5SQuaker Fang if (--sc->sc_tx_timer == 0) { 19761a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "tx timer timeout\n"); 197787c96ac5SQuaker Fang RAL_UNLOCK(sc); 197887c96ac5SQuaker Fang (void) rum_init(sc); 197987c96ac5SQuaker Fang (void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 198087c96ac5SQuaker Fang return; 198187c96ac5SQuaker Fang } 198287c96ac5SQuaker Fang } 198387c96ac5SQuaker Fang 198487c96ac5SQuaker Fang if (ic->ic_state == IEEE80211_S_RUN) 198587c96ac5SQuaker Fang ntimer = 1; 198687c96ac5SQuaker Fang 198787c96ac5SQuaker Fang RAL_UNLOCK(sc); 198887c96ac5SQuaker Fang 198987c96ac5SQuaker Fang ieee80211_watchdog(ic); 199087c96ac5SQuaker Fang 199187c96ac5SQuaker Fang if (ntimer) 199287c96ac5SQuaker Fang ieee80211_start_watchdog(ic, ntimer); 199387c96ac5SQuaker Fang } 199487c96ac5SQuaker Fang 199587c96ac5SQuaker Fang static int 199687c96ac5SQuaker Fang rum_m_start(void *arg) 199787c96ac5SQuaker Fang { 199887c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)arg; 199987c96ac5SQuaker Fang int err; 200087c96ac5SQuaker Fang 200187c96ac5SQuaker Fang /* 200287c96ac5SQuaker Fang * initialize RT2501USB hardware 200387c96ac5SQuaker Fang */ 200487c96ac5SQuaker Fang err = rum_init(sc); 200587c96ac5SQuaker Fang if (err != DDI_SUCCESS) { 20061a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "device configuration failed\n"); 200787c96ac5SQuaker Fang goto fail; 200887c96ac5SQuaker Fang } 200987c96ac5SQuaker Fang sc->sc_flags |= RAL_FLAG_RUNNING; /* RUNNING */ 201087c96ac5SQuaker Fang return (err); 201187c96ac5SQuaker Fang 201287c96ac5SQuaker Fang fail: 201387c96ac5SQuaker Fang rum_stop(sc); 201487c96ac5SQuaker Fang return (err); 201587c96ac5SQuaker Fang } 201687c96ac5SQuaker Fang 201787c96ac5SQuaker Fang static void 201887c96ac5SQuaker Fang rum_m_stop(void *arg) 201987c96ac5SQuaker Fang { 202087c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)arg; 202187c96ac5SQuaker Fang 202287c96ac5SQuaker Fang (void) rum_stop(sc); 202387c96ac5SQuaker Fang sc->sc_flags &= ~RAL_FLAG_RUNNING; /* STOP */ 202487c96ac5SQuaker Fang } 202587c96ac5SQuaker Fang 202687c96ac5SQuaker Fang static int 202787c96ac5SQuaker Fang rum_m_unicst(void *arg, const uint8_t *macaddr) 202887c96ac5SQuaker Fang { 202987c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)arg; 203087c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 203187c96ac5SQuaker Fang 20321a932f2eSQuaker Fang ral_debug(RAL_DBG_MSG, "rum_m_unicst(): " MACSTR "\n", 203387c96ac5SQuaker Fang MAC2STR(macaddr)); 203487c96ac5SQuaker Fang 203587c96ac5SQuaker Fang IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr); 203687c96ac5SQuaker Fang (void) rum_set_macaddr(sc, (uint8_t *)macaddr); 203787c96ac5SQuaker Fang (void) rum_init(sc); 203887c96ac5SQuaker Fang 203987c96ac5SQuaker Fang return (0); 204087c96ac5SQuaker Fang } 204187c96ac5SQuaker Fang 204287c96ac5SQuaker Fang /*ARGSUSED*/ 204387c96ac5SQuaker Fang static int 204487c96ac5SQuaker Fang rum_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 204587c96ac5SQuaker Fang { 204687c96ac5SQuaker Fang return (0); 204787c96ac5SQuaker Fang } 204887c96ac5SQuaker Fang 204987c96ac5SQuaker Fang static int 205087c96ac5SQuaker Fang rum_m_promisc(void *arg, boolean_t on) 205187c96ac5SQuaker Fang { 205287c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)arg; 205387c96ac5SQuaker Fang 205487c96ac5SQuaker Fang if (on) { 205587c96ac5SQuaker Fang sc->sc_rcr |= RAL_RCR_PROMISC; 205687c96ac5SQuaker Fang sc->sc_rcr |= RAL_RCR_MULTI; 205787c96ac5SQuaker Fang } else { 205887c96ac5SQuaker Fang sc->sc_rcr &= ~RAL_RCR_PROMISC; 205987c96ac5SQuaker Fang sc->sc_rcr &= ~RAL_RCR_MULTI; 206087c96ac5SQuaker Fang } 206187c96ac5SQuaker Fang 206287c96ac5SQuaker Fang rum_update_promisc(sc); 206387c96ac5SQuaker Fang return (0); 206487c96ac5SQuaker Fang } 206587c96ac5SQuaker Fang 206687c96ac5SQuaker Fang /* 206787c96ac5SQuaker Fang * callback functions for /get/set properties 206887c96ac5SQuaker Fang */ 206987c96ac5SQuaker Fang static int 207087c96ac5SQuaker Fang rum_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 207187c96ac5SQuaker Fang uint_t wldp_length, const void *wldp_buf) 207287c96ac5SQuaker Fang { 207387c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)arg; 207487c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 207587c96ac5SQuaker Fang int err; 207687c96ac5SQuaker Fang 207787c96ac5SQuaker Fang err = ieee80211_setprop(ic, pr_name, wldp_pr_num, 207887c96ac5SQuaker Fang wldp_length, wldp_buf); 207987c96ac5SQuaker Fang RAL_LOCK(sc); 208087c96ac5SQuaker Fang if (err == ENETRESET) { 208187c96ac5SQuaker Fang if (RAL_IS_RUNNING(sc)) { 208287c96ac5SQuaker Fang RAL_UNLOCK(sc); 208387c96ac5SQuaker Fang (void) rum_init(sc); 208487c96ac5SQuaker Fang (void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 208587c96ac5SQuaker Fang RAL_LOCK(sc); 208687c96ac5SQuaker Fang } 208787c96ac5SQuaker Fang err = 0; 208887c96ac5SQuaker Fang } 208987c96ac5SQuaker Fang RAL_UNLOCK(sc); 209087c96ac5SQuaker Fang 209187c96ac5SQuaker Fang return (err); 209287c96ac5SQuaker Fang } 209387c96ac5SQuaker Fang 209487c96ac5SQuaker Fang static int 209587c96ac5SQuaker Fang rum_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2096*0dc2366fSVenugopal Iyer uint_t wldp_length, void *wldp_buf) 209787c96ac5SQuaker Fang { 209887c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)arg; 209987c96ac5SQuaker Fang int err; 210087c96ac5SQuaker Fang 210187c96ac5SQuaker Fang err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num, 2102*0dc2366fSVenugopal Iyer wldp_length, wldp_buf); 210387c96ac5SQuaker Fang 210487c96ac5SQuaker Fang return (err); 210587c96ac5SQuaker Fang } 210687c96ac5SQuaker Fang 210787c96ac5SQuaker Fang static void 2108*0dc2366fSVenugopal Iyer rum_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num, 2109*0dc2366fSVenugopal Iyer mac_prop_info_handle_t prh) 2110*0dc2366fSVenugopal Iyer { 2111*0dc2366fSVenugopal Iyer struct rum_softc *sc = (struct rum_softc *)arg; 2112*0dc2366fSVenugopal Iyer 2113*0dc2366fSVenugopal Iyer ieee80211_propinfo(&sc->sc_ic, pr_name, wldp_pr_num, prh); 2114*0dc2366fSVenugopal Iyer } 2115*0dc2366fSVenugopal Iyer 2116*0dc2366fSVenugopal Iyer static void 211787c96ac5SQuaker Fang rum_m_ioctl(void* arg, queue_t *wq, mblk_t *mp) 211887c96ac5SQuaker Fang { 211987c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)arg; 212087c96ac5SQuaker Fang struct ieee80211com *ic = &sc->sc_ic; 212187c96ac5SQuaker Fang int err; 212287c96ac5SQuaker Fang 212387c96ac5SQuaker Fang err = ieee80211_ioctl(ic, wq, mp); 212487c96ac5SQuaker Fang RAL_LOCK(sc); 212587c96ac5SQuaker Fang if (err == ENETRESET) { 212687c96ac5SQuaker Fang if (RAL_IS_RUNNING(sc)) { 212787c96ac5SQuaker Fang RAL_UNLOCK(sc); 212887c96ac5SQuaker Fang (void) rum_init(sc); 212987c96ac5SQuaker Fang (void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); 213087c96ac5SQuaker Fang RAL_LOCK(sc); 213187c96ac5SQuaker Fang } 213287c96ac5SQuaker Fang } 213387c96ac5SQuaker Fang RAL_UNLOCK(sc); 213487c96ac5SQuaker Fang } 213587c96ac5SQuaker Fang 213687c96ac5SQuaker Fang static int 213787c96ac5SQuaker Fang rum_m_stat(void *arg, uint_t stat, uint64_t *val) 213887c96ac5SQuaker Fang { 213987c96ac5SQuaker Fang struct rum_softc *sc = (struct rum_softc *)arg; 214087c96ac5SQuaker Fang ieee80211com_t *ic = &sc->sc_ic; 214187c96ac5SQuaker Fang ieee80211_node_t *ni; 214287c96ac5SQuaker Fang struct ieee80211_rateset *rs; 214387c96ac5SQuaker Fang 214487c96ac5SQuaker Fang RAL_LOCK(sc); 214587c96ac5SQuaker Fang 214687c96ac5SQuaker Fang ni = ic->ic_bss; 214787c96ac5SQuaker Fang rs = &ni->in_rates; 214887c96ac5SQuaker Fang 214987c96ac5SQuaker Fang switch (stat) { 215087c96ac5SQuaker Fang case MAC_STAT_IFSPEED: 215187c96ac5SQuaker Fang *val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ? 215287c96ac5SQuaker Fang (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL) 215387c96ac5SQuaker Fang : ic->ic_fixed_rate) * 500000ull; 215487c96ac5SQuaker Fang break; 215587c96ac5SQuaker Fang case MAC_STAT_NOXMTBUF: 215687c96ac5SQuaker Fang *val = sc->sc_tx_nobuf; 215787c96ac5SQuaker Fang break; 215887c96ac5SQuaker Fang case MAC_STAT_NORCVBUF: 215987c96ac5SQuaker Fang *val = sc->sc_rx_nobuf; 216087c96ac5SQuaker Fang break; 216187c96ac5SQuaker Fang case MAC_STAT_IERRORS: 216287c96ac5SQuaker Fang *val = sc->sc_rx_err; 216387c96ac5SQuaker Fang break; 216487c96ac5SQuaker Fang case MAC_STAT_RBYTES: 216587c96ac5SQuaker Fang *val = ic->ic_stats.is_rx_bytes; 216687c96ac5SQuaker Fang break; 216787c96ac5SQuaker Fang case MAC_STAT_IPACKETS: 216887c96ac5SQuaker Fang *val = ic->ic_stats.is_rx_frags; 216987c96ac5SQuaker Fang break; 217087c96ac5SQuaker Fang case MAC_STAT_OBYTES: 217187c96ac5SQuaker Fang *val = ic->ic_stats.is_tx_bytes; 217287c96ac5SQuaker Fang break; 217387c96ac5SQuaker Fang case MAC_STAT_OPACKETS: 217487c96ac5SQuaker Fang *val = ic->ic_stats.is_tx_frags; 217587c96ac5SQuaker Fang break; 217687c96ac5SQuaker Fang case MAC_STAT_OERRORS: 217787c96ac5SQuaker Fang case WIFI_STAT_TX_FAILED: 217887c96ac5SQuaker Fang *val = sc->sc_tx_err; 217987c96ac5SQuaker Fang break; 218087c96ac5SQuaker Fang case WIFI_STAT_TX_RETRANS: 218187c96ac5SQuaker Fang *val = sc->sc_tx_retries; 218287c96ac5SQuaker Fang break; 218387c96ac5SQuaker Fang case WIFI_STAT_FCS_ERRORS: 218487c96ac5SQuaker Fang case WIFI_STAT_WEP_ERRORS: 218587c96ac5SQuaker Fang case WIFI_STAT_TX_FRAGS: 218687c96ac5SQuaker Fang case WIFI_STAT_MCAST_TX: 218787c96ac5SQuaker Fang case WIFI_STAT_RTS_SUCCESS: 218887c96ac5SQuaker Fang case WIFI_STAT_RTS_FAILURE: 218987c96ac5SQuaker Fang case WIFI_STAT_ACK_FAILURE: 219087c96ac5SQuaker Fang case WIFI_STAT_RX_FRAGS: 219187c96ac5SQuaker Fang case WIFI_STAT_MCAST_RX: 219287c96ac5SQuaker Fang case WIFI_STAT_RX_DUPS: 219387c96ac5SQuaker Fang RAL_UNLOCK(sc); 219487c96ac5SQuaker Fang return (ieee80211_stat(ic, stat, val)); 219587c96ac5SQuaker Fang default: 219687c96ac5SQuaker Fang RAL_UNLOCK(sc); 219787c96ac5SQuaker Fang return (ENOTSUP); 219887c96ac5SQuaker Fang } 219987c96ac5SQuaker Fang RAL_UNLOCK(sc); 220087c96ac5SQuaker Fang 220187c96ac5SQuaker Fang return (0); 220287c96ac5SQuaker Fang } 220387c96ac5SQuaker Fang 220487c96ac5SQuaker Fang static int 220587c96ac5SQuaker Fang rum_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 220687c96ac5SQuaker Fang { 220787c96ac5SQuaker Fang struct rum_softc *sc; 220887c96ac5SQuaker Fang struct ieee80211com *ic; 220987c96ac5SQuaker Fang int err, i, ntries; 221087c96ac5SQuaker Fang uint32_t tmp; 221187c96ac5SQuaker Fang int instance; 221287c96ac5SQuaker Fang 221387c96ac5SQuaker Fang char strbuf[32]; 221487c96ac5SQuaker Fang 221587c96ac5SQuaker Fang wifi_data_t wd = { 0 }; 221687c96ac5SQuaker Fang mac_register_t *macp; 221787c96ac5SQuaker Fang 22181a932f2eSQuaker Fang switch (cmd) { 22191a932f2eSQuaker Fang case DDI_ATTACH: 22201a932f2eSQuaker Fang break; 22211a932f2eSQuaker Fang case DDI_RESUME: 22221a932f2eSQuaker Fang sc = ddi_get_soft_state(rum_soft_state_p, 22231a932f2eSQuaker Fang ddi_get_instance(devinfo)); 22241a932f2eSQuaker Fang ASSERT(sc != NULL); 22251a932f2eSQuaker Fang rum_resume(sc); 22261a932f2eSQuaker Fang return (DDI_SUCCESS); 22271a932f2eSQuaker Fang default: 222887c96ac5SQuaker Fang return (DDI_FAILURE); 22291a932f2eSQuaker Fang } 223087c96ac5SQuaker Fang 223187c96ac5SQuaker Fang instance = ddi_get_instance(devinfo); 223287c96ac5SQuaker Fang 223387c96ac5SQuaker Fang if (ddi_soft_state_zalloc(rum_soft_state_p, instance) != DDI_SUCCESS) { 22341a932f2eSQuaker Fang ral_debug(RAL_DBG_MSG, "rum_attach(): " 223587c96ac5SQuaker Fang "unable to alloc soft_state_p\n"); 223687c96ac5SQuaker Fang return (DDI_FAILURE); 223787c96ac5SQuaker Fang } 223887c96ac5SQuaker Fang 223987c96ac5SQuaker Fang sc = ddi_get_soft_state(rum_soft_state_p, instance); 224087c96ac5SQuaker Fang ic = (ieee80211com_t *)&sc->sc_ic; 224187c96ac5SQuaker Fang sc->sc_dev = devinfo; 224287c96ac5SQuaker Fang 224387c96ac5SQuaker Fang if (usb_client_attach(devinfo, USBDRV_VERSION, 0) != USB_SUCCESS) { 22441a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 224587c96ac5SQuaker Fang "rum_attach(): usb_client_attach failed\n"); 224687c96ac5SQuaker Fang goto fail1; 224787c96ac5SQuaker Fang } 224887c96ac5SQuaker Fang 224987c96ac5SQuaker Fang if (usb_get_dev_data(devinfo, &sc->sc_udev, 225087c96ac5SQuaker Fang USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) { 225187c96ac5SQuaker Fang sc->sc_udev = NULL; 225287c96ac5SQuaker Fang goto fail2; 225387c96ac5SQuaker Fang } 225487c96ac5SQuaker Fang 225587c96ac5SQuaker Fang mutex_init(&sc->sc_genlock, NULL, MUTEX_DRIVER, NULL); 225687c96ac5SQuaker Fang mutex_init(&sc->tx_lock, NULL, MUTEX_DRIVER, NULL); 225787c96ac5SQuaker Fang mutex_init(&sc->rx_lock, NULL, MUTEX_DRIVER, NULL); 225887c96ac5SQuaker Fang 225987c96ac5SQuaker Fang /* retrieve RT2573 rev. no */ 226087c96ac5SQuaker Fang for (ntries = 0; ntries < 1000; ntries++) { 226187c96ac5SQuaker Fang if ((tmp = rum_read(sc, RT2573_MAC_CSR0)) != 0) 226287c96ac5SQuaker Fang break; 226387c96ac5SQuaker Fang drv_usecwait(1000); 226487c96ac5SQuaker Fang } 226587c96ac5SQuaker Fang if (ntries == 1000) { 22661a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 226787c96ac5SQuaker Fang "rum_attach(): timeout waiting for chip to settle\n"); 226887c96ac5SQuaker Fang goto fail3; 226987c96ac5SQuaker Fang } 227087c96ac5SQuaker Fang 227187c96ac5SQuaker Fang /* retrieve MAC address and various other things from EEPROM */ 227287c96ac5SQuaker Fang rum_read_eeprom(sc); 227387c96ac5SQuaker Fang 22741a932f2eSQuaker Fang ral_debug(RAL_DBG_MSG, "rum: MAC/BBP RT2573 (rev 0x%05x), RF %s\n", 227587c96ac5SQuaker Fang tmp, rum_get_rf(sc->rf_rev)); 227687c96ac5SQuaker Fang 227787c96ac5SQuaker Fang err = rum_load_microcode(sc); 227887c96ac5SQuaker Fang if (err != USB_SUCCESS) { 22791a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "could not load 8051 microcode\n"); 228087c96ac5SQuaker Fang goto fail3; 228187c96ac5SQuaker Fang } 228287c96ac5SQuaker Fang 228387c96ac5SQuaker Fang ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ 228487c96ac5SQuaker Fang ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ 228587c96ac5SQuaker Fang ic->ic_state = IEEE80211_S_INIT; 228687c96ac5SQuaker Fang 228787c96ac5SQuaker Fang ic->ic_maxrssi = 63; 228887c96ac5SQuaker Fang ic->ic_set_shortslot = rum_update_slot; 228987c96ac5SQuaker Fang ic->ic_xmit = rum_send; 229087c96ac5SQuaker Fang 229187c96ac5SQuaker Fang /* set device capabilities */ 229287c96ac5SQuaker Fang ic->ic_caps = 229387c96ac5SQuaker Fang IEEE80211_C_TXPMGT | /* tx power management */ 229487c96ac5SQuaker Fang IEEE80211_C_SHPREAMBLE | /* short preamble supported */ 229587c96ac5SQuaker Fang IEEE80211_C_SHSLOT; /* short slot time supported */ 229687c96ac5SQuaker Fang 229787c96ac5SQuaker Fang ic->ic_caps |= IEEE80211_C_WPA; /* Support WPA/WPA2 */ 229887c96ac5SQuaker Fang 229987c96ac5SQuaker Fang #define IEEE80211_CHAN_A \ 230087c96ac5SQuaker Fang (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) 230187c96ac5SQuaker Fang 230287c96ac5SQuaker Fang if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_5226) { 230387c96ac5SQuaker Fang /* set supported .11a rates */ 230487c96ac5SQuaker Fang ic->ic_sup_rates[IEEE80211_MODE_11A] = rum_rateset_11a; 230587c96ac5SQuaker Fang 230687c96ac5SQuaker Fang /* set supported .11a channels */ 230787c96ac5SQuaker Fang for (i = 34; i <= 46; i += 4) { 230887c96ac5SQuaker Fang ic->ic_sup_channels[i].ich_freq = 230987c96ac5SQuaker Fang ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 231087c96ac5SQuaker Fang ic->ic_sup_channels[i].ich_flags = IEEE80211_CHAN_A; 231187c96ac5SQuaker Fang } 231287c96ac5SQuaker Fang for (i = 36; i <= 64; i += 4) { 231387c96ac5SQuaker Fang ic->ic_sup_channels[i].ich_freq = 231487c96ac5SQuaker Fang ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 231587c96ac5SQuaker Fang ic->ic_sup_channels[i].ich_flags = IEEE80211_CHAN_A; 231687c96ac5SQuaker Fang } 231787c96ac5SQuaker Fang for (i = 100; i <= 140; i += 4) { 231887c96ac5SQuaker Fang ic->ic_sup_channels[i].ich_freq = 231987c96ac5SQuaker Fang ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 232087c96ac5SQuaker Fang ic->ic_sup_channels[i].ich_flags = IEEE80211_CHAN_A; 232187c96ac5SQuaker Fang } 232287c96ac5SQuaker Fang for (i = 149; i <= 165; i += 4) { 232387c96ac5SQuaker Fang ic->ic_sup_channels[i].ich_freq = 232487c96ac5SQuaker Fang ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ); 232587c96ac5SQuaker Fang ic->ic_sup_channels[i].ich_flags = IEEE80211_CHAN_A; 232687c96ac5SQuaker Fang } 232787c96ac5SQuaker Fang } 232887c96ac5SQuaker Fang 232987c96ac5SQuaker Fang /* set supported .11b and .11g rates */ 233087c96ac5SQuaker Fang ic->ic_sup_rates[IEEE80211_MODE_11B] = rum_rateset_11b; 233187c96ac5SQuaker Fang ic->ic_sup_rates[IEEE80211_MODE_11G] = rum_rateset_11g; 233287c96ac5SQuaker Fang 233387c96ac5SQuaker Fang /* set supported .11b and .11g channels (1 through 14) */ 233487c96ac5SQuaker Fang for (i = 1; i <= 14; i++) { 233587c96ac5SQuaker Fang ic->ic_sup_channels[i].ich_freq = 233687c96ac5SQuaker Fang ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); 233787c96ac5SQuaker Fang ic->ic_sup_channels[i].ich_flags = 233887c96ac5SQuaker Fang IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | 233987c96ac5SQuaker Fang IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; 234087c96ac5SQuaker Fang } 234187c96ac5SQuaker Fang 234287c96ac5SQuaker Fang ieee80211_attach(ic); 234387c96ac5SQuaker Fang 234487c96ac5SQuaker Fang /* register WPA door */ 234587c96ac5SQuaker Fang ieee80211_register_door(ic, ddi_driver_name(devinfo), 234687c96ac5SQuaker Fang ddi_get_instance(devinfo)); 234787c96ac5SQuaker Fang 234887c96ac5SQuaker Fang /* override state transition machine */ 234987c96ac5SQuaker Fang sc->sc_newstate = ic->ic_newstate; 235087c96ac5SQuaker Fang ic->ic_newstate = rum_newstate; 235187c96ac5SQuaker Fang ic->ic_watchdog = rum_watchdog; 235287c96ac5SQuaker Fang ieee80211_media_init(ic); 235387c96ac5SQuaker Fang ic->ic_def_txkey = 0; 235487c96ac5SQuaker Fang 235587c96ac5SQuaker Fang sc->sc_rcr = 0; 235687c96ac5SQuaker Fang sc->dwelltime = 300; 23571a932f2eSQuaker Fang sc->sc_flags = 0; 235887c96ac5SQuaker Fang 235987c96ac5SQuaker Fang /* 236087c96ac5SQuaker Fang * Provide initial settings for the WiFi plugin; whenever this 236187c96ac5SQuaker Fang * information changes, we need to call mac_plugindata_update() 236287c96ac5SQuaker Fang */ 236387c96ac5SQuaker Fang wd.wd_opmode = ic->ic_opmode; 236487c96ac5SQuaker Fang wd.wd_secalloc = WIFI_SEC_NONE; 236587c96ac5SQuaker Fang IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid); 236687c96ac5SQuaker Fang 236787c96ac5SQuaker Fang if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 23681a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "rum_attach(): " 236987c96ac5SQuaker Fang "MAC version mismatch\n"); 237087c96ac5SQuaker Fang goto fail3; 237187c96ac5SQuaker Fang } 237287c96ac5SQuaker Fang 237387c96ac5SQuaker Fang macp->m_type_ident = MAC_PLUGIN_IDENT_WIFI; 237487c96ac5SQuaker Fang macp->m_driver = sc; 237587c96ac5SQuaker Fang macp->m_dip = devinfo; 237687c96ac5SQuaker Fang macp->m_src_addr = ic->ic_macaddr; 237787c96ac5SQuaker Fang macp->m_callbacks = &rum_m_callbacks; 237887c96ac5SQuaker Fang macp->m_min_sdu = 0; 237987c96ac5SQuaker Fang macp->m_max_sdu = IEEE80211_MTU; 238087c96ac5SQuaker Fang macp->m_pdata = &wd; 238187c96ac5SQuaker Fang macp->m_pdata_size = sizeof (wd); 238287c96ac5SQuaker Fang 238387c96ac5SQuaker Fang err = mac_register(macp, &ic->ic_mach); 238487c96ac5SQuaker Fang mac_free(macp); 238587c96ac5SQuaker Fang if (err != 0) { 23861a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "rum_attach(): " 238787c96ac5SQuaker Fang "mac_register() err %x\n", err); 238887c96ac5SQuaker Fang goto fail3; 238987c96ac5SQuaker Fang } 239087c96ac5SQuaker Fang 239187c96ac5SQuaker Fang if (usb_register_hotplug_cbs(devinfo, rum_disconnect, 239287c96ac5SQuaker Fang rum_reconnect) != USB_SUCCESS) { 23931a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, 239487c96ac5SQuaker Fang "rum_attach() failed to register events"); 239587c96ac5SQuaker Fang goto fail4; 239687c96ac5SQuaker Fang } 239787c96ac5SQuaker Fang 239887c96ac5SQuaker Fang /* 239987c96ac5SQuaker Fang * Create minor node of type DDI_NT_NET_WIFI 240087c96ac5SQuaker Fang */ 240187c96ac5SQuaker Fang (void) snprintf(strbuf, sizeof (strbuf), "%s%d", 240287c96ac5SQuaker Fang "rum", instance); 240387c96ac5SQuaker Fang err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR, 240487c96ac5SQuaker Fang instance + 1, DDI_NT_NET_WIFI, 0); 240587c96ac5SQuaker Fang 240687c96ac5SQuaker Fang if (err != DDI_SUCCESS) 24071a932f2eSQuaker Fang ral_debug(RAL_DBG_ERR, "ddi_create_minor_node() failed\n"); 240887c96ac5SQuaker Fang 240987c96ac5SQuaker Fang /* 241087c96ac5SQuaker Fang * Notify link is down now 241187c96ac5SQuaker Fang */ 241287c96ac5SQuaker Fang mac_link_update(ic->ic_mach, LINK_STATE_DOWN); 241387c96ac5SQuaker Fang return (DDI_SUCCESS); 241487c96ac5SQuaker Fang 241587c96ac5SQuaker Fang fail4: 241687c96ac5SQuaker Fang (void) mac_unregister(ic->ic_mach); 241787c96ac5SQuaker Fang fail3: 241887c96ac5SQuaker Fang mutex_destroy(&sc->sc_genlock); 241987c96ac5SQuaker Fang mutex_destroy(&sc->tx_lock); 242087c96ac5SQuaker Fang mutex_destroy(&sc->rx_lock); 242187c96ac5SQuaker Fang fail2: 242287c96ac5SQuaker Fang usb_client_detach(sc->sc_dev, sc->sc_udev); 242387c96ac5SQuaker Fang fail1: 242487c96ac5SQuaker Fang ddi_soft_state_free(rum_soft_state_p, ddi_get_instance(devinfo)); 242587c96ac5SQuaker Fang 242687c96ac5SQuaker Fang return (DDI_FAILURE); 242787c96ac5SQuaker Fang } 242887c96ac5SQuaker Fang 242987c96ac5SQuaker Fang static int 243087c96ac5SQuaker Fang rum_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 243187c96ac5SQuaker Fang { 243287c96ac5SQuaker Fang struct rum_softc *sc; 243387c96ac5SQuaker Fang 243487c96ac5SQuaker Fang sc = ddi_get_soft_state(rum_soft_state_p, ddi_get_instance(devinfo)); 24351a932f2eSQuaker Fang ASSERT(sc != NULL); 243687c96ac5SQuaker Fang 24371a932f2eSQuaker Fang switch (cmd) { 24381a932f2eSQuaker Fang case DDI_DETACH: 24391a932f2eSQuaker Fang break; 24401a932f2eSQuaker Fang case DDI_SUSPEND: 24411a932f2eSQuaker Fang if (RAL_IS_RUNNING(sc)) 24421a932f2eSQuaker Fang (void) rum_stop(sc); 24431a932f2eSQuaker Fang return (DDI_SUCCESS); 24441a932f2eSQuaker Fang default: 244587c96ac5SQuaker Fang return (DDI_FAILURE); 24461a932f2eSQuaker Fang } 244787c96ac5SQuaker Fang 244887c96ac5SQuaker Fang rum_stop(sc); 244987c96ac5SQuaker Fang usb_unregister_hotplug_cbs(devinfo); 245087c96ac5SQuaker Fang 245187c96ac5SQuaker Fang /* 245287c96ac5SQuaker Fang * Unregister from the MAC layer subsystem 245387c96ac5SQuaker Fang */ 245487c96ac5SQuaker Fang if (mac_unregister(sc->sc_ic.ic_mach) != 0) 245587c96ac5SQuaker Fang return (DDI_FAILURE); 245687c96ac5SQuaker Fang 245787c96ac5SQuaker Fang /* 245887c96ac5SQuaker Fang * detach ieee80211 layer 245987c96ac5SQuaker Fang */ 246087c96ac5SQuaker Fang ieee80211_detach(&sc->sc_ic); 246187c96ac5SQuaker Fang 246287c96ac5SQuaker Fang mutex_destroy(&sc->sc_genlock); 246387c96ac5SQuaker Fang mutex_destroy(&sc->tx_lock); 246487c96ac5SQuaker Fang mutex_destroy(&sc->rx_lock); 246587c96ac5SQuaker Fang 246687c96ac5SQuaker Fang /* pipes will be closed in rum_stop() */ 246787c96ac5SQuaker Fang usb_client_detach(devinfo, sc->sc_udev); 246887c96ac5SQuaker Fang sc->sc_udev = NULL; 246987c96ac5SQuaker Fang 247087c96ac5SQuaker Fang ddi_remove_minor_node(devinfo, NULL); 247187c96ac5SQuaker Fang ddi_soft_state_free(rum_soft_state_p, ddi_get_instance(devinfo)); 247287c96ac5SQuaker Fang 247387c96ac5SQuaker Fang return (DDI_SUCCESS); 247487c96ac5SQuaker Fang } 247587c96ac5SQuaker Fang 247687c96ac5SQuaker Fang int 247787c96ac5SQuaker Fang _info(struct modinfo *modinfop) 247887c96ac5SQuaker Fang { 247987c96ac5SQuaker Fang return (mod_info(&modlinkage, modinfop)); 248087c96ac5SQuaker Fang } 248187c96ac5SQuaker Fang 248287c96ac5SQuaker Fang int 248387c96ac5SQuaker Fang _init(void) 248487c96ac5SQuaker Fang { 248587c96ac5SQuaker Fang int status; 248687c96ac5SQuaker Fang 248787c96ac5SQuaker Fang status = ddi_soft_state_init(&rum_soft_state_p, 248887c96ac5SQuaker Fang sizeof (struct rum_softc), 1); 248987c96ac5SQuaker Fang if (status != 0) 249087c96ac5SQuaker Fang return (status); 249187c96ac5SQuaker Fang 249287c96ac5SQuaker Fang mac_init_ops(&rum_dev_ops, "rum"); 249387c96ac5SQuaker Fang status = mod_install(&modlinkage); 249487c96ac5SQuaker Fang if (status != 0) { 249587c96ac5SQuaker Fang mac_fini_ops(&rum_dev_ops); 249687c96ac5SQuaker Fang ddi_soft_state_fini(&rum_soft_state_p); 249787c96ac5SQuaker Fang } 249887c96ac5SQuaker Fang return (status); 249987c96ac5SQuaker Fang } 250087c96ac5SQuaker Fang 250187c96ac5SQuaker Fang int 250287c96ac5SQuaker Fang _fini(void) 250387c96ac5SQuaker Fang { 250487c96ac5SQuaker Fang int status; 250587c96ac5SQuaker Fang 250687c96ac5SQuaker Fang status = mod_remove(&modlinkage); 250787c96ac5SQuaker Fang if (status == 0) { 250887c96ac5SQuaker Fang mac_fini_ops(&rum_dev_ops); 250987c96ac5SQuaker Fang ddi_soft_state_fini(&rum_soft_state_p); 251087c96ac5SQuaker Fang } 251187c96ac5SQuaker Fang return (status); 251287c96ac5SQuaker Fang } 2513