xref: /illumos-gate/usr/src/uts/common/io/ural/ural.c (revision 0dc2366f)
140db2e2bSzf /*
2*0dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
340db2e2bSzf  * Use is subject to license terms.
440db2e2bSzf  */
540db2e2bSzf 
640db2e2bSzf /*
740db2e2bSzf  * Copyright (c) 2005, 2006
840db2e2bSzf  *	Damien Bergamini <damien.bergamini@free.fr>
940db2e2bSzf  *
1040db2e2bSzf  * Permission to use, copy, modify, and distribute this software for any
1140db2e2bSzf  * purpose with or without fee is hereby granted, provided that the above
1240db2e2bSzf  * copyright notice and this permission notice appear in all copies.
1340db2e2bSzf  *
1440db2e2bSzf  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1540db2e2bSzf  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1640db2e2bSzf  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1740db2e2bSzf  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1840db2e2bSzf  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1940db2e2bSzf  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2040db2e2bSzf  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2140db2e2bSzf  */
2240db2e2bSzf 
2340db2e2bSzf /*
2440db2e2bSzf  * Ralink Technology RT2500USB chipset driver
2540db2e2bSzf  * http://www.ralinktech.com/
2640db2e2bSzf  */
2740db2e2bSzf #include <sys/types.h>
2840db2e2bSzf #include <sys/cmn_err.h>
2940db2e2bSzf #include <sys/strsubr.h>
3040db2e2bSzf #include <sys/modctl.h>
3140db2e2bSzf #include <sys/devops.h>
32*0dc2366fSVenugopal Iyer #include <sys/byteorder.h>
33da14cebeSEric Cheng #include <sys/mac_provider.h>
3440db2e2bSzf #include <sys/mac_wifi.h>
3540db2e2bSzf #include <sys/net80211.h>
3640db2e2bSzf 
3740db2e2bSzf #define	USBDRV_MAJOR_VER	2
3840db2e2bSzf #define	USBDRV_MINOR_VER	0
3940db2e2bSzf #include <sys/usb/usba.h>
401a932f2eSQuaker Fang #include <sys/usb/usba/usba_types.h>
4140db2e2bSzf 
4240db2e2bSzf #include "ural_reg.h"
4340db2e2bSzf #include "ural_var.h"
4440db2e2bSzf 
4540db2e2bSzf static void *ural_soft_state_p = NULL;
4640db2e2bSzf 
4740db2e2bSzf #define	RAL_TXBUF_SIZE  	(IEEE80211_MAX_LEN)
4840db2e2bSzf #define	RAL_RXBUF_SIZE  	(IEEE80211_MAX_LEN)
4940db2e2bSzf 
5040db2e2bSzf /* quickly determine if a given rate is CCK or OFDM */
5140db2e2bSzf #define	RAL_RATE_IS_OFDM(rate)	((rate) >= 12 && (rate) != 22)
5240db2e2bSzf #define	RAL_ACK_SIZE		14	/* 10 + 4(FCS) */
5340db2e2bSzf #define	RAL_CTS_SIZE		14	/* 10 + 4(FCS) */
5440db2e2bSzf #define	RAL_SIFS		10	/* us */
5540db2e2bSzf #define	RAL_RXTX_TURNAROUND	5	/* us */
5640db2e2bSzf 
5740db2e2bSzf #define	URAL_N(a)		(sizeof (a) / sizeof ((a)[0]))
5840db2e2bSzf 
5940db2e2bSzf /*
6040db2e2bSzf  * Supported rates for 802.11a/b/g modes (in 500Kbps unit).
6140db2e2bSzf  */
6240db2e2bSzf static const struct ieee80211_rateset ural_rateset_11a =
6340db2e2bSzf 	{ 8, { 12, 18, 24, 36, 48, 72, 96, 108 } };
6440db2e2bSzf 
6540db2e2bSzf static const struct ieee80211_rateset ural_rateset_11b =
6640db2e2bSzf 	{ 4, { 2, 4, 11, 22 } };
6740db2e2bSzf 
6840db2e2bSzf static const struct ieee80211_rateset ural_rateset_11g =
6940db2e2bSzf 	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
7040db2e2bSzf 
7140db2e2bSzf /*
7240db2e2bSzf  * Default values for MAC registers; values taken from the reference driver.
7340db2e2bSzf  */
7440db2e2bSzf static const struct {
7540db2e2bSzf 	uint16_t	reg;
7640db2e2bSzf 	uint16_t	val;
7740db2e2bSzf } ural_def_mac[] = {
7840db2e2bSzf 	{ RAL_TXRX_CSR5,  0x8c8d },
7940db2e2bSzf 	{ RAL_TXRX_CSR6,  0x8b8a },
8040db2e2bSzf 	{ RAL_TXRX_CSR7,  0x8687 },
8140db2e2bSzf 	{ RAL_TXRX_CSR8,  0x0085 },
8240db2e2bSzf 	{ RAL_MAC_CSR13,  0x1111 },
8340db2e2bSzf 	{ RAL_MAC_CSR14,  0x1e11 },
8440db2e2bSzf 	{ RAL_TXRX_CSR21, 0xe78f },
8540db2e2bSzf 	{ RAL_MAC_CSR9,   0xff1d },
8640db2e2bSzf 	{ RAL_MAC_CSR11,  0x0002 },
8740db2e2bSzf 	{ RAL_MAC_CSR22,  0x0053 },
8840db2e2bSzf 	{ RAL_MAC_CSR15,  0x0000 },
8940db2e2bSzf 	{ RAL_MAC_CSR8,   0x0780 },
9040db2e2bSzf 	{ RAL_TXRX_CSR19, 0x0000 },
9140db2e2bSzf 	{ RAL_TXRX_CSR18, 0x005a },
9240db2e2bSzf 	{ RAL_PHY_CSR2,   0x0000 },
9340db2e2bSzf 	{ RAL_TXRX_CSR0,  0x1ec0 },
9440db2e2bSzf 	{ RAL_PHY_CSR4,   0x000f }
9540db2e2bSzf };
9640db2e2bSzf 
9740db2e2bSzf /*
9840db2e2bSzf  * Default values for BBP registers; values taken from the reference driver.
9940db2e2bSzf  */
10040db2e2bSzf static const struct {
10140db2e2bSzf 	uint8_t	reg;
10240db2e2bSzf 	uint8_t	val;
10340db2e2bSzf } ural_def_bbp[] = {
10440db2e2bSzf 	{  3, 0x02 },
10540db2e2bSzf 	{  4, 0x19 },
10640db2e2bSzf 	{ 14, 0x1c },
10740db2e2bSzf 	{ 15, 0x30 },
10840db2e2bSzf 	{ 16, 0xac },
10940db2e2bSzf 	{ 17, 0x48 },
11040db2e2bSzf 	{ 18, 0x18 },
11140db2e2bSzf 	{ 19, 0xff },
11240db2e2bSzf 	{ 20, 0x1e },
11340db2e2bSzf 	{ 21, 0x08 },
11440db2e2bSzf 	{ 22, 0x08 },
11540db2e2bSzf 	{ 23, 0x08 },
11640db2e2bSzf 	{ 24, 0x80 },
11740db2e2bSzf 	{ 25, 0x50 },
11840db2e2bSzf 	{ 26, 0x08 },
11940db2e2bSzf 	{ 27, 0x23 },
12040db2e2bSzf 	{ 30, 0x10 },
12140db2e2bSzf 	{ 31, 0x2b },
12240db2e2bSzf 	{ 32, 0xb9 },
12340db2e2bSzf 	{ 34, 0x12 },
12440db2e2bSzf 	{ 35, 0x50 },
12540db2e2bSzf 	{ 39, 0xc4 },
12640db2e2bSzf 	{ 40, 0x02 },
12740db2e2bSzf 	{ 41, 0x60 },
12840db2e2bSzf 	{ 53, 0x10 },
12940db2e2bSzf 	{ 54, 0x18 },
13040db2e2bSzf 	{ 56, 0x08 },
13140db2e2bSzf 	{ 57, 0x10 },
13240db2e2bSzf 	{ 58, 0x08 },
13340db2e2bSzf 	{ 61, 0x60 },
13440db2e2bSzf 	{ 62, 0x10 },
13540db2e2bSzf 	{ 75, 0xff }
13640db2e2bSzf };
13740db2e2bSzf 
13840db2e2bSzf /*
13940db2e2bSzf  * Default values for RF register R2 indexed by channel numbers.
14040db2e2bSzf  */
14140db2e2bSzf static const uint32_t ural_rf2522_r2[] = {
14240db2e2bSzf 	0x307f6, 0x307fb, 0x30800, 0x30805, 0x3080a, 0x3080f, 0x30814,
14340db2e2bSzf 	0x30819, 0x3081e, 0x30823, 0x30828, 0x3082d, 0x30832, 0x3083e
14440db2e2bSzf };
14540db2e2bSzf 
14640db2e2bSzf static const uint32_t ural_rf2523_r2[] = {
14740db2e2bSzf 	0x00327, 0x00328, 0x00329, 0x0032a, 0x0032b, 0x0032c, 0x0032d,
14840db2e2bSzf 	0x0032e, 0x0032f, 0x00340, 0x00341, 0x00342, 0x00343, 0x00346
14940db2e2bSzf };
15040db2e2bSzf 
15140db2e2bSzf static const uint32_t ural_rf2524_r2[] = {
15240db2e2bSzf 	0x00327, 0x00328, 0x00329, 0x0032a, 0x0032b, 0x0032c, 0x0032d,
15340db2e2bSzf 	0x0032e, 0x0032f, 0x00340, 0x00341, 0x00342, 0x00343, 0x00346
15440db2e2bSzf };
15540db2e2bSzf 
15640db2e2bSzf static const uint32_t ural_rf2525_r2[] = {
15740db2e2bSzf 	0x20327, 0x20328, 0x20329, 0x2032a, 0x2032b, 0x2032c, 0x2032d,
15840db2e2bSzf 	0x2032e, 0x2032f, 0x20340, 0x20341, 0x20342, 0x20343, 0x20346
15940db2e2bSzf };
16040db2e2bSzf 
16140db2e2bSzf static const uint32_t ural_rf2525_hi_r2[] = {
16240db2e2bSzf 	0x2032f, 0x20340, 0x20341, 0x20342, 0x20343, 0x20344, 0x20345,
16340db2e2bSzf 	0x20346, 0x20347, 0x20348, 0x20349, 0x2034a, 0x2034b, 0x2034e
16440db2e2bSzf };
16540db2e2bSzf 
16640db2e2bSzf static const uint32_t ural_rf2525e_r2[] = {
16740db2e2bSzf 	0x2044d, 0x2044e, 0x2044f, 0x20460, 0x20461, 0x20462, 0x20463,
16840db2e2bSzf 	0x20464, 0x20465, 0x20466, 0x20467, 0x20468, 0x20469, 0x2046b
16940db2e2bSzf };
17040db2e2bSzf 
17140db2e2bSzf static const uint32_t ural_rf2526_hi_r2[] = {
17240db2e2bSzf 	0x0022a, 0x0022b, 0x0022b, 0x0022c, 0x0022c, 0x0022d, 0x0022d,
17340db2e2bSzf 	0x0022e, 0x0022e, 0x0022f, 0x0022d, 0x00240, 0x00240, 0x00241
17440db2e2bSzf };
17540db2e2bSzf 
17640db2e2bSzf static const uint32_t ural_rf2526_r2[] = {
17740db2e2bSzf 	0x00226, 0x00227, 0x00227, 0x00228, 0x00228, 0x00229, 0x00229,
17840db2e2bSzf 	0x0022a, 0x0022a, 0x0022b, 0x0022b, 0x0022c, 0x0022c, 0x0022d
17940db2e2bSzf };
18040db2e2bSzf 
18140db2e2bSzf /*
18240db2e2bSzf  * For dual-band RF, RF registers R1 and R4 also depend on channel number;
18340db2e2bSzf  * values taken from the reference driver.
18440db2e2bSzf  */
18540db2e2bSzf static const struct {
18640db2e2bSzf 	uint8_t		chan;
18740db2e2bSzf 	uint32_t	r1;
18840db2e2bSzf 	uint32_t	r2;
18940db2e2bSzf 	uint32_t	r4;
19040db2e2bSzf } ural_rf5222[] = {
19140db2e2bSzf 	{   1, 0x08808, 0x0044d, 0x00282 },
19240db2e2bSzf 	{   2, 0x08808, 0x0044e, 0x00282 },
19340db2e2bSzf 	{   3, 0x08808, 0x0044f, 0x00282 },
19440db2e2bSzf 	{   4, 0x08808, 0x00460, 0x00282 },
19540db2e2bSzf 	{   5, 0x08808, 0x00461, 0x00282 },
19640db2e2bSzf 	{   6, 0x08808, 0x00462, 0x00282 },
19740db2e2bSzf 	{   7, 0x08808, 0x00463, 0x00282 },
19840db2e2bSzf 	{   8, 0x08808, 0x00464, 0x00282 },
19940db2e2bSzf 	{   9, 0x08808, 0x00465, 0x00282 },
20040db2e2bSzf 	{  10, 0x08808, 0x00466, 0x00282 },
20140db2e2bSzf 	{  11, 0x08808, 0x00467, 0x00282 },
20240db2e2bSzf 	{  12, 0x08808, 0x00468, 0x00282 },
20340db2e2bSzf 	{  13, 0x08808, 0x00469, 0x00282 },
20440db2e2bSzf 	{  14, 0x08808, 0x0046b, 0x00286 },
20540db2e2bSzf 
20640db2e2bSzf 	{  36, 0x08804, 0x06225, 0x00287 },
20740db2e2bSzf 	{  40, 0x08804, 0x06226, 0x00287 },
20840db2e2bSzf 	{  44, 0x08804, 0x06227, 0x00287 },
20940db2e2bSzf 	{  48, 0x08804, 0x06228, 0x00287 },
21040db2e2bSzf 	{  52, 0x08804, 0x06229, 0x00287 },
21140db2e2bSzf 	{  56, 0x08804, 0x0622a, 0x00287 },
21240db2e2bSzf 	{  60, 0x08804, 0x0622b, 0x00287 },
21340db2e2bSzf 	{  64, 0x08804, 0x0622c, 0x00287 },
21440db2e2bSzf 
21540db2e2bSzf 	{ 100, 0x08804, 0x02200, 0x00283 },
21640db2e2bSzf 	{ 104, 0x08804, 0x02201, 0x00283 },
21740db2e2bSzf 	{ 108, 0x08804, 0x02202, 0x00283 },
21840db2e2bSzf 	{ 112, 0x08804, 0x02203, 0x00283 },
21940db2e2bSzf 	{ 116, 0x08804, 0x02204, 0x00283 },
22040db2e2bSzf 	{ 120, 0x08804, 0x02205, 0x00283 },
22140db2e2bSzf 	{ 124, 0x08804, 0x02206, 0x00283 },
22240db2e2bSzf 	{ 128, 0x08804, 0x02207, 0x00283 },
22340db2e2bSzf 	{ 132, 0x08804, 0x02208, 0x00283 },
22440db2e2bSzf 	{ 136, 0x08804, 0x02209, 0x00283 },
22540db2e2bSzf 	{ 140, 0x08804, 0x0220a, 0x00283 },
22640db2e2bSzf 
22740db2e2bSzf 	{ 149, 0x08808, 0x02429, 0x00281 },
22840db2e2bSzf 	{ 153, 0x08808, 0x0242b, 0x00281 },
22940db2e2bSzf 	{ 157, 0x08808, 0x0242d, 0x00281 },
23040db2e2bSzf 	{ 161, 0x08808, 0x0242f, 0x00281 }
23140db2e2bSzf };
23240db2e2bSzf 
23340db2e2bSzf /*
23440db2e2bSzf  * device operations
23540db2e2bSzf  */
23640db2e2bSzf static int ural_attach(dev_info_t *, ddi_attach_cmd_t);
23740db2e2bSzf static int ural_detach(dev_info_t *, ddi_detach_cmd_t);
23840db2e2bSzf 
23940db2e2bSzf /*
24040db2e2bSzf  * Module Loading Data & Entry Points
24140db2e2bSzf  */
24240db2e2bSzf DDI_DEFINE_STREAM_OPS(ural_dev_ops, nulldev, nulldev, ural_attach,
2435644143aSQuaker Fang     ural_detach, nodev, NULL, D_MP, NULL, ddi_quiesce_not_needed);
24440db2e2bSzf 
24540db2e2bSzf static struct modldrv ural_modldrv = {
24640db2e2bSzf 	&mod_driverops,		/* Type of module.  This one is a driver */
2471a932f2eSQuaker Fang 	"ural driver v1.4",	/* short description */
24840db2e2bSzf 	&ural_dev_ops		/* driver specific ops */
24940db2e2bSzf };
25040db2e2bSzf 
25140db2e2bSzf static struct modlinkage modlinkage = {
25240db2e2bSzf 	MODREV_1,
25340db2e2bSzf 	(void *)&ural_modldrv,
25440db2e2bSzf 	NULL
25540db2e2bSzf };
25640db2e2bSzf 
25740db2e2bSzf static int	ural_m_stat(void *,  uint_t, uint64_t *);
25840db2e2bSzf static int	ural_m_start(void *);
25940db2e2bSzf static void	ural_m_stop(void *);
26040db2e2bSzf static int	ural_m_promisc(void *, boolean_t);
26140db2e2bSzf static int	ural_m_multicst(void *, boolean_t, const uint8_t *);
26240db2e2bSzf static int	ural_m_unicst(void *, const uint8_t *);
26340db2e2bSzf static mblk_t	*ural_m_tx(void *, mblk_t *);
26440db2e2bSzf static void	ural_m_ioctl(void *, queue_t *, mblk_t *);
2655644143aSQuaker Fang static int	ural_m_setprop(void *, const char *, mac_prop_id_t,
2665644143aSQuaker Fang     uint_t, const void *);
2675644143aSQuaker Fang static int	ural_m_getprop(void *, const char *, mac_prop_id_t,
268*0dc2366fSVenugopal Iyer     uint_t, void *);
269*0dc2366fSVenugopal Iyer static void	ural_m_propinfo(void *, const char *, mac_prop_id_t,
270*0dc2366fSVenugopal Iyer     mac_prop_info_handle_t);
27140db2e2bSzf 
27240db2e2bSzf static mac_callbacks_t ural_m_callbacks = {
273*0dc2366fSVenugopal Iyer 	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
27440db2e2bSzf 	ural_m_stat,
27540db2e2bSzf 	ural_m_start,
27640db2e2bSzf 	ural_m_stop,
27740db2e2bSzf 	ural_m_promisc,
27840db2e2bSzf 	ural_m_multicst,
27940db2e2bSzf 	ural_m_unicst,
28040db2e2bSzf 	ural_m_tx,
281*0dc2366fSVenugopal Iyer 	NULL,
28240db2e2bSzf 	ural_m_ioctl,
2835644143aSQuaker Fang 	NULL,		/* mc_getcapab */
2845644143aSQuaker Fang 	NULL,
2855644143aSQuaker Fang 	NULL,
2865644143aSQuaker Fang 	ural_m_setprop,
287*0dc2366fSVenugopal Iyer 	ural_m_getprop,
288*0dc2366fSVenugopal Iyer 	ural_m_propinfo
28940db2e2bSzf };
29040db2e2bSzf 
29140db2e2bSzf static void ural_amrr_start(struct ural_softc *, struct ieee80211_node *);
29240db2e2bSzf static int  ural_tx_trigger(struct ural_softc *, mblk_t *);
29340db2e2bSzf static int  ural_rx_trigger(struct ural_softc *);
29440db2e2bSzf 
29540db2e2bSzf uint32_t ural_dbg_flags = 0;
29640db2e2bSzf 
29740db2e2bSzf void
ral_debug(uint32_t dbg_flags,const int8_t * fmt,...)29840db2e2bSzf ral_debug(uint32_t dbg_flags, const int8_t *fmt, ...)
29940db2e2bSzf {
30040db2e2bSzf 	va_list args;
30140db2e2bSzf 
30240db2e2bSzf 	if (dbg_flags & ural_dbg_flags) {
30340db2e2bSzf 		va_start(args, fmt);
30440db2e2bSzf 		vcmn_err(CE_CONT, fmt, args);
30540db2e2bSzf 		va_end(args);
30640db2e2bSzf 	}
30740db2e2bSzf }
30840db2e2bSzf 
30940db2e2bSzf static uint16_t
ural_read(struct ural_softc * sc,uint16_t reg)31040db2e2bSzf ural_read(struct ural_softc *sc, uint16_t reg)
31140db2e2bSzf {
31240db2e2bSzf 	usb_ctrl_setup_t req;
31340db2e2bSzf 	usb_cr_t cr;
31440db2e2bSzf 	usb_cb_flags_t cf;
31540db2e2bSzf 	mblk_t *mp;
31640db2e2bSzf 	int err;
31740db2e2bSzf 	uint16_t val;
31840db2e2bSzf 
31940db2e2bSzf 	bzero(&req, sizeof (req));
32040db2e2bSzf 	req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_DEV_TO_HOST;
32140db2e2bSzf 	req.bRequest = RAL_READ_MAC;
32240db2e2bSzf 	req.wValue = 0;
32340db2e2bSzf 	req.wIndex = reg;
32440db2e2bSzf 	req.wLength = sizeof (uint16_t);
32540db2e2bSzf 
32640db2e2bSzf 	mp = NULL;
32740db2e2bSzf 	err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
32840db2e2bSzf 	    &cr, &cf, 0);
32940db2e2bSzf 
33040db2e2bSzf 	if (err != USB_SUCCESS) {
3311a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
33240db2e2bSzf 		    "ural_read(): could not read MAC register:"
33340db2e2bSzf 		    " cr:%s(%d), cf:(%x)\n",
33440db2e2bSzf 		    usb_str_cr(cr), cr, cf);
33540db2e2bSzf 		return (0);
33640db2e2bSzf 	}
33740db2e2bSzf 
33840db2e2bSzf 	bcopy(mp->b_rptr, &val, sizeof (uint16_t));
33940db2e2bSzf 
34040db2e2bSzf 	if (mp)
34140db2e2bSzf 		freemsg(mp);
34240db2e2bSzf 
34340db2e2bSzf 	return (LE_16(val));
34440db2e2bSzf }
34540db2e2bSzf 
34640db2e2bSzf static void
ural_read_multi(struct ural_softc * sc,uint16_t reg,void * buf,int len)34740db2e2bSzf ural_read_multi(struct ural_softc *sc, uint16_t reg, void *buf, int len)
34840db2e2bSzf {
34940db2e2bSzf 	usb_ctrl_setup_t req;
35040db2e2bSzf 	usb_cr_t cr;
35140db2e2bSzf 	usb_cb_flags_t cf;
35240db2e2bSzf 	mblk_t *mp;
35340db2e2bSzf 	int err;
35440db2e2bSzf 
35540db2e2bSzf 	bzero(&req, sizeof (req));
35640db2e2bSzf 	req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_DEV_TO_HOST;
35740db2e2bSzf 	req.bRequest = RAL_READ_MULTI_MAC;
35840db2e2bSzf 	req.wValue = 0;
35940db2e2bSzf 	req.wIndex = reg;
36040db2e2bSzf 	req.wLength = (uint16_t)len;
36140db2e2bSzf 	req.attrs = USB_ATTRS_AUTOCLEARING;
36240db2e2bSzf 
36340db2e2bSzf 	mp = NULL;
36440db2e2bSzf 	err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
36540db2e2bSzf 	    &cr, &cf, 0);
36640db2e2bSzf 
36740db2e2bSzf 	if (err != USB_SUCCESS) {
3681a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
36940db2e2bSzf 		    "ural_read_multi(): could not read MAC register:"
37040db2e2bSzf 		    "cr:%s(%d), cf:(%x)\n",
37140db2e2bSzf 		    usb_str_cr(cr), cr, cf);
37240db2e2bSzf 		return;
37340db2e2bSzf 	}
37440db2e2bSzf 
37540db2e2bSzf 	bcopy(mp->b_rptr, buf, len);
37640db2e2bSzf 
37740db2e2bSzf 	if (mp)
37840db2e2bSzf 		freemsg(mp);
37940db2e2bSzf }
38040db2e2bSzf 
38140db2e2bSzf static void
ural_write(struct ural_softc * sc,uint16_t reg,uint16_t val)38240db2e2bSzf ural_write(struct ural_softc *sc, uint16_t reg, uint16_t val)
38340db2e2bSzf {
38440db2e2bSzf 	usb_ctrl_setup_t req;
38540db2e2bSzf 	usb_cr_t cr;
38640db2e2bSzf 	usb_cb_flags_t cf;
38740db2e2bSzf 	int err;
38840db2e2bSzf 
38940db2e2bSzf 	bzero(&req, sizeof (req));
39040db2e2bSzf 	req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_HOST_TO_DEV;
39140db2e2bSzf 	req.bRequest = RAL_WRITE_MAC;
39240db2e2bSzf 	req.wValue = val;
39340db2e2bSzf 	req.wIndex = reg;
39440db2e2bSzf 	req.wLength = 0;
39540db2e2bSzf 	req.attrs = USB_ATTRS_NONE;
39640db2e2bSzf 
39740db2e2bSzf 	err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, NULL,
39840db2e2bSzf 	    &cr, &cf, 0);
39940db2e2bSzf 
40040db2e2bSzf 	if (err != USB_SUCCESS) {
4011a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
40240db2e2bSzf 		    "ural_write(): could not write MAC register:"
40340db2e2bSzf 		    "cr:%s(%d), cf:(%x)\n",
40440db2e2bSzf 		    usb_str_cr(cr), cr, cf);
40540db2e2bSzf 	}
40640db2e2bSzf }
40740db2e2bSzf 
40840db2e2bSzf /* ARGSUSED */
40940db2e2bSzf static void
ural_txeof(usb_pipe_handle_t pipe,usb_bulk_req_t * req)41040db2e2bSzf ural_txeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
41140db2e2bSzf {
41240db2e2bSzf 	struct ural_softc *sc = (struct ural_softc *)req->bulk_client_private;
41340db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
41440db2e2bSzf 
4151a932f2eSQuaker Fang 	ral_debug(RAL_DBG_TX,
41640db2e2bSzf 	    "ural_txeof(): cr:%s(%d), flags:0x%x, tx_queued:%d",
41740db2e2bSzf 	    usb_str_cr(req->bulk_completion_reason),
41840db2e2bSzf 	    req->bulk_completion_reason,
41940db2e2bSzf 	    req->bulk_cb_flags,
42040db2e2bSzf 	    sc->tx_queued);
42140db2e2bSzf 
42240db2e2bSzf 	if (req->bulk_completion_reason != USB_CR_OK)
42340db2e2bSzf 		sc->sc_tx_err++;
42440db2e2bSzf 
42540db2e2bSzf 	mutex_enter(&sc->tx_lock);
42640db2e2bSzf 
42740db2e2bSzf 	sc->tx_queued--;
42840db2e2bSzf 	sc->sc_tx_timer = 0;
42940db2e2bSzf 
43040db2e2bSzf 	if (sc->sc_need_sched) {
43140db2e2bSzf 		sc->sc_need_sched = 0;
43240db2e2bSzf 		mac_tx_update(ic->ic_mach);
43340db2e2bSzf 	}
43440db2e2bSzf 
43540db2e2bSzf 	mutex_exit(&sc->tx_lock);
43640db2e2bSzf 	usb_free_bulk_req(req);
43740db2e2bSzf }
43840db2e2bSzf 
43940db2e2bSzf /* ARGSUSED */
44040db2e2bSzf static void
ural_rxeof(usb_pipe_handle_t pipe,usb_bulk_req_t * req)44140db2e2bSzf ural_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
44240db2e2bSzf {
44340db2e2bSzf 	struct ural_softc *sc = (struct ural_softc *)req->bulk_client_private;
44440db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
44540db2e2bSzf 
44640db2e2bSzf 	struct ural_rx_desc *desc;
44740db2e2bSzf 	struct ieee80211_frame *wh;
44840db2e2bSzf 	struct ieee80211_node *ni;
44940db2e2bSzf 
45040db2e2bSzf 	mblk_t *m, *mp;
45140db2e2bSzf 	int len, pktlen;
45240db2e2bSzf 	char *rxbuf;
45340db2e2bSzf 
45440db2e2bSzf 	mp = req->bulk_data;
45540db2e2bSzf 	req->bulk_data = NULL;
45640db2e2bSzf 
4571a932f2eSQuaker Fang 	ral_debug(RAL_DBG_RX,
45840db2e2bSzf 	    "ural_rxeof(): cr:%s(%d), flags:0x%x, rx_queued:%d",
45940db2e2bSzf 	    usb_str_cr(req->bulk_completion_reason),
46040db2e2bSzf 	    req->bulk_completion_reason,
46140db2e2bSzf 	    req->bulk_cb_flags,
46240db2e2bSzf 	    sc->rx_queued);
46340db2e2bSzf 
46440db2e2bSzf 	if (req->bulk_completion_reason != USB_CR_OK) {
46540db2e2bSzf 		sc->sc_rx_err++;
46640db2e2bSzf 		goto fail;
46740db2e2bSzf 	}
46840db2e2bSzf 
46940db2e2bSzf 	len = (uintptr_t)mp->b_wptr - (uintptr_t)mp->b_rptr;
47040db2e2bSzf 	rxbuf = (char *)mp->b_rptr;
47140db2e2bSzf 
47240db2e2bSzf 	if (len < RAL_RX_DESC_SIZE + IEEE80211_MIN_LEN) {
4731a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
47440db2e2bSzf 		    "ural_rxeof(): xfer too short %d\n", len);
47540db2e2bSzf 		sc->sc_rx_err++;
47640db2e2bSzf 		goto fail;
47740db2e2bSzf 	}
47840db2e2bSzf 
47940db2e2bSzf 	/* rx descriptor is located at the end */
48040db2e2bSzf 	desc = (struct ural_rx_desc *)(rxbuf + len - RAL_RX_DESC_SIZE);
48140db2e2bSzf 
48240db2e2bSzf 	if ((LE_32(desc->flags) & RAL_RX_PHY_ERROR) ||
48340db2e2bSzf 	    (LE_32(desc->flags) & RAL_RX_CRC_ERROR)) {
48440db2e2bSzf 		/*
48540db2e2bSzf 		 * This should not happen since we did not request to receive
48640db2e2bSzf 		 * those frames when we filled RAL_TXRX_CSR2.
48740db2e2bSzf 		 */
4881a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "PHY or CRC error\n");
48940db2e2bSzf 		sc->sc_rx_err++;
49040db2e2bSzf 		goto fail;
49140db2e2bSzf 	}
49240db2e2bSzf 
49340db2e2bSzf 	pktlen = (LE_32(desc->flags) >> 16) & 0xfff;
49440db2e2bSzf 
49540db2e2bSzf 	if (pktlen > (len - RAL_RX_DESC_SIZE)) {
4961a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
49740db2e2bSzf 		    "ural_rxeof(): pktlen mismatch <%d, %d>.\n", pktlen, len);
49840db2e2bSzf 		goto fail;
49940db2e2bSzf 	}
50040db2e2bSzf 
50140db2e2bSzf 	/* Strip trailing 802.11 MAC FCS. */
50240db2e2bSzf 	pktlen -= IEEE80211_CRC_LEN;
50340db2e2bSzf 
50440db2e2bSzf 	if ((m = allocb(pktlen, BPRI_MED)) == NULL) {
5051a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
50640db2e2bSzf 		    "ural_rxeof(): allocate mblk failed.\n");
50740db2e2bSzf 		sc->sc_rx_nobuf++;
50840db2e2bSzf 		goto fail;
50940db2e2bSzf 	}
51040db2e2bSzf 
51140db2e2bSzf 	bcopy(rxbuf, m->b_rptr, pktlen);
51240db2e2bSzf 	m->b_wptr += pktlen;
51340db2e2bSzf 
51440db2e2bSzf 	wh = (struct ieee80211_frame *)m->b_rptr;
51540db2e2bSzf 	ni = ieee80211_find_rxnode(ic, wh);
51640db2e2bSzf 
51740db2e2bSzf 	/* send the frame to the 802.11 layer */
51840db2e2bSzf 	(void) ieee80211_input(ic, m, ni, desc->rssi, 0);
51940db2e2bSzf 
52040db2e2bSzf 	/* node is no longer needed */
52140db2e2bSzf 	ieee80211_free_node(ni);
52240db2e2bSzf fail:
52340db2e2bSzf 	mutex_enter(&sc->rx_lock);
52440db2e2bSzf 	sc->rx_queued--;
52540db2e2bSzf 	mutex_exit(&sc->rx_lock);
52640db2e2bSzf 
52740db2e2bSzf 	freemsg(mp);
52840db2e2bSzf 	usb_free_bulk_req(req);
52940db2e2bSzf 
53040db2e2bSzf 	if (RAL_IS_RUNNING(sc))
53140db2e2bSzf 		(void) ural_rx_trigger(sc);
53240db2e2bSzf }
53340db2e2bSzf 
53440db2e2bSzf /*
53540db2e2bSzf  * Return the expected ack rate for a frame transmitted at rate `rate'.
53640db2e2bSzf  * this should depend on the destination node basic rate set.
53740db2e2bSzf  */
53840db2e2bSzf static int
ural_ack_rate(struct ieee80211com * ic,int rate)53940db2e2bSzf ural_ack_rate(struct ieee80211com *ic, int rate)
54040db2e2bSzf {
54140db2e2bSzf 	switch (rate) {
54240db2e2bSzf 	/* CCK rates */
54340db2e2bSzf 	case 2:
54440db2e2bSzf 		return (2);
54540db2e2bSzf 	case 4:
54640db2e2bSzf 	case 11:
54740db2e2bSzf 	case 22:
54840db2e2bSzf 		return ((ic->ic_curmode == IEEE80211_MODE_11B) ? 4 : rate);
54940db2e2bSzf 
55040db2e2bSzf 	/* OFDM rates */
55140db2e2bSzf 	case 12:
55240db2e2bSzf 	case 18:
55340db2e2bSzf 		return (12);
55440db2e2bSzf 	case 24:
55540db2e2bSzf 	case 36:
55640db2e2bSzf 		return (24);
55740db2e2bSzf 	case 48:
55840db2e2bSzf 	case 72:
55940db2e2bSzf 	case 96:
56040db2e2bSzf 	case 108:
56140db2e2bSzf 		return (48);
56240db2e2bSzf 	}
56340db2e2bSzf 
56440db2e2bSzf 	/* default to 1Mbps */
56540db2e2bSzf 	return (2);
56640db2e2bSzf }
56740db2e2bSzf 
56840db2e2bSzf /*
56940db2e2bSzf  * Compute the duration (in us) needed to transmit `len' bytes at rate `rate'.
57040db2e2bSzf  * The function automatically determines the operating mode depending on the
57140db2e2bSzf  * given rate. `flags' indicates whether short preamble is in use or not.
57240db2e2bSzf  */
57340db2e2bSzf static uint16_t
ural_txtime(int len,int rate,uint32_t flags)57440db2e2bSzf ural_txtime(int len, int rate, uint32_t flags)
57540db2e2bSzf {
57640db2e2bSzf 	uint16_t txtime;
57740db2e2bSzf 
57840db2e2bSzf 	if (RAL_RATE_IS_OFDM(rate)) {
57940db2e2bSzf 		/* IEEE Std 802.11a-1999, pp. 37 */
58040db2e2bSzf 		txtime = (8 + 4 * len + 3 + rate - 1) / rate;
58140db2e2bSzf 		txtime = 16 + 4 + 4 * txtime + 6;
58240db2e2bSzf 	} else {
58340db2e2bSzf 		/* IEEE Std 802.11b-1999, pp. 28 */
58440db2e2bSzf 		txtime = (16 * len + rate - 1) / rate;
58540db2e2bSzf 		if (rate != 2 && (flags & IEEE80211_F_SHPREAMBLE))
58640db2e2bSzf 			txtime +=  72 + 24;
58740db2e2bSzf 		else
58840db2e2bSzf 			txtime += 144 + 48;
58940db2e2bSzf 	}
59040db2e2bSzf 	return (txtime);
59140db2e2bSzf }
59240db2e2bSzf 
59340db2e2bSzf static uint8_t
ural_plcp_signal(int rate)59440db2e2bSzf ural_plcp_signal(int rate)
59540db2e2bSzf {
59640db2e2bSzf 	switch (rate) {
59740db2e2bSzf 	/* CCK rates (returned values are device-dependent) */
59840db2e2bSzf 	case 2:		return (0x0);
59940db2e2bSzf 	case 4:		return (0x1);
60040db2e2bSzf 	case 11:	return (0x2);
60140db2e2bSzf 	case 22:	return (0x3);
60240db2e2bSzf 
60340db2e2bSzf 	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
60440db2e2bSzf 	case 12:	return (0xb);
60540db2e2bSzf 	case 18:	return (0xf);
60640db2e2bSzf 	case 24:	return (0xa);
60740db2e2bSzf 	case 36:	return (0xe);
60840db2e2bSzf 	case 48:	return (0x9);
60940db2e2bSzf 	case 72:	return (0xd);
61040db2e2bSzf 	case 96:	return (0x8);
61140db2e2bSzf 	case 108:	return (0xc);
61240db2e2bSzf 
61340db2e2bSzf 	/* unsupported rates (should not get there) */
61440db2e2bSzf 	default:	return (0xff);
61540db2e2bSzf 	}
61640db2e2bSzf }
61740db2e2bSzf 
61840db2e2bSzf static void
ural_setup_tx_desc(struct ural_softc * sc,struct ural_tx_desc * desc,uint32_t flags,int len,int rate)61940db2e2bSzf ural_setup_tx_desc(struct ural_softc *sc, struct ural_tx_desc *desc,
62040db2e2bSzf     uint32_t flags, int len, int rate)
62140db2e2bSzf {
62240db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
62340db2e2bSzf 	uint16_t plcp_length;
62440db2e2bSzf 	int remainder;
62540db2e2bSzf 
62640db2e2bSzf 	desc->flags = LE_32(flags);
62740db2e2bSzf 	desc->flags |= LE_32(RAL_TX_NEWSEQ);
62840db2e2bSzf 	desc->flags |= LE_32(len << 16);
62940db2e2bSzf 
63040db2e2bSzf 	desc->wme = LE_16(RAL_AIFSN(2) | RAL_LOGCWMIN(3) | RAL_LOGCWMAX(5));
63140db2e2bSzf 	desc->wme |= LE_16(RAL_IVOFFSET(sizeof (struct ieee80211_frame)));
63240db2e2bSzf 
63340db2e2bSzf 	/* setup PLCP fields */
63440db2e2bSzf 	desc->plcp_signal  = ural_plcp_signal(rate);
63540db2e2bSzf 	desc->plcp_service = 4;
63640db2e2bSzf 
63740db2e2bSzf 	len += IEEE80211_CRC_LEN;
63840db2e2bSzf 	if (RAL_RATE_IS_OFDM(rate)) {
63940db2e2bSzf 		desc->flags |= LE_32(RAL_TX_OFDM);
64040db2e2bSzf 
64140db2e2bSzf 		plcp_length = len & 0xfff;
64240db2e2bSzf 		desc->plcp_length_hi = plcp_length >> 6;
64340db2e2bSzf 		desc->plcp_length_lo = plcp_length & 0x3f;
64440db2e2bSzf 	} else {
64540db2e2bSzf 		plcp_length = (16 * len + rate - 1) / rate;
64640db2e2bSzf 		if (rate == 22) {
64740db2e2bSzf 			remainder = (16 * len) % 22;
64840db2e2bSzf 			if (remainder != 0 && remainder < 7)
64940db2e2bSzf 				desc->plcp_service |= RAL_PLCP_LENGEXT;
65040db2e2bSzf 		}
65140db2e2bSzf 		desc->plcp_length_hi = plcp_length >> 8;
65240db2e2bSzf 		desc->plcp_length_lo = plcp_length & 0xff;
65340db2e2bSzf 
65440db2e2bSzf 		if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
65540db2e2bSzf 			desc->plcp_signal |= 0x08;
65640db2e2bSzf 	}
65740db2e2bSzf 
65840db2e2bSzf 	desc->iv = 0;
65940db2e2bSzf 	desc->eiv = 0;
66040db2e2bSzf }
66140db2e2bSzf 
66240db2e2bSzf #define	RAL_TX_TIMEOUT		5
66340db2e2bSzf 
66440db2e2bSzf static int
ural_send(ieee80211com_t * ic,mblk_t * mp,uint8_t type)66540db2e2bSzf ural_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
66640db2e2bSzf {
66740db2e2bSzf 	struct ural_softc *sc = (struct ural_softc *)ic;
66840db2e2bSzf 	struct ural_tx_desc *desc;
66940db2e2bSzf 
67040db2e2bSzf 	struct ieee80211_frame *wh;
67140db2e2bSzf 	struct ieee80211_key *k;
67240db2e2bSzf 
67340db2e2bSzf 	uint16_t dur;
67440db2e2bSzf 	uint32_t flags = 0;
67540db2e2bSzf 	int rate, err = DDI_SUCCESS;
67640db2e2bSzf 
67740db2e2bSzf 	struct ieee80211_node *ni = NULL;
67840db2e2bSzf 	mblk_t *m, *m0;
67940db2e2bSzf 	int off, mblen, pktlen, xferlen;
68040db2e2bSzf 
6811a932f2eSQuaker Fang 	/* discard packets while suspending or not inited */
6821a932f2eSQuaker Fang 	if (!RAL_IS_RUNNING(sc)) {
6831a932f2eSQuaker Fang 		freemsg(mp);
6841a932f2eSQuaker Fang 		return (ENXIO);
6851a932f2eSQuaker Fang 	}
6861a932f2eSQuaker Fang 
68740db2e2bSzf 	mutex_enter(&sc->tx_lock);
68840db2e2bSzf 
68940db2e2bSzf 	if (sc->tx_queued > RAL_TX_LIST_COUNT) {
6901a932f2eSQuaker Fang 		ral_debug(RAL_DBG_TX, "ural_send(): "
69140db2e2bSzf 		    "no TX buffer available!\n");
69240db2e2bSzf 		if ((type & IEEE80211_FC0_TYPE_MASK) ==
69340db2e2bSzf 		    IEEE80211_FC0_TYPE_DATA) {
69440db2e2bSzf 			sc->sc_need_sched = 1;
69540db2e2bSzf 		}
69640db2e2bSzf 		sc->sc_tx_nobuf++;
69740db2e2bSzf 		err = ENOMEM;
69840db2e2bSzf 		goto fail;
69940db2e2bSzf 	}
70040db2e2bSzf 
70140db2e2bSzf 	m = allocb(RAL_TXBUF_SIZE + RAL_TX_DESC_SIZE, BPRI_MED);
70240db2e2bSzf 	if (m == NULL) {
7031a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "ural_send(): can't alloc mblk.\n");
70440db2e2bSzf 		err = DDI_FAILURE;
70540db2e2bSzf 		goto fail;
70640db2e2bSzf 	}
70740db2e2bSzf 
70840db2e2bSzf 	m->b_rptr += RAL_TX_DESC_SIZE;	/* skip TX descriptor */
70940db2e2bSzf 	m->b_wptr += RAL_TX_DESC_SIZE;
71040db2e2bSzf 
71140db2e2bSzf 	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
71240db2e2bSzf 		mblen = (uintptr_t)m0->b_wptr - (uintptr_t)m0->b_rptr;
71340db2e2bSzf 		(void) memcpy(m->b_rptr + off, m0->b_rptr, mblen);
71440db2e2bSzf 		off += mblen;
71540db2e2bSzf 	}
71640db2e2bSzf 	m->b_wptr += off;
71740db2e2bSzf 
71840db2e2bSzf 	wh = (struct ieee80211_frame *)m->b_rptr;
71940db2e2bSzf 
72040db2e2bSzf 	ni = ieee80211_find_txnode(ic, wh->i_addr1);
72140db2e2bSzf 	if (ni == NULL) {
72240db2e2bSzf 		err = DDI_FAILURE;
72340db2e2bSzf 		sc->sc_tx_err++;
72440db2e2bSzf 		freemsg(m);
72540db2e2bSzf 		goto fail;
72640db2e2bSzf 	}
72740db2e2bSzf 
72840db2e2bSzf 	if ((type & IEEE80211_FC0_TYPE_MASK) ==
72940db2e2bSzf 	    IEEE80211_FC0_TYPE_DATA) {
73040db2e2bSzf 		(void) ieee80211_encap(ic, m, ni);
73140db2e2bSzf 	}
73240db2e2bSzf 
73340db2e2bSzf 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
73440db2e2bSzf 		k = ieee80211_crypto_encap(ic, m);
73540db2e2bSzf 		if (k == NULL) {
73640db2e2bSzf 			sc->sc_tx_err++;
73740db2e2bSzf 			freemsg(m);
73840db2e2bSzf 			err = DDI_FAILURE;
73940db2e2bSzf 			goto fail;
74040db2e2bSzf 		}
74140db2e2bSzf 		/* packet header may have moved, reset our local pointer */
74240db2e2bSzf 		wh = (struct ieee80211_frame *)m->b_rptr;
74340db2e2bSzf 	}
74440db2e2bSzf 
74540db2e2bSzf 	m->b_rptr -= RAL_TX_DESC_SIZE;	/* restore */
74640db2e2bSzf 	desc = (struct ural_tx_desc *)m->b_rptr;
74740db2e2bSzf 
74840db2e2bSzf 	if ((type & IEEE80211_FC0_TYPE_MASK) ==
74940db2e2bSzf 	    IEEE80211_FC0_TYPE_DATA) {	/* DATA */
75040db2e2bSzf 		if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
75140db2e2bSzf 			rate = ic->ic_bss->in_rates.ir_rates[ic->ic_fixed_rate];
75240db2e2bSzf 		else
75340db2e2bSzf 			rate = ni->in_rates.ir_rates[ni->in_txrate];
75440db2e2bSzf 
75540db2e2bSzf 		rate &= IEEE80211_RATE_VAL;
75640db2e2bSzf 		if (rate <= 0) {
75740db2e2bSzf 			rate = 2;	/* basic rate */
75840db2e2bSzf 		}
75940db2e2bSzf 
76040db2e2bSzf 		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
76140db2e2bSzf 			flags |= RAL_TX_ACK;
76240db2e2bSzf 			flags |= RAL_TX_RETRY(7);
76340db2e2bSzf 
76440db2e2bSzf 			dur = ural_txtime(RAL_ACK_SIZE, ural_ack_rate(ic, rate),
76540db2e2bSzf 			    ic->ic_flags) + RAL_SIFS;
76640db2e2bSzf 			*(uint16_t *)(uintptr_t)wh->i_dur = LE_16(dur);
76740db2e2bSzf 		}
76840db2e2bSzf 	} else {	/* MGMT */
76940db2e2bSzf 		rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2;
77040db2e2bSzf 
77140db2e2bSzf 		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
77240db2e2bSzf 			flags |= RAL_TX_ACK;
77340db2e2bSzf 
77440db2e2bSzf 			dur = ural_txtime(RAL_ACK_SIZE, rate, ic->ic_flags)
77540db2e2bSzf 			    + RAL_SIFS;
77640db2e2bSzf 			*(uint16_t *)(uintptr_t)wh->i_dur = LE_16(dur);
77740db2e2bSzf 
77840db2e2bSzf 			/* tell hardware to add timestamp for probe responses */
77940db2e2bSzf 			if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
78040db2e2bSzf 			    IEEE80211_FC0_TYPE_MGT &&
78140db2e2bSzf 			    (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
78240db2e2bSzf 			    IEEE80211_FC0_SUBTYPE_PROBE_RESP)
78340db2e2bSzf 				flags |= RAL_TX_TIMESTAMP;
78440db2e2bSzf 		}
78540db2e2bSzf 	}
78640db2e2bSzf 
78740db2e2bSzf 	pktlen = (uintptr_t)m->b_wptr - (uintptr_t)m->b_rptr - RAL_TX_DESC_SIZE;
78840db2e2bSzf 	ural_setup_tx_desc(sc, desc, flags, pktlen, rate);
78940db2e2bSzf 
79040db2e2bSzf 	/* align end on a 2-bytes boundary */
79140db2e2bSzf 	xferlen = (RAL_TX_DESC_SIZE + pktlen + 1) & ~1;
79240db2e2bSzf 
79340db2e2bSzf 	/*
79440db2e2bSzf 	 * No space left in the last URB to store the extra 2 bytes, force
79540db2e2bSzf 	 * sending of another URB.
79640db2e2bSzf 	 */
79740db2e2bSzf 	if ((xferlen % 64) == 0)
79840db2e2bSzf 		xferlen += 2;
79940db2e2bSzf 
80040db2e2bSzf 	m->b_wptr = m->b_rptr + xferlen;
80140db2e2bSzf 
8021a932f2eSQuaker Fang 	ral_debug(RAL_DBG_TX, "sending data frame len=%u rate=%u xfer len=%u\n",
80340db2e2bSzf 	    pktlen, rate, xferlen);
80440db2e2bSzf 
80540db2e2bSzf 	(void) ural_tx_trigger(sc, m);
80640db2e2bSzf 
80740db2e2bSzf 	ic->ic_stats.is_tx_frags++;
80840db2e2bSzf 	ic->ic_stats.is_tx_bytes += pktlen;
80940db2e2bSzf 
81040db2e2bSzf fail:
81140db2e2bSzf 	if (ni != NULL)
81240db2e2bSzf 		ieee80211_free_node(ni);
81340db2e2bSzf 
81440db2e2bSzf 	if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA ||
81540db2e2bSzf 	    err == 0) {
81640db2e2bSzf 		freemsg(mp);
81740db2e2bSzf 	}
81840db2e2bSzf 
81940db2e2bSzf 	mutex_exit(&sc->tx_lock);
82040db2e2bSzf 
82140db2e2bSzf 	return (err);
82240db2e2bSzf }
82340db2e2bSzf 
82440db2e2bSzf static mblk_t *
ural_m_tx(void * arg,mblk_t * mp)82540db2e2bSzf ural_m_tx(void *arg, mblk_t *mp)
82640db2e2bSzf {
82740db2e2bSzf 	struct ural_softc *sc = (struct ural_softc *)arg;
82840db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
82940db2e2bSzf 	mblk_t *next;
83040db2e2bSzf 
83140db2e2bSzf 	/*
83240db2e2bSzf 	 * No data frames go out unless we're associated; this
83340db2e2bSzf 	 * should not happen as the 802.11 layer does not enable
83440db2e2bSzf 	 * the xmit queue until we enter the RUN state.
83540db2e2bSzf 	 */
83640db2e2bSzf 	if (ic->ic_state != IEEE80211_S_RUN) {
8371a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "ural_m_tx(): "
83840db2e2bSzf 		    "discard, state %u\n", ic->ic_state);
83940db2e2bSzf 		freemsgchain(mp);
84040db2e2bSzf 		return (NULL);
84140db2e2bSzf 	}
84240db2e2bSzf 
84340db2e2bSzf 	while (mp != NULL) {
84440db2e2bSzf 		next = mp->b_next;
84540db2e2bSzf 		mp->b_next = NULL;
84640db2e2bSzf 		if (ural_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != DDI_SUCCESS) {
84740db2e2bSzf 			mp->b_next = next;
84840db2e2bSzf 			freemsgchain(mp);
84940db2e2bSzf 			return (NULL);
85040db2e2bSzf 		}
85140db2e2bSzf 		mp = next;
85240db2e2bSzf 	}
85340db2e2bSzf 	return (mp);
85440db2e2bSzf }
85540db2e2bSzf 
85640db2e2bSzf static void
ural_set_testmode(struct ural_softc * sc)85740db2e2bSzf ural_set_testmode(struct ural_softc *sc)
85840db2e2bSzf {
85940db2e2bSzf 	usb_ctrl_setup_t req;
86040db2e2bSzf 	usb_cr_t cr;
86140db2e2bSzf 	usb_cb_flags_t cf;
86240db2e2bSzf 	int err;
86340db2e2bSzf 
86440db2e2bSzf 	bzero(&req, sizeof (req));
86540db2e2bSzf 	req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_HOST_TO_DEV;
86640db2e2bSzf 	req.bRequest = RAL_VENDOR_REQUEST;
86740db2e2bSzf 	req.wValue = 4;
86840db2e2bSzf 	req.wIndex = 1;
86940db2e2bSzf 	req.wLength = 0;
87040db2e2bSzf 	req.attrs = USB_ATTRS_NONE;
87140db2e2bSzf 
87240db2e2bSzf 	err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, NULL,
87340db2e2bSzf 	    &cr, &cf, 0);
87440db2e2bSzf 
87540db2e2bSzf 	if (err != USB_SUCCESS) {
8761a932f2eSQuaker Fang 		ral_debug(RAL_DBG_USB,
87740db2e2bSzf 		    "ural_set_testmode(): could not set test mode:"
87840db2e2bSzf 		    "cr:%s(%d), cf:%(x)\n",
87940db2e2bSzf 		    usb_str_cr(cr), cr, cf);
88040db2e2bSzf 	}
88140db2e2bSzf }
88240db2e2bSzf 
88340db2e2bSzf static void
ural_eeprom_read(struct ural_softc * sc,uint16_t addr,void * buf,int len)88440db2e2bSzf ural_eeprom_read(struct ural_softc *sc, uint16_t addr, void *buf, int len)
88540db2e2bSzf {
88640db2e2bSzf 	usb_ctrl_setup_t req;
88740db2e2bSzf 	usb_cr_t cr;
88840db2e2bSzf 	usb_cb_flags_t cf;
88940db2e2bSzf 	mblk_t *mp;
89040db2e2bSzf 	int err;
89140db2e2bSzf 
89240db2e2bSzf 	bzero(&req, sizeof (req));
89340db2e2bSzf 	req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_DEV_TO_HOST;
89440db2e2bSzf 	req.bRequest = RAL_READ_EEPROM;
89540db2e2bSzf 	req.wValue = 0;
89640db2e2bSzf 	req.wIndex = addr;
89740db2e2bSzf 	req.wLength = (uint16_t)len;
89840db2e2bSzf 
89940db2e2bSzf 	mp = NULL;
90040db2e2bSzf 	err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
90140db2e2bSzf 	    &cr, &cf, 0);
90240db2e2bSzf 
90340db2e2bSzf 	if (err != USB_SUCCESS) {
9041a932f2eSQuaker Fang 		ral_debug(RAL_DBG_USB,
90540db2e2bSzf 		    "ural_eeprom_read(): could not read EEPROM:"
90640db2e2bSzf 		    "cr:%s(%d), cf:(%x)\n",
90740db2e2bSzf 		    usb_str_cr(cr), cr, cf);
90840db2e2bSzf 		return;
90940db2e2bSzf 	}
91040db2e2bSzf 
91140db2e2bSzf 	bcopy(mp->b_rptr, buf, len);
91240db2e2bSzf 
91340db2e2bSzf 	if (mp)
91440db2e2bSzf 		freemsg(mp);
91540db2e2bSzf }
91640db2e2bSzf 
91740db2e2bSzf static void
ural_bbp_write(struct ural_softc * sc,uint8_t reg,uint8_t val)91840db2e2bSzf ural_bbp_write(struct ural_softc *sc, uint8_t reg, uint8_t val)
91940db2e2bSzf {
92040db2e2bSzf 	uint16_t tmp;
92140db2e2bSzf 	int ntries;
92240db2e2bSzf 
92340db2e2bSzf 	for (ntries = 0; ntries < 5; ntries++) {
92440db2e2bSzf 		if (!(ural_read(sc, RAL_PHY_CSR8) & RAL_BBP_BUSY))
92540db2e2bSzf 			break;
92640db2e2bSzf 	}
92740db2e2bSzf 	if (ntries == 5) {
9281a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
92940db2e2bSzf 		    "ural_bbp_write(): could not write to BBP\n");
93040db2e2bSzf 		return;
93140db2e2bSzf 	}
93240db2e2bSzf 
93340db2e2bSzf 	tmp = reg << 8 | val;
93440db2e2bSzf 	ural_write(sc, RAL_PHY_CSR7, tmp);
93540db2e2bSzf }
93640db2e2bSzf 
93740db2e2bSzf static uint8_t
ural_bbp_read(struct ural_softc * sc,uint8_t reg)93840db2e2bSzf ural_bbp_read(struct ural_softc *sc, uint8_t reg)
93940db2e2bSzf {
94040db2e2bSzf 	uint16_t val;
94140db2e2bSzf 	int ntries;
94240db2e2bSzf 
94340db2e2bSzf 	val = RAL_BBP_WRITE | reg << 8;
94440db2e2bSzf 	ural_write(sc, RAL_PHY_CSR7, val);
94540db2e2bSzf 
94640db2e2bSzf 	for (ntries = 0; ntries < 5; ntries++) {
94740db2e2bSzf 		if (!(ural_read(sc, RAL_PHY_CSR8) & RAL_BBP_BUSY))
94840db2e2bSzf 			break;
94940db2e2bSzf 	}
95040db2e2bSzf 	if (ntries == 5) {
9511a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "ural_bbp_read(): could not read BBP\n");
95240db2e2bSzf 		return (0);
95340db2e2bSzf 	}
95440db2e2bSzf 
95540db2e2bSzf 	return (ural_read(sc, RAL_PHY_CSR7) & 0xff);
95640db2e2bSzf }
95740db2e2bSzf 
95840db2e2bSzf static void
ural_rf_write(struct ural_softc * sc,uint8_t reg,uint32_t val)95940db2e2bSzf ural_rf_write(struct ural_softc *sc, uint8_t reg, uint32_t val)
96040db2e2bSzf {
96140db2e2bSzf 	uint32_t tmp;
96240db2e2bSzf 	int ntries;
96340db2e2bSzf 
96440db2e2bSzf 	for (ntries = 0; ntries < 5; ntries++) {
96540db2e2bSzf 		if (!(ural_read(sc, RAL_PHY_CSR10) & RAL_RF_LOBUSY))
96640db2e2bSzf 			break;
96740db2e2bSzf 	}
96840db2e2bSzf 	if (ntries == 5) {
9691a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
97040db2e2bSzf 		    "ural_rf_write(): could not write to RF\n");
97140db2e2bSzf 		return;
97240db2e2bSzf 	}
97340db2e2bSzf 
97440db2e2bSzf 	tmp = RAL_RF_BUSY | RAL_RF_20BIT | (val & 0xffff) << 2 | (reg & 0x3);
97540db2e2bSzf 	ural_write(sc, RAL_PHY_CSR9,  tmp & 0xffff);
97640db2e2bSzf 	ural_write(sc, RAL_PHY_CSR10, tmp >> 16);
97740db2e2bSzf 
97840db2e2bSzf 	/* remember last written value in sc */
97940db2e2bSzf 	sc->rf_regs[reg] = val;
98040db2e2bSzf 
9811a932f2eSQuaker Fang 	ral_debug(RAL_DBG_HW, "RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff);
98240db2e2bSzf }
98340db2e2bSzf 
98440db2e2bSzf /*
98540db2e2bSzf  * Disable RF auto-tuning.
98640db2e2bSzf  */
98740db2e2bSzf static void
ural_disable_rf_tune(struct ural_softc * sc)98840db2e2bSzf ural_disable_rf_tune(struct ural_softc *sc)
98940db2e2bSzf {
99040db2e2bSzf 	uint32_t tmp;
99140db2e2bSzf 
99240db2e2bSzf 	if (sc->rf_rev != RAL_RF_2523) {
99340db2e2bSzf 		tmp = sc->rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE;
99440db2e2bSzf 		ural_rf_write(sc, RAL_RF1, tmp);
99540db2e2bSzf 	}
99640db2e2bSzf 
99740db2e2bSzf 	tmp = sc->rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE;
99840db2e2bSzf 	ural_rf_write(sc, RAL_RF3, tmp);
99940db2e2bSzf 
10001a932f2eSQuaker Fang 	ral_debug(RAL_DBG_HW, "disabling RF autotune\n");
100140db2e2bSzf }
100240db2e2bSzf 
100340db2e2bSzf 
100440db2e2bSzf static void
ural_set_chan(struct ural_softc * sc,struct ieee80211_channel * c)100540db2e2bSzf ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
100640db2e2bSzf {
100740db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
100840db2e2bSzf 	uint8_t power, tmp;
100940db2e2bSzf 	uint_t i, chan;
101040db2e2bSzf 
101140db2e2bSzf 	chan = ieee80211_chan2ieee(ic, c);
101240db2e2bSzf 	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
101340db2e2bSzf 		return;
101440db2e2bSzf 
101540db2e2bSzf 	if (IEEE80211_IS_CHAN_2GHZ(c))
101640db2e2bSzf 		power = min(sc->txpow[chan - 1], 31);
101740db2e2bSzf 	else
101840db2e2bSzf 		power = 31;
101940db2e2bSzf 
102040db2e2bSzf 	/* adjust txpower using ifconfig settings */
102140db2e2bSzf 	power -= (100 - ic->ic_txpowlimit) / 8;
102240db2e2bSzf 
10231a932f2eSQuaker Fang 	ral_debug(RAL_DBG_HW, "setting channel to %u, txpower to %u\n",
102440db2e2bSzf 	    chan, power);
102540db2e2bSzf 
102640db2e2bSzf 	switch (sc->rf_rev) {
102740db2e2bSzf 	case RAL_RF_2522:
102840db2e2bSzf 		ural_rf_write(sc, RAL_RF1, 0x00814);
102940db2e2bSzf 		ural_rf_write(sc, RAL_RF2, ural_rf2522_r2[chan - 1]);
103040db2e2bSzf 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
103140db2e2bSzf 		break;
103240db2e2bSzf 
103340db2e2bSzf 	case RAL_RF_2523:
103440db2e2bSzf 		ural_rf_write(sc, RAL_RF1, 0x08804);
103540db2e2bSzf 		ural_rf_write(sc, RAL_RF2, ural_rf2523_r2[chan - 1]);
103640db2e2bSzf 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x38044);
103740db2e2bSzf 		ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
103840db2e2bSzf 		break;
103940db2e2bSzf 
104040db2e2bSzf 	case RAL_RF_2524:
104140db2e2bSzf 		ural_rf_write(sc, RAL_RF1, 0x0c808);
104240db2e2bSzf 		ural_rf_write(sc, RAL_RF2, ural_rf2524_r2[chan - 1]);
104340db2e2bSzf 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
104440db2e2bSzf 		ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
104540db2e2bSzf 		break;
104640db2e2bSzf 
104740db2e2bSzf 	case RAL_RF_2525:
104840db2e2bSzf 		ural_rf_write(sc, RAL_RF1, 0x08808);
104940db2e2bSzf 		ural_rf_write(sc, RAL_RF2, ural_rf2525_hi_r2[chan - 1]);
105040db2e2bSzf 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
105140db2e2bSzf 		ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
105240db2e2bSzf 
105340db2e2bSzf 		ural_rf_write(sc, RAL_RF1, 0x08808);
105440db2e2bSzf 		ural_rf_write(sc, RAL_RF2, ural_rf2525_r2[chan - 1]);
105540db2e2bSzf 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
105640db2e2bSzf 		ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
105740db2e2bSzf 		break;
105840db2e2bSzf 
105940db2e2bSzf 	case RAL_RF_2525E:
106040db2e2bSzf 		ural_rf_write(sc, RAL_RF1, 0x08808);
106140db2e2bSzf 		ural_rf_write(sc, RAL_RF2, ural_rf2525e_r2[chan - 1]);
106240db2e2bSzf 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
106340db2e2bSzf 		ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282);
106440db2e2bSzf 		break;
106540db2e2bSzf 
106640db2e2bSzf 	case RAL_RF_2526:
106740db2e2bSzf 		ural_rf_write(sc, RAL_RF2, ural_rf2526_hi_r2[chan - 1]);
106840db2e2bSzf 		ural_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381);
106940db2e2bSzf 		ural_rf_write(sc, RAL_RF1, 0x08804);
107040db2e2bSzf 
107140db2e2bSzf 		ural_rf_write(sc, RAL_RF2, ural_rf2526_r2[chan - 1]);
107240db2e2bSzf 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
107340db2e2bSzf 		ural_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381);
107440db2e2bSzf 		break;
107540db2e2bSzf 
107640db2e2bSzf 	/* dual-band RF */
107740db2e2bSzf 	case RAL_RF_5222:
107840db2e2bSzf 		for (i = 0; ural_rf5222[i].chan != chan; i++) {
107940db2e2bSzf 			if (i > URAL_N(ural_rf5222)) break;
108040db2e2bSzf 		}
108140db2e2bSzf 
108240db2e2bSzf 		ural_rf_write(sc, RAL_RF1, ural_rf5222[i].r1);
108340db2e2bSzf 		ural_rf_write(sc, RAL_RF2, ural_rf5222[i].r2);
108440db2e2bSzf 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
108540db2e2bSzf 		ural_rf_write(sc, RAL_RF4, ural_rf5222[i].r4);
108640db2e2bSzf 		break;
108740db2e2bSzf 	}
108840db2e2bSzf 
108940db2e2bSzf 	if (ic->ic_opmode != IEEE80211_M_MONITOR &&
109040db2e2bSzf 	    ic->ic_state != IEEE80211_S_SCAN) {
109140db2e2bSzf 		/* set Japan filter bit for channel 14 */
109240db2e2bSzf 		tmp = ural_bbp_read(sc, 70);
109340db2e2bSzf 
109440db2e2bSzf 		tmp &= ~RAL_JAPAN_FILTER;
109540db2e2bSzf 		if (chan == 14)
109640db2e2bSzf 			tmp |= RAL_JAPAN_FILTER;
109740db2e2bSzf 
109840db2e2bSzf 		ural_bbp_write(sc, 70, tmp);
109940db2e2bSzf 
110040db2e2bSzf 		/* clear CRC errs */
110140db2e2bSzf 		(void) ural_read(sc, RAL_STA_CSR0);
110240db2e2bSzf 
110340db2e2bSzf 		drv_usecwait(10000);
110440db2e2bSzf 		ural_disable_rf_tune(sc);
110540db2e2bSzf 	}
110640db2e2bSzf }
110740db2e2bSzf 
110840db2e2bSzf /*
110940db2e2bSzf  * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF
111040db2e2bSzf  * synchronization.
111140db2e2bSzf  */
111240db2e2bSzf static void
ural_enable_tsf_sync(struct ural_softc * sc)111340db2e2bSzf ural_enable_tsf_sync(struct ural_softc *sc)
111440db2e2bSzf {
111540db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
111640db2e2bSzf 	uint16_t logcwmin, preload, tmp;
111740db2e2bSzf 
111840db2e2bSzf 	/* first, disable TSF synchronization */
111940db2e2bSzf 	ural_write(sc, RAL_TXRX_CSR19, 0);
112040db2e2bSzf 
112140db2e2bSzf 	tmp = (16 * ic->ic_bss->in_intval) << 4;
112240db2e2bSzf 	ural_write(sc, RAL_TXRX_CSR18, tmp);
112340db2e2bSzf 
112440db2e2bSzf 	logcwmin = (ic->ic_opmode == IEEE80211_M_IBSS) ? 2 : 0;
112540db2e2bSzf 	preload = (ic->ic_opmode == IEEE80211_M_IBSS) ? 320 : 6;
112640db2e2bSzf 	tmp = logcwmin << 12 | preload;
112740db2e2bSzf 	ural_write(sc, RAL_TXRX_CSR20, tmp);
112840db2e2bSzf 
112940db2e2bSzf 	/* finally, enable TSF synchronization */
113040db2e2bSzf 	tmp = RAL_ENABLE_TSF | RAL_ENABLE_TBCN;
113140db2e2bSzf 	if (ic->ic_opmode == IEEE80211_M_STA)
113240db2e2bSzf 		tmp |= RAL_ENABLE_TSF_SYNC(1);
113340db2e2bSzf 	else
113440db2e2bSzf 		tmp |= RAL_ENABLE_TSF_SYNC(2) | RAL_ENABLE_BEACON_GENERATOR;
113540db2e2bSzf 	ural_write(sc, RAL_TXRX_CSR19, tmp);
113640db2e2bSzf 
11371a932f2eSQuaker Fang 	ral_debug(RAL_DBG_HW, "enabling TSF synchronization\n");
113840db2e2bSzf }
113940db2e2bSzf 
114040db2e2bSzf /*
114140db2e2bSzf  * This function can be called by ieee80211_set_shortslottime(). Refer to
114240db2e2bSzf  * IEEE Std 802.11-1999 pp. 85 to know how these values are computed.
114340db2e2bSzf  */
114440db2e2bSzf /* ARGSUSED */
114540db2e2bSzf static void
ural_update_slot(struct ieee80211com * ic,int onoff)114640db2e2bSzf ural_update_slot(struct ieee80211com *ic, int onoff)
114740db2e2bSzf {
114840db2e2bSzf 	struct ural_softc *sc = (struct ural_softc *)ic;
114940db2e2bSzf 	uint16_t slottime, sifs, eifs;
115040db2e2bSzf 
115140db2e2bSzf 	slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
115240db2e2bSzf 	/* slottime = (onoff ? 9 : 20); */
115340db2e2bSzf 
115440db2e2bSzf 	/*
115540db2e2bSzf 	 * These settings may sound a bit inconsistent but this is what the
115640db2e2bSzf 	 * reference driver does.
115740db2e2bSzf 	 */
115840db2e2bSzf 	if (ic->ic_curmode == IEEE80211_MODE_11B) {
115940db2e2bSzf 		sifs = 16 - RAL_RXTX_TURNAROUND;
116040db2e2bSzf 		eifs = 364;
116140db2e2bSzf 	} else {
116240db2e2bSzf 		sifs = 10 - RAL_RXTX_TURNAROUND;
116340db2e2bSzf 		eifs = 64;
116440db2e2bSzf 	}
116540db2e2bSzf 
116640db2e2bSzf 	ural_write(sc, RAL_MAC_CSR10, slottime);
116740db2e2bSzf 	ural_write(sc, RAL_MAC_CSR11, sifs);
116840db2e2bSzf 	ural_write(sc, RAL_MAC_CSR12, eifs);
116940db2e2bSzf }
117040db2e2bSzf 
117140db2e2bSzf static void
ural_set_txpreamble(struct ural_softc * sc)117240db2e2bSzf ural_set_txpreamble(struct ural_softc *sc)
117340db2e2bSzf {
117440db2e2bSzf 	uint16_t tmp;
117540db2e2bSzf 
117640db2e2bSzf 	tmp = ural_read(sc, RAL_TXRX_CSR10);
117740db2e2bSzf 
117840db2e2bSzf 	tmp &= ~RAL_SHORT_PREAMBLE;
117940db2e2bSzf 	if (sc->sc_ic.ic_flags & IEEE80211_F_SHPREAMBLE)
118040db2e2bSzf 		tmp |= RAL_SHORT_PREAMBLE;
118140db2e2bSzf 
118240db2e2bSzf 	ural_write(sc, RAL_TXRX_CSR10, tmp);
118340db2e2bSzf }
118440db2e2bSzf 
118540db2e2bSzf static void
ural_set_basicrates(struct ural_softc * sc)118640db2e2bSzf ural_set_basicrates(struct ural_softc *sc)
118740db2e2bSzf {
118840db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
118940db2e2bSzf 
119040db2e2bSzf 	/* update basic rate set */
119140db2e2bSzf 	if (ic->ic_curmode == IEEE80211_MODE_11B) {
119240db2e2bSzf 		/* 11b basic rates: 1, 2Mbps */
119340db2e2bSzf 		ural_write(sc, RAL_TXRX_CSR11, 0x3);
119440db2e2bSzf 	} else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->in_chan)) {
119540db2e2bSzf 		/* 11a basic rates: 6, 12, 24Mbps */
119640db2e2bSzf 		ural_write(sc, RAL_TXRX_CSR11, 0x150);
119740db2e2bSzf 	} else {
119840db2e2bSzf 		/* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */
119940db2e2bSzf 		ural_write(sc, RAL_TXRX_CSR11, 0x15f);
120040db2e2bSzf 	}
120140db2e2bSzf }
120240db2e2bSzf 
120340db2e2bSzf static void
ural_set_bssid(struct ural_softc * sc,uint8_t * bssid)120440db2e2bSzf ural_set_bssid(struct ural_softc *sc, uint8_t *bssid)
120540db2e2bSzf {
120640db2e2bSzf 	uint16_t tmp;
120740db2e2bSzf 
120840db2e2bSzf 	tmp = bssid[0] | bssid[1] << 8;
120940db2e2bSzf 	ural_write(sc, RAL_MAC_CSR5, tmp);
121040db2e2bSzf 
121140db2e2bSzf 	tmp = bssid[2] | bssid[3] << 8;
121240db2e2bSzf 	ural_write(sc, RAL_MAC_CSR6, tmp);
121340db2e2bSzf 
121440db2e2bSzf 	tmp = bssid[4] | bssid[5] << 8;
121540db2e2bSzf 	ural_write(sc, RAL_MAC_CSR7, tmp);
121640db2e2bSzf 
12171a932f2eSQuaker Fang 	ral_debug(RAL_DBG_HW, "setting BSSID to " MACSTR "\n", MAC2STR(bssid));
121840db2e2bSzf }
121940db2e2bSzf 
122040db2e2bSzf static void
ural_set_macaddr(struct ural_softc * sc,uint8_t * addr)122140db2e2bSzf ural_set_macaddr(struct ural_softc *sc, uint8_t *addr)
122240db2e2bSzf {
122340db2e2bSzf 	uint16_t tmp;
122440db2e2bSzf 
122540db2e2bSzf 	tmp = addr[0] | addr[1] << 8;
122640db2e2bSzf 	ural_write(sc, RAL_MAC_CSR2, tmp);
122740db2e2bSzf 
122840db2e2bSzf 	tmp = addr[2] | addr[3] << 8;
122940db2e2bSzf 	ural_write(sc, RAL_MAC_CSR3, tmp);
123040db2e2bSzf 
123140db2e2bSzf 	tmp = addr[4] | addr[5] << 8;
123240db2e2bSzf 	ural_write(sc, RAL_MAC_CSR4, tmp);
123340db2e2bSzf 
12341a932f2eSQuaker Fang 	ral_debug(RAL_DBG_HW,
123540db2e2bSzf 	    "setting MAC address to " MACSTR "\n", MAC2STR(addr));
123640db2e2bSzf }
123740db2e2bSzf 
123840db2e2bSzf static void
ural_update_promisc(struct ural_softc * sc)123940db2e2bSzf ural_update_promisc(struct ural_softc *sc)
124040db2e2bSzf {
124140db2e2bSzf 	uint32_t tmp;
124240db2e2bSzf 
124340db2e2bSzf 	tmp = ural_read(sc, RAL_TXRX_CSR2);
124440db2e2bSzf 
124540db2e2bSzf 	tmp &= ~RAL_DROP_NOT_TO_ME;
124640db2e2bSzf 	if (!(sc->sc_rcr & RAL_RCR_PROMISC))
124740db2e2bSzf 		tmp |= RAL_DROP_NOT_TO_ME;
124840db2e2bSzf 
124940db2e2bSzf 	ural_write(sc, RAL_TXRX_CSR2, tmp);
125040db2e2bSzf 
12511a932f2eSQuaker Fang 	ral_debug(RAL_DBG_HW, "%s promiscuous mode\n",
125240db2e2bSzf 	    (sc->sc_rcr & RAL_RCR_PROMISC) ?  "entering" : "leaving");
125340db2e2bSzf }
125440db2e2bSzf 
125540db2e2bSzf static const char *
ural_get_rf(int rev)125640db2e2bSzf ural_get_rf(int rev)
125740db2e2bSzf {
125840db2e2bSzf 	switch (rev) {
125940db2e2bSzf 	case RAL_RF_2522:	return ("RT2522");
126040db2e2bSzf 	case RAL_RF_2523:	return ("RT2523");
126140db2e2bSzf 	case RAL_RF_2524:	return ("RT2524");
126240db2e2bSzf 	case RAL_RF_2525:	return ("RT2525");
126340db2e2bSzf 	case RAL_RF_2525E:	return ("RT2525e");
126440db2e2bSzf 	case RAL_RF_2526:	return ("RT2526");
126540db2e2bSzf 	case RAL_RF_5222:	return ("RT5222");
126640db2e2bSzf 	default:		return ("unknown");
126740db2e2bSzf 	}
126840db2e2bSzf }
126940db2e2bSzf 
127040db2e2bSzf static void
ural_read_eeprom(struct ural_softc * sc)127140db2e2bSzf ural_read_eeprom(struct ural_softc *sc)
127240db2e2bSzf {
127340db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
127440db2e2bSzf 	uint16_t val;
127540db2e2bSzf 
127640db2e2bSzf 	ural_eeprom_read(sc, RAL_EEPROM_CONFIG0, &val, 2);
127740db2e2bSzf 	val = LE_16(val);
127840db2e2bSzf 	sc->rf_rev =   (val >> 11) & 0x7;
127940db2e2bSzf 	sc->hw_radio = (val >> 10) & 0x1;
128040db2e2bSzf 	sc->led_mode = (val >> 6)  & 0x7;
128140db2e2bSzf 	sc->rx_ant =   (val >> 4)  & 0x3;
128240db2e2bSzf 	sc->tx_ant =   (val >> 2)  & 0x3;
128340db2e2bSzf 	sc->nb_ant =   val & 0x3;
128440db2e2bSzf 
128540db2e2bSzf 	/* read MAC address */
128640db2e2bSzf 	ural_eeprom_read(sc, RAL_EEPROM_ADDRESS, ic->ic_macaddr, 6);
128740db2e2bSzf 
128840db2e2bSzf 	/* read default values for BBP registers */
128940db2e2bSzf 	ural_eeprom_read(sc, RAL_EEPROM_BBP_BASE, sc->bbp_prom, 2 * 16);
129040db2e2bSzf 
129140db2e2bSzf 	/* read Tx power for all b/g channels */
129240db2e2bSzf 	ural_eeprom_read(sc, RAL_EEPROM_TXPOWER, sc->txpow, 14);
129340db2e2bSzf }
129440db2e2bSzf 
129540db2e2bSzf static int
ural_bbp_init(struct ural_softc * sc)129640db2e2bSzf ural_bbp_init(struct ural_softc *sc)
129740db2e2bSzf {
129840db2e2bSzf 	int i, ntries;
129940db2e2bSzf 
130040db2e2bSzf 	/* wait for BBP to be ready */
130140db2e2bSzf 	for (ntries = 0; ntries < 100; ntries++) {
130240db2e2bSzf 		if (ural_bbp_read(sc, RAL_BBP_VERSION) != 0)
130340db2e2bSzf 			break;
130440db2e2bSzf 		drv_usecwait(1000);
130540db2e2bSzf 	}
130640db2e2bSzf 	if (ntries == 100) {
13071a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "timeout waiting for BBP\n");
130840db2e2bSzf 		return (EIO);
130940db2e2bSzf 	}
131040db2e2bSzf 
131140db2e2bSzf 	/* initialize BBP registers to default values */
131240db2e2bSzf 	for (i = 0; i < URAL_N(ural_def_bbp); i++)
131340db2e2bSzf 		ural_bbp_write(sc, ural_def_bbp[i].reg, ural_def_bbp[i].val);
131440db2e2bSzf 
131540db2e2bSzf 	return (0);
131640db2e2bSzf }
131740db2e2bSzf 
131840db2e2bSzf static void
ural_set_txantenna(struct ural_softc * sc,int antenna)131940db2e2bSzf ural_set_txantenna(struct ural_softc *sc, int antenna)
132040db2e2bSzf {
132140db2e2bSzf 	uint16_t tmp;
132240db2e2bSzf 	uint8_t tx;
132340db2e2bSzf 
132440db2e2bSzf 	tx = ural_bbp_read(sc, RAL_BBP_TX) & ~RAL_BBP_ANTMASK;
132540db2e2bSzf 	if (antenna == 1)
132640db2e2bSzf 		tx |= RAL_BBP_ANTA;
132740db2e2bSzf 	else if (antenna == 2)
132840db2e2bSzf 		tx |= RAL_BBP_ANTB;
132940db2e2bSzf 	else
133040db2e2bSzf 		tx |= RAL_BBP_DIVERSITY;
133140db2e2bSzf 
133240db2e2bSzf 	/* need to force I/Q flip for RF 2525e, 2526 and 5222 */
133340db2e2bSzf 	if (sc->rf_rev == RAL_RF_2525E || sc->rf_rev == RAL_RF_2526 ||
133440db2e2bSzf 	    sc->rf_rev == RAL_RF_5222)
133540db2e2bSzf 		tx |= RAL_BBP_FLIPIQ;
133640db2e2bSzf 
133740db2e2bSzf 	ural_bbp_write(sc, RAL_BBP_TX, tx);
133840db2e2bSzf 
133940db2e2bSzf 	/* update values in PHY_CSR5 and PHY_CSR6 */
134040db2e2bSzf 	tmp = ural_read(sc, RAL_PHY_CSR5) & ~0x7;
134140db2e2bSzf 	ural_write(sc, RAL_PHY_CSR5, tmp | (tx & 0x7));
134240db2e2bSzf 
134340db2e2bSzf 	tmp = ural_read(sc, RAL_PHY_CSR6) & ~0x7;
134440db2e2bSzf 	ural_write(sc, RAL_PHY_CSR6, tmp | (tx & 0x7));
134540db2e2bSzf }
134640db2e2bSzf 
134740db2e2bSzf static void
ural_set_rxantenna(struct ural_softc * sc,int antenna)134840db2e2bSzf ural_set_rxantenna(struct ural_softc *sc, int antenna)
134940db2e2bSzf {
135040db2e2bSzf 	uint8_t rx;
135140db2e2bSzf 
135240db2e2bSzf 	rx = ural_bbp_read(sc, RAL_BBP_RX) & ~RAL_BBP_ANTMASK;
135340db2e2bSzf 	if (antenna == 1)
135440db2e2bSzf 		rx |= RAL_BBP_ANTA;
135540db2e2bSzf 	else if (antenna == 2)
135640db2e2bSzf 		rx |= RAL_BBP_ANTB;
135740db2e2bSzf 	else
135840db2e2bSzf 		rx |= RAL_BBP_DIVERSITY;
135940db2e2bSzf 
136040db2e2bSzf 	/* need to force no I/Q flip for RF 2525e and 2526 */
136140db2e2bSzf 	if (sc->rf_rev == RAL_RF_2525E || sc->rf_rev == RAL_RF_2526)
136240db2e2bSzf 		rx &= ~RAL_BBP_FLIPIQ;
136340db2e2bSzf 
136440db2e2bSzf 	ural_bbp_write(sc, RAL_BBP_RX, rx);
136540db2e2bSzf }
136640db2e2bSzf 
136740db2e2bSzf /*
136840db2e2bSzf  * This function is called periodically (every 200ms) during scanning to
136940db2e2bSzf  * switch from one channel to another.
137040db2e2bSzf  */
137140db2e2bSzf static void
ural_next_scan(void * arg)137240db2e2bSzf ural_next_scan(void *arg)
137340db2e2bSzf {
137440db2e2bSzf 	struct ural_softc *sc = arg;
137540db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
137640db2e2bSzf 
137740db2e2bSzf 	if (ic->ic_state == IEEE80211_S_SCAN)
137840db2e2bSzf 		ieee80211_next_scan(ic);
137940db2e2bSzf }
138040db2e2bSzf 
138140db2e2bSzf static int
ural_newstate(struct ieee80211com * ic,enum ieee80211_state nstate,int arg)138240db2e2bSzf ural_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
138340db2e2bSzf {
138440db2e2bSzf 	struct ural_softc *sc = (struct ural_softc *)ic;
138540db2e2bSzf 	enum ieee80211_state ostate;
138640db2e2bSzf 	struct ieee80211_node *ni;
138740db2e2bSzf 	int err;
138840db2e2bSzf 
138940db2e2bSzf 	RAL_LOCK(sc);
139040db2e2bSzf 
139140db2e2bSzf 	ostate = ic->ic_state;
139240db2e2bSzf 
139340db2e2bSzf 	if (sc->sc_scan_id != 0) {
139440db2e2bSzf 		(void) untimeout(sc->sc_scan_id);
139540db2e2bSzf 		sc->sc_scan_id = 0;
139640db2e2bSzf 	}
139740db2e2bSzf 
139840db2e2bSzf 	if (sc->sc_amrr_id != 0) {
139940db2e2bSzf 		(void) untimeout(sc->sc_amrr_id);
140040db2e2bSzf 		sc->sc_amrr_id = 0;
140140db2e2bSzf 	}
140240db2e2bSzf 
140340db2e2bSzf 	switch (nstate) {
140440db2e2bSzf 	case IEEE80211_S_INIT:
140540db2e2bSzf 		if (ostate == IEEE80211_S_RUN) {
140640db2e2bSzf 			/* abort TSF synchronization */
140740db2e2bSzf 			ural_write(sc, RAL_TXRX_CSR19, 0);
140840db2e2bSzf 			/* force tx led to stop blinking */
140940db2e2bSzf 			ural_write(sc, RAL_MAC_CSR20, 0);
141040db2e2bSzf 		}
141140db2e2bSzf 		break;
141240db2e2bSzf 
141340db2e2bSzf 	case IEEE80211_S_SCAN:
141440db2e2bSzf 		ural_set_chan(sc, ic->ic_curchan);
141540db2e2bSzf 		sc->sc_scan_id = timeout(ural_next_scan, (void *)sc,
141640db2e2bSzf 		    drv_usectohz(sc->dwelltime * 1000));
141740db2e2bSzf 		break;
141840db2e2bSzf 
141940db2e2bSzf 	case IEEE80211_S_AUTH:
142040db2e2bSzf 		ural_set_chan(sc, ic->ic_curchan);
142140db2e2bSzf 		break;
142240db2e2bSzf 
142340db2e2bSzf 	case IEEE80211_S_ASSOC:
142440db2e2bSzf 		ural_set_chan(sc, ic->ic_curchan);
142540db2e2bSzf 		break;
142640db2e2bSzf 
142740db2e2bSzf 	case IEEE80211_S_RUN:
142840db2e2bSzf 		ural_set_chan(sc, ic->ic_curchan);
142940db2e2bSzf 
143040db2e2bSzf 		ni = ic->ic_bss;
143140db2e2bSzf 
143240db2e2bSzf 		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
143340db2e2bSzf 			ural_update_slot(ic, 1);
143440db2e2bSzf 			ural_set_txpreamble(sc);
143540db2e2bSzf 			ural_set_basicrates(sc);
143640db2e2bSzf 			ural_set_bssid(sc, ni->in_bssid);
143740db2e2bSzf 		}
143840db2e2bSzf 
143940db2e2bSzf 
144040db2e2bSzf 		/* make tx led blink on tx (controlled by ASIC) */
144140db2e2bSzf 		ural_write(sc, RAL_MAC_CSR20, 1);
144240db2e2bSzf 
144340db2e2bSzf 		if (ic->ic_opmode != IEEE80211_M_MONITOR)
144440db2e2bSzf 			ural_enable_tsf_sync(sc);
144540db2e2bSzf 
144640db2e2bSzf 		/* enable automatic rate adaptation in STA mode */
144740db2e2bSzf 		if (ic->ic_opmode == IEEE80211_M_STA &&
144840db2e2bSzf 		    ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
144940db2e2bSzf 			ural_amrr_start(sc, ni);
145040db2e2bSzf 
145140db2e2bSzf 		break;
145240db2e2bSzf 	}
145340db2e2bSzf 
145440db2e2bSzf 	RAL_UNLOCK(sc);
145540db2e2bSzf 
145640db2e2bSzf 	err = sc->sc_newstate(ic, nstate, arg);
145740db2e2bSzf 	/*
145840db2e2bSzf 	 * Finally, start any timers.
145940db2e2bSzf 	 */
146040db2e2bSzf 	if (nstate == IEEE80211_S_RUN)
146140db2e2bSzf 		ieee80211_start_watchdog(ic, 1);
146240db2e2bSzf 
146340db2e2bSzf 	return (err);
146440db2e2bSzf }
146540db2e2bSzf 
146640db2e2bSzf 
146740db2e2bSzf 
146840db2e2bSzf static void
ural_close_pipes(struct ural_softc * sc)146940db2e2bSzf ural_close_pipes(struct ural_softc *sc)
147040db2e2bSzf {
147140db2e2bSzf 	usb_flags_t flags = USB_FLAGS_SLEEP;
147240db2e2bSzf 
147340db2e2bSzf 	if (sc->sc_rx_pipeh != NULL) {
147440db2e2bSzf 		usb_pipe_reset(sc->sc_dev, sc->sc_rx_pipeh, flags, NULL, 0);
147540db2e2bSzf 		usb_pipe_close(sc->sc_dev, sc->sc_rx_pipeh, flags, NULL, 0);
147640db2e2bSzf 		sc->sc_rx_pipeh = NULL;
147740db2e2bSzf 	}
147840db2e2bSzf 
147940db2e2bSzf 	if (sc->sc_tx_pipeh != NULL) {
148040db2e2bSzf 		usb_pipe_reset(sc->sc_dev, sc->sc_tx_pipeh, flags, NULL, 0);
148140db2e2bSzf 		usb_pipe_close(sc->sc_dev, sc->sc_tx_pipeh, flags, NULL, 0);
148240db2e2bSzf 		sc->sc_tx_pipeh = NULL;
148340db2e2bSzf 	}
148440db2e2bSzf }
148540db2e2bSzf 
148640db2e2bSzf static int
ural_open_pipes(struct ural_softc * sc)148740db2e2bSzf ural_open_pipes(struct ural_softc *sc)
148840db2e2bSzf {
148940db2e2bSzf 	usb_ep_data_t *ep_node;
149040db2e2bSzf 	usb_pipe_policy_t policy;
149140db2e2bSzf 	int err;
149240db2e2bSzf 
149340db2e2bSzf 	ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0, 0,
149440db2e2bSzf 	    USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
149540db2e2bSzf 
149640db2e2bSzf 	bzero(&policy, sizeof (usb_pipe_policy_t));
149740db2e2bSzf 	policy.pp_max_async_reqs = RAL_TX_LIST_COUNT;
149840db2e2bSzf 
149940db2e2bSzf 	if ((err = usb_pipe_open(sc->sc_dev,
150040db2e2bSzf 	    &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP,
150140db2e2bSzf 	    &sc->sc_tx_pipeh)) != USB_SUCCESS) {
15021a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
150340db2e2bSzf 		    "ural_open_pipes(): %x failed to open tx pipe\n", err);
150440db2e2bSzf 		goto fail;
150540db2e2bSzf 	}
150640db2e2bSzf 
150740db2e2bSzf 	ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0, 0,
150840db2e2bSzf 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN);
150940db2e2bSzf 
151040db2e2bSzf 	bzero(&policy, sizeof (usb_pipe_policy_t));
151140db2e2bSzf 	policy.pp_max_async_reqs = RAL_RX_LIST_COUNT + 32;
151240db2e2bSzf 
151340db2e2bSzf 	if ((err = usb_pipe_open(sc->sc_dev,
151440db2e2bSzf 	    &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP,
151540db2e2bSzf 	    &sc->sc_rx_pipeh)) != USB_SUCCESS) {
15161a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
151740db2e2bSzf 		    "ural_open_pipes(): %x failed to open rx pipe\n", err);
151840db2e2bSzf 		goto fail;
151940db2e2bSzf 	}
152040db2e2bSzf 
152140db2e2bSzf 	return (USB_SUCCESS);
152240db2e2bSzf 
152340db2e2bSzf fail:
152440db2e2bSzf 	if (sc->sc_rx_pipeh != NULL) {
152540db2e2bSzf 		usb_pipe_close(sc->sc_dev, sc->sc_rx_pipeh,
152640db2e2bSzf 		    USB_FLAGS_SLEEP, NULL, 0);
152740db2e2bSzf 		sc->sc_rx_pipeh = NULL;
152840db2e2bSzf 	}
152940db2e2bSzf 
153040db2e2bSzf 	if (sc->sc_tx_pipeh != NULL) {
153140db2e2bSzf 		usb_pipe_close(sc->sc_dev, sc->sc_tx_pipeh,
153240db2e2bSzf 		    USB_FLAGS_SLEEP, NULL, 0);
153340db2e2bSzf 		sc->sc_tx_pipeh = NULL;
153440db2e2bSzf 	}
153540db2e2bSzf 
153640db2e2bSzf 	return (USB_FAILURE);
153740db2e2bSzf }
153840db2e2bSzf 
153940db2e2bSzf static int
ural_tx_trigger(struct ural_softc * sc,mblk_t * mp)154040db2e2bSzf ural_tx_trigger(struct ural_softc *sc, mblk_t *mp)
154140db2e2bSzf {
154240db2e2bSzf 	usb_bulk_req_t *req;
154340db2e2bSzf 	int err;
154440db2e2bSzf 
154540db2e2bSzf 	sc->sc_tx_timer = RAL_TX_TIMEOUT;
154640db2e2bSzf 
154740db2e2bSzf 	req = usb_alloc_bulk_req(sc->sc_dev, 0, USB_FLAGS_SLEEP);
154840db2e2bSzf 	if (req == NULL) {
15491a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
155040db2e2bSzf 		    "ural_tx_trigger(): failed to allocate req");
155140db2e2bSzf 		freemsg(mp);
155240db2e2bSzf 		return (-1);
155340db2e2bSzf 	}
155440db2e2bSzf 
155540db2e2bSzf 	req->bulk_len		= (uintptr_t)mp->b_wptr - (uintptr_t)mp->b_rptr;
155640db2e2bSzf 	req->bulk_data		= mp;
155740db2e2bSzf 	req->bulk_client_private = (usb_opaque_t)sc;
155840db2e2bSzf 	req->bulk_timeout	= RAL_TX_TIMEOUT;
155940db2e2bSzf 	req->bulk_attributes	= USB_ATTRS_AUTOCLEARING;
156040db2e2bSzf 	req->bulk_cb		= ural_txeof;
156140db2e2bSzf 	req->bulk_exc_cb	= ural_txeof;
156240db2e2bSzf 	req->bulk_completion_reason = 0;
156340db2e2bSzf 	req->bulk_cb_flags	= 0;
156440db2e2bSzf 
156540db2e2bSzf 	if ((err = usb_pipe_bulk_xfer(sc->sc_tx_pipeh, req, 0))
156640db2e2bSzf 	    != USB_SUCCESS) {
156740db2e2bSzf 
15681a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "ural_tx_trigger(): "
156940db2e2bSzf 		    "failed to do tx xfer, %d", err);
157040db2e2bSzf 		usb_free_bulk_req(req);
157140db2e2bSzf 		return (-1);
157240db2e2bSzf 	}
157340db2e2bSzf 
157440db2e2bSzf 	sc->tx_queued++;
157540db2e2bSzf 
157640db2e2bSzf 	return (0);
157740db2e2bSzf }
157840db2e2bSzf 
157940db2e2bSzf static int
ural_rx_trigger(struct ural_softc * sc)158040db2e2bSzf ural_rx_trigger(struct ural_softc *sc)
158140db2e2bSzf {
158240db2e2bSzf 	usb_bulk_req_t *req;
158340db2e2bSzf 	int err;
158440db2e2bSzf 
158540db2e2bSzf 	req = usb_alloc_bulk_req(sc->sc_dev, RAL_RXBUF_SIZE, USB_FLAGS_SLEEP);
158640db2e2bSzf 	if (req == NULL) {
15871a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
158840db2e2bSzf 		    "ural_rx_trigger(): failed to allocate req");
158940db2e2bSzf 		return (-1);
159040db2e2bSzf 	}
159140db2e2bSzf 
159240db2e2bSzf 	req->bulk_len		= RAL_RXBUF_SIZE;
159340db2e2bSzf 	req->bulk_client_private = (usb_opaque_t)sc;
159440db2e2bSzf 	req->bulk_timeout	= 0;
159540db2e2bSzf 	req->bulk_attributes	= USB_ATTRS_SHORT_XFER_OK
159640db2e2bSzf 	    | USB_ATTRS_AUTOCLEARING;
159740db2e2bSzf 	req->bulk_cb		= ural_rxeof;
159840db2e2bSzf 	req->bulk_exc_cb	= ural_rxeof;
159940db2e2bSzf 	req->bulk_completion_reason = 0;
160040db2e2bSzf 	req->bulk_cb_flags	= 0;
160140db2e2bSzf 
160240db2e2bSzf 	err = usb_pipe_bulk_xfer(sc->sc_rx_pipeh, req, 0);
160340db2e2bSzf 
160440db2e2bSzf 	if (err != USB_SUCCESS) {
16051a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "ural_rx_trigger(): "
160640db2e2bSzf 		    "failed to do rx xfer, %d", err);
160740db2e2bSzf 		usb_free_bulk_req(req);
160840db2e2bSzf 
160940db2e2bSzf 		return (-1);
161040db2e2bSzf 	}
161140db2e2bSzf 
161240db2e2bSzf 	mutex_enter(&sc->rx_lock);
161340db2e2bSzf 	sc->rx_queued++;
161440db2e2bSzf 	mutex_exit(&sc->rx_lock);
161540db2e2bSzf 
161640db2e2bSzf 	return (0);
161740db2e2bSzf }
161840db2e2bSzf 
161940db2e2bSzf static void
ural_init_tx_queue(struct ural_softc * sc)162040db2e2bSzf ural_init_tx_queue(struct ural_softc *sc)
162140db2e2bSzf {
162240db2e2bSzf 	sc->tx_queued = 0;
162340db2e2bSzf }
162440db2e2bSzf 
162540db2e2bSzf static int
ural_init_rx_queue(struct ural_softc * sc)162640db2e2bSzf ural_init_rx_queue(struct ural_softc *sc)
162740db2e2bSzf {
162840db2e2bSzf 	int	i;
162940db2e2bSzf 
163040db2e2bSzf 	sc->rx_queued = 0;
163140db2e2bSzf 
163240db2e2bSzf 	for (i = 0; i < RAL_RX_LIST_COUNT; i++) {
163340db2e2bSzf 		if (ural_rx_trigger(sc) != 0) {
163440db2e2bSzf 			return (USB_FAILURE);
163540db2e2bSzf 		}
163640db2e2bSzf 	}
163740db2e2bSzf 
163840db2e2bSzf 	return (USB_SUCCESS);
163940db2e2bSzf }
164040db2e2bSzf 
164140db2e2bSzf static void
ural_stop(struct ural_softc * sc)164240db2e2bSzf ural_stop(struct ural_softc *sc)
164340db2e2bSzf {
164440db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
164540db2e2bSzf 
164640db2e2bSzf 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
164740db2e2bSzf 	ieee80211_stop_watchdog(ic);	/* stop the watchdog */
164840db2e2bSzf 
164940db2e2bSzf 	RAL_LOCK(sc);
165040db2e2bSzf 
165140db2e2bSzf 	sc->sc_tx_timer = 0;
165240db2e2bSzf 	sc->sc_flags &= ~RAL_FLAG_RUNNING;	/* STOP */
165340db2e2bSzf 
165440db2e2bSzf 	/* disable Rx */
165540db2e2bSzf 	ural_write(sc, RAL_TXRX_CSR2, RAL_DISABLE_RX);
165640db2e2bSzf 
165740db2e2bSzf 	/* reset ASIC and BBP (but won't reset MAC registers!) */
165840db2e2bSzf 	ural_write(sc, RAL_MAC_CSR1, RAL_RESET_ASIC | RAL_RESET_BBP);
165940db2e2bSzf 	ural_write(sc, RAL_MAC_CSR1, 0);
166040db2e2bSzf 
166140db2e2bSzf 	ural_close_pipes(sc);
166240db2e2bSzf 
166340db2e2bSzf 	RAL_UNLOCK(sc);
166440db2e2bSzf }
166540db2e2bSzf 
166640db2e2bSzf static int
ural_init(struct ural_softc * sc)166740db2e2bSzf ural_init(struct ural_softc *sc)
166840db2e2bSzf {
166940db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
167040db2e2bSzf 	uint16_t tmp;
167140db2e2bSzf 	int i, ntries;
167240db2e2bSzf 
167340db2e2bSzf 	ural_set_testmode(sc);
167440db2e2bSzf 	ural_write(sc, 0x308, 0x00f0);	/* magic */
167540db2e2bSzf 
167640db2e2bSzf 	ural_stop(sc);
167740db2e2bSzf 
167840db2e2bSzf 	/* initialize MAC registers to default values */
167940db2e2bSzf 	for (i = 0; i < URAL_N(ural_def_mac); i++)
168040db2e2bSzf 		ural_write(sc, ural_def_mac[i].reg, ural_def_mac[i].val);
168140db2e2bSzf 
168240db2e2bSzf 	/* wait for BBP and RF to wake up (this can take a long time!) */
168340db2e2bSzf 	for (ntries = 0; ntries < 100; ntries++) {
168440db2e2bSzf 		tmp = ural_read(sc, RAL_MAC_CSR17);
168540db2e2bSzf 		if ((tmp & (RAL_BBP_AWAKE | RAL_RF_AWAKE)) ==
168640db2e2bSzf 		    (RAL_BBP_AWAKE | RAL_RF_AWAKE))
168740db2e2bSzf 			break;
168840db2e2bSzf 		drv_usecwait(1000);
168940db2e2bSzf 	}
169040db2e2bSzf 	if (ntries == 100) {
16911a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
169240db2e2bSzf 		    "ural_init(): timeout waiting for BBP/RF to wakeup\n");
169340db2e2bSzf 		goto fail;
169440db2e2bSzf 	}
169540db2e2bSzf 
169640db2e2bSzf 	/* we're ready! */
169740db2e2bSzf 	ural_write(sc, RAL_MAC_CSR1, RAL_HOST_READY);
169840db2e2bSzf 
169940db2e2bSzf 	/* set basic rate set (will be updated later) */
170040db2e2bSzf 	ural_write(sc, RAL_TXRX_CSR11, 0x15f);
170140db2e2bSzf 
170240db2e2bSzf 	if (ural_bbp_init(sc) != 0)
170340db2e2bSzf 		goto fail;
170440db2e2bSzf 
170540db2e2bSzf 	/* set default BSS channel */
170640db2e2bSzf 	ural_set_chan(sc, ic->ic_curchan);
170740db2e2bSzf 
170840db2e2bSzf 	/* clear statistic registers (STA_CSR0 to STA_CSR10) */
170940db2e2bSzf 	ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof (sc->sta));
171040db2e2bSzf 
171140db2e2bSzf 	ural_set_txantenna(sc, sc->tx_ant);
171240db2e2bSzf 	ural_set_rxantenna(sc, sc->rx_ant);
171340db2e2bSzf 
171440db2e2bSzf 	ural_set_macaddr(sc, ic->ic_macaddr);
171540db2e2bSzf 
171640db2e2bSzf 	if (ural_open_pipes(sc) != USB_SUCCESS) {
17171a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "ural_init(): "
171840db2e2bSzf 		    "could not open pipes.\n");
171940db2e2bSzf 		goto fail;
172040db2e2bSzf 	}
172140db2e2bSzf 
172240db2e2bSzf 	ural_init_tx_queue(sc);
172340db2e2bSzf 
172440db2e2bSzf 	if (ural_init_rx_queue(sc) != USB_SUCCESS)
172540db2e2bSzf 		goto fail;
172640db2e2bSzf 
172740db2e2bSzf 	/* kick Rx */
172840db2e2bSzf 	tmp = RAL_DROP_PHY | RAL_DROP_CRC;
172940db2e2bSzf 	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
173040db2e2bSzf 		tmp |= RAL_DROP_CTL | RAL_DROP_BAD_VERSION;
173140db2e2bSzf 		if (ic->ic_opmode != IEEE80211_M_HOSTAP)
173240db2e2bSzf 			tmp |= RAL_DROP_TODS;
173340db2e2bSzf 		if (!(sc->sc_rcr & RAL_RCR_PROMISC))
173440db2e2bSzf 			tmp |= RAL_DROP_NOT_TO_ME;
173540db2e2bSzf 	}
173640db2e2bSzf 	ural_write(sc, RAL_TXRX_CSR2, tmp);
173740db2e2bSzf 	sc->sc_flags |= RAL_FLAG_RUNNING;	/* RUNNING */
173840db2e2bSzf 
173940db2e2bSzf 	return (DDI_SUCCESS);
174040db2e2bSzf fail:
174140db2e2bSzf 	ural_stop(sc);
174240db2e2bSzf 	return (EIO);
174340db2e2bSzf }
174440db2e2bSzf 
174540db2e2bSzf static int
ural_disconnect(dev_info_t * devinfo)17461a932f2eSQuaker Fang ural_disconnect(dev_info_t *devinfo)
174740db2e2bSzf {
174840db2e2bSzf 	struct ural_softc *sc;
174940db2e2bSzf 	struct ieee80211com *ic;
175040db2e2bSzf 
175140db2e2bSzf 	/*
175240db2e2bSzf 	 * We can't call ural_stop() here, since the hardware is removed,
175340db2e2bSzf 	 * we can't access the register anymore.
175440db2e2bSzf 	 */
175540db2e2bSzf 	sc = ddi_get_soft_state(ural_soft_state_p, ddi_get_instance(devinfo));
17561a932f2eSQuaker Fang 	ASSERT(sc != NULL);
17571a932f2eSQuaker Fang 
17581a932f2eSQuaker Fang 	if (!RAL_IS_RUNNING(sc))	/* different device or not inited */
17591a932f2eSQuaker Fang 		return (DDI_SUCCESS);
176040db2e2bSzf 
17611a932f2eSQuaker Fang 	ic = &sc->sc_ic;
176240db2e2bSzf 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
176340db2e2bSzf 	ieee80211_stop_watchdog(ic);	/* stop the watchdog */
176440db2e2bSzf 
176540db2e2bSzf 	RAL_LOCK(sc);
176640db2e2bSzf 
176740db2e2bSzf 	sc->sc_tx_timer = 0;
176840db2e2bSzf 	sc->sc_flags &= ~RAL_FLAG_RUNNING;	/* STOP */
176940db2e2bSzf 
177040db2e2bSzf 	ural_close_pipes(sc);
177140db2e2bSzf 
177240db2e2bSzf 	RAL_UNLOCK(sc);
177340db2e2bSzf 
177440db2e2bSzf 	return (DDI_SUCCESS);
177540db2e2bSzf }
177640db2e2bSzf 
177740db2e2bSzf static int
ural_reconnect(dev_info_t * devinfo)17781a932f2eSQuaker Fang ural_reconnect(dev_info_t *devinfo)
177940db2e2bSzf {
178040db2e2bSzf 	struct ural_softc *sc;
178140db2e2bSzf 	int err;
178240db2e2bSzf 
178340db2e2bSzf 	sc = ddi_get_soft_state(ural_soft_state_p, ddi_get_instance(devinfo));
17841a932f2eSQuaker Fang 	ASSERT(sc != NULL);
17851a932f2eSQuaker Fang 
17861a932f2eSQuaker Fang 	/* check device changes after disconnect */
17871a932f2eSQuaker Fang 	if (usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1,
17881a932f2eSQuaker Fang 	    USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
17891a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "different device connected\n");
17901a932f2eSQuaker Fang 		return (DDI_FAILURE);
17911a932f2eSQuaker Fang 	}
17921a932f2eSQuaker Fang 
179340db2e2bSzf 	err = ural_init(sc);
179440db2e2bSzf 
179540db2e2bSzf 	return (err);
179640db2e2bSzf }
179740db2e2bSzf 
17981a932f2eSQuaker Fang static void
ural_resume(struct ural_softc * sc)17991a932f2eSQuaker Fang ural_resume(struct ural_softc *sc)
18001a932f2eSQuaker Fang {
18011a932f2eSQuaker Fang 	/* check device changes after suspend */
18021a932f2eSQuaker Fang 	if (usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1,
18031a932f2eSQuaker Fang 	    USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
18041a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "no or different device connected\n");
18051a932f2eSQuaker Fang 		return;
18061a932f2eSQuaker Fang 	}
18071a932f2eSQuaker Fang 
18081a932f2eSQuaker Fang 	(void) ural_init(sc);
18091a932f2eSQuaker Fang }
18101a932f2eSQuaker Fang 
181140db2e2bSzf #define	URAL_AMRR_MIN_SUCCESS_THRESHOLD	1
181240db2e2bSzf #define	URAL_AMRR_MAX_SUCCESS_THRESHOLD	10
181340db2e2bSzf 
181440db2e2bSzf /*
181540db2e2bSzf  * Naive implementation of the Adaptive Multi Rate Retry algorithm:
181640db2e2bSzf  * "IEEE 802.11 Rate Adaptation: A Practical Approach"
181740db2e2bSzf  * Mathieu Lacage, Hossein Manshaei, Thierry Turletti
181840db2e2bSzf  * INRIA Sophia - Projet Planete
181940db2e2bSzf  * http://www-sop.inria.fr/rapports/sophia/RR-5208.html
182040db2e2bSzf  *
182140db2e2bSzf  * This algorithm is particularly well suited for ural since it does not
182240db2e2bSzf  * require per-frame retry statistics.  Note however that since h/w does
182340db2e2bSzf  * not provide per-frame stats, we can't do per-node rate adaptation and
182440db2e2bSzf  * thus automatic rate adaptation is only enabled in STA operating mode.
182540db2e2bSzf  */
182640db2e2bSzf #define	is_success(amrr)	\
182740db2e2bSzf 	((amrr)->retrycnt < (amrr)->txcnt / 10)
182840db2e2bSzf #define	is_failure(amrr)	\
182940db2e2bSzf 	((amrr)->retrycnt > (amrr)->txcnt / 3)
183040db2e2bSzf #define	is_enough(amrr)		\
183140db2e2bSzf 	((amrr)->txcnt > 10)
183240db2e2bSzf #define	is_min_rate(ni)		\
183340db2e2bSzf 	((ni)->in_txrate == 0)
183440db2e2bSzf #define	is_max_rate(ni)		\
183540db2e2bSzf 	((ni)->in_txrate == (ni)->in_rates.ir_nrates - 1)
183640db2e2bSzf #define	increase_rate(ni)	\
183740db2e2bSzf 	((ni)->in_txrate++)
183840db2e2bSzf #define	decrease_rate(ni)	\
183940db2e2bSzf 	((ni)->in_txrate--)
184040db2e2bSzf #define	reset_cnt(amrr)	do {	\
184140db2e2bSzf 	(amrr)->txcnt = (amrr)->retrycnt = 0;	\
184240db2e2bSzf 	_NOTE(CONSTCOND)	\
184340db2e2bSzf } while (/* CONSTCOND */0)
184440db2e2bSzf 
184540db2e2bSzf static void
ural_ratectl(struct ural_amrr * amrr,struct ieee80211_node * ni)184640db2e2bSzf ural_ratectl(struct ural_amrr *amrr, struct ieee80211_node *ni)
184740db2e2bSzf {
184840db2e2bSzf 	int need_change = 0;
184940db2e2bSzf 
185040db2e2bSzf 	if (is_success(amrr) && is_enough(amrr)) {
185140db2e2bSzf 		amrr->success++;
185240db2e2bSzf 		if (amrr->success >= amrr->success_threshold &&
185340db2e2bSzf 		    !is_max_rate(ni)) {
185440db2e2bSzf 			amrr->recovery = 1;
185540db2e2bSzf 			amrr->success = 0;
185640db2e2bSzf 			increase_rate(ni);
185740db2e2bSzf 			need_change = 1;
185840db2e2bSzf 		} else {
185940db2e2bSzf 			amrr->recovery = 0;
186040db2e2bSzf 		}
186140db2e2bSzf 	} else if (is_failure(amrr)) {
186240db2e2bSzf 		amrr->success = 0;
186340db2e2bSzf 		if (!is_min_rate(ni)) {
186440db2e2bSzf 			if (amrr->recovery) {
186540db2e2bSzf 				amrr->success_threshold *= 2;
186640db2e2bSzf 				if (amrr->success_threshold >
186740db2e2bSzf 				    URAL_AMRR_MAX_SUCCESS_THRESHOLD)
186840db2e2bSzf 					amrr->success_threshold =
186940db2e2bSzf 					    URAL_AMRR_MAX_SUCCESS_THRESHOLD;
187040db2e2bSzf 			} else {
187140db2e2bSzf 				amrr->success_threshold =
187240db2e2bSzf 				    URAL_AMRR_MIN_SUCCESS_THRESHOLD;
187340db2e2bSzf 			}
187440db2e2bSzf 			decrease_rate(ni);
187540db2e2bSzf 			need_change = 1;
187640db2e2bSzf 		}
187740db2e2bSzf 		amrr->recovery = 0;	/* original paper was incorrect */
187840db2e2bSzf 	}
187940db2e2bSzf 
188040db2e2bSzf 	if (is_enough(amrr) || need_change)
188140db2e2bSzf 		reset_cnt(amrr);
188240db2e2bSzf }
188340db2e2bSzf 
188440db2e2bSzf static void
ural_amrr_timeout(void * arg)188540db2e2bSzf ural_amrr_timeout(void *arg)
188640db2e2bSzf {
188740db2e2bSzf 	struct ural_softc *sc = (struct ural_softc *)arg;
188840db2e2bSzf 	struct ural_amrr *amrr = &sc->amrr;
188940db2e2bSzf 
189040db2e2bSzf 	ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof (sc->sta));
189140db2e2bSzf 
189240db2e2bSzf 	/* count TX retry-fail as Tx errors */
189340db2e2bSzf 	sc->sc_tx_err += sc->sta[9];
189440db2e2bSzf 	sc->sc_tx_retries += (sc->sta[7] + sc->sta[8]);
189540db2e2bSzf 
189640db2e2bSzf 	amrr->retrycnt =
189740db2e2bSzf 	    sc->sta[7] +	/* TX one-retry ok count */
189840db2e2bSzf 	    sc->sta[8] +	/* TX more-retry ok count */
189940db2e2bSzf 	    sc->sta[9];		/* TX retry-fail count */
190040db2e2bSzf 
190140db2e2bSzf 	amrr->txcnt =
190240db2e2bSzf 	    amrr->retrycnt +
190340db2e2bSzf 	    sc->sta[6];		/* TX no-retry ok count */
190440db2e2bSzf 
190540db2e2bSzf 	ural_ratectl(amrr, sc->sc_ic.ic_bss);
190640db2e2bSzf 
190740db2e2bSzf 	sc->sc_amrr_id = timeout(ural_amrr_timeout, (void *)sc,
190840db2e2bSzf 	    drv_usectohz(1000 * 1000)); /* 1 second */
190940db2e2bSzf }
191040db2e2bSzf 
191140db2e2bSzf 
191240db2e2bSzf static void
ural_amrr_start(struct ural_softc * sc,struct ieee80211_node * ni)191340db2e2bSzf ural_amrr_start(struct ural_softc *sc, struct ieee80211_node *ni)
191440db2e2bSzf {
191540db2e2bSzf 	struct ural_amrr *amrr = &sc->amrr;
191640db2e2bSzf 	int i;
191740db2e2bSzf 
191840db2e2bSzf 	/* clear statistic registers (STA_CSR0 to STA_CSR10) */
191940db2e2bSzf 	ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof (sc->sta));
192040db2e2bSzf 
192140db2e2bSzf 	amrr->success = 0;
192240db2e2bSzf 	amrr->recovery = 0;
192340db2e2bSzf 	amrr->txcnt = amrr->retrycnt = 0;
192440db2e2bSzf 	amrr->success_threshold = URAL_AMRR_MIN_SUCCESS_THRESHOLD;
192540db2e2bSzf 
192640db2e2bSzf 	/* set rate to some reasonable initial value */
192740db2e2bSzf 	for (i = ni->in_rates.ir_nrates - 1;
192840db2e2bSzf 	    i > 0 && (ni->in_rates.ir_rates[i] & IEEE80211_RATE_VAL) > 72;
192940db2e2bSzf 	    i--) {
193040db2e2bSzf 	}
193140db2e2bSzf 
193240db2e2bSzf 	ni->in_txrate = i;
193340db2e2bSzf 
193440db2e2bSzf 	sc->sc_amrr_id = timeout(ural_amrr_timeout, (void *)sc,
193540db2e2bSzf 	    drv_usectohz(1000 * 1000)); /* 1 second */
193640db2e2bSzf }
193740db2e2bSzf 
193840db2e2bSzf void
ural_watchdog(void * arg)193940db2e2bSzf ural_watchdog(void *arg)
194040db2e2bSzf {
194140db2e2bSzf 	struct ural_softc *sc = arg;
194240db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
194340db2e2bSzf 	int ntimer = 0;
194440db2e2bSzf 
194540db2e2bSzf 	RAL_LOCK(sc);
194640db2e2bSzf 	ic->ic_watchdog_timer = 0;
194740db2e2bSzf 
194840db2e2bSzf 	if (!RAL_IS_RUNNING(sc)) {
194940db2e2bSzf 		RAL_UNLOCK(sc);
195040db2e2bSzf 		return;
195140db2e2bSzf 	}
195240db2e2bSzf 
195340db2e2bSzf 	if (sc->sc_tx_timer > 0) {
195440db2e2bSzf 		if (--sc->sc_tx_timer == 0) {
19551a932f2eSQuaker Fang 			ral_debug(RAL_DBG_ERR, "tx timer timeout\n");
195640db2e2bSzf 			RAL_UNLOCK(sc);
195740db2e2bSzf 			(void) ural_init(sc);
195840db2e2bSzf 			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
195940db2e2bSzf 			return;
196040db2e2bSzf 		}
196140db2e2bSzf 	}
196240db2e2bSzf 
196340db2e2bSzf 	if (ic->ic_state == IEEE80211_S_RUN)
196440db2e2bSzf 		ntimer = 1;
196540db2e2bSzf 
196640db2e2bSzf 	RAL_UNLOCK(sc);
196740db2e2bSzf 
196840db2e2bSzf 	ieee80211_watchdog(ic);
196940db2e2bSzf 
197040db2e2bSzf 	if (ntimer)
197140db2e2bSzf 		ieee80211_start_watchdog(ic, ntimer);
197240db2e2bSzf }
197340db2e2bSzf 
197440db2e2bSzf static int
ural_m_start(void * arg)197540db2e2bSzf ural_m_start(void *arg)
197640db2e2bSzf {
197740db2e2bSzf 	struct ural_softc *sc = (struct ural_softc *)arg;
197840db2e2bSzf 	int err;
197940db2e2bSzf 
198040db2e2bSzf 	/*
198140db2e2bSzf 	 * initialize RT2500USB hardware
198240db2e2bSzf 	 */
198340db2e2bSzf 	err = ural_init(sc);
198440db2e2bSzf 	if (err != DDI_SUCCESS) {
19851a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "device configuration failed\n");
198640db2e2bSzf 		goto fail;
198740db2e2bSzf 	}
198840db2e2bSzf 	sc->sc_flags |= RAL_FLAG_RUNNING;	/* RUNNING */
198940db2e2bSzf 	return (err);
199040db2e2bSzf 
199140db2e2bSzf fail:
199240db2e2bSzf 	ural_stop(sc);
199340db2e2bSzf 	return (err);
199440db2e2bSzf }
199540db2e2bSzf 
199640db2e2bSzf static void
ural_m_stop(void * arg)199740db2e2bSzf ural_m_stop(void *arg)
199840db2e2bSzf {
199940db2e2bSzf 	struct ural_softc *sc = (struct ural_softc *)arg;
200040db2e2bSzf 
200140db2e2bSzf 	(void) ural_stop(sc);
200240db2e2bSzf 	sc->sc_flags &= ~RAL_FLAG_RUNNING;	/* STOP */
200340db2e2bSzf }
200440db2e2bSzf 
200540db2e2bSzf static int
ural_m_unicst(void * arg,const uint8_t * macaddr)200640db2e2bSzf ural_m_unicst(void *arg, const uint8_t *macaddr)
200740db2e2bSzf {
200840db2e2bSzf 	struct ural_softc *sc = (struct ural_softc *)arg;
200940db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
201040db2e2bSzf 
20111a932f2eSQuaker Fang 	ral_debug(RAL_DBG_MSG, "ural_m_unicst(): " MACSTR "\n",
201240db2e2bSzf 	    MAC2STR(macaddr));
201340db2e2bSzf 
201440db2e2bSzf 	IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
201540db2e2bSzf 	(void) ural_set_macaddr(sc, (uint8_t *)macaddr);
201640db2e2bSzf 	(void) ural_init(sc);
201740db2e2bSzf 
201840db2e2bSzf 	return (0);
201940db2e2bSzf }
202040db2e2bSzf 
202140db2e2bSzf /*ARGSUSED*/
202240db2e2bSzf static int
ural_m_multicst(void * arg,boolean_t add,const uint8_t * mca)202340db2e2bSzf ural_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
202440db2e2bSzf {
202540db2e2bSzf 	return (0);
202640db2e2bSzf }
202740db2e2bSzf 
202840db2e2bSzf static int
ural_m_promisc(void * arg,boolean_t on)202940db2e2bSzf ural_m_promisc(void *arg, boolean_t on)
203040db2e2bSzf {
203140db2e2bSzf 	struct ural_softc *sc = (struct ural_softc *)arg;
203240db2e2bSzf 
203340db2e2bSzf 	if (on) {
203440db2e2bSzf 		sc->sc_rcr |= RAL_RCR_PROMISC;
203540db2e2bSzf 		sc->sc_rcr |= RAL_RCR_MULTI;
203640db2e2bSzf 	} else {
203740db2e2bSzf 		sc->sc_rcr &= ~RAL_RCR_PROMISC;
203840db2e2bSzf 		sc->sc_rcr &= ~RAL_RCR_PROMISC;
203940db2e2bSzf 	}
204040db2e2bSzf 
204140db2e2bSzf 	ural_update_promisc(sc);
204240db2e2bSzf 	return (0);
204340db2e2bSzf }
204440db2e2bSzf 
20455644143aSQuaker Fang /*
20465644143aSQuaker Fang  * callback functions for /get/set properties
20475644143aSQuaker Fang  */
20485644143aSQuaker Fang static int
ural_m_setprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,const void * wldp_buf)20495644143aSQuaker Fang ural_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
20505644143aSQuaker Fang     uint_t wldp_length, const void *wldp_buf)
20515644143aSQuaker Fang {
20525644143aSQuaker Fang 	struct ural_softc *sc = (struct ural_softc *)arg;
20535644143aSQuaker Fang 	struct ieee80211com *ic = &sc->sc_ic;
20545644143aSQuaker Fang 	int err;
20555644143aSQuaker Fang 
20565644143aSQuaker Fang 	err = ieee80211_setprop(ic, pr_name, wldp_pr_num,
20575644143aSQuaker Fang 	    wldp_length, wldp_buf);
20585644143aSQuaker Fang 	RAL_LOCK(sc);
20595644143aSQuaker Fang 	if (err == ENETRESET) {
20605644143aSQuaker Fang 		if (RAL_IS_RUNNING(sc)) {
20615644143aSQuaker Fang 			RAL_UNLOCK(sc);
20625644143aSQuaker Fang 			(void) ural_init(sc);
20635644143aSQuaker Fang 			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
20645644143aSQuaker Fang 			RAL_LOCK(sc);
20655644143aSQuaker Fang 		}
20665644143aSQuaker Fang 		err = 0;
20675644143aSQuaker Fang 	}
20685644143aSQuaker Fang 	RAL_UNLOCK(sc);
20695644143aSQuaker Fang 
20705644143aSQuaker Fang 	return (err);
20715644143aSQuaker Fang }
20725644143aSQuaker Fang 
20735644143aSQuaker Fang static int
ural_m_getprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,void * wldp_buf)20745644143aSQuaker Fang ural_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2075*0dc2366fSVenugopal Iyer     uint_t wldp_length, void *wldp_buf)
20765644143aSQuaker Fang {
20775644143aSQuaker Fang 	struct ural_softc *sc = (struct ural_softc *)arg;
20785644143aSQuaker Fang 	int err;
20795644143aSQuaker Fang 
20805644143aSQuaker Fang 	err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
2081*0dc2366fSVenugopal Iyer 	    wldp_length, wldp_buf);
20825644143aSQuaker Fang 
20835644143aSQuaker Fang 	return (err);
20845644143aSQuaker Fang }
20855644143aSQuaker Fang 
2086*0dc2366fSVenugopal Iyer static void
ural_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,mac_prop_info_handle_t mph)2087*0dc2366fSVenugopal Iyer ural_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2088*0dc2366fSVenugopal Iyer     mac_prop_info_handle_t mph)
2089*0dc2366fSVenugopal Iyer {
2090*0dc2366fSVenugopal Iyer 	struct ural_softc *sc = (struct ural_softc *)arg;
2091*0dc2366fSVenugopal Iyer 
2092*0dc2366fSVenugopal Iyer 	ieee80211_propinfo(&sc->sc_ic, pr_name, wldp_pr_num, mph);
2093*0dc2366fSVenugopal Iyer }
2094*0dc2366fSVenugopal Iyer 
209540db2e2bSzf static void
ural_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)209640db2e2bSzf ural_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
209740db2e2bSzf {
209840db2e2bSzf 	struct ural_softc *sc = (struct ural_softc *)arg;
209940db2e2bSzf 	struct ieee80211com *ic = &sc->sc_ic;
210040db2e2bSzf 	int err;
210140db2e2bSzf 
210240db2e2bSzf 	err = ieee80211_ioctl(ic, wq, mp);
210340db2e2bSzf 	RAL_LOCK(sc);
210440db2e2bSzf 	if (err == ENETRESET) {
210540db2e2bSzf 		if (RAL_IS_RUNNING(sc)) {
210640db2e2bSzf 			RAL_UNLOCK(sc);
210740db2e2bSzf 			(void) ural_init(sc);
210840db2e2bSzf 			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
210940db2e2bSzf 			RAL_LOCK(sc);
211040db2e2bSzf 		}
211140db2e2bSzf 	}
211240db2e2bSzf 	RAL_UNLOCK(sc);
211340db2e2bSzf }
211440db2e2bSzf 
211540db2e2bSzf static int
ural_m_stat(void * arg,uint_t stat,uint64_t * val)211640db2e2bSzf ural_m_stat(void *arg, uint_t stat, uint64_t *val)
211740db2e2bSzf {
211840db2e2bSzf 	struct ural_softc *sc  = (struct ural_softc *)arg;
211940db2e2bSzf 	ieee80211com_t	*ic = &sc->sc_ic;
212040db2e2bSzf 	ieee80211_node_t *ni = ic->ic_bss;
212140db2e2bSzf 	struct ieee80211_rateset *rs = &ni->in_rates;
212240db2e2bSzf 
212340db2e2bSzf 	RAL_LOCK(sc);
212440db2e2bSzf 	switch (stat) {
212540db2e2bSzf 	case MAC_STAT_IFSPEED:
212640db2e2bSzf 		*val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
212740db2e2bSzf 		    (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL)
2128020c4770Sql 		    : ic->ic_fixed_rate) / 2 * 1000000;
212940db2e2bSzf 		break;
213040db2e2bSzf 	case MAC_STAT_NOXMTBUF:
213140db2e2bSzf 		*val = sc->sc_tx_nobuf;
213240db2e2bSzf 		break;
213340db2e2bSzf 	case MAC_STAT_NORCVBUF:
213440db2e2bSzf 		*val = sc->sc_rx_nobuf;
213540db2e2bSzf 		break;
213640db2e2bSzf 	case MAC_STAT_IERRORS:
213740db2e2bSzf 		*val = sc->sc_rx_err;
213840db2e2bSzf 		break;
213940db2e2bSzf 	case MAC_STAT_RBYTES:
214040db2e2bSzf 		*val = ic->ic_stats.is_rx_bytes;
214140db2e2bSzf 		break;
214240db2e2bSzf 	case MAC_STAT_IPACKETS:
214340db2e2bSzf 		*val = ic->ic_stats.is_rx_frags;
214440db2e2bSzf 		break;
214540db2e2bSzf 	case MAC_STAT_OBYTES:
214640db2e2bSzf 		*val = ic->ic_stats.is_tx_bytes;
214740db2e2bSzf 		break;
214840db2e2bSzf 	case MAC_STAT_OPACKETS:
214940db2e2bSzf 		*val = ic->ic_stats.is_tx_frags;
215040db2e2bSzf 		break;
215140db2e2bSzf 	case MAC_STAT_OERRORS:
215240db2e2bSzf 	case WIFI_STAT_TX_FAILED:
215340db2e2bSzf 		*val = sc->sc_tx_err;
215440db2e2bSzf 		break;
215540db2e2bSzf 	case WIFI_STAT_TX_RETRANS:
215640db2e2bSzf 		*val = sc->sc_tx_retries;
215740db2e2bSzf 		break;
215840db2e2bSzf 	case WIFI_STAT_FCS_ERRORS:
215940db2e2bSzf 	case WIFI_STAT_WEP_ERRORS:
216040db2e2bSzf 	case WIFI_STAT_TX_FRAGS:
216140db2e2bSzf 	case WIFI_STAT_MCAST_TX:
216240db2e2bSzf 	case WIFI_STAT_RTS_SUCCESS:
216340db2e2bSzf 	case WIFI_STAT_RTS_FAILURE:
216440db2e2bSzf 	case WIFI_STAT_ACK_FAILURE:
216540db2e2bSzf 	case WIFI_STAT_RX_FRAGS:
216640db2e2bSzf 	case WIFI_STAT_MCAST_RX:
216740db2e2bSzf 	case WIFI_STAT_RX_DUPS:
216840db2e2bSzf 		RAL_UNLOCK(sc);
216940db2e2bSzf 		return (ieee80211_stat(ic, stat, val));
217040db2e2bSzf 	default:
217140db2e2bSzf 		RAL_UNLOCK(sc);
217240db2e2bSzf 		return (ENOTSUP);
217340db2e2bSzf 	}
217440db2e2bSzf 	RAL_UNLOCK(sc);
217540db2e2bSzf 
217640db2e2bSzf 	return (0);
217740db2e2bSzf }
217840db2e2bSzf 
217940db2e2bSzf 
218040db2e2bSzf static int
ural_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)218140db2e2bSzf ural_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
218240db2e2bSzf {
218340db2e2bSzf 	struct ural_softc *sc;
218440db2e2bSzf 	struct ieee80211com *ic;
218540db2e2bSzf 	int err, i;
218640db2e2bSzf 	int instance;
218740db2e2bSzf 
218840db2e2bSzf 	char strbuf[32];
218940db2e2bSzf 
219040db2e2bSzf 	wifi_data_t wd = { 0 };
219140db2e2bSzf 	mac_register_t *macp;
219240db2e2bSzf 
21931a932f2eSQuaker Fang 	switch (cmd) {
21941a932f2eSQuaker Fang 	case DDI_ATTACH:
21951a932f2eSQuaker Fang 		break;
21961a932f2eSQuaker Fang 	case DDI_RESUME:
21971a932f2eSQuaker Fang 		sc = ddi_get_soft_state(ural_soft_state_p,
21981a932f2eSQuaker Fang 		    ddi_get_instance(devinfo));
21991a932f2eSQuaker Fang 		ASSERT(sc != NULL);
22001a932f2eSQuaker Fang 		ural_resume(sc);
22011a932f2eSQuaker Fang 		return (DDI_SUCCESS);
22021a932f2eSQuaker Fang 	default:
220340db2e2bSzf 		return (DDI_FAILURE);
22041a932f2eSQuaker Fang 	}
220540db2e2bSzf 
220640db2e2bSzf 	instance = ddi_get_instance(devinfo);
220740db2e2bSzf 
220840db2e2bSzf 	if (ddi_soft_state_zalloc(ural_soft_state_p, instance) != DDI_SUCCESS) {
22091a932f2eSQuaker Fang 		ral_debug(RAL_DBG_MSG, "ural_attach(): "
221040db2e2bSzf 		    "unable to alloc soft_state_p\n");
221140db2e2bSzf 		return (DDI_FAILURE);
221240db2e2bSzf 	}
221340db2e2bSzf 
221440db2e2bSzf 	sc = ddi_get_soft_state(ural_soft_state_p, instance);
221540db2e2bSzf 	ic = (ieee80211com_t *)&sc->sc_ic;
221640db2e2bSzf 	sc->sc_dev = devinfo;
221740db2e2bSzf 
221840db2e2bSzf 	if (usb_client_attach(devinfo, USBDRV_VERSION, 0) != USB_SUCCESS) {
22191a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
222040db2e2bSzf 		    "ural_attach(): usb_client_attach failed\n");
222140db2e2bSzf 		goto fail1;
222240db2e2bSzf 	}
222340db2e2bSzf 
222440db2e2bSzf 	if (usb_get_dev_data(devinfo, &sc->sc_udev,
222540db2e2bSzf 	    USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
222640db2e2bSzf 		sc->sc_udev = NULL;
222740db2e2bSzf 		goto fail2;
222840db2e2bSzf 	}
222940db2e2bSzf 
223040db2e2bSzf 	mutex_init(&sc->sc_genlock, NULL, MUTEX_DRIVER, NULL);
223140db2e2bSzf 	mutex_init(&sc->tx_lock, NULL, MUTEX_DRIVER, NULL);
223240db2e2bSzf 	mutex_init(&sc->rx_lock, NULL, MUTEX_DRIVER, NULL);
223340db2e2bSzf 
223440db2e2bSzf 	/* retrieve RT2570 rev. no */
223540db2e2bSzf 	sc->asic_rev = ural_read(sc, RAL_MAC_CSR0);
223640db2e2bSzf 
223740db2e2bSzf 	/* retrieve MAC address and various other things from EEPROM */
223840db2e2bSzf 	ural_read_eeprom(sc);
223940db2e2bSzf 
22401a932f2eSQuaker Fang 	ral_debug(RAL_DBG_MSG, "ural: MAC/BBP RT2570 (rev 0x%02x), RF %s\n",
224140db2e2bSzf 	    sc->asic_rev, ural_get_rf(sc->rf_rev));
224240db2e2bSzf 
224340db2e2bSzf 	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
224440db2e2bSzf 	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
224540db2e2bSzf 	ic->ic_state = IEEE80211_S_INIT;
224640db2e2bSzf 
224740db2e2bSzf 	ic->ic_maxrssi = 63;
224840db2e2bSzf 	ic->ic_set_shortslot = ural_update_slot;
224940db2e2bSzf 	ic->ic_xmit = ural_send;
225040db2e2bSzf 
225140db2e2bSzf 	/* set device capabilities */
225240db2e2bSzf 	ic->ic_caps =
225340db2e2bSzf 	    IEEE80211_C_TXPMGT |	/* tx power management */
225440db2e2bSzf 	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
225540db2e2bSzf 	    IEEE80211_C_SHSLOT;		/* short slot time supported */
225640db2e2bSzf 
225740db2e2bSzf 	ic->ic_caps |= IEEE80211_C_WPA; /* Support WPA/WPA2 */
225840db2e2bSzf 
225940db2e2bSzf #define	IEEE80211_CHAN_A	\
226040db2e2bSzf 	(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
226140db2e2bSzf 
226240db2e2bSzf 	if (sc->rf_rev == RAL_RF_5222) {
226340db2e2bSzf 		/* set supported .11a rates */
226440db2e2bSzf 		ic->ic_sup_rates[IEEE80211_MODE_11A] = ural_rateset_11a;
226540db2e2bSzf 
226640db2e2bSzf 		/* set supported .11a channels */
226740db2e2bSzf 		for (i = 36; i <= 64; i += 4) {
226840db2e2bSzf 			ic->ic_sup_channels[i].ich_freq =
226940db2e2bSzf 			    ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
227040db2e2bSzf 			ic->ic_sup_channels[i].ich_flags = IEEE80211_CHAN_A;
227140db2e2bSzf 		}
227240db2e2bSzf 		for (i = 100; i <= 140; i += 4) {
227340db2e2bSzf 			ic->ic_sup_channels[i].ich_freq =
227440db2e2bSzf 			    ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
227540db2e2bSzf 			ic->ic_sup_channels[i].ich_flags = IEEE80211_CHAN_A;
227640db2e2bSzf 		}
227740db2e2bSzf 		for (i = 149; i <= 161; i += 4) {
227840db2e2bSzf 			ic->ic_sup_channels[i].ich_freq =
227940db2e2bSzf 			    ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
228040db2e2bSzf 			ic->ic_sup_channels[i].ich_flags = IEEE80211_CHAN_A;
228140db2e2bSzf 		}
228240db2e2bSzf 	}
228340db2e2bSzf 
228440db2e2bSzf 	/* set supported .11b and .11g rates */
228540db2e2bSzf 	ic->ic_sup_rates[IEEE80211_MODE_11B] = ural_rateset_11b;
228640db2e2bSzf 	ic->ic_sup_rates[IEEE80211_MODE_11G] = ural_rateset_11g;
228740db2e2bSzf 
228840db2e2bSzf 	/* set supported .11b and .11g channels (1 through 14) */
228940db2e2bSzf 	for (i = 1; i <= 14; i++) {
229040db2e2bSzf 		ic->ic_sup_channels[i].ich_freq =
229140db2e2bSzf 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
229240db2e2bSzf 		ic->ic_sup_channels[i].ich_flags =
229340db2e2bSzf 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
229440db2e2bSzf 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
229540db2e2bSzf 	}
229640db2e2bSzf 
229740db2e2bSzf 	ieee80211_attach(ic);
229840db2e2bSzf 
229940db2e2bSzf 	/* register WPA door */
230040db2e2bSzf 	ieee80211_register_door(ic, ddi_driver_name(devinfo),
230140db2e2bSzf 	    ddi_get_instance(devinfo));
230240db2e2bSzf 
230340db2e2bSzf 	/* override state transition machine */
230440db2e2bSzf 	sc->sc_newstate = ic->ic_newstate;
230540db2e2bSzf 	ic->ic_newstate = ural_newstate;
230640db2e2bSzf 	ic->ic_watchdog = ural_watchdog;
230740db2e2bSzf 	ieee80211_media_init(ic);
230840db2e2bSzf 	ic->ic_def_txkey = 0;
230940db2e2bSzf 
231040db2e2bSzf 	sc->sc_rcr = 0;
231140db2e2bSzf 	sc->dwelltime = 300;
23121a932f2eSQuaker Fang 	sc->sc_flags &= 0;
231340db2e2bSzf 
231440db2e2bSzf 	/*
231540db2e2bSzf 	 * Provide initial settings for the WiFi plugin; whenever this
231640db2e2bSzf 	 * information changes, we need to call mac_plugindata_update()
231740db2e2bSzf 	 */
231840db2e2bSzf 	wd.wd_opmode = ic->ic_opmode;
231940db2e2bSzf 	wd.wd_secalloc = WIFI_SEC_NONE;
232040db2e2bSzf 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
232140db2e2bSzf 
232240db2e2bSzf 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
23231a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "ural_attach(): "
232440db2e2bSzf 		    "MAC version mismatch\n");
232540db2e2bSzf 		goto fail3;
232640db2e2bSzf 	}
232740db2e2bSzf 
232840db2e2bSzf 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
232940db2e2bSzf 	macp->m_driver		= sc;
233040db2e2bSzf 	macp->m_dip		= devinfo;
233140db2e2bSzf 	macp->m_src_addr	= ic->ic_macaddr;
233240db2e2bSzf 	macp->m_callbacks	= &ural_m_callbacks;
233340db2e2bSzf 	macp->m_min_sdu		= 0;
233440db2e2bSzf 	macp->m_max_sdu		= IEEE80211_MTU;
233540db2e2bSzf 	macp->m_pdata		= &wd;
233640db2e2bSzf 	macp->m_pdata_size	= sizeof (wd);
233740db2e2bSzf 
233840db2e2bSzf 	err = mac_register(macp, &ic->ic_mach);
233940db2e2bSzf 	mac_free(macp);
234040db2e2bSzf 	if (err != 0) {
23411a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "ural_attach(): "
234240db2e2bSzf 		    "mac_register() err %x\n", err);
234340db2e2bSzf 		goto fail3;
234440db2e2bSzf 	}
234540db2e2bSzf 
23461a932f2eSQuaker Fang 	if (usb_register_hotplug_cbs(devinfo, ural_disconnect,
23471a932f2eSQuaker Fang 	    ural_reconnect) != USB_SUCCESS) {
23481a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR,
234940db2e2bSzf 		    "ural: ural_attach() failed to register events");
235040db2e2bSzf 		goto fail4;
235140db2e2bSzf 	}
235240db2e2bSzf 
235340db2e2bSzf 	/*
235440db2e2bSzf 	 * Create minor node of type DDI_NT_NET_WIFI
235540db2e2bSzf 	 */
235640db2e2bSzf 	(void) snprintf(strbuf, sizeof (strbuf), "%s%d",
235740db2e2bSzf 	    "ural", instance);
235840db2e2bSzf 	err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
235940db2e2bSzf 	    instance + 1, DDI_NT_NET_WIFI, 0);
236040db2e2bSzf 
236140db2e2bSzf 	if (err != DDI_SUCCESS)
23621a932f2eSQuaker Fang 		ral_debug(RAL_DBG_ERR, "ddi_create_minor_node() failed\n");
236340db2e2bSzf 
236440db2e2bSzf 	/*
236540db2e2bSzf 	 * Notify link is down now
236640db2e2bSzf 	 */
236740db2e2bSzf 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
236840db2e2bSzf 
236940db2e2bSzf 	return (DDI_SUCCESS);
237040db2e2bSzf fail4:
237140db2e2bSzf 	(void) mac_unregister(ic->ic_mach);
237240db2e2bSzf fail3:
237340db2e2bSzf 	mutex_destroy(&sc->sc_genlock);
237440db2e2bSzf 	mutex_destroy(&sc->tx_lock);
237540db2e2bSzf 	mutex_destroy(&sc->rx_lock);
237640db2e2bSzf fail2:
237740db2e2bSzf 	usb_client_detach(sc->sc_dev, sc->sc_udev);
237840db2e2bSzf fail1:
237940db2e2bSzf 	ddi_soft_state_free(ural_soft_state_p, ddi_get_instance(devinfo));
238040db2e2bSzf 
238140db2e2bSzf 	return (DDI_FAILURE);
238240db2e2bSzf }
238340db2e2bSzf 
238440db2e2bSzf static int
ural_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)238540db2e2bSzf ural_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
238640db2e2bSzf {
238740db2e2bSzf 	struct ural_softc *sc;
238840db2e2bSzf 
238940db2e2bSzf 	sc = ddi_get_soft_state(ural_soft_state_p, ddi_get_instance(devinfo));
23901a932f2eSQuaker Fang 	ASSERT(sc != NULL);
239140db2e2bSzf 
23921a932f2eSQuaker Fang 	switch (cmd) {
23931a932f2eSQuaker Fang 	case DDI_DETACH:
23941a932f2eSQuaker Fang 		break;
23951a932f2eSQuaker Fang 	case DDI_SUSPEND:
23961a932f2eSQuaker Fang 		if (RAL_IS_RUNNING(sc))
23971a932f2eSQuaker Fang 			(void) ural_stop(sc);
23981a932f2eSQuaker Fang 		return (DDI_SUCCESS);
23991a932f2eSQuaker Fang 	default:
240040db2e2bSzf 		return (DDI_FAILURE);
24011a932f2eSQuaker Fang 	}
240240db2e2bSzf 
240342516a0cSxinghua wen - Sun Microsystems - Beijing China 	if (mac_disable(sc->sc_ic.ic_mach) != 0)
240442516a0cSxinghua wen - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
240542516a0cSxinghua wen - Sun Microsystems - Beijing China 
240640db2e2bSzf 	ural_stop(sc);
240740db2e2bSzf 	usb_unregister_hotplug_cbs(devinfo);
240840db2e2bSzf 
240940db2e2bSzf 	/*
241040db2e2bSzf 	 * Unregister from the MAC layer subsystem
241140db2e2bSzf 	 */
241242516a0cSxinghua wen - Sun Microsystems - Beijing China 	(void) mac_unregister(sc->sc_ic.ic_mach);
241340db2e2bSzf 
241440db2e2bSzf 	/*
241540db2e2bSzf 	 * detach ieee80211 layer
241640db2e2bSzf 	 */
241740db2e2bSzf 	ieee80211_detach(&sc->sc_ic);
241840db2e2bSzf 
241940db2e2bSzf 	mutex_destroy(&sc->sc_genlock);
242040db2e2bSzf 	mutex_destroy(&sc->tx_lock);
242140db2e2bSzf 	mutex_destroy(&sc->rx_lock);
242240db2e2bSzf 
242340db2e2bSzf 	/* pipes will be close in ural_stop() */
242440db2e2bSzf 	usb_client_detach(devinfo, sc->sc_udev);
242540db2e2bSzf 	sc->sc_udev = NULL;
242640db2e2bSzf 
242740db2e2bSzf 	ddi_remove_minor_node(devinfo, NULL);
242840db2e2bSzf 	ddi_soft_state_free(ural_soft_state_p, ddi_get_instance(devinfo));
242940db2e2bSzf 
243040db2e2bSzf 	return (DDI_SUCCESS);
243140db2e2bSzf }
243240db2e2bSzf 
243340db2e2bSzf int
_info(struct modinfo * modinfop)243440db2e2bSzf _info(struct modinfo *modinfop)
243540db2e2bSzf {
243640db2e2bSzf 	return (mod_info(&modlinkage, modinfop));
243740db2e2bSzf }
243840db2e2bSzf 
243940db2e2bSzf int
_init(void)244040db2e2bSzf _init(void)
244140db2e2bSzf {
244240db2e2bSzf 	int status;
244340db2e2bSzf 
244440db2e2bSzf 	status = ddi_soft_state_init(&ural_soft_state_p,
244540db2e2bSzf 	    sizeof (struct ural_softc), 1);
244640db2e2bSzf 	if (status != 0)
244740db2e2bSzf 		return (status);
244840db2e2bSzf 
244940db2e2bSzf 	mac_init_ops(&ural_dev_ops, "ural");
245040db2e2bSzf 	status = mod_install(&modlinkage);
245140db2e2bSzf 	if (status != 0) {
245240db2e2bSzf 		mac_fini_ops(&ural_dev_ops);
245340db2e2bSzf 		ddi_soft_state_fini(&ural_soft_state_p);
245440db2e2bSzf 	}
245540db2e2bSzf 	return (status);
245640db2e2bSzf }
245740db2e2bSzf 
245840db2e2bSzf int
_fini(void)245940db2e2bSzf _fini(void)
246040db2e2bSzf {
246140db2e2bSzf 	int status;
246240db2e2bSzf 
246340db2e2bSzf 	status = mod_remove(&modlinkage);
246440db2e2bSzf 	if (status == 0) {
246540db2e2bSzf 		mac_fini_ops(&ural_dev_ops);
246640db2e2bSzf 		ddi_soft_state_fini(&ural_soft_state_p);
246740db2e2bSzf 	}
246840db2e2bSzf 	return (status);
246940db2e2bSzf }
2470