xref: /onnv-gate/usr/src/uts/common/io/ural/ural.c (revision 11878:ac93462db6d7)
16629Szf162725 /*
2*11878SVenu.Iyer@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
36629Szf162725  * Use is subject to license terms.
46629Szf162725  */
56629Szf162725 
66629Szf162725 /*
76629Szf162725  * Copyright (c) 2005, 2006
86629Szf162725  *	Damien Bergamini <damien.bergamini@free.fr>
96629Szf162725  *
106629Szf162725  * Permission to use, copy, modify, and distribute this software for any
116629Szf162725  * purpose with or without fee is hereby granted, provided that the above
126629Szf162725  * copyright notice and this permission notice appear in all copies.
136629Szf162725  *
146629Szf162725  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
156629Szf162725  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
166629Szf162725  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
176629Szf162725  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
186629Szf162725  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
196629Szf162725  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
206629Szf162725  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
216629Szf162725  */
226629Szf162725 
236629Szf162725 /*
246629Szf162725  * Ralink Technology RT2500USB chipset driver
256629Szf162725  * http://www.ralinktech.com/
266629Szf162725  */
276629Szf162725 #include <sys/types.h>
286629Szf162725 #include <sys/cmn_err.h>
296629Szf162725 #include <sys/strsubr.h>
306629Szf162725 #include <sys/modctl.h>
316629Szf162725 #include <sys/devops.h>
32*11878SVenu.Iyer@Sun.COM #include <sys/byteorder.h>
338275SEric Cheng #include <sys/mac_provider.h>
346629Szf162725 #include <sys/mac_wifi.h>
356629Szf162725 #include <sys/net80211.h>
366629Szf162725 
376629Szf162725 #define	USBDRV_MAJOR_VER	2
386629Szf162725 #define	USBDRV_MINOR_VER	0
396629Szf162725 #include <sys/usb/usba.h>
409345SQuaker.Fang@Sun.COM #include <sys/usb/usba/usba_types.h>
416629Szf162725 
426629Szf162725 #include "ural_reg.h"
436629Szf162725 #include "ural_var.h"
446629Szf162725 
456629Szf162725 static void *ural_soft_state_p = NULL;
466629Szf162725 
476629Szf162725 #define	RAL_TXBUF_SIZE  	(IEEE80211_MAX_LEN)
486629Szf162725 #define	RAL_RXBUF_SIZE  	(IEEE80211_MAX_LEN)
496629Szf162725 
506629Szf162725 /* quickly determine if a given rate is CCK or OFDM */
516629Szf162725 #define	RAL_RATE_IS_OFDM(rate)	((rate) >= 12 && (rate) != 22)
526629Szf162725 #define	RAL_ACK_SIZE		14	/* 10 + 4(FCS) */
536629Szf162725 #define	RAL_CTS_SIZE		14	/* 10 + 4(FCS) */
546629Szf162725 #define	RAL_SIFS		10	/* us */
556629Szf162725 #define	RAL_RXTX_TURNAROUND	5	/* us */
566629Szf162725 
576629Szf162725 #define	URAL_N(a)		(sizeof (a) / sizeof ((a)[0]))
586629Szf162725 
596629Szf162725 /*
606629Szf162725  * Supported rates for 802.11a/b/g modes (in 500Kbps unit).
616629Szf162725  */
626629Szf162725 static const struct ieee80211_rateset ural_rateset_11a =
636629Szf162725 	{ 8, { 12, 18, 24, 36, 48, 72, 96, 108 } };
646629Szf162725 
656629Szf162725 static const struct ieee80211_rateset ural_rateset_11b =
666629Szf162725 	{ 4, { 2, 4, 11, 22 } };
676629Szf162725 
686629Szf162725 static const struct ieee80211_rateset ural_rateset_11g =
696629Szf162725 	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
706629Szf162725 
716629Szf162725 /*
726629Szf162725  * Default values for MAC registers; values taken from the reference driver.
736629Szf162725  */
746629Szf162725 static const struct {
756629Szf162725 	uint16_t	reg;
766629Szf162725 	uint16_t	val;
776629Szf162725 } ural_def_mac[] = {
786629Szf162725 	{ RAL_TXRX_CSR5,  0x8c8d },
796629Szf162725 	{ RAL_TXRX_CSR6,  0x8b8a },
806629Szf162725 	{ RAL_TXRX_CSR7,  0x8687 },
816629Szf162725 	{ RAL_TXRX_CSR8,  0x0085 },
826629Szf162725 	{ RAL_MAC_CSR13,  0x1111 },
836629Szf162725 	{ RAL_MAC_CSR14,  0x1e11 },
846629Szf162725 	{ RAL_TXRX_CSR21, 0xe78f },
856629Szf162725 	{ RAL_MAC_CSR9,   0xff1d },
866629Szf162725 	{ RAL_MAC_CSR11,  0x0002 },
876629Szf162725 	{ RAL_MAC_CSR22,  0x0053 },
886629Szf162725 	{ RAL_MAC_CSR15,  0x0000 },
896629Szf162725 	{ RAL_MAC_CSR8,   0x0780 },
906629Szf162725 	{ RAL_TXRX_CSR19, 0x0000 },
916629Szf162725 	{ RAL_TXRX_CSR18, 0x005a },
926629Szf162725 	{ RAL_PHY_CSR2,   0x0000 },
936629Szf162725 	{ RAL_TXRX_CSR0,  0x1ec0 },
946629Szf162725 	{ RAL_PHY_CSR4,   0x000f }
956629Szf162725 };
966629Szf162725 
976629Szf162725 /*
986629Szf162725  * Default values for BBP registers; values taken from the reference driver.
996629Szf162725  */
1006629Szf162725 static const struct {
1016629Szf162725 	uint8_t	reg;
1026629Szf162725 	uint8_t	val;
1036629Szf162725 } ural_def_bbp[] = {
1046629Szf162725 	{  3, 0x02 },
1056629Szf162725 	{  4, 0x19 },
1066629Szf162725 	{ 14, 0x1c },
1076629Szf162725 	{ 15, 0x30 },
1086629Szf162725 	{ 16, 0xac },
1096629Szf162725 	{ 17, 0x48 },
1106629Szf162725 	{ 18, 0x18 },
1116629Szf162725 	{ 19, 0xff },
1126629Szf162725 	{ 20, 0x1e },
1136629Szf162725 	{ 21, 0x08 },
1146629Szf162725 	{ 22, 0x08 },
1156629Szf162725 	{ 23, 0x08 },
1166629Szf162725 	{ 24, 0x80 },
1176629Szf162725 	{ 25, 0x50 },
1186629Szf162725 	{ 26, 0x08 },
1196629Szf162725 	{ 27, 0x23 },
1206629Szf162725 	{ 30, 0x10 },
1216629Szf162725 	{ 31, 0x2b },
1226629Szf162725 	{ 32, 0xb9 },
1236629Szf162725 	{ 34, 0x12 },
1246629Szf162725 	{ 35, 0x50 },
1256629Szf162725 	{ 39, 0xc4 },
1266629Szf162725 	{ 40, 0x02 },
1276629Szf162725 	{ 41, 0x60 },
1286629Szf162725 	{ 53, 0x10 },
1296629Szf162725 	{ 54, 0x18 },
1306629Szf162725 	{ 56, 0x08 },
1316629Szf162725 	{ 57, 0x10 },
1326629Szf162725 	{ 58, 0x08 },
1336629Szf162725 	{ 61, 0x60 },
1346629Szf162725 	{ 62, 0x10 },
1356629Szf162725 	{ 75, 0xff }
1366629Szf162725 };
1376629Szf162725 
1386629Szf162725 /*
1396629Szf162725  * Default values for RF register R2 indexed by channel numbers.
1406629Szf162725  */
1416629Szf162725 static const uint32_t ural_rf2522_r2[] = {
1426629Szf162725 	0x307f6, 0x307fb, 0x30800, 0x30805, 0x3080a, 0x3080f, 0x30814,
1436629Szf162725 	0x30819, 0x3081e, 0x30823, 0x30828, 0x3082d, 0x30832, 0x3083e
1446629Szf162725 };
1456629Szf162725 
1466629Szf162725 static const uint32_t ural_rf2523_r2[] = {
1476629Szf162725 	0x00327, 0x00328, 0x00329, 0x0032a, 0x0032b, 0x0032c, 0x0032d,
1486629Szf162725 	0x0032e, 0x0032f, 0x00340, 0x00341, 0x00342, 0x00343, 0x00346
1496629Szf162725 };
1506629Szf162725 
1516629Szf162725 static const uint32_t ural_rf2524_r2[] = {
1526629Szf162725 	0x00327, 0x00328, 0x00329, 0x0032a, 0x0032b, 0x0032c, 0x0032d,
1536629Szf162725 	0x0032e, 0x0032f, 0x00340, 0x00341, 0x00342, 0x00343, 0x00346
1546629Szf162725 };
1556629Szf162725 
1566629Szf162725 static const uint32_t ural_rf2525_r2[] = {
1576629Szf162725 	0x20327, 0x20328, 0x20329, 0x2032a, 0x2032b, 0x2032c, 0x2032d,
1586629Szf162725 	0x2032e, 0x2032f, 0x20340, 0x20341, 0x20342, 0x20343, 0x20346
1596629Szf162725 };
1606629Szf162725 
1616629Szf162725 static const uint32_t ural_rf2525_hi_r2[] = {
1626629Szf162725 	0x2032f, 0x20340, 0x20341, 0x20342, 0x20343, 0x20344, 0x20345,
1636629Szf162725 	0x20346, 0x20347, 0x20348, 0x20349, 0x2034a, 0x2034b, 0x2034e
1646629Szf162725 };
1656629Szf162725 
1666629Szf162725 static const uint32_t ural_rf2525e_r2[] = {
1676629Szf162725 	0x2044d, 0x2044e, 0x2044f, 0x20460, 0x20461, 0x20462, 0x20463,
1686629Szf162725 	0x20464, 0x20465, 0x20466, 0x20467, 0x20468, 0x20469, 0x2046b
1696629Szf162725 };
1706629Szf162725 
1716629Szf162725 static const uint32_t ural_rf2526_hi_r2[] = {
1726629Szf162725 	0x0022a, 0x0022b, 0x0022b, 0x0022c, 0x0022c, 0x0022d, 0x0022d,
1736629Szf162725 	0x0022e, 0x0022e, 0x0022f, 0x0022d, 0x00240, 0x00240, 0x00241
1746629Szf162725 };
1756629Szf162725 
1766629Szf162725 static const uint32_t ural_rf2526_r2[] = {
1776629Szf162725 	0x00226, 0x00227, 0x00227, 0x00228, 0x00228, 0x00229, 0x00229,
1786629Szf162725 	0x0022a, 0x0022a, 0x0022b, 0x0022b, 0x0022c, 0x0022c, 0x0022d
1796629Szf162725 };
1806629Szf162725 
1816629Szf162725 /*
1826629Szf162725  * For dual-band RF, RF registers R1 and R4 also depend on channel number;
1836629Szf162725  * values taken from the reference driver.
1846629Szf162725  */
1856629Szf162725 static const struct {
1866629Szf162725 	uint8_t		chan;
1876629Szf162725 	uint32_t	r1;
1886629Szf162725 	uint32_t	r2;
1896629Szf162725 	uint32_t	r4;
1906629Szf162725 } ural_rf5222[] = {
1916629Szf162725 	{   1, 0x08808, 0x0044d, 0x00282 },
1926629Szf162725 	{   2, 0x08808, 0x0044e, 0x00282 },
1936629Szf162725 	{   3, 0x08808, 0x0044f, 0x00282 },
1946629Szf162725 	{   4, 0x08808, 0x00460, 0x00282 },
1956629Szf162725 	{   5, 0x08808, 0x00461, 0x00282 },
1966629Szf162725 	{   6, 0x08808, 0x00462, 0x00282 },
1976629Szf162725 	{   7, 0x08808, 0x00463, 0x00282 },
1986629Szf162725 	{   8, 0x08808, 0x00464, 0x00282 },
1996629Szf162725 	{   9, 0x08808, 0x00465, 0x00282 },
2006629Szf162725 	{  10, 0x08808, 0x00466, 0x00282 },
2016629Szf162725 	{  11, 0x08808, 0x00467, 0x00282 },
2026629Szf162725 	{  12, 0x08808, 0x00468, 0x00282 },
2036629Szf162725 	{  13, 0x08808, 0x00469, 0x00282 },
2046629Szf162725 	{  14, 0x08808, 0x0046b, 0x00286 },
2056629Szf162725 
2066629Szf162725 	{  36, 0x08804, 0x06225, 0x00287 },
2076629Szf162725 	{  40, 0x08804, 0x06226, 0x00287 },
2086629Szf162725 	{  44, 0x08804, 0x06227, 0x00287 },
2096629Szf162725 	{  48, 0x08804, 0x06228, 0x00287 },
2106629Szf162725 	{  52, 0x08804, 0x06229, 0x00287 },
2116629Szf162725 	{  56, 0x08804, 0x0622a, 0x00287 },
2126629Szf162725 	{  60, 0x08804, 0x0622b, 0x00287 },
2136629Szf162725 	{  64, 0x08804, 0x0622c, 0x00287 },
2146629Szf162725 
2156629Szf162725 	{ 100, 0x08804, 0x02200, 0x00283 },
2166629Szf162725 	{ 104, 0x08804, 0x02201, 0x00283 },
2176629Szf162725 	{ 108, 0x08804, 0x02202, 0x00283 },
2186629Szf162725 	{ 112, 0x08804, 0x02203, 0x00283 },
2196629Szf162725 	{ 116, 0x08804, 0x02204, 0x00283 },
2206629Szf162725 	{ 120, 0x08804, 0x02205, 0x00283 },
2216629Szf162725 	{ 124, 0x08804, 0x02206, 0x00283 },
2226629Szf162725 	{ 128, 0x08804, 0x02207, 0x00283 },
2236629Szf162725 	{ 132, 0x08804, 0x02208, 0x00283 },
2246629Szf162725 	{ 136, 0x08804, 0x02209, 0x00283 },
2256629Szf162725 	{ 140, 0x08804, 0x0220a, 0x00283 },
2266629Szf162725 
2276629Szf162725 	{ 149, 0x08808, 0x02429, 0x00281 },
2286629Szf162725 	{ 153, 0x08808, 0x0242b, 0x00281 },
2296629Szf162725 	{ 157, 0x08808, 0x0242d, 0x00281 },
2306629Szf162725 	{ 161, 0x08808, 0x0242f, 0x00281 }
2316629Szf162725 };
2326629Szf162725 
2336629Szf162725 /*
2346629Szf162725  * device operations
2356629Szf162725  */
2366629Szf162725 static int ural_attach(dev_info_t *, ddi_attach_cmd_t);
2376629Szf162725 static int ural_detach(dev_info_t *, ddi_detach_cmd_t);
2386629Szf162725 
2396629Szf162725 /*
2406629Szf162725  * Module Loading Data & Entry Points
2416629Szf162725  */
2426629Szf162725 DDI_DEFINE_STREAM_OPS(ural_dev_ops, nulldev, nulldev, ural_attach,
2438099SQuaker.Fang@Sun.COM     ural_detach, nodev, NULL, D_MP, NULL, ddi_quiesce_not_needed);
2446629Szf162725 
2456629Szf162725 static struct modldrv ural_modldrv = {
2466629Szf162725 	&mod_driverops,		/* Type of module.  This one is a driver */
2479345SQuaker.Fang@Sun.COM 	"ural driver v1.4",	/* short description */
2486629Szf162725 	&ural_dev_ops		/* driver specific ops */
2496629Szf162725 };
2506629Szf162725 
2516629Szf162725 static struct modlinkage modlinkage = {
2526629Szf162725 	MODREV_1,
2536629Szf162725 	(void *)&ural_modldrv,
2546629Szf162725 	NULL
2556629Szf162725 };
2566629Szf162725 
2576629Szf162725 static int	ural_m_stat(void *,  uint_t, uint64_t *);
2586629Szf162725 static int	ural_m_start(void *);
2596629Szf162725 static void	ural_m_stop(void *);
2606629Szf162725 static int	ural_m_promisc(void *, boolean_t);
2616629Szf162725 static int	ural_m_multicst(void *, boolean_t, const uint8_t *);
2626629Szf162725 static int	ural_m_unicst(void *, const uint8_t *);
2636629Szf162725 static mblk_t	*ural_m_tx(void *, mblk_t *);
2646629Szf162725 static void	ural_m_ioctl(void *, queue_t *, mblk_t *);
2658099SQuaker.Fang@Sun.COM static int	ural_m_setprop(void *, const char *, mac_prop_id_t,
2668099SQuaker.Fang@Sun.COM     uint_t, const void *);
2678099SQuaker.Fang@Sun.COM static int	ural_m_getprop(void *, const char *, mac_prop_id_t,
268*11878SVenu.Iyer@Sun.COM     uint_t, void *);
269*11878SVenu.Iyer@Sun.COM static void	ural_m_propinfo(void *, const char *, mac_prop_id_t,
270*11878SVenu.Iyer@Sun.COM     mac_prop_info_handle_t);
2716629Szf162725 
2726629Szf162725 static mac_callbacks_t ural_m_callbacks = {
273*11878SVenu.Iyer@Sun.COM 	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
2746629Szf162725 	ural_m_stat,
2756629Szf162725 	ural_m_start,
2766629Szf162725 	ural_m_stop,
2776629Szf162725 	ural_m_promisc,
2786629Szf162725 	ural_m_multicst,
2796629Szf162725 	ural_m_unicst,
2806629Szf162725 	ural_m_tx,
281*11878SVenu.Iyer@Sun.COM 	NULL,
2826629Szf162725 	ural_m_ioctl,
2838099SQuaker.Fang@Sun.COM 	NULL,		/* mc_getcapab */
2848099SQuaker.Fang@Sun.COM 	NULL,
2858099SQuaker.Fang@Sun.COM 	NULL,
2868099SQuaker.Fang@Sun.COM 	ural_m_setprop,
287*11878SVenu.Iyer@Sun.COM 	ural_m_getprop,
288*11878SVenu.Iyer@Sun.COM 	ural_m_propinfo
2896629Szf162725 };
2906629Szf162725 
2916629Szf162725 static void ural_amrr_start(struct ural_softc *, struct ieee80211_node *);
2926629Szf162725 static int  ural_tx_trigger(struct ural_softc *, mblk_t *);
2936629Szf162725 static int  ural_rx_trigger(struct ural_softc *);
2946629Szf162725 
2956629Szf162725 uint32_t ural_dbg_flags = 0;
2966629Szf162725 
2976629Szf162725 void
ral_debug(uint32_t dbg_flags,const int8_t * fmt,...)2986629Szf162725 ral_debug(uint32_t dbg_flags, const int8_t *fmt, ...)
2996629Szf162725 {
3006629Szf162725 	va_list args;
3016629Szf162725 
3026629Szf162725 	if (dbg_flags & ural_dbg_flags) {
3036629Szf162725 		va_start(args, fmt);
3046629Szf162725 		vcmn_err(CE_CONT, fmt, args);
3056629Szf162725 		va_end(args);
3066629Szf162725 	}
3076629Szf162725 }
3086629Szf162725 
3096629Szf162725 static uint16_t
ural_read(struct ural_softc * sc,uint16_t reg)3106629Szf162725 ural_read(struct ural_softc *sc, uint16_t reg)
3116629Szf162725 {
3126629Szf162725 	usb_ctrl_setup_t req;
3136629Szf162725 	usb_cr_t cr;
3146629Szf162725 	usb_cb_flags_t cf;
3156629Szf162725 	mblk_t *mp;
3166629Szf162725 	int err;
3176629Szf162725 	uint16_t val;
3186629Szf162725 
3196629Szf162725 	bzero(&req, sizeof (req));
3206629Szf162725 	req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_DEV_TO_HOST;
3216629Szf162725 	req.bRequest = RAL_READ_MAC;
3226629Szf162725 	req.wValue = 0;
3236629Szf162725 	req.wIndex = reg;
3246629Szf162725 	req.wLength = sizeof (uint16_t);
3256629Szf162725 
3266629Szf162725 	mp = NULL;
3276629Szf162725 	err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
3286629Szf162725 	    &cr, &cf, 0);
3296629Szf162725 
3306629Szf162725 	if (err != USB_SUCCESS) {
3319345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
3326629Szf162725 		    "ural_read(): could not read MAC register:"
3336629Szf162725 		    " cr:%s(%d), cf:(%x)\n",
3346629Szf162725 		    usb_str_cr(cr), cr, cf);
3356629Szf162725 		return (0);
3366629Szf162725 	}
3376629Szf162725 
3386629Szf162725 	bcopy(mp->b_rptr, &val, sizeof (uint16_t));
3396629Szf162725 
3406629Szf162725 	if (mp)
3416629Szf162725 		freemsg(mp);
3426629Szf162725 
3436629Szf162725 	return (LE_16(val));
3446629Szf162725 }
3456629Szf162725 
3466629Szf162725 static void
ural_read_multi(struct ural_softc * sc,uint16_t reg,void * buf,int len)3476629Szf162725 ural_read_multi(struct ural_softc *sc, uint16_t reg, void *buf, int len)
3486629Szf162725 {
3496629Szf162725 	usb_ctrl_setup_t req;
3506629Szf162725 	usb_cr_t cr;
3516629Szf162725 	usb_cb_flags_t cf;
3526629Szf162725 	mblk_t *mp;
3536629Szf162725 	int err;
3546629Szf162725 
3556629Szf162725 	bzero(&req, sizeof (req));
3566629Szf162725 	req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_DEV_TO_HOST;
3576629Szf162725 	req.bRequest = RAL_READ_MULTI_MAC;
3586629Szf162725 	req.wValue = 0;
3596629Szf162725 	req.wIndex = reg;
3606629Szf162725 	req.wLength = (uint16_t)len;
3616629Szf162725 	req.attrs = USB_ATTRS_AUTOCLEARING;
3626629Szf162725 
3636629Szf162725 	mp = NULL;
3646629Szf162725 	err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
3656629Szf162725 	    &cr, &cf, 0);
3666629Szf162725 
3676629Szf162725 	if (err != USB_SUCCESS) {
3689345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
3696629Szf162725 		    "ural_read_multi(): could not read MAC register:"
3706629Szf162725 		    "cr:%s(%d), cf:(%x)\n",
3716629Szf162725 		    usb_str_cr(cr), cr, cf);
3726629Szf162725 		return;
3736629Szf162725 	}
3746629Szf162725 
3756629Szf162725 	bcopy(mp->b_rptr, buf, len);
3766629Szf162725 
3776629Szf162725 	if (mp)
3786629Szf162725 		freemsg(mp);
3796629Szf162725 }
3806629Szf162725 
3816629Szf162725 static void
ural_write(struct ural_softc * sc,uint16_t reg,uint16_t val)3826629Szf162725 ural_write(struct ural_softc *sc, uint16_t reg, uint16_t val)
3836629Szf162725 {
3846629Szf162725 	usb_ctrl_setup_t req;
3856629Szf162725 	usb_cr_t cr;
3866629Szf162725 	usb_cb_flags_t cf;
3876629Szf162725 	int err;
3886629Szf162725 
3896629Szf162725 	bzero(&req, sizeof (req));
3906629Szf162725 	req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_HOST_TO_DEV;
3916629Szf162725 	req.bRequest = RAL_WRITE_MAC;
3926629Szf162725 	req.wValue = val;
3936629Szf162725 	req.wIndex = reg;
3946629Szf162725 	req.wLength = 0;
3956629Szf162725 	req.attrs = USB_ATTRS_NONE;
3966629Szf162725 
3976629Szf162725 	err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, NULL,
3986629Szf162725 	    &cr, &cf, 0);
3996629Szf162725 
4006629Szf162725 	if (err != USB_SUCCESS) {
4019345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
4026629Szf162725 		    "ural_write(): could not write MAC register:"
4036629Szf162725 		    "cr:%s(%d), cf:(%x)\n",
4046629Szf162725 		    usb_str_cr(cr), cr, cf);
4056629Szf162725 	}
4066629Szf162725 }
4076629Szf162725 
4086629Szf162725 /* ARGSUSED */
4096629Szf162725 static void
ural_txeof(usb_pipe_handle_t pipe,usb_bulk_req_t * req)4106629Szf162725 ural_txeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
4116629Szf162725 {
4126629Szf162725 	struct ural_softc *sc = (struct ural_softc *)req->bulk_client_private;
4136629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
4146629Szf162725 
4159345SQuaker.Fang@Sun.COM 	ral_debug(RAL_DBG_TX,
4166629Szf162725 	    "ural_txeof(): cr:%s(%d), flags:0x%x, tx_queued:%d",
4176629Szf162725 	    usb_str_cr(req->bulk_completion_reason),
4186629Szf162725 	    req->bulk_completion_reason,
4196629Szf162725 	    req->bulk_cb_flags,
4206629Szf162725 	    sc->tx_queued);
4216629Szf162725 
4226629Szf162725 	if (req->bulk_completion_reason != USB_CR_OK)
4236629Szf162725 		sc->sc_tx_err++;
4246629Szf162725 
4256629Szf162725 	mutex_enter(&sc->tx_lock);
4266629Szf162725 
4276629Szf162725 	sc->tx_queued--;
4286629Szf162725 	sc->sc_tx_timer = 0;
4296629Szf162725 
4306629Szf162725 	if (sc->sc_need_sched) {
4316629Szf162725 		sc->sc_need_sched = 0;
4326629Szf162725 		mac_tx_update(ic->ic_mach);
4336629Szf162725 	}
4346629Szf162725 
4356629Szf162725 	mutex_exit(&sc->tx_lock);
4366629Szf162725 	usb_free_bulk_req(req);
4376629Szf162725 }
4386629Szf162725 
4396629Szf162725 /* ARGSUSED */
4406629Szf162725 static void
ural_rxeof(usb_pipe_handle_t pipe,usb_bulk_req_t * req)4416629Szf162725 ural_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
4426629Szf162725 {
4436629Szf162725 	struct ural_softc *sc = (struct ural_softc *)req->bulk_client_private;
4446629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
4456629Szf162725 
4466629Szf162725 	struct ural_rx_desc *desc;
4476629Szf162725 	struct ieee80211_frame *wh;
4486629Szf162725 	struct ieee80211_node *ni;
4496629Szf162725 
4506629Szf162725 	mblk_t *m, *mp;
4516629Szf162725 	int len, pktlen;
4526629Szf162725 	char *rxbuf;
4536629Szf162725 
4546629Szf162725 	mp = req->bulk_data;
4556629Szf162725 	req->bulk_data = NULL;
4566629Szf162725 
4579345SQuaker.Fang@Sun.COM 	ral_debug(RAL_DBG_RX,
4586629Szf162725 	    "ural_rxeof(): cr:%s(%d), flags:0x%x, rx_queued:%d",
4596629Szf162725 	    usb_str_cr(req->bulk_completion_reason),
4606629Szf162725 	    req->bulk_completion_reason,
4616629Szf162725 	    req->bulk_cb_flags,
4626629Szf162725 	    sc->rx_queued);
4636629Szf162725 
4646629Szf162725 	if (req->bulk_completion_reason != USB_CR_OK) {
4656629Szf162725 		sc->sc_rx_err++;
4666629Szf162725 		goto fail;
4676629Szf162725 	}
4686629Szf162725 
4696629Szf162725 	len = (uintptr_t)mp->b_wptr - (uintptr_t)mp->b_rptr;
4706629Szf162725 	rxbuf = (char *)mp->b_rptr;
4716629Szf162725 
4726629Szf162725 	if (len < RAL_RX_DESC_SIZE + IEEE80211_MIN_LEN) {
4739345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
4746629Szf162725 		    "ural_rxeof(): xfer too short %d\n", len);
4756629Szf162725 		sc->sc_rx_err++;
4766629Szf162725 		goto fail;
4776629Szf162725 	}
4786629Szf162725 
4796629Szf162725 	/* rx descriptor is located at the end */
4806629Szf162725 	desc = (struct ural_rx_desc *)(rxbuf + len - RAL_RX_DESC_SIZE);
4816629Szf162725 
4826629Szf162725 	if ((LE_32(desc->flags) & RAL_RX_PHY_ERROR) ||
4836629Szf162725 	    (LE_32(desc->flags) & RAL_RX_CRC_ERROR)) {
4846629Szf162725 		/*
4856629Szf162725 		 * This should not happen since we did not request to receive
4866629Szf162725 		 * those frames when we filled RAL_TXRX_CSR2.
4876629Szf162725 		 */
4889345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "PHY or CRC error\n");
4896629Szf162725 		sc->sc_rx_err++;
4906629Szf162725 		goto fail;
4916629Szf162725 	}
4926629Szf162725 
4936629Szf162725 	pktlen = (LE_32(desc->flags) >> 16) & 0xfff;
4946629Szf162725 
4956629Szf162725 	if (pktlen > (len - RAL_RX_DESC_SIZE)) {
4969345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
4976629Szf162725 		    "ural_rxeof(): pktlen mismatch <%d, %d>.\n", pktlen, len);
4986629Szf162725 		goto fail;
4996629Szf162725 	}
5006629Szf162725 
5016629Szf162725 	/* Strip trailing 802.11 MAC FCS. */
5026629Szf162725 	pktlen -= IEEE80211_CRC_LEN;
5036629Szf162725 
5046629Szf162725 	if ((m = allocb(pktlen, BPRI_MED)) == NULL) {
5059345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
5066629Szf162725 		    "ural_rxeof(): allocate mblk failed.\n");
5076629Szf162725 		sc->sc_rx_nobuf++;
5086629Szf162725 		goto fail;
5096629Szf162725 	}
5106629Szf162725 
5116629Szf162725 	bcopy(rxbuf, m->b_rptr, pktlen);
5126629Szf162725 	m->b_wptr += pktlen;
5136629Szf162725 
5146629Szf162725 	wh = (struct ieee80211_frame *)m->b_rptr;
5156629Szf162725 	ni = ieee80211_find_rxnode(ic, wh);
5166629Szf162725 
5176629Szf162725 	/* send the frame to the 802.11 layer */
5186629Szf162725 	(void) ieee80211_input(ic, m, ni, desc->rssi, 0);
5196629Szf162725 
5206629Szf162725 	/* node is no longer needed */
5216629Szf162725 	ieee80211_free_node(ni);
5226629Szf162725 fail:
5236629Szf162725 	mutex_enter(&sc->rx_lock);
5246629Szf162725 	sc->rx_queued--;
5256629Szf162725 	mutex_exit(&sc->rx_lock);
5266629Szf162725 
5276629Szf162725 	freemsg(mp);
5286629Szf162725 	usb_free_bulk_req(req);
5296629Szf162725 
5306629Szf162725 	if (RAL_IS_RUNNING(sc))
5316629Szf162725 		(void) ural_rx_trigger(sc);
5326629Szf162725 }
5336629Szf162725 
5346629Szf162725 /*
5356629Szf162725  * Return the expected ack rate for a frame transmitted at rate `rate'.
5366629Szf162725  * this should depend on the destination node basic rate set.
5376629Szf162725  */
5386629Szf162725 static int
ural_ack_rate(struct ieee80211com * ic,int rate)5396629Szf162725 ural_ack_rate(struct ieee80211com *ic, int rate)
5406629Szf162725 {
5416629Szf162725 	switch (rate) {
5426629Szf162725 	/* CCK rates */
5436629Szf162725 	case 2:
5446629Szf162725 		return (2);
5456629Szf162725 	case 4:
5466629Szf162725 	case 11:
5476629Szf162725 	case 22:
5486629Szf162725 		return ((ic->ic_curmode == IEEE80211_MODE_11B) ? 4 : rate);
5496629Szf162725 
5506629Szf162725 	/* OFDM rates */
5516629Szf162725 	case 12:
5526629Szf162725 	case 18:
5536629Szf162725 		return (12);
5546629Szf162725 	case 24:
5556629Szf162725 	case 36:
5566629Szf162725 		return (24);
5576629Szf162725 	case 48:
5586629Szf162725 	case 72:
5596629Szf162725 	case 96:
5606629Szf162725 	case 108:
5616629Szf162725 		return (48);
5626629Szf162725 	}
5636629Szf162725 
5646629Szf162725 	/* default to 1Mbps */
5656629Szf162725 	return (2);
5666629Szf162725 }
5676629Szf162725 
5686629Szf162725 /*
5696629Szf162725  * Compute the duration (in us) needed to transmit `len' bytes at rate `rate'.
5706629Szf162725  * The function automatically determines the operating mode depending on the
5716629Szf162725  * given rate. `flags' indicates whether short preamble is in use or not.
5726629Szf162725  */
5736629Szf162725 static uint16_t
ural_txtime(int len,int rate,uint32_t flags)5746629Szf162725 ural_txtime(int len, int rate, uint32_t flags)
5756629Szf162725 {
5766629Szf162725 	uint16_t txtime;
5776629Szf162725 
5786629Szf162725 	if (RAL_RATE_IS_OFDM(rate)) {
5796629Szf162725 		/* IEEE Std 802.11a-1999, pp. 37 */
5806629Szf162725 		txtime = (8 + 4 * len + 3 + rate - 1) / rate;
5816629Szf162725 		txtime = 16 + 4 + 4 * txtime + 6;
5826629Szf162725 	} else {
5836629Szf162725 		/* IEEE Std 802.11b-1999, pp. 28 */
5846629Szf162725 		txtime = (16 * len + rate - 1) / rate;
5856629Szf162725 		if (rate != 2 && (flags & IEEE80211_F_SHPREAMBLE))
5866629Szf162725 			txtime +=  72 + 24;
5876629Szf162725 		else
5886629Szf162725 			txtime += 144 + 48;
5896629Szf162725 	}
5906629Szf162725 	return (txtime);
5916629Szf162725 }
5926629Szf162725 
5936629Szf162725 static uint8_t
ural_plcp_signal(int rate)5946629Szf162725 ural_plcp_signal(int rate)
5956629Szf162725 {
5966629Szf162725 	switch (rate) {
5976629Szf162725 	/* CCK rates (returned values are device-dependent) */
5986629Szf162725 	case 2:		return (0x0);
5996629Szf162725 	case 4:		return (0x1);
6006629Szf162725 	case 11:	return (0x2);
6016629Szf162725 	case 22:	return (0x3);
6026629Szf162725 
6036629Szf162725 	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
6046629Szf162725 	case 12:	return (0xb);
6056629Szf162725 	case 18:	return (0xf);
6066629Szf162725 	case 24:	return (0xa);
6076629Szf162725 	case 36:	return (0xe);
6086629Szf162725 	case 48:	return (0x9);
6096629Szf162725 	case 72:	return (0xd);
6106629Szf162725 	case 96:	return (0x8);
6116629Szf162725 	case 108:	return (0xc);
6126629Szf162725 
6136629Szf162725 	/* unsupported rates (should not get there) */
6146629Szf162725 	default:	return (0xff);
6156629Szf162725 	}
6166629Szf162725 }
6176629Szf162725 
6186629Szf162725 static void
ural_setup_tx_desc(struct ural_softc * sc,struct ural_tx_desc * desc,uint32_t flags,int len,int rate)6196629Szf162725 ural_setup_tx_desc(struct ural_softc *sc, struct ural_tx_desc *desc,
6206629Szf162725     uint32_t flags, int len, int rate)
6216629Szf162725 {
6226629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
6236629Szf162725 	uint16_t plcp_length;
6246629Szf162725 	int remainder;
6256629Szf162725 
6266629Szf162725 	desc->flags = LE_32(flags);
6276629Szf162725 	desc->flags |= LE_32(RAL_TX_NEWSEQ);
6286629Szf162725 	desc->flags |= LE_32(len << 16);
6296629Szf162725 
6306629Szf162725 	desc->wme = LE_16(RAL_AIFSN(2) | RAL_LOGCWMIN(3) | RAL_LOGCWMAX(5));
6316629Szf162725 	desc->wme |= LE_16(RAL_IVOFFSET(sizeof (struct ieee80211_frame)));
6326629Szf162725 
6336629Szf162725 	/* setup PLCP fields */
6346629Szf162725 	desc->plcp_signal  = ural_plcp_signal(rate);
6356629Szf162725 	desc->plcp_service = 4;
6366629Szf162725 
6376629Szf162725 	len += IEEE80211_CRC_LEN;
6386629Szf162725 	if (RAL_RATE_IS_OFDM(rate)) {
6396629Szf162725 		desc->flags |= LE_32(RAL_TX_OFDM);
6406629Szf162725 
6416629Szf162725 		plcp_length = len & 0xfff;
6426629Szf162725 		desc->plcp_length_hi = plcp_length >> 6;
6436629Szf162725 		desc->plcp_length_lo = plcp_length & 0x3f;
6446629Szf162725 	} else {
6456629Szf162725 		plcp_length = (16 * len + rate - 1) / rate;
6466629Szf162725 		if (rate == 22) {
6476629Szf162725 			remainder = (16 * len) % 22;
6486629Szf162725 			if (remainder != 0 && remainder < 7)
6496629Szf162725 				desc->plcp_service |= RAL_PLCP_LENGEXT;
6506629Szf162725 		}
6516629Szf162725 		desc->plcp_length_hi = plcp_length >> 8;
6526629Szf162725 		desc->plcp_length_lo = plcp_length & 0xff;
6536629Szf162725 
6546629Szf162725 		if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
6556629Szf162725 			desc->plcp_signal |= 0x08;
6566629Szf162725 	}
6576629Szf162725 
6586629Szf162725 	desc->iv = 0;
6596629Szf162725 	desc->eiv = 0;
6606629Szf162725 }
6616629Szf162725 
6626629Szf162725 #define	RAL_TX_TIMEOUT		5
6636629Szf162725 
6646629Szf162725 static int
ural_send(ieee80211com_t * ic,mblk_t * mp,uint8_t type)6656629Szf162725 ural_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
6666629Szf162725 {
6676629Szf162725 	struct ural_softc *sc = (struct ural_softc *)ic;
6686629Szf162725 	struct ural_tx_desc *desc;
6696629Szf162725 
6706629Szf162725 	struct ieee80211_frame *wh;
6716629Szf162725 	struct ieee80211_key *k;
6726629Szf162725 
6736629Szf162725 	uint16_t dur;
6746629Szf162725 	uint32_t flags = 0;
6756629Szf162725 	int rate, err = DDI_SUCCESS;
6766629Szf162725 
6776629Szf162725 	struct ieee80211_node *ni = NULL;
6786629Szf162725 	mblk_t *m, *m0;
6796629Szf162725 	int off, mblen, pktlen, xferlen;
6806629Szf162725 
6819345SQuaker.Fang@Sun.COM 	/* discard packets while suspending or not inited */
6829345SQuaker.Fang@Sun.COM 	if (!RAL_IS_RUNNING(sc)) {
6839345SQuaker.Fang@Sun.COM 		freemsg(mp);
6849345SQuaker.Fang@Sun.COM 		return (ENXIO);
6859345SQuaker.Fang@Sun.COM 	}
6869345SQuaker.Fang@Sun.COM 
6876629Szf162725 	mutex_enter(&sc->tx_lock);
6886629Szf162725 
6896629Szf162725 	if (sc->tx_queued > RAL_TX_LIST_COUNT) {
6909345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_TX, "ural_send(): "
6916629Szf162725 		    "no TX buffer available!\n");
6926629Szf162725 		if ((type & IEEE80211_FC0_TYPE_MASK) ==
6936629Szf162725 		    IEEE80211_FC0_TYPE_DATA) {
6946629Szf162725 			sc->sc_need_sched = 1;
6956629Szf162725 		}
6966629Szf162725 		sc->sc_tx_nobuf++;
6976629Szf162725 		err = ENOMEM;
6986629Szf162725 		goto fail;
6996629Szf162725 	}
7006629Szf162725 
7016629Szf162725 	m = allocb(RAL_TXBUF_SIZE + RAL_TX_DESC_SIZE, BPRI_MED);
7026629Szf162725 	if (m == NULL) {
7039345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "ural_send(): can't alloc mblk.\n");
7046629Szf162725 		err = DDI_FAILURE;
7056629Szf162725 		goto fail;
7066629Szf162725 	}
7076629Szf162725 
7086629Szf162725 	m->b_rptr += RAL_TX_DESC_SIZE;	/* skip TX descriptor */
7096629Szf162725 	m->b_wptr += RAL_TX_DESC_SIZE;
7106629Szf162725 
7116629Szf162725 	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
7126629Szf162725 		mblen = (uintptr_t)m0->b_wptr - (uintptr_t)m0->b_rptr;
7136629Szf162725 		(void) memcpy(m->b_rptr + off, m0->b_rptr, mblen);
7146629Szf162725 		off += mblen;
7156629Szf162725 	}
7166629Szf162725 	m->b_wptr += off;
7176629Szf162725 
7186629Szf162725 	wh = (struct ieee80211_frame *)m->b_rptr;
7196629Szf162725 
7206629Szf162725 	ni = ieee80211_find_txnode(ic, wh->i_addr1);
7216629Szf162725 	if (ni == NULL) {
7226629Szf162725 		err = DDI_FAILURE;
7236629Szf162725 		sc->sc_tx_err++;
7246629Szf162725 		freemsg(m);
7256629Szf162725 		goto fail;
7266629Szf162725 	}
7276629Szf162725 
7286629Szf162725 	if ((type & IEEE80211_FC0_TYPE_MASK) ==
7296629Szf162725 	    IEEE80211_FC0_TYPE_DATA) {
7306629Szf162725 		(void) ieee80211_encap(ic, m, ni);
7316629Szf162725 	}
7326629Szf162725 
7336629Szf162725 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
7346629Szf162725 		k = ieee80211_crypto_encap(ic, m);
7356629Szf162725 		if (k == NULL) {
7366629Szf162725 			sc->sc_tx_err++;
7376629Szf162725 			freemsg(m);
7386629Szf162725 			err = DDI_FAILURE;
7396629Szf162725 			goto fail;
7406629Szf162725 		}
7416629Szf162725 		/* packet header may have moved, reset our local pointer */
7426629Szf162725 		wh = (struct ieee80211_frame *)m->b_rptr;
7436629Szf162725 	}
7446629Szf162725 
7456629Szf162725 	m->b_rptr -= RAL_TX_DESC_SIZE;	/* restore */
7466629Szf162725 	desc = (struct ural_tx_desc *)m->b_rptr;
7476629Szf162725 
7486629Szf162725 	if ((type & IEEE80211_FC0_TYPE_MASK) ==
7496629Szf162725 	    IEEE80211_FC0_TYPE_DATA) {	/* DATA */
7506629Szf162725 		if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
7516629Szf162725 			rate = ic->ic_bss->in_rates.ir_rates[ic->ic_fixed_rate];
7526629Szf162725 		else
7536629Szf162725 			rate = ni->in_rates.ir_rates[ni->in_txrate];
7546629Szf162725 
7556629Szf162725 		rate &= IEEE80211_RATE_VAL;
7566629Szf162725 		if (rate <= 0) {
7576629Szf162725 			rate = 2;	/* basic rate */
7586629Szf162725 		}
7596629Szf162725 
7606629Szf162725 		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
7616629Szf162725 			flags |= RAL_TX_ACK;
7626629Szf162725 			flags |= RAL_TX_RETRY(7);
7636629Szf162725 
7646629Szf162725 			dur = ural_txtime(RAL_ACK_SIZE, ural_ack_rate(ic, rate),
7656629Szf162725 			    ic->ic_flags) + RAL_SIFS;
7666629Szf162725 			*(uint16_t *)(uintptr_t)wh->i_dur = LE_16(dur);
7676629Szf162725 		}
7686629Szf162725 	} else {	/* MGMT */
7696629Szf162725 		rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ? 12 : 2;
7706629Szf162725 
7716629Szf162725 		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
7726629Szf162725 			flags |= RAL_TX_ACK;
7736629Szf162725 
7746629Szf162725 			dur = ural_txtime(RAL_ACK_SIZE, rate, ic->ic_flags)
7756629Szf162725 			    + RAL_SIFS;
7766629Szf162725 			*(uint16_t *)(uintptr_t)wh->i_dur = LE_16(dur);
7776629Szf162725 
7786629Szf162725 			/* tell hardware to add timestamp for probe responses */
7796629Szf162725 			if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
7806629Szf162725 			    IEEE80211_FC0_TYPE_MGT &&
7816629Szf162725 			    (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
7826629Szf162725 			    IEEE80211_FC0_SUBTYPE_PROBE_RESP)
7836629Szf162725 				flags |= RAL_TX_TIMESTAMP;
7846629Szf162725 		}
7856629Szf162725 	}
7866629Szf162725 
7876629Szf162725 	pktlen = (uintptr_t)m->b_wptr - (uintptr_t)m->b_rptr - RAL_TX_DESC_SIZE;
7886629Szf162725 	ural_setup_tx_desc(sc, desc, flags, pktlen, rate);
7896629Szf162725 
7906629Szf162725 	/* align end on a 2-bytes boundary */
7916629Szf162725 	xferlen = (RAL_TX_DESC_SIZE + pktlen + 1) & ~1;
7926629Szf162725 
7936629Szf162725 	/*
7946629Szf162725 	 * No space left in the last URB to store the extra 2 bytes, force
7956629Szf162725 	 * sending of another URB.
7966629Szf162725 	 */
7976629Szf162725 	if ((xferlen % 64) == 0)
7986629Szf162725 		xferlen += 2;
7996629Szf162725 
8006629Szf162725 	m->b_wptr = m->b_rptr + xferlen;
8016629Szf162725 
8029345SQuaker.Fang@Sun.COM 	ral_debug(RAL_DBG_TX, "sending data frame len=%u rate=%u xfer len=%u\n",
8036629Szf162725 	    pktlen, rate, xferlen);
8046629Szf162725 
8056629Szf162725 	(void) ural_tx_trigger(sc, m);
8066629Szf162725 
8076629Szf162725 	ic->ic_stats.is_tx_frags++;
8086629Szf162725 	ic->ic_stats.is_tx_bytes += pktlen;
8096629Szf162725 
8106629Szf162725 fail:
8116629Szf162725 	if (ni != NULL)
8126629Szf162725 		ieee80211_free_node(ni);
8136629Szf162725 
8146629Szf162725 	if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA ||
8156629Szf162725 	    err == 0) {
8166629Szf162725 		freemsg(mp);
8176629Szf162725 	}
8186629Szf162725 
8196629Szf162725 	mutex_exit(&sc->tx_lock);
8206629Szf162725 
8216629Szf162725 	return (err);
8226629Szf162725 }
8236629Szf162725 
8246629Szf162725 static mblk_t *
ural_m_tx(void * arg,mblk_t * mp)8256629Szf162725 ural_m_tx(void *arg, mblk_t *mp)
8266629Szf162725 {
8276629Szf162725 	struct ural_softc *sc = (struct ural_softc *)arg;
8286629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
8296629Szf162725 	mblk_t *next;
8306629Szf162725 
8316629Szf162725 	/*
8326629Szf162725 	 * No data frames go out unless we're associated; this
8336629Szf162725 	 * should not happen as the 802.11 layer does not enable
8346629Szf162725 	 * the xmit queue until we enter the RUN state.
8356629Szf162725 	 */
8366629Szf162725 	if (ic->ic_state != IEEE80211_S_RUN) {
8379345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "ural_m_tx(): "
8386629Szf162725 		    "discard, state %u\n", ic->ic_state);
8396629Szf162725 		freemsgchain(mp);
8406629Szf162725 		return (NULL);
8416629Szf162725 	}
8426629Szf162725 
8436629Szf162725 	while (mp != NULL) {
8446629Szf162725 		next = mp->b_next;
8456629Szf162725 		mp->b_next = NULL;
8466629Szf162725 		if (ural_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != DDI_SUCCESS) {
8476629Szf162725 			mp->b_next = next;
8486629Szf162725 			freemsgchain(mp);
8496629Szf162725 			return (NULL);
8506629Szf162725 		}
8516629Szf162725 		mp = next;
8526629Szf162725 	}
8536629Szf162725 	return (mp);
8546629Szf162725 }
8556629Szf162725 
8566629Szf162725 static void
ural_set_testmode(struct ural_softc * sc)8576629Szf162725 ural_set_testmode(struct ural_softc *sc)
8586629Szf162725 {
8596629Szf162725 	usb_ctrl_setup_t req;
8606629Szf162725 	usb_cr_t cr;
8616629Szf162725 	usb_cb_flags_t cf;
8626629Szf162725 	int err;
8636629Szf162725 
8646629Szf162725 	bzero(&req, sizeof (req));
8656629Szf162725 	req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_HOST_TO_DEV;
8666629Szf162725 	req.bRequest = RAL_VENDOR_REQUEST;
8676629Szf162725 	req.wValue = 4;
8686629Szf162725 	req.wIndex = 1;
8696629Szf162725 	req.wLength = 0;
8706629Szf162725 	req.attrs = USB_ATTRS_NONE;
8716629Szf162725 
8726629Szf162725 	err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, NULL,
8736629Szf162725 	    &cr, &cf, 0);
8746629Szf162725 
8756629Szf162725 	if (err != USB_SUCCESS) {
8769345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_USB,
8776629Szf162725 		    "ural_set_testmode(): could not set test mode:"
8786629Szf162725 		    "cr:%s(%d), cf:%(x)\n",
8796629Szf162725 		    usb_str_cr(cr), cr, cf);
8806629Szf162725 	}
8816629Szf162725 }
8826629Szf162725 
8836629Szf162725 static void
ural_eeprom_read(struct ural_softc * sc,uint16_t addr,void * buf,int len)8846629Szf162725 ural_eeprom_read(struct ural_softc *sc, uint16_t addr, void *buf, int len)
8856629Szf162725 {
8866629Szf162725 	usb_ctrl_setup_t req;
8876629Szf162725 	usb_cr_t cr;
8886629Szf162725 	usb_cb_flags_t cf;
8896629Szf162725 	mblk_t *mp;
8906629Szf162725 	int err;
8916629Szf162725 
8926629Szf162725 	bzero(&req, sizeof (req));
8936629Szf162725 	req.bmRequestType = USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_DEV_TO_HOST;
8946629Szf162725 	req.bRequest = RAL_READ_EEPROM;
8956629Szf162725 	req.wValue = 0;
8966629Szf162725 	req.wIndex = addr;
8976629Szf162725 	req.wLength = (uint16_t)len;
8986629Szf162725 
8996629Szf162725 	mp = NULL;
9006629Szf162725 	err = usb_pipe_ctrl_xfer_wait(sc->sc_udev->dev_default_ph, &req, &mp,
9016629Szf162725 	    &cr, &cf, 0);
9026629Szf162725 
9036629Szf162725 	if (err != USB_SUCCESS) {
9049345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_USB,
9056629Szf162725 		    "ural_eeprom_read(): could not read EEPROM:"
9066629Szf162725 		    "cr:%s(%d), cf:(%x)\n",
9076629Szf162725 		    usb_str_cr(cr), cr, cf);
9086629Szf162725 		return;
9096629Szf162725 	}
9106629Szf162725 
9116629Szf162725 	bcopy(mp->b_rptr, buf, len);
9126629Szf162725 
9136629Szf162725 	if (mp)
9146629Szf162725 		freemsg(mp);
9156629Szf162725 }
9166629Szf162725 
9176629Szf162725 static void
ural_bbp_write(struct ural_softc * sc,uint8_t reg,uint8_t val)9186629Szf162725 ural_bbp_write(struct ural_softc *sc, uint8_t reg, uint8_t val)
9196629Szf162725 {
9206629Szf162725 	uint16_t tmp;
9216629Szf162725 	int ntries;
9226629Szf162725 
9236629Szf162725 	for (ntries = 0; ntries < 5; ntries++) {
9246629Szf162725 		if (!(ural_read(sc, RAL_PHY_CSR8) & RAL_BBP_BUSY))
9256629Szf162725 			break;
9266629Szf162725 	}
9276629Szf162725 	if (ntries == 5) {
9289345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
9296629Szf162725 		    "ural_bbp_write(): could not write to BBP\n");
9306629Szf162725 		return;
9316629Szf162725 	}
9326629Szf162725 
9336629Szf162725 	tmp = reg << 8 | val;
9346629Szf162725 	ural_write(sc, RAL_PHY_CSR7, tmp);
9356629Szf162725 }
9366629Szf162725 
9376629Szf162725 static uint8_t
ural_bbp_read(struct ural_softc * sc,uint8_t reg)9386629Szf162725 ural_bbp_read(struct ural_softc *sc, uint8_t reg)
9396629Szf162725 {
9406629Szf162725 	uint16_t val;
9416629Szf162725 	int ntries;
9426629Szf162725 
9436629Szf162725 	val = RAL_BBP_WRITE | reg << 8;
9446629Szf162725 	ural_write(sc, RAL_PHY_CSR7, val);
9456629Szf162725 
9466629Szf162725 	for (ntries = 0; ntries < 5; ntries++) {
9476629Szf162725 		if (!(ural_read(sc, RAL_PHY_CSR8) & RAL_BBP_BUSY))
9486629Szf162725 			break;
9496629Szf162725 	}
9506629Szf162725 	if (ntries == 5) {
9519345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "ural_bbp_read(): could not read BBP\n");
9526629Szf162725 		return (0);
9536629Szf162725 	}
9546629Szf162725 
9556629Szf162725 	return (ural_read(sc, RAL_PHY_CSR7) & 0xff);
9566629Szf162725 }
9576629Szf162725 
9586629Szf162725 static void
ural_rf_write(struct ural_softc * sc,uint8_t reg,uint32_t val)9596629Szf162725 ural_rf_write(struct ural_softc *sc, uint8_t reg, uint32_t val)
9606629Szf162725 {
9616629Szf162725 	uint32_t tmp;
9626629Szf162725 	int ntries;
9636629Szf162725 
9646629Szf162725 	for (ntries = 0; ntries < 5; ntries++) {
9656629Szf162725 		if (!(ural_read(sc, RAL_PHY_CSR10) & RAL_RF_LOBUSY))
9666629Szf162725 			break;
9676629Szf162725 	}
9686629Szf162725 	if (ntries == 5) {
9699345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
9706629Szf162725 		    "ural_rf_write(): could not write to RF\n");
9716629Szf162725 		return;
9726629Szf162725 	}
9736629Szf162725 
9746629Szf162725 	tmp = RAL_RF_BUSY | RAL_RF_20BIT | (val & 0xffff) << 2 | (reg & 0x3);
9756629Szf162725 	ural_write(sc, RAL_PHY_CSR9,  tmp & 0xffff);
9766629Szf162725 	ural_write(sc, RAL_PHY_CSR10, tmp >> 16);
9776629Szf162725 
9786629Szf162725 	/* remember last written value in sc */
9796629Szf162725 	sc->rf_regs[reg] = val;
9806629Szf162725 
9819345SQuaker.Fang@Sun.COM 	ral_debug(RAL_DBG_HW, "RF R[%u] <- 0x%05x\n", reg & 0x3, val & 0xfffff);
9826629Szf162725 }
9836629Szf162725 
9846629Szf162725 /*
9856629Szf162725  * Disable RF auto-tuning.
9866629Szf162725  */
9876629Szf162725 static void
ural_disable_rf_tune(struct ural_softc * sc)9886629Szf162725 ural_disable_rf_tune(struct ural_softc *sc)
9896629Szf162725 {
9906629Szf162725 	uint32_t tmp;
9916629Szf162725 
9926629Szf162725 	if (sc->rf_rev != RAL_RF_2523) {
9936629Szf162725 		tmp = sc->rf_regs[RAL_RF1] & ~RAL_RF1_AUTOTUNE;
9946629Szf162725 		ural_rf_write(sc, RAL_RF1, tmp);
9956629Szf162725 	}
9966629Szf162725 
9976629Szf162725 	tmp = sc->rf_regs[RAL_RF3] & ~RAL_RF3_AUTOTUNE;
9986629Szf162725 	ural_rf_write(sc, RAL_RF3, tmp);
9996629Szf162725 
10009345SQuaker.Fang@Sun.COM 	ral_debug(RAL_DBG_HW, "disabling RF autotune\n");
10016629Szf162725 }
10026629Szf162725 
10036629Szf162725 
10046629Szf162725 static void
ural_set_chan(struct ural_softc * sc,struct ieee80211_channel * c)10056629Szf162725 ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
10066629Szf162725 {
10076629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
10086629Szf162725 	uint8_t power, tmp;
10096629Szf162725 	uint_t i, chan;
10106629Szf162725 
10116629Szf162725 	chan = ieee80211_chan2ieee(ic, c);
10126629Szf162725 	if (chan == 0 || chan == IEEE80211_CHAN_ANY)
10136629Szf162725 		return;
10146629Szf162725 
10156629Szf162725 	if (IEEE80211_IS_CHAN_2GHZ(c))
10166629Szf162725 		power = min(sc->txpow[chan - 1], 31);
10176629Szf162725 	else
10186629Szf162725 		power = 31;
10196629Szf162725 
10206629Szf162725 	/* adjust txpower using ifconfig settings */
10216629Szf162725 	power -= (100 - ic->ic_txpowlimit) / 8;
10226629Szf162725 
10239345SQuaker.Fang@Sun.COM 	ral_debug(RAL_DBG_HW, "setting channel to %u, txpower to %u\n",
10246629Szf162725 	    chan, power);
10256629Szf162725 
10266629Szf162725 	switch (sc->rf_rev) {
10276629Szf162725 	case RAL_RF_2522:
10286629Szf162725 		ural_rf_write(sc, RAL_RF1, 0x00814);
10296629Szf162725 		ural_rf_write(sc, RAL_RF2, ural_rf2522_r2[chan - 1]);
10306629Szf162725 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
10316629Szf162725 		break;
10326629Szf162725 
10336629Szf162725 	case RAL_RF_2523:
10346629Szf162725 		ural_rf_write(sc, RAL_RF1, 0x08804);
10356629Szf162725 		ural_rf_write(sc, RAL_RF2, ural_rf2523_r2[chan - 1]);
10366629Szf162725 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x38044);
10376629Szf162725 		ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
10386629Szf162725 		break;
10396629Szf162725 
10406629Szf162725 	case RAL_RF_2524:
10416629Szf162725 		ural_rf_write(sc, RAL_RF1, 0x0c808);
10426629Szf162725 		ural_rf_write(sc, RAL_RF2, ural_rf2524_r2[chan - 1]);
10436629Szf162725 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
10446629Szf162725 		ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
10456629Szf162725 		break;
10466629Szf162725 
10476629Szf162725 	case RAL_RF_2525:
10486629Szf162725 		ural_rf_write(sc, RAL_RF1, 0x08808);
10496629Szf162725 		ural_rf_write(sc, RAL_RF2, ural_rf2525_hi_r2[chan - 1]);
10506629Szf162725 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
10516629Szf162725 		ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
10526629Szf162725 
10536629Szf162725 		ural_rf_write(sc, RAL_RF1, 0x08808);
10546629Szf162725 		ural_rf_write(sc, RAL_RF2, ural_rf2525_r2[chan - 1]);
10556629Szf162725 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
10566629Szf162725 		ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00280 : 0x00286);
10576629Szf162725 		break;
10586629Szf162725 
10596629Szf162725 	case RAL_RF_2525E:
10606629Szf162725 		ural_rf_write(sc, RAL_RF1, 0x08808);
10616629Szf162725 		ural_rf_write(sc, RAL_RF2, ural_rf2525e_r2[chan - 1]);
10626629Szf162725 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
10636629Szf162725 		ural_rf_write(sc, RAL_RF4, (chan == 14) ? 0x00286 : 0x00282);
10646629Szf162725 		break;
10656629Szf162725 
10666629Szf162725 	case RAL_RF_2526:
10676629Szf162725 		ural_rf_write(sc, RAL_RF2, ural_rf2526_hi_r2[chan - 1]);
10686629Szf162725 		ural_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381);
10696629Szf162725 		ural_rf_write(sc, RAL_RF1, 0x08804);
10706629Szf162725 
10716629Szf162725 		ural_rf_write(sc, RAL_RF2, ural_rf2526_r2[chan - 1]);
10726629Szf162725 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x18044);
10736629Szf162725 		ural_rf_write(sc, RAL_RF4, (chan & 1) ? 0x00386 : 0x00381);
10746629Szf162725 		break;
10756629Szf162725 
10766629Szf162725 	/* dual-band RF */
10776629Szf162725 	case RAL_RF_5222:
10786629Szf162725 		for (i = 0; ural_rf5222[i].chan != chan; i++) {
10796629Szf162725 			if (i > URAL_N(ural_rf5222)) break;
10806629Szf162725 		}
10816629Szf162725 
10826629Szf162725 		ural_rf_write(sc, RAL_RF1, ural_rf5222[i].r1);
10836629Szf162725 		ural_rf_write(sc, RAL_RF2, ural_rf5222[i].r2);
10846629Szf162725 		ural_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
10856629Szf162725 		ural_rf_write(sc, RAL_RF4, ural_rf5222[i].r4);
10866629Szf162725 		break;
10876629Szf162725 	}
10886629Szf162725 
10896629Szf162725 	if (ic->ic_opmode != IEEE80211_M_MONITOR &&
10906629Szf162725 	    ic->ic_state != IEEE80211_S_SCAN) {
10916629Szf162725 		/* set Japan filter bit for channel 14 */
10926629Szf162725 		tmp = ural_bbp_read(sc, 70);
10936629Szf162725 
10946629Szf162725 		tmp &= ~RAL_JAPAN_FILTER;
10956629Szf162725 		if (chan == 14)
10966629Szf162725 			tmp |= RAL_JAPAN_FILTER;
10976629Szf162725 
10986629Szf162725 		ural_bbp_write(sc, 70, tmp);
10996629Szf162725 
11006629Szf162725 		/* clear CRC errs */
11016629Szf162725 		(void) ural_read(sc, RAL_STA_CSR0);
11026629Szf162725 
11036629Szf162725 		drv_usecwait(10000);
11046629Szf162725 		ural_disable_rf_tune(sc);
11056629Szf162725 	}
11066629Szf162725 }
11076629Szf162725 
11086629Szf162725 /*
11096629Szf162725  * Refer to IEEE Std 802.11-1999 pp. 123 for more information on TSF
11106629Szf162725  * synchronization.
11116629Szf162725  */
11126629Szf162725 static void
ural_enable_tsf_sync(struct ural_softc * sc)11136629Szf162725 ural_enable_tsf_sync(struct ural_softc *sc)
11146629Szf162725 {
11156629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
11166629Szf162725 	uint16_t logcwmin, preload, tmp;
11176629Szf162725 
11186629Szf162725 	/* first, disable TSF synchronization */
11196629Szf162725 	ural_write(sc, RAL_TXRX_CSR19, 0);
11206629Szf162725 
11216629Szf162725 	tmp = (16 * ic->ic_bss->in_intval) << 4;
11226629Szf162725 	ural_write(sc, RAL_TXRX_CSR18, tmp);
11236629Szf162725 
11246629Szf162725 	logcwmin = (ic->ic_opmode == IEEE80211_M_IBSS) ? 2 : 0;
11256629Szf162725 	preload = (ic->ic_opmode == IEEE80211_M_IBSS) ? 320 : 6;
11266629Szf162725 	tmp = logcwmin << 12 | preload;
11276629Szf162725 	ural_write(sc, RAL_TXRX_CSR20, tmp);
11286629Szf162725 
11296629Szf162725 	/* finally, enable TSF synchronization */
11306629Szf162725 	tmp = RAL_ENABLE_TSF | RAL_ENABLE_TBCN;
11316629Szf162725 	if (ic->ic_opmode == IEEE80211_M_STA)
11326629Szf162725 		tmp |= RAL_ENABLE_TSF_SYNC(1);
11336629Szf162725 	else
11346629Szf162725 		tmp |= RAL_ENABLE_TSF_SYNC(2) | RAL_ENABLE_BEACON_GENERATOR;
11356629Szf162725 	ural_write(sc, RAL_TXRX_CSR19, tmp);
11366629Szf162725 
11379345SQuaker.Fang@Sun.COM 	ral_debug(RAL_DBG_HW, "enabling TSF synchronization\n");
11386629Szf162725 }
11396629Szf162725 
11406629Szf162725 /*
11416629Szf162725  * This function can be called by ieee80211_set_shortslottime(). Refer to
11426629Szf162725  * IEEE Std 802.11-1999 pp. 85 to know how these values are computed.
11436629Szf162725  */
11446629Szf162725 /* ARGSUSED */
11456629Szf162725 static void
ural_update_slot(struct ieee80211com * ic,int onoff)11466629Szf162725 ural_update_slot(struct ieee80211com *ic, int onoff)
11476629Szf162725 {
11486629Szf162725 	struct ural_softc *sc = (struct ural_softc *)ic;
11496629Szf162725 	uint16_t slottime, sifs, eifs;
11506629Szf162725 
11516629Szf162725 	slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
11526629Szf162725 	/* slottime = (onoff ? 9 : 20); */
11536629Szf162725 
11546629Szf162725 	/*
11556629Szf162725 	 * These settings may sound a bit inconsistent but this is what the
11566629Szf162725 	 * reference driver does.
11576629Szf162725 	 */
11586629Szf162725 	if (ic->ic_curmode == IEEE80211_MODE_11B) {
11596629Szf162725 		sifs = 16 - RAL_RXTX_TURNAROUND;
11606629Szf162725 		eifs = 364;
11616629Szf162725 	} else {
11626629Szf162725 		sifs = 10 - RAL_RXTX_TURNAROUND;
11636629Szf162725 		eifs = 64;
11646629Szf162725 	}
11656629Szf162725 
11666629Szf162725 	ural_write(sc, RAL_MAC_CSR10, slottime);
11676629Szf162725 	ural_write(sc, RAL_MAC_CSR11, sifs);
11686629Szf162725 	ural_write(sc, RAL_MAC_CSR12, eifs);
11696629Szf162725 }
11706629Szf162725 
11716629Szf162725 static void
ural_set_txpreamble(struct ural_softc * sc)11726629Szf162725 ural_set_txpreamble(struct ural_softc *sc)
11736629Szf162725 {
11746629Szf162725 	uint16_t tmp;
11756629Szf162725 
11766629Szf162725 	tmp = ural_read(sc, RAL_TXRX_CSR10);
11776629Szf162725 
11786629Szf162725 	tmp &= ~RAL_SHORT_PREAMBLE;
11796629Szf162725 	if (sc->sc_ic.ic_flags & IEEE80211_F_SHPREAMBLE)
11806629Szf162725 		tmp |= RAL_SHORT_PREAMBLE;
11816629Szf162725 
11826629Szf162725 	ural_write(sc, RAL_TXRX_CSR10, tmp);
11836629Szf162725 }
11846629Szf162725 
11856629Szf162725 static void
ural_set_basicrates(struct ural_softc * sc)11866629Szf162725 ural_set_basicrates(struct ural_softc *sc)
11876629Szf162725 {
11886629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
11896629Szf162725 
11906629Szf162725 	/* update basic rate set */
11916629Szf162725 	if (ic->ic_curmode == IEEE80211_MODE_11B) {
11926629Szf162725 		/* 11b basic rates: 1, 2Mbps */
11936629Szf162725 		ural_write(sc, RAL_TXRX_CSR11, 0x3);
11946629Szf162725 	} else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->in_chan)) {
11956629Szf162725 		/* 11a basic rates: 6, 12, 24Mbps */
11966629Szf162725 		ural_write(sc, RAL_TXRX_CSR11, 0x150);
11976629Szf162725 	} else {
11986629Szf162725 		/* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */
11996629Szf162725 		ural_write(sc, RAL_TXRX_CSR11, 0x15f);
12006629Szf162725 	}
12016629Szf162725 }
12026629Szf162725 
12036629Szf162725 static void
ural_set_bssid(struct ural_softc * sc,uint8_t * bssid)12046629Szf162725 ural_set_bssid(struct ural_softc *sc, uint8_t *bssid)
12056629Szf162725 {
12066629Szf162725 	uint16_t tmp;
12076629Szf162725 
12086629Szf162725 	tmp = bssid[0] | bssid[1] << 8;
12096629Szf162725 	ural_write(sc, RAL_MAC_CSR5, tmp);
12106629Szf162725 
12116629Szf162725 	tmp = bssid[2] | bssid[3] << 8;
12126629Szf162725 	ural_write(sc, RAL_MAC_CSR6, tmp);
12136629Szf162725 
12146629Szf162725 	tmp = bssid[4] | bssid[5] << 8;
12156629Szf162725 	ural_write(sc, RAL_MAC_CSR7, tmp);
12166629Szf162725 
12179345SQuaker.Fang@Sun.COM 	ral_debug(RAL_DBG_HW, "setting BSSID to " MACSTR "\n", MAC2STR(bssid));
12186629Szf162725 }
12196629Szf162725 
12206629Szf162725 static void
ural_set_macaddr(struct ural_softc * sc,uint8_t * addr)12216629Szf162725 ural_set_macaddr(struct ural_softc *sc, uint8_t *addr)
12226629Szf162725 {
12236629Szf162725 	uint16_t tmp;
12246629Szf162725 
12256629Szf162725 	tmp = addr[0] | addr[1] << 8;
12266629Szf162725 	ural_write(sc, RAL_MAC_CSR2, tmp);
12276629Szf162725 
12286629Szf162725 	tmp = addr[2] | addr[3] << 8;
12296629Szf162725 	ural_write(sc, RAL_MAC_CSR3, tmp);
12306629Szf162725 
12316629Szf162725 	tmp = addr[4] | addr[5] << 8;
12326629Szf162725 	ural_write(sc, RAL_MAC_CSR4, tmp);
12336629Szf162725 
12349345SQuaker.Fang@Sun.COM 	ral_debug(RAL_DBG_HW,
12356629Szf162725 	    "setting MAC address to " MACSTR "\n", MAC2STR(addr));
12366629Szf162725 }
12376629Szf162725 
12386629Szf162725 static void
ural_update_promisc(struct ural_softc * sc)12396629Szf162725 ural_update_promisc(struct ural_softc *sc)
12406629Szf162725 {
12416629Szf162725 	uint32_t tmp;
12426629Szf162725 
12436629Szf162725 	tmp = ural_read(sc, RAL_TXRX_CSR2);
12446629Szf162725 
12456629Szf162725 	tmp &= ~RAL_DROP_NOT_TO_ME;
12466629Szf162725 	if (!(sc->sc_rcr & RAL_RCR_PROMISC))
12476629Szf162725 		tmp |= RAL_DROP_NOT_TO_ME;
12486629Szf162725 
12496629Szf162725 	ural_write(sc, RAL_TXRX_CSR2, tmp);
12506629Szf162725 
12519345SQuaker.Fang@Sun.COM 	ral_debug(RAL_DBG_HW, "%s promiscuous mode\n",
12526629Szf162725 	    (sc->sc_rcr & RAL_RCR_PROMISC) ?  "entering" : "leaving");
12536629Szf162725 }
12546629Szf162725 
12556629Szf162725 static const char *
ural_get_rf(int rev)12566629Szf162725 ural_get_rf(int rev)
12576629Szf162725 {
12586629Szf162725 	switch (rev) {
12596629Szf162725 	case RAL_RF_2522:	return ("RT2522");
12606629Szf162725 	case RAL_RF_2523:	return ("RT2523");
12616629Szf162725 	case RAL_RF_2524:	return ("RT2524");
12626629Szf162725 	case RAL_RF_2525:	return ("RT2525");
12636629Szf162725 	case RAL_RF_2525E:	return ("RT2525e");
12646629Szf162725 	case RAL_RF_2526:	return ("RT2526");
12656629Szf162725 	case RAL_RF_5222:	return ("RT5222");
12666629Szf162725 	default:		return ("unknown");
12676629Szf162725 	}
12686629Szf162725 }
12696629Szf162725 
12706629Szf162725 static void
ural_read_eeprom(struct ural_softc * sc)12716629Szf162725 ural_read_eeprom(struct ural_softc *sc)
12726629Szf162725 {
12736629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
12746629Szf162725 	uint16_t val;
12756629Szf162725 
12766629Szf162725 	ural_eeprom_read(sc, RAL_EEPROM_CONFIG0, &val, 2);
12776629Szf162725 	val = LE_16(val);
12786629Szf162725 	sc->rf_rev =   (val >> 11) & 0x7;
12796629Szf162725 	sc->hw_radio = (val >> 10) & 0x1;
12806629Szf162725 	sc->led_mode = (val >> 6)  & 0x7;
12816629Szf162725 	sc->rx_ant =   (val >> 4)  & 0x3;
12826629Szf162725 	sc->tx_ant =   (val >> 2)  & 0x3;
12836629Szf162725 	sc->nb_ant =   val & 0x3;
12846629Szf162725 
12856629Szf162725 	/* read MAC address */
12866629Szf162725 	ural_eeprom_read(sc, RAL_EEPROM_ADDRESS, ic->ic_macaddr, 6);
12876629Szf162725 
12886629Szf162725 	/* read default values for BBP registers */
12896629Szf162725 	ural_eeprom_read(sc, RAL_EEPROM_BBP_BASE, sc->bbp_prom, 2 * 16);
12906629Szf162725 
12916629Szf162725 	/* read Tx power for all b/g channels */
12926629Szf162725 	ural_eeprom_read(sc, RAL_EEPROM_TXPOWER, sc->txpow, 14);
12936629Szf162725 }
12946629Szf162725 
12956629Szf162725 static int
ural_bbp_init(struct ural_softc * sc)12966629Szf162725 ural_bbp_init(struct ural_softc *sc)
12976629Szf162725 {
12986629Szf162725 	int i, ntries;
12996629Szf162725 
13006629Szf162725 	/* wait for BBP to be ready */
13016629Szf162725 	for (ntries = 0; ntries < 100; ntries++) {
13026629Szf162725 		if (ural_bbp_read(sc, RAL_BBP_VERSION) != 0)
13036629Szf162725 			break;
13046629Szf162725 		drv_usecwait(1000);
13056629Szf162725 	}
13066629Szf162725 	if (ntries == 100) {
13079345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "timeout waiting for BBP\n");
13086629Szf162725 		return (EIO);
13096629Szf162725 	}
13106629Szf162725 
13116629Szf162725 	/* initialize BBP registers to default values */
13126629Szf162725 	for (i = 0; i < URAL_N(ural_def_bbp); i++)
13136629Szf162725 		ural_bbp_write(sc, ural_def_bbp[i].reg, ural_def_bbp[i].val);
13146629Szf162725 
13156629Szf162725 	return (0);
13166629Szf162725 }
13176629Szf162725 
13186629Szf162725 static void
ural_set_txantenna(struct ural_softc * sc,int antenna)13196629Szf162725 ural_set_txantenna(struct ural_softc *sc, int antenna)
13206629Szf162725 {
13216629Szf162725 	uint16_t tmp;
13226629Szf162725 	uint8_t tx;
13236629Szf162725 
13246629Szf162725 	tx = ural_bbp_read(sc, RAL_BBP_TX) & ~RAL_BBP_ANTMASK;
13256629Szf162725 	if (antenna == 1)
13266629Szf162725 		tx |= RAL_BBP_ANTA;
13276629Szf162725 	else if (antenna == 2)
13286629Szf162725 		tx |= RAL_BBP_ANTB;
13296629Szf162725 	else
13306629Szf162725 		tx |= RAL_BBP_DIVERSITY;
13316629Szf162725 
13326629Szf162725 	/* need to force I/Q flip for RF 2525e, 2526 and 5222 */
13336629Szf162725 	if (sc->rf_rev == RAL_RF_2525E || sc->rf_rev == RAL_RF_2526 ||
13346629Szf162725 	    sc->rf_rev == RAL_RF_5222)
13356629Szf162725 		tx |= RAL_BBP_FLIPIQ;
13366629Szf162725 
13376629Szf162725 	ural_bbp_write(sc, RAL_BBP_TX, tx);
13386629Szf162725 
13396629Szf162725 	/* update values in PHY_CSR5 and PHY_CSR6 */
13406629Szf162725 	tmp = ural_read(sc, RAL_PHY_CSR5) & ~0x7;
13416629Szf162725 	ural_write(sc, RAL_PHY_CSR5, tmp | (tx & 0x7));
13426629Szf162725 
13436629Szf162725 	tmp = ural_read(sc, RAL_PHY_CSR6) & ~0x7;
13446629Szf162725 	ural_write(sc, RAL_PHY_CSR6, tmp | (tx & 0x7));
13456629Szf162725 }
13466629Szf162725 
13476629Szf162725 static void
ural_set_rxantenna(struct ural_softc * sc,int antenna)13486629Szf162725 ural_set_rxantenna(struct ural_softc *sc, int antenna)
13496629Szf162725 {
13506629Szf162725 	uint8_t rx;
13516629Szf162725 
13526629Szf162725 	rx = ural_bbp_read(sc, RAL_BBP_RX) & ~RAL_BBP_ANTMASK;
13536629Szf162725 	if (antenna == 1)
13546629Szf162725 		rx |= RAL_BBP_ANTA;
13556629Szf162725 	else if (antenna == 2)
13566629Szf162725 		rx |= RAL_BBP_ANTB;
13576629Szf162725 	else
13586629Szf162725 		rx |= RAL_BBP_DIVERSITY;
13596629Szf162725 
13606629Szf162725 	/* need to force no I/Q flip for RF 2525e and 2526 */
13616629Szf162725 	if (sc->rf_rev == RAL_RF_2525E || sc->rf_rev == RAL_RF_2526)
13626629Szf162725 		rx &= ~RAL_BBP_FLIPIQ;
13636629Szf162725 
13646629Szf162725 	ural_bbp_write(sc, RAL_BBP_RX, rx);
13656629Szf162725 }
13666629Szf162725 
13676629Szf162725 /*
13686629Szf162725  * This function is called periodically (every 200ms) during scanning to
13696629Szf162725  * switch from one channel to another.
13706629Szf162725  */
13716629Szf162725 static void
ural_next_scan(void * arg)13726629Szf162725 ural_next_scan(void *arg)
13736629Szf162725 {
13746629Szf162725 	struct ural_softc *sc = arg;
13756629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
13766629Szf162725 
13776629Szf162725 	if (ic->ic_state == IEEE80211_S_SCAN)
13786629Szf162725 		ieee80211_next_scan(ic);
13796629Szf162725 }
13806629Szf162725 
13816629Szf162725 static int
ural_newstate(struct ieee80211com * ic,enum ieee80211_state nstate,int arg)13826629Szf162725 ural_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
13836629Szf162725 {
13846629Szf162725 	struct ural_softc *sc = (struct ural_softc *)ic;
13856629Szf162725 	enum ieee80211_state ostate;
13866629Szf162725 	struct ieee80211_node *ni;
13876629Szf162725 	int err;
13886629Szf162725 
13896629Szf162725 	RAL_LOCK(sc);
13906629Szf162725 
13916629Szf162725 	ostate = ic->ic_state;
13926629Szf162725 
13936629Szf162725 	if (sc->sc_scan_id != 0) {
13946629Szf162725 		(void) untimeout(sc->sc_scan_id);
13956629Szf162725 		sc->sc_scan_id = 0;
13966629Szf162725 	}
13976629Szf162725 
13986629Szf162725 	if (sc->sc_amrr_id != 0) {
13996629Szf162725 		(void) untimeout(sc->sc_amrr_id);
14006629Szf162725 		sc->sc_amrr_id = 0;
14016629Szf162725 	}
14026629Szf162725 
14036629Szf162725 	switch (nstate) {
14046629Szf162725 	case IEEE80211_S_INIT:
14056629Szf162725 		if (ostate == IEEE80211_S_RUN) {
14066629Szf162725 			/* abort TSF synchronization */
14076629Szf162725 			ural_write(sc, RAL_TXRX_CSR19, 0);
14086629Szf162725 			/* force tx led to stop blinking */
14096629Szf162725 			ural_write(sc, RAL_MAC_CSR20, 0);
14106629Szf162725 		}
14116629Szf162725 		break;
14126629Szf162725 
14136629Szf162725 	case IEEE80211_S_SCAN:
14146629Szf162725 		ural_set_chan(sc, ic->ic_curchan);
14156629Szf162725 		sc->sc_scan_id = timeout(ural_next_scan, (void *)sc,
14166629Szf162725 		    drv_usectohz(sc->dwelltime * 1000));
14176629Szf162725 		break;
14186629Szf162725 
14196629Szf162725 	case IEEE80211_S_AUTH:
14206629Szf162725 		ural_set_chan(sc, ic->ic_curchan);
14216629Szf162725 		break;
14226629Szf162725 
14236629Szf162725 	case IEEE80211_S_ASSOC:
14246629Szf162725 		ural_set_chan(sc, ic->ic_curchan);
14256629Szf162725 		break;
14266629Szf162725 
14276629Szf162725 	case IEEE80211_S_RUN:
14286629Szf162725 		ural_set_chan(sc, ic->ic_curchan);
14296629Szf162725 
14306629Szf162725 		ni = ic->ic_bss;
14316629Szf162725 
14326629Szf162725 		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
14336629Szf162725 			ural_update_slot(ic, 1);
14346629Szf162725 			ural_set_txpreamble(sc);
14356629Szf162725 			ural_set_basicrates(sc);
14366629Szf162725 			ural_set_bssid(sc, ni->in_bssid);
14376629Szf162725 		}
14386629Szf162725 
14396629Szf162725 
14406629Szf162725 		/* make tx led blink on tx (controlled by ASIC) */
14416629Szf162725 		ural_write(sc, RAL_MAC_CSR20, 1);
14426629Szf162725 
14436629Szf162725 		if (ic->ic_opmode != IEEE80211_M_MONITOR)
14446629Szf162725 			ural_enable_tsf_sync(sc);
14456629Szf162725 
14466629Szf162725 		/* enable automatic rate adaptation in STA mode */
14476629Szf162725 		if (ic->ic_opmode == IEEE80211_M_STA &&
14486629Szf162725 		    ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
14496629Szf162725 			ural_amrr_start(sc, ni);
14506629Szf162725 
14516629Szf162725 		break;
14526629Szf162725 	}
14536629Szf162725 
14546629Szf162725 	RAL_UNLOCK(sc);
14556629Szf162725 
14566629Szf162725 	err = sc->sc_newstate(ic, nstate, arg);
14576629Szf162725 	/*
14586629Szf162725 	 * Finally, start any timers.
14596629Szf162725 	 */
14606629Szf162725 	if (nstate == IEEE80211_S_RUN)
14616629Szf162725 		ieee80211_start_watchdog(ic, 1);
14626629Szf162725 
14636629Szf162725 	return (err);
14646629Szf162725 }
14656629Szf162725 
14666629Szf162725 
14676629Szf162725 
14686629Szf162725 static void
ural_close_pipes(struct ural_softc * sc)14696629Szf162725 ural_close_pipes(struct ural_softc *sc)
14706629Szf162725 {
14716629Szf162725 	usb_flags_t flags = USB_FLAGS_SLEEP;
14726629Szf162725 
14736629Szf162725 	if (sc->sc_rx_pipeh != NULL) {
14746629Szf162725 		usb_pipe_reset(sc->sc_dev, sc->sc_rx_pipeh, flags, NULL, 0);
14756629Szf162725 		usb_pipe_close(sc->sc_dev, sc->sc_rx_pipeh, flags, NULL, 0);
14766629Szf162725 		sc->sc_rx_pipeh = NULL;
14776629Szf162725 	}
14786629Szf162725 
14796629Szf162725 	if (sc->sc_tx_pipeh != NULL) {
14806629Szf162725 		usb_pipe_reset(sc->sc_dev, sc->sc_tx_pipeh, flags, NULL, 0);
14816629Szf162725 		usb_pipe_close(sc->sc_dev, sc->sc_tx_pipeh, flags, NULL, 0);
14826629Szf162725 		sc->sc_tx_pipeh = NULL;
14836629Szf162725 	}
14846629Szf162725 }
14856629Szf162725 
14866629Szf162725 static int
ural_open_pipes(struct ural_softc * sc)14876629Szf162725 ural_open_pipes(struct ural_softc *sc)
14886629Szf162725 {
14896629Szf162725 	usb_ep_data_t *ep_node;
14906629Szf162725 	usb_pipe_policy_t policy;
14916629Szf162725 	int err;
14926629Szf162725 
14936629Szf162725 	ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0, 0,
14946629Szf162725 	    USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
14956629Szf162725 
14966629Szf162725 	bzero(&policy, sizeof (usb_pipe_policy_t));
14976629Szf162725 	policy.pp_max_async_reqs = RAL_TX_LIST_COUNT;
14986629Szf162725 
14996629Szf162725 	if ((err = usb_pipe_open(sc->sc_dev,
15006629Szf162725 	    &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP,
15016629Szf162725 	    &sc->sc_tx_pipeh)) != USB_SUCCESS) {
15029345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
15036629Szf162725 		    "ural_open_pipes(): %x failed to open tx pipe\n", err);
15046629Szf162725 		goto fail;
15056629Szf162725 	}
15066629Szf162725 
15076629Szf162725 	ep_node = usb_lookup_ep_data(sc->sc_dev, sc->sc_udev, 0, 0, 0,
15086629Szf162725 	    USB_EP_ATTR_BULK, USB_EP_DIR_IN);
15096629Szf162725 
15106629Szf162725 	bzero(&policy, sizeof (usb_pipe_policy_t));
15116629Szf162725 	policy.pp_max_async_reqs = RAL_RX_LIST_COUNT + 32;
15126629Szf162725 
15136629Szf162725 	if ((err = usb_pipe_open(sc->sc_dev,
15146629Szf162725 	    &ep_node->ep_descr, &policy, USB_FLAGS_SLEEP,
15156629Szf162725 	    &sc->sc_rx_pipeh)) != USB_SUCCESS) {
15169345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
15176629Szf162725 		    "ural_open_pipes(): %x failed to open rx pipe\n", err);
15186629Szf162725 		goto fail;
15196629Szf162725 	}
15206629Szf162725 
15216629Szf162725 	return (USB_SUCCESS);
15226629Szf162725 
15236629Szf162725 fail:
15246629Szf162725 	if (sc->sc_rx_pipeh != NULL) {
15256629Szf162725 		usb_pipe_close(sc->sc_dev, sc->sc_rx_pipeh,
15266629Szf162725 		    USB_FLAGS_SLEEP, NULL, 0);
15276629Szf162725 		sc->sc_rx_pipeh = NULL;
15286629Szf162725 	}
15296629Szf162725 
15306629Szf162725 	if (sc->sc_tx_pipeh != NULL) {
15316629Szf162725 		usb_pipe_close(sc->sc_dev, sc->sc_tx_pipeh,
15326629Szf162725 		    USB_FLAGS_SLEEP, NULL, 0);
15336629Szf162725 		sc->sc_tx_pipeh = NULL;
15346629Szf162725 	}
15356629Szf162725 
15366629Szf162725 	return (USB_FAILURE);
15376629Szf162725 }
15386629Szf162725 
15396629Szf162725 static int
ural_tx_trigger(struct ural_softc * sc,mblk_t * mp)15406629Szf162725 ural_tx_trigger(struct ural_softc *sc, mblk_t *mp)
15416629Szf162725 {
15426629Szf162725 	usb_bulk_req_t *req;
15436629Szf162725 	int err;
15446629Szf162725 
15456629Szf162725 	sc->sc_tx_timer = RAL_TX_TIMEOUT;
15466629Szf162725 
15476629Szf162725 	req = usb_alloc_bulk_req(sc->sc_dev, 0, USB_FLAGS_SLEEP);
15486629Szf162725 	if (req == NULL) {
15499345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
15506629Szf162725 		    "ural_tx_trigger(): failed to allocate req");
15516629Szf162725 		freemsg(mp);
15526629Szf162725 		return (-1);
15536629Szf162725 	}
15546629Szf162725 
15556629Szf162725 	req->bulk_len		= (uintptr_t)mp->b_wptr - (uintptr_t)mp->b_rptr;
15566629Szf162725 	req->bulk_data		= mp;
15576629Szf162725 	req->bulk_client_private = (usb_opaque_t)sc;
15586629Szf162725 	req->bulk_timeout	= RAL_TX_TIMEOUT;
15596629Szf162725 	req->bulk_attributes	= USB_ATTRS_AUTOCLEARING;
15606629Szf162725 	req->bulk_cb		= ural_txeof;
15616629Szf162725 	req->bulk_exc_cb	= ural_txeof;
15626629Szf162725 	req->bulk_completion_reason = 0;
15636629Szf162725 	req->bulk_cb_flags	= 0;
15646629Szf162725 
15656629Szf162725 	if ((err = usb_pipe_bulk_xfer(sc->sc_tx_pipeh, req, 0))
15666629Szf162725 	    != USB_SUCCESS) {
15676629Szf162725 
15689345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "ural_tx_trigger(): "
15696629Szf162725 		    "failed to do tx xfer, %d", err);
15706629Szf162725 		usb_free_bulk_req(req);
15716629Szf162725 		return (-1);
15726629Szf162725 	}
15736629Szf162725 
15746629Szf162725 	sc->tx_queued++;
15756629Szf162725 
15766629Szf162725 	return (0);
15776629Szf162725 }
15786629Szf162725 
15796629Szf162725 static int
ural_rx_trigger(struct ural_softc * sc)15806629Szf162725 ural_rx_trigger(struct ural_softc *sc)
15816629Szf162725 {
15826629Szf162725 	usb_bulk_req_t *req;
15836629Szf162725 	int err;
15846629Szf162725 
15856629Szf162725 	req = usb_alloc_bulk_req(sc->sc_dev, RAL_RXBUF_SIZE, USB_FLAGS_SLEEP);
15866629Szf162725 	if (req == NULL) {
15879345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
15886629Szf162725 		    "ural_rx_trigger(): failed to allocate req");
15896629Szf162725 		return (-1);
15906629Szf162725 	}
15916629Szf162725 
15926629Szf162725 	req->bulk_len		= RAL_RXBUF_SIZE;
15936629Szf162725 	req->bulk_client_private = (usb_opaque_t)sc;
15946629Szf162725 	req->bulk_timeout	= 0;
15956629Szf162725 	req->bulk_attributes	= USB_ATTRS_SHORT_XFER_OK
15966629Szf162725 	    | USB_ATTRS_AUTOCLEARING;
15976629Szf162725 	req->bulk_cb		= ural_rxeof;
15986629Szf162725 	req->bulk_exc_cb	= ural_rxeof;
15996629Szf162725 	req->bulk_completion_reason = 0;
16006629Szf162725 	req->bulk_cb_flags	= 0;
16016629Szf162725 
16026629Szf162725 	err = usb_pipe_bulk_xfer(sc->sc_rx_pipeh, req, 0);
16036629Szf162725 
16046629Szf162725 	if (err != USB_SUCCESS) {
16059345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "ural_rx_trigger(): "
16066629Szf162725 		    "failed to do rx xfer, %d", err);
16076629Szf162725 		usb_free_bulk_req(req);
16086629Szf162725 
16096629Szf162725 		return (-1);
16106629Szf162725 	}
16116629Szf162725 
16126629Szf162725 	mutex_enter(&sc->rx_lock);
16136629Szf162725 	sc->rx_queued++;
16146629Szf162725 	mutex_exit(&sc->rx_lock);
16156629Szf162725 
16166629Szf162725 	return (0);
16176629Szf162725 }
16186629Szf162725 
16196629Szf162725 static void
ural_init_tx_queue(struct ural_softc * sc)16206629Szf162725 ural_init_tx_queue(struct ural_softc *sc)
16216629Szf162725 {
16226629Szf162725 	sc->tx_queued = 0;
16236629Szf162725 }
16246629Szf162725 
16256629Szf162725 static int
ural_init_rx_queue(struct ural_softc * sc)16266629Szf162725 ural_init_rx_queue(struct ural_softc *sc)
16276629Szf162725 {
16286629Szf162725 	int	i;
16296629Szf162725 
16306629Szf162725 	sc->rx_queued = 0;
16316629Szf162725 
16326629Szf162725 	for (i = 0; i < RAL_RX_LIST_COUNT; i++) {
16336629Szf162725 		if (ural_rx_trigger(sc) != 0) {
16346629Szf162725 			return (USB_FAILURE);
16356629Szf162725 		}
16366629Szf162725 	}
16376629Szf162725 
16386629Szf162725 	return (USB_SUCCESS);
16396629Szf162725 }
16406629Szf162725 
16416629Szf162725 static void
ural_stop(struct ural_softc * sc)16426629Szf162725 ural_stop(struct ural_softc *sc)
16436629Szf162725 {
16446629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
16456629Szf162725 
16466629Szf162725 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
16476629Szf162725 	ieee80211_stop_watchdog(ic);	/* stop the watchdog */
16486629Szf162725 
16496629Szf162725 	RAL_LOCK(sc);
16506629Szf162725 
16516629Szf162725 	sc->sc_tx_timer = 0;
16526629Szf162725 	sc->sc_flags &= ~RAL_FLAG_RUNNING;	/* STOP */
16536629Szf162725 
16546629Szf162725 	/* disable Rx */
16556629Szf162725 	ural_write(sc, RAL_TXRX_CSR2, RAL_DISABLE_RX);
16566629Szf162725 
16576629Szf162725 	/* reset ASIC and BBP (but won't reset MAC registers!) */
16586629Szf162725 	ural_write(sc, RAL_MAC_CSR1, RAL_RESET_ASIC | RAL_RESET_BBP);
16596629Szf162725 	ural_write(sc, RAL_MAC_CSR1, 0);
16606629Szf162725 
16616629Szf162725 	ural_close_pipes(sc);
16626629Szf162725 
16636629Szf162725 	RAL_UNLOCK(sc);
16646629Szf162725 }
16656629Szf162725 
16666629Szf162725 static int
ural_init(struct ural_softc * sc)16676629Szf162725 ural_init(struct ural_softc *sc)
16686629Szf162725 {
16696629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
16706629Szf162725 	uint16_t tmp;
16716629Szf162725 	int i, ntries;
16726629Szf162725 
16736629Szf162725 	ural_set_testmode(sc);
16746629Szf162725 	ural_write(sc, 0x308, 0x00f0);	/* magic */
16756629Szf162725 
16766629Szf162725 	ural_stop(sc);
16776629Szf162725 
16786629Szf162725 	/* initialize MAC registers to default values */
16796629Szf162725 	for (i = 0; i < URAL_N(ural_def_mac); i++)
16806629Szf162725 		ural_write(sc, ural_def_mac[i].reg, ural_def_mac[i].val);
16816629Szf162725 
16826629Szf162725 	/* wait for BBP and RF to wake up (this can take a long time!) */
16836629Szf162725 	for (ntries = 0; ntries < 100; ntries++) {
16846629Szf162725 		tmp = ural_read(sc, RAL_MAC_CSR17);
16856629Szf162725 		if ((tmp & (RAL_BBP_AWAKE | RAL_RF_AWAKE)) ==
16866629Szf162725 		    (RAL_BBP_AWAKE | RAL_RF_AWAKE))
16876629Szf162725 			break;
16886629Szf162725 		drv_usecwait(1000);
16896629Szf162725 	}
16906629Szf162725 	if (ntries == 100) {
16919345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
16926629Szf162725 		    "ural_init(): timeout waiting for BBP/RF to wakeup\n");
16936629Szf162725 		goto fail;
16946629Szf162725 	}
16956629Szf162725 
16966629Szf162725 	/* we're ready! */
16976629Szf162725 	ural_write(sc, RAL_MAC_CSR1, RAL_HOST_READY);
16986629Szf162725 
16996629Szf162725 	/* set basic rate set (will be updated later) */
17006629Szf162725 	ural_write(sc, RAL_TXRX_CSR11, 0x15f);
17016629Szf162725 
17026629Szf162725 	if (ural_bbp_init(sc) != 0)
17036629Szf162725 		goto fail;
17046629Szf162725 
17056629Szf162725 	/* set default BSS channel */
17066629Szf162725 	ural_set_chan(sc, ic->ic_curchan);
17076629Szf162725 
17086629Szf162725 	/* clear statistic registers (STA_CSR0 to STA_CSR10) */
17096629Szf162725 	ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof (sc->sta));
17106629Szf162725 
17116629Szf162725 	ural_set_txantenna(sc, sc->tx_ant);
17126629Szf162725 	ural_set_rxantenna(sc, sc->rx_ant);
17136629Szf162725 
17146629Szf162725 	ural_set_macaddr(sc, ic->ic_macaddr);
17156629Szf162725 
17166629Szf162725 	if (ural_open_pipes(sc) != USB_SUCCESS) {
17179345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "ural_init(): "
17186629Szf162725 		    "could not open pipes.\n");
17196629Szf162725 		goto fail;
17206629Szf162725 	}
17216629Szf162725 
17226629Szf162725 	ural_init_tx_queue(sc);
17236629Szf162725 
17246629Szf162725 	if (ural_init_rx_queue(sc) != USB_SUCCESS)
17256629Szf162725 		goto fail;
17266629Szf162725 
17276629Szf162725 	/* kick Rx */
17286629Szf162725 	tmp = RAL_DROP_PHY | RAL_DROP_CRC;
17296629Szf162725 	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
17306629Szf162725 		tmp |= RAL_DROP_CTL | RAL_DROP_BAD_VERSION;
17316629Szf162725 		if (ic->ic_opmode != IEEE80211_M_HOSTAP)
17326629Szf162725 			tmp |= RAL_DROP_TODS;
17336629Szf162725 		if (!(sc->sc_rcr & RAL_RCR_PROMISC))
17346629Szf162725 			tmp |= RAL_DROP_NOT_TO_ME;
17356629Szf162725 	}
17366629Szf162725 	ural_write(sc, RAL_TXRX_CSR2, tmp);
17376629Szf162725 	sc->sc_flags |= RAL_FLAG_RUNNING;	/* RUNNING */
17386629Szf162725 
17396629Szf162725 	return (DDI_SUCCESS);
17406629Szf162725 fail:
17416629Szf162725 	ural_stop(sc);
17426629Szf162725 	return (EIO);
17436629Szf162725 }
17446629Szf162725 
17456629Szf162725 static int
ural_disconnect(dev_info_t * devinfo)17469345SQuaker.Fang@Sun.COM ural_disconnect(dev_info_t *devinfo)
17476629Szf162725 {
17486629Szf162725 	struct ural_softc *sc;
17496629Szf162725 	struct ieee80211com *ic;
17506629Szf162725 
17516629Szf162725 	/*
17526629Szf162725 	 * We can't call ural_stop() here, since the hardware is removed,
17536629Szf162725 	 * we can't access the register anymore.
17546629Szf162725 	 */
17556629Szf162725 	sc = ddi_get_soft_state(ural_soft_state_p, ddi_get_instance(devinfo));
17569345SQuaker.Fang@Sun.COM 	ASSERT(sc != NULL);
17579345SQuaker.Fang@Sun.COM 
17589345SQuaker.Fang@Sun.COM 	if (!RAL_IS_RUNNING(sc))	/* different device or not inited */
17599345SQuaker.Fang@Sun.COM 		return (DDI_SUCCESS);
17609345SQuaker.Fang@Sun.COM 
17616629Szf162725 	ic = &sc->sc_ic;
17626629Szf162725 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
17636629Szf162725 	ieee80211_stop_watchdog(ic);	/* stop the watchdog */
17646629Szf162725 
17656629Szf162725 	RAL_LOCK(sc);
17666629Szf162725 
17676629Szf162725 	sc->sc_tx_timer = 0;
17686629Szf162725 	sc->sc_flags &= ~RAL_FLAG_RUNNING;	/* STOP */
17696629Szf162725 
17706629Szf162725 	ural_close_pipes(sc);
17716629Szf162725 
17726629Szf162725 	RAL_UNLOCK(sc);
17736629Szf162725 
17746629Szf162725 	return (DDI_SUCCESS);
17756629Szf162725 }
17766629Szf162725 
17776629Szf162725 static int
ural_reconnect(dev_info_t * devinfo)17789345SQuaker.Fang@Sun.COM ural_reconnect(dev_info_t *devinfo)
17796629Szf162725 {
17806629Szf162725 	struct ural_softc *sc;
17816629Szf162725 	int err;
17826629Szf162725 
17836629Szf162725 	sc = ddi_get_soft_state(ural_soft_state_p, ddi_get_instance(devinfo));
17849345SQuaker.Fang@Sun.COM 	ASSERT(sc != NULL);
17859345SQuaker.Fang@Sun.COM 
17869345SQuaker.Fang@Sun.COM 	/* check device changes after disconnect */
17879345SQuaker.Fang@Sun.COM 	if (usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1,
17889345SQuaker.Fang@Sun.COM 	    USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
17899345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "different device connected\n");
17909345SQuaker.Fang@Sun.COM 		return (DDI_FAILURE);
17919345SQuaker.Fang@Sun.COM 	}
17929345SQuaker.Fang@Sun.COM 
17936629Szf162725 	err = ural_init(sc);
17946629Szf162725 
17956629Szf162725 	return (err);
17966629Szf162725 }
17976629Szf162725 
17989345SQuaker.Fang@Sun.COM static void
ural_resume(struct ural_softc * sc)17999345SQuaker.Fang@Sun.COM ural_resume(struct ural_softc *sc)
18009345SQuaker.Fang@Sun.COM {
18019345SQuaker.Fang@Sun.COM 	/* check device changes after suspend */
18029345SQuaker.Fang@Sun.COM 	if (usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1,
18039345SQuaker.Fang@Sun.COM 	    USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
18049345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "no or different device connected\n");
18059345SQuaker.Fang@Sun.COM 		return;
18069345SQuaker.Fang@Sun.COM 	}
18079345SQuaker.Fang@Sun.COM 
18089345SQuaker.Fang@Sun.COM 	(void) ural_init(sc);
18099345SQuaker.Fang@Sun.COM }
18109345SQuaker.Fang@Sun.COM 
18116629Szf162725 #define	URAL_AMRR_MIN_SUCCESS_THRESHOLD	1
18126629Szf162725 #define	URAL_AMRR_MAX_SUCCESS_THRESHOLD	10
18136629Szf162725 
18146629Szf162725 /*
18156629Szf162725  * Naive implementation of the Adaptive Multi Rate Retry algorithm:
18166629Szf162725  * "IEEE 802.11 Rate Adaptation: A Practical Approach"
18176629Szf162725  * Mathieu Lacage, Hossein Manshaei, Thierry Turletti
18186629Szf162725  * INRIA Sophia - Projet Planete
18196629Szf162725  * http://www-sop.inria.fr/rapports/sophia/RR-5208.html
18206629Szf162725  *
18216629Szf162725  * This algorithm is particularly well suited for ural since it does not
18226629Szf162725  * require per-frame retry statistics.  Note however that since h/w does
18236629Szf162725  * not provide per-frame stats, we can't do per-node rate adaptation and
18246629Szf162725  * thus automatic rate adaptation is only enabled in STA operating mode.
18256629Szf162725  */
18266629Szf162725 #define	is_success(amrr)	\
18276629Szf162725 	((amrr)->retrycnt < (amrr)->txcnt / 10)
18286629Szf162725 #define	is_failure(amrr)	\
18296629Szf162725 	((amrr)->retrycnt > (amrr)->txcnt / 3)
18306629Szf162725 #define	is_enough(amrr)		\
18316629Szf162725 	((amrr)->txcnt > 10)
18326629Szf162725 #define	is_min_rate(ni)		\
18336629Szf162725 	((ni)->in_txrate == 0)
18346629Szf162725 #define	is_max_rate(ni)		\
18356629Szf162725 	((ni)->in_txrate == (ni)->in_rates.ir_nrates - 1)
18366629Szf162725 #define	increase_rate(ni)	\
18376629Szf162725 	((ni)->in_txrate++)
18386629Szf162725 #define	decrease_rate(ni)	\
18396629Szf162725 	((ni)->in_txrate--)
18406629Szf162725 #define	reset_cnt(amrr)	do {	\
18416629Szf162725 	(amrr)->txcnt = (amrr)->retrycnt = 0;	\
18426629Szf162725 	_NOTE(CONSTCOND)	\
18436629Szf162725 } while (/* CONSTCOND */0)
18446629Szf162725 
18456629Szf162725 static void
ural_ratectl(struct ural_amrr * amrr,struct ieee80211_node * ni)18466629Szf162725 ural_ratectl(struct ural_amrr *amrr, struct ieee80211_node *ni)
18476629Szf162725 {
18486629Szf162725 	int need_change = 0;
18496629Szf162725 
18506629Szf162725 	if (is_success(amrr) && is_enough(amrr)) {
18516629Szf162725 		amrr->success++;
18526629Szf162725 		if (amrr->success >= amrr->success_threshold &&
18536629Szf162725 		    !is_max_rate(ni)) {
18546629Szf162725 			amrr->recovery = 1;
18556629Szf162725 			amrr->success = 0;
18566629Szf162725 			increase_rate(ni);
18576629Szf162725 			need_change = 1;
18586629Szf162725 		} else {
18596629Szf162725 			amrr->recovery = 0;
18606629Szf162725 		}
18616629Szf162725 	} else if (is_failure(amrr)) {
18626629Szf162725 		amrr->success = 0;
18636629Szf162725 		if (!is_min_rate(ni)) {
18646629Szf162725 			if (amrr->recovery) {
18656629Szf162725 				amrr->success_threshold *= 2;
18666629Szf162725 				if (amrr->success_threshold >
18676629Szf162725 				    URAL_AMRR_MAX_SUCCESS_THRESHOLD)
18686629Szf162725 					amrr->success_threshold =
18696629Szf162725 					    URAL_AMRR_MAX_SUCCESS_THRESHOLD;
18706629Szf162725 			} else {
18716629Szf162725 				amrr->success_threshold =
18726629Szf162725 				    URAL_AMRR_MIN_SUCCESS_THRESHOLD;
18736629Szf162725 			}
18746629Szf162725 			decrease_rate(ni);
18756629Szf162725 			need_change = 1;
18766629Szf162725 		}
18776629Szf162725 		amrr->recovery = 0;	/* original paper was incorrect */
18786629Szf162725 	}
18796629Szf162725 
18806629Szf162725 	if (is_enough(amrr) || need_change)
18816629Szf162725 		reset_cnt(amrr);
18826629Szf162725 }
18836629Szf162725 
18846629Szf162725 static void
ural_amrr_timeout(void * arg)18856629Szf162725 ural_amrr_timeout(void *arg)
18866629Szf162725 {
18876629Szf162725 	struct ural_softc *sc = (struct ural_softc *)arg;
18886629Szf162725 	struct ural_amrr *amrr = &sc->amrr;
18896629Szf162725 
18906629Szf162725 	ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof (sc->sta));
18916629Szf162725 
18926629Szf162725 	/* count TX retry-fail as Tx errors */
18936629Szf162725 	sc->sc_tx_err += sc->sta[9];
18946629Szf162725 	sc->sc_tx_retries += (sc->sta[7] + sc->sta[8]);
18956629Szf162725 
18966629Szf162725 	amrr->retrycnt =
18976629Szf162725 	    sc->sta[7] +	/* TX one-retry ok count */
18986629Szf162725 	    sc->sta[8] +	/* TX more-retry ok count */
18996629Szf162725 	    sc->sta[9];		/* TX retry-fail count */
19006629Szf162725 
19016629Szf162725 	amrr->txcnt =
19026629Szf162725 	    amrr->retrycnt +
19036629Szf162725 	    sc->sta[6];		/* TX no-retry ok count */
19046629Szf162725 
19056629Szf162725 	ural_ratectl(amrr, sc->sc_ic.ic_bss);
19066629Szf162725 
19076629Szf162725 	sc->sc_amrr_id = timeout(ural_amrr_timeout, (void *)sc,
19086629Szf162725 	    drv_usectohz(1000 * 1000)); /* 1 second */
19096629Szf162725 }
19106629Szf162725 
19116629Szf162725 
19126629Szf162725 static void
ural_amrr_start(struct ural_softc * sc,struct ieee80211_node * ni)19136629Szf162725 ural_amrr_start(struct ural_softc *sc, struct ieee80211_node *ni)
19146629Szf162725 {
19156629Szf162725 	struct ural_amrr *amrr = &sc->amrr;
19166629Szf162725 	int i;
19176629Szf162725 
19186629Szf162725 	/* clear statistic registers (STA_CSR0 to STA_CSR10) */
19196629Szf162725 	ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof (sc->sta));
19206629Szf162725 
19216629Szf162725 	amrr->success = 0;
19226629Szf162725 	amrr->recovery = 0;
19236629Szf162725 	amrr->txcnt = amrr->retrycnt = 0;
19246629Szf162725 	amrr->success_threshold = URAL_AMRR_MIN_SUCCESS_THRESHOLD;
19256629Szf162725 
19266629Szf162725 	/* set rate to some reasonable initial value */
19276629Szf162725 	for (i = ni->in_rates.ir_nrates - 1;
19286629Szf162725 	    i > 0 && (ni->in_rates.ir_rates[i] & IEEE80211_RATE_VAL) > 72;
19296629Szf162725 	    i--) {
19306629Szf162725 	}
19316629Szf162725 
19326629Szf162725 	ni->in_txrate = i;
19336629Szf162725 
19346629Szf162725 	sc->sc_amrr_id = timeout(ural_amrr_timeout, (void *)sc,
19356629Szf162725 	    drv_usectohz(1000 * 1000)); /* 1 second */
19366629Szf162725 }
19376629Szf162725 
19386629Szf162725 void
ural_watchdog(void * arg)19396629Szf162725 ural_watchdog(void *arg)
19406629Szf162725 {
19416629Szf162725 	struct ural_softc *sc = arg;
19426629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
19436629Szf162725 	int ntimer = 0;
19446629Szf162725 
19456629Szf162725 	RAL_LOCK(sc);
19466629Szf162725 	ic->ic_watchdog_timer = 0;
19476629Szf162725 
19486629Szf162725 	if (!RAL_IS_RUNNING(sc)) {
19496629Szf162725 		RAL_UNLOCK(sc);
19506629Szf162725 		return;
19516629Szf162725 	}
19526629Szf162725 
19536629Szf162725 	if (sc->sc_tx_timer > 0) {
19546629Szf162725 		if (--sc->sc_tx_timer == 0) {
19559345SQuaker.Fang@Sun.COM 			ral_debug(RAL_DBG_ERR, "tx timer timeout\n");
19566629Szf162725 			RAL_UNLOCK(sc);
19576629Szf162725 			(void) ural_init(sc);
19586629Szf162725 			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
19596629Szf162725 			return;
19606629Szf162725 		}
19616629Szf162725 	}
19626629Szf162725 
19636629Szf162725 	if (ic->ic_state == IEEE80211_S_RUN)
19646629Szf162725 		ntimer = 1;
19656629Szf162725 
19666629Szf162725 	RAL_UNLOCK(sc);
19676629Szf162725 
19686629Szf162725 	ieee80211_watchdog(ic);
19696629Szf162725 
19706629Szf162725 	if (ntimer)
19716629Szf162725 		ieee80211_start_watchdog(ic, ntimer);
19726629Szf162725 }
19736629Szf162725 
19746629Szf162725 static int
ural_m_start(void * arg)19756629Szf162725 ural_m_start(void *arg)
19766629Szf162725 {
19776629Szf162725 	struct ural_softc *sc = (struct ural_softc *)arg;
19786629Szf162725 	int err;
19796629Szf162725 
19806629Szf162725 	/*
19816629Szf162725 	 * initialize RT2500USB hardware
19826629Szf162725 	 */
19836629Szf162725 	err = ural_init(sc);
19846629Szf162725 	if (err != DDI_SUCCESS) {
19859345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "device configuration failed\n");
19866629Szf162725 		goto fail;
19876629Szf162725 	}
19886629Szf162725 	sc->sc_flags |= RAL_FLAG_RUNNING;	/* RUNNING */
19896629Szf162725 	return (err);
19906629Szf162725 
19916629Szf162725 fail:
19926629Szf162725 	ural_stop(sc);
19936629Szf162725 	return (err);
19946629Szf162725 }
19956629Szf162725 
19966629Szf162725 static void
ural_m_stop(void * arg)19976629Szf162725 ural_m_stop(void *arg)
19986629Szf162725 {
19996629Szf162725 	struct ural_softc *sc = (struct ural_softc *)arg;
20006629Szf162725 
20016629Szf162725 	(void) ural_stop(sc);
20026629Szf162725 	sc->sc_flags &= ~RAL_FLAG_RUNNING;	/* STOP */
20036629Szf162725 }
20046629Szf162725 
20056629Szf162725 static int
ural_m_unicst(void * arg,const uint8_t * macaddr)20066629Szf162725 ural_m_unicst(void *arg, const uint8_t *macaddr)
20076629Szf162725 {
20086629Szf162725 	struct ural_softc *sc = (struct ural_softc *)arg;
20096629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
20106629Szf162725 
20119345SQuaker.Fang@Sun.COM 	ral_debug(RAL_DBG_MSG, "ural_m_unicst(): " MACSTR "\n",
20126629Szf162725 	    MAC2STR(macaddr));
20136629Szf162725 
20146629Szf162725 	IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
20156629Szf162725 	(void) ural_set_macaddr(sc, (uint8_t *)macaddr);
20166629Szf162725 	(void) ural_init(sc);
20176629Szf162725 
20186629Szf162725 	return (0);
20196629Szf162725 }
20206629Szf162725 
20216629Szf162725 /*ARGSUSED*/
20226629Szf162725 static int
ural_m_multicst(void * arg,boolean_t add,const uint8_t * mca)20236629Szf162725 ural_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
20246629Szf162725 {
20256629Szf162725 	return (0);
20266629Szf162725 }
20276629Szf162725 
20286629Szf162725 static int
ural_m_promisc(void * arg,boolean_t on)20296629Szf162725 ural_m_promisc(void *arg, boolean_t on)
20306629Szf162725 {
20316629Szf162725 	struct ural_softc *sc = (struct ural_softc *)arg;
20326629Szf162725 
20336629Szf162725 	if (on) {
20346629Szf162725 		sc->sc_rcr |= RAL_RCR_PROMISC;
20356629Szf162725 		sc->sc_rcr |= RAL_RCR_MULTI;
20366629Szf162725 	} else {
20376629Szf162725 		sc->sc_rcr &= ~RAL_RCR_PROMISC;
20386629Szf162725 		sc->sc_rcr &= ~RAL_RCR_PROMISC;
20396629Szf162725 	}
20406629Szf162725 
20416629Szf162725 	ural_update_promisc(sc);
20426629Szf162725 	return (0);
20436629Szf162725 }
20446629Szf162725 
20458099SQuaker.Fang@Sun.COM /*
20468099SQuaker.Fang@Sun.COM  * callback functions for /get/set properties
20478099SQuaker.Fang@Sun.COM  */
20488099SQuaker.Fang@Sun.COM 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)20498099SQuaker.Fang@Sun.COM ural_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
20508099SQuaker.Fang@Sun.COM     uint_t wldp_length, const void *wldp_buf)
20518099SQuaker.Fang@Sun.COM {
20528099SQuaker.Fang@Sun.COM 	struct ural_softc *sc = (struct ural_softc *)arg;
20538099SQuaker.Fang@Sun.COM 	struct ieee80211com *ic = &sc->sc_ic;
20548099SQuaker.Fang@Sun.COM 	int err;
20558099SQuaker.Fang@Sun.COM 
20568099SQuaker.Fang@Sun.COM 	err = ieee80211_setprop(ic, pr_name, wldp_pr_num,
20578099SQuaker.Fang@Sun.COM 	    wldp_length, wldp_buf);
20588099SQuaker.Fang@Sun.COM 	RAL_LOCK(sc);
20598099SQuaker.Fang@Sun.COM 	if (err == ENETRESET) {
20608099SQuaker.Fang@Sun.COM 		if (RAL_IS_RUNNING(sc)) {
20618099SQuaker.Fang@Sun.COM 			RAL_UNLOCK(sc);
20628099SQuaker.Fang@Sun.COM 			(void) ural_init(sc);
20638099SQuaker.Fang@Sun.COM 			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
20648099SQuaker.Fang@Sun.COM 			RAL_LOCK(sc);
20658099SQuaker.Fang@Sun.COM 		}
20668099SQuaker.Fang@Sun.COM 		err = 0;
20678099SQuaker.Fang@Sun.COM 	}
20688099SQuaker.Fang@Sun.COM 	RAL_UNLOCK(sc);
20698099SQuaker.Fang@Sun.COM 
20708099SQuaker.Fang@Sun.COM 	return (err);
20718099SQuaker.Fang@Sun.COM }
20728099SQuaker.Fang@Sun.COM 
20738099SQuaker.Fang@Sun.COM 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)20748099SQuaker.Fang@Sun.COM ural_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2075*11878SVenu.Iyer@Sun.COM     uint_t wldp_length, void *wldp_buf)
20768099SQuaker.Fang@Sun.COM {
20778099SQuaker.Fang@Sun.COM 	struct ural_softc *sc = (struct ural_softc *)arg;
20788099SQuaker.Fang@Sun.COM 	int err;
20798099SQuaker.Fang@Sun.COM 
20808099SQuaker.Fang@Sun.COM 	err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
2081*11878SVenu.Iyer@Sun.COM 	    wldp_length, wldp_buf);
20828099SQuaker.Fang@Sun.COM 
20838099SQuaker.Fang@Sun.COM 	return (err);
20848099SQuaker.Fang@Sun.COM }
20858099SQuaker.Fang@Sun.COM 
20866629Szf162725 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*11878SVenu.Iyer@Sun.COM ural_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2088*11878SVenu.Iyer@Sun.COM     mac_prop_info_handle_t mph)
2089*11878SVenu.Iyer@Sun.COM {
2090*11878SVenu.Iyer@Sun.COM 	struct ural_softc *sc = (struct ural_softc *)arg;
2091*11878SVenu.Iyer@Sun.COM 
2092*11878SVenu.Iyer@Sun.COM 	ieee80211_propinfo(&sc->sc_ic, pr_name, wldp_pr_num, mph);
2093*11878SVenu.Iyer@Sun.COM }
2094*11878SVenu.Iyer@Sun.COM 
2095*11878SVenu.Iyer@Sun.COM static void
ural_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)20966629Szf162725 ural_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
20976629Szf162725 {
20986629Szf162725 	struct ural_softc *sc = (struct ural_softc *)arg;
20996629Szf162725 	struct ieee80211com *ic = &sc->sc_ic;
21006629Szf162725 	int err;
21016629Szf162725 
21026629Szf162725 	err = ieee80211_ioctl(ic, wq, mp);
21036629Szf162725 	RAL_LOCK(sc);
21046629Szf162725 	if (err == ENETRESET) {
21056629Szf162725 		if (RAL_IS_RUNNING(sc)) {
21066629Szf162725 			RAL_UNLOCK(sc);
21076629Szf162725 			(void) ural_init(sc);
21086629Szf162725 			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
21096629Szf162725 			RAL_LOCK(sc);
21106629Szf162725 		}
21116629Szf162725 	}
21126629Szf162725 	RAL_UNLOCK(sc);
21136629Szf162725 }
21146629Szf162725 
21156629Szf162725 static int
ural_m_stat(void * arg,uint_t stat,uint64_t * val)21166629Szf162725 ural_m_stat(void *arg, uint_t stat, uint64_t *val)
21176629Szf162725 {
21186629Szf162725 	struct ural_softc *sc  = (struct ural_softc *)arg;
21196629Szf162725 	ieee80211com_t	*ic = &sc->sc_ic;
21206629Szf162725 	ieee80211_node_t *ni = ic->ic_bss;
21216629Szf162725 	struct ieee80211_rateset *rs = &ni->in_rates;
21226629Szf162725 
21236629Szf162725 	RAL_LOCK(sc);
21246629Szf162725 	switch (stat) {
21256629Szf162725 	case MAC_STAT_IFSPEED:
21266629Szf162725 		*val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
21276629Szf162725 		    (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL)
21286890Sql147931 		    : ic->ic_fixed_rate) / 2 * 1000000;
21296629Szf162725 		break;
21306629Szf162725 	case MAC_STAT_NOXMTBUF:
21316629Szf162725 		*val = sc->sc_tx_nobuf;
21326629Szf162725 		break;
21336629Szf162725 	case MAC_STAT_NORCVBUF:
21346629Szf162725 		*val = sc->sc_rx_nobuf;
21356629Szf162725 		break;
21366629Szf162725 	case MAC_STAT_IERRORS:
21376629Szf162725 		*val = sc->sc_rx_err;
21386629Szf162725 		break;
21396629Szf162725 	case MAC_STAT_RBYTES:
21406629Szf162725 		*val = ic->ic_stats.is_rx_bytes;
21416629Szf162725 		break;
21426629Szf162725 	case MAC_STAT_IPACKETS:
21436629Szf162725 		*val = ic->ic_stats.is_rx_frags;
21446629Szf162725 		break;
21456629Szf162725 	case MAC_STAT_OBYTES:
21466629Szf162725 		*val = ic->ic_stats.is_tx_bytes;
21476629Szf162725 		break;
21486629Szf162725 	case MAC_STAT_OPACKETS:
21496629Szf162725 		*val = ic->ic_stats.is_tx_frags;
21506629Szf162725 		break;
21516629Szf162725 	case MAC_STAT_OERRORS:
21526629Szf162725 	case WIFI_STAT_TX_FAILED:
21536629Szf162725 		*val = sc->sc_tx_err;
21546629Szf162725 		break;
21556629Szf162725 	case WIFI_STAT_TX_RETRANS:
21566629Szf162725 		*val = sc->sc_tx_retries;
21576629Szf162725 		break;
21586629Szf162725 	case WIFI_STAT_FCS_ERRORS:
21596629Szf162725 	case WIFI_STAT_WEP_ERRORS:
21606629Szf162725 	case WIFI_STAT_TX_FRAGS:
21616629Szf162725 	case WIFI_STAT_MCAST_TX:
21626629Szf162725 	case WIFI_STAT_RTS_SUCCESS:
21636629Szf162725 	case WIFI_STAT_RTS_FAILURE:
21646629Szf162725 	case WIFI_STAT_ACK_FAILURE:
21656629Szf162725 	case WIFI_STAT_RX_FRAGS:
21666629Szf162725 	case WIFI_STAT_MCAST_RX:
21676629Szf162725 	case WIFI_STAT_RX_DUPS:
21686629Szf162725 		RAL_UNLOCK(sc);
21696629Szf162725 		return (ieee80211_stat(ic, stat, val));
21706629Szf162725 	default:
21716629Szf162725 		RAL_UNLOCK(sc);
21726629Szf162725 		return (ENOTSUP);
21736629Szf162725 	}
21746629Szf162725 	RAL_UNLOCK(sc);
21756629Szf162725 
21766629Szf162725 	return (0);
21776629Szf162725 }
21786629Szf162725 
21796629Szf162725 
21806629Szf162725 static int
ural_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)21816629Szf162725 ural_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
21826629Szf162725 {
21836629Szf162725 	struct ural_softc *sc;
21846629Szf162725 	struct ieee80211com *ic;
21856629Szf162725 	int err, i;
21866629Szf162725 	int instance;
21876629Szf162725 
21886629Szf162725 	char strbuf[32];
21896629Szf162725 
21906629Szf162725 	wifi_data_t wd = { 0 };
21916629Szf162725 	mac_register_t *macp;
21926629Szf162725 
21939345SQuaker.Fang@Sun.COM 	switch (cmd) {
21949345SQuaker.Fang@Sun.COM 	case DDI_ATTACH:
21959345SQuaker.Fang@Sun.COM 		break;
21969345SQuaker.Fang@Sun.COM 	case DDI_RESUME:
21979345SQuaker.Fang@Sun.COM 		sc = ddi_get_soft_state(ural_soft_state_p,
21989345SQuaker.Fang@Sun.COM 		    ddi_get_instance(devinfo));
21999345SQuaker.Fang@Sun.COM 		ASSERT(sc != NULL);
22009345SQuaker.Fang@Sun.COM 		ural_resume(sc);
22019345SQuaker.Fang@Sun.COM 		return (DDI_SUCCESS);
22029345SQuaker.Fang@Sun.COM 	default:
22036629Szf162725 		return (DDI_FAILURE);
22049345SQuaker.Fang@Sun.COM 	}
22056629Szf162725 
22066629Szf162725 	instance = ddi_get_instance(devinfo);
22076629Szf162725 
22086629Szf162725 	if (ddi_soft_state_zalloc(ural_soft_state_p, instance) != DDI_SUCCESS) {
22099345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_MSG, "ural_attach(): "
22106629Szf162725 		    "unable to alloc soft_state_p\n");
22116629Szf162725 		return (DDI_FAILURE);
22126629Szf162725 	}
22136629Szf162725 
22146629Szf162725 	sc = ddi_get_soft_state(ural_soft_state_p, instance);
22156629Szf162725 	ic = (ieee80211com_t *)&sc->sc_ic;
22166629Szf162725 	sc->sc_dev = devinfo;
22176629Szf162725 
22186629Szf162725 	if (usb_client_attach(devinfo, USBDRV_VERSION, 0) != USB_SUCCESS) {
22199345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
22206629Szf162725 		    "ural_attach(): usb_client_attach failed\n");
22216629Szf162725 		goto fail1;
22226629Szf162725 	}
22236629Szf162725 
22246629Szf162725 	if (usb_get_dev_data(devinfo, &sc->sc_udev,
22256629Szf162725 	    USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
22266629Szf162725 		sc->sc_udev = NULL;
22276629Szf162725 		goto fail2;
22286629Szf162725 	}
22296629Szf162725 
22306629Szf162725 	mutex_init(&sc->sc_genlock, NULL, MUTEX_DRIVER, NULL);
22316629Szf162725 	mutex_init(&sc->tx_lock, NULL, MUTEX_DRIVER, NULL);
22326629Szf162725 	mutex_init(&sc->rx_lock, NULL, MUTEX_DRIVER, NULL);
22336629Szf162725 
22346629Szf162725 	/* retrieve RT2570 rev. no */
22356629Szf162725 	sc->asic_rev = ural_read(sc, RAL_MAC_CSR0);
22366629Szf162725 
22376629Szf162725 	/* retrieve MAC address and various other things from EEPROM */
22386629Szf162725 	ural_read_eeprom(sc);
22396629Szf162725 
22409345SQuaker.Fang@Sun.COM 	ral_debug(RAL_DBG_MSG, "ural: MAC/BBP RT2570 (rev 0x%02x), RF %s\n",
22416629Szf162725 	    sc->asic_rev, ural_get_rf(sc->rf_rev));
22426629Szf162725 
22436629Szf162725 	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
22446629Szf162725 	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
22456629Szf162725 	ic->ic_state = IEEE80211_S_INIT;
22466629Szf162725 
22476629Szf162725 	ic->ic_maxrssi = 63;
22486629Szf162725 	ic->ic_set_shortslot = ural_update_slot;
22496629Szf162725 	ic->ic_xmit = ural_send;
22506629Szf162725 
22516629Szf162725 	/* set device capabilities */
22526629Szf162725 	ic->ic_caps =
22536629Szf162725 	    IEEE80211_C_TXPMGT |	/* tx power management */
22546629Szf162725 	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
22556629Szf162725 	    IEEE80211_C_SHSLOT;		/* short slot time supported */
22566629Szf162725 
22576629Szf162725 	ic->ic_caps |= IEEE80211_C_WPA; /* Support WPA/WPA2 */
22586629Szf162725 
22596629Szf162725 #define	IEEE80211_CHAN_A	\
22606629Szf162725 	(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
22616629Szf162725 
22626629Szf162725 	if (sc->rf_rev == RAL_RF_5222) {
22636629Szf162725 		/* set supported .11a rates */
22646629Szf162725 		ic->ic_sup_rates[IEEE80211_MODE_11A] = ural_rateset_11a;
22656629Szf162725 
22666629Szf162725 		/* set supported .11a channels */
22676629Szf162725 		for (i = 36; i <= 64; i += 4) {
22686629Szf162725 			ic->ic_sup_channels[i].ich_freq =
22696629Szf162725 			    ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
22706629Szf162725 			ic->ic_sup_channels[i].ich_flags = IEEE80211_CHAN_A;
22716629Szf162725 		}
22726629Szf162725 		for (i = 100; i <= 140; i += 4) {
22736629Szf162725 			ic->ic_sup_channels[i].ich_freq =
22746629Szf162725 			    ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
22756629Szf162725 			ic->ic_sup_channels[i].ich_flags = IEEE80211_CHAN_A;
22766629Szf162725 		}
22776629Szf162725 		for (i = 149; i <= 161; i += 4) {
22786629Szf162725 			ic->ic_sup_channels[i].ich_freq =
22796629Szf162725 			    ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
22806629Szf162725 			ic->ic_sup_channels[i].ich_flags = IEEE80211_CHAN_A;
22816629Szf162725 		}
22826629Szf162725 	}
22836629Szf162725 
22846629Szf162725 	/* set supported .11b and .11g rates */
22856629Szf162725 	ic->ic_sup_rates[IEEE80211_MODE_11B] = ural_rateset_11b;
22866629Szf162725 	ic->ic_sup_rates[IEEE80211_MODE_11G] = ural_rateset_11g;
22876629Szf162725 
22886629Szf162725 	/* set supported .11b and .11g channels (1 through 14) */
22896629Szf162725 	for (i = 1; i <= 14; i++) {
22906629Szf162725 		ic->ic_sup_channels[i].ich_freq =
22916629Szf162725 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
22926629Szf162725 		ic->ic_sup_channels[i].ich_flags =
22936629Szf162725 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
22946629Szf162725 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
22956629Szf162725 	}
22966629Szf162725 
22976629Szf162725 	ieee80211_attach(ic);
22986629Szf162725 
22996629Szf162725 	/* register WPA door */
23006629Szf162725 	ieee80211_register_door(ic, ddi_driver_name(devinfo),
23016629Szf162725 	    ddi_get_instance(devinfo));
23026629Szf162725 
23036629Szf162725 	/* override state transition machine */
23046629Szf162725 	sc->sc_newstate = ic->ic_newstate;
23056629Szf162725 	ic->ic_newstate = ural_newstate;
23066629Szf162725 	ic->ic_watchdog = ural_watchdog;
23076629Szf162725 	ieee80211_media_init(ic);
23086629Szf162725 	ic->ic_def_txkey = 0;
23096629Szf162725 
23106629Szf162725 	sc->sc_rcr = 0;
23116629Szf162725 	sc->dwelltime = 300;
23129345SQuaker.Fang@Sun.COM 	sc->sc_flags &= 0;
23136629Szf162725 
23146629Szf162725 	/*
23156629Szf162725 	 * Provide initial settings for the WiFi plugin; whenever this
23166629Szf162725 	 * information changes, we need to call mac_plugindata_update()
23176629Szf162725 	 */
23186629Szf162725 	wd.wd_opmode = ic->ic_opmode;
23196629Szf162725 	wd.wd_secalloc = WIFI_SEC_NONE;
23206629Szf162725 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
23216629Szf162725 
23226629Szf162725 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
23239345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "ural_attach(): "
23246629Szf162725 		    "MAC version mismatch\n");
23256629Szf162725 		goto fail3;
23266629Szf162725 	}
23276629Szf162725 
23286629Szf162725 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
23296629Szf162725 	macp->m_driver		= sc;
23306629Szf162725 	macp->m_dip		= devinfo;
23316629Szf162725 	macp->m_src_addr	= ic->ic_macaddr;
23326629Szf162725 	macp->m_callbacks	= &ural_m_callbacks;
23336629Szf162725 	macp->m_min_sdu		= 0;
23346629Szf162725 	macp->m_max_sdu		= IEEE80211_MTU;
23356629Szf162725 	macp->m_pdata		= &wd;
23366629Szf162725 	macp->m_pdata_size	= sizeof (wd);
23376629Szf162725 
23386629Szf162725 	err = mac_register(macp, &ic->ic_mach);
23396629Szf162725 	mac_free(macp);
23406629Szf162725 	if (err != 0) {
23419345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "ural_attach(): "
23426629Szf162725 		    "mac_register() err %x\n", err);
23436629Szf162725 		goto fail3;
23446629Szf162725 	}
23456629Szf162725 
23469345SQuaker.Fang@Sun.COM 	if (usb_register_hotplug_cbs(devinfo, ural_disconnect,
23479345SQuaker.Fang@Sun.COM 	    ural_reconnect) != USB_SUCCESS) {
23489345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR,
23496629Szf162725 		    "ural: ural_attach() failed to register events");
23506629Szf162725 		goto fail4;
23516629Szf162725 	}
23526629Szf162725 
23536629Szf162725 	/*
23546629Szf162725 	 * Create minor node of type DDI_NT_NET_WIFI
23556629Szf162725 	 */
23566629Szf162725 	(void) snprintf(strbuf, sizeof (strbuf), "%s%d",
23576629Szf162725 	    "ural", instance);
23586629Szf162725 	err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
23596629Szf162725 	    instance + 1, DDI_NT_NET_WIFI, 0);
23606629Szf162725 
23616629Szf162725 	if (err != DDI_SUCCESS)
23629345SQuaker.Fang@Sun.COM 		ral_debug(RAL_DBG_ERR, "ddi_create_minor_node() failed\n");
23636629Szf162725 
23646629Szf162725 	/*
23656629Szf162725 	 * Notify link is down now
23666629Szf162725 	 */
23676629Szf162725 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
23686629Szf162725 
23696629Szf162725 	return (DDI_SUCCESS);
23706629Szf162725 fail4:
23716629Szf162725 	(void) mac_unregister(ic->ic_mach);
23726629Szf162725 fail3:
23736629Szf162725 	mutex_destroy(&sc->sc_genlock);
23746629Szf162725 	mutex_destroy(&sc->tx_lock);
23756629Szf162725 	mutex_destroy(&sc->rx_lock);
23766629Szf162725 fail2:
23776629Szf162725 	usb_client_detach(sc->sc_dev, sc->sc_udev);
23786629Szf162725 fail1:
23796629Szf162725 	ddi_soft_state_free(ural_soft_state_p, ddi_get_instance(devinfo));
23806629Szf162725 
23816629Szf162725 	return (DDI_FAILURE);
23826629Szf162725 }
23836629Szf162725 
23846629Szf162725 static int
ural_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)23856629Szf162725 ural_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
23866629Szf162725 {
23876629Szf162725 	struct ural_softc *sc;
23886629Szf162725 
23896629Szf162725 	sc = ddi_get_soft_state(ural_soft_state_p, ddi_get_instance(devinfo));
23909345SQuaker.Fang@Sun.COM 	ASSERT(sc != NULL);
23919345SQuaker.Fang@Sun.COM 
23929345SQuaker.Fang@Sun.COM 	switch (cmd) {
23939345SQuaker.Fang@Sun.COM 	case DDI_DETACH:
23949345SQuaker.Fang@Sun.COM 		break;
23959345SQuaker.Fang@Sun.COM 	case DDI_SUSPEND:
23969345SQuaker.Fang@Sun.COM 		if (RAL_IS_RUNNING(sc))
23979345SQuaker.Fang@Sun.COM 			(void) ural_stop(sc);
23989345SQuaker.Fang@Sun.COM 		return (DDI_SUCCESS);
23999345SQuaker.Fang@Sun.COM 	default:
24006629Szf162725 		return (DDI_FAILURE);
24019345SQuaker.Fang@Sun.COM 	}
24026629Szf162725 
24037507SXinghua.Wen@Sun.COM 	if (mac_disable(sc->sc_ic.ic_mach) != 0)
24047507SXinghua.Wen@Sun.COM 		return (DDI_FAILURE);
24057507SXinghua.Wen@Sun.COM 
24066629Szf162725 	ural_stop(sc);
24076629Szf162725 	usb_unregister_hotplug_cbs(devinfo);
24086629Szf162725 
24096629Szf162725 	/*
24106629Szf162725 	 * Unregister from the MAC layer subsystem
24116629Szf162725 	 */
24127507SXinghua.Wen@Sun.COM 	(void) mac_unregister(sc->sc_ic.ic_mach);
24136629Szf162725 
24146629Szf162725 	/*
24156629Szf162725 	 * detach ieee80211 layer
24166629Szf162725 	 */
24176629Szf162725 	ieee80211_detach(&sc->sc_ic);
24186629Szf162725 
24196629Szf162725 	mutex_destroy(&sc->sc_genlock);
24206629Szf162725 	mutex_destroy(&sc->tx_lock);
24216629Szf162725 	mutex_destroy(&sc->rx_lock);
24226629Szf162725 
24236629Szf162725 	/* pipes will be close in ural_stop() */
24246629Szf162725 	usb_client_detach(devinfo, sc->sc_udev);
24256629Szf162725 	sc->sc_udev = NULL;
24266629Szf162725 
24276629Szf162725 	ddi_remove_minor_node(devinfo, NULL);
24286629Szf162725 	ddi_soft_state_free(ural_soft_state_p, ddi_get_instance(devinfo));
24296629Szf162725 
24306629Szf162725 	return (DDI_SUCCESS);
24316629Szf162725 }
24326629Szf162725 
24336629Szf162725 int
_info(struct modinfo * modinfop)24346629Szf162725 _info(struct modinfo *modinfop)
24356629Szf162725 {
24366629Szf162725 	return (mod_info(&modlinkage, modinfop));
24376629Szf162725 }
24386629Szf162725 
24396629Szf162725 int
_init(void)24406629Szf162725 _init(void)
24416629Szf162725 {
24426629Szf162725 	int status;
24436629Szf162725 
24446629Szf162725 	status = ddi_soft_state_init(&ural_soft_state_p,
24456629Szf162725 	    sizeof (struct ural_softc), 1);
24466629Szf162725 	if (status != 0)
24476629Szf162725 		return (status);
24486629Szf162725 
24496629Szf162725 	mac_init_ops(&ural_dev_ops, "ural");
24506629Szf162725 	status = mod_install(&modlinkage);
24516629Szf162725 	if (status != 0) {
24526629Szf162725 		mac_fini_ops(&ural_dev_ops);
24536629Szf162725 		ddi_soft_state_fini(&ural_soft_state_p);
24546629Szf162725 	}
24556629Szf162725 	return (status);
24566629Szf162725 }
24576629Szf162725 
24586629Szf162725 int
_fini(void)24596629Szf162725 _fini(void)
24606629Szf162725 {
24616629Szf162725 	int status;
24626629Szf162725 
24636629Szf162725 	status = mod_remove(&modlinkage);
24646629Szf162725 	if (status == 0) {
24656629Szf162725 		mac_fini_ops(&ural_dev_ops);
24666629Szf162725 		ddi_soft_state_fini(&ural_soft_state_p);
24676629Szf162725 	}
24686629Szf162725 	return (status);
24696629Szf162725 }
2470