changeset 10741:26a74e07a95b

6873319 WiFi driver for Marvell 88W8363 chipset
author fei feng - Sun Microsystems - Beijing China <Fei.Feng@Sun.COM>
date Thu, 08 Oct 2009 14:27:17 +0800
parents b13b4915cb81
children 98b03a712f28
files usr/src/pkgdefs/Makefile usr/src/pkgdefs/SUNWmwl/Makefile usr/src/pkgdefs/SUNWmwl/pkginfo.tmpl usr/src/pkgdefs/SUNWmwl/postinstall usr/src/pkgdefs/SUNWmwl/postremove usr/src/pkgdefs/SUNWmwl/prototype_com usr/src/pkgdefs/SUNWmwl/prototype_i386 usr/src/pkgdefs/common_files/i.minorperm_i386 usr/src/tools/opensolaris/license-list usr/src/uts/common/Makefile.files usr/src/uts/common/Makefile.rules usr/src/uts/common/io/mwl/THIRDPARTYLICENSE usr/src/uts/common/io/mwl/THIRDPARTYLICENSE.descrip usr/src/uts/common/io/mwl/mwl.c usr/src/uts/common/io/mwl/mwl_fw/LICENSE usr/src/uts/common/io/mwl/mwl_fw/LICENSE.descrip usr/src/uts/common/io/mwl/mwl_fw/mw88W8363 usr/src/uts/common/io/mwl/mwl_fw/mwlboot usr/src/uts/common/io/mwl/mwl_fw/mwlfw_mode.c usr/src/uts/common/io/mwl/mwl_reg.h usr/src/uts/common/io/mwl/mwl_var.h usr/src/uts/intel/Makefile.intel.shared usr/src/uts/intel/mwl/Makefile usr/src/uts/intel/mwlfw/Makefile usr/src/uts/intel/os/minor_perm
diffstat 25 files changed, 6794 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/pkgdefs/Makefile	Thu Oct 08 10:37:32 2009 +0800
+++ b/usr/src/pkgdefs/Makefile	Thu Oct 08 14:27:17 2009 +0800
@@ -139,6 +139,7 @@
 	SUNWlxu \
 	SUNWmegasas \
 	SUNWmv88sx \
+	SUNWmwl	\
 	SUNWbcmsata \
 	SUNWnge \
 	SUNWntfsprogs \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWmwl/Makefile	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,37 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+DATAFILES += depend
+LICENSEFILES = \
+	../../uts/common/io/mwl/THIRDPARTYLICENSE \
+	../../uts/common/io/mwl/mwl_fw/LICENSE
+
+.KEEP_STATE:
+
+all: $(FILES) postinstall postremove
+install: all pkg
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWmwl/pkginfo.tmpl	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,44 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+PKG="SUNWmwl"
+NAME="Marvell 88W8363 IEEE802.11b/g Wireless Network Device Driver"
+ARCH="ISA"
+VERSION="ONVERS,REV=0.0.0"
+SUNW_PRODNAME="SunOS"
+SUNW_PRODVERS="RELEASE/VERSION"
+SUNW_PKGVERS="1.0"
+SUNW_PKGTYPE="root"
+MAXINST="1000"
+CATEGORY="system"
+VENDOR="Sun Microsystems, Inc."
+DESC="Marvell 88W8363 IEEE802.11b/g Wireless Network Device Driver"
+CLASSES="none"
+HOTLINE="Please contact your local service provider"
+EMAIL=""
+BASEDIR=/
+SUNW_PKG_ALLZONES="true"
+SUNW_PKG_HOLLOW="true"
+SUNW_PKG_THISZONE="false"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWmwl/postinstall	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,91 @@
+#! /usr/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+# Driver info
+DRV=mwl
+DRVALIAS='"pci11ab,2a24" "pci11ab,2a0a"'
+
+BASEDIR=${BASEDIR:-/}
+
+# Function: check_add_drv()
+#
+# This function will check if add_drv has been executed.
+# If not simply calls add_drv. Otherwise adds entries to
+# driver_aliases, driver_classes and minor_perm if necessary.
+# The syntax of this function is the same as add_drv. 
+
+check_add_drv()
+{
+	CMD="add_drv"
+
+	ALIAS=""
+	ALIASDIR="${BASEDIR}"/etc/driver_aliases
+	while getopts i:b: opt 2>/dev/null; do
+		case "$opt" in
+		i)	CMD="${CMD} -i ${OPTARG}"
+			ALIAS=`echo ${OPTARG} | /usr/bin/sed -e "s/'//g"`
+			;;
+		b)	if [ "${OPTARG}" != "/" ]; then
+				# On a client
+				# modify the sytem files and touch
+				# /reconfigure for reconfigure reboot
+				CMD="${CMD} -b \"${OPTARG}\""
+			fi
+			;;
+		\?)	echo "check_add_drv(): Unknown option $opt"
+			return
+			;;
+		esac
+	done
+	shift `/usr/bin/expr ${OPTIND} - 1`
+	DRIVER=$1
+	CMD="${CMD} ${DRIVER}"
+
+	# Make sure add_drv has not been previously executed
+	# before attempting to add the driver
+	/usr/bin/egrep -s "^${DRIVER}[ 	]" "$BASEDIR"/etc/name_to_major
+
+	if [ $? -ne 0 ]; then
+		eval ${CMD}
+		if [ $? -ne 0 ]; then
+			echo "Failed add_drv ${DRIVER}!\n" >&2
+			exit 1
+		fi
+	else
+		# Add driver entry if necessary
+		if [ -n "${ALIAS}" ]; then
+			for i in ${ALIAS}; do
+				/usr/bin/egrep -s "^${DRIVER}[ 	]+$i" ${ALIASDIR}
+				if [ $? -ne 0 ]; then
+					echo "${DRIVER} $i" >> ${ALIASDIR}
+				fi
+			done
+		fi
+	fi
+}
+
+check_add_drv -b "${BASEDIR}" -i "'${DRVALIAS}'" ${DRV}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWmwl/postremove	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,38 @@
+#! /usr/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+DRV=mwl
+BD=${BASEDIR:-/}
+if grep -w $DRV $BD/etc/name_to_major > /dev/null 2>&1
+then
+        rem_drv -b ${BD} $DRV
+        if [ $? -ne 0 ]
+        then
+                exit 1
+        fi
+fi
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWmwl/prototype_com	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,45 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>        # where to find pkg objects
+#!include <filename>                    # include another 'prototype' file
+#!default <mode> <owner> <group>        # default used if not specified on entry
+#!<param>=<value>                       # puts parameter in pkg environment
+
+#
+# SUNWmwl
+#
+
+i pkginfo
+i copyright
+i depend
+i postinstall
+i postremove
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWmwl/prototype_i386	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,54 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>        # where to find pkg objects
+#!include <filename>                    # include another 'prototype' file
+#!default <mode> <owner> <group>        # default used if not specified on entry
+#!<param>=<value>                       # puts parameter in pkg environment
+
+#
+# SUNWmwl
+#
+
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+
+# mwl ieee80211b/g wifi driver
+d none kernel 0755 root sys
+d none kernel/drv 0755 root sys
+f none kernel/drv/mwl 0755 root sys
+d none kernel/misc 0755 root sys
+f none kernel/misc/mwlfw 0755 root sys
+d none kernel/drv/amd64 0755 root sys
+f none kernel/drv/amd64/mwl 0755 root sys
+d none kernel/misc/amd64 0755 root sys
+f none kernel/misc/amd64/mwlfw 0755 root sys
--- a/usr/src/pkgdefs/common_files/i.minorperm_i386	Thu Oct 08 10:37:32 2009 +0800
+++ b/usr/src/pkgdefs/common_files/i.minorperm_i386	Thu Oct 08 14:27:17 2009 +0800
@@ -117,6 +117,7 @@
 clone:iwh		0600 root sys 0666 root sys	/dev/iwh
 clone:iwi               0600 root sys 0666 root sys     /dev/iwi
 clone:iwk               0600 root sys 0666 root sys     /dev/iwk
+clone:mwl               0600 root sys 0666 root sys     /dev/mwl
 clone:pcwl              0600 root sys 0666 root sys     /dev/pcwl
 clone:pcan              0600 root sys 0666 root sys     /dev/pcan
 clone:ral		0600 root sys 0666 root sys	/dev/ral
@@ -150,6 +151,7 @@
 iwh:*			0600 root sys 0666 root sys	/dev/iwh*
 iwi:*                   0600 root sys 0666 root sys     /dev/iwi*
 iwk:*                   0600 root sys 0666 root sys     /dev/iwk*
+mwl:*                   0600 root sys 0666 root sys     /dev/mwl*
 pcwl:*                  0600 root sys 0666 root sys     /dev/pcwl*
 pcan:*                  0600 root sys 0666 root sys     /dev/pcan*
 ral:*			0600 root sys 0666 root sys	/dev/ral*
@@ -310,6 +312,7 @@
 clone:iwh
 clone:iwi
 clone:iwk
+clone:mwl
 clone:pcwl
 clone:pcan
 clone:ral
@@ -343,6 +346,7 @@
 iwh:*
 iwi:*
 iwk:*
+mwl:*
 pcwl:*
 pcan:*
 ral:*
--- a/usr/src/tools/opensolaris/license-list	Thu Oct 08 10:37:32 2009 +0800
+++ b/usr/src/tools/opensolaris/license-list	Thu Oct 08 14:27:17 2009 +0800
@@ -160,6 +160,8 @@
 usr/src/uts/common/io/mxfe/THIRDPARTYLICENSE
 usr/src/uts/common/io/ntxn/THIRDPARTYLICENSE
 usr/src/uts/common/io/myri10ge/THIRDPARTYLICENSE
+usr/src/uts/common/io/mwl/THIRDPARTYLICENSE
+usr/src/uts/common/io/mwl/mwl_fw/LICENSE
 usr/src/uts/common/io/pcan/THIRDPARTYLICENSE
 usr/src/uts/common/io/pcwl/THIRDPARTYLICENSE
 usr/src/uts/common/io/ppp/THIRDPARTYLICENSE
--- a/usr/src/uts/common/Makefile.files	Thu Oct 08 10:37:32 2009 +0800
+++ b/usr/src/uts/common/Makefile.files	Thu Oct 08 14:27:17 2009 +0800
@@ -1734,6 +1734,10 @@
 
 IWK_OBJS += iwk2.o
 
+MWL_OBJS += mwl.o
+
+MWLFW_OBJS += mwlfw_mode.o
+
 WPI_OBJS += wpi.o
 
 RAL_OBJS += rt2560.o ral_rate.o
--- a/usr/src/uts/common/Makefile.rules	Thu Oct 08 10:37:32 2009 +0800
+++ b/usr/src/uts/common/Makefile.rules	Thu Oct 08 14:27:17 2009 +0800
@@ -880,6 +880,14 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/mwl/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/mwl/mwl_fw/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/net80211/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -2090,6 +2098,12 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/mxfe/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/mwl/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/mwl/mwl_fw/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/net80211/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/mwl/THIRDPARTYLICENSE	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2007-2009 Marvell Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/mwl/THIRDPARTYLICENSE.descrip	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,1 @@
+MARVELL 88W8363 IEEE802.11b/g WIFI DRIVER
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/mwl/mwl.c	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,4354 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2007-2008 Marvell Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * Driver for the Marvell 88W8363 Wireless LAN controller.
+ */
+#include <sys/stat.h>
+#include <sys/dlpi.h>
+#include <inet/common.h>
+#include <inet/mi.h>
+#include <sys/stream.h>
+#include <sys/errno.h>
+#include <sys/stropts.h>
+#include <sys/stat.h>
+#include <sys/sunddi.h>
+#include <sys/strsubr.h>
+#include <sys/strsun.h>
+#include <sys/pci.h>
+#include <sys/mac_provider.h>
+#include <sys/mac_wifi.h>
+#include <sys/net80211.h>
+#include <inet/wifi_ioctl.h>
+
+#include "mwl_var.h"
+
+static int mwl_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd);
+static int mwl_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd);
+static int mwl_quiesce(dev_info_t *devinfo);
+
+DDI_DEFINE_STREAM_OPS(mwl_dev_ops, nulldev, nulldev, mwl_attach, mwl_detach,
+    nodev, NULL, D_MP, NULL, mwl_quiesce);
+
+static struct modldrv mwl_modldrv = {
+	&mod_driverops,	/* Type of module.  This one is a driver */
+	"Marvell 88W8363 WiFi driver v1.1",	/* short description */
+	&mwl_dev_ops	/* driver specific ops */
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1, (void *)&mwl_modldrv, NULL
+};
+
+static void *mwl_soft_state_p = NULL;
+
+static int	mwl_m_stat(void *,  uint_t, uint64_t *);
+static int	mwl_m_start(void *);
+static void	mwl_m_stop(void *);
+static int	mwl_m_promisc(void *, boolean_t);
+static int	mwl_m_multicst(void *, boolean_t, const uint8_t *);
+static int	mwl_m_unicst(void *, const uint8_t *);
+static mblk_t	*mwl_m_tx(void *, mblk_t *);
+static void	mwl_m_ioctl(void *, queue_t *, mblk_t *);
+static int	mwl_m_setprop(void *arg, const char *pr_name,
+		    mac_prop_id_t wldp_pr_num,
+		    uint_t wldp_length, const void *wldp_buf);
+static int	mwl_m_getprop(void *arg, const char *pr_name,
+		    mac_prop_id_t wldp_pr_num, uint_t pr_flags,
+		    uint_t wldp_length, void *wldp_buf, uint_t *);
+
+static mac_callbacks_t mwl_m_callbacks = {
+	MC_IOCTL | MC_SETPROP | MC_GETPROP,
+	mwl_m_stat,
+	mwl_m_start,
+	mwl_m_stop,
+	mwl_m_promisc,
+	mwl_m_multicst,
+	mwl_m_unicst,
+	mwl_m_tx,
+	mwl_m_ioctl,
+	NULL,
+	NULL,
+	NULL,
+	mwl_m_setprop,
+	mwl_m_getprop
+};
+
+#define	MWL_DBG_ATTACH		(1 << 0)
+#define	MWL_DBG_DMA		(1 << 1)
+#define	MWL_DBG_FW		(1 << 2)
+#define	MWL_DBG_HW		(1 << 3)
+#define	MWL_DBG_INTR		(1 << 4)
+#define	MWL_DBG_RX		(1 << 5)
+#define	MWL_DBG_TX		(1 << 6)
+#define	MWL_DBG_CMD		(1 << 7)
+#define	MWL_DBG_CRYPTO		(1 << 8)
+#define	MWL_DBG_SR		(1 << 9)
+#define	MWL_DBG_MSG		(1 << 10)
+
+uint32_t mwl_dbg_flags = 0x0;
+
+#ifdef DEBUG
+#define	MWL_DBG	\
+	mwl_debug
+#else
+#define	MWL_DBG
+#endif
+
+/*
+ * PIO access attributes for registers
+ */
+static ddi_device_acc_attr_t mwl_reg_accattr = {
+	DDI_DEVICE_ATTR_V0,
+	DDI_STRUCTURE_LE_ACC,
+	DDI_STRICTORDER_ACC,
+	DDI_DEFAULT_ACC
+};
+
+static ddi_device_acc_attr_t mwl_cmdbuf_accattr = {
+	DDI_DEVICE_ATTR_V0,
+	DDI_NEVERSWAP_ACC,
+	DDI_STRICTORDER_ACC,
+	DDI_DEFAULT_ACC
+};
+
+/*
+ * DMA access attributes for descriptors and bufs: NOT to be byte swapped.
+ */
+static ddi_device_acc_attr_t mwl_desc_accattr = {
+	DDI_DEVICE_ATTR_V0,
+	DDI_NEVERSWAP_ACC,
+	DDI_STRICTORDER_ACC,
+	DDI_DEFAULT_ACC
+};
+
+static ddi_device_acc_attr_t mwl_buf_accattr = {
+	DDI_DEVICE_ATTR_V0,
+	DDI_NEVERSWAP_ACC,
+	DDI_STRICTORDER_ACC,
+	DDI_DEFAULT_ACC
+};
+
+/*
+ * Describes the chip's DMA engine
+ */
+static ddi_dma_attr_t mwl_dma_attr = {
+	DMA_ATTR_V0,			/* dma_attr version */
+	0x0000000000000000ull,		/* dma_attr_addr_lo */
+	0xFFFFFFFF,			/* dma_attr_addr_hi */
+	0x00000000FFFFFFFFull,		/* dma_attr_count_max */
+	0x0000000000000001ull,		/* dma_attr_align */
+	0x00000FFF,			/* dma_attr_burstsizes */
+	0x00000001,			/* dma_attr_minxfer */
+	0x000000000000FFFFull,		/* dma_attr_maxxfer */
+	0xFFFFFFFFFFFFFFFFull,		/* dma_attr_seg */
+	1,				/* dma_attr_sgllen */
+	0x00000001,			/* dma_attr_granular */
+	0				/* dma_attr_flags */
+};
+
+/*
+ * Supported rates for 802.11a/b/g modes (in 500Kbps unit).
+ */
+static const struct ieee80211_rateset mwl_rateset_11b =
+	{ 4, { 2, 4, 11, 22 } };
+
+static const struct ieee80211_rateset mwl_rateset_11g =
+	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
+
+static int	mwl_alloc_dma_mem(dev_info_t *, ddi_dma_attr_t *, size_t,
+		    ddi_device_acc_attr_t *, uint_t, uint_t,
+		    struct dma_area *);
+static void	mwl_free_dma_mem(struct dma_area *);
+static int	mwl_alloc_cmdbuf(struct mwl_softc *);
+static void	mwl_free_cmdbuf(struct mwl_softc *);
+static int	mwl_alloc_rx_ring(struct mwl_softc *, int);
+static void	mwl_free_rx_ring(struct mwl_softc *);
+static int	mwl_alloc_tx_ring(struct mwl_softc *, struct mwl_tx_ring *,
+		    int);
+static void	mwl_free_tx_ring(struct mwl_softc *, struct mwl_tx_ring *);
+static int	mwl_setupdma(struct mwl_softc *);
+static void	mwl_txq_init(struct mwl_softc *, struct mwl_tx_ring *, int);
+static int	mwl_tx_setup(struct mwl_softc *, int, int);
+static int	mwl_setup_txq(struct mwl_softc *);
+static int	mwl_fwload(struct mwl_softc *, void *);
+static int	mwl_loadsym(ddi_modhandle_t, char *, char **, size_t *);
+static void	mwlFwReset(struct mwl_softc *);
+static void	mwlPokeSdramController(struct mwl_softc *, int);
+static void	mwlTriggerPciCmd(struct mwl_softc *);
+static int	mwlWaitFor(struct mwl_softc *, uint32_t);
+static int	mwlSendBlock(struct mwl_softc *, int, const void *, size_t);
+static int	mwlSendBlock2(struct mwl_softc *, const void *, size_t);
+static void	mwlSendCmd(struct mwl_softc *);
+static int	mwlExecuteCmd(struct mwl_softc *, unsigned short);
+static int	mwlWaitForCmdComplete(struct mwl_softc *, uint16_t);
+static void	dumpresult(struct mwl_softc *, int);
+static int	mwlResetHalState(struct mwl_softc *);
+static int	mwlGetPwrCalTable(struct mwl_softc *);
+static int	mwlGetCalTable(struct mwl_softc *, uint8_t, uint8_t);
+static int	mwlGetPwrCalTable(struct mwl_softc *);
+static void	dumpcaldata(const char *, const uint8_t *, int);
+static void	get2Ghz(MWL_HAL_CHANNELINFO *, const uint8_t *, int);
+static void	get5Ghz(MWL_HAL_CHANNELINFO *, const uint8_t *, int);
+static void	setmaxtxpow(struct mwl_hal_channel *, int, int);
+static uint16_t	ieee2mhz(int);
+static const char *
+		mwlcmdname(int);
+static int	mwl_gethwspecs(struct mwl_softc *);
+static int	mwl_getchannels(struct mwl_softc *);
+static void	getchannels(struct mwl_softc *, int, int *,
+		    struct mwl_channel *);
+static void	addchannels(struct mwl_channel *, int, int *,
+		    const MWL_HAL_CHANNELINFO *, int);
+static void	addht40channels(struct mwl_channel *, int, int *,
+		    const MWL_HAL_CHANNELINFO *, int);
+static const struct mwl_channel *
+		findchannel(const struct mwl_channel *, int,
+		    int, int);
+static void	addchan(struct mwl_channel *, int, int, int, int);
+
+static int	mwl_chan_set(struct mwl_softc *, struct mwl_channel *);
+static void	mwl_mapchan(MWL_HAL_CHANNEL *, const struct mwl_channel *);
+static int	mwl_setcurchanrates(struct mwl_softc *);
+const struct ieee80211_rateset *
+		mwl_get_suprates(struct ieee80211com *,
+		    const struct mwl_channel *);
+static uint32_t	cvtChannelFlags(const MWL_HAL_CHANNEL *);
+static const struct mwl_hal_channel *
+		findhalchannel(const struct mwl_softc *,
+		    const MWL_HAL_CHANNEL *);
+enum ieee80211_phymode
+		mwl_chan2mode(const struct mwl_channel *);
+static int	mwl_map2regioncode(const struct mwl_regdomain *);
+static int	mwl_startrecv(struct mwl_softc *);
+static int	mwl_mode_init(struct mwl_softc *);
+static void	mwl_hal_intrset(struct mwl_softc *, uint32_t);
+static void	mwl_hal_getisr(struct mwl_softc *, uint32_t *);
+static int	mwl_hal_sethwdma(struct mwl_softc *,
+		    const struct mwl_hal_txrxdma *);
+static int	mwl_hal_getchannelinfo(struct mwl_softc *, int, int,
+		    const MWL_HAL_CHANNELINFO **);
+static int	mwl_hal_setmac_locked(struct mwl_softc *, const uint8_t *);
+static int	mwl_hal_keyreset(struct mwl_softc *, const MWL_HAL_KEYVAL *,
+		    const uint8_t mac[IEEE80211_ADDR_LEN]);
+static int	mwl_hal_keyset(struct mwl_softc *, const MWL_HAL_KEYVAL *,
+		    const uint8_t mac[IEEE80211_ADDR_LEN]);
+static int	mwl_hal_newstation(struct mwl_softc *, const uint8_t *,
+		    uint16_t, uint16_t, const MWL_HAL_PEERINFO *, int, int);
+static int	mwl_hal_setantenna(struct mwl_softc *, MWL_HAL_ANTENNA, int);
+static int	mwl_hal_setradio(struct mwl_softc *, int, MWL_HAL_PREAMBLE);
+static int	mwl_hal_setwmm(struct mwl_softc *, int);
+static int	mwl_hal_setchannel(struct mwl_softc *, const MWL_HAL_CHANNEL *);
+static int	mwl_hal_settxpower(struct mwl_softc *, const MWL_HAL_CHANNEL *,
+		    uint8_t);
+static int	mwl_hal_settxrate(struct mwl_softc *, MWL_HAL_TXRATE_HANDLING,
+		    const MWL_HAL_TXRATE *);
+static int	mwl_hal_settxrate_auto(struct mwl_softc *,
+		    const MWL_HAL_TXRATE *);
+static int	mwl_hal_setrateadaptmode(struct mwl_softc *, uint16_t);
+static int	mwl_hal_setoptimizationlevel(struct mwl_softc *, int);
+static int	mwl_hal_setregioncode(struct mwl_softc *, int);
+static int	mwl_hal_setassocid(struct mwl_softc *, const uint8_t *,
+		    uint16_t);
+static int	mwl_setrates(struct ieee80211com *);
+static int	mwl_hal_setrtsthreshold(struct mwl_softc *, int);
+static int	mwl_hal_setcsmode(struct mwl_softc *, MWL_HAL_CSMODE);
+static int	mwl_hal_setpromisc(struct mwl_softc *, int);
+static int	mwl_hal_start(struct mwl_softc *);
+static int	mwl_hal_setinframode(struct mwl_softc *);
+static int	mwl_hal_stop(struct mwl_softc *);
+static struct ieee80211_node *
+		mwl_node_alloc(struct ieee80211com *);
+static void	mwl_node_free(struct ieee80211_node *);
+static int	mwl_key_alloc(struct ieee80211com *,
+		    const struct ieee80211_key *,
+		    ieee80211_keyix *, ieee80211_keyix *);
+static int	mwl_key_delete(struct ieee80211com *,
+		    const struct ieee80211_key *);
+static int	mwl_key_set(struct ieee80211com *, const struct ieee80211_key *,
+		    const uint8_t mac[IEEE80211_ADDR_LEN]);
+static void	mwl_setanywepkey(struct ieee80211com *, const uint8_t *);
+static void	mwl_setglobalkeys(struct ieee80211com *c);
+static int	addgroupflags(MWL_HAL_KEYVAL *, const struct ieee80211_key *);
+static void	mwl_hal_txstart(struct mwl_softc *, int);
+static int	mwl_send(ieee80211com_t *, mblk_t *, uint8_t);
+static void	mwl_next_scan(void *);
+static MWL_HAL_PEERINFO *
+		mkpeerinfo(MWL_HAL_PEERINFO *, const struct ieee80211_node *);
+static uint32_t	get_rate_bitmap(const struct ieee80211_rateset *);
+static int	mwl_newstate(struct ieee80211com *, enum ieee80211_state, int);
+static int	cvtrssi(uint8_t);
+static uint_t	mwl_intr(caddr_t, caddr_t);
+static uint_t	mwl_softintr(caddr_t, caddr_t);
+static void	mwl_tx_intr(struct mwl_softc *);
+static void	mwl_rx_intr(struct mwl_softc *);
+static int	mwl_init(struct mwl_softc *);
+static void	mwl_stop(struct mwl_softc *);
+static int	mwl_resume(struct mwl_softc *);
+
+
+#ifdef DEBUG
+static void
+mwl_debug(uint32_t dbg_flags, const int8_t *fmt, ...)
+{
+	va_list args;
+
+	if (dbg_flags & mwl_dbg_flags) {
+		va_start(args, fmt);
+		vcmn_err(CE_CONT, fmt, args);
+		va_end(args);
+	}
+}
+#endif
+
+/*
+ * Allocate an DMA memory and a DMA handle for accessing it
+ */
+static int
+mwl_alloc_dma_mem(dev_info_t *devinfo, ddi_dma_attr_t *dma_attr,
+	size_t memsize, ddi_device_acc_attr_t *attr_p, uint_t alloc_flags,
+	uint_t bind_flags, struct dma_area *dma_p)
+{
+	int err;
+
+	/*
+	 * Allocate handle
+	 */
+	err = ddi_dma_alloc_handle(devinfo, dma_attr,
+	    DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
+	if (err != DDI_SUCCESS) {
+		MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_dma_mem(): "
+		    "failed to alloc handle\n");
+		goto fail1;
+	}
+
+	/*
+	 * Allocate memory
+	 */
+	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
+	    alloc_flags, DDI_DMA_SLEEP, NULL, &dma_p->mem_va,
+	    &dma_p->alength, &dma_p->acc_hdl);
+	if (err != DDI_SUCCESS) {
+		MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_dma_mem(): "
+		    "failed to alloc mem\n");
+		goto fail2;
+	}
+
+	/*
+	 * Bind the two together
+	 */
+	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
+	    dma_p->mem_va, dma_p->alength, bind_flags,
+	    DDI_DMA_SLEEP, NULL, &dma_p->cookie, &dma_p->ncookies);
+	if (err != DDI_DMA_MAPPED) {
+		MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_dma_mem(): "
+		    "failed to bind handle\n");
+		goto fail3;
+	}
+
+	if (dma_p->ncookies != 1) {
+		MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_dma_mem(): "
+		    "failed to alloc cookies\n");
+		goto fail4;
+	}
+
+	dma_p->nslots = ~0U;
+	dma_p->size = ~0U;
+	dma_p->token = ~0U;
+	dma_p->offset = 0;
+
+	return (DDI_SUCCESS);
+
+fail4:
+	(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
+fail3:
+	ddi_dma_mem_free(&dma_p->acc_hdl);
+fail2:
+	ddi_dma_free_handle(&dma_p->dma_hdl);
+fail1:
+	return (err);
+}
+
+static void
+mwl_free_dma_mem(struct dma_area *dma_p)
+{
+	if (dma_p->dma_hdl != NULL) {
+		(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
+		if (dma_p->acc_hdl != NULL) {
+			ddi_dma_mem_free(&dma_p->acc_hdl);
+			dma_p->acc_hdl = NULL;
+		}
+		ddi_dma_free_handle(&dma_p->dma_hdl);
+		dma_p->ncookies = 0;
+		dma_p->dma_hdl = NULL;
+	}
+}
+
+static int
+mwl_alloc_cmdbuf(struct mwl_softc *sc)
+{
+	int err;
+	size_t size;
+
+	size = MWL_CMDBUF_SIZE;
+
+	err = mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr, size,
+	    &mwl_cmdbuf_accattr, DDI_DMA_CONSISTENT,
+	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
+	    &sc->sc_cmd_dma);
+	if (err != DDI_SUCCESS) {
+		MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_cmdbuf(): "
+		    "failed to alloc dma mem\n");
+		return (DDI_FAILURE);
+	}
+
+	sc->sc_cmd_mem = (uint16_t *)sc->sc_cmd_dma.mem_va;
+	sc->sc_cmd_dmaaddr = sc->sc_cmd_dma.cookie.dmac_address;
+
+	return (DDI_SUCCESS);
+}
+
+static void
+mwl_free_cmdbuf(struct mwl_softc *sc)
+{
+	if (sc->sc_cmd_mem != NULL)
+		mwl_free_dma_mem(&sc->sc_cmd_dma);
+}
+
+static int
+mwl_alloc_rx_ring(struct mwl_softc *sc, int count)
+{
+	struct mwl_rx_ring *ring;
+	struct mwl_rxdesc *ds;
+	struct mwl_rxbuf *bf;
+	int i, err, datadlen;
+
+	ring = &sc->sc_rxring;
+	ring->count = count;
+	ring->cur = ring->next = 0;
+	err = mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr,
+	    count * sizeof (struct mwl_rxdesc),
+	    &mwl_desc_accattr,
+	    DDI_DMA_CONSISTENT, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
+	    &ring->rxdesc_dma);
+	if (err) {
+		MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_rxring(): "
+		    "alloc tx ring failed, size %d\n",
+		    (uint32_t)(count * sizeof (struct mwl_rxdesc)));
+		return (DDI_FAILURE);
+	}
+
+	MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_rx_ring(): "
+	    "dma len = %d\n", (uint32_t)(ring->rxdesc_dma.alength));
+	ring->desc = (struct mwl_rxdesc *)ring->rxdesc_dma.mem_va;
+	ring->physaddr = ring->rxdesc_dma.cookie.dmac_address;
+	bzero(ring->desc, count * sizeof (struct mwl_rxdesc));
+
+	datadlen = count * sizeof (struct mwl_rxbuf);
+	ring->buf = (struct mwl_rxbuf *)kmem_zalloc(datadlen, KM_SLEEP);
+	if (ring->buf == NULL) {
+		MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_rxring(): "
+		    "could not alloc rx ring data buffer\n");
+		return (DDI_FAILURE);
+	}
+	bzero(ring->buf, count * sizeof (struct mwl_rxbuf));
+
+	/*
+	 * Pre-allocate Rx buffers and populate Rx ring.
+	 */
+	for (i = 0; i < count; i++) {
+		ds = &ring->desc[i];
+		bf = &ring->buf[i];
+		/* alloc DMA memory */
+		(void) mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr,
+		    sc->sc_dmabuf_size,
+		    &mwl_buf_accattr,
+		    DDI_DMA_STREAMING,
+		    DDI_DMA_READ | DDI_DMA_STREAMING,
+		    &bf->rxbuf_dma);
+		bf->bf_mem = (uint8_t *)(bf->rxbuf_dma.mem_va);
+		bf->bf_baddr = bf->rxbuf_dma.cookie.dmac_address;
+		bf->bf_desc = ds;
+		bf->bf_daddr = ring->physaddr + _PTRDIFF(ds, ring->desc);
+	}
+
+	(void) ddi_dma_sync(ring->rxdesc_dma.dma_hdl,
+	    0,
+	    ring->rxdesc_dma.alength,
+	    DDI_DMA_SYNC_FORDEV);
+
+	return (0);
+}
+
+static void
+mwl_free_rx_ring(struct mwl_softc *sc)
+{
+	struct mwl_rx_ring *ring;
+	struct mwl_rxbuf *bf;
+	int i;
+
+	ring = &sc->sc_rxring;
+
+	if (ring->desc != NULL) {
+		mwl_free_dma_mem(&ring->rxdesc_dma);
+	}
+
+	if (ring->buf != NULL) {
+		for (i = 0; i < ring->count; i++) {
+			bf = &ring->buf[i];
+			mwl_free_dma_mem(&bf->rxbuf_dma);
+		}
+		kmem_free(ring->buf,
+		    (ring->count * sizeof (struct mwl_rxbuf)));
+	}
+}
+
+static int
+mwl_alloc_tx_ring(struct mwl_softc *sc, struct mwl_tx_ring *ring,
+    int count)
+{
+	struct mwl_txdesc *ds;
+	struct mwl_txbuf *bf;
+	int i, err, datadlen;
+
+	ring->count = count;
+	ring->queued = 0;
+	ring->cur = ring->next = ring->stat = 0;
+	err = mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr,
+	    count * sizeof (struct mwl_txdesc), &mwl_desc_accattr,
+	    DDI_DMA_CONSISTENT, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
+	    &ring->txdesc_dma);
+	if (err) {
+		MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_tx_ring(): "
+		    "alloc tx ring failed, size %d\n",
+		    (uint32_t)(count * sizeof (struct mwl_txdesc)));
+		return (DDI_FAILURE);
+	}
+
+	MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_tx_ring(): "
+	    "dma len = %d\n", (uint32_t)(ring->txdesc_dma.alength));
+	ring->desc = (struct mwl_txdesc *)ring->txdesc_dma.mem_va;
+	ring->physaddr = ring->txdesc_dma.cookie.dmac_address;
+	bzero(ring->desc, count * sizeof (struct mwl_txdesc));
+
+	datadlen = count * sizeof (struct mwl_txbuf);
+	ring->buf = kmem_zalloc(datadlen, KM_SLEEP);
+	if (ring->buf == NULL) {
+		MWL_DBG(MWL_DBG_DMA, "mwl: mwl_alloc_tx_ring(): "
+		    "could not alloc tx ring data buffer\n");
+		return (DDI_FAILURE);
+	}
+	bzero(ring->buf, count * sizeof (struct mwl_txbuf));
+
+	for (i = 0; i < count; i++) {
+		ds = &ring->desc[i];
+		bf = &ring->buf[i];
+		/* alloc DMA memory */
+		(void) mwl_alloc_dma_mem(sc->sc_dev, &mwl_dma_attr,
+		    sc->sc_dmabuf_size,
+		    &mwl_buf_accattr,
+		    DDI_DMA_STREAMING,
+		    DDI_DMA_WRITE | DDI_DMA_STREAMING,
+		    &bf->txbuf_dma);
+		bf->bf_baddr = bf->txbuf_dma.cookie.dmac_address;
+		bf->bf_mem = (uint8_t *)(bf->txbuf_dma.mem_va);
+		bf->bf_daddr = ring->physaddr + _PTRDIFF(ds, ring->desc);
+		bf->bf_desc = ds;
+	}
+
+	(void) ddi_dma_sync(ring->txdesc_dma.dma_hdl,
+	    0,
+	    ring->txdesc_dma.alength,
+	    DDI_DMA_SYNC_FORDEV);
+
+	return (0);
+}
+
+/* ARGSUSED */
+static void
+mwl_free_tx_ring(struct mwl_softc *sc, struct mwl_tx_ring *ring)
+{
+	struct mwl_txbuf *bf;
+	int i;
+
+	if (ring->desc != NULL) {
+		mwl_free_dma_mem(&ring->txdesc_dma);
+	}
+
+	if (ring->buf != NULL) {
+		for (i = 0; i < ring->count; i++) {
+			bf = &ring->buf[i];
+			mwl_free_dma_mem(&bf->txbuf_dma);
+		}
+		kmem_free(ring->buf,
+		    (ring->count * sizeof (struct mwl_txbuf)));
+	}
+}
+
+/*
+ * Inform the f/w about location of the tx/rx dma data structures
+ * and related state.  This cmd must be done immediately after a
+ * mwl_hal_gethwspecs call or the f/w will lockup.
+ */
+static int
+mwl_hal_sethwdma(struct mwl_softc *sc, const struct mwl_hal_txrxdma *dma)
+{
+	HostCmd_DS_SET_HW_SPEC *pCmd;
+	int retval;
+
+	_CMD_SETUP(pCmd, HostCmd_DS_SET_HW_SPEC, HostCmd_CMD_SET_HW_SPEC);
+	pCmd->WcbBase[0] = LE_32(dma->wcbBase[0]);
+	pCmd->WcbBase[1] = LE_32(dma->wcbBase[1]);
+	pCmd->WcbBase[2] = LE_32(dma->wcbBase[2]);
+	pCmd->WcbBase[3] = LE_32(dma->wcbBase[3]);
+	pCmd->TxWcbNumPerQueue = LE_32(dma->maxNumTxWcb);
+	pCmd->NumTxQueues = LE_32(dma->maxNumWCB);
+	pCmd->TotalRxWcb = LE_32(1);		/* XXX */
+	pCmd->RxPdWrPtr = LE_32(dma->rxDescRead);
+	/*
+	 * pCmd->Flags = LE_32(SET_HW_SPEC_HOSTFORM_BEACON
+	 * #ifdef MWL_HOST_PS_SUPPORT
+	 * | SET_HW_SPEC_HOST_POWERSAVE
+	 * #endif
+	 * | SET_HW_SPEC_HOSTFORM_PROBERESP);
+	 */
+	pCmd->Flags = 0;
+	/* disable multi-bss operation for A1-A4 parts */
+	if (sc->sc_revs.mh_macRev < 5)
+		pCmd->Flags |= LE_32(SET_HW_SPEC_DISABLEMBSS);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_HW_SPEC);
+	if (retval == 0) {
+		if (pCmd->Flags & LE_32(SET_HW_SPEC_DISABLEMBSS))
+			sc->sc_hw_flags &= ~MHF_MBSS;
+		else
+			sc->sc_hw_flags |= MHF_MBSS;
+	}
+
+	return (retval);
+}
+
+/*
+ * Inform firmware of our tx/rx dma setup.  The BAR 0
+ * writes below are for compatibility with older firmware.
+ * For current firmware we send this information with a
+ * cmd block via mwl_hal_sethwdma.
+ */
+static int
+mwl_setupdma(struct mwl_softc *sc)
+{
+	int i, err;
+
+	sc->sc_hwdma.rxDescRead = sc->sc_rxring.physaddr;
+	mwl_mem_write4(sc, sc->sc_hwspecs.rxDescRead, sc->sc_hwdma.rxDescRead);
+	mwl_mem_write4(sc, sc->sc_hwspecs.rxDescWrite, sc->sc_hwdma.rxDescRead);
+
+	for (i = 0; i < MWL_NUM_TX_QUEUES - MWL_NUM_ACK_QUEUES; i++) {
+		struct mwl_tx_ring *txring = &sc->sc_txring[i];
+		sc->sc_hwdma.wcbBase[i] = txring->physaddr;
+		mwl_mem_write4(sc, sc->sc_hwspecs.wcbBase[i],
+		    sc->sc_hwdma.wcbBase[i]);
+	}
+	sc->sc_hwdma.maxNumTxWcb = MWL_TX_RING_COUNT;
+	sc->sc_hwdma.maxNumWCB = MWL_NUM_TX_QUEUES - MWL_NUM_ACK_QUEUES;
+
+	err = mwl_hal_sethwdma(sc, &sc->sc_hwdma);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_DMA, "mwl: mwl_setupdma(): "
+		    "unable to setup tx/rx dma; hal status %u\n", err);
+		/* XXX */
+	}
+
+	return (err);
+}
+
+/* ARGSUSED */
+static void
+mwl_txq_init(struct mwl_softc *sc, struct mwl_tx_ring *txring, int qnum)
+{
+	struct mwl_txbuf *bf;
+	struct mwl_txdesc *ds;
+	int i;
+
+	txring->qnum = qnum;
+	txring->txpri = 0;	/* XXX */
+
+	bf = txring->buf;
+	ds = txring->desc;
+	for (i = 0; i < MWL_TX_RING_COUNT - 1; i++) {
+		bf++;
+		ds->pPhysNext = bf->bf_daddr;
+		ds++;
+	}
+	bf = txring->buf;
+	ds->pPhysNext = LE_32(bf->bf_daddr);
+}
+
+/*
+ * Setup a hardware data transmit queue for the specified
+ * access control.  We record the mapping from ac's
+ * to h/w queues for use by mwl_tx_start.
+ */
+static int
+mwl_tx_setup(struct mwl_softc *sc, int ac, int mvtype)
+{
+#define	N(a)	(sizeof (a)/sizeof (a[0]))
+	struct mwl_tx_ring *txring;
+
+	if (ac >= N(sc->sc_ac2q)) {
+		MWL_DBG(MWL_DBG_DMA, "mwl: mwl_tx_setup(): "
+		    "AC %u out of range, max %u!\n",
+		    ac, (uint_t)N(sc->sc_ac2q));
+		return (0);
+	}
+	if (mvtype >= MWL_NUM_TX_QUEUES) {
+		MWL_DBG(MWL_DBG_DMA, "mwl: mwl_tx_setup(): "
+		    "mvtype %u out of range, max %u!\n",
+		    mvtype, MWL_NUM_TX_QUEUES);
+		return (0);
+	}
+	txring = &sc->sc_txring[mvtype];
+	mwl_txq_init(sc, txring, mvtype);
+	sc->sc_ac2q[ac] = txring;
+	return (1);
+#undef N
+}
+
+static int
+mwl_setup_txq(struct mwl_softc *sc)
+{
+	int err = 0;
+
+	/* NB: insure BK queue is the lowest priority h/w queue */
+	if (!mwl_tx_setup(sc, WME_AC_BK, MWL_WME_AC_BK)) {
+		MWL_DBG(MWL_DBG_DMA, "mwl: mwl_setup_txq(): "
+		    "unable to setup xmit queue for %s traffic!\n",
+		    mwl_wme_acnames[WME_AC_BK]);
+		err = EIO;
+		return (err);
+	}
+	if (!mwl_tx_setup(sc, WME_AC_BE, MWL_WME_AC_BE) ||
+	    !mwl_tx_setup(sc, WME_AC_VI, MWL_WME_AC_VI) ||
+	    !mwl_tx_setup(sc, WME_AC_VO, MWL_WME_AC_VO)) {
+		/*
+		 * Not enough hardware tx queues to properly do WME;
+		 * just punt and assign them all to the same h/w queue.
+		 * We could do a better job of this if, for example,
+		 * we allocate queues when we switch from station to
+		 * AP mode.
+		 */
+		sc->sc_ac2q[WME_AC_BE] = sc->sc_ac2q[WME_AC_BK];
+		sc->sc_ac2q[WME_AC_VI] = sc->sc_ac2q[WME_AC_BK];
+		sc->sc_ac2q[WME_AC_VO] = sc->sc_ac2q[WME_AC_BK];
+	}
+
+	return (err);
+}
+
+/*
+ * find mwl firmware module's "_start" "_end" symbols
+ * and get its size.
+ */
+static int
+mwl_loadsym(ddi_modhandle_t modp, char *sym, char **start, size_t *len)
+{
+	char start_sym[64];
+	char end_sym[64];
+	char *p, *end;
+	int rv;
+	size_t n;
+
+	(void) snprintf(start_sym, sizeof (start_sym), "%s_start", sym);
+	(void) snprintf(end_sym, sizeof (end_sym), "%s_end", sym);
+
+	p = (char *)ddi_modsym(modp, start_sym, &rv);
+	if (p == NULL || rv != 0) {
+		MWL_DBG(MWL_DBG_FW, "mwl: mwl_loadsym(): "
+		    "mod %s: symbol %s not found\n", sym, start_sym);
+		return (-1);
+	}
+
+	end = (char *)ddi_modsym(modp, end_sym, &rv);
+	if (end == NULL || rv != 0) {
+		MWL_DBG(MWL_DBG_FW, "mwl: mwl_loadsym(): "
+		    "mod %s: symbol %s not found\n", sym, end_sym);
+		return (-1);
+	}
+
+	n = _PTRDIFF(end, p);
+	*start = p;
+	*len = n;
+
+	return (0);
+}
+
+static void
+mwlFwReset(struct mwl_softc *sc)
+{
+	if (mwl_ctl_read4(sc,  MACREG_REG_INT_CODE) == 0xffffffff) {
+		MWL_DBG(MWL_DBG_FW, "mwl: mwlFWReset(): "
+		    "device not present!\n");
+		return;
+	}
+
+	mwl_ctl_write4(sc, MACREG_REG_H2A_INTERRUPT_EVENTS, ISR_RESET);
+	sc->sc_hw_flags &= ~MHF_FWHANG;
+}
+
+static void
+mwlPokeSdramController(struct mwl_softc *sc, int SDRAMSIZE_Addr)
+{
+	/* Set up sdram controller for superflyv2 */
+	mwl_ctl_write4(sc, 0x00006014, 0x33);
+	mwl_ctl_write4(sc, 0x00006018, 0xa3a2632);
+	mwl_ctl_write4(sc, 0x00006010, SDRAMSIZE_Addr);
+}
+
+static void
+mwlTriggerPciCmd(struct mwl_softc *sc)
+{
+	(void) ddi_dma_sync(sc->sc_cmd_dma.dma_hdl,
+	    0,
+	    sc->sc_cmd_dma.alength,
+	    DDI_DMA_SYNC_FORDEV);
+
+	mwl_ctl_write4(sc, MACREG_REG_GEN_PTR, sc->sc_cmd_dmaaddr);
+	(void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
+
+	mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0x00);
+	(void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
+
+	mwl_ctl_write4(sc, MACREG_REG_H2A_INTERRUPT_EVENTS,
+	    MACREG_H2ARIC_BIT_DOOR_BELL);
+	(void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
+}
+
+static int
+mwlWaitFor(struct mwl_softc *sc, uint32_t val)
+{
+	int i;
+
+	for (i = 0; i < FW_MAX_NUM_CHECKS; i++) {
+		DELAY(FW_CHECK_USECS);
+		if (mwl_ctl_read4(sc, MACREG_REG_INT_CODE) == val)
+			return (1);
+	}
+	return (0);
+}
+
+/*
+ * Firmware block xmit when talking to the boot-rom.
+ */
+static int
+mwlSendBlock(struct mwl_softc *sc, int bsize, const void *data, size_t dsize)
+{
+	sc->sc_cmd_mem[0] = LE_16(HostCmd_CMD_CODE_DNLD);
+	sc->sc_cmd_mem[1] = LE_16(bsize);
+	(void) memcpy(&sc->sc_cmd_mem[4], data, dsize);
+	mwlTriggerPciCmd(sc);
+	/* XXX 2000 vs 200 */
+	if (mwlWaitFor(sc, MACREG_INT_CODE_CMD_FINISHED)) {
+		mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0);
+		return (1);
+	}
+
+	MWL_DBG(MWL_DBG_FW, "mwl: mwlSendBlock(): "
+	    "timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
+	    mwl_ctl_read4(sc, MACREG_REG_INT_CODE));
+	return (0);
+}
+
+/*
+ * Firmware block xmit when talking to the 1st-stage loader.
+ */
+static int
+mwlSendBlock2(struct mwl_softc *sc, const void *data, size_t dsize)
+{
+	(void) memcpy(&sc->sc_cmd_mem[0], data, dsize);
+	mwlTriggerPciCmd(sc);
+	if (mwlWaitFor(sc, MACREG_INT_CODE_CMD_FINISHED)) {
+		mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0);
+		return (1);
+	}
+
+	MWL_DBG(MWL_DBG_FW, "mwl: mwlSendBlock2(): "
+	    "timeout waiting for CMD_FINISHED, INT_CODE 0x%x\n",
+	    mwl_ctl_read4(sc, MACREG_REG_INT_CODE));
+	return (0);
+}
+
+/* ARGSUSED */
+static int
+mwl_fwload(struct mwl_softc *sc, void *fwargs)
+{
+	char *fwname = "mwlfw";
+	char *fwbootname = "mwlboot";
+	char *fwbinname = "mw88W8363fw";
+	char *fwboot_index, *fw_index;
+	uint8_t *fw, *fwboot;
+	ddi_modhandle_t modfw;
+	/* XXX get from firmware header */
+	uint32_t FwReadySignature = HostCmd_SOFTAP_FWRDY_SIGNATURE;
+	uint32_t OpMode = HostCmd_SOFTAP_MODE;
+	const uint8_t *fp, *ep;
+	size_t fw_size, fwboot_size;
+	uint32_t blocksize, nbytes;
+	int i, rv, err, ntries;
+
+	rv = err = 0;
+	fw = fwboot = NULL;
+	fw_index = fwboot_index = NULL;
+
+	modfw = ddi_modopen(fwname, KRTLD_MODE_FIRST, &rv);
+	if (modfw == NULL) {
+		MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
+		    "module %s not found\n", fwname);
+		err = -1;
+		goto bad2;
+	}
+
+	err = mwl_loadsym(modfw, fwbootname, &fwboot_index, &fwboot_size);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
+		    "could not get boot firmware\n");
+		err = -1;
+		goto bad2;
+	}
+
+	err = mwl_loadsym(modfw, fwbinname, &fw_index, &fw_size);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
+		    "could not get firmware\n");
+		err = -1;
+		goto bad2;
+	}
+
+	fwboot = (uint8_t *)kmem_alloc(fwboot_size, KM_SLEEP);
+	if (fwboot == NULL) {
+		MWL_DBG(MWL_DBG_FW, "mwl: mwl_loadfirmware(): "
+		    "failed to alloc boot firmware memory\n");
+		err = -1;
+		goto bad2;
+	}
+	(void) memcpy(fwboot, fwboot_index, fwboot_size);
+
+	fw = (uint8_t *)kmem_alloc(fw_size, KM_SLEEP);
+	if (fw == NULL) {
+		MWL_DBG(MWL_DBG_FW, "mwl: mwl_loadfirmware(): "
+		    "failed to alloc firmware memory\n");
+		err = -1;
+		goto bad2;
+	}
+	(void) memcpy(fw, fw_index, fw_size);
+
+	if (modfw != NULL)
+		(void) ddi_modclose(modfw);
+
+	if (fw_size < 4) {
+		MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
+		    "could not load firmware image %s\n",
+		    fwname);
+		err = ENXIO;
+		goto bad2;
+	}
+
+	if (fw[0] == 0x01 && fw[1] == 0x00 &&
+	    fw[2] == 0x00 && fw[3] == 0x00) {
+		/*
+		 * 2-stage load, get the boot firmware.
+		 */
+		if (fwboot == NULL) {
+			MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
+			    "could not load firmware image %s\n",
+			    fwbootname);
+			err = ENXIO;
+			goto bad2;
+		}
+	} else
+		fwboot = NULL;
+
+	mwlFwReset(sc);
+
+	mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_CLEAR_SEL,
+	    MACREG_A2HRIC_BIT_MASK);
+	mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_CAUSE, 0x00);
+	mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_MASK, 0x00);
+	mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_STATUS_MASK,
+	    MACREG_A2HRIC_BIT_MASK);
+	if (sc->sc_SDRAMSIZE_Addr != 0) {
+		/* Set up sdram controller for superflyv2 */
+		mwlPokeSdramController(sc, sc->sc_SDRAMSIZE_Addr);
+	}
+
+	MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
+	    "load %s firmware image (%u bytes)\n",
+	    fwname, (unsigned int)fw_size);
+
+	if (fwboot != NULL) {
+		/*
+		 * Do 2-stage load.  The 1st stage loader is setup
+		 * with the bootrom loader then we load the real
+		 * image using a different handshake. With this
+		 * mechanism the firmware is segmented into chunks
+		 * that have a CRC.  If a chunk is incorrect we'll
+		 * be told to retransmit.
+		 */
+		/* XXX assumes hlpimage fits in a block */
+		/* NB: zero size block indicates download is finished */
+		if (!mwlSendBlock(sc, fwboot_size, fwboot, fwboot_size) ||
+		    !mwlSendBlock(sc, 0, NULL, 0)) {
+			err = ETIMEDOUT;
+			goto bad;
+		}
+		DELAY(200 * FW_CHECK_USECS);
+		if (sc->sc_SDRAMSIZE_Addr != 0) {
+			/* Set up sdram controller for superflyv2 */
+			mwlPokeSdramController(sc, sc->sc_SDRAMSIZE_Addr);
+		}
+		nbytes = ntries = 0;		/* NB: silence compiler */
+		for (fp = fw, ep = fp + fw_size; fp < ep; ) {
+			mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0);
+			blocksize = mwl_ctl_read4(sc, MACREG_REG_SCRATCH);
+			if (blocksize == 0)	/* download complete */
+				break;
+			if (blocksize > 0x00000c00) {
+				err = EINVAL;
+				goto bad;
+			}
+			if ((blocksize & 0x1) == 0) {
+				/* block successfully downloaded, advance */
+				fp += nbytes;
+				ntries = 0;
+			} else {
+				if (++ntries > 2) {
+					/*
+					 * Guard against f/w telling us to
+					 * retry infinitely.
+					 */
+					err = ELOOP;
+					goto bad;
+				}
+				/* clear NAK bit/flag */
+				blocksize &= ~0x1;
+			}
+			if (blocksize > _PTRDIFF(ep, fp)) {
+				/* XXX this should not happen, what to do? */
+				blocksize = _PTRDIFF(ep, fp);
+			}
+			nbytes = blocksize;
+			if (!mwlSendBlock2(sc, fp, nbytes)) {
+				err = ETIMEDOUT;
+				goto bad;
+			}
+		}
+	} else {
+		for (fp = fw, ep = fp + fw_size; fp < ep; ) {
+			nbytes = _PTRDIFF(ep, fp);
+			if (nbytes > FW_DOWNLOAD_BLOCK_SIZE)
+				nbytes = FW_DOWNLOAD_BLOCK_SIZE;
+			if (!mwlSendBlock(sc, FW_DOWNLOAD_BLOCK_SIZE, fp,
+			    nbytes)) {
+				err = EIO;
+				goto bad;
+			}
+			fp += nbytes;
+		}
+	}
+
+	/*
+	 * Wait for firmware to startup; we monitor the
+	 * INT_CODE register waiting for a signature to
+	 * written back indicating it's ready to go.
+	 */
+	sc->sc_cmd_mem[1] = 0;
+	/*
+	 * XXX WAR for mfg fw download
+	 */
+	if (OpMode != HostCmd_STA_MODE)
+		mwlTriggerPciCmd(sc);
+	for (i = 0; i < FW_MAX_NUM_CHECKS; i++) {
+		mwl_ctl_write4(sc, MACREG_REG_GEN_PTR, OpMode);
+		DELAY(FW_CHECK_USECS);
+		if (mwl_ctl_read4(sc, MACREG_REG_INT_CODE) ==
+		    FwReadySignature) {
+			mwl_ctl_write4(sc, MACREG_REG_INT_CODE, 0x00);
+			return (mwlResetHalState(sc));
+		}
+	}
+	MWL_DBG(MWL_DBG_FW, "mwl: mwl_fwload(): "
+	    "firmware download timeout\n");
+	return (ETIMEDOUT);
+bad:
+	mwlFwReset(sc);
+bad2:
+	if (fw != NULL)
+		kmem_free(fw, fw_size);
+	if (fwboot != NULL)
+		kmem_free(fwboot, fwboot_size);
+	fwboot = fw = NULL;
+	fwboot_index = fw_index = NULL;
+	if (modfw != NULL)
+		(void) ddi_modclose(modfw);
+	return (err);
+}
+
+/*
+ * Low level firmware cmd block handshake support.
+ */
+static void
+mwlSendCmd(struct mwl_softc *sc)
+{
+	(void) ddi_dma_sync(sc->sc_cmd_dma.dma_hdl,
+	    0,
+	    sc->sc_cmd_dma.alength,
+	    DDI_DMA_SYNC_FORDEV);
+
+	mwl_ctl_write4(sc, MACREG_REG_GEN_PTR, sc->sc_cmd_dmaaddr);
+	(void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
+
+	mwl_ctl_write4(sc, MACREG_REG_H2A_INTERRUPT_EVENTS,
+	    MACREG_H2ARIC_BIT_DOOR_BELL);
+}
+
+static int
+mwlExecuteCmd(struct mwl_softc *sc, unsigned short cmd)
+{
+	if (mwl_ctl_read4(sc,  MACREG_REG_INT_CODE) == 0xffffffff) {
+		MWL_DBG(MWL_DBG_CMD, "mwl: mwlExecuteCmd(): "
+		    "device not present!\n");
+		return (EIO);
+	}
+	mwlSendCmd(sc);
+	if (!mwlWaitForCmdComplete(sc, 0x8000 | cmd)) {
+		MWL_DBG(MWL_DBG_CMD, "mwl: mwlExecuteCmd(): "
+		    "timeout waiting for f/w cmd %s\n", mwlcmdname(cmd));
+		return (ETIMEDOUT);
+	}
+	(void) ddi_dma_sync(sc->sc_cmd_dma.dma_hdl,
+	    0,
+	    sc->sc_cmd_dma.alength,
+	    DDI_DMA_SYNC_FORDEV);
+
+	MWL_DBG(MWL_DBG_CMD, "mwl: mwlExecuteCmd(): "
+	    "send cmd %s\n", mwlcmdname(cmd));
+
+	if (mwl_dbg_flags & MWL_DBG_CMD)
+		dumpresult(sc, 1);
+
+	return (0);
+}
+
+static int
+mwlWaitForCmdComplete(struct mwl_softc *sc, uint16_t cmdCode)
+{
+#define	MAX_WAIT_FW_COMPLETE_ITERATIONS	10000
+	int i;
+
+	for (i = 0; i < MAX_WAIT_FW_COMPLETE_ITERATIONS; i++) {
+		if (sc->sc_cmd_mem[0] == LE_16(cmdCode))
+			return (1);
+		DELAY(1 * 1000);
+	}
+	return (0);
+#undef MAX_WAIT_FW_COMPLETE_ITERATIONS
+}
+
+static const char *
+mwlcmdname(int cmd)
+{
+	static char buf[12];
+#define	CMD(x)	case HostCmd_CMD_##x: return #x
+	switch (cmd) {
+	CMD(CODE_DNLD);
+	CMD(GET_HW_SPEC);
+	CMD(SET_HW_SPEC);
+	CMD(MAC_MULTICAST_ADR);
+	CMD(802_11_GET_STAT);
+	CMD(MAC_REG_ACCESS);
+	CMD(BBP_REG_ACCESS);
+	CMD(RF_REG_ACCESS);
+	CMD(802_11_RADIO_CONTROL);
+	CMD(802_11_RF_TX_POWER);
+	CMD(802_11_RF_ANTENNA);
+	CMD(SET_BEACON);
+	CMD(SET_RF_CHANNEL);
+	CMD(SET_AID);
+	CMD(SET_INFRA_MODE);
+	CMD(SET_G_PROTECT_FLAG);
+	CMD(802_11_RTS_THSD);
+	CMD(802_11_SET_SLOT);
+	CMD(SET_EDCA_PARAMS);
+	CMD(802_11H_DETECT_RADAR);
+	CMD(SET_WMM_MODE);
+	CMD(HT_GUARD_INTERVAL);
+	CMD(SET_FIXED_RATE);
+	CMD(SET_LINKADAPT_CS_MODE);
+	CMD(SET_MAC_ADDR);
+	CMD(SET_RATE_ADAPT_MODE);
+	CMD(BSS_START);
+	CMD(SET_NEW_STN);
+	CMD(SET_KEEP_ALIVE);
+	CMD(SET_APMODE);
+	CMD(SET_SWITCH_CHANNEL);
+	CMD(UPDATE_ENCRYPTION);
+	CMD(BASTREAM);
+	CMD(SET_RIFS);
+	CMD(SET_N_PROTECT_FLAG);
+	CMD(SET_N_PROTECT_OPMODE);
+	CMD(SET_OPTIMIZATION_LEVEL);
+	CMD(GET_CALTABLE);
+	CMD(SET_MIMOPSHT);
+	CMD(GET_BEACON);
+	CMD(SET_REGION_CODE);
+	CMD(SET_POWERSAVESTATION);
+	CMD(SET_TIM);
+	CMD(GET_TIM);
+	CMD(GET_SEQNO);
+	CMD(DWDS_ENABLE);
+	CMD(AMPDU_RETRY_RATEDROP_MODE);
+	CMD(CFEND_ENABLE);
+	}
+	(void) snprintf(buf, sizeof (buf), "0x%x", cmd);
+	return (buf);
+#undef CMD
+}
+
+static void
+dumpresult(struct mwl_softc *sc, int showresult)
+{
+	const FWCmdHdr *h = (const FWCmdHdr *)sc->sc_cmd_mem;
+	int len;
+
+	len = LE_16(h->Length);
+#ifdef MWL_MBSS_SUPPORT
+	MWL_DBG(MWL_DBG_CMD, "mwl: mwl_dumpresult(): "
+	    "Cmd %s Length %d SeqNum %d MacId %d",
+	    mwlcmdname(LE_16(h->Cmd) & ~0x8000), len, h->SeqNum, h->MacId);
+#else
+	MWL_DBG(MWL_DBG_CMD, "mwl: mwl_dumpresult(): "
+	    "Cmd %s Length %d SeqNum %d",
+	    mwlcmdname(LE_16(h->Cmd) & ~0x8000), len, LE_16(h->SeqNum));
+#endif
+	if (showresult) {
+		const char *results[] =
+		    { "OK", "ERROR", "NOT_SUPPORT", "PENDING", "BUSY",
+		    "PARTIAL_DATA" };
+		int result = LE_16(h->Result);
+
+		if (result <= HostCmd_RESULT_PARTIAL_DATA)
+			MWL_DBG(MWL_DBG_CMD, "mwl: dumpresult(): "
+			    "Result %s", results[result]);
+		else
+			MWL_DBG(MWL_DBG_CMD, "mwl: dumpresult(): "
+			    "Result %d", result);
+	}
+}
+
+static int
+mwlGetCalTable(struct mwl_softc *sc, uint8_t annex, uint8_t index)
+{
+	HostCmd_FW_GET_CALTABLE *pCmd;
+	int retval;
+
+	_CMD_SETUP(pCmd, HostCmd_FW_GET_CALTABLE, HostCmd_CMD_GET_CALTABLE);
+	pCmd->annex = annex;
+	pCmd->index = index;
+	memset(pCmd->calTbl, 0, sizeof (pCmd->calTbl));
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_GET_CALTABLE);
+	if (retval == 0 &&
+	    pCmd->calTbl[0] != annex && annex != 0 && annex != 255)
+		retval = EIO;
+	return (retval);
+}
+
+/*
+ * Construct channel info for 2.4GHz channels from cal data.
+ */
+static void
+get2Ghz(MWL_HAL_CHANNELINFO *ci, const uint8_t table[], int len)
+{
+	int i, j;
+
+	j = 0;
+	for (i = 0; i < len; i += 4) {
+		struct mwl_hal_channel *hc = &ci->channels[j];
+		hc->ieee = 1+j;
+		hc->freq = ieee2mhz(1+j);
+		(void) memcpy(hc->targetPowers, &table[i], 4);
+		setmaxtxpow(hc, 0, 4);
+		j++;
+	}
+	ci->nchannels = j;
+	ci->freqLow = ieee2mhz(1);
+	ci->freqHigh = ieee2mhz(j);
+}
+
+/*
+ * Construct channel info for 5GHz channels from cal data.
+ */
+static void
+get5Ghz(MWL_HAL_CHANNELINFO *ci, const uint8_t table[], int len)
+{
+	int i, j, f, l, h;
+
+	l = 32000;
+	h = 0;
+	j = 0;
+	for (i = 0; i < len; i += 4) {
+		struct mwl_hal_channel *hc;
+
+		if (table[i] == 0)
+			continue;
+		f = 5000 + 5*table[i];
+		if (f < l)
+			l = f;
+		if (f > h)
+			h = f;
+		hc = &ci->channels[j];
+		hc->freq = (uint16_t)f;
+		hc->ieee = table[i];
+		(void) memcpy(hc->targetPowers, &table[i], 4);
+		setmaxtxpow(hc, 1, 4);	/* NB: col 1 is the freq, skip */
+		j++;
+	}
+	ci->nchannels = j;
+	ci->freqLow = (uint16_t)((l == 32000) ? 0 : l);
+	ci->freqHigh = (uint16_t)h;
+}
+
+/*
+ * Calculate the max tx power from the channel's cal data.
+ */
+static void
+setmaxtxpow(struct mwl_hal_channel *hc, int i, int maxix)
+{
+	hc->maxTxPow = hc->targetPowers[i];
+	for (i++; i < maxix; i++)
+		if (hc->targetPowers[i] > hc->maxTxPow)
+			hc->maxTxPow = hc->targetPowers[i];
+}
+
+static uint16_t
+ieee2mhz(int chan)
+{
+	if (chan == 14)
+		return (2484);
+	if (chan < 14)
+		return (2407 + chan * 5);
+	return (2512 + (chan - 15) * 20);
+}
+
+static void
+dumpcaldata(const char *name, const uint8_t *table, int n)
+{
+	int i;
+	MWL_DBG(MWL_DBG_HW, "\n%s:\n", name);
+	for (i = 0; i < n; i += 4)
+		MWL_DBG(MWL_DBG_HW, "[%2d] %3d %3d %3d %3d\n",
+		    i/4, table[i+0], table[i+1], table[i+2], table[i+3]);
+}
+
+static int
+mwlGetPwrCalTable(struct mwl_softc *sc)
+{
+	const uint8_t *data;
+	MWL_HAL_CHANNELINFO *ci;
+	int len;
+
+	/* NB: we hold the lock so it's ok to use cmdbuf */
+	data = ((const HostCmd_FW_GET_CALTABLE *) sc->sc_cmd_mem)->calTbl;
+	if (mwlGetCalTable(sc, 33, 0) == 0) {
+		len = (data[2] | (data[3] << 8)) - 12;
+		if (len > PWTAGETRATETABLE20M)
+			len = PWTAGETRATETABLE20M;
+		dumpcaldata("2.4G 20M", &data[12], len);
+		get2Ghz(&sc->sc_20M, &data[12], len);
+	}
+	if (mwlGetCalTable(sc, 34, 0) == 0) {
+		len = (data[2] | (data[3] << 8)) - 12;
+		if (len > PWTAGETRATETABLE40M)
+			len = PWTAGETRATETABLE40M;
+		dumpcaldata("2.4G 40M", &data[12], len);
+		ci = &sc->sc_40M;
+		get2Ghz(ci, &data[12], len);
+	}
+	if (mwlGetCalTable(sc, 35, 0) == 0) {
+		len = (data[2] | (data[3] << 8)) - 20;
+		if (len > PWTAGETRATETABLE20M_5G)
+			len = PWTAGETRATETABLE20M_5G;
+		dumpcaldata("5G 20M", &data[20], len);
+		get5Ghz(&sc->sc_20M_5G, &data[20], len);
+	}
+	if (mwlGetCalTable(sc, 36, 0) == 0) {
+		len = (data[2] | (data[3] << 8)) - 20;
+		if (len > PWTAGETRATETABLE40M_5G)
+			len = PWTAGETRATETABLE40M_5G;
+		dumpcaldata("5G 40M", &data[20], len);
+		ci = &sc->sc_40M_5G;
+		get5Ghz(ci, &data[20], len);
+	}
+	sc->sc_hw_flags |= MHF_CALDATA;
+	return (0);
+}
+
+/*
+ * Reset internal state after a firmware download.
+ */
+static int
+mwlResetHalState(struct mwl_softc *sc)
+{
+	int err = 0;
+
+	/*
+	 * Fetch cal data for later use.
+	 * XXX may want to fetch other stuff too.
+	 */
+	/* XXX check return */
+	if ((sc->sc_hw_flags & MHF_CALDATA) == 0)
+		err = mwlGetPwrCalTable(sc);
+	return (err);
+}
+
+#define	IEEE80211_CHAN_HTG	(IEEE80211_CHAN_HT|IEEE80211_CHAN_G)
+#define	IEEE80211_CHAN_HTA	(IEEE80211_CHAN_HT|IEEE80211_CHAN_A)
+
+static void
+addchan(struct mwl_channel *c, int freq, int flags, int ieee, int txpow)
+{
+	c->ic_freq = (uint16_t)freq;
+	c->ic_flags = flags;
+	c->ic_ieee = (uint8_t)ieee;
+	c->ic_minpower = 0;
+	c->ic_maxpower = 2*txpow;
+	c->ic_maxregpower = (uint8_t)txpow;
+}
+
+static const struct mwl_channel *
+findchannel(const struct mwl_channel chans[], int nchans,
+	int freq, int flags)
+{
+	const struct mwl_channel *c;
+	int i;
+
+	for (i = 0; i < nchans; i++) {
+		c = &chans[i];
+		if (c->ic_freq == freq && c->ic_flags == flags)
+			return (c);
+	}
+	return (NULL);
+}
+
+static void
+addht40channels(struct mwl_channel chans[], int maxchans, int *nchans,
+	const MWL_HAL_CHANNELINFO *ci, int flags)
+{
+	struct mwl_channel *c;
+	const struct mwl_channel *extc;
+	const struct mwl_hal_channel *hc;
+	int i;
+
+	c = &chans[*nchans];
+
+	flags &= ~IEEE80211_CHAN_HT;
+	for (i = 0; i < ci->nchannels; i++) {
+		/*
+		 * Each entry defines an HT40 channel pair; find the
+		 * extension channel above and the insert the pair.
+		 */
+		hc = &ci->channels[i];
+		extc = findchannel(chans, *nchans, hc->freq+20,
+		    flags | IEEE80211_CHAN_HT20);
+		if (extc != NULL) {
+			if (*nchans >= maxchans)
+				break;
+			addchan(c, hc->freq, flags | IEEE80211_CHAN_HT40U,
+			    hc->ieee, hc->maxTxPow);
+			c->ic_extieee = extc->ic_ieee;
+			c++, (*nchans)++;
+			if (*nchans >= maxchans)
+				break;
+			addchan(c, extc->ic_freq, flags | IEEE80211_CHAN_HT40D,
+			    extc->ic_ieee, hc->maxTxPow);
+			c->ic_extieee = hc->ieee;
+			c++, (*nchans)++;
+		}
+	}
+}
+
+static void
+addchannels(struct mwl_channel chans[], int maxchans, int *nchans,
+	const MWL_HAL_CHANNELINFO *ci, int flags)
+{
+	struct mwl_channel *c;
+	int i;
+
+	c = &chans[*nchans];
+
+	for (i = 0; i < ci->nchannels; i++) {
+		const struct mwl_hal_channel *hc;
+
+		hc = &ci->channels[i];
+		if (*nchans >= maxchans)
+			break;
+		addchan(c, hc->freq, flags, hc->ieee, hc->maxTxPow);
+		c++, (*nchans)++;
+
+		if (flags == IEEE80211_CHAN_G || flags == IEEE80211_CHAN_HTG) {
+			/* g channel have a separate b-only entry */
+			if (*nchans >= maxchans)
+				break;
+			c[0] = c[-1];
+			c[-1].ic_flags = IEEE80211_CHAN_B;
+			c++, (*nchans)++;
+		}
+		if (flags == IEEE80211_CHAN_HTG) {
+			/* HT g channel have a separate g-only entry */
+			if (*nchans >= maxchans)
+				break;
+			c[-1].ic_flags = IEEE80211_CHAN_G;
+			c[0] = c[-1];
+			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
+			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
+			c++, (*nchans)++;
+		}
+		if (flags == IEEE80211_CHAN_HTA) {
+			/* HT a channel have a separate a-only entry */
+			if (*nchans >= maxchans)
+				break;
+			c[-1].ic_flags = IEEE80211_CHAN_A;
+			c[0] = c[-1];
+			c[0].ic_flags &= ~IEEE80211_CHAN_HT;
+			c[0].ic_flags |= IEEE80211_CHAN_HT20;	/* HT20 */
+			c++, (*nchans)++;
+		}
+	}
+}
+
+static int
+mwl_hal_getchannelinfo(struct mwl_softc *sc, int band, int chw,
+	const MWL_HAL_CHANNELINFO **ci)
+{
+	switch (band) {
+	case MWL_FREQ_BAND_2DOT4GHZ:
+		*ci = (chw == MWL_CH_20_MHz_WIDTH) ? &sc->sc_20M : &sc->sc_40M;
+		break;
+	case MWL_FREQ_BAND_5GHZ:
+		*ci = (chw == MWL_CH_20_MHz_WIDTH) ?
+		    &sc->sc_20M_5G : &sc->sc_40M_5G;
+		break;
+	default:
+		return (EINVAL);
+	}
+	return (((*ci)->freqLow == (*ci)->freqHigh) ? EINVAL : 0);
+}
+
+static void
+getchannels(struct mwl_softc *sc, int maxchans, int *nchans,
+	struct mwl_channel chans[])
+{
+	const MWL_HAL_CHANNELINFO *ci;
+
+	/*
+	 * Use the channel info from the hal to craft the
+	 * channel list.  Note that we pass back an unsorted
+	 * list; the caller is required to sort it for us
+	 * (if desired).
+	 */
+	*nchans = 0;
+	if (mwl_hal_getchannelinfo(sc,
+	    MWL_FREQ_BAND_2DOT4GHZ, MWL_CH_20_MHz_WIDTH, &ci) == 0)
+		addchannels(chans, maxchans, nchans, ci, IEEE80211_CHAN_HTG);
+	if (mwl_hal_getchannelinfo(sc,
+	    MWL_FREQ_BAND_5GHZ, MWL_CH_20_MHz_WIDTH, &ci) == 0)
+		addchannels(chans, maxchans, nchans, ci, IEEE80211_CHAN_HTA);
+	if (mwl_hal_getchannelinfo(sc,
+	    MWL_FREQ_BAND_2DOT4GHZ, MWL_CH_40_MHz_WIDTH, &ci) == 0)
+		addht40channels(chans, maxchans, nchans, ci,
+		    IEEE80211_CHAN_HTG);
+	if (mwl_hal_getchannelinfo(sc,
+	    MWL_FREQ_BAND_5GHZ, MWL_CH_40_MHz_WIDTH, &ci) == 0)
+		addht40channels(chans, maxchans, nchans, ci,
+		    IEEE80211_CHAN_HTA);
+}
+
+static int
+mwl_getchannels(struct mwl_softc *sc)
+{
+	/*
+	 * Use the channel info from the hal to craft the
+	 * channel list for net80211.  Note that we pass up
+	 * an unsorted list; net80211 will sort it for us.
+	 */
+	memset(sc->sc_channels, 0, sizeof (sc->sc_channels));
+	sc->sc_nchans = 0;
+	getchannels(sc, IEEE80211_CHAN_MAX, &sc->sc_nchans, sc->sc_channels);
+
+	sc->sc_regdomain.regdomain = SKU_DEBUG;
+	sc->sc_regdomain.country = CTRY_DEFAULT;
+	sc->sc_regdomain.location = 'I';
+	sc->sc_regdomain.isocc[0] = ' ';	/* XXX? */
+	sc->sc_regdomain.isocc[1] = ' ';
+	return (sc->sc_nchans == 0 ? EIO : 0);
+}
+
+#undef IEEE80211_CHAN_HTA
+#undef IEEE80211_CHAN_HTG
+
+/*
+ * Return "hw specs".  Note this must be the first
+ * cmd MUST be done after a firmware download or the
+ * f/w will lockup.
+ * XXX move into the hal so driver doesn't need to be responsible
+ */
+static int
+mwl_gethwspecs(struct mwl_softc *sc)
+{
+	struct mwl_hal_hwspec *hw;
+	HostCmd_DS_GET_HW_SPEC *pCmd;
+	int retval;
+
+	hw = &sc->sc_hwspecs;
+	_CMD_SETUP(pCmd, HostCmd_DS_GET_HW_SPEC, HostCmd_CMD_GET_HW_SPEC);
+	memset(&pCmd->PermanentAddr[0], 0xff, IEEE80211_ADDR_LEN);
+	pCmd->ulFwAwakeCookie = LE_32((unsigned int)sc->sc_cmd_dmaaddr + 2048);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_GET_HW_SPEC);
+	if (retval == 0) {
+		IEEE80211_ADDR_COPY(hw->macAddr, pCmd->PermanentAddr);
+		hw->wcbBase[0] = LE_32(pCmd->WcbBase0) & 0x0000ffff;
+		hw->wcbBase[1] = LE_32(pCmd->WcbBase1[0]) & 0x0000ffff;
+		hw->wcbBase[2] = LE_32(pCmd->WcbBase1[1]) & 0x0000ffff;
+		hw->wcbBase[3] = LE_32(pCmd->WcbBase1[2]) & 0x0000ffff;
+		hw->rxDescRead = LE_32(pCmd->RxPdRdPtr)& 0x0000ffff;
+		hw->rxDescWrite = LE_32(pCmd->RxPdWrPtr)& 0x0000ffff;
+		hw->regionCode = LE_16(pCmd->RegionCode) & 0x00ff;
+		hw->fwReleaseNumber = LE_32(pCmd->FWReleaseNumber);
+		hw->maxNumWCB = LE_16(pCmd->NumOfWCB);
+		hw->maxNumMCAddr = LE_16(pCmd->NumOfMCastAddr);
+		hw->numAntennas = LE_16(pCmd->NumberOfAntenna);
+		hw->hwVersion = pCmd->Version;
+		hw->hostInterface = pCmd->HostIf;
+
+		sc->sc_revs.mh_macRev = hw->hwVersion;		/* XXX */
+		sc->sc_revs.mh_phyRev = hw->hostInterface;	/* XXX */
+	}
+
+	return (retval);
+}
+
+static int
+mwl_hal_setmac_locked(struct mwl_softc *sc,
+	const uint8_t addr[IEEE80211_ADDR_LEN])
+{
+	HostCmd_DS_SET_MAC *pCmd;
+
+	_VCMD_SETUP(pCmd, HostCmd_DS_SET_MAC, HostCmd_CMD_SET_MAC_ADDR);
+	IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr);
+#ifdef MWL_MBSS_SUPPORT
+	/* NB: already byte swapped */
+	pCmd->MacType = WL_MAC_TYPE_PRIMARY_CLIENT;
+#endif
+	return (mwlExecuteCmd(sc, HostCmd_CMD_SET_MAC_ADDR));
+}
+
+static void
+cvtPeerInfo(PeerInfo_t *to, const MWL_HAL_PEERINFO *from)
+{
+	to->LegacyRateBitMap = LE_32(from->LegacyRateBitMap);
+	to->HTRateBitMap = LE_32(from->HTRateBitMap);
+	to->CapInfo = LE_16(from->CapInfo);
+	to->HTCapabilitiesInfo = LE_16(from->HTCapabilitiesInfo);
+	to->MacHTParamInfo = from->MacHTParamInfo;
+	to->AddHtInfo.ControlChan = from->AddHtInfo.ControlChan;
+	to->AddHtInfo.AddChan = from->AddHtInfo.AddChan;
+	to->AddHtInfo.OpMode = LE_16(from->AddHtInfo.OpMode);
+	to->AddHtInfo.stbc = LE_16(from->AddHtInfo.stbc);
+}
+
+/* XXX station id must be in [0..63] */
+static int
+mwl_hal_newstation(struct mwl_softc *sc,
+	const uint8_t addr[IEEE80211_ADDR_LEN], uint16_t aid, uint16_t sid,
+	const MWL_HAL_PEERINFO *peer, int isQosSta, int wmeInfo)
+{
+	HostCmd_FW_SET_NEW_STN *pCmd;
+	int retval;
+
+	_VCMD_SETUP(pCmd, HostCmd_FW_SET_NEW_STN, HostCmd_CMD_SET_NEW_STN);
+	pCmd->AID = LE_16(aid);
+	pCmd->StnId = LE_16(sid);
+	pCmd->Action = LE_16(0);	/* SET */
+	if (peer != NULL) {
+		/* NB: must fix up byte order */
+		cvtPeerInfo(&pCmd->PeerInfo, peer);
+	}
+	IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], addr);
+	pCmd->Qosinfo = (uint8_t)wmeInfo;
+	pCmd->isQosSta = (isQosSta != 0);
+
+	MWL_DBG(MWL_DBG_HW, "mwl: mwl_hal_newstation(): "
+	    "LegacyRateBitMap %x, CapInfo %x\n",
+	    pCmd->PeerInfo.LegacyRateBitMap, pCmd->PeerInfo.CapInfo);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_NEW_STN);
+	return (retval);
+}
+
+/*
+ * Configure antenna use.
+ * Takes effect immediately.
+ * XXX tx antenna setting ignored
+ * XXX rx antenna setting should always be 3 (for now)
+ */
+static int
+mwl_hal_setantenna(struct mwl_softc *sc, MWL_HAL_ANTENNA dirSet, int ant)
+{
+	HostCmd_DS_802_11_RF_ANTENNA *pCmd;
+	int retval;
+
+	if (!(dirSet == WL_ANTENNATYPE_RX || dirSet == WL_ANTENNATYPE_TX))
+		return (EINVAL);
+
+	_CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_ANTENNA,
+	    HostCmd_CMD_802_11_RF_ANTENNA);
+	pCmd->Action = LE_16(dirSet);
+	if (ant == 0)			/* default to all/both antennae */
+		ant = 3;
+	pCmd->AntennaMode = LE_16(ant);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_802_11_RF_ANTENNA);
+	return (retval);
+}
+
+/*
+ * Configure radio.
+ * Takes effect immediately.
+ * XXX preamble installed after set fixed rate cmd
+ */
+static int
+mwl_hal_setradio(struct mwl_softc *sc, int onoff, MWL_HAL_PREAMBLE preamble)
+{
+	HostCmd_DS_802_11_RADIO_CONTROL *pCmd;
+	int retval;
+
+	_CMD_SETUP(pCmd, HostCmd_DS_802_11_RADIO_CONTROL,
+	    HostCmd_CMD_802_11_RADIO_CONTROL);
+	pCmd->Action = LE_16(HostCmd_ACT_GEN_SET);
+	if (onoff == 0)
+		pCmd->Control = 0;
+	else
+		pCmd->Control = LE_16(preamble);
+	pCmd->RadioOn = LE_16(onoff);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_802_11_RADIO_CONTROL);
+	return (retval);
+}
+
+static int
+mwl_hal_setwmm(struct mwl_softc *sc, int onoff)
+{
+	HostCmd_FW_SetWMMMode *pCmd;
+	int retval;
+
+	_CMD_SETUP(pCmd, HostCmd_FW_SetWMMMode,
+	    HostCmd_CMD_SET_WMM_MODE);
+	pCmd->Action = LE_16(onoff);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_WMM_MODE);
+	return (retval);
+}
+
+/*
+ * Convert public channel flags definition to a
+ * value suitable for feeding to the firmware.
+ * Note this includes byte swapping.
+ */
+static uint32_t
+cvtChannelFlags(const MWL_HAL_CHANNEL *chan)
+{
+	uint32_t w;
+
+	/*
+	 * NB: f/w only understands FREQ_BAND_5GHZ, supplying the more
+	 * precise band info causes it to lockup (sometimes).
+	 */
+	w = (chan->channelFlags.FreqBand == MWL_FREQ_BAND_2DOT4GHZ) ?
+	    FREQ_BAND_2DOT4GHZ : FREQ_BAND_5GHZ;
+	switch (chan->channelFlags.ChnlWidth) {
+	case MWL_CH_10_MHz_WIDTH:
+		w |= CH_10_MHz_WIDTH;
+		break;
+	case MWL_CH_20_MHz_WIDTH:
+		w |= CH_20_MHz_WIDTH;
+		break;
+	case MWL_CH_40_MHz_WIDTH:
+	default:
+		w |= CH_40_MHz_WIDTH;
+		break;
+	}
+	switch (chan->channelFlags.ExtChnlOffset) {
+	case MWL_EXT_CH_NONE:
+		w |= EXT_CH_NONE;
+		break;
+	case MWL_EXT_CH_ABOVE_CTRL_CH:
+		w |= EXT_CH_ABOVE_CTRL_CH;
+		break;
+	case MWL_EXT_CH_BELOW_CTRL_CH:
+		w |= EXT_CH_BELOW_CTRL_CH;
+		break;
+	}
+	return (LE_32(w));
+}
+
+static int
+mwl_hal_setchannel(struct mwl_softc *sc, const MWL_HAL_CHANNEL *chan)
+{
+	HostCmd_FW_SET_RF_CHANNEL *pCmd;
+	int retval;
+
+	_CMD_SETUP(pCmd, HostCmd_FW_SET_RF_CHANNEL, HostCmd_CMD_SET_RF_CHANNEL);
+	pCmd->Action = LE_16(HostCmd_ACT_GEN_SET);
+	pCmd->CurrentChannel = chan->channel;
+	pCmd->ChannelFlags = cvtChannelFlags(chan);	/* NB: byte-swapped */
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_RF_CHANNEL);
+	return (retval);
+}
+
+static int
+mwl_hal_settxpower(struct mwl_softc *sc,
+    const MWL_HAL_CHANNEL *c, uint8_t maxtxpow)
+{
+	HostCmd_DS_802_11_RF_TX_POWER *pCmd;
+	const struct mwl_hal_channel *hc;
+	int i = 0, retval;
+
+	hc = findhalchannel(sc, c);
+	if (hc == NULL) {
+		/* XXX temp while testing */
+		MWL_DBG(MWL_DBG_HW, "mwl: mwl_hal_settxpower(): "
+		    "no cal data for channel %u band %u width %u ext %u\n",
+		    c->channel, c->channelFlags.FreqBand,
+		    c->channelFlags.ChnlWidth, c->channelFlags.ExtChnlOffset);
+		return (EINVAL);
+	}
+
+	_CMD_SETUP(pCmd, HostCmd_DS_802_11_RF_TX_POWER,
+	    HostCmd_CMD_802_11_RF_TX_POWER);
+	pCmd->Action = LE_16(HostCmd_ACT_GEN_SET_LIST);
+	/* NB: 5Ghz cal data have the channel # in [0]; don't truncate */
+	if (c->channelFlags.FreqBand == MWL_FREQ_BAND_5GHZ)
+		pCmd->PowerLevelList[i++] = LE_16(hc->targetPowers[0]);
+	for (; i < 4; i++) {
+		uint16_t pow = hc->targetPowers[i];
+		if (pow > maxtxpow)
+			pow = maxtxpow;
+		pCmd->PowerLevelList[i] = LE_16(pow);
+	}
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_802_11_RF_TX_POWER);
+	return (retval);
+}
+
+#define	RATEVAL(r)	((r) &~ RATE_MCS)
+#define	RATETYPE(r)	(((r) & RATE_MCS) ? HT_RATE_TYPE : LEGACY_RATE_TYPE)
+
+static int
+mwl_hal_settxrate(struct mwl_softc *sc, MWL_HAL_TXRATE_HANDLING handling,
+	const MWL_HAL_TXRATE *rate)
+{
+	HostCmd_FW_USE_FIXED_RATE *pCmd;
+	FIXED_RATE_ENTRY *fp;
+	int retval, i, n;
+
+	_VCMD_SETUP(pCmd, HostCmd_FW_USE_FIXED_RATE,
+	    HostCmd_CMD_SET_FIXED_RATE);
+
+	pCmd->MulticastRate = RATEVAL(rate->McastRate);
+	pCmd->MultiRateTxType = RATETYPE(rate->McastRate);
+	/* NB: no rate type field */
+	pCmd->ManagementRate = RATEVAL(rate->MgtRate);
+	memset(pCmd->FixedRateTable, 0, sizeof (pCmd->FixedRateTable));
+	if (handling == RATE_FIXED) {
+		pCmd->Action = LE_32(HostCmd_ACT_GEN_SET);
+		pCmd->AllowRateDrop = LE_32(FIXED_RATE_WITHOUT_AUTORATE_DROP);
+		fp = pCmd->FixedRateTable;
+		fp->FixedRate =
+		    LE_32(RATEVAL(rate->RateSeries[0].Rate));
+		fp->FixRateTypeFlags.FixRateType =
+		    LE_32(RATETYPE(rate->RateSeries[0].Rate));
+		pCmd->EntryCount = LE_32(1);
+	} else if (handling == RATE_FIXED_DROP) {
+		pCmd->Action = LE_32(HostCmd_ACT_GEN_SET);
+		pCmd->AllowRateDrop = LE_32(FIXED_RATE_WITH_AUTO_RATE_DROP);
+		n = 0;
+		fp = pCmd->FixedRateTable;
+		for (i = 0; i < 4; i++) {
+			if (rate->RateSeries[0].TryCount == 0)
+				break;
+			fp->FixRateTypeFlags.FixRateType =
+			    LE_32(RATETYPE(rate->RateSeries[i].Rate));
+			fp->FixedRate =
+			    LE_32(RATEVAL(rate->RateSeries[i].Rate));
+			fp->FixRateTypeFlags.RetryCountValid =
+			    LE_32(RETRY_COUNT_VALID);
+			fp->RetryCount =
+			    LE_32(rate->RateSeries[i].TryCount-1);
+			n++;
+		}
+		pCmd->EntryCount = LE_32(n);
+	} else
+		pCmd->Action = LE_32(HostCmd_ACT_NOT_USE_FIXED_RATE);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_FIXED_RATE);
+	return (retval);
+}
+
+static int
+mwl_hal_settxrate_auto(struct mwl_softc *sc, const MWL_HAL_TXRATE *rate)
+{
+	HostCmd_FW_USE_FIXED_RATE *pCmd;
+	int retval;
+
+	_CMD_SETUP(pCmd, HostCmd_FW_USE_FIXED_RATE,
+	    HostCmd_CMD_SET_FIXED_RATE);
+
+	pCmd->MulticastRate = RATEVAL(rate->McastRate);
+	pCmd->MultiRateTxType = RATETYPE(rate->McastRate);
+	/* NB: no rate type field */
+	pCmd->ManagementRate = RATEVAL(rate->MgtRate);
+	memset(pCmd->FixedRateTable, 0, sizeof (pCmd->FixedRateTable));
+	pCmd->Action = LE_32(HostCmd_ACT_NOT_USE_FIXED_RATE);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_FIXED_RATE);
+	return (retval);
+}
+
+#undef RATEVAL
+#undef RATETYPE
+
+/* XXX 0 = indoor, 1 = outdoor */
+static int
+mwl_hal_setrateadaptmode(struct mwl_softc *sc, uint16_t mode)
+{
+	HostCmd_DS_SET_RATE_ADAPT_MODE *pCmd;
+	int retval;
+
+	_CMD_SETUP(pCmd, HostCmd_DS_SET_RATE_ADAPT_MODE,
+	    HostCmd_CMD_SET_RATE_ADAPT_MODE);
+	pCmd->Action = LE_16(HostCmd_ACT_GEN_SET);
+	pCmd->RateAdaptMode = LE_16(mode);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_RATE_ADAPT_MODE);
+	return (retval);
+}
+
+static int
+mwl_hal_setoptimizationlevel(struct mwl_softc *sc, int level)
+{
+	HostCmd_FW_SET_OPTIMIZATION_LEVEL *pCmd;
+	int retval;
+
+	_CMD_SETUP(pCmd, HostCmd_FW_SET_OPTIMIZATION_LEVEL,
+	    HostCmd_CMD_SET_OPTIMIZATION_LEVEL);
+	pCmd->OptLevel = (uint8_t)level;
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_OPTIMIZATION_LEVEL);
+	return (retval);
+}
+
+/*
+ * Set the region code that selects the radar bin'ing agorithm.
+ */
+static int
+mwl_hal_setregioncode(struct mwl_softc *sc, int regionCode)
+{
+	HostCmd_SET_REGIONCODE_INFO *pCmd;
+	int retval;
+
+	_CMD_SETUP(pCmd, HostCmd_SET_REGIONCODE_INFO,
+	    HostCmd_CMD_SET_REGION_CODE);
+	/* XXX map pseudo-codes to fw codes */
+	switch (regionCode) {
+	case DOMAIN_CODE_ETSI_131:
+		pCmd->regionCode = LE_16(DOMAIN_CODE_ETSI);
+		break;
+	default:
+		pCmd->regionCode = LE_16(regionCode);
+		break;
+	}
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_REGION_CODE);
+	return (retval);
+}
+
+static int
+mwl_hal_setassocid(struct mwl_softc *sc,
+	const uint8_t bssId[IEEE80211_ADDR_LEN], uint16_t assocId)
+{
+	HostCmd_FW_SET_AID *pCmd = (HostCmd_FW_SET_AID *) &sc->sc_cmd_mem[0];
+	int retval;
+
+	_VCMD_SETUP(pCmd, HostCmd_FW_SET_AID, HostCmd_CMD_SET_AID);
+	pCmd->AssocID = LE_16(assocId);
+	IEEE80211_ADDR_COPY(&pCmd->MacAddr[0], bssId);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_AID);
+	return (retval);
+}
+
+/*
+ * Inform firmware of tx rate parameters.  Called whenever
+ * user-settable params change and after a channel change.
+ */
+static int
+mwl_setrates(struct ieee80211com *ic)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)ic;
+	MWL_HAL_TXRATE rates;
+
+	const struct ieee80211_rateset *rs;
+	rs = &ic->ic_bss->in_rates;
+
+	/*
+	 * Update the h/w rate map.
+	 * NB: 0x80 for MCS is passed through unchanged
+	 */
+	memset(&rates, 0, sizeof (rates));
+	/* rate used to send management frames */
+	rates.MgtRate = rs->ir_rates[0] & IEEE80211_RATE_VAL;
+	/* rate used to send multicast frames */
+	rates.McastRate = rates.MgtRate;
+
+	return (mwl_hal_settxrate(sc, RATE_AUTO, &rates));
+}
+
+/*
+ * Set packet size threshold for implicit use of RTS.
+ * Takes effect immediately.
+ * XXX packet length > threshold =>'s RTS
+ */
+static int
+mwl_hal_setrtsthreshold(struct mwl_softc *sc, int threshold)
+{
+	HostCmd_DS_802_11_RTS_THSD *pCmd;
+	int retval;
+
+	_VCMD_SETUP(pCmd, HostCmd_DS_802_11_RTS_THSD,
+	    HostCmd_CMD_802_11_RTS_THSD);
+	pCmd->Action  = LE_16(HostCmd_ACT_GEN_SET);
+	pCmd->Threshold = LE_16(threshold);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_802_11_RTS_THSD);
+	return (retval);
+}
+
+static int
+mwl_hal_setcsmode(struct mwl_softc *sc, MWL_HAL_CSMODE csmode)
+{
+	HostCmd_DS_SET_LINKADAPT_CS_MODE *pCmd;
+	int retval;
+
+	_CMD_SETUP(pCmd, HostCmd_DS_SET_LINKADAPT_CS_MODE,
+	    HostCmd_CMD_SET_LINKADAPT_CS_MODE);
+	pCmd->Action = LE_16(HostCmd_ACT_GEN_SET);
+	pCmd->CSMode = LE_16(csmode);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_LINKADAPT_CS_MODE);
+	return (retval);
+}
+
+static int
+mwl_hal_setpromisc(struct mwl_softc *sc, int ena)
+{
+	uint32_t v;
+
+	v = mwl_ctl_read4(sc, MACREG_REG_PROMISCUOUS);
+	mwl_ctl_write4(sc, MACREG_REG_PROMISCUOUS, ena ? v | 1 : v & ~1);
+
+	return (0);
+}
+
+static int
+mwl_hal_start(struct mwl_softc *sc)
+{
+	HostCmd_DS_BSS_START *pCmd;
+	int retval;
+
+	_VCMD_SETUP(pCmd, HostCmd_DS_BSS_START, HostCmd_CMD_BSS_START);
+	pCmd->Enable = LE_32(HostCmd_ACT_GEN_ON);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_BSS_START);
+	return (retval);
+}
+
+/*
+ * Enable sta-mode operation (disables beacon frame xmit).
+ */
+static int
+mwl_hal_setinframode(struct mwl_softc *sc)
+{
+	HostCmd_FW_SET_INFRA_MODE *pCmd;
+	int retval;
+
+	_VCMD_SETUP(pCmd, HostCmd_FW_SET_INFRA_MODE,
+	    HostCmd_CMD_SET_INFRA_MODE);
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_SET_INFRA_MODE);
+	return (retval);
+}
+
+static int
+mwl_hal_stop(struct mwl_softc *sc)
+{
+	HostCmd_DS_BSS_START *pCmd;
+	int retval;
+
+	_VCMD_SETUP(pCmd, HostCmd_DS_BSS_START,
+	    HostCmd_CMD_BSS_START);
+	pCmd->Enable = LE_32(HostCmd_ACT_GEN_OFF);
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_BSS_START);
+
+	return (retval);
+}
+
+static int
+mwl_hal_keyset(struct mwl_softc *sc, const MWL_HAL_KEYVAL *kv,
+	const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+	HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY *pCmd;
+	int retval;
+
+	_VCMD_SETUP(pCmd, HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY,
+	    HostCmd_CMD_UPDATE_ENCRYPTION);
+	if (kv->keyFlags & (KEY_FLAG_TXGROUPKEY|KEY_FLAG_RXGROUPKEY))
+		pCmd->ActionType = LE_32(EncrActionTypeSetGroupKey);
+	else
+		pCmd->ActionType = LE_32(EncrActionTypeSetKey);
+	pCmd->KeyParam.Length = LE_16(sizeof (pCmd->KeyParam));
+	pCmd->KeyParam.KeyTypeId = LE_16(kv->keyTypeId);
+	pCmd->KeyParam.KeyInfo = LE_32(kv->keyFlags);
+	pCmd->KeyParam.KeyIndex = LE_32(kv->keyIndex);
+	/* NB: includes TKIP MIC keys */
+	(void) memcpy(&pCmd->KeyParam.Key, &kv->key, kv->keyLen);
+	switch (kv->keyTypeId) {
+	case KEY_TYPE_ID_WEP:
+		pCmd->KeyParam.KeyLen = LE_16(kv->keyLen);
+		break;
+	case KEY_TYPE_ID_TKIP:
+		pCmd->KeyParam.KeyLen = LE_16(sizeof (TKIP_TYPE_KEY));
+		pCmd->KeyParam.Key.TkipKey.TkipRsc.low =
+		    LE_16(kv->key.tkip.rsc.low);
+		pCmd->KeyParam.Key.TkipKey.TkipRsc.high =
+		    LE_32(kv->key.tkip.rsc.high);
+		pCmd->KeyParam.Key.TkipKey.TkipTsc.low =
+		    LE_16(kv->key.tkip.tsc.low);
+		pCmd->KeyParam.Key.TkipKey.TkipTsc.high =
+		    LE_32(kv->key.tkip.tsc.high);
+		break;
+	case KEY_TYPE_ID_AES:
+		pCmd->KeyParam.KeyLen = LE_16(sizeof (AES_TYPE_KEY));
+		break;
+	}
+#ifdef MWL_MBSS_SUPPORT
+	IEEE80211_ADDR_COPY(pCmd->KeyParam.Macaddr, mac);
+#else
+	IEEE80211_ADDR_COPY(pCmd->Macaddr, mac);
+#endif
+
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_UPDATE_ENCRYPTION);
+	return (retval);
+}
+
+static int
+mwl_hal_keyreset(struct mwl_softc *sc, const MWL_HAL_KEYVAL *kv,
+    const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+	HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY *pCmd;
+	int retval;
+
+	_VCMD_SETUP(pCmd, HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY,
+	    HostCmd_CMD_UPDATE_ENCRYPTION);
+	pCmd->ActionType = LE_16(EncrActionTypeRemoveKey);
+	pCmd->KeyParam.Length = LE_16(sizeof (pCmd->KeyParam));
+	pCmd->KeyParam.KeyTypeId = LE_16(kv->keyTypeId);
+	pCmd->KeyParam.KeyInfo = LE_32(kv->keyFlags);
+	pCmd->KeyParam.KeyIndex = LE_32(kv->keyIndex);
+#ifdef MWL_MBSS_SUPPORT
+	IEEE80211_ADDR_COPY(pCmd->KeyParam.Macaddr, mac);
+#else
+	IEEE80211_ADDR_COPY(pCmd->Macaddr, mac);
+#endif
+	retval = mwlExecuteCmd(sc, HostCmd_CMD_UPDATE_ENCRYPTION);
+	return (retval);
+}
+
+/* ARGSUSED */
+static struct ieee80211_node *
+mwl_node_alloc(struct ieee80211com *ic)
+{
+	struct mwl_node *mn;
+
+	mn = kmem_zalloc(sizeof (struct mwl_node), KM_SLEEP);
+	if (mn == NULL) {
+		/* XXX stat+msg */
+		MWL_DBG(MWL_DBG_MSG, "mwl: mwl_node_alloc(): "
+		    "alloc node failed\n");
+		return (NULL);
+	}
+	return (&mn->mn_node);
+}
+
+static void
+mwl_node_free(struct ieee80211_node *ni)
+{
+	struct ieee80211com *ic = ni->in_ic;
+	struct mwl_node *mn = MWL_NODE(ni);
+
+	if (mn->mn_staid != 0) {
+		// mwl_hal_delstation(mn->mn_hvap, vap->iv_myaddr);
+		// delstaid(sc, mn->mn_staid);
+		mn->mn_staid = 0;
+	}
+	ic->ic_node_cleanup(ni);
+	kmem_free(ni, sizeof (struct mwl_node));
+}
+
+/*
+ * Allocate a key cache slot for a unicast key.  The
+ * firmware handles key allocation and every station is
+ * guaranteed key space so we are always successful.
+ */
+static int
+mwl_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
+	ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
+{
+	if (k->wk_keyix != IEEE80211_KEYIX_NONE ||
+	    (k->wk_flags & IEEE80211_KEY_GROUP)) {
+		if (!(&ic->ic_nw_keys[0] <= k &&
+		    k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) {
+			/* should not happen */
+			MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_alloc(): "
+			    "bogus group key\n");
+			return (0);
+		}
+		/* give the caller what they requested */
+		*keyix = *rxkeyix = k - ic->ic_nw_keys;
+		MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_alloc(): "
+		    "alloc GROUP key keyix %x, rxkeyix %x\n",
+		    *keyix, *rxkeyix);
+	} else {
+		/*
+		 * Firmware handles key allocation.
+		 */
+		*keyix = *rxkeyix = 0;
+		MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_alloc(): "
+		    "reset key index in key allocation\n");
+	}
+
+	return (1);
+}
+
+/*
+ * Delete a key entry allocated by mwl_key_alloc.
+ */
+static int
+mwl_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)ic;
+	MWL_HAL_KEYVAL hk;
+	const uint8_t bcastaddr[IEEE80211_ADDR_LEN] =
+	    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+	memset(&hk, 0, sizeof (hk));
+	hk.keyIndex = k->wk_keyix;
+	switch (k->wk_cipher->ic_cipher) {
+	case IEEE80211_CIPHER_WEP:
+		hk.keyTypeId = KEY_TYPE_ID_WEP;
+		break;
+	case IEEE80211_CIPHER_TKIP:
+		hk.keyTypeId = KEY_TYPE_ID_TKIP;
+		break;
+	case IEEE80211_CIPHER_AES_CCM:
+		hk.keyTypeId = KEY_TYPE_ID_AES;
+		break;
+	default:
+		/* XXX should not happen */
+		MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_delete(): "
+		    "unknown cipher %d\n", k->wk_cipher->ic_cipher);
+		return (0);
+	}
+	return (mwl_hal_keyreset(sc, &hk, bcastaddr) == 0);
+}
+
+/*
+ * Set the key cache contents for the specified key.  Key cache
+ * slot(s) must already have been allocated by mwl_key_alloc.
+ */
+/* ARGSUSED */
+static int
+mwl_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
+	const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+#define	GRPXMIT	(IEEE80211_KEY_XMIT | IEEE80211_KEY_GROUP)
+/* NB: static wep keys are marked GROUP+tx/rx; GTK will be tx or rx */
+#define	IEEE80211_IS_STATICKEY(k) \
+	(((k)->wk_flags & (GRPXMIT|IEEE80211_KEY_RECV)) == \
+	(GRPXMIT|IEEE80211_KEY_RECV))
+	struct mwl_softc *sc = (struct mwl_softc *)ic;
+	const struct ieee80211_cipher *cip = k->wk_cipher;
+	const uint8_t *macaddr;
+	MWL_HAL_KEYVAL hk;
+
+	memset(&hk, 0, sizeof (hk));
+	hk.keyIndex = k->wk_keyix;
+	switch (cip->ic_cipher) {
+	case IEEE80211_CIPHER_WEP:
+		hk.keyTypeId = KEY_TYPE_ID_WEP;
+		hk.keyLen = k->wk_keylen;
+		if (k->wk_keyix == ic->ic_def_txkey)
+			hk.keyFlags = KEY_FLAG_WEP_TXKEY;
+		if (!IEEE80211_IS_STATICKEY(k)) {
+			/* NB: WEP is never used for the PTK */
+			(void) addgroupflags(&hk, k);
+		}
+		break;
+	case IEEE80211_CIPHER_TKIP:
+		hk.keyTypeId = KEY_TYPE_ID_TKIP;
+		hk.key.tkip.tsc.high = (uint32_t)(k->wk_keytsc >> 16);
+		hk.key.tkip.tsc.low = (uint16_t)k->wk_keytsc;
+		hk.keyFlags = KEY_FLAG_TSC_VALID | KEY_FLAG_MICKEY_VALID;
+		hk.keyLen = k->wk_keylen + IEEE80211_MICBUF_SIZE;
+		if (!addgroupflags(&hk, k))
+			hk.keyFlags |= KEY_FLAG_PAIRWISE;
+		break;
+	case IEEE80211_CIPHER_AES_CCM:
+		hk.keyTypeId = KEY_TYPE_ID_AES;
+		hk.keyLen = k->wk_keylen;
+		if (!addgroupflags(&hk, k))
+			hk.keyFlags |= KEY_FLAG_PAIRWISE;
+		break;
+	default:
+		/* XXX should not happen */
+		MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_key_set(): "
+		    "unknown cipher %d\n",
+		    k->wk_cipher->ic_cipher);
+		return (0);
+	}
+	/*
+	 * NB: tkip mic keys get copied here too; the layout
+	 * just happens to match that in ieee80211_key.
+	 */
+	(void) memcpy(hk.key.aes, k->wk_key, hk.keyLen);
+
+	/*
+	 * Locate address of sta db entry for writing key;
+	 * the convention unfortunately is somewhat different
+	 * than how net80211, hostapd, and wpa_supplicant think.
+	 */
+
+	/*
+	 * NB: keys plumbed before the sta reaches AUTH state
+	 * will be discarded or written to the wrong sta db
+	 * entry because iv_bss is meaningless.  This is ok
+	 * (right now) because we handle deferred plumbing of
+	 * WEP keys when the sta reaches AUTH state.
+	 */
+	macaddr = ic->ic_bss->in_bssid;
+	if (k->wk_flags & IEEE80211_KEY_XMIT) {
+		/* XXX plumb to local sta db too for static key wep */
+		(void) mwl_hal_keyset(sc, &hk, ic->ic_macaddr);
+	}
+	return (mwl_hal_keyset(sc, &hk, macaddr) == 0);
+#undef IEEE80211_IS_STATICKEY
+#undef GRPXMIT
+}
+
+/*
+ * Plumb any static WEP key for the station.  This is
+ * necessary as we must propagate the key from the
+ * global key table of the vap to each sta db entry.
+ */
+static void
+mwl_setanywepkey(struct ieee80211com *ic, const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+	if ((ic->ic_flags & (IEEE80211_F_PRIVACY|IEEE80211_F_WPA)) ==
+	    IEEE80211_F_PRIVACY &&
+	    ic->ic_def_txkey != IEEE80211_KEYIX_NONE &&
+	    ic->ic_nw_keys[ic->ic_def_txkey].wk_keyix != IEEE80211_KEYIX_NONE)
+		(void) mwl_key_set(ic, &ic->ic_nw_keys[ic->ic_def_txkey], mac);
+}
+
+static void
+mwl_setglobalkeys(struct ieee80211com *ic)
+{
+	struct ieee80211_key *wk;
+
+	wk = &ic->ic_nw_keys[0];
+	for (; wk < &ic->ic_nw_keys[IEEE80211_WEP_NKID]; wk++)
+		if (wk->wk_keyix != IEEE80211_KEYIX_NONE)
+			(void) mwl_key_set(ic, wk, ic->ic_macaddr);
+}
+
+static int
+addgroupflags(MWL_HAL_KEYVAL *hk, const struct ieee80211_key *k)
+{
+	if (k->wk_flags & IEEE80211_KEY_GROUP) {
+		if (k->wk_flags & IEEE80211_KEY_XMIT)
+			hk->keyFlags |= KEY_FLAG_TXGROUPKEY;
+		if (k->wk_flags & IEEE80211_KEY_RECV)
+			hk->keyFlags |= KEY_FLAG_RXGROUPKEY;
+		return (1);
+	} else
+		return (0);
+}
+
+/*
+ * Set/change channels.
+ */
+static int
+mwl_chan_set(struct mwl_softc *sc, struct mwl_channel *chan)
+{
+	MWL_HAL_CHANNEL hchan;
+	int maxtxpow;
+
+	MWL_DBG(MWL_DBG_HW, "mwl: mwl_chan_set(): "
+	    "chan %u MHz/flags 0x%x\n",
+	    chan->ic_freq, chan->ic_flags);
+
+	/*
+	 * Convert to a HAL channel description with
+	 * the flags constrained to reflect the current
+	 * operating mode.
+	 */
+	mwl_mapchan(&hchan, chan);
+	mwl_hal_intrset(sc, 0);		/* disable interrupts */
+
+	(void) mwl_hal_setchannel(sc, &hchan);
+	/*
+	 * Tx power is cap'd by the regulatory setting and
+	 * possibly a user-set limit.  We pass the min of
+	 * these to the hal to apply them to the cal data
+	 * for this channel.
+	 * XXX min bound?
+	 */
+	maxtxpow = 2 * chan->ic_maxregpower;
+	if (maxtxpow > 100)
+		maxtxpow = 100;
+	(void) mwl_hal_settxpower(sc, &hchan, maxtxpow / 2);
+	/* NB: potentially change mcast/mgt rates */
+	(void) mwl_setcurchanrates(sc);
+
+	sc->sc_curchan = hchan;
+	mwl_hal_intrset(sc, sc->sc_imask);
+
+	return (0);
+}
+
+/*
+ * Convert net80211 channel to a HAL channel.
+ */
+static void
+mwl_mapchan(MWL_HAL_CHANNEL *hc, const struct mwl_channel *chan)
+{
+	hc->channel = chan->ic_ieee;
+
+	*(uint32_t *)&hc->channelFlags = 0;
+	if (((chan)->ic_flags & IEEE80211_CHAN_2GHZ) != 0)
+		hc->channelFlags.FreqBand = MWL_FREQ_BAND_2DOT4GHZ;
+	else if (((chan)->ic_flags & IEEE80211_CHAN_5GHZ) != 0)
+		hc->channelFlags.FreqBand = MWL_FREQ_BAND_5GHZ;
+	if (((chan)->ic_flags & IEEE80211_CHAN_HT40) != 0) {
+		hc->channelFlags.ChnlWidth = MWL_CH_40_MHz_WIDTH;
+		if (((chan)->ic_flags & IEEE80211_CHAN_HT40U) != 0)
+			hc->channelFlags.ExtChnlOffset =
+			    MWL_EXT_CH_ABOVE_CTRL_CH;
+		else
+			hc->channelFlags.ExtChnlOffset =
+			    MWL_EXT_CH_BELOW_CTRL_CH;
+	} else
+		hc->channelFlags.ChnlWidth = MWL_CH_20_MHz_WIDTH;
+	/* XXX 10MHz channels */
+}
+
+/*
+ * Return the phy mode for with the specified channel.
+ */
+enum ieee80211_phymode
+mwl_chan2mode(const struct mwl_channel *chan)
+{
+
+	if (IEEE80211_IS_CHAN_HTA(chan))
+		return (IEEE80211_MODE_11NA);
+	else if (IEEE80211_IS_CHAN_HTG(chan))
+		return (IEEE80211_MODE_11NG);
+	else if (IEEE80211_IS_CHAN_108G(chan))
+		return (IEEE80211_MODE_TURBO_G);
+	else if (IEEE80211_IS_CHAN_ST(chan))
+		return (IEEE80211_MODE_STURBO_A);
+	else if (IEEE80211_IS_CHAN_TURBO(chan))
+		return (IEEE80211_MODE_TURBO_A);
+	else if (IEEE80211_IS_CHAN_HALF(chan))
+		return (IEEE80211_MODE_HALF);
+	else if (IEEE80211_IS_CHAN_QUARTER(chan))
+		return (IEEE80211_MODE_QUARTER);
+	else if (IEEE80211_IS_CHAN_A(chan))
+		return (IEEE80211_MODE_11A);
+	else if (IEEE80211_IS_CHAN_ANYG(chan))
+		return (IEEE80211_MODE_11G);
+	else if (IEEE80211_IS_CHAN_B(chan))
+		return (IEEE80211_MODE_11B);
+	else if (IEEE80211_IS_CHAN_FHSS(chan))
+		return (IEEE80211_MODE_FH);
+
+	/* NB: should not get here */
+	MWL_DBG(MWL_DBG_HW, "mwl: mwl_chan2mode(): "
+	    "cannot map channel to mode; freq %u flags 0x%x\n",
+	    chan->ic_freq, chan->ic_flags);
+	return (IEEE80211_MODE_11B);
+}
+
+/* XXX inline or eliminate? */
+const struct ieee80211_rateset *
+mwl_get_suprates(struct ieee80211com *ic, const struct mwl_channel *c)
+{
+	/* XXX does this work for 11ng basic rates? */
+	return (&ic->ic_sup_rates[mwl_chan2mode(c)]);
+}
+
+/*
+ * Inform firmware of tx rate parameters.
+ * Called after a channel change.
+ */
+static int
+mwl_setcurchanrates(struct mwl_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	const struct ieee80211_rateset *rs;
+	MWL_HAL_TXRATE rates;
+
+	memset(&rates, 0, sizeof (rates));
+	rs = mwl_get_suprates(ic, sc->sc_cur_chan);
+	/* rate used to send management frames */
+	rates.MgtRate = rs->ir_rates[0] & IEEE80211_RATE_VAL;
+	/* rate used to send multicast frames */
+	rates.McastRate = rates.MgtRate;
+
+	return (mwl_hal_settxrate_auto(sc, &rates));
+}
+
+static const struct mwl_hal_channel *
+findhalchannel(const struct mwl_softc *sc, const MWL_HAL_CHANNEL *c)
+{
+	const struct mwl_hal_channel *hc;
+	const MWL_HAL_CHANNELINFO *ci;
+	int chan = c->channel, i;
+
+	if (c->channelFlags.FreqBand == MWL_FREQ_BAND_2DOT4GHZ) {
+		i = chan - 1;
+		if (c->channelFlags.ChnlWidth == MWL_CH_40_MHz_WIDTH) {
+			ci = &sc->sc_40M;
+			if (c->channelFlags.ExtChnlOffset ==
+			    MWL_EXT_CH_BELOW_CTRL_CH)
+				i -= 4;
+		} else
+			ci = &sc->sc_20M;
+		/* 2.4G channel table is directly indexed */
+		hc = ((unsigned)i < ci->nchannels) ? &ci->channels[i] : NULL;
+	} else if (c->channelFlags.FreqBand == MWL_FREQ_BAND_5GHZ) {
+		if (c->channelFlags.ChnlWidth == MWL_CH_40_MHz_WIDTH) {
+			ci = &sc->sc_40M_5G;
+			if (c->channelFlags.ExtChnlOffset ==
+			    MWL_EXT_CH_BELOW_CTRL_CH)
+				chan -= 4;
+		} else
+			ci = &sc->sc_20M_5G;
+		/* 5GHz channel table is sparse and must be searched */
+		for (i = 0; i < ci->nchannels; i++)
+			if (ci->channels[i].ieee == chan)
+				break;
+		hc = (i < ci->nchannels) ? &ci->channels[i] : NULL;
+	} else
+		hc = NULL;
+	return (hc);
+}
+
+/*
+ * Map SKU+country code to region code for radar bin'ing.
+ */
+static int
+mwl_map2regioncode(const struct mwl_regdomain *rd)
+{
+	switch (rd->regdomain) {
+	case SKU_FCC:
+	case SKU_FCC3:
+		return (DOMAIN_CODE_FCC);
+	case SKU_CA:
+		return (DOMAIN_CODE_IC);
+	case SKU_ETSI:
+	case SKU_ETSI2:
+	case SKU_ETSI3:
+		if (rd->country == CTRY_SPAIN)
+			return (DOMAIN_CODE_SPAIN);
+		if (rd->country == CTRY_FRANCE || rd->country == CTRY_FRANCE2)
+			return (DOMAIN_CODE_FRANCE);
+		/* XXX force 1.3.1 radar type */
+		return (DOMAIN_CODE_ETSI_131);
+	case SKU_JAPAN:
+		return (DOMAIN_CODE_MKK);
+	case SKU_ROW:
+		return (DOMAIN_CODE_DGT);	/* Taiwan */
+	case SKU_APAC:
+	case SKU_APAC2:
+	case SKU_APAC3:
+		return (DOMAIN_CODE_AUS);	/* Australia */
+	}
+	/* XXX KOREA? */
+	return (DOMAIN_CODE_FCC);			/* XXX? */
+}
+
+/*
+ * Setup the rx data structures.  This should only be
+ * done once or we may get out of sync with the firmware.
+ */
+static int
+mwl_startrecv(struct mwl_softc *sc)
+{
+	struct mwl_rx_ring *ring;
+	struct mwl_rxdesc *ds;
+	struct mwl_rxbuf *bf, *prev;
+
+	int i;
+
+	ring = &sc->sc_rxring;
+	bf = ring->buf;
+
+	prev = NULL;
+	for (i = 0; i < MWL_RX_RING_COUNT; i++, bf++) {
+		ds = bf->bf_desc;
+		/*
+		 * NB: DMA buffer contents is known to be unmodified
+		 * so there's no need to flush the data cache.
+		 */
+
+		/*
+		 * Setup descriptor.
+		 */
+		ds->QosCtrl = 0;
+		ds->RSSI = 0;
+		ds->Status = EAGLE_RXD_STATUS_IDLE;
+		ds->Channel = 0;
+		ds->PktLen = LE_16(MWL_AGGR_SIZE);
+		ds->SQ2 = 0;
+		ds->pPhysBuffData = LE_32(bf->bf_baddr);
+		/* NB: don't touch pPhysNext, set once */
+		ds->RxControl = EAGLE_RXD_CTRL_DRIVER_OWN;
+
+		(void) ddi_dma_sync(ring->rxdesc_dma.dma_hdl,
+		    i * sizeof (struct mwl_rxdesc),
+		    sizeof (struct mwl_rxdesc),
+		    DDI_DMA_SYNC_FORDEV);
+
+		if (prev != NULL) {
+			ds = prev->bf_desc;
+			ds->pPhysNext = LE_32(bf->bf_daddr);
+		}
+		prev = bf;
+	}
+
+	if (prev != NULL) {
+		ds = prev->bf_desc;
+		ds->pPhysNext = ring->physaddr;
+	}
+
+	/* set filters, etc. */
+	(void) mwl_mode_init(sc);
+
+	return (0);
+}
+
+static int
+mwl_mode_init(struct mwl_softc *sc)
+{
+	/*
+	 * NB: Ignore promisc in hostap mode; it's set by the
+	 * bridge.  This is wrong but we have no way to
+	 * identify internal requests (from the bridge)
+	 * versus external requests such as for tcpdump.
+	 */
+	/* mwl_setmcastfilter - not support now */
+	(void) mwl_hal_setpromisc(sc, 0);
+
+	return (0);
+}
+
+/*
+ * Kick the firmware to tell it there are new tx descriptors
+ * for processing.  The driver says what h/w q has work in
+ * case the f/w ever gets smarter.
+ */
+/* ARGSUSED */
+static void
+mwl_hal_txstart(struct mwl_softc *sc, int qnum)
+{
+
+	mwl_ctl_write4(sc, MACREG_REG_H2A_INTERRUPT_EVENTS,
+	    MACREG_H2ARIC_BIT_PPA_READY);
+	(void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
+}
+
+static int
+mwl_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)ic;
+	struct mwl_tx_ring *ring;
+	struct mwl_txdesc *ds;
+	struct mwl_txbuf *bf;
+	struct ieee80211_frame *wh, *wh1;
+	struct ieee80211_node *ni = NULL;
+
+	int err, off;
+	int mblen, pktlen, hdrlen;
+	mblk_t *m, *m0;
+	uint8_t *addr_4, *txbuf;
+	uint16_t *pfwlen;
+
+	MWL_TXLOCK(sc);
+
+	err = DDI_SUCCESS;
+	if (!MWL_IS_RUNNING(sc) || MWL_IS_SUSPEND(sc)) {
+		err = ENXIO;
+		goto fail1;
+	}
+
+	ring = &sc->sc_txring[1];
+	if (ring->queued > 15) {
+		MWL_DBG(MWL_DBG_TX, "mwl: mwl_send(): "
+		    "no txbuf, %d\n", ring->queued);
+		sc->sc_need_sched = 1;
+		sc->sc_tx_nobuf++;
+		err = ENOMEM;
+		goto fail1;
+	}
+
+	m = allocb(msgdsize(mp) + 32, BPRI_MED);
+	if (m == NULL) {
+		MWL_DBG(MWL_DBG_TX, "mwl: mwl_send():"
+		    "can't alloc mblk.\n");
+		err = DDI_FAILURE;
+		goto fail1;
+	}
+
+	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
+		mblen = MBLKL(m0);
+		(void) bcopy(m0->b_rptr, m->b_rptr + off, mblen);
+		off += mblen;
+	}
+	m->b_wptr += off;
+
+	wh = (struct ieee80211_frame *)m->b_rptr;
+	ni = ieee80211_find_txnode(ic, wh->i_addr1);
+	if (ni == NULL) {
+		err = DDI_FAILURE;
+		sc->sc_tx_err++;
+		goto fail2;
+	}
+
+	hdrlen = sizeof (*wh);
+	pktlen = msgdsize(m);
+
+	(void) ieee80211_encap(ic, m, ni);
+
+	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+		const struct ieee80211_cipher *cip;
+		struct ieee80211_key *k;
+		k = ieee80211_crypto_encap(ic, m);
+		if (k == NULL) {
+			sc->sc_tx_err++;
+			err = DDI_FAILURE;
+			goto fail3;
+		}
+
+		/*
+		 * Adjust the packet length for the crypto additions
+		 * done during encap and any other bits that the f/w
+		 * will add later on.
+		 */
+		cip = k->wk_cipher;
+		pktlen += cip->ic_header + cip->ic_miclen + cip->ic_trailer;
+		/* packet header may have moved, reset our local pointer */
+		wh = (struct ieee80211_frame *)m->b_rptr;
+	}
+
+	ds = &ring->desc[ring->cur];
+	bf = &ring->buf[ring->cur];
+
+	bf->bf_node = ieee80211_ref_node(ni);
+	txbuf = (uint8_t *)bf->bf_mem;
+
+	/*
+	 * inject FW specific fields into the 802.11 frame
+	 *
+	 *  2   bytes FW len (inject)
+	 *  24 bytes 802.11 frame header
+	 *  6   bytes addr4 (inject)
+	 *  n   bytes 802.11 frame body
+	 */
+	pfwlen = (uint16_t *)txbuf;
+	*pfwlen = pktlen - hdrlen;
+	wh1 = (struct ieee80211_frame *)(txbuf + 2);
+	bcopy(wh, wh1, sizeof (struct ieee80211_frame));
+	addr_4 = txbuf + (sizeof (struct ieee80211_frame) + sizeof (uint16_t));
+	(void) memset(addr_4, 0, 6);
+	bcopy(m->b_rptr + sizeof (struct ieee80211_frame), txbuf + 32, *pfwlen);
+	pktlen += 8;
+
+	(void) ddi_dma_sync(bf->txbuf_dma.dma_hdl,
+	    0,
+	    pktlen,
+	    DDI_DMA_SYNC_FORDEV);
+
+	ds->QosCtrl = 0;
+	ds->PktLen = (uint16_t)pktlen;
+	ds->PktPtr = bf->bf_baddr;
+	ds->Status = LE_32(EAGLE_TXD_STATUS_FW_OWNED);
+	ds->Format = 0;
+	ds->pad = 0;
+	ds->ack_wcb_addr = 0;
+	ds->TxPriority = 1;
+
+	MWL_DBG(MWL_DBG_TX, "mwl: mwl_send(): "
+	    "tx desc Status %x, DataRate %x, TxPriority %x, QosCtrl %x, "
+	    "PktLen %x, SapPktInfo %x, Format %x, Pad %x, ack_wcb_addr %x\n",
+	    ds->Status, ds->DataRate, ds->TxPriority, ds->QosCtrl, ds->PktLen,
+	    ds->SapPktInfo, ds->Format, ds->pad, ds->ack_wcb_addr);
+
+	(void) ddi_dma_sync(ring->txdesc_dma.dma_hdl,
+	    ring->cur * sizeof (struct mwl_txdesc),
+	    sizeof (struct mwl_txdesc),
+	    DDI_DMA_SYNC_FORDEV);
+
+	MWL_DBG(MWL_DBG_TX, "mwl: mwl_send(): "
+	    "pktlen = %u, slot = %u, queued = %x\n",
+	    mblen, ring->cur, ring->queued);
+
+	ring->queued++;
+	ring->cur = (ring->cur + 1) % MWL_TX_RING_COUNT;
+
+	/*
+	 * NB: We don't need to lock against tx done because
+	 * this just prods the firmware to check the transmit
+	 * descriptors.  The firmware will also start fetching
+	 * descriptors by itself if it notices new ones are
+	 * present when it goes to deliver a tx done interrupt
+	 * to the host. So if we race with tx done processing
+	 * it's ok.  Delivering the kick here rather than in
+	 * mwl_tx_start is an optimization to avoid poking the
+	 * firmware for each packet.
+	 *
+	 * NB: the queue id isn't used so 0 is ok.
+	 */
+	mwl_hal_txstart(sc, 0);
+
+	ic->ic_stats.is_tx_frags++;
+	ic->ic_stats.is_tx_bytes += pktlen;
+
+fail3:
+	ieee80211_free_node(ni);
+fail2:
+	freemsg(m);
+fail1:
+	if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA ||
+	    err == DDI_SUCCESS)
+		freemsg(mp);
+	MWL_TXUNLOCK(sc);
+	return (err);
+}
+
+/*
+ * This function is called periodically (every 200ms) during scanning to
+ * switch from one channel to another.
+ */
+static void
+mwl_next_scan(void *arg)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)arg;
+	struct ieee80211com *ic = &sc->sc_ic;
+
+	if (ic->ic_state == IEEE80211_S_SCAN)
+		(void) ieee80211_next_scan(ic);
+
+	sc->sc_scan_id = 0;
+}
+
+/*
+ * Convert a legacy rate set to a firmware bitmask.
+ */
+static uint32_t
+get_rate_bitmap(const struct ieee80211_rateset *rs)
+{
+	uint32_t rates;
+	int i;
+
+	rates = 0;
+	for (i = 0; i < rs->ir_nrates; i++)
+		switch (rs->ir_rates[i] & IEEE80211_RATE_VAL) {
+		case 2:	  rates |= 0x001; break;
+		case 4:	  rates |= 0x002; break;
+		case 11:  rates |= 0x004; break;
+		case 22:  rates |= 0x008; break;
+		case 44:  rates |= 0x010; break;
+		case 12:  rates |= 0x020; break;
+		case 18:  rates |= 0x040; break;
+		case 24:  rates |= 0x080; break;
+		case 36:  rates |= 0x100; break;
+		case 48:  rates |= 0x200; break;
+		case 72:  rates |= 0x400; break;
+		case 96:  rates |= 0x800; break;
+		case 108: rates |= 0x1000; break;
+		}
+	return (rates);
+}
+
+/*
+ * Craft station database entry for station.
+ * NB: use host byte order here, the hal handles byte swapping.
+ */
+static MWL_HAL_PEERINFO *
+mkpeerinfo(MWL_HAL_PEERINFO *pi, const struct ieee80211_node *ni)
+{
+	memset(pi, 0, sizeof (*pi));
+	pi->LegacyRateBitMap = get_rate_bitmap(&ni->in_rates);
+	pi->CapInfo = ni->in_capinfo;
+	return (pi);
+}
+
+static int
+mwl_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)ic;
+	enum ieee80211_state ostate;
+	struct ieee80211_channel *ic_chan;
+	struct ieee80211_node *ni = NULL;
+	MWL_HAL_PEERINFO pi;
+	uint32_t chan;
+
+	if (sc->sc_scan_id != 0) {
+		(void) untimeout(sc->sc_scan_id);
+		sc->sc_scan_id = 0;
+	}
+
+	MWL_GLOCK(sc);
+
+	ostate = ic->ic_state;
+	MWL_DBG(MWL_DBG_MSG, "mwl: mwl_newstate(): "
+	    "ostate %x -> nstate %x\n",
+	    ostate, nstate);
+
+	switch (nstate) {
+	case IEEE80211_S_INIT:
+		break;
+	case IEEE80211_S_SCAN:
+		if (ostate != IEEE80211_S_INIT) {
+			ic_chan = ic->ic_curchan;
+			chan = ieee80211_chan2ieee(ic, ic_chan);
+			if (chan != 0 && chan != IEEE80211_CHAN_ANY) {
+				sc->sc_cur_chan =
+				    &sc->sc_channels[3 * chan - 2];
+				MWL_DBG(MWL_DBG_MSG, "mwl: mwl_newstate(): "
+				    "chan num is %u, sc chan is %u\n",
+				    chan, sc->sc_cur_chan->ic_ieee);
+				(void) mwl_chan_set(sc, sc->sc_cur_chan);
+			}
+		}
+		sc->sc_scan_id = timeout(mwl_next_scan, (void *)sc,
+		    drv_usectohz(250000));
+		break;
+	case IEEE80211_S_AUTH:
+		ic_chan = ic->ic_curchan;
+		chan = ieee80211_chan2ieee(ic, ic_chan);
+		sc->sc_cur_chan = &sc->sc_channels[3 * chan - 2];
+		MWL_DBG(MWL_DBG_MSG, "mwl: mwl_newstate(): "
+		    "chan num is %u, sc chan is %u\n",
+		    chan, sc->sc_cur_chan->ic_ieee);
+		(void) mwl_chan_set(sc, sc->sc_cur_chan);
+		ni = ic->ic_bss;
+		(void) mwl_hal_newstation(sc, ic->ic_macaddr, 0, 0, NULL, 0, 0);
+		mwl_setanywepkey(ic, ni->in_macaddr);
+		break;
+	case IEEE80211_S_ASSOC:
+		break;
+	case IEEE80211_S_RUN:
+		ni = ic->ic_bss;
+		(void) mwl_hal_newstation(sc,
+		    ic->ic_macaddr, 0, 0, mkpeerinfo(&pi, ni), 0, 0);
+		mwl_setglobalkeys(ic);
+		(void) mwl_hal_setassocid(sc,
+		    ic->ic_bss->in_bssid, ic->ic_bss->in_associd);
+		(void) mwl_setrates(ic);
+		(void) mwl_hal_setrtsthreshold(sc, ic->ic_rtsthreshold);
+		(void) mwl_hal_setcsmode(sc, CSMODE_AUTO_ENA);
+		break;
+	default:
+		break;
+	}
+
+	MWL_GUNLOCK(sc);
+
+	return (sc->sc_newstate(ic, nstate, arg));
+}
+
+/*
+ * Set the interrupt mask.
+ */
+static void
+mwl_hal_intrset(struct mwl_softc *sc, uint32_t mask)
+{
+	mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_MASK, 0);
+	(void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
+
+	sc->sc_hal_imask = mask;
+	mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_MASK, mask);
+	(void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
+}
+
+/*
+ * Return the current ISR setting and clear the cause.
+ */
+static void
+mwl_hal_getisr(struct mwl_softc *sc, uint32_t *status)
+{
+	uint32_t cause;
+
+	cause = mwl_ctl_read4(sc, MACREG_REG_A2H_INTERRUPT_CAUSE);
+	if (cause == 0xffffffff) {	/* card removed */
+		cause = 0;
+	} else if (cause != 0) {
+		/* clear cause bits */
+		mwl_ctl_write4(sc, MACREG_REG_A2H_INTERRUPT_CAUSE,
+		    cause & ~sc->sc_hal_imask);
+		(void) mwl_ctl_read4(sc, MACREG_REG_INT_CODE);
+		cause &= sc->sc_hal_imask;
+	}
+	*status = cause;
+}
+
+static void
+mwl_tx_intr(struct mwl_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct mwl_tx_ring *ring;
+	struct mwl_txdesc *ds;
+
+	uint32_t status;
+
+	MWL_TXLOCK(sc);
+
+	ring = &sc->sc_txring[1];
+
+	if (!(ring->queued)) {
+		MWL_TXUNLOCK(sc);
+		return;
+	}
+
+	(void) ddi_dma_sync(ring->txdesc_dma.dma_hdl,
+	    0,
+	    ring->txdesc_dma.alength,
+	    DDI_DMA_SYNC_FORCPU);
+
+	for (;;) {
+		ds = &ring->desc[ring->next];
+
+		status = LE_32(ds->Status);
+
+		if (status & LE_32(EAGLE_TXD_STATUS_FW_OWNED)) {
+			break;
+		}
+
+		if (status == LE_32(EAGLE_TXD_STATUS_IDLE)) {
+			break;
+		}
+
+		MWL_DBG(MWL_DBG_TX, "mwl: mwl_tx_intr(): "
+		    "recv tx desc status %x, datarate %x, txpriority %x, "
+		    "QosCtrl %x, pktLen %x, SapPktInfo %x, Format %x, "
+		    "pad %x, ack_wcb_addr %x\n",
+		    ds->Status, ds->DataRate, ds->TxPriority,
+		    ds->QosCtrl, ds->PktLen, ds->SapPktInfo,
+		    ds->Format, ds->pad, ds->ack_wcb_addr);
+
+		/* descriptor is no longer valid */
+		ds->Status = LE_32(EAGLE_TXD_STATUS_IDLE);
+
+		(void) ddi_dma_sync(ring->txdesc_dma.dma_hdl,
+		    ring->next * sizeof (struct mwl_txdesc),
+		    sizeof (struct mwl_txdesc),
+		    DDI_DMA_SYNC_FORDEV);
+
+		ring->queued--;
+		ring->next = (ring->next + 1) % MWL_TX_RING_COUNT;
+		MWL_DBG(MWL_DBG_TX, "mwl: mwl_tx_intr(): "
+		    " tx done idx=%u, queued= %d\n",
+		    ring->next, ring->queued);
+
+		if (sc->sc_need_sched &&
+		    (ring->queued < MWL_TX_RING_COUNT)) {
+			sc->sc_need_sched = 0;
+			mac_tx_update(ic->ic_mach);
+		}
+
+	}
+
+	MWL_TXUNLOCK(sc);
+}
+
+/*
+ * Convert hardware signal strength to rssi.  The value
+ * provided by the device has the noise floor added in;
+ * we need to compensate for this but we don't have that
+ * so we use a fixed value.
+ *
+ * The offset of 8 is good for both 2.4 and 5GHz.  The LNA
+ * offset is already set as part of the initial gain.  This
+ * will give at least +/- 3dB for 2.4GHz and +/- 5dB for 5GHz.
+ */
+static int
+cvtrssi(uint8_t ssi)
+{
+	int rssi = (int)ssi + 8;
+	/* XXX hack guess until we have a real noise floor */
+	rssi = 2 * (87 - rssi);	/* NB: .5 dBm units */
+	return (rssi < 0 ? 0 : rssi > 127 ? 127 : rssi);
+}
+
+static void
+mwl_rx_intr(struct mwl_softc *sc)
+{
+	struct ieee80211com	*ic = &sc->sc_ic;
+	struct mwl_rx_ring *ring;
+	struct ieee80211_node	*ni;
+	struct ieee80211_frame *wh;
+
+	struct mwl_rxbuf *bf;
+	struct mwl_rxdesc *ds;
+	mblk_t	*mp0;
+
+	int ntodo, len, rssi;
+	uint8_t *data, status;
+
+	MWL_RXLOCK(sc);
+
+	ring = &sc->sc_rxring;
+	for (ntodo = MWL_RX_RING_COUNT; ntodo > 0; ntodo--) {
+		bf = &ring->buf[ring->cur];
+		ds = bf->bf_desc;
+		data = bf->bf_mem;
+
+		(void) ddi_dma_sync(ring->rxdesc_dma.dma_hdl,
+		    ring->cur * sizeof (struct mwl_rxdesc),
+		    sizeof (struct mwl_rxdesc),
+		    DDI_DMA_SYNC_FORCPU);
+
+		if (ds->RxControl != EAGLE_RXD_CTRL_DMA_OWN)
+			break;
+
+		status = ds->Status;
+		if (status & EAGLE_RXD_STATUS_DECRYPT_ERR_MASK) {
+			MWL_DBG(MWL_DBG_CRYPTO, "mwl: mwl_rx_intr(): "
+			    "rx decrypt error\n");
+			sc->sc_rx_err++;
+		}
+
+		/*
+		 * Sync the data buffer.
+		 */
+		len = LE_16(ds->PktLen);
+
+		(void) ddi_dma_sync(bf->rxbuf_dma.dma_hdl,
+		    0,
+		    bf->rxbuf_dma.alength,
+		    DDI_DMA_SYNC_FORCPU);
+
+		if (len < 32 || len > sc->sc_dmabuf_size) {
+			MWL_DBG(MWL_DBG_RX, "mwl: mwl_rx_intr(): "
+			    "packet len error %d\n", len);
+			sc->sc_rx_err++;
+			goto rxnext;
+		}
+
+		mp0 = allocb(sc->sc_dmabuf_size, BPRI_MED);
+		if (mp0 == NULL) {
+			MWL_DBG(MWL_DBG_RX, "mwl: mwl_rx_intr(): "
+			    "alloc mblk error\n");
+			sc->sc_rx_nobuf++;
+			goto rxnext;
+		}
+		bcopy(data+ 2, mp0->b_wptr, 24);
+		mp0->b_wptr += 24;
+		bcopy(data + 32, mp0->b_wptr, len - 32);
+		mp0->b_wptr += (len - 32);
+
+		wh = (struct ieee80211_frame *)mp0->b_rptr;
+		if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
+		    IEEE80211_FC0_TYPE_CTL) {
+			freemsg(mp0);
+			goto rxnext;
+		}
+
+		/*
+		 * The f/w strips WEP header but doesn't clear
+		 * the WEP bit; mark the packet with M_WEP so
+		 * net80211 will treat the data as decrypted.
+		 * While here also clear the PWR_MGT bit since
+		 * power save is handled by the firmware and
+		 * passing this up will potentially cause the
+		 * upper layer to put a station in power save
+		 * (except when configured with MWL_HOST_PS_SUPPORT).
+		 */
+#ifdef MWL_HOST_PS_SUPPORT
+		wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+#else
+		wh->i_fc[1] &= ~(IEEE80211_FC1_WEP | IEEE80211_FC1_PWR_MGT);
+#endif
+
+		/* calculate rssi early so we can re-use for each aggregate */
+		rssi = cvtrssi(ds->RSSI);
+
+		ni = ieee80211_find_rxnode(ic, wh);
+
+		/* send the frame to the 802.11 layer */
+		(void) ieee80211_input(ic, mp0, ni, rssi, 0);
+		ieee80211_free_node(ni);
+rxnext:
+		/*
+		 * Setup descriptor.
+		 */
+		ds->QosCtrl = 0;
+		ds->RSSI = 0;
+		ds->Status = EAGLE_RXD_STATUS_IDLE;
+		ds->Channel = 0;
+		ds->PktLen = LE_16(MWL_AGGR_SIZE);
+		ds->SQ2 = 0;
+		ds->pPhysBuffData = bf->bf_baddr;
+		/* NB: don't touch pPhysNext, set once */
+		ds->RxControl = EAGLE_RXD_CTRL_DRIVER_OWN;
+
+		(void) ddi_dma_sync(ring->rxdesc_dma.dma_hdl,
+		    ring->cur * sizeof (struct mwl_rxdesc),
+		    sizeof (struct mwl_rxdesc),
+		    DDI_DMA_SYNC_FORDEV);
+
+		/* NB: ignore ENOMEM so we process more descriptors */
+		ring->cur = (ring->cur + 1) % MWL_RX_RING_COUNT;
+	}
+
+	MWL_RXUNLOCK(sc);
+}
+
+/*ARGSUSED*/
+static uint_t
+mwl_softintr(caddr_t data, caddr_t unused)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)data;
+
+	/*
+	 * Check if the soft interrupt is triggered by another
+	 * driver at the same level.
+	 */
+	MWL_GLOCK(sc);
+	if (sc->sc_rx_pend) {
+		sc->sc_rx_pend = 0;
+		MWL_GUNLOCK(sc);
+		mwl_rx_intr(sc);
+		return (DDI_INTR_CLAIMED);
+	}
+	MWL_GUNLOCK(sc);
+
+	return (DDI_INTR_UNCLAIMED);
+}
+
+/*ARGSUSED*/
+static uint_t
+mwl_intr(caddr_t arg, caddr_t unused)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)arg;
+	uint32_t status;
+
+	MWL_GLOCK(sc);
+
+	if (!MWL_IS_RUNNING(sc) || MWL_IS_SUSPEND(sc)) {
+		MWL_GUNLOCK(sc);
+		return (DDI_INTR_UNCLAIMED);
+	}
+
+	/*
+	 * Figure out the reason(s) for the interrupt.
+	 */
+	mwl_hal_getisr(sc, &status);		/* NB: clears ISR too */
+	if (status == 0) {
+		MWL_GUNLOCK(sc);
+		return (DDI_INTR_UNCLAIMED);
+	}
+
+	if (status & MACREG_A2HRIC_BIT_RX_RDY) {
+		sc->sc_rx_pend = 1;
+		(void) ddi_intr_trigger_softint(sc->sc_softintr_hdl, NULL);
+	}
+	if (status & MACREG_A2HRIC_BIT_TX_DONE) {
+		mwl_tx_intr(sc);
+	}
+	if (status & MACREG_A2HRIC_BIT_BA_WATCHDOG) {
+		MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
+		    "ba watchdog\n");
+	}
+	if (status & MACREG_A2HRIC_BIT_OPC_DONE) {
+		MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
+		    "opc done\n");
+	}
+	if (status & MACREG_A2HRIC_BIT_MAC_EVENT) {
+		MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
+		    "mac event\n");
+	}
+	if (status & MACREG_A2HRIC_BIT_ICV_ERROR) {
+		MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
+		    "ICV error\n");
+	}
+	if (status & MACREG_A2HRIC_BIT_QUEUE_EMPTY) {
+		MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
+		    "queue empty\n");
+	}
+	if (status & MACREG_A2HRIC_BIT_QUEUE_FULL) {
+		MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
+		    "queue full\n");
+	}
+	if (status & MACREG_A2HRIC_BIT_RADAR_DETECT) {
+		MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
+		    "radar detect\n");
+	}
+	if (status & MACREG_A2HRIC_BIT_CHAN_SWITCH) {
+		MWL_DBG(MWL_DBG_INTR, "mwl: mwl_intr(): "
+		    "chan switch\n");
+	}
+
+	MWL_GUNLOCK(sc);
+
+	return (DDI_INTR_CLAIMED);
+}
+
+static int
+mwl_init(struct mwl_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	int err = 0;
+
+	mwl_hal_intrset(sc, 0);
+
+	sc->sc_txantenna = 0;		/* h/w default */
+	sc->sc_rxantenna = 0;		/* h/w default */
+
+	err = mwl_hal_setantenna(sc, WL_ANTENNATYPE_RX, sc->sc_rxantenna);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_HW, "mwl: mwl_init(): "
+		    "could not set rx antenna\n");
+		goto fail;
+	}
+
+	err = mwl_hal_setantenna(sc, WL_ANTENNATYPE_TX, sc->sc_txantenna);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_HW, "mwl: init(): "
+		    "could not set tx antenna\n");
+		goto fail;
+	}
+
+	err = mwl_hal_setradio(sc, 1, WL_AUTO_PREAMBLE);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_HW, "mwl: init(): "
+		    "could not set radio\n");
+		goto fail;
+	}
+
+	err = mwl_hal_setwmm(sc, (ic->ic_flags & IEEE80211_F_WME) != 0);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_HW, "mwl: init(): "
+		    "could not set wme\n");
+		goto fail;
+	}
+
+	/* select default channel */
+	ic->ic_ibss_chan = &ic->ic_sup_channels[0];
+	ic->ic_curchan = ic->ic_ibss_chan;
+	sc->sc_cur_chan = &sc->sc_channels[1];
+
+	err = mwl_chan_set(sc, sc->sc_cur_chan);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_HW, "mwl: init(): "
+		    "could not set wme\n");
+		goto fail;
+	}
+
+	err = mwl_hal_setrateadaptmode(sc, 0);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_HW, "mwl: init(): "
+		    "could not set rate adapt mode\n");
+		goto fail;
+	}
+
+	err = mwl_hal_setoptimizationlevel(sc,
+	    (ic->ic_flags & IEEE80211_F_BURST) != 0);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_HW, "mwl: init(): "
+		    "could not set optimization level\n");
+		goto fail;
+	}
+
+	err = mwl_hal_setregioncode(sc, mwl_map2regioncode(&sc->sc_regdomain));
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_HW, "mwl: init(): "
+		    "could not set regioncode\n");
+		goto fail;
+	}
+
+	err = mwl_startrecv(sc);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_HW, "mwl: init(): "
+		    "could not set start recv logic\n");
+		goto fail;
+	}
+
+	/*
+	 * Enable interrupts.
+	 */
+	sc->sc_imask = MACREG_A2HRIC_BIT_RX_RDY
+	    | MACREG_A2HRIC_BIT_TX_DONE
+	    | MACREG_A2HRIC_BIT_OPC_DONE
+	    | MACREG_A2HRIC_BIT_ICV_ERROR
+	    | MACREG_A2HRIC_BIT_RADAR_DETECT
+	    | MACREG_A2HRIC_BIT_CHAN_SWITCH
+	    | MACREG_A2HRIC_BIT_BA_WATCHDOG
+	    | MACREQ_A2HRIC_BIT_TX_ACK;
+
+	mwl_hal_intrset(sc, sc->sc_imask);
+
+	err = mwl_hal_start(sc);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_HW, "mwl: init(): "
+		    "could not get hal start\n");
+		goto fail;
+	}
+
+	err = mwl_hal_setinframode(sc);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_HW, "mwl: init(): "
+		    "could not set infra mode\n");
+		goto fail;
+	}
+
+fail:
+	return (err);
+}
+
+static int
+mwl_resume(struct mwl_softc *sc)
+{
+	int qid, err = 0;
+
+	err = mwl_fwload(sc, NULL);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
+		    "failed to load fw\n");
+		goto fail;
+	}
+
+	err = mwl_gethwspecs(sc);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
+		    "failed to get hw spec\n");
+		goto fail;
+	}
+
+	err = mwl_alloc_rx_ring(sc, MWL_RX_RING_COUNT);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
+		    "could not alloc cmd dma buffer\n");
+		goto fail;
+	}
+
+	for (qid = 0; qid < MWL_NUM_TX_QUEUES; qid++) {
+		err = mwl_alloc_tx_ring(sc,
+		    &sc->sc_txring[qid], MWL_TX_RING_COUNT);
+		if (err != 0) {
+			MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
+			    "could not alloc tx ring %d\n", qid);
+			goto fail;
+		}
+	}
+
+	err = mwl_setupdma(sc);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
+		    "could not setup dma\n");
+		goto fail;
+	}
+
+	err = mwl_setup_txq(sc);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_SR, "mwl: mwl_resume(): "
+		    "could not setup txq\n");
+		goto fail;
+	}
+
+fail:
+	return (err);
+}
+
+static void
+mwl_stop(struct mwl_softc *sc)
+{
+	int err;
+
+	/* by pass if it's quiesced */
+	if (!MWL_IS_QUIESCE(sc))
+		MWL_GLOCK(sc);
+
+	err = mwl_hal_stop(sc);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_HW, "mwl: mwl_stop(): "
+		    "could not stop hw\n");
+	}
+
+	/* by pass if it's quiesced */
+	if (!MWL_IS_QUIESCE(sc))
+		MWL_GUNLOCK(sc);
+}
+
+static int
+mwl_m_stat(void *arg, uint_t stat, uint64_t *val)
+{
+	struct mwl_softc *sc  = (struct mwl_softc *)arg;
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211_node *ni = NULL;
+	struct ieee80211_rateset *rs = NULL;
+
+	MWL_GLOCK(sc);
+	switch (stat) {
+	case MAC_STAT_IFSPEED:
+		ni = ic->ic_bss;
+		rs = &ni->in_rates;
+		*val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
+		    (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL)
+		    : ic->ic_fixed_rate) / 2 * 1000000;
+		break;
+	case MAC_STAT_NOXMTBUF:
+		*val = sc->sc_tx_nobuf;
+		break;
+	case MAC_STAT_NORCVBUF:
+		*val = sc->sc_rx_nobuf;
+		break;
+	case MAC_STAT_IERRORS:
+		*val = sc->sc_rx_err;
+		break;
+	case MAC_STAT_RBYTES:
+		*val = ic->ic_stats.is_rx_bytes;
+		break;
+	case MAC_STAT_IPACKETS:
+		*val = ic->ic_stats.is_rx_frags;
+		break;
+	case MAC_STAT_OBYTES:
+		*val = ic->ic_stats.is_tx_bytes;
+		break;
+	case MAC_STAT_OPACKETS:
+		*val = ic->ic_stats.is_tx_frags;
+		break;
+	case MAC_STAT_OERRORS:
+	case WIFI_STAT_TX_FAILED:
+		*val = sc->sc_tx_err;
+		break;
+	case WIFI_STAT_TX_RETRANS:
+		*val = sc->sc_tx_retries;
+		break;
+	case WIFI_STAT_FCS_ERRORS:
+	case WIFI_STAT_WEP_ERRORS:
+	case WIFI_STAT_TX_FRAGS:
+	case WIFI_STAT_MCAST_TX:
+	case WIFI_STAT_RTS_SUCCESS:
+	case WIFI_STAT_RTS_FAILURE:
+	case WIFI_STAT_ACK_FAILURE:
+	case WIFI_STAT_RX_FRAGS:
+	case WIFI_STAT_MCAST_RX:
+	case WIFI_STAT_RX_DUPS:
+		MWL_GUNLOCK(sc);
+		return (ieee80211_stat(ic, stat, val));
+	default:
+		MWL_GUNLOCK(sc);
+		return (ENOTSUP);
+	}
+
+	MWL_GUNLOCK(sc);
+	return (0);
+}
+
+static int
+mwl_m_start(void *arg)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)arg;
+	struct ieee80211com *ic = &sc->sc_ic;
+	int err;
+
+	err = mwl_init(sc);
+	if (err != DDI_SUCCESS) {
+		MWL_DBG(MWL_DBG_HW, "mwl: mwl_m_start():"
+		    "Hardware initialization failed\n");
+		goto fail1;
+	}
+
+	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+
+	MWL_GLOCK(sc);
+	sc->sc_flags |= MWL_F_RUNNING;
+	MWL_GUNLOCK(sc);
+
+	return (0);
+fail1:
+	mwl_stop(sc);
+	return (err);
+}
+
+static void
+mwl_m_stop(void *arg)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)arg;
+
+	mwl_stop(sc);
+
+	ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
+
+	MWL_GLOCK(sc);
+	sc->sc_flags &= ~MWL_F_RUNNING;
+	MWL_GUNLOCK(sc);
+}
+
+/*ARGSUSED*/
+static int
+mwl_m_promisc(void *arg, boolean_t on)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)arg;
+	int err;
+
+	err = mwl_hal_setpromisc(sc, on);
+
+	return (err);
+}
+
+/*ARGSUSED*/
+static int
+mwl_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
+{
+	return (ENOTSUP);
+}
+
+/*ARGSUSED*/
+static int
+mwl_m_unicst(void *arg, const uint8_t *macaddr)
+{
+	return (ENOTSUP);
+}
+
+static mblk_t *
+mwl_m_tx(void *arg, mblk_t *mp)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)arg;
+	struct ieee80211com *ic = &sc->sc_ic;
+	mblk_t *next;
+
+	if (MWL_IS_SUSPEND(sc)) {
+		freemsgchain(mp);
+		return (NULL);
+	}
+
+	/*
+	 * No data frames go out unless we're associated; this
+	 * should not happen as the 802.11 layer does not enable
+	 * the xmit queue until we enter the RUN state.
+	 */
+	if (ic->ic_state != IEEE80211_S_RUN) {
+		MWL_DBG(MWL_DBG_TX, "mwl: mwl_m_tx(): "
+		    "discard, state %u\n", ic->ic_state);
+		freemsgchain(mp);
+		return (NULL);
+	}
+
+	while (mp != NULL) {
+		next = mp->b_next;
+		mp->b_next = NULL;
+		if (mwl_send(ic, mp, IEEE80211_FC0_TYPE_DATA) !=
+		    DDI_SUCCESS) {
+			mp->b_next = next;
+			break;
+		}
+		mp = next;
+	}
+	return (mp);
+}
+
+static void
+mwl_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)arg;
+	struct ieee80211com *ic = &sc->sc_ic;
+	int err;
+
+	err = ieee80211_ioctl(ic, wq, mp);
+	if (err == ENETRESET) {
+		if (ic->ic_des_esslen) {
+			if (MWL_IS_RUNNING(sc)) {
+				(void) mwl_init(sc);
+				(void) ieee80211_new_state(ic,
+				    IEEE80211_S_SCAN, -1);
+			}
+		}
+	}
+}
+
+/*
+ * Call back function for get/set proporty
+ */
+static int
+mwl_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
+    uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)arg;
+	int err = 0;
+
+	err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
+	    pr_flags, wldp_length, wldp_buf, perm);
+
+	return (err);
+}
+
+static int
+mwl_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
+    uint_t wldp_length, const void *wldp_buf)
+{
+	struct mwl_softc *sc = (struct mwl_softc *)arg;
+	ieee80211com_t *ic = &sc->sc_ic;
+	int err;
+
+	err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
+	    wldp_buf);
+	if (err == ENETRESET) {
+		if (ic->ic_des_esslen) {
+			if (MWL_IS_RUNNING(sc)) {
+				(void) mwl_init(sc);
+				(void) ieee80211_new_state(ic,
+				    IEEE80211_S_SCAN, -1);
+			}
+		}
+		err = 0;
+	}
+	return (err);
+}
+
+static int
+mwl_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
+{
+	struct mwl_softc *sc;
+	struct ieee80211com *ic;
+	int i, err, qid, instance;
+	int intr_type, intr_count, intr_actual;
+	char strbuf[32];
+	uint8_t csz;
+	uint16_t vendor_id, device_id, command;
+
+	wifi_data_t wd = { 0 };
+	mac_register_t *macp;
+
+	switch (cmd) {
+	case DDI_ATTACH:
+		break;
+	case DDI_RESUME:
+		sc = ddi_get_soft_state(mwl_soft_state_p,
+		    ddi_get_instance(devinfo));
+		ASSERT(sc != NULL);
+		MWL_GLOCK(sc);
+		sc->sc_flags &= ~MWL_F_SUSPEND;
+		MWL_GUNLOCK(sc);
+		if (mwl_resume(sc) != 0) {
+			MWL_DBG(MWL_DBG_SR, "mwl: mwl_attach(): "
+			    "failed to resume\n");
+			return (DDI_FAILURE);
+		}
+		if (MWL_IS_RUNNING(sc)) {
+			(void) mwl_init(sc);
+			ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
+		}
+		MWL_DBG(MWL_DBG_SR, "mwl: mwl_attach(): "
+		    "resume now\n");
+		return (DDI_SUCCESS);
+	default:
+		return (DDI_FAILURE);
+	}
+
+	instance = ddi_get_instance(devinfo);
+	if (ddi_soft_state_zalloc(mwl_soft_state_p,
+	    ddi_get_instance(devinfo)) != DDI_SUCCESS) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "Unable to alloc soft state\n");
+		return (DDI_FAILURE);
+	}
+
+	sc = ddi_get_soft_state(mwl_soft_state_p, ddi_get_instance(devinfo));
+	ic = &sc->sc_ic;
+	sc->sc_dev = devinfo;
+
+	/* PCI configuration space */
+	err = ddi_regs_map_setup(devinfo, 0, (caddr_t *)&sc->sc_cfg_base, 0, 0,
+	    &mwl_reg_accattr, &sc->sc_cfg_handle);
+	if (err != DDI_SUCCESS) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "ddi_regs_map_setup() failed");
+		goto attach_fail0;
+	}
+	csz = ddi_get8(sc->sc_cfg_handle,
+	    (uint8_t *)(sc->sc_cfg_base + PCI_CONF_CACHE_LINESZ));
+	if (!csz)
+		csz = 16;
+	sc->sc_cachelsz = csz << 2;
+	sc->sc_dmabuf_size = roundup(IEEE80211_MAX_LEN, sc->sc_cachelsz);
+	vendor_id = ddi_get16(sc->sc_cfg_handle,
+	    (uint16_t *)(sc->sc_cfg_base + PCI_CONF_VENID));
+	device_id = ddi_get16(sc->sc_cfg_handle,
+	    (uint16_t *)(sc->sc_cfg_base + PCI_CONF_DEVID));
+	MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+	    "vendor 0x%x, device id 0x%x, cache size %d\n",
+	    vendor_id, device_id, csz);
+
+	/*
+	 * Enable response to memory space accesses,
+	 * and enabe bus master.
+	 */
+	command = PCI_COMM_MAE | PCI_COMM_ME;
+	ddi_put16(sc->sc_cfg_handle,
+	    (uint16_t *)((uintptr_t)(sc->sc_cfg_base) + PCI_CONF_COMM),
+	    command);
+	ddi_put8(sc->sc_cfg_handle,
+	    (uint8_t *)(sc->sc_cfg_base + PCI_CONF_LATENCY_TIMER), 0xa8);
+	ddi_put8(sc->sc_cfg_handle,
+	    (uint8_t *)(sc->sc_cfg_base + PCI_CONF_ILINE), 0x10);
+
+	/* BAR0 */
+	err = ddi_regs_map_setup(devinfo, 1,
+	    &sc->sc_mem_base, 0, 0, &mwl_reg_accattr, &sc->sc_mem_handle);
+	if (err != DDI_SUCCESS) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "i/o space failed");
+		goto attach_fail1;
+	}
+
+	/* BAR1 */
+	err = ddi_regs_map_setup(devinfo, 2,
+	    &sc->sc_io_base, 0, 0, &mwl_reg_accattr, &sc->sc_io_handle);
+	if (err != DDI_SUCCESS) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "memory space failed");
+		goto attach_fail2;
+	}
+
+	MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+	    "PCI configuration is done successfully\n");
+
+	/*
+	 * Alloc cmd DMA buffer for firmware download
+	 */
+	err = mwl_alloc_cmdbuf(sc);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "could not alloc cmd dma buffer\n");
+		goto attach_fail3;
+	}
+
+	sc->sc_imask = 0;
+	sc->sc_hw_flags = 0;
+	sc->sc_flags = 0;
+
+	/*
+	 * Some cards have SDRAM.  When loading firmware we need
+	 * to reset the SDRAM controller prior to doing this.
+	 * When the SDRAMSIZE is non-zero we do that work in
+	 * mwl_hal_fwload.
+	 */
+	switch (device_id) {
+	case 0x2a02:		/* CB82 */
+	case 0x2a03:		/* CB85 */
+	case 0x2a08:		/* MC85_B1 */
+	case 0x2a0b:		/* CB85AP */
+	case 0x2a24:
+		sc->sc_SDRAMSIZE_Addr = 0x40fe70b7;	/* 8M SDRAM */
+		break;
+	case 0x2a04:		/* MC85 */
+		sc->sc_SDRAMSIZE_Addr = 0x40fc70b7;	/* 16M SDRAM */
+		break;
+	default:
+		break;
+	}
+
+	err = mwl_fwload(sc, NULL);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "firmware download failed\n");
+		goto attach_fail4;
+	}
+
+	MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+	    "firmware download successfully\n");
+
+	err = mwl_gethwspecs(sc);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "failed to get hw spec\n");
+		goto attach_fail4;
+	}
+
+	err = mwl_getchannels(sc);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "failed to get channels\n");
+		goto attach_fail4;
+	}
+
+	/*
+	 * Alloc rx DMA buffer
+	 */
+	err = mwl_alloc_rx_ring(sc, MWL_RX_RING_COUNT);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "could not alloc cmd dma buffer\n");
+		goto attach_fail5;
+	}
+
+	/*
+	 * Alloc rx DMA buffer
+	 */
+	for (qid = 0; qid < MWL_NUM_TX_QUEUES; qid++) {
+		err = mwl_alloc_tx_ring(sc,
+		    &sc->sc_txring[qid], MWL_TX_RING_COUNT);
+		if (err != 0) {
+			MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+			    "could not alloc tx ring %d\n", qid);
+			goto attach_fail6;
+		}
+	}
+
+	err = mwl_setupdma(sc);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "could not setup dma\n");
+		goto attach_fail6;
+	}
+
+	err = mwl_setup_txq(sc);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "could not setup txq\n");
+		goto attach_fail6;
+	}
+
+	IEEE80211_ADDR_COPY(ic->ic_macaddr, sc->sc_hwspecs.macAddr);
+	MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+	    "mwl MAC:%2x:%2x:%2x:%2x:%2x:%2x\n",
+	    ic->ic_macaddr[0],
+	    ic->ic_macaddr[1],
+	    ic->ic_macaddr[2],
+	    ic->ic_macaddr[3],
+	    ic->ic_macaddr[4],
+	    ic->ic_macaddr[5]);
+
+	err = mwl_hal_setmac_locked(sc, ic->ic_macaddr);
+	if (err != 0) {			/* NB: mwl_setupdma prints msg */
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: attach(): "
+		    "could not set mac\n");
+		goto attach_fail6;
+	}
+
+	mutex_init(&sc->sc_glock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&sc->sc_rxlock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&sc->sc_txlock, NULL, MUTEX_DRIVER, NULL);
+
+
+	/* set supported rates */
+	ic->ic_sup_rates[IEEE80211_MODE_11B] = mwl_rateset_11b;
+	ic->ic_sup_rates[IEEE80211_MODE_11G] = mwl_rateset_11g;
+
+	/* set supported .11b and .11g channels (1 through 14) */
+	for (i = 1; i <= 14; i++) {
+		ic->ic_sup_channels[i].ich_freq =
+		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
+		ic->ic_sup_channels[i].ich_flags =
+		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
+	}
+
+	ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
+	ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
+	ic->ic_state = IEEE80211_S_INIT;
+
+	/* set device capabilities */
+	ic->ic_caps =
+	    IEEE80211_C_TXPMGT |	/* tx power management */
+	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
+	    IEEE80211_C_SHSLOT;		/* short slot time supported */
+
+	/* WPA/WPA2 support */
+	ic->ic_caps |= IEEE80211_C_WPA; /* Support WPA/WPA2 */
+
+	/* Enable hardware encryption */
+	ic->ic_caps |= IEEE80211_C_WEP | IEEE80211_C_TKIP | IEEE80211_C_AES_CCM;
+
+	ic->ic_xmit = mwl_send;
+
+	ieee80211_attach(ic);
+
+	/* register WPA door */
+	ieee80211_register_door(ic, ddi_driver_name(devinfo),
+	    ddi_get_instance(devinfo));
+
+	/* override state transition machine */
+	sc->sc_newstate = ic->ic_newstate;
+	ic->ic_newstate = mwl_newstate;
+	ic->ic_node_alloc = mwl_node_alloc;
+	ic->ic_node_free = mwl_node_free;
+	ic->ic_crypto.cs_max_keyix = 0;
+	ic->ic_crypto.cs_key_alloc = mwl_key_alloc;
+	ic->ic_crypto.cs_key_delete = mwl_key_delete;
+	ic->ic_crypto.cs_key_set = mwl_key_set;
+
+	ieee80211_media_init(ic);
+
+	ic->ic_def_txkey = 0;
+
+	err = mwl_hal_newstation(sc, ic->ic_macaddr, 0, 0, NULL, 0, 0);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: attach(): "
+		    "could not create new station\n");
+		goto attach_fail7;
+	}
+
+	IEEE80211_ADDR_COPY(ic->ic_bss->in_bssid, ic->ic_macaddr);
+	// mwl_setglobalkeys(ic);
+
+	err = ddi_intr_get_supported_types(devinfo, &intr_type);
+	if ((err != DDI_SUCCESS) || (!(intr_type & DDI_INTR_TYPE_FIXED))) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "fixed type interrupt is not supported\n");
+		goto attach_fail7;
+	}
+
+	err = ddi_intr_get_nintrs(devinfo, DDI_INTR_TYPE_FIXED, &intr_count);
+	if ((err != DDI_SUCCESS) || (intr_count != 1)) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "no fixed interrupts\n");
+		goto attach_fail7;
+	}
+
+	sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
+
+	err = ddi_intr_alloc(devinfo, sc->sc_intr_htable,
+	    DDI_INTR_TYPE_FIXED, 0, intr_count, &intr_actual, 0);
+	if ((err != DDI_SUCCESS) || (intr_actual != 1)) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "ddi_intr_alloc() failed 0x%x\n", err);
+		goto attach_fail8;
+	}
+
+	err = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_pri);
+	if (err != DDI_SUCCESS) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "ddi_intr_get_pri() failed 0x%x\n", err);
+		goto attach_fail9;
+	}
+
+	err = ddi_intr_add_softint(devinfo, &sc->sc_softintr_hdl,
+	    DDI_INTR_SOFTPRI_MAX, mwl_softintr, (caddr_t)sc);
+	if (err != DDI_SUCCESS) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "ddi_add_softintr() failed");
+		goto attach_fail9;
+	}
+
+	err = ddi_intr_add_handler(sc->sc_intr_htable[0], mwl_intr,
+	    (caddr_t)sc, NULL);
+	if (err != DDI_SUCCESS) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "ddi_intr_addr_handle() failed\n");
+		goto attach_fail10;
+	}
+
+	err = ddi_intr_enable(sc->sc_intr_htable[0]);
+	if (err != DDI_SUCCESS) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "ddi_intr_enable() failed\n");
+		goto attach_fail11;
+	}
+
+	/*
+	 * Provide initial settings for the WiFi plugin; whenever this
+	 * information changes, we need to call mac_plugindata_update()
+	 */
+	wd.wd_opmode = ic->ic_opmode;
+	wd.wd_secalloc = WIFI_SEC_NONE;
+	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
+
+	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "MAC version mismatch\n");
+		goto attach_fail12;
+	}
+
+	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
+	macp->m_driver		= sc;
+	macp->m_dip		= devinfo;
+	macp->m_src_addr	= ic->ic_macaddr;
+	macp->m_callbacks	= &mwl_m_callbacks;
+	macp->m_min_sdu		= 0;
+	macp->m_max_sdu		= IEEE80211_MTU;
+	macp->m_pdata		= &wd;
+	macp->m_pdata_size	= sizeof (wd);
+
+	err = mac_register(macp, &ic->ic_mach);
+	mac_free(macp);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "mac_register err %x\n", err);
+		goto attach_fail12;
+	}
+
+	/*
+	 * Create minor node of type DDI_NT_NET_WIFI
+	 */
+	(void) snprintf(strbuf, sizeof (strbuf), "%s%d",
+	    "mwl", instance);
+	err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
+	    instance + 1, DDI_NT_NET_WIFI, 0);
+	if (err != 0) {
+		MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+		    "create minor node error\n");
+		goto attach_fail13;
+	}
+
+	/*
+	 * Notify link is down now
+	 */
+	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
+
+	MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_attach(): "
+	    "driver attach successfully\n");
+	return (DDI_SUCCESS);
+
+attach_fail13:
+	(void) mac_disable(ic->ic_mach);
+	(void) mac_unregister(ic->ic_mach);
+attach_fail12:
+	(void) ddi_intr_disable(sc->sc_intr_htable[0]);
+attach_fail11:
+	(void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
+attach_fail10:
+	(void) ddi_intr_remove_softint(sc->sc_softintr_hdl);
+	sc->sc_softintr_hdl = NULL;
+attach_fail9:
+	(void) ddi_intr_free(sc->sc_intr_htable[0]);
+attach_fail8:
+	kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
+attach_fail7:
+	mutex_destroy(&sc->sc_txlock);
+	mutex_destroy(&sc->sc_rxlock);
+	mutex_destroy(&sc->sc_glock);
+attach_fail6:
+	while (--qid >= 0)
+		mwl_free_tx_ring(sc, &sc->sc_txring[qid]);
+attach_fail5:
+	mwl_free_rx_ring(sc);
+attach_fail4:
+	mwl_free_cmdbuf(sc);
+attach_fail3:
+	ddi_regs_map_free(&sc->sc_mem_handle);
+attach_fail2:
+	ddi_regs_map_free(&sc->sc_io_handle);
+attach_fail1:
+	ddi_regs_map_free(&sc->sc_cfg_handle);
+attach_fail0:
+	ddi_soft_state_free(mwl_soft_state_p, ddi_get_instance(devinfo));
+	return (DDI_FAILURE);
+}
+
+static int32_t
+mwl_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
+{
+	struct mwl_softc *sc;
+	int qid;
+
+	sc = ddi_get_soft_state(mwl_soft_state_p, ddi_get_instance(devinfo));
+	ASSERT(sc != NULL);
+
+	switch (cmd) {
+	case DDI_DETACH:
+		break;
+	case DDI_SUSPEND:
+		if (MWL_IS_RUNNING(sc))
+			mwl_stop(sc);
+		for (qid = 0; qid < MWL_NUM_TX_QUEUES; qid++)
+			mwl_free_tx_ring(sc, &sc->sc_txring[qid]);
+		mwl_free_rx_ring(sc);
+		MWL_GLOCK(sc);
+		sc->sc_flags |= MWL_F_SUSPEND;
+		MWL_GUNLOCK(sc);
+		MWL_DBG(MWL_DBG_SR, "mwl: mwl_detach(): "
+		    "suspend now\n");
+		return (DDI_SUCCESS);
+	default:
+		return (DDI_FAILURE);
+	}
+
+	if (mac_disable(sc->sc_ic.ic_mach) != 0)
+		return (DDI_FAILURE);
+
+	/*
+	 * Unregister from the MAC layer subsystem
+	 */
+	(void) mac_unregister(sc->sc_ic.ic_mach);
+
+	(void) ddi_intr_remove_softint(sc->sc_softintr_hdl);
+	sc->sc_softintr_hdl = NULL;
+	(void) ddi_intr_disable(sc->sc_intr_htable[0]);
+	(void) ddi_intr_remove_handler(sc->sc_intr_htable[0]);
+	(void) ddi_intr_free(sc->sc_intr_htable[0]);
+	kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t));
+
+	/*
+	 * detach ieee80211 layer
+	 */
+	ieee80211_detach(&sc->sc_ic);
+
+
+	for (qid = 0; qid < MWL_NUM_TX_QUEUES; qid++)
+		mwl_free_tx_ring(sc, &sc->sc_txring[qid]);
+	mwl_free_rx_ring(sc);
+	mwl_free_cmdbuf(sc);
+
+	mutex_destroy(&sc->sc_txlock);
+	mutex_destroy(&sc->sc_rxlock);
+	mutex_destroy(&sc->sc_glock);
+
+	ddi_regs_map_free(&sc->sc_mem_handle);
+	ddi_regs_map_free(&sc->sc_io_handle);
+	ddi_regs_map_free(&sc->sc_cfg_handle);
+
+	ddi_remove_minor_node(devinfo, NULL);
+	ddi_soft_state_free(mwl_soft_state_p, ddi_get_instance(devinfo));
+
+	MWL_DBG(MWL_DBG_ATTACH, "mwl: mwl_detach(): "
+	    "detach successfully\n");
+	return (DDI_SUCCESS);
+}
+
+/*
+ * quiesce(9E) entry point.
+ *
+ * This function is called when the system is single-threaded at high
+ * PIL with preemption disabled. Therefore, this function must not be
+ * blocked.
+ *
+ * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
+ * DDI_FAILURE indicates an error condition and should almost never happen.
+ */
+int
+mwl_quiesce(dev_info_t *dip)
+{
+	struct mwl_softc *sc;
+
+	sc = ddi_get_soft_state(mwl_soft_state_p, ddi_get_instance(dip));
+	if (sc == NULL)
+		return (DDI_FAILURE);
+
+#ifdef DEBUG
+	mwl_dbg_flags = 0;
+#endif
+
+	/*
+	 * No more blocking is allowed while we are in quiesce(9E) entry point
+	 */
+	sc->sc_flags |= MWL_F_QUIESCE;
+
+	/*
+	 * Disable all interrupts
+	 */
+	mwl_stop(sc);
+	return (DDI_SUCCESS);
+}
+
+int
+_init(void)
+{
+	int status;
+
+	status = ddi_soft_state_init(&mwl_soft_state_p,
+	    sizeof (struct mwl_softc), 1);
+	if (status != 0)
+		return (status);
+
+	mac_init_ops(&mwl_dev_ops, "mwl");
+	status = mod_install(&modlinkage);
+	if (status != 0) {
+		mac_fini_ops(&mwl_dev_ops);
+		ddi_soft_state_fini(&mwl_soft_state_p);
+	}
+	return (status);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+	int status;
+
+	status = mod_remove(&modlinkage);
+	if (status == 0) {
+		mac_fini_ops(&mwl_dev_ops);
+		ddi_soft_state_fini(&mwl_soft_state_p);
+	}
+	return (status);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/mwl/mwl_fw/LICENSE	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,44 @@
+# FIRMWARE LICENSE TERMS
+# 
+# 
+# Copyright (c) Marvell International Ltd.
+# 
+# All rights reserved.
+# 
+# Redistribution. Redistribution and use in binary form, without
+# modification, are permitted provided that the following conditions are
+# met:
+# 
+# * Redistributions must reproduce the above copyright notice and the
+# following disclaimer in the documentation and/or other materials
+# provided with the distribution. 
+# 
+# * Neither the name of Marvell International Ltd. nor the names of its
+# suppliers may be used to endorse or promote products derived from this
+# software without specific prior written permission. 
+# 
+# * No reverse engineering, decompilation, or disassembly of this software
+# is permitted.
+# 
+# Limited patent license. Marvell International Ltd. grants a world-wide,
+# royalty-free, non-exclusive license under patents it now or hereafter
+# owns or controls to make, have made, use, import, offer to sell and sell
+# ("Utilize") this software, but solely to the extent that any such patent
+# is necessary to Utilize the software alone, or in combination with an
+# operating system licensed under an approved Open Source license as
+# listed by the Open Source Initiative at http://opensource.org/licenses.
+# The patent license shall not apply to any other combinations which
+# include this software. No hardware per se is licensed hereunder.
+# 
+# DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIPOSSIBILITY OF SUCH DAMAGE.
+# 
+# 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/mwl/mwl_fw/LICENSE.descrip	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,2 @@
+Marvell 88W8363 Wireless LAN controller Boot FIRMWARE
+Marvell 88W8363 Wireless LAN controller FIRMWARE
Binary file usr/src/uts/common/io/mwl/mwl_fw/mw88W8363 has changed
Binary file usr/src/uts/common/io/mwl/mwl_fw/mwlboot has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/mwl/mwl_fw/mwlfw_mode.c	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,67 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * misc module wrapper for a firmware module for mwl driver
+ * User must use elfwrap(1) to convert raw firmware data file to
+ * ELF object file. Then use ld(1) to link the ELF object file and
+ * this module to produce a kernel loadable module.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/modctl.h>
+
+
+extern struct mod_ops mod_miscops;
+static struct modlmisc modlmisc = {
+	&mod_miscops,
+	"mwl firmware wrapper module 1.1"
+};
+static struct modlinkage modlinkage = {
+	MODREV_1,
+	&modlmisc,
+	0
+};
+
+int
+_init(void)
+{
+	return (mod_install(&modlinkage));
+}
+
+int
+_fini(void)
+{
+	return (mod_remove(&modlinkage));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/mwl/mwl_reg.h	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,866 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2007-2009 Marvell Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * Definitions for the Marvell Wireless LAN controller Hardware Access Layer.
+ */
+
+#ifndef _MWL_REG_H
+#define	_MWL_REG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define	MWL_MBSS_SUPPORT		/* enable multi-bss support */
+
+/*
+ * Host/Firmware Interface definitions.
+ */
+
+/*
+ * Define total number of TX queues in the shared memory.
+ * This count includes the EDCA queues, Block Ack queues, and HCCA queues
+ * In addition to this, there could be a management packet queue some
+ * time in the future
+ */
+#define	NUM_EDCA_QUEUES		4
+#define	NUM_HCCA_QUEUES		0
+#define	NUM_BA_QUEUES		0
+#define	NUM_MGMT_QUEUES		0
+#define	NUM_ACK_EVENT_QUEUE	1
+#define	TOTAL_TX_QUEUES		\
+	(NUM_EDCA_QUEUES +	\
+	NUM_HCCA_QUEUES +	\
+	NUM_BA_QUEUES +		\
+	NUM_MGMT_QUEUES +	\
+	NUM_ACK_EVENT_QUEUE)
+#define	MAX_TXWCB_QUEUES	TOTAL_TX_QUEUES - NUM_ACK_EVENT_QUEUE
+#define	MAX_RXWCB_QUEUES	1
+
+/*
+ * Firmware download support.
+ */
+#define	FW_DOWNLOAD_BLOCK_SIZE	256
+#define	FW_CHECK_USECS		(5*1000) /* 5ms */
+#define	FW_MAX_NUM_CHECKS	200
+
+#define	MWL_ANT_INFO_SUPPORT /* per-antenna data in rx descriptor */
+
+#define	MACREG_REG_TSF_LOW	0xa600 /* TSF lo */
+#define	MACREG_REG_TSF_HIGH	0xa604 /* TSF hi */
+#define	MACREG_REG_CHIP_REV	0xa814 /* chip rev */
+
+/*
+ * Map to 0x80000000 (Bus control) on BAR0
+ */
+/* From host to ARM */
+#define	MACREG_REG_H2A_INTERRUPT_EVENTS		0x00000C18
+#define	MACREG_REG_H2A_INTERRUPT_CAUSE		0x00000C1C
+#define	MACREG_REG_H2A_INTERRUPT_MASK		0x00000C20
+#define	MACREG_REG_H2A_INTERRUPT_CLEAR_SEL	0x00000C24
+#define	MACREG_REG_H2A_INTERRUPT_STATUS_MASK	0x00000C28
+/* From ARM to host */
+#define	MACREG_REG_A2H_INTERRUPT_EVENTS		0x00000C2C
+#define	MACREG_REG_A2H_INTERRUPT_CAUSE		0x00000C30
+#define	MACREG_REG_A2H_INTERRUPT_MASK		0x00000C34
+#define	MACREG_REG_A2H_INTERRUPT_CLEAR_SEL	0x00000C38
+#define	MACREG_REG_A2H_INTERRUPT_STATUS_MASK	0x00000C3C
+
+
+/* Map to 0x80000000 on BAR1 */
+#define	MACREG_REG_GEN_PTR		0x00000C10
+#define	MACREG_REG_INT_CODE		0x00000C14
+#define	MACREG_REG_SCRATCH		0x00000C40
+#define	MACREG_REG_FW_PRESENT		0x0000BFFC
+
+#define	MACREG_REG_PROMISCUOUS		0xA300
+/* Bit definitio for MACREG_REG_A2H_INTERRUPT_CAUSE (A2HRIC) */
+#define	MACREG_A2HRIC_BIT_TX_DONE	0x00000001 /* bit 0 */
+#define	MACREG_A2HRIC_BIT_RX_RDY	0x00000002 /* bit 1 */
+#define	MACREG_A2HRIC_BIT_OPC_DONE	0x00000004 /* bit 2 */
+#define	MACREG_A2HRIC_BIT_MAC_EVENT	0x00000008 /* bit 3 */
+#define	MACREG_A2HRIC_BIT_RX_PROBLEM	0x00000010 /* bit 4 */
+
+#define	MACREG_A2HRIC_BIT_RADIO_OFF	0x00000020 /* bit 5 */
+#define	MACREG_A2HRIC_BIT_RADIO_ON	0x00000040 /* bit 6 */
+
+#define	MACREG_A2HRIC_BIT_RADAR_DETECT	0x00000080 /* bit 7 */
+
+#define	MACREG_A2HRIC_BIT_ICV_ERROR	0x00000100 /* bit 8 */
+#define	MACREG_A2HRIC_BIT_MIC_ERROR	0x00000200 /* bit 9 */
+#define	MACREG_A2HRIC_BIT_QUEUE_EMPTY	0x00004000
+#define	MACREG_A2HRIC_BIT_QUEUE_FULL	0x00000800
+#define	MACREG_A2HRIC_BIT_CHAN_SWITCH	0x00001000
+#define	MACREG_A2HRIC_BIT_TX_WATCHDOG	0x00002000
+#define	MACREG_A2HRIC_BIT_BA_WATCHDOG	0x00000400
+#define	MACREQ_A2HRIC_BIT_TX_ACK	0x00008000
+#define	ISR_SRC_BITS	((MACREG_A2HRIC_BIT_RX_RDY)	| \
+			(MACREG_A2HRIC_BIT_TX_DONE)	| \
+			(MACREG_A2HRIC_BIT_OPC_DONE)	| \
+			(MACREG_A2HRIC_BIT_MAC_EVENT)	| \
+			(MACREG_A2HRIC_BIT_MIC_ERROR)	| \
+			(MACREG_A2HRIC_BIT_ICV_ERROR)	| \
+			(MACREG_A2HRIC_BIT_RADAR_DETECT)| \
+			(MACREG_A2HRIC_BIT_CHAN_SWITCH)	| \
+			(MACREG_A2HRIC_BIT_TX_WATCHDOG)	| \
+			(MACREG_A2HRIC_BIT_QUEUE_EMPTY)	| \
+			(MACREG_A2HRIC_BIT_BA_WATCHDOG)	| \
+			(MACREQ_A2HRIC_BIT_TX_ACK))
+
+#define	MACREG_A2HRIC_BIT_MASK	ISR_SRC_BITS
+
+/* Bit definitio for MACREG_REG_H2A_INTERRUPT_CAUSE (H2ARIC) */
+#define	MACREG_H2ARIC_BIT_PPA_READY	0x00000001 /* bit 0 */
+#define	MACREG_H2ARIC_BIT_DOOR_BELL	0x00000002 /* bit 1 */
+#define	ISR_RESET			(1<<15)
+
+/* INT code register event definition */
+#define	MACREG_INT_CODE_CMD_FINISHED	0x00000005
+
+/*
+ * Define OpMode for SoftAP/Station mode
+ */
+
+/*
+ * The following mode signature has to be written to PCI scratch register#0
+ * right after successfully downloading the last block of firmware and
+ * before waiting for firmware ready signature
+ */
+#define	HostCmd_STA_MODE		0x5A
+#define	HostCmd_SOFTAP_MODE		0xA5
+
+#define	HostCmd_STA_FWRDY_SIGNATURE	0xF0F1F2F4
+#define	HostCmd_SOFTAP_FWRDY_SIGNATURE	0xF1F2F4A5
+
+#define	HostCmd_CMD_CODE_DNLD			0x0001
+#define	HostCmd_CMD_GET_HW_SPEC			0x0003
+#define	HostCmd_CMD_SET_HW_SPEC			0x0004
+#define	HostCmd_CMD_MAC_MULTICAST_ADR		0x0010
+#define	HostCmd_CMD_802_11_GET_STAT		0x0014
+#define	HostCmd_CMD_MAC_REG_ACCESS		0x0019
+#define	HostCmd_CMD_BBP_REG_ACCESS		0x001a
+#define	HostCmd_CMD_RF_REG_ACCESS		0x001b
+#define	HostCmd_CMD_802_11_RADIO_CONTROL	0x001c
+#define	HostCmd_CMD_802_11_RF_TX_POWER		0x001e
+#define	HostCmd_CMD_802_11_RF_ANTENNA		0x0020
+#define	HostCmd_CMD_SET_BEACON			0x0100
+#define	HostCmd_CMD_SET_AID			0x010d
+#define	HostCmd_CMD_SET_RF_CHANNEL		0x010a
+#define	HostCmd_CMD_SET_INFRA_MODE		0x010e
+#define	HostCmd_CMD_SET_G_PROTECT_FLAG		0x010f
+#define	HostCmd_CMD_802_11_RTS_THSD		0x0113
+#define	HostCmd_CMD_802_11_SET_SLOT		0x0114
+
+#define	HostCmd_CMD_802_11H_DETECT_RADAR	0x0120
+#define	HostCmd_CMD_SET_WMM_MODE		0x0123
+#define	HostCmd_CMD_HT_GUARD_INTERVAL		0x0124
+#define	HostCmd_CMD_SET_FIXED_RATE		0x0126
+#define	HostCmd_CMD_SET_LINKADAPT_CS_MODE	0x0129
+#define	HostCmd_CMD_SET_MAC_ADDR		0x0202
+#define	HostCmd_CMD_SET_RATE_ADAPT_MODE		0x0203
+#define	HostCmd_CMD_GET_WATCHDOG_BITMAP		0x0205
+
+/* SoftAP command code */
+#define	HostCmd_CMD_BSS_START			0x1100
+#define	HostCmd_CMD_SET_NEW_STN			0x1111
+#define	HostCmd_CMD_SET_KEEP_ALIVE		0x1112
+#define	HostCmd_CMD_SET_APMODE			0x1114
+#define	HostCmd_CMD_SET_SWITCH_CHANNEL		0x1121
+
+/*
+ * @HWENCR@
+ * Command to update firmware encryption keys.
+ */
+#define	HostCmd_CMD_UPDATE_ENCRYPTION		0x1122
+/*
+ * @11E-BA@
+ * Command to create/destroy block ACK
+ */
+#define	HostCmd_CMD_BASTREAM			0x1125
+#define	HostCmd_CMD_SET_RIFS			0x1126
+#define	HostCmd_CMD_SET_N_PROTECT_FLAG		0x1131
+#define	HostCmd_CMD_SET_N_PROTECT_OPMODE	0x1132
+#define	HostCmd_CMD_SET_OPTIMIZATION_LEVEL	0x1133
+#define	HostCmd_CMD_GET_CALTABLE		0x1134
+#define	HostCmd_CMD_SET_MIMOPSHT		0x1135
+#define	HostCmd_CMD_GET_BEACON			0x1138
+#define	HostCmd_CMD_SET_REGION_CODE		0x1139
+#define	HostCmd_CMD_SET_POWERSAVESTATION	0x1140
+#define	HostCmd_CMD_SET_TIM			0x1141
+#define	HostCmd_CMD_GET_TIM			0x1142
+#define	HostCmd_CMD_GET_SEQNO			0x1143
+#define	HostCmd_CMD_DWDS_ENABLE			0x1144
+#define	HostCmd_CMD_AMPDU_RETRY_RATEDROP_MODE	0x1145
+#define	HostCmd_CMD_CFEND_ENABLE		0x1146
+
+/*
+ * Define general result code for each command
+ */
+/* RESULT OK */
+#define	HostCmd_RESULT_OK		0x0000
+/* Genenral error */
+#define	HostCmd_RESULT_ERROR		0x0001
+/* Command is not valid */
+#define	HostCmd_RESULT_NOT_SUPPORT	0x0002
+/* Command is pending (will be processed) */
+#define	HostCmd_RESULT_PENDING		0x0003
+/* System is busy (command ignored) */
+#define	HostCmd_RESULT_BUSY		0x0004
+/* Data buffer is not big enough */
+#define	HostCmd_RESULT_PARTIAL_DATA	0x0005
+
+#define	HostCmd_CMD_SET_EDCA_PARAMS	0x0115
+
+/*
+ * Definition of action or option for each command
+ */
+
+/*
+ * Define general purpose action
+ */
+#define	HostCmd_ACT_GEN_READ	0x0000
+#define	HostCmd_ACT_GEN_WRITE	0x0001
+#define	HostCmd_ACT_GEN_GET	0x0000
+#define	HostCmd_ACT_GEN_SET	0x0001
+#define	HostCmd_ACT_GEN_OFF	0x0000
+#define	HostCmd_ACT_GEN_ON	0x0001
+
+#define	HostCmd_ACT_DIFF_CHANNEL	0x0002
+#define	HostCmd_ACT_GEN_SET_LIST	0x0002
+
+/* Define action or option for HostCmd_FW_USE_FIXED_RATE */
+#define	HostCmd_ACT_USE_FIXED_RATE	0x0001
+#define	HostCmd_ACT_NOT_USE_FIXED_RATE	0x0002
+
+/* Define action or option for HostCmd_CMD_802_11_SET_WEP */
+#define	HostCmd_ACT_ADD		0x0002
+#define	HostCmd_ACT_REMOVE	0x0004
+#define	HostCmd_ACT_USE_DEFAULT	0x0008
+
+/*
+ * PUBLIC DEFINITIONS
+ */
+#define	RATE_INDEX_MAX_ARRAY	14
+#define	WOW_MAX_STATION		32
+
+
+#pragma pack(1)
+
+struct mwl_ant_info {
+	uint8_t		rssi_a;	/* RSSI for antenna A */
+	uint8_t		rssi_b;	/* RSSI for antenna B */
+	uint8_t		rssi_c;	/* RSSI for antenna C */
+	uint8_t		rsvd1;	/* Reserved */
+	uint8_t		nf_a;	/* Noise floor for antenna A */
+	uint8_t		nf_b;	/* Noise floor for antenna B */
+	uint8_t		nf_c;	/* Noise floor for antenna C */
+	uint8_t		rsvd2;	/* Reserved */
+	uint8_t		nf;	/* Noise floor */
+	uint8_t		rsvd3[3]; /* Reserved - To make word aligned */
+};
+
+/*
+ * Hardware tx/rx descriptors.
+ *
+ * NB: tx descriptor size must match f/w expected size
+ * because f/w prefetch's the next descriptor linearly
+ * and doesn't chase the next pointer.
+ */
+struct mwl_txdesc {
+	uint32_t	Status;
+#define	EAGLE_TXD_STATUS_IDLE		0x00000000
+#define	EAGLE_TXD_STATUS_USED		0x00000001
+#define	EAGLE_TXD_STATUS_OK		0x00000001
+#define	EAGLE_TXD_STATUS_OK_RETRY	0x00000002
+#define	EAGLE_TXD_STATUS_OK_MORE_RETRY	0x00000004
+#define	EAGLE_TXD_STATUS_MULTICAST_TX	0x00000008
+#define	EAGLE_TXD_STATUS_BROADCAST_TX	0x00000010
+#define	EAGLE_TXD_STATUS_FAILED_LINK_ERROR		0x00000020
+#define	EAGLE_TXD_STATUS_FAILED_EXCEED_LIMIT		0x00000040
+#define	EAGLE_TXD_STATUS_FAILED_XRETRY	EAGLE_TXD_STATUS_FAILED_EXCEED_LIMIT
+#define	EAGLE_TXD_STATUS_FAILED_AGING	0x00000080
+#define	EAGLE_TXD_STATUS_FW_OWNED	0x80000000
+	uint8_t		DataRate;
+	uint8_t		TxPriority;
+	uint16_t	QosCtrl;
+	uint32_t	PktPtr;
+	uint16_t	PktLen;
+	uint8_t		DestAddr[6];
+	uint32_t	pPhysNext;
+	uint32_t	SapPktInfo;
+#define	EAGLE_TXD_MODE_BONLY	1
+#define	EAGLE_TXD_MODE_GONLY	2
+#define	EAGLE_TXD_MODE_BG	3
+#define	EAGLE_TXD_MODE_NONLY	4
+#define	EAGLE_TXD_MODE_BN	5
+#define	EAGLE_TXD_MODE_GN	6
+#define	EAGLE_TXD_MODE_BGN	7
+#define	EAGLE_TXD_MODE_AONLY	8
+#define	EAGLE_TXD_MODE_AG	10
+#define	EAGLE_TXD_MODE_AN	12
+	uint16_t	Format;
+#define	EAGLE_TXD_FORMAT	0x0001	/* frame format/rate */
+#define	EAGLE_TXD_FORMAT_LEGACY	0x0000	/* legacy rate frame */
+#define	EAGLE_TXD_FORMAT_HT	0x0001	/* HT rate frame */
+#define	EAGLE_TXD_GI		0x0002	/* guard interval */
+#define	EAGLE_TXD_GI_SHORT	0x0002	/* short guard interval */
+#define	EAGLE_TXD_GI_LONG	0x0000	/* long guard interval */
+#define	EAGLE_TXD_CHW		0x0004	/* channel width */
+#define	EAGLE_TXD_CHW_20	0x0000	/* 20MHz channel width */
+#define	EAGLE_TXD_CHW_40	0x0004	/* 40MHz channel width */
+#define	EAGLE_TXD_RATE		0x01f8	/* tx rate (legacy)/ MCS */
+#define	EAGLE_TXD_RATE_S	3
+#define	EAGLE_TXD_ADV		0x0600	/* advanced coding */
+#define	EAGLE_TXD_ADV_S		9
+#define	EAGLE_TXD_ADV_NONE	0x0000
+#define	EAGLE_TXD_ADV_LDPC	0x0200
+#define	EAGLE_TXD_ADV_RS	0x0400
+/* NB: 3 is reserved */
+#define	EAGLE_TXD_ANTENNA	0x1800	/* antenna select */
+#define	EAGLE_TXD_ANTENNA_S	11
+#define	EAGLE_TXD_EXTCHAN	0x6000	/* extension channel */
+#define	EAGLE_TXD_EXTCHAN_S	13
+#define	EAGLE_TXD_EXTCHAN_HI	0x0000	/* above */
+#define	EAGLE_TXD_EXTCHAN_LO	0x2000	/* below */
+#define	EAGLE_TXD_PREAMBLE	0x8000
+#define	EAGLE_TXD_PREAMBLE_SHORT 0x8000	/* short preamble */
+#define	EAGLE_TXD_PREAMBLE_LONG 0x0000	/* long preamble */
+	uint16_t	pad;		/* align to 4-byte boundary */
+#define	EAGLE_TXD_FIXED_RATE	0x0100	/* get tx rate from Format */
+#define	EAGLE_TXD_DONT_AGGR	0x0200	/* don't aggregate frame */
+	uint32_t	ack_wcb_addr;
+};
+
+struct mwl_rxdesc {
+	/* control element */
+	uint8_t		RxControl;
+#define	EAGLE_RXD_CTRL_DRIVER_OWN	0x00
+#define	EAGLE_RXD_CTRL_OS_OWN		0x04
+#define	EAGLE_RXD_CTRL_DMA_OWN		0x80
+	/* received signal strengt indication */
+	uint8_t		RSSI;
+	/* status field w/ USED bit */
+	uint8_t		Status;
+#define	EAGLE_RXD_STATUS_IDLE		0x00
+#define	EAGLE_RXD_STATUS_OK		0x01
+#define	EAGLE_RXD_STATUS_MULTICAST_RX	0x02
+#define	EAGLE_RXD_STATUS_BROADCAST_RX	0x04
+#define	EAGLE_RXD_STATUS_FRAGMENT_RX	0x08
+#define	EAGLE_RXD_STATUS_GENERAL_DECRYPT_ERR	0xff
+#define	EAGLE_RXD_STATUS_DECRYPT_ERR_MASK	0x80
+#define	EAGLE_RXD_STATUS_TKIP_MIC_DECRYPT_ERR	0x02
+#define	EAGLE_RXD_STATUS_WEP_ICV_DECRYPT_ERR	0x04
+#define	EAGLE_RXD_STATUS_TKIP_ICV_DECRYPT_ERR	0x08
+	/* channel # pkt received on */
+	uint8_t		Channel;
+	/* total length of received data */
+	uint16_t	PktLen;
+	/* not used */
+	uint8_t		SQ2;
+	/* received data rate */
+	uint8_t		Rate;
+	/* physical address of payload data */
+	uint32_t	pPhysBuffData;
+	/* physical address of next RX desc */
+	uint32_t	pPhysNext;
+	/* received QosCtrl field variable */
+	uint16_t	QosCtrl;
+	/* like name states */
+	uint16_t	HtSig2;
+#ifdef MWL_ANT_INFO_SUPPORT
+	/* antenna info */
+	struct mwl_ant_info ai;
+#endif
+};
+#pragma pack()
+
+
+
+// =============================================================================
+//			HOST COMMAND DEFINITIONS
+// =============================================================================
+
+//
+// Definition of data structure for each command
+//
+// Define general data structure
+#pragma pack(1)
+typedef struct {
+	uint16_t	Cmd;
+	uint16_t	Length;
+#ifdef MWL_MBSS_SUPPORT
+	uint8_t		SeqNum;
+	uint8_t		MacId;
+#else
+	uint16_t	SeqNum;
+#endif
+	uint16_t	Result;
+} FWCmdHdr;
+
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint8_t		annex;
+	uint8_t		index;
+	uint8_t		len;
+	uint8_t		Reserverd;
+#define	CAL_TBL_SIZE	160
+	uint8_t	calTbl[CAL_TBL_SIZE];
+} HostCmd_FW_GET_CALTABLE;
+
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	/* version of the HW */
+	uint8_t		Version;
+	/* host interface */
+	uint8_t		HostIf;
+	/* Max. number of WCB FW can handle */
+	uint16_t	NumOfWCB;
+	/* MaxNbr of MC addresses FW can handle */
+	uint16_t	NumOfMCastAddr;
+	/* MAC address programmed in HW */
+	uint8_t		PermanentAddr[6];
+	uint16_t	RegionCode;
+	/* Number of antenna used */
+	uint16_t	NumberOfAntenna;
+	/* 4 byte of FW release number */
+	uint32_t	FWReleaseNumber;
+	uint32_t	WcbBase0;
+	uint32_t	RxPdWrPtr;
+	uint32_t	RxPdRdPtr;
+	uint32_t	ulFwAwakeCookie;
+	uint32_t	WcbBase1[3];
+} HostCmd_DS_GET_HW_SPEC;
+
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	/* HW revision */
+	uint8_t		Version;
+	/* Host interface */
+	uint8_t		HostIf;
+	/* Max. number of Multicast address FW can handle */
+	uint16_t	NumOfMCastAdr;
+	/* MAC address */
+	uint8_t		PermanentAddr[6];
+	/* Region Code */
+	uint16_t	RegionCode;
+	/* 4 byte of FW release number */
+	uint32_t	FWReleaseNumber;
+	/* Firmware awake cookie */
+	uint32_t	ulFwAwakeCookie;
+	/* Device capabilities (see above) */
+	uint32_t	DeviceCaps;
+	/* Rx shared memory queue */
+	uint32_t	RxPdWrPtr;
+	/* TX queues in WcbBase array */
+	uint32_t	NumTxQueues;
+	/* TX WCB Rings */
+	uint32_t	WcbBase[MAX_TXWCB_QUEUES];
+	uint32_t	Flags;
+#define	SET_HW_SPEC_DISABLEMBSS		0x08
+#define	SET_HW_SPEC_HOSTFORM_BEACON	0x10
+#define	SET_HW_SPEC_HOSTFORM_PROBERESP	0x20
+#define	SET_HW_SPEC_HOST_POWERSAVE	0x40
+#define	SET_HW_SPEC_HOSTENCRDECR_MGMT	0x80
+	uint32_t	TxWcbNumPerQueue;
+	uint32_t	TotalRxWcb;
+}HostCmd_DS_SET_HW_SPEC;
+
+// used for stand alone bssid sets/clears
+typedef struct {
+	FWCmdHdr	CmdHdr;
+#ifdef MWL_MBSS_SUPPORT
+	uint16_t	MacType;
+#define	WL_MAC_TYPE_PRIMARY_CLIENT	0
+#define	WL_MAC_TYPE_SECONDARY_CLIENT	1
+#define	WL_MAC_TYPE_PRIMARY_AP		2
+#define	WL_MAC_TYPE_SECONDARY_AP	3
+#endif
+	uint8_t		MacAddr[6];
+} HostCmd_DS_SET_MAC,
+	HostCmd_FW_SET_BSSID,
+	HostCmd_FW_SET_MAC;
+
+typedef struct {
+	uint32_t	LegacyRateBitMap;
+	uint32_t	HTRateBitMap;
+	uint16_t	CapInfo;
+	uint16_t	HTCapabilitiesInfo;
+	uint8_t		MacHTParamInfo;
+	uint8_t		Rev;
+	struct {
+		uint8_t		ControlChan;
+		uint8_t		AddChan;
+		uint16_t	OpMode;
+		uint16_t	stbc;
+	} AddHtInfo;
+} PeerInfo_t;
+
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint16_t	AID;
+	uint8_t		MacAddr[6];
+	uint16_t	StnId;
+	uint16_t	Action;
+	uint16_t	Reserved;
+	PeerInfo_t	PeerInfo;
+	uint8_t		Qosinfo;
+	uint8_t		isQosSta;
+	uint32_t	FwStaPtr;
+} HostCmd_FW_SET_NEW_STN;
+
+/* Define data structure for HostCmd_CMD_802_11_RF_ANTENNA */
+typedef struct _HostCmd_DS_802_11_RF_ANTENNA {
+	FWCmdHdr	CmdHdr;
+	uint16_t	Action;
+	/* Number of antennas or 0xffff(diversity) */
+	uint16_t	AntennaMode;
+} HostCmd_DS_802_11_RF_ANTENNA;
+
+/* Define data structure for HostCmd_CMD_802_11_RADIO_CONTROL */
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint16_t	Action;
+	/*
+	 *  @bit0: 1/0, on/off
+	 *  @bit1: 1/0, long/short
+	 *  @bit2: 1/0,auto/fix
+	 */
+	uint16_t	Control;
+	uint16_t	RadioOn;
+} HostCmd_DS_802_11_RADIO_CONTROL;
+
+/* for HostCmd_CMD_SET_WMM_MODE */
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	/* 0->unset, 1->set */
+	uint16_t	Action;
+} HostCmd_FW_SetWMMMode;
+
+/* bits 0-5 specify frequency band */
+#define	FREQ_BAND_2DOT4GHZ	0x0001
+#define	FREQ_BAND_4DOT9GHZ	0x0002	/* XXX not implemented */
+#define	FREQ_BAND_5GHZ		0x0004
+#define	FREQ_BAND_5DOT2GHZ	0x0008	/* XXX not implemented */
+/* bits 6-10 specify channel width */
+#define	CH_AUTO_WIDTH		0x0000	/* XXX not used? */
+#define	CH_10_MHz_WIDTH		0x0040
+#define	CH_20_MHz_WIDTH		0x0080
+#define	CH_40_MHz_WIDTH		0x0100
+/* bits 11-12 specify extension channel */
+#define	EXT_CH_NONE		0x0000	/* no extension channel */
+#define	EXT_CH_ABOVE_CTRL_CH	0x0800	/* extension channel above */
+#define	EXT_CH_AUTO		0x1000	/* XXX not used? */
+#define	EXT_CH_BELOW_CTRL_CH	0x1800	/* extension channel below */
+/* bits 13-31 are reserved */
+
+#define	FIXED_RATE_WITH_AUTO_RATE_DROP		0
+#define	FIXED_RATE_WITHOUT_AUTORATE_DROP	1
+
+#define	LEGACY_RATE_TYPE			0
+#define	HT_RATE_TYPE				1
+
+#define	RETRY_COUNT_VALID			0
+#define	RETRY_COUNT_INVALID			1
+
+// Define data structure for HostCmd_CMD_802_11_RF_CHANNEL
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint16_t	Action;
+	uint8_t		CurrentChannel;	/* channel # */
+	uint32_t	ChannelFlags;	/* see below */
+} HostCmd_FW_SET_RF_CHANNEL;
+
+#define	TX_POWER_LEVEL_TOTAL	8
+
+/* Define data structure for HostCmd_CMD_802_11_RF_TX_POWER */
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint16_t	Action;
+	uint16_t	SupportTxPowerLevel;
+	uint16_t	CurrentTxPowerLevel;
+	uint16_t	Reserved;
+	uint16_t	PowerLevelList[TX_POWER_LEVEL_TOTAL];
+} HostCmd_DS_802_11_RF_TX_POWER;
+
+typedef struct {
+	/*
+	 * lower rate after the retry count
+	 * 0: legacy, 1: HT
+	 */
+	uint32_t	FixRateType;
+	/*
+	 *  0: retry count is not valid
+	 *  1: use retry count specified
+	 */
+	uint32_t	RetryCountValid;
+} FIX_RATE_FLAG;
+
+typedef  struct {
+	FIX_RATE_FLAG	FixRateTypeFlags;
+	/* legacy rate(not index) or an MCS code */
+	uint32_t	FixedRate;
+	uint32_t	RetryCount;
+} FIXED_RATE_ENTRY;
+
+typedef  struct {
+	FWCmdHdr	CmdHdr;
+	/*
+	 * HostCmd_ACT_GEN_GET			0x0000
+	 * HostCmd_ACT_GEN_SET 			0x0001
+	 * HostCmd_ACT_NOT_USE_FIXED_RATE	0x0002
+	 */
+	uint32_t	Action;
+	/* use fixed rate specified but firmware can drop */
+	uint32_t	AllowRateDrop;
+	uint32_t	EntryCount;
+	FIXED_RATE_ENTRY FixedRateTable[4];
+	uint8_t		MulticastRate;
+	uint8_t		MultiRateTxType;
+	uint8_t		ManagementRate;
+} HostCmd_FW_USE_FIXED_RATE;
+
+/* Define data structure for HostCmd_CMD_SET_RATE_ADAPT_MODE */
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint16_t	Action;
+	uint16_t	RateAdaptMode;
+} HostCmd_DS_SET_RATE_ADAPT_MODE;
+
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint8_t	OptLevel;
+} HostCmd_FW_SET_OPTIMIZATION_LEVEL;
+
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint16_t	regionCode;
+} HostCmd_SET_REGIONCODE_INFO;
+
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint16_t	Action;	/* 0: Get. 1:Set */
+	uint32_t	Option;	/* 0: default. 1:Aggressive */
+	uint32_t	Threshold;	/* Range 0-200, default 8 */
+} HostCmd_FW_AMPDU_RETRY_RATEDROP_MODE;
+
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint32_t	Enable;	/* 0 -- Disable. or 1 -- Enable */
+} HostCmd_CFEND_ENABLE;
+
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint32_t	Enable;	/* FALSE: Disable or TRUE: Enable */
+} HostCmd_DS_BSS_START;
+
+typedef struct {
+	FWCmdHdr	CmdHdr;
+} HostCmd_FW_SET_INFRA_MODE;
+
+/* used for AID sets/clears */
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint16_t	AssocID;
+	uint8_t		MacAddr[6]; /* AP's Mac Address(BSSID) */
+	uint32_t	GProtection;
+	uint8_t		ApRates[RATE_INDEX_MAX_ARRAY];
+} HostCmd_FW_SET_AID;
+
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint16_t	Action;
+	uint16_t	Threshold;
+} HostCmd_DS_802_11_RTS_THSD;
+
+/* Define data structure for HostCmd_CMD_SET_LINKADAPT_CS_MODE */
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint16_t	Action;
+	uint16_t	CSMode;
+} HostCmd_DS_SET_LINKADAPT_CS_MODE;
+
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint32_t	ActionType; /* ENCR_ACTION_TYPE */
+	uint32_t	DataLength; /* size of the data buffer attached */
+#ifdef MWL_MBSS_SUPPORT
+	uint8_t	macaddr[6];
+#endif
+	uint8_t	ActionData[1];
+} HostCmd_FW_UPDATE_ENCRYPTION;
+
+/*
+ * @HWENCR@
+ * Hardware Encryption related data structures and constant definitions.
+ * Note that all related changes are marked with the @HWENCR@ tag.
+ */
+
+#define	MAX_ENCR_KEY_LENGTH	16	/* max 128 bits - depends on type */
+#define	MIC_KEY_LENGTH		8	/* size of Tx/Rx MIC key - 8 bytes */
+
+#define	ENCR_KEY_TYPE_ID_WEP	0x00	/* Key type is WEP */
+#define	ENCR_KEY_TYPE_ID_TKIP	0x01	/* Key type is TKIP */
+#define	ENCR_KEY_TYPE_ID_AES	0x02	/* Key type is AES-CCMP	*/
+
+/*
+ * flags used in structure - same as driver EKF_XXX flags
+ */
+/* indicate key is in use */
+#define	ENCR_KEY_FLAG_INUSE		0x00000001
+/* Group key for RX only */
+#define	ENCR_KEY_FLAG_RXGROUPKEY	0x00000002
+/* Group key for TX */
+#define	ENCR_KEY_FLAG_TXGROUPKEY	0x00000004
+/* pairwise */
+#define	ENCR_KEY_FLAG_PAIRWISE		0x00000008
+/* only used for RX */
+#define	ENCR_KEY_FLAG_RXONLY		0x00000010
+/*
+ * These flags are new additions - for hardware encryption commands only
+ */
+/* Key is for Authenticator */
+#define	ENCR_KEY_FLAG_AUTHENTICATOR	0x00000020
+/* Sequence counters valid */
+#define	ENCR_KEY_FLAG_TSC_VALID		0x00000040
+/* Tx key for WEP */
+#define	ENCR_KEY_FLAG_WEP_TXKEY		0x01000000
+/* Tx/Rx MIC keys are valid */
+#define	ENCR_KEY_FLAG_MICKEY_VALID	0x02000000
+
+/*
+ * Key material definitions (for WEP, TKIP, & AES-CCMP)
+ */
+
+/*
+ * WEP Key material definition
+ * ----------------------------
+ * WEPKey	--> An array of 'MAX_ENCR_KEY_LENGTH' bytes.
+ * Note that we do not support 152bit WEP keys
+ */
+typedef struct {
+	/* WEP key material (max 128bit) */
+	uint8_t	KeyMaterial[MAX_ENCR_KEY_LENGTH];
+} WEP_TYPE_KEY;
+
+/*
+ * TKIP Key material definition
+ * ----------------------------
+ * This structure defines TKIP key material. Note that
+ * the TxMicKey and RxMicKey may or may not be valid.
+ */
+/*
+ * TKIP Sequence counter - 24 bits
+ * Incremented on each fragment MPDU
+ */
+typedef struct {
+	uint16_t	low;
+	uint32_t	high;
+} ENCR_TKIPSEQCNT;
+
+/*
+ * TKIP Key material. Key type (group or pairwise key) is
+ * determined by flags in KEY_PARAM_SET structure
+ */
+typedef struct {
+	uint8_t		KeyMaterial[MAX_ENCR_KEY_LENGTH];
+	uint8_t		TkipTxMicKey[MIC_KEY_LENGTH];
+	uint8_t		TkipRxMicKey[MIC_KEY_LENGTH];
+	ENCR_TKIPSEQCNT	TkipRsc;
+	ENCR_TKIPSEQCNT	TkipTsc;
+} TKIP_TYPE_KEY;
+
+/*
+ * AES-CCMP Key material definition
+ * --------------------------------
+ * This structure defines AES-CCMP key material.
+ */
+typedef struct {
+	/* AES Key material */
+	uint8_t	KeyMaterial[MAX_ENCR_KEY_LENGTH];
+} AES_TYPE_KEY;
+
+/*
+ * UPDATE_ENCRYPTION command action type.
+ */
+typedef enum {
+	/* request to enable/disable HW encryption */
+	EncrActionEnableHWEncryption,
+	/* request to set encryption key */
+	EncrActionTypeSetKey,
+	/* request to remove one or more keys */
+	EncrActionTypeRemoveKey,
+	EncrActionTypeSetGroupKey
+} ENCR_ACTION_TYPE;
+
+/*
+ * Encryption key definition.
+ * --------------------------
+ * This structure provides all required/essential
+ * information about the key being set/removed.
+ */
+typedef struct {
+	uint16_t	Length;		/* Total length of this structure */
+	uint16_t	KeyTypeId;	/* Key type - WEP, TKIP or AES-CCMP */
+	uint32_t	KeyInfo;	/* key flags */
+	uint32_t	KeyIndex; 	/* For WEP only - actual key index */
+	uint16_t	KeyLen;		/* Size of the key */
+	union {				/* Key material (variable size array) */
+		WEP_TYPE_KEY	WepKey;
+		TKIP_TYPE_KEY	TkipKey;
+		AES_TYPE_KEY	AesKey;
+	} Key;
+#ifdef MWL_MBSS_SUPPORT
+	uint8_t	Macaddr[6];
+#endif
+} KEY_PARAM_SET;
+
+
+typedef struct {
+	FWCmdHdr	CmdHdr;
+	uint32_t	ActionType;	/* ENCR_ACTION_TYPE */
+	uint32_t	DataLength;	/* size of the data buffer attached */
+	KEY_PARAM_SET	KeyParam;
+#ifndef MWL_MBSS_SUPPORT
+	uint8_t		Macaddr[8];
+#endif
+} HostCmd_FW_UPDATE_ENCRYPTION_SET_KEY;
+#pragma pack()
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MWL_REG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/mwl/mwl_var.h	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,878 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
+ * Copyright (c) 2007-2009 Marvell Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * Definitions for the Marvell 88W8363 Wireless LAN controller.
+ */
+
+#ifndef	_MWL_VAR_H
+#define	_MWL_VAR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/note.h>
+#include "mwl_reg.h"
+
+#define	MWL_CMDBUF_SIZE		0x4000	/* size of f/w command buffer */
+#define	MWL_RX_RING_COUNT	256
+#define	MWL_TX_RING_COUNT	256
+
+#ifndef MWL_AGGR_SIZE
+#define	MWL_AGGR_SIZE		3839	/* max tx agregation size */
+#endif
+#define	MWL_AGEINTERVAL		1	/* poke f/w every sec to age q's */
+
+/*
+ * Define total number of TX queues in the shared memory.
+ * This count includes the EDCA queues, Block Ack queues, and HCCA queues
+ * In addition to this, there could be a management packet queue some
+ * time in the future
+ */
+#define	MWL_NUM_EDCA_QUEUES	4
+#define	MWL_NUM_HCCA_QUEUES	0
+#define	MWL_NUM_BA_QUEUES	0
+#define	MWL_NUM_MGMT_QUEUES	0
+#define	MWL_NUM_ACK_QUEUES	0
+#define	MWL_NUM_TX_QUEUES \
+	(MWL_NUM_EDCA_QUEUES + MWL_NUM_HCCA_QUEUES + MWL_NUM_BA_QUEUES + \
+	MWL_NUM_MGMT_QUEUES + MWL_NUM_ACK_QUEUES)
+#define	MWL_MAX_RXWCB_QUEUES	1
+
+#define	MWL_MAX_SUPPORTED_RATES	12
+#define	MWL_MAX_SUPPORTED_MCS	32
+
+#define	PWTAGETRATETABLE20M	14 * 4
+#define	PWTAGETRATETABLE40M	9 * 4
+#define	PWTAGETRATETABLE20M_5G	35 * 4
+#define	PWTAGETRATETABLE40M_5G	16 * 4
+
+#define	MHF_CALDATA	0x0001		/* cal data retrieved */
+#define	MHF_FWHANG	0x0002		/* fw appears hung */
+#define	MHF_MBSS	0x0004		/* mbss enabled */
+
+#define	IEEE80211_CHAN_STURBO	0x00002000 /* 11a static turbo channel only */
+#define	IEEE80211_CHAN_HALF	0x00004000 /* Half rate channel */
+#define	IEEE80211_CHAN_QUARTER	0x00008000 /* Quarter rate channel */
+
+#define	IEEE80211_CHAN_HT20	0x00010000 /* HT 20 channel */
+#define	IEEE80211_CHAN_HT40U	0x00020000 /* HT 40 channel w/ ext above */
+#define	IEEE80211_CHAN_HT40D	0x00040000 /* HT 40 channel w/ ext below */
+
+#define	IEEE80211_CHAN_FHSS \
+	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK)
+#define	IEEE80211_CHAN_A	\
+	(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
+#define	IEEE80211_CHAN_B	\
+	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
+#define	IEEE80211_CHAN_PUREG \
+	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
+#define	IEEE80211_CHAN_G	\
+	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
+#define	IEEE80211_CHAN_HT40	\
+	(IEEE80211_CHAN_HT40U | IEEE80211_CHAN_HT40D)
+#define	IEEE80211_CHAN_HT	\
+	(IEEE80211_CHAN_HT20 | IEEE80211_CHAN_HT40)
+
+#define	IEEE80211_CHAN_108A \
+	(IEEE80211_CHAN_A | IEEE80211_CHAN_TURBO)
+#define	IEEE80211_CHAN_108G \
+	(IEEE80211_CHAN_PUREG | IEEE80211_CHAN_TURBO)
+#define	IEEE80211_CHAN_ST \
+	(IEEE80211_CHAN_108A | IEEE80211_CHAN_STURBO)
+
+#define	IEEE80211_MODE_STURBO_A	7
+#define	IEEE80211_MODE_11NA	8	/* 5GHz, w/ HT */
+#define	IEEE80211_MODE_11NG	9	/* 2GHz, w/ HT */
+#define	IEEE80211_MODE_HALF	10	/* OFDM, 1/2x clock */
+#define	IEEE80211_MODE_QUARTER	11	/* OFDM, 1/4x clock */
+
+
+#define	IEEE80211_IS_CHAN_2GHZ_F(_c) \
+	(((_c)->ic_flags & IEEE80211_CHAN_2GHZ) != 0)
+#define	IEEE80211_IS_CHAN_5GHZ_F(_c) \
+	(((_c)->ic_flags & IEEE80211_CHAN_5GHZ) != 0)
+
+#define	IEEE80211_IS_CHAN_FHSS(_c) \
+	(((_c)->ic_flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS)
+#define	IEEE80211_IS_CHAN_A(_c) \
+	(((_c)->ic_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)
+#define	IEEE80211_IS_CHAN_B(_c) \
+	(((_c)->ic_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)
+#define	IEEE80211_IS_CHAN_PUREG(_c) \
+	(((_c)->ic_flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG)
+#define	IEEE80211_IS_CHAN_G(_c) \
+	(((_c)->ic_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
+#define	IEEE80211_IS_CHAN_ANYG(_c) \
+	(IEEE80211_IS_CHAN_PUREG(_c) || IEEE80211_IS_CHAN_G(_c))
+#define	IEEE80211_IS_CHAN_ST(_c) \
+	(((_c)->ic_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST)
+#define	IEEE80211_IS_CHAN_108A(_c) \
+	(((_c)->ic_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A)
+#define	IEEE80211_IS_CHAN_108G(_c) \
+	(((_c)->ic_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G)
+
+#define	IEEE80211_IS_CHAN_HTA(_c) \
+	(IEEE80211_IS_CHAN_5GHZ_F(_c) && \
+	((_c)->ic_flags & IEEE80211_CHAN_HT) != 0)
+
+#define	IEEE80211_IS_CHAN_HTG(_c) \
+	(IEEE80211_IS_CHAN_2GHZ_F(_c) && \
+	((_c)->ic_flags & IEEE80211_CHAN_HT) != 0)
+
+#define	IEEE80211_IS_CHAN_TURBO(_c) \
+	(((_c)->ic_flags & IEEE80211_CHAN_TURBO) != 0)
+
+#define	IEEE80211_IS_CHAN_HALF(_c) \
+	(((_c)->ic_flags & IEEE80211_CHAN_HALF) != 0)
+
+#define	IEEE80211_IS_CHAN_QUARTER(_c) \
+	(((_c)->ic_flags & IEEE80211_CHAN_QUARTER) != 0)
+
+/* WME stream classes */
+#define	WME_AC_BE	0		/* best effort */
+#define	WME_AC_BK	1		/* background */
+#define	WME_AC_VI	2		/* video */
+#define	WME_AC_VO	3		/* voice */
+
+/*
+ * Transmit queue assignment.
+ */
+enum {
+	MWL_WME_AC_BK	= 0,		/* background access category */
+	MWL_WME_AC_BE	= 1, 		/* best effort access category */
+	MWL_WME_AC_VI	= 2,		/* video access category */
+	MWL_WME_AC_VO	= 3,		/* voice access category */
+};
+
+const char *mwl_wme_acnames[] = {
+	"WME_AC_BE",
+	"WME_AC_BK",
+	"WME_AC_VI",
+	"WME_AC_VO",
+	"WME_UPSD",
+};
+
+/*
+ * Set Antenna Configuration (legacy operation).
+ *
+ * The RX antenna can be selected using the the bitmask
+ * ant (bit 0 = antenna 1, bit 1 = antenna 2, etc.)
+ * (diversity?XXX)
+ */
+typedef enum {
+	WL_ANTENNATYPE_RX = 1,
+	WL_ANTENNATYPE_TX = 2,
+} MWL_HAL_ANTENNA;
+
+/*
+ * Set Radio Configuration.
+ *
+ * onoff != 0 turns radio on; otherwise off.
+ * if radio is enabled, the preamble is set too.
+ */
+typedef enum {
+	WL_LONG_PREAMBLE = 1,
+	WL_SHORT_PREAMBLE = 3,
+	WL_AUTO_PREAMBLE = 5,
+} MWL_HAL_PREAMBLE;
+
+/*
+ * Transmit rate control.  Rate codes with bit 0x80 set are
+ * interpreted as MCS codes (this limits us to 0-127).  The
+ * transmit rate can be set to a single fixed rate or can
+ * be configured to start at an initial rate and drop based
+ * on retry counts.
+ */
+typedef enum {
+	RATE_AUTO	= 0,	/* rate selected by firmware */
+	RATE_FIXED	= 2,	/* rate fixed */
+	RATE_FIXED_DROP	= 1,	/* rate starts fixed but may drop */
+} MWL_HAL_TXRATE_HANDLING;
+
+typedef enum {
+	CSMODE_CONSERVATIVE = 0,
+	CSMODE_AGGRESSIVE = 1,
+	CSMODE_AUTO_ENA = 2,
+	CSMODE_AUTO_DIS = 3,
+} MWL_HAL_CSMODE;
+
+#pragma pack(1)
+
+/*
+ * Device revision information.
+ */
+typedef struct {
+	uint16_t	mh_devid;		/* PCI device ID */
+	uint16_t	mh_subvendorid;		/* PCI subvendor ID */
+	uint16_t	mh_macRev;		/* MAC revision */
+	uint16_t	mh_phyRev;		/* PHY revision */
+} MWL_DIAG_REVS;
+
+typedef struct {
+	uint16_t freqLow;
+	uint16_t freqHigh;
+	int nchannels;
+	struct mwl_hal_channel {
+		uint16_t freq;		/* channel center */
+		uint8_t ieee;		/* channel number */
+		int8_t maxTxPow;	/* max tx power (dBm) */
+		uint8_t targetPowers[4]; /* target powers (dBm) */
+#define	MWL_HAL_MAXCHAN	40
+	} channels[MWL_HAL_MAXCHAN];
+} MWL_HAL_CHANNELINFO;
+
+typedef struct {
+    uint32_t	FreqBand : 6,
+#define	MWL_FREQ_BAND_2DOT4GHZ	0x1
+#define	MWL_FREQ_BAND_5GHZ	0x4
+		ChnlWidth: 5,
+#define	MWL_CH_10_MHz_WIDTH  	0x1
+#define	MWL_CH_20_MHz_WIDTH  	0x2
+#define	MWL_CH_40_MHz_WIDTH  	0x4
+		ExtChnlOffset: 2,
+#define	MWL_EXT_CH_NONE		0x0
+#define	MWL_EXT_CH_ABOVE_CTRL_CH 0x1
+#define	MWL_EXT_CH_BELOW_CTRL_CH 0x3
+		    : 19;		/* reserved */
+} MWL_HAL_CHANNEL_FLAGS;
+
+typedef struct {
+    uint32_t	channel;
+    MWL_HAL_CHANNEL_FLAGS channelFlags;
+} MWL_HAL_CHANNEL;
+
+/*
+ * Channels are specified by frequency and attributes.
+ */
+struct mwl_channel {
+	uint32_t	ic_flags;	/* see below */
+	uint16_t	ic_freq;	/* setting in Mhz */
+	uint8_t		ic_ieee;	/* IEEE channel number */
+	int8_t		ic_maxregpower;	/* maximum regulatory tx power in dBm */
+	int8_t		ic_maxpower;	/* maximum tx power in .5 dBm */
+	int8_t		ic_minpower;	/* minimum tx power in .5 dBm */
+	uint8_t		ic_state;	/* dynamic state */
+	uint8_t		ic_extieee;	/* HT40 extension channel number */
+	int8_t		ic_maxantgain;	/* maximum antenna gain in .5 dBm */
+	uint8_t		ic_pad;
+	uint16_t	ic_devdata;	/* opaque device/driver data */
+};
+
+/*
+ * Regulatory Information.
+ */
+struct mwl_regdomain {
+	uint16_t	regdomain;	/* SKU */
+	uint16_t	country;	/* ISO country code */
+	uint8_t		location;	/* I (indoor), O (outdoor), other */
+	uint8_t		ecm;		/* Extended Channel Mode */
+	char		isocc[2];	/* country code string */
+	short		pad[2];
+};
+
+/*
+ * Get Hardware/Firmware capabilities.
+ */
+struct mwl_hal_hwspec {
+	uint8_t		hwVersion;	/* version of the HW */
+	uint8_t		hostInterface;	/* host interface */
+	uint16_t	maxNumWCB;	/* max # of WCB FW handles */
+	uint16_t	maxNumMCAddr;	/* max # of mcast addresse FW handles */
+	uint16_t	maxNumTxWcb;	/* max # of tx descs per WCB */
+	uint8_t		macAddr[6];	/* MAC address programmed in HW */
+	uint16_t	regionCode;	/* EEPROM region code */
+	uint16_t	numAntennas;	/* Number of antenna used */
+	uint32_t	fwReleaseNumber; /* firmware release number */
+	uint32_t	wcbBase0;
+	uint32_t	rxDescRead;
+	uint32_t	rxDescWrite;
+	uint32_t	ulFwAwakeCookie;
+	uint32_t	wcbBase[MWL_NUM_TX_QUEUES - MWL_NUM_ACK_QUEUES];
+};
+
+/*
+ * Crypto Configuration.
+ */
+typedef struct {
+	uint16_t	pad;
+	uint16_t	keyTypeId;
+#define	KEY_TYPE_ID_WEP		0
+#define	KEY_TYPE_ID_TKIP	1
+#define	KEY_TYPE_ID_AES		2	/* AES-CCMP */
+	uint32_t	keyFlags;
+#define	KEY_FLAG_INUSE		0x00000001	/* indicate key is in use */
+#define	KEY_FLAG_RXGROUPKEY	0x00000002	/* Group key for RX only */
+#define	KEY_FLAG_TXGROUPKEY	0x00000004	/* Group key for TX */
+#define	KEY_FLAG_PAIRWISE	0x00000008	/* pairwise */
+#define	KEY_FLAG_RXONLY		0x00000010	/* only used for RX */
+#define	KEY_FLAG_AUTHENTICATOR	0x00000020	/* Key is for Authenticator */
+#define	KEY_FLAG_TSC_VALID	0x00000040	/* Sequence counters valid */
+#define	KEY_FLAG_WEP_TXKEY	0x01000000	/* Tx key for WEP */
+#define	KEY_FLAG_MICKEY_VALID	0x02000000	/* Tx/Rx MIC keys are valid */
+	uint32_t	keyIndex; 	/* for WEP only; actual key index */
+	uint16_t	keyLen;		/* key size in bytes */
+	union {			/* key material, keyLen gives size */
+		uint8_t	wep[16];	/* enough for 128 bits */
+		uint8_t	aes[16];
+		struct	{
+		    /* NB: group or pairwise key is determined by keyFlags */
+		    uint8_t	keyMaterial[16];
+		    uint8_t	txMic[8];
+		    uint8_t	rxMic[8];
+		    struct {
+			uint16_t	low;
+			uint32_t	high;
+		    } rsc;
+		struct	{
+			uint16_t	low;
+			uint32_t	high;
+		    } tsc;
+		} tkip;
+	} key;
+} MWL_HAL_KEYVAL;
+
+/*
+ * Supply tx/rx dma-related settings to the firmware.
+ */
+struct mwl_hal_txrxdma {
+	uint32_t   maxNumWCB;		/* max # of WCB FW handles */
+	uint32_t   maxNumTxWcb;		/* max # of tx descs per WCB */
+	uint32_t   rxDescRead;
+	uint32_t   rxDescWrite;
+	uint32_t   wcbBase[MWL_NUM_TX_QUEUES - MWL_NUM_ACK_QUEUES];
+};
+
+/*
+ * Inform the firmware of a new association station.
+ * The address is the MAC address of the peer station.
+ * The AID is supplied sans the 0xc000 bits.  The station
+ * ID is defined by the caller.  The peer information must
+ * be supplied.
+ *
+ * NB: All values are in host byte order; any byte swapping
+ *     is handled by the hal.
+ */
+typedef struct {
+	uint32_t LegacyRateBitMap;
+	uint32_t HTRateBitMap;
+	uint16_t CapInfo;
+	uint16_t HTCapabilitiesInfo;
+	uint8_t	MacHTParamInfo;
+	uint8_t	Rev;
+	struct {
+	    uint8_t ControlChan;
+	    uint8_t AddChan;
+	    uint8_t OpMode;
+	    uint8_t stbc;
+	} AddHtInfo;
+} MWL_HAL_PEERINFO;
+
+typedef struct {
+	uint8_t	McastRate;	/* rate for multicast frames */
+#define	RATE_MCS	0x80	/* rate is an MCS index */
+	uint8_t	MgtRate;	/* rate for management frames */
+	struct {
+	    uint8_t TryCount;	/* try this many times */
+	    uint8_t Rate;	/* use this tx rate */
+	} RateSeries[4];	/* rate series */
+} MWL_HAL_TXRATE;
+
+#pragma pack()
+
+/* driver-specific node state */
+struct mwl_node {
+	struct ieee80211_node	mn_node;	/* base class */
+	struct mwl_ant_info	mn_ai;		/* antenna info */
+	uint32_t	mn_avgrssi;	/* average rssi over all rx frames */
+	uint16_t	mn_staid;	/* firmware station id */
+};
+#define	MWL_NODE(ni)		((struct mwl_node *)(ni))
+#define	MWL_NODE_CONST(ni)	((const struct mwl_node *)(ni))
+
+/*
+ * DMA state for tx/rx.
+ */
+
+/*
+ * Software backed version of tx/rx descriptors.  We keep
+ * the software state out of the h/w descriptor structure
+ * so that may be allocated in uncached memory w/o paying
+ * performance hit.
+ */
+struct dma_area {
+	ddi_acc_handle_t	acc_hdl;	/* handle for memory */
+	caddr_t			mem_va;		/* CPU VA of memory */
+	uint32_t		nslots;		/* number of slots */
+	uint32_t		size;		/* size per slot */
+	size_t			alength;	/* allocated size */
+	ddi_dma_handle_t	dma_hdl;	/* DMA handle */
+	offset_t		offset;		/* relative to handle */
+	ddi_dma_cookie_t	cookie;		/* associated cookie */
+	uint32_t		ncookies;	/* must be 1 */
+	uint32_t		token;		/* arbitrary identifier */
+};
+
+struct mwl_rxbuf {
+	struct dma_area		rxbuf_dma;	/* dma area for buf */
+	uint32_t		bf_baddr;
+	uint8_t			*bf_mem;
+	void			*bf_desc;
+	uint32_t		bf_daddr;
+};
+
+struct mwl_rx_ring {
+	struct dma_area		rxdesc_dma;
+	uint32_t		physaddr;
+	struct mwl_rxdesc	*desc;
+	struct mwl_rxbuf	*buf;
+	int			count;
+	int			cur;
+	int			next;
+};
+
+struct mwl_txbuf {
+	struct dma_area		txbuf_dma;
+	uint32_t		bf_baddr;	/* physical addr of buf */
+	uint8_t			*bf_mem;
+	uint32_t		bf_daddr;	/* physical addr of desc */
+	void 			*bf_desc;	/* h/w descriptor */
+	int			bf_nseg;
+	struct ieee80211_node	*bf_node;
+	struct mwl_txq		*bf_txq;	/* backpointer to tx q/ring */
+};
+
+struct mwl_tx_ring {
+	struct dma_area		txdesc_dma;
+	uint32_t		physaddr;
+	struct mwl_txdesc	*desc;
+	struct mwl_txbuf	*buf;
+	int			qnum;	/* f/w q number */
+	int			txpri;	/* f/w tx priority */
+	int			count;
+	int			queued;
+	int			cur;
+	int			next;
+	int			stat;
+};
+
+struct mwl_softc {
+	ieee80211com_t		sc_ic;
+	dev_info_t		*sc_dev;
+
+	/* ddi reg handler */
+	ddi_acc_handle_t	sc_cfg_handle;
+	caddr_t			sc_cfg_base;
+
+	/* bar0 handler */
+	ddi_acc_handle_t	sc_mem_handle;
+	caddr_t			sc_mem_base;
+
+	/* bar1 handler */
+	ddi_acc_handle_t	sc_io_handle;
+	caddr_t			sc_io_base;
+
+	uint16_t		sc_cachelsz;
+	uint32_t		sc_dmabuf_size;
+	uchar_t			sc_macaddr[6];
+
+	struct dma_area		sc_cmd_dma;
+	uint16_t		*sc_cmd_mem;	/* f/w cmd buffer */
+	uint32_t		sc_cmd_dmaaddr;	/* physaddr of cmd buffer */
+
+	int			sc_hw_flags;
+	uint32_t		sc_flags;
+
+	/* SDRAM addr in the chipset */
+	int			sc_SDRAMSIZE_Addr;
+
+	MWL_HAL_CHANNELINFO	sc_20M;
+	MWL_HAL_CHANNELINFO	sc_40M;
+	MWL_HAL_CHANNELINFO	sc_20M_5G;
+	MWL_HAL_CHANNELINFO	sc_40M_5G;
+
+	struct mwl_hal_hwspec	sc_hwspecs;	/* h/w capabilities */
+	MWL_DIAG_REVS		sc_revs;
+
+	int			sc_nchans;	/* # entries in ic_channels */
+	struct mwl_channel 	sc_channels[IEEE80211_CHAN_MAX];
+	struct mwl_channel 	*sc_cur_chan;
+	MWL_HAL_CHANNEL		sc_curchan;
+	struct mwl_regdomain 	sc_regdomain; /* regulatory data */
+
+	struct mwl_rx_ring	sc_rxring;
+	struct mwl_tx_ring	sc_txring[MWL_NUM_TX_QUEUES];
+	struct mwl_tx_ring	*sc_ac2q[5];	/* WME AC -> h/w q map */
+
+	struct mwl_hal_txrxdma	sc_hwdma;	/* h/w dma setup */
+
+	/* interrupt */
+	ddi_iblock_cookie_t	sc_iblock;
+	ddi_softint_handle_t	sc_softintr_hdl;
+	ddi_intr_handle_t	*sc_intr_htable;
+	uint_t			sc_intr_pri;
+	uint32_t		sc_imask;	/* interrupt mask */
+	uint32_t		sc_hal_imask;	/* interrupt mask copy */
+	uint32_t		sc_rx_pend;
+
+	/* mutex lock */
+	kmutex_t		sc_glock;
+	kmutex_t		sc_rxlock;
+	kmutex_t		sc_txlock;
+
+	uint16_t		sc_rxantenna;	/* rx antenna */
+	uint16_t		sc_txantenna;	/* tx antenna */
+
+	timeout_id_t		sc_scan_id;
+
+	/* kstats */
+	uint32_t		sc_tx_nobuf;
+	uint32_t		sc_rx_nobuf;
+	uint32_t		sc_tx_err;
+	uint32_t		sc_rx_err;
+	uint32_t		sc_tx_retries;
+
+	uint32_t		sc_need_sched;
+	uint32_t		sc_rcr;
+
+	int			(*sc_newstate)(struct ieee80211com *,
+				    enum ieee80211_state, int);
+};
+
+#define	mwl_mem_write4(sc, off, x) \
+	ddi_put32((sc)->sc_mem_handle, \
+	(uint32_t *)((sc)->sc_mem_base + (off)), x)
+
+#define	mwl_mem_read4(sc, off) \
+	ddi_get32((sc)->sc_mem_handle, \
+	(uint32_t *)((sc)->sc_mem_base + (off)))
+
+#define	mwl_ctl_write4(sc, off, x) \
+	ddi_put32((sc)->sc_io_handle, \
+	(uint32_t *)((sc)->sc_io_base + (off)), x)
+
+#define	mwl_ctl_read4(sc, off) \
+	ddi_get32((sc)->sc_io_handle, \
+	(uint32_t *)((sc)->sc_io_base + (off)))
+
+#define	mwl_ctl_read1(sc, off) \
+	ddi_get8((sc)->sc_io_handle, \
+	(uint8_t *)((sc)->sc_io_base + (off)))
+
+#define	_CMD_SETUP(pCmd, type, cmd) do {				\
+	pCmd = (type *)&sc->sc_cmd_mem[0];				\
+	memset(pCmd, 0, sizeof (type));					\
+	pCmd->CmdHdr.Cmd = LE_16(cmd);					\
+	pCmd->CmdHdr.Length = LE_16(sizeof (type));			\
+	_NOTE(CONSTCOND)						\
+} while (0)
+
+#define	_VCMD_SETUP(pCmd, type, cmd) do {				\
+	_CMD_SETUP(pCmd, type, cmd);					\
+	pCmd->CmdHdr.MacId = 8;						\
+	_NOTE(CONSTCOND)						\
+} while (0)
+
+#define	MWL_GLOCK(_sc)		mutex_enter(&(_sc)->sc_glock)
+#define	MWL_GUNLOCK(_sc)	mutex_exit(&(_sc)->sc_glock)
+
+#define	MWL_RXLOCK(_sc)		mutex_enter(&(_sc)->sc_rxlock)
+#define	MWL_RXUNLOCK(_sc)	mutex_exit(&(_sc)->sc_rxlock)
+
+#define	MWL_TXLOCK(_sc)		mutex_enter(&(_sc)->sc_txlock)
+#define	MWL_TXUNLOCK(_sc)	mutex_exit(&(_sc)->sc_txlock)
+
+#define	MWL_F_RUNNING		(1 << 0)
+#define	MWL_F_SUSPEND		(1 << 1)
+#define	MWL_F_QUIESCE		(1 << 2)
+
+#define	MWL_RCR_PROMISC		(1 << 0)
+#define	MWL_RCR_MULTI		(1 << 1)
+
+#define	MWL_IS_RUNNING(_sc)	(((_sc)->sc_flags & MWL_F_RUNNING))
+#define	MWL_IS_SUSPEND(_sc)	(((_sc)->sc_flags & MWL_F_SUSPEND))
+#define	MWL_IS_QUIESCE(_sc)	(((_sc)->sc_flags & MWL_F_QUIESCE))
+
+/*
+ * 802.11 regulatory domain definitions.
+ */
+enum ISOCountryCode {
+	CTRY_AFGHANISTAN	= 4,
+	CTRY_ALBANIA		= 8,	/* Albania */
+	CTRY_ALGERIA		= 12,	/* Algeria */
+	CTRY_AMERICAN_SAMOA	= 16,
+	CTRY_ANDORRA		= 20,
+	CTRY_ANGOLA		= 24,
+	CTRY_ANGUILLA		= 660,
+	CTRY_ANTARTICA		= 10,
+	CTRY_ANTIGUA		= 28,	/* Antigua and Barbuda */
+	CTRY_ARGENTINA		= 32,	/* Argentina */
+	CTRY_ARMENIA		= 51,	/* Armenia */
+	CTRY_ARUBA		= 533,	/* Aruba */
+	CTRY_AUSTRALIA		= 36,	/* Australia */
+	CTRY_AUSTRIA		= 40,	/* Austria */
+	CTRY_AZERBAIJAN		= 31,	/* Azerbaijan */
+	CTRY_BAHAMAS		= 44,	/* Bahamas */
+	CTRY_BAHRAIN		= 48,	/* Bahrain */
+	CTRY_BANGLADESH		= 50,	/* Bangladesh */
+	CTRY_BARBADOS		= 52,
+	CTRY_BELARUS		= 112,	/* Belarus */
+	CTRY_BELGIUM		= 56,	/* Belgium */
+	CTRY_BELIZE		= 84,
+	CTRY_BENIN		= 204,
+	CTRY_BERMUDA		= 60,
+	CTRY_BHUTAN		= 64,
+	CTRY_BOLIVIA		= 68,	/* Bolivia */
+	CTRY_BOSNIA_AND_HERZEGOWINA = 70,
+	CTRY_BOTSWANA		= 72,
+	CTRY_BOUVET_ISLAND	= 74,
+	CTRY_BRAZIL		= 76,	/* Brazil */
+	CTRY_BRITISH_INDIAN_OCEAN_TERRITORY = 86,
+	CTRY_BRUNEI_DARUSSALAM	= 96,	/* Brunei Darussalam */
+	CTRY_BULGARIA		= 100,	/* Bulgaria */
+	CTRY_BURKINA_FASO	= 854,
+	CTRY_BURUNDI		= 108,
+	CTRY_CAMBODIA		= 116,
+	CTRY_CAMEROON		= 120,
+	CTRY_CANADA		= 124,	/* Canada */
+	CTRY_CAPE_VERDE		= 132,
+	CTRY_CAYMAN_ISLANDS	= 136,
+	CTRY_CENTRAL_AFRICAN_REPUBLIC = 140,
+	CTRY_CHAD		= 148,
+	CTRY_CHILE		= 152,	/* Chile */
+	CTRY_CHINA		= 156,	/* People's Republic of China */
+	CTRY_CHRISTMAS_ISLAND	= 162,
+	CTRY_COCOS_ISLANDS	= 166,
+	CTRY_COLOMBIA		= 170,	/* Colombia */
+	CTRY_COMOROS		= 174,
+	CTRY_CONGO		= 178,
+	CTRY_COOK_ISLANDS	= 184,
+	CTRY_COSTA_RICA		= 188,	/* Costa Rica */
+	CTRY_COTE_DIVOIRE	= 384,
+	CTRY_CROATIA		= 191,	/* Croatia (local name: Hrvatska) */
+	CTRY_CYPRUS		= 196,	/* Cyprus */
+	CTRY_CZECH		= 203,	/* Czech Republic */
+	CTRY_DENMARK		= 208,	/* Denmark */
+	CTRY_DJIBOUTI		= 262,
+	CTRY_DOMINICA		= 212,
+	CTRY_DOMINICAN_REPUBLIC	= 214,	/* Dominican Republic */
+	CTRY_EAST_TIMOR		= 626,
+	CTRY_ECUADOR		= 218,	/* Ecuador */
+	CTRY_EGYPT		= 818,	/* Egypt */
+	CTRY_EL_SALVADOR	= 222,	/* El Salvador */
+	CTRY_EQUATORIAL_GUINEA	= 226,
+	CTRY_ERITREA		= 232,
+	CTRY_ESTONIA		= 233,	/* Estonia */
+	CTRY_ETHIOPIA		= 210,
+	CTRY_FALKLAND_ISLANDS	= 238,	/* (Malvinas) */
+	CTRY_FAEROE_ISLANDS	= 234,	/* Faeroe Islands */
+	CTRY_FIJI		= 242,
+	CTRY_FINLAND		= 246,	/* Finland */
+	CTRY_FRANCE		= 250,	/* France */
+	CTRY_FRANCE2		= 255,	/* France (Metropolitan) */
+	CTRY_FRENCH_GUIANA	= 254,
+	CTRY_FRENCH_POLYNESIA	= 258,
+	CTRY_FRENCH_SOUTHERN_TERRITORIES	= 260,
+	CTRY_GABON		= 266,
+	CTRY_GAMBIA		= 270,
+	CTRY_GEORGIA		= 268,	/* Georgia */
+	CTRY_GERMANY		= 276,	/* Germany */
+	CTRY_GHANA		= 288,
+	CTRY_GIBRALTAR		= 292,
+	CTRY_GREECE		= 300,	/* Greece */
+	CTRY_GREENLAND		= 304,
+	CTRY_GRENADA		= 308,
+	CTRY_GUADELOUPE		= 312,
+	CTRY_GUAM		= 316,
+	CTRY_GUATEMALA		= 320,	/* Guatemala */
+	CTRY_GUINEA		= 324,
+	CTRY_GUINEA_BISSAU	= 624,
+	CTRY_GUYANA		= 328,
+	/* XXX correct remainder */
+	CTRY_HAITI		= 332,
+	CTRY_HONDURAS		= 340,	/* Honduras */
+	CTRY_HONG_KONG		= 344,	/* Hong Kong S.A.R., P.R.C. */
+	CTRY_HUNGARY		= 348,	/* Hungary */
+	CTRY_ICELAND		= 352,	/* Iceland */
+	CTRY_INDIA		= 356,	/* India */
+	CTRY_INDONESIA		= 360,	/* Indonesia */
+	CTRY_IRAN		= 364,	/* Iran */
+	CTRY_IRAQ		= 368,	/* Iraq */
+	CTRY_IRELAND		= 372,	/* Ireland */
+	CTRY_ISRAEL		= 376,	/* Israel */
+	CTRY_ITALY		= 380,	/* Italy */
+	CTRY_JAMAICA		= 388,	/* Jamaica */
+	CTRY_JAPAN		= 392,	/* Japan */
+	CTRY_JORDAN		= 400,	/* Jordan */
+	CTRY_KAZAKHSTAN		= 398,	/* Kazakhstan */
+	CTRY_KENYA		= 404,	/* Kenya */
+	CTRY_KOREA_NORTH	= 408,	/* North Korea */
+	CTRY_KOREA_ROC		= 410,	/* South Korea */
+	CTRY_KOREA_ROC2		= 411,	/* South Korea */
+	CTRY_KUWAIT		= 414,	/* Kuwait */
+	CTRY_LATVIA		= 428,	/* Latvia */
+	CTRY_LEBANON		= 422,	/* Lebanon */
+	CTRY_LIBYA		= 434,	/* Libya */
+	CTRY_LIECHTENSTEIN	= 438,	/* Liechtenstein */
+	CTRY_LITHUANIA		= 440,	/* Lithuania */
+	CTRY_LUXEMBOURG		= 442,	/* Luxembourg */
+	CTRY_MACAU		= 446,	/* Macau */
+	CTRY_MACEDONIA		= 807,	/* Macedonia */
+	CTRY_MALAYSIA		= 458,	/* Malaysia */
+	CTRY_MALTA		= 470,	/* Malta */
+	CTRY_MEXICO		= 484,	/* Mexico */
+	CTRY_MONACO		= 492,	/* Principality of Monaco */
+	CTRY_MOROCCO		= 504,	/* Morocco */
+	CTRY_NEPAL		= 524,	/* Nepal */
+	CTRY_NETHERLANDS	= 528,	/* Netherlands */
+	CTRY_NEW_ZEALAND	= 554,	/* New Zealand */
+	CTRY_NICARAGUA		= 558,	/* Nicaragua */
+	CTRY_NORWAY		= 578,	/* Norway */
+	CTRY_OMAN		= 512,	/* Oman */
+	CTRY_PAKISTAN		= 586,	/* Islamic Republic of Pakistan */
+	CTRY_PANAMA		= 591,	/* Panama */
+	CTRY_PARAGUAY		= 600,	/* Paraguay */
+	CTRY_PERU		= 604,	/* Peru */
+	CTRY_PHILIPPINES	= 608,	/* Republic of the Philippines */
+	CTRY_POLAND		= 616,	/* Poland */
+	CTRY_PORTUGAL		= 620,	/* Portugal */
+	CTRY_PUERTO_RICO	= 630,	/* Puerto Rico */
+	CTRY_QATAR		= 634,	/* Qatar */
+	CTRY_ROMANIA		= 642,	/* Romania */
+	CTRY_RUSSIA		= 643,	/* Russia */
+	CTRY_SAUDI_ARABIA	= 682,	/* Saudi Arabia */
+	CTRY_SINGAPORE		= 702,	/* Singapore */
+	CTRY_SLOVAKIA		= 703,	/* Slovak Republic */
+	CTRY_SLOVENIA		= 705,	/* Slovenia */
+	CTRY_SOUTH_AFRICA	= 710,	/* South Africa */
+	CTRY_SPAIN		= 724,	/* Spain */
+	CTRY_SRILANKA		= 144,	/* Sri Lanka */
+	CTRY_SWEDEN		= 752,	/* Sweden */
+	CTRY_SWITZERLAND	= 756,	/* Switzerland */
+	CTRY_SYRIA		= 760,	/* Syria */
+	CTRY_TAIWAN		= 158,	/* Taiwan */
+	CTRY_THAILAND		= 764,	/* Thailand */
+	CTRY_TRINIDAD_Y_TOBAGO	= 780,	/* Trinidad y Tobago */
+	CTRY_TUNISIA		= 788,	/* Tunisia */
+	CTRY_TURKEY		= 792,	/* Turkey */
+	CTRY_UAE		= 784,	/* U.A.E. */
+	CTRY_UKRAINE		= 804,	/* Ukraine */
+	CTRY_UNITED_KINGDOM	= 826,	/* United Kingdom */
+	CTRY_UNITED_STATES	= 840,	/* United States */
+	CTRY_URUGUAY		= 858,	/* Uruguay */
+	CTRY_UZBEKISTAN		= 860,	/* Uzbekistan */
+	CTRY_VENEZUELA		= 862,	/* Venezuela */
+	CTRY_VIET_NAM		= 704,	/* Viet Nam */
+	CTRY_YEMEN		= 887,	/* Yemen */
+	CTRY_ZIMBABWE		= 716,	/* Zimbabwe */
+
+	/* NB: from here down not listed in 3166; they come from Atheros */
+	CTRY_DEBUG		= 0x1ff, /* debug */
+	CTRY_DEFAULT		= 0,	 /* default */
+
+	CTRY_UNITED_STATES_FCC49 = 842,	/* United States (Public Safety) */
+	CTRY_KOREA_ROC3		= 412,	/* South Korea */
+
+	CTRY_JAPAN1		= 393,	/* Japan (JP1) */
+	CTRY_JAPAN2		= 394,	/* Japan (JP0) */
+	CTRY_JAPAN3		= 395,	/* Japan (JP1-1) */
+	CTRY_JAPAN4		= 396,	/* Japan (JE1) */
+	CTRY_JAPAN5		= 397,	/* Japan (JE2) */
+	CTRY_JAPAN6		= 399,	/* Japan (JP6) */
+	CTRY_JAPAN7		= 4007,	/* Japan (J7) */
+	CTRY_JAPAN8		= 4008,	/* Japan (J8) */
+	CTRY_JAPAN9		= 4009,	/* Japan (J9) */
+	CTRY_JAPAN10		= 4010,	/* Japan (J10) */
+	CTRY_JAPAN11		= 4011,	/* Japan (J11) */
+	CTRY_JAPAN12		= 4012,	/* Japan (J12) */
+	CTRY_JAPAN13		= 4013,	/* Japan (J13) */
+	CTRY_JAPAN14		= 4014,	/* Japan (J14) */
+	CTRY_JAPAN15		= 4015,	/* Japan (J15) */
+	CTRY_JAPAN16		= 4016,	/* Japan (J16) */
+	CTRY_JAPAN17		= 4017,	/* Japan (J17) */
+	CTRY_JAPAN18		= 4018,	/* Japan (J18) */
+	CTRY_JAPAN19		= 4019,	/* Japan (J19) */
+	CTRY_JAPAN20		= 4020,	/* Japan (J20) */
+	CTRY_JAPAN21		= 4021,	/* Japan (J21) */
+	CTRY_JAPAN22		= 4022,	/* Japan (J22) */
+	CTRY_JAPAN23		= 4023,	/* Japan (J23) */
+	CTRY_JAPAN24		= 4024,	/* Japan (J24) */
+};
+
+enum RegdomainCode {
+	SKU_FCC			= 0x10,	/* FCC, aka United States */
+	SKU_CA			= 0x20,	/* North America, aka Canada */
+	SKU_ETSI		= 0x30,	/* Europe */
+	SKU_ETSI2		= 0x32,	/* Europe w/o HT40 in 5GHz */
+	SKU_ETSI3		= 0x33,	/* Europe - channel 36 */
+	SKU_FCC3		= 0x3a,	/* FCC w/5470 band, 11h, DFS */
+	SKU_JAPAN		= 0x40,
+	SKU_KOREA		= 0x45,
+	SKU_APAC		= 0x50,	/* Asia Pacific */
+	SKU_APAC2		= 0x51,	/* Asia Pacific w/ DFS on mid-band */
+	SKU_APAC3		= 0x5d,	/* Asia Pacific w/o ISM band */
+	SKU_ROW			= 0x81,	/* China/Taiwan/Rest of World */
+	SKU_NONE		= 0xf0,	/* "Region Free" */
+	SKU_DEBUG		= 0x1ff,
+
+	/* NB: from here down private */
+	SKU_SR9			= 0x0298, /* Ubiquiti SR9 (900MHz/GSM) */
+	SKU_XR9			= 0x0299, /* Ubiquiti XR9 (900MHz/GSM) */
+	SKU_GZ901		= 0x029a, /* Zcomax GZ-901 (900MHz/GSM) */
+};
+
+/*
+ * Set regdomain code (IEEE SKU).
+ */
+enum {
+	DOMAIN_CODE_FCC		= 0x10,	/* USA */
+	DOMAIN_CODE_IC		= 0x20,	/* Canda */
+	DOMAIN_CODE_ETSI	= 0x30,	/* Europe */
+	DOMAIN_CODE_SPAIN	= 0x31,	/* Spain */
+	DOMAIN_CODE_FRANCE	= 0x32,	/* France */
+	DOMAIN_CODE_ETSI_131	= 0x130, /* ETSI w/ 1.3.1 radar type */
+	DOMAIN_CODE_MKK		= 0x40,	/* Japan */
+	DOMAIN_CODE_MKK2	= 0x41,	/* Japan w/ 10MHz chan spacing */
+	DOMAIN_CODE_DGT		= 0x80,	/* Taiwan */
+	DOMAIN_CODE_AUS		= 0x81,	/* Australia */
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MWL_VAR_H */
--- a/usr/src/uts/intel/Makefile.intel.shared	Thu Oct 08 10:37:32 2009 +0800
+++ b/usr/src/uts/intel/Makefile.intel.shared	Thu Oct 08 14:27:17 2009 +0800
@@ -277,6 +277,7 @@
 DRV_KMODS	+= mouse8042
 DRV_KMODS	+= mpt_sas
 DRV_KMODS	+= mr_sas
+DRV_KMODS	+= mwl 
 DRV_KMODS	+= nca
 DRV_KMODS	+= nsmb
 DRV_KMODS	+= nulldriver
@@ -610,6 +611,7 @@
 MISC_KMODS	+= ksocket
 MISC_KMODS	+= mac
 MISC_KMODS	+= mii
+MISC_KMODS	+= mwlfw
 MISC_KMODS	+= net80211
 MISC_KMODS	+= nfs_dlboot
 MISC_KMODS	+= nfssrv
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/mwl/Makefile	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,97 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# This makefile drives the production of the rwd driver kernel module.
+#
+# i86pc architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= mwl
+OBJECTS		= $(MWL_OBJS:%=$(OBJS_DIR)/%)
+LINTS           = $(MWL_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+#	Driver depends on GLDv3 & wifi kernel support module.
+#
+LDFLAGS		+= -dy -Nmisc/mac -Nmisc/net80211
+
+#
+#	Overrides
+#
+LINTTAGS	+= -erroff=E_BAD_PTR_CAST_ALIGN
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
+
+#
+#	If you have any special case that general
+#	Makefile rules don't serve for you, just do
+#	it yourself.
+#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/mwlfw/Makefile	Thu Oct 08 14:27:17 2009 +0800
@@ -0,0 +1,116 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+#	This makefile drives the production of the mwlfw kernel module.
+#
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= mwlfw
+OBJECTS		= $(MWLFW_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(MWLFW_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_MISC_DIR)/$(MODULE)
+
+FWOBJ		= $(OBJS_DIR)/$(MODULE).o
+
+OBJECTS		+= $(FWOBJ)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+LDFLAGS	= 
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+# For now, disable these lint checks; maintainers should endeavor
+# to investigate and remove these for maximum lint coverage.
+# Please do not carry these forward to new Makefiles.
+#
+LINTTAGS	+= -erroff=E_BAD_PTR_CAST_ALIGN
+LINTTAGS	+= -erroff=E_PTRDIFF_OVERFLOW
+LINTTAGS	+= -erroff=E_ASSIGN_NARROW_CONV
+LINTTAGS	+= -erroff=E_STATIC_UNUSED
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS) $(FWOBJ)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+		$(RM) $(BINDEST)/$(FWBINCOPY)
+		$(RM) $(BINDEST)/$(BOOTBINCOPY)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+
+# customized section for transforming firmware binary
+ELFWRAP		= elfwrap
+BINSRC		= $(UTSBASE)/common/io/mwl/mwl_fw
+BINDEST		= $(UTSBASE)/intel/mwlfw
+FWBINCOPY	= mw88W8363fw
+BOOTBINCOPY	= mwlboot
+ORIGIN_FWBIN	= mw88W8363
+ORIGIN_BOOTBIN	= mwlboot
+
+#get build type, 32/64
+WRAPTYPE	= $(CLASS:%=-%)
+
+#set elfwrap option
+WRAPOPT		= $(WRAPTYPE:-32=)
+
+$(FWOBJ):
+	cp $(BINSRC)/$(ORIGIN_FWBIN) $(BINDEST)/$(FWBINCOPY)
+	cp $(BINSRC)/$(ORIGIN_BOOTBIN) $(BINDEST)/$(BOOTBINCOPY)
+	$(ELFWRAP) $(WRAPOPT) -o $@ $(BINDEST)/$(FWBINCOPY) $(BINDEST)/$(BOOTBINCOPY)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
+
--- a/usr/src/uts/intel/os/minor_perm	Thu Oct 08 10:37:32 2009 +0800
+++ b/usr/src/uts/intel/os/minor_perm	Thu Oct 08 14:27:17 2009 +0800
@@ -137,6 +137,7 @@
 clone:iwh 0666 root sys
 clone:iwi 0666 root sys
 clone:iwk 0666 root sys
+clone:mwl 0666 root sys
 clone:pcwl 0666 root sys
 clone:pcan 0666 root sys
 clone:ral 0666 root sys
@@ -172,6 +173,7 @@
 iwh:* 0666 root sys
 iwi:* 0666 root sys
 iwk:* 0666 root sys
+mwl:* 0666 root sys
 pcwl:* 0666 root sys
 pcan:* 0666 root sys
 ral:* 0666 root sys