PSARC 2006/394 Solaris audio driver for Munich Workstation
authorfl147353
Thu, 29 Jun 2006 20:57:57 -0700
changeset 2307 0b8abf5d5947
parent 2306 eb8669cd1052
child 2308 a86e1db407c3
PSARC 2006/394 Solaris audio driver for Munich Workstation 6415300 Need ALC880/885 HDA codec support (audio) for NVidia MCP55 chipset
usr/src/pkgdefs/Makefile
usr/src/pkgdefs/SUNWaudh/prototype_i386
usr/src/pkgdefs/SUNWaudiohd/Makefile
usr/src/pkgdefs/SUNWaudiohd/depend
usr/src/pkgdefs/SUNWaudiohd/pkginfo.tmpl
usr/src/pkgdefs/SUNWaudiohd/postinstall
usr/src/pkgdefs/SUNWaudiohd/preremove
usr/src/pkgdefs/SUNWaudiohd/prototype_com
usr/src/pkgdefs/SUNWaudiohd/prototype_i386
usr/src/pkgdefs/etc/exception_list_sparc
usr/src/uts/common/Makefile.files
usr/src/uts/common/Makefile.rules
usr/src/uts/common/io/audio/inc.flg
usr/src/uts/common/io/audio/sada/drv/audiohd/audiohd.c
usr/src/uts/common/io/audio/sada/drv/audiohd/audiohd.conf
usr/src/uts/common/sys/Makefile
usr/src/uts/common/sys/audio/audiohd.h
usr/src/uts/common/sys/audio/impl/audiohd_impl.h
usr/src/uts/i86pc/Makefile.i86pc.shared
usr/src/uts/i86pc/audiohd/Makefile
usr/src/uts/sparc/Makefile.sparc.shared
usr/src/uts/sparc/audiohd/Makefile
usr/src/uts/sparc/audiohd/audiohd.wlcmd
usr/src/uts/sparc/audiohd/audiohd_with_sada.wlcmd
usr/src/uts/sparc/warlock/Makefile
--- a/usr/src/pkgdefs/Makefile	Thu Jun 29 15:21:59 2006 -0700
+++ b/usr/src/pkgdefs/Makefile	Thu Jun 29 20:57:57 2006 -0700
@@ -106,6 +106,7 @@
 	SUNWagph \
 	SUNWamr \
 	SUNWatheros \
+	SUNWaudiohd \
 	SUNWcakr.i \
 	SUNWcar.i  \
 	SUNWcpc.i \
--- a/usr/src/pkgdefs/SUNWaudh/prototype_i386	Thu Jun 29 15:21:59 2006 -0700
+++ b/usr/src/pkgdefs/SUNWaudh/prototype_i386	Thu Jun 29 20:57:57 2006 -0700
@@ -47,5 +47,6 @@
 # SUNWaudh
 #
 f none usr/include/sys/audio/audio810.h 644 root bin
+f none usr/include/sys/audio/audiohd.h 644 root bin
 f none usr/include/sys/audio/audioixp.h 644 root bin
 f none usr/include/sys/audio/audiovia823x.h 644 root bin
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWaudiohd/Makefile	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,36 @@
+#
+# 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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.com
+
+
+.KEEP_STATE:
+
+all: $(FILES) depend postinstall preremove
+install: all pkg
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWaudiohd/depend	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,53 @@
+#
+# 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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This package information file defines software dependencies associated
+# with the pkg.  You can define three types of pkg dependencies with this file:
+#	 P indicates a prerequisite for installation
+#	 I indicates an incompatible package
+#	 R indicates a reverse dependency
+# <pkg.abbr> see pkginfo(4), PKG parameter
+# <name> see pkginfo(4), NAME parameter
+# <version> see pkginfo(4), VERSION parameter
+# <arch> see pkginfo(4), ARCH parameter
+# <type> <pkg.abbr> <name>
+# 	(<arch>)<version>
+# 	(<arch>)<version>
+# 	...
+# <type> <pkg.abbr> <name>
+# ...
+#
+
+P SUNWcar	Core Architecture, (Root)
+P SUNWcakr	Core Solaris Kernel Architecture (Root)
+P SUNWkvm	Core Architecture, (Kvm)
+P SUNWcsr	Core Solaris, (Root)
+P SUNWckr	Core Solaris Kernel (Root)
+P SUNWcnetr	Core Solaris Network Infrastructure (Root)
+P SUNWcsu	Core Solaris, (Usr)
+P SUNWcsd	Core Solaris Devices
+P SUNWcsl	Core Solaris Libraries
+P SUNWaudd	Audio Drivers
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWaudiohd/pkginfo.tmpl	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,59 @@
+#
+# 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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+#
+# This required package information file describes characteristics of the
+# package, such as package abbreviation, full package name, package version,
+# and package architecture.
+#
+PKG="SUNWaudiohd"
+NAME="SUNW High Definition Audio Drivers"
+ARCH="ISA"
+VERSION="ONVERS,REV=0.0.0"
+CATEGORY="system"
+DESC="SunOS audio device driver for Munich workstation"
+SUNW_PRODNAME="SunOS"
+SUNW_PRODVERS="RELEASE/VERSION"
+SUNW_PKGTYPE="root"
+MAXINST="1000"
+VENDOR="Sun Microsystems, Inc."
+HOTLINE="Please contact your local service provider"
+EMAIL=""
+CLASSES="none"
+BASEDIR=/
+SUNW_PKGVERS="1.0"
+SUNW_PKG_ALLZONES="true"
+SUNW_PKG_HOLLOW="true"
+SUNW_PKG_THISZONE="false"
+#VSTOCK="<reserved by Release Engineering for package part #>"
+#ISTATES="<developer defined>"
+#RSTATES='<developer defined>'
+#ULIMIT="<developer defined>"
+#ORDER="<developer defined>"
+#PSTAMP="<developer defined>"
+#INTONLY="<developer defined>"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWaudiohd/postinstall	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,55 @@
+#! /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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# SUNWaudiohd postinstall script
+
+PATH=/usr/bin:/usr/sbin:${PATH}
+export PATH
+
+not_installed() {
+	driver=$1
+	grep "^${driver} " $BASEDIR/etc/name_to_major > /dev/null 2>&1
+	return $?
+}
+
+EXIT=0
+
+AUDIOHD_ALIASES="\
+	\"pci8086,2668\" \
+	\"pci10de,371\" \
+	"
+	
+case "${ARCH}" in
+	i386)
+		not_installed audiohd || \
+		add_drv -b "${BASEDIR}" -i "${AUDIOHD_ALIASES}" -n audiohd || \
+		EXIT=1
+
+	;;
+esac
+
+exit ${EXIT}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWaudiohd/preremove	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,51 @@
+#! /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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# SUNWaudiohd preremove script
+
+PATH=/usr/bin:/usr/sbin:${PATH}
+export PATH
+
+EXIT=0
+
+installed() {
+	driver=$1
+	grep "^${driver} " $BASEDIR/etc/name_to_major > /dev/null 2>&1
+	if [ "$?" -eq 0 ]; then
+		return 1
+	else
+		return 0
+	fi
+}
+
+case "${ARCH}" in
+	i386)
+		installed audiohd || rem_drv -b ${BASEDIR} audiohd || EXIT=1
+	;;
+esac
+
+exit ${EXIT}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWaudiohd/prototype_com	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,47 @@
+#
+# 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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# 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
+
+# packaging files
+i pkginfo
+i copyright
+i depend
+i postinstall
+i preremove
+#
+# source locations relative to the prototype file
+#
+# SUNWaudiohd
+#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWaudiohd/prototype_i386	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,53 @@
+#
+# 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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# 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
+
+#
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+#
+# List files which are i386 specific here
+#
+# source locations relative to the prototype file
+#
+# SUNWaudiohd
+#
+d none kernel 755 root sys
+d none kernel/drv 755 root sys
+f none kernel/drv/audiohd 755 root sys
+f none kernel/drv/audiohd.conf 644 root sys
+d none kernel/drv/amd64 755 root sys
+f none kernel/drv/amd64/audiohd 755 root sys
--- a/usr/src/pkgdefs/etc/exception_list_sparc	Thu Jun 29 15:21:59 2006 -0700
+++ b/usr/src/pkgdefs/etc/exception_list_sparc	Thu Jun 29 20:57:57 2006 -0700
@@ -779,6 +779,11 @@
 kernel/drv/sparcv9/audio810			sparc
 kernel/drv/audio810.conf			sparc 
 #
+# High definition audio driver doesn't ship in sparc platform.
+#
+kernel/drv/sparcv9/audiohd			sparc
+kernel/drv/audiohd.conf			sparc 
+#
 # ATI IXP audio driver doesn't ship in sparc platform.
 #
 kernel/drv/sparcv9/audioixp			sparc
--- a/usr/src/uts/common/Makefile.files	Thu Jun 29 15:21:59 2006 -0700
+++ b/usr/src/uts/common/Makefile.files	Thu Jun 29 20:57:57 2006 -0700
@@ -372,6 +372,8 @@
 
 AUDIO810_OBJS += audio810.o
 
+AUDIOHD_OBJS +=	audiohd.o
+
 AUDIOTS_OBJS +=	audiots.o
 
 CARDBUS_OBJS += cardbus.o cardbus_hp.o cardbus_cfg.o
--- a/usr/src/uts/common/Makefile.rules	Thu Jun 29 15:21:59 2006 -0700
+++ b/usr/src/uts/common/Makefile.rules	Thu Jun 29 20:57:57 2006 -0700
@@ -428,6 +428,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/audio/sada/drv/audiohd/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/audio/sada/drv/audiots/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -1159,6 +1163,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/audio/sada/drv/audio810/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/audio/sada/drv/audiohd/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/audio/sada/drv/audiots/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- a/usr/src/uts/common/io/audio/inc.flg	Thu Jun 29 15:21:59 2006 -0700
+++ b/usr/src/uts/common/io/audio/inc.flg	Thu Jun 29 20:57:57 2006 -0700
@@ -21,7 +21,7 @@
 #
 
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -76,11 +76,13 @@
 	usr/src/uts/sparc/audiots	\
 	usr/src/uts/sparc/audio810	\
 	usr/src/uts/sparc/audio1575	\
+	usr/src/uts/sparc/audiohd	\
 	usr/src/uts/sparc/audiosup	\
 	usr/src/uts/sparc/mixer		\
 	usr/src/uts/sparc/amsrc2	\
 	usr/src/uts/sparc/diaudio	\
 	usr/src/uts/i86pc/audio810	\
+	usr/src/uts/i86pc/audiohd	\
 	usr/src/uts/intel/audiosup	\
 	usr/src/uts/intel/mixer		\
 	usr/src/uts/intel/diaudio
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/audio/sada/drv/audiohd/audiohd.c	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,2673 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * The audiohd driver provides functionality for playing audio on
+ * the nVidia MCP55 high-definition audio controller with Realtek
+ * ALC88x codec. This enables basic audio functionality for Sun's
+ * 2006 line of new workstations and PCs, which are MCP55-based
+ * with Realtek ALC88x codec. Due to short time constraints on the
+ * production of this software kernel module, we used a minimalistic
+ * approach to only provide audio play functionality for just the
+ * nVidia HD audio controller and the Realtek ALC880, ALC883 and
+ * ALC885  codecs.  Certainly, the driver may work and attach to
+ * Intel High-Definition audio devices which have same the Realtek
+ * Codec.
+ *
+ * HD audio supports multiple streams, each of which can act as an
+ * independent device. However, we just support two streams: the
+ * first input stream for recording, and the first output stream
+ * for playback. And because ALC880 doesn't support sample rates
+ * below 48K (except 44.1K), this driver just supports 48K sample
+ * rate in compatible mode.
+ */
+#include <sys/types.h>
+#include <sys/modctl.h>
+#include <sys/conf.h>
+#include <sys/devops.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/note.h>
+#include <sys/pci.h>
+#include <sys/audio.h>
+#include <sys/audiovar.h>
+#include <sys/audio/audio_trace.h>
+#include <sys/audio/audio_support.h>
+#include <sys/audio/audio_src.h>
+#include <sys/mixer.h>
+#include <sys/audio/audio_mixer.h>
+#include <sys/audio/am_src2.h>
+#include <sys/audio/audiohd.h>
+#include <sys/audio/impl/audiohd_impl.h>
+
+/*
+ * Module linkage routines for the kernel
+ */
+static int audiohd_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int audiohd_attach(dev_info_t *, ddi_attach_cmd_t);
+static int audiohd_detach(dev_info_t *, ddi_detach_cmd_t);
+
+/*
+ * Entry point routine prototypes
+ */
+static int audiohd_ad_set_config(audiohdl_t, int, int, int, int, int);
+static int audiohd_ad_set_format(audiohdl_t, int, int, int, int, int, int);
+static int audiohd_ad_start_play(audiohdl_t, int);
+static int audiohd_ad_start_record(audiohdl_t, int);
+static void audiohd_ad_pause_play(audiohdl_t, int);
+static void audiohd_ad_stop_play(audiohdl_t, int);
+static void audiohd_ad_stop_record(audiohdl_t, int);
+
+/* interrupt handler */
+static uint_t audiohd_intr(caddr_t);
+
+/*
+ * Local routines
+ */
+static int audiohd_init_state(audiohd_state_t *, dev_info_t *);
+static int audiohd_init_pci(audiohd_state_t *, ddi_device_acc_attr_t *);
+static void audiohd_fini_pci(audiohd_state_t *);
+static int audiohd_reset_controller(audiohd_state_t *);
+static int audiohd_init_controller(audiohd_state_t *);
+static void audiohd_fini_controller(audiohd_state_t *);
+static void audiohd_stop_dma(audiohd_state_t *);
+static void audiohd_disable_intr(audiohd_state_t *);
+static int audiohd_create_codec(audiohd_state_t *);
+static void audiohd_destroy_codec(audiohd_state_t *);
+static int audiohd_reset_stream(audiohd_state_t	*, int);
+static int audiohd_fill_pbuf(audiohd_state_t *);
+static void audiohd_refill_pbuf(audiohd_state_t *);
+static void audiohd_preset_rbuf(audiohd_state_t *);
+static void audiohd_get_rbuf(audiohd_state_t *);
+static int audiohd_set_gain(audiohd_state_t *, int, int, int);
+static int audiohd_set_port(audiohd_state_t *, int, int);
+static void audiohd_mute_outputs(audiohd_state_t *, boolean_t);
+static int audiohd_set_monitor_gain(audiohd_state_t *, int);
+static int audiohd_alloc_dma_mem(audiohd_state_t *, audiohd_dma_t *,
+    size_t, ddi_dma_attr_t *, uint_t);
+
+static uint32_t audioha_codec_verb_get(void *, uint8_t,
+    uint8_t, uint16_t, uint8_t);
+static uint32_t audioha_codec_4bit_verb_get(void *, uint8_t,
+    uint8_t, uint16_t, uint16_t);
+
+/*
+ * operation routines for ALC88x codec
+ */
+static int audiohd_alc880_enable_play(audiohd_state_t *);
+static int audiohd_alc880_enable_record(audiohd_state_t *);
+static int audiohd_alc880_set_pcm_fmt(audiohd_state_t *, int, uint_t);
+static int audiohd_alc880_set_gain(audiohd_state_t *, int, int, int);
+static int audiohd_alc880_set_port(audiohd_state_t *, int, int);
+static int audiohd_alc880_mute_outputs(audiohd_state_t *, boolean_t);
+static int audiohd_alc880_set_monitor_gain(audiohd_state_t *, int);
+
+/* ops for ALC880 */
+static struct audiohd_codec_ops audiohd_alc880_ops = {
+	audiohd_alc880_enable_play,	/* ac_enable_play */
+	audiohd_alc880_enable_record,	/* ac_enable_record */
+	audiohd_alc880_set_pcm_fmt,	/* ac_set_pcm_fmt */
+	audiohd_alc880_set_gain,	/* ac_set_out_gain */
+	audiohd_alc880_set_port,	/* ac_set_port */
+	audiohd_alc880_mute_outputs,	/* ac_mute_outputs */
+	audiohd_alc880_set_monitor_gain	/* ac_set_monitor_gain */
+};
+
+/* anchor for soft state structures */
+static void *audiohd_statep;
+
+/* driver name */
+static char *audiohd_name = AUDIOHD_NAME;
+
+static uint_t audiohd_mixer_srs[] = {
+	AUDIOHD_SAMPR5510, AUDIOHD_SAMPR48000, 0
+};
+
+static uint_t audiohd_comp_srs[] = {
+	AUDIOHD_SAMPR48000,
+	0
+};
+
+static am_ad_sample_rates_t audiohd_mixer_sample_rates = {
+	MIXER_SRS_FLAG_SR_LIMITS,
+	audiohd_mixer_srs
+};
+
+static am_ad_sample_rates_t audiohd_comp_sample_rates = {
+	MIXER_SRS_FLAG_SR_NOT_LIMITS,
+	audiohd_comp_srs
+};
+
+static uint_t audiohd_channels[] = {
+	AUDIO_CHANNELS_STEREO,
+	0
+};
+
+static am_ad_cap_comb_t audiohd_combinations[] = {
+	{ AUDIO_PRECISION_16, AUDIO_ENCODING_LINEAR },
+	{ 0 }
+};
+
+static ddi_device_acc_attr_t hda_dev_accattr = {
+	DDI_DEVICE_ATTR_V0,
+	DDI_STRUCTURE_LE_ACC,
+	DDI_STRICTORDER_ACC
+};
+
+/* STREAMS driver id and limit value struct */
+static struct module_info audiohd_modinfo = {
+	AUDIOHD_IDNUM,
+	AUDIOHD_NAME,
+	AUDIOHD_MINPACKET,
+	AUDIOHD_MAXPACKET,
+	AUDIOHD_HIWATER,
+	AUDIOHD_LOWATER,
+};
+
+/* STREAMS queue processing procedures structures for read queue */
+static struct qinit audiohd_rqueue = {
+	audio_sup_rput,
+	audio_sup_rsvc,
+	audio_sup_open,
+	audio_sup_close,
+	NULL,
+	&audiohd_modinfo,
+	NULL,
+};
+
+/* STREAMS queue processing procedures structures for write queue */
+static struct qinit audiohd_wqueue = {
+	audio_sup_wput,
+	audio_sup_wsvc,
+	NULL,
+	NULL,
+	NULL,
+	&audiohd_modinfo,
+	NULL
+};
+
+/* STREAMS entity declaration structure */
+static struct streamtab audiohd_streamtab = {
+	&audiohd_rqueue,
+	&audiohd_wqueue,
+	NULL,
+	NULL,
+};
+
+/* Entry points structure */
+static struct cb_ops audiohd_cb_ops = {
+	nulldev,		/* cb_open */
+	nulldev,		/* cb_close */
+	nodev,			/* cb_strategy */
+	nodev,			/* cb_print */
+	nodev,			/* cb_dump */
+	nodev,			/* cb_read */
+	nodev,			/* cb_write */
+	nodev,			/* cb_ioctl */
+	nodev,			/* cb_devmap */
+	nodev,			/* cb_mmap */
+	nodev,			/* cb_segmap */
+	nochpoll,		/* cb_chpoll */
+	ddi_prop_op,		/* cb_prop_op */
+	&audiohd_streamtab,		/* cb_str */
+	D_NEW | D_MP | D_64BIT,	/* cb_flag */
+	CB_REV,			/* cb_rev */
+	nodev,			/* cb_aread */
+	nodev			/* cb_awrite */
+};
+
+/* Device operations structure */
+static struct dev_ops audiohd_dev_ops = {
+	DEVO_REV,		/* devo_rev */
+	0,			/* devo_refcnt */
+	audiohd_getinfo,	/* devo_getinfo */
+	nulldev,		/* devo_identify */
+	nulldev,		/* devo_probe */
+	audiohd_attach,		/* devo_attach */
+	audiohd_detach,		/* devo_detach */
+	nodev,			/* devo_reset */
+	&audiohd_cb_ops,		/* devo_cb_ops */
+	NULL,			/* devo_bus_ops */
+	NULL			/* devo_power */
+};
+
+/* Linkage structure for loadable drivers */
+static struct modldrv audiohd_modldrv = {
+	&mod_driverops,		/* drv_modops */
+	AUDIOHD_MOD_NAME"%I%",		/* drv_linkinfo */
+	&audiohd_dev_ops,		/* drv_dev_ops */
+};
+
+/* Module linkage structure */
+static struct modlinkage audiohd_modlinkage = {
+	MODREV_1,			/* ml_rev */
+	(void *)&audiohd_modldrv,	/* ml_linkage */
+	NULL				/* NULL */
+};
+
+
+/*
+ * Audio driver ops vector for mixer
+ */
+static am_ad_entry_t audiohd_entry = {
+	NULL,				/* ad_setup() */
+	NULL,				/* ad_teardown() */
+	audiohd_ad_set_config,		/* ad_set_config() */
+	audiohd_ad_set_format,		/* ad_set_format() */
+	audiohd_ad_start_play,		/* ad_start_play() */
+	audiohd_ad_pause_play,		/* ad_pause_play() */
+	audiohd_ad_stop_play,		/* ad_stop_play() */
+	audiohd_ad_start_record,	/* ad_start_record() */
+	audiohd_ad_stop_record,		/* ad_stop_record() */
+	NULL,				/* ad_ioctl() */
+	NULL				/* ad_iocdata() */
+};
+
+int
+_init(void)
+{
+	int error;
+
+	if ((error = ddi_soft_state_init(&audiohd_statep,
+	    sizeof (audiohd_state_t), 1)) != 0) {
+		return (error);
+	}
+
+	if ((error = mod_install(&audiohd_modlinkage)) != 0) {
+		ddi_soft_state_fini(&audiohd_statep);
+	}
+
+	return (error);
+
+}	/* _init() */
+
+
+int
+_fini(void)
+{
+	int error;
+
+	if ((error = mod_remove(&audiohd_modlinkage)) != 0) {
+		return (error);
+	}
+
+	ddi_soft_state_fini(&audiohd_statep);
+
+	return (0);
+
+}	/* _fini() */
+
+
+int
+_info(struct modinfo *modinfop)
+{
+	int error;
+
+	error = mod_info(&audiohd_modlinkage, modinfop);
+
+	return (error);
+
+}	/* _info() */
+
+
+int
+audiohd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
+{
+	audiohd_state_t	*statep;
+	int		instance;
+	int		error;
+
+	ATRACE("in audiohd_getinfo()", dip);
+	error = DDI_FAILURE;
+	switch (cmd) {
+	case DDI_INFO_DEVT2DEVINFO:
+		instance = audio_sup_devt_to_instance((dev_t)arg);
+		if ((statep = ddi_get_soft_state(audiohd_statep,
+		    instance)) != NULL) {
+			*result = statep->hda_dip;
+			error = DDI_SUCCESS;
+		} else {
+			*result = NULL;
+		}
+		break;
+
+	case DDI_INFO_DEVT2INSTANCE:
+		*result = (void *)(uintptr_t)
+		    audio_sup_devt_to_instance((dev_t)arg);
+		error = DDI_SUCCESS;
+		break;
+
+	default:
+		break;
+	}
+
+	return (error);
+
+}	/* audiohd_getinfo() */
+
+/*
+ * audiohd_attach()
+ *
+ * Arguments:
+ * 	dev_info_t  *dip    Pointer to the device's dev_info struct
+ *	ddi_attach_cmd_t cmd    Attach command
+ *
+ * Returns:
+ *	DDI_SUCCESS		The driver was initialized properly
+ *	DDI_FAILURE		The driver couldn't be initialized properly
+ */
+int
+audiohd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	audio_sup_reg_data_t		data;
+	audiohd_state_t		*statep;
+	int			instance;
+
+	instance = ddi_get_instance(dip);
+	switch (cmd) {
+	case DDI_ATTACH:
+		break;
+
+	case DDI_RESUME:
+		ATRACE("audiohd_attach() DDI_RESUME", NULL);
+		return (DDI_FAILURE);
+
+	default:
+		return (DDI_FAILURE);
+	}
+
+	/* High-level interrupt isn't supported by this driver */
+	if (ddi_intr_hilevel(dip, 0) != 0) {
+		audio_sup_log(NULL, CE_WARN,
+		    "!%s%d: audiohd_attach() unsupported high level interrupt",
+		    audiohd_name, instance);
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_soft_state_zalloc(audiohd_statep, instance) != DDI_SUCCESS) {
+		audio_sup_log(NULL, CE_WARN,
+		    "!%s%d: audiohd_attach() softstate alloc failed",
+		    audiohd_name, instance);
+		return (DDI_FAILURE);
+	}
+
+	if ((statep = ddi_get_soft_state(audiohd_statep, instance)) == NULL) {
+		audio_sup_log(NULL, CE_WARN,
+		    "!%s%d: audiohd_attach() no softstate",
+		    audiohd_name, instance);
+		goto err_attach_exit1;
+	}
+
+	data.asrd_version = AUDIOSUP_VERSION;
+	data.asrd_key = NULL;
+	if ((statep->hda_ahandle = audio_sup_register(dip, &data)) == NULL) {
+		audio_sup_log(NULL, CE_WARN,
+		    "!%s%d: audiohd_attach() audio_sup_register() failed",
+		    audiohd_name, instance);
+		goto err_attach_exit2;
+	}
+
+	/* save private state */
+	audio_sup_set_private(statep->hda_ahandle, statep);
+
+	/* interrupt cookie and initilize mutex */
+	if (audiohd_init_state(statep, dip) != AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!audiohd_attach() audiohd_init_state failed");
+		goto err_attach_exit3;
+	}
+
+	/* Set PCI command register to enable bus master and memeory I/O */
+	if (audiohd_init_pci(statep, &hda_dev_accattr) != AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!audiohd_attach() couldn't init pci regs");
+		goto err_attach_exit4;
+	}
+
+	if (audiohd_init_controller(statep) != AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!audiohd_attach() counldn't init controller");
+		goto err_attach_exit5;
+	}
+
+	if (audiohd_create_codec(statep) != AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!audiohd_attach() counldn't create codec");
+		goto err_attach_exit6;
+	}
+
+	/*
+	 * This is a workaround. ALC880 doesn't support 8k sample rate,
+	 * but solaris requires hardware to be set to 8K by default. This
+	 * checking is performed in am_attach(). To overcome this flaw,
+	 * we have to set default sample to 48K before calling am_attach().
+	 * After we fix bug 6363625 in near future, we will change this
+	 * and set sample rate to 8K by default.
+	 */
+	statep->hda_info_defaults.play.sample_rate = audiohd_comp_srs[0];
+	statep->hda_info_defaults.record.sample_rate = audiohd_comp_srs[0];
+
+	if (am_attach(statep->hda_ahandle, cmd, &statep->hda_ad_info) !=
+	    AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!attach() am_attach() failed");
+		goto err_attach_exit7;
+	}
+
+	/* set up kernel statistics */
+	if ((statep->hda_ksp = kstat_create(AUDIOHD_NAME, instance,
+	    AUDIOHD_NAME, "controller", KSTAT_TYPE_INTR, 1,
+	    KSTAT_FLAG_PERSISTENT)) != NULL) {
+		kstat_install(statep->hda_ksp);
+	}
+
+	/* disable interrupts and clear interrupt status */
+	audiohd_disable_intr(statep);
+
+	/* set up the interrupt handler */
+	if (ddi_add_intr(dip, 0, &statep->hda_intr_cookie,
+	    (ddi_idevice_cookie_t *)NULL, audiohd_intr, (caddr_t)statep) !=
+	    DDI_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!attach() bad interrupt specification ");
+		goto err_attach_exit8;
+	}
+	ddi_report_dev(dip);
+
+	/* enable interrupt */
+	AUDIOHD_REG_SET32(AUDIOHD_REG_INTCTL,
+	    AUDIOHD_INTCTL_BIT_GIE | AUDIOHD_INTCTL_BIT_SIE);
+
+	return (DDI_SUCCESS);
+
+err_attach_exit8:
+	if (statep->hda_ksp)
+		kstat_delete(statep->hda_ksp);
+	(void) am_detach(statep->hda_ahandle, DDI_DETACH);
+
+err_attach_exit7:
+	audiohd_destroy_codec(statep);
+
+err_attach_exit6:
+	audiohd_fini_controller(statep);
+
+err_attach_exit5:
+	audiohd_fini_pci(statep);
+
+err_attach_exit4:
+	mutex_destroy(&statep->hda_mutex);
+
+err_attach_exit3:
+	(void) audio_sup_unregister(statep->hda_ahandle);
+
+err_attach_exit2:
+err_attach_exit1:
+	ddi_soft_state_free(audiohd_statep, instance);
+
+	return (DDI_FAILURE);
+
+}	/* audiohd_attach() */
+
+/*
+ * audiohd_detach()
+ * Arguments:
+ *	dev_info_t		*dip	Pointer to the device's dev_info struct
+ *	ddi_detach_cmd_t	cmd	Detach command
+ *
+ * Returns:
+ *	DDI_SUCCESS		The driver was detached
+ *	DDI_FAILURE		The driver couldn't be detached
+ */
+int
+audiohd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	audiohd_state_t		*statep;
+	int			instance;
+
+	instance = ddi_get_instance(dip);
+
+	if ((statep = ddi_get_soft_state(audiohd_statep, instance)) == NULL) {
+		return (DDI_FAILURE);
+	}
+
+	switch (cmd) {
+	case DDI_DETACH:
+		break;
+
+	case DDI_SUSPEND:
+		return (DDI_FAILURE);
+
+	default:
+		return (DDI_FAILURE);
+	}
+
+	mutex_enter(&statep->hda_mutex);
+	audiohd_stop_dma(statep);
+	audiohd_disable_intr(statep);
+	mutex_exit(&statep->hda_mutex);
+	ddi_remove_intr(dip, 0, statep->hda_intr_cookie);
+	if (statep->hda_ksp)
+		kstat_delete(statep->hda_ksp);
+	(void) am_detach(statep->hda_ahandle, DDI_DETACH);
+	audiohd_destroy_codec(statep);
+	audiohd_fini_controller(statep);
+	audiohd_fini_pci(statep);
+	mutex_destroy(&statep->hda_mutex);
+	(void) audio_sup_unregister(statep->hda_ahandle);
+	ddi_soft_state_free(audiohd_statep, instance);
+
+	return (DDI_SUCCESS);
+
+}	/* audiohd_detach() */
+
+/*
+ * audiohd_intr()
+ *
+ * Description
+ *
+ *
+ * Arguments:
+ *	caddr_t     arg Pointer to the interrupting device's state
+ *	            structure
+ *
+ * Returns:
+ *	DDI_INTR_CLAIMED    Interrupt claimed and processed
+ *	DDI_INTR_UNCLAIMED  Interrupt not claimed, and thus ignored
+ */
+static uint_t
+audiohd_intr(caddr_t arg)
+{
+	audiohd_state_t	*statep = (audiohd_state_t *)arg;
+	uint32_t	status;
+	uint32_t	regbase;
+	uint8_t		sdstatus;
+	int	i;
+
+	mutex_enter(&statep->hda_mutex);
+	status = AUDIOHD_REG_GET32(AUDIOHD_REG_INTSTS);
+
+	if (status == 0) {
+		mutex_exit(&statep->hda_mutex);
+		return (DDI_INTR_UNCLAIMED);
+	}
+
+	/* stream intr */
+	for (i = 0; i < statep->hda_streams_nums; i++) {
+		if ((status & (1<<i)) == 0)
+			continue;
+
+		regbase = AUDIOHD_REG_SD_BASE + AUDIOHD_REG_SD_LEN * i;
+		sdstatus = AUDIOHD_REG_GET8(regbase + AUDIOHD_SDREG_OFFSET_STS);
+
+		/* clear intrs */
+		AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_STS, sdstatus);
+
+		if ((sdstatus & AUDIOHDR_SD_STS_DESE) != 0) {
+			/*
+			 * fatal error. Hardware will clear run bit. So,
+			 * we need to shutdown the stream
+			 */
+			audio_sup_log(statep->hda_ahandle, CE_WARN,
+			    "!audiohd_intr() fatal error, shutdown "
+			    "stream %d", i);
+
+			if (i == statep->hda_input_streams) {
+				/* playback */
+				mutex_exit(&statep->hda_mutex);
+				am_play_shutdown(statep->hda_ahandle, NULL);
+				mutex_enter(&statep->hda_mutex);
+				statep->hda_flags &= ~(AUDIOHD_PLAY_EMPTY |
+				    AUDIOHD_PLAY_STARTED);
+				continue;
+			} else if (i == 0) { /* recording */
+				statep->hda_flags &= ~(AUDIOHD_RECORD_STARTED);
+				continue;
+			}
+		}
+
+		/* Buffer Complete Intr */
+		if (sdstatus & AUDIOHDR_SD_STS_BCIS)
+			if (i < statep->hda_input_streams) {
+				if (statep->hda_flags & AUDIOHD_RECORD_STARTED)
+					audiohd_get_rbuf(statep);
+			} else if (statep->hda_flags & AUDIOHD_PLAY_STARTED)
+				audiohd_refill_pbuf(statep);
+	}
+
+	/* update the kernel interrupt statistics */
+	if (statep->hda_ksp) {
+		((kstat_intr_t *)
+		    (statep->hda_ksp->ks_data))->intrs[KSTAT_INTR_HARD]++;
+	}
+
+	mutex_exit(&statep->hda_mutex);
+	return (DDI_INTR_CLAIMED);
+
+}	/* audiohd_intr() */
+
+/*
+ * audiohd_ad_start_play()
+ *
+ * Description:
+ *	This routine starts the first output stream of hardware
+ *
+ * Arguments:
+ *	audiohdl_t	ahandle		Handle to this device
+ *	int		stream		Stream number for multi-stream Codecs
+ *
+ * Returns:
+ *	AUDIO_SUCCESS   Playing started/restarted
+ *	AUDIO_FAILURE   Play not started/restarted, no audio to play
+ */
+static int
+audiohd_ad_start_play(audiohdl_t ahandle, int stream)
+{
+	audiohd_state_t	*statep;
+	uintptr_t	sbd_phys_addr;
+	uint8_t		cTmp;
+	uint_t	regbase;
+
+	ATRACE_32("i810_ad_start_play() stream", stream);
+	statep = audio_sup_get_private(ahandle);
+	ASSERT(statep);
+
+	mutex_enter(&statep->hda_mutex);
+	if (statep->hda_flags & AUDIOHD_PLAY_STARTED) {
+		mutex_exit(&statep->hda_mutex);
+		return (AUDIO_SUCCESS);
+	}
+
+	regbase = statep->hda_play_regbase;
+	if (statep->hda_flags & AUDIOHD_PLAY_PAUSED) {
+		cTmp = AUDIOHD_REG_GET8(regbase + AUDIOHD_SDREG_OFFSET_CTL);
+		statep->hda_flags |= AUDIOHD_PLAY_STARTED;
+		statep->hda_flags &= ~AUDIOHD_PLAY_PAUSED;
+		AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL,
+		    cTmp | AUDIOHDR_SD_CTL_SRUN);
+		mutex_exit(&statep->hda_mutex);
+		return (AUDIO_SUCCESS);
+	}
+
+	if (audiohd_reset_stream(statep, statep->hda_input_streams)
+	    != AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!start_play() failed to reset play stream");
+		mutex_exit(&statep->hda_mutex);
+		return (AUDIO_FAILURE);
+	}
+
+	statep->hda_flags |= AUDIOHD_PLAY_STARTED;
+
+	if (audiohd_fill_pbuf(statep) != AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!start_play() failed to get play sample");
+		statep->hda_flags &= ~AUDIOHD_PLAY_STARTED;
+		mutex_exit(&statep->hda_mutex);
+		return (AUDIO_FAILURE);
+	}
+
+	sbd_phys_addr = statep->hda_dma_play_bd.ad_paddr;
+	AUDIOHD_REG_SET64(regbase + AUDIOHD_SDREG_OFFSET_BDLPL, sbd_phys_addr);
+	AUDIOHD_REG_SET16(regbase + AUDIOHD_SDREG_OFFSET_LVI,
+	    AUDIOHD_BDLE_NUMS - 1);
+	AUDIOHD_REG_SET32(regbase + AUDIOHD_SDREG_OFFSET_CBL,
+	    statep->hda_pbuf_size * AUDIOHD_BDLE_NUMS);
+
+	AUDIOHD_REG_SET16(regbase + AUDIOHD_SDREG_OFFSET_FORMAT,
+	    statep->hda_play_format);
+	AUDIOHD_CODEC_SET_PCM_FORMAT(statep, AUDIO_PLAY,
+	    statep->hda_play_format);
+
+	/* clear status */
+	AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_STS,
+	    AUDIOHDR_SD_STS_BCIS | AUDIOHDR_SD_STS_FIFOE |
+	    AUDIOHDR_SD_STS_DESE);
+
+	AUDIOHD_CODEC_ENABLE_PLAY(statep);
+
+	/* set playback stream tag */
+	AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL + 2,
+	    (statep->hda_play_stag) << 4 | 4);
+
+	/* Enable interrupt and start DMA */
+	AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL,
+	    AUDIOHDR_SD_CTL_INTS | AUDIOHDR_SD_CTL_SRUN);
+
+	mutex_exit(&statep->hda_mutex);
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_ad_start_play() */
+
+
+/*
+ * audiohd_ad_set_config()
+ */
+static int
+audiohd_ad_set_config(audiohdl_t ahandle, int stream, int command,
+    int dir, int arg1, int arg2)
+{
+	audiohd_state_t	*statep;
+	int 	rc = AUDIO_SUCCESS;
+
+	ATRACE_32("audiohd_ad_set_config() stream", stream);
+	ATRACE_32("audiohd_ad_set_config() command", command);
+	ATRACE_32("audiohd_ad_set_config() dir", dir);
+	ATRACE_32("audiohd_ad_set_config() arg1", arg1);
+	ATRACE_32("audiohd_ad_set_config() arg2", arg2);
+
+	/* get the soft state structure */
+	statep = audio_sup_get_private(ahandle);
+	ASSERT(statep);
+
+	mutex_enter(&statep->hda_mutex);
+	switch (command) {
+	case AM_SET_GAIN:
+		/*
+		 * Set the gain for a channel. The audio mixer calculates the
+		 * impact, if any, of balance on gain.
+		 *
+		 * 	AUDIO_MIN_GAIN <= gain <= AUDIO_MAX_GAIN
+		 *
+		 * 	arg1 --> gain
+		 * 	arg2 --> channel #, 0 == left, 1 == right
+		 */
+		rc = audiohd_set_gain(statep, dir, arg1, arg2);
+		break;
+
+	case AM_SET_PORT:
+		/*
+		 * Enable/disable the input or output ports. The audio mixer
+		 * enforces exclusiveness of in ports, as well as which ports
+		 * are modifiable. We just turn on the ports that match the
+		 * bits.
+		 *
+		 * 	arg1 --> port bit pattern
+		 * 	arg2 --> not used
+		 */
+		rc = audiohd_set_port(statep, dir, arg1);
+		break;
+
+	case AM_SET_MONITOR_GAIN:
+		/*
+		 * Set the loopback monitor gain.
+		 *
+		 * 	AUDIO_MIN_GAIN <= gain <= AUDIO_MAX_GAIN
+		 *
+		 * 	dir ---> N/A
+		 *	arg1 --> gain
+		 * 	arg2 --> not used
+		 */
+		rc = audiohd_set_monitor_gain(statep, arg1);
+		break;
+
+	case AM_OUTPUT_MUTE:
+		/*
+		 * Mute or enable the output.
+		 *
+		 * 	dir ---> N/A
+		 * 	arg1 --> ~0 == mute, 0 == enable
+		 * 	arg2 --> not used
+		 */
+		audiohd_mute_outputs(statep, arg1);
+		break;
+
+	case AM_MIC_BOOST:
+		break;
+
+	default:
+		/*
+		 * We let default catch commands we don't support, as well
+		 * as bad commands.
+		 *
+		 *
+		 * AM_SET_GAIN_BAL
+		 * AM_SET_MONO_MIC
+		 * AM_BASS_BOOST
+		 * AM_MID_BOOST
+		 * AM_TREBLE_BOOST
+		 * AM_LOUDNESS
+		 */
+		rc = AUDIO_FAILURE;
+		ATRACE_32("audiohd_ad_set_config() unsupported command",
+		    command);
+		break;
+	}
+	mutex_exit(&statep->hda_mutex);
+
+	return (rc);
+
+}	/* audiohd_ad_set_config */
+
+/*
+ * audiohd_ad_set_format()
+ *
+ * Description
+ *	currently, only 48k sample rate, 16-bit precision,
+ *	2-channel format is supported.
+ */
+/*ARGSUSED*/
+static int
+audiohd_ad_set_format(audiohdl_t ahandle, int stream, int dir,
+    int sample_rate, int channels, int precision, int encoding)
+{
+	audiohd_state_t	*statep;
+
+	/*
+	 * Currently, force to 48k, 16bits, 2-channel
+	 */
+	if ((sample_rate != AUDIOHD_SAMPR48000) ||
+	    (channels != AUDIO_CHANNELS_STEREO) ||
+	    (precision != AUDIO_PRECISION_16) ||
+	    (encoding != AUDIO_ENCODING_LINEAR))
+		return (AUDIO_FAILURE);
+
+	/*
+	 * we will support other format later
+	 */
+	statep = audio_sup_get_private(ahandle);
+	ASSERT(statep);
+	mutex_enter(&statep->hda_mutex);
+
+	if (dir == AUDIO_PLAY) {
+		statep->hda_psample_rate = sample_rate;
+		statep->hda_pchannels = channels;
+		statep->hda_pprecision = precision;
+		statep->hda_play_format = AUDIOHD_FMT_PCMOUT;
+	} else {
+		ASSERT(dir == AUDIO_RECORD);
+		statep->hda_csample_rate = sample_rate;
+		statep->hda_cchannels = channels;
+		statep->hda_cprecision = precision;
+		statep->hda_record_format = AUDIOHD_FMT_PCMIN;
+	}
+
+	mutex_exit(&statep->hda_mutex);
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_ad_set_format() */
+
+
+/*
+ * audiohd_ad_pause_play()
+ */
+/*ARGSUSED*/
+static void
+audiohd_ad_pause_play(audiohdl_t ahandle, int stream)
+{
+	audiohd_state_t	*statep;
+	uint32_t	regbase;
+	uint8_t		cTmp;
+
+	statep = audio_sup_get_private(ahandle);
+	ASSERT(statep);
+
+	mutex_enter(&statep->hda_mutex);
+	regbase = statep->hda_play_regbase;
+	cTmp = AUDIOHD_REG_GET8(regbase + AUDIOHD_SDREG_OFFSET_CTL);
+	cTmp &= ~AUDIOHDR_SD_CTL_SRUN;
+	AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL, cTmp);
+	statep->hda_flags &= ~AUDIOHD_PLAY_STARTED;
+	statep->hda_flags |= AUDIOHD_PLAY_PAUSED;
+	mutex_exit(&statep->hda_mutex);
+
+}	/* audiohd_ad_pause_play() */
+
+/*
+ * audiohd_ad_stop_play()
+ */
+/*ARGSUSED*/
+static void
+audiohd_ad_stop_play(audiohdl_t ahandle, int stream)
+{
+	audiohd_state_t	*statep;
+	uint32_t	regbase;
+
+	statep = audio_sup_get_private(ahandle);
+	ASSERT(statep);
+
+	mutex_enter(&statep->hda_mutex);
+	regbase = statep->hda_play_regbase;
+	AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL, 0);
+	statep->hda_flags &=
+	    ~(AUDIOHD_PLAY_EMPTY | AUDIOHD_PLAY_STARTED);
+	mutex_exit(&statep->hda_mutex);
+
+}	/* audiohd_ad_stop_play() */
+
+/*
+ * audiohd_ad_start_record()
+ */
+/*ARGSUSED*/
+static int
+audiohd_ad_start_record(audiohdl_t ahandle, int stream)
+{
+	audiohd_state_t	*statep;
+	uint64_t	sbd_phys_addr;
+	uint_t		regbase;
+
+	statep = audio_sup_get_private(ahandle);
+	ASSERT(statep);
+
+	mutex_enter(&statep->hda_mutex);
+	if (statep->hda_flags & AUDIOHD_RECORD_STARTED) {
+		mutex_exit(&statep->hda_mutex);
+		return (AUDIO_SUCCESS);
+	}
+
+	if (audiohd_reset_stream(statep, 0) != AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!start_record() failed to reset record stream");
+		mutex_exit(&statep->hda_mutex);
+		return (AUDIO_FAILURE);
+	}
+
+	audiohd_preset_rbuf(statep);
+	statep->hda_rbuf_pos = 0;
+
+	regbase = statep->hda_record_regbase;
+	sbd_phys_addr = statep->hda_dma_record_bd.ad_paddr;
+	AUDIOHD_REG_SET64(regbase + AUDIOHD_SDREG_OFFSET_BDLPL, sbd_phys_addr);
+	AUDIOHD_REG_SET16(regbase + AUDIOHD_SDREG_OFFSET_FORMAT,
+	    statep->hda_record_format);
+	AUDIOHD_REG_SET16(regbase + AUDIOHD_SDREG_OFFSET_LVI,
+	    AUDIOHD_BDLE_NUMS - 1);
+	AUDIOHD_REG_SET32(regbase + AUDIOHD_SDREG_OFFSET_CBL,
+	    statep->hda_rbuf_size * AUDIOHD_BDLE_NUMS);
+
+	/* clear status */
+	AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_STS,
+	    AUDIOHDR_SD_STS_INTRS);
+
+	AUDIOHD_CODEC_SET_PCM_FORMAT(statep, AUDIO_RECORD,
+	    statep->hda_record_format);
+	AUDIOHD_CODEC_ENABLE_RECORD(statep);
+
+	/* set stream tag to 1 */
+	AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL + 2,
+	    statep->hda_record_stag << 4 | 4);
+	statep->hda_flags |= AUDIOHD_RECORD_STARTED;
+
+	/* start DMA */
+	AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL,
+	    AUDIOHDR_SD_CTL_INTS | AUDIOHDR_SD_CTL_SRUN);
+
+	mutex_exit(&statep->hda_mutex);
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_ad_start_record() */
+
+
+/*
+ * audiohd_ad_stop_record()
+ */
+/*ARGSUSED*/
+static void
+audiohd_ad_stop_record(audiohdl_t ahandle, int stream)
+{
+	audiohd_state_t	*statep;
+	uint32_t	regbase;
+
+	statep = audio_sup_get_private(ahandle);
+	ASSERT(statep);
+
+	mutex_enter(&statep->hda_mutex);
+	regbase = statep->hda_record_regbase;
+	AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL, 0);
+	statep->hda_flags &= ~(AUDIOHD_RECORD_STARTED);
+	mutex_exit(&statep->hda_mutex);
+
+}	/* audiohd_ad_stop_play */
+
+/*
+ * audiohd_init_state()
+ *
+ * Description
+ *	This routine initailizes soft state of driver instance,
+ *	also, it requests an interrupt cookie and initializes
+ *	mutex for soft state.
+ */
+/*ARGSUSED*/
+static int
+audiohd_init_state(audiohd_state_t *statep, dev_info_t *dip)
+{
+	int	pints, rints, mode;
+
+	statep->hda_dip = dip;
+
+	/* get the mode from the .conf file */
+	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
+	    "mixer-mode", 1)) {
+		mode = AM_MIXER_MODE;
+	} else {
+		mode = AM_COMPAT_MODE;
+	}
+
+	pints = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "play-interrupts", AUDIOHD_INTS);
+	if (pints > AUDIOHD_MAX_INTS) {
+		audio_sup_log(statep->hda_ahandle, CE_NOTE, "init_state() "
+		    "play interrupt rate set too high, %d, resetting to %d",
+		    pints, AUDIOHD_INTS);
+		pints = AUDIOHD_INTS;
+	} else if (pints < AUDIOHD_MIN_INTS) {
+		audio_sup_log(statep->hda_ahandle, CE_NOTE, "init_state() "
+		    "play interrupt rate set too low, %d, resetting to %d",
+		    pints, AUDIOHD_INTS);
+		pints = AUDIOHD_INTS;
+	}
+	rints = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
+	    DDI_PROP_DONTPASS, "record-interrupts", AUDIOHD_INTS);
+	if (rints > AUDIOHD_MAX_INTS) {
+		audio_sup_log(statep->hda_ahandle, CE_NOTE, "init_state() "
+		    "record interrupt rate set too high, %d, resetting to %d",
+		    rints, AUDIOHD_INTS);
+		rints = AUDIOHD_INTS;
+	} else if (rints < AUDIOHD_MIN_INTS) {
+		audio_sup_log(statep->hda_ahandle, CE_NOTE, "init_state() "
+		    "record interrupt rate set too low, %d, resetting to %d",
+		    rints, AUDIOHD_INTS);
+		rints = AUDIOHD_INTS;
+	}
+
+	statep->hda_pint_freq = pints;
+	statep->hda_rint_freq = rints;
+	statep->hda_pbuf_size = (AUDIOHD_SAMPLER_MAX * AUDIOHD_MAX_CHANNELS *
+	    AUDIOHD_MAX_PRECISION / 8) / pints;
+	statep->hda_pbuf_size = (statep->hda_pbuf_size +
+	    AUDIOHD_BDLE_BUF_ALIGN - 1) & ~(AUDIOHD_BDLE_BUF_ALIGN - 1);
+	statep->hda_rbuf_size = (AUDIOHD_SAMPLER_MAX * AUDIOHD_MAX_CHANNELS *
+	    AUDIOHD_MAX_PRECISION / 8) / rints;
+	statep->hda_rbuf_size = (statep->hda_rbuf_size +
+	    AUDIOHD_BDLE_BUF_ALIGN - 1) & ~(AUDIOHD_BDLE_BUF_ALIGN - 1);
+
+	/* fill in the device default state */
+	statep->hda_info_defaults.play.sample_rate = AUDIOHD_DEFAULT_SR;
+	statep->hda_info_defaults.play.channels = AUDIOHD_DEFAULT_CH;
+	statep->hda_info_defaults.play.precision = AUDIOHD_DEFAULT_PREC;
+	statep->hda_info_defaults.play.encoding = AUDIOHD_DEFAULT_ENC;
+	statep->hda_info_defaults.play.gain = AUDIOHD_DEFAULT_PGAIN;
+	statep->hda_info_defaults.play.port = AUDIO_HEADPHONE;
+	statep->hda_info_defaults.play.avail_ports = AUDIO_HEADPHONE;
+	statep->hda_info_defaults.play.mod_ports = AUDIO_HEADPHONE;
+	statep->hda_info_defaults.play.buffer_size = AUDIOHD_BSIZE;
+	statep->hda_info_defaults.play.balance = AUDIOHD_DEFAULT_BAL;
+
+	statep->hda_info_defaults.record.sample_rate = AUDIOHD_DEFAULT_SR;
+	statep->hda_info_defaults.record.channels = AUDIOHD_DEFAULT_CH;
+	statep->hda_info_defaults.record.precision = AUDIOHD_DEFAULT_PREC;
+	statep->hda_info_defaults.record.encoding = AUDIOHD_DEFAULT_ENC;
+	statep->hda_info_defaults.record.gain = AUDIOHD_DEFAULT_RGAIN;
+	statep->hda_info_defaults.record.port = AUDIO_MICROPHONE;
+	statep->hda_info_defaults.record.avail_ports =
+	    AUDIO_MICROPHONE | AUDIO_LINE_IN;
+	statep->hda_info_defaults.record.mod_ports =
+	    AUDIO_MICROPHONE | AUDIO_LINE_IN;
+	statep->hda_info_defaults.record.buffer_size = AUDIOHD_BSIZE;
+	statep->hda_info_defaults.record.balance = AUDIOHD_DEFAULT_BAL;
+
+	statep->hda_info_defaults.monitor_gain = AUDIOHD_DEFAULT_MONITOR_GAIN;
+	statep->hda_info_defaults.output_muted = B_FALSE;
+	statep->hda_info_defaults.ref_cnt = B_FALSE;
+	statep->hda_info_defaults.hw_features =
+	    AUDIO_HWFEATURE_DUPLEX | AUDIO_HWFEATURE_PLAY |
+	    AUDIO_HWFEATURE_IN2OUT | AUDIO_HWFEATURE_RECORD;
+	statep->hda_info_defaults.sw_features = AUDIO_SWFEATURE_MIXER;
+
+	statep->hda_psample_rate =
+	    statep->hda_info_defaults.play.sample_rate;
+	statep->hda_pchannels =
+	    statep->hda_info_defaults.play.channels;
+	statep->hda_pprecision =
+	    statep->hda_info_defaults.play.precision;
+	statep->hda_play_format = AUDIOHD_FMT_PCMOUT;
+
+	statep->hda_csample_rate =
+	    statep->hda_info_defaults.record.sample_rate;
+	statep->hda_cchannels =
+	    statep->hda_info_defaults.record.channels;
+	statep->hda_cprecision =
+	    statep->hda_info_defaults.record.precision;
+	statep->hda_record_format = AUDIOHD_FMT_PCMIN;
+
+	statep->hda_out_ports = AUDIO_HEADPHONE;
+	statep->hda_in_ports = AUDIO_MICROPHONE;
+
+	/*
+	 * fill in the ad_info structure
+	 */
+	statep->hda_ad_info.ad_mode = mode;
+	statep->hda_ad_info.ad_int_vers = AM_VERSION;
+	statep->hda_ad_info.ad_add_mode = NULL;
+	statep->hda_ad_info.ad_codec_type = AM_TRAD_CODEC;
+	statep->hda_ad_info.ad_defaults = &statep->hda_info_defaults;
+	statep->hda_ad_info.ad_play_comb = audiohd_combinations;
+	statep->hda_ad_info.ad_rec_comb = audiohd_combinations;
+	statep->hda_ad_info.ad_entry = &audiohd_entry;
+	statep->hda_ad_info.ad_dev_info = &statep->hda_dev_info;
+	statep->hda_ad_info.ad_diag_flags = AM_DIAG_INTERNAL_LOOP;
+	statep->hda_ad_info.ad_diff_flags =
+	    AM_DIFF_SR | AM_DIFF_CH | AM_DIFF_PREC | AM_DIFF_ENC;
+	statep->hda_ad_info.ad_assist_flags = AM_ASSIST_MIC;
+	statep->hda_ad_info.ad_misc_flags = AM_MISC_RP_EXCL | AM_MISC_MONO_DUP;
+	statep->hda_ad_info.ad_num_mics = 1;
+
+	/* play capabilities */
+	statep->hda_ad_info.ad_play.ad_mixer_srs = audiohd_mixer_sample_rates;
+	statep->hda_ad_info.ad_play.ad_compat_srs = audiohd_comp_sample_rates;
+	statep->hda_ad_info.ad_play.ad_conv = &am_src2;
+	statep->hda_ad_info.ad_play.ad_sr_info = NULL;
+	statep->hda_ad_info.ad_play.ad_chs = audiohd_channels;
+	statep->hda_ad_info.ad_play.ad_int_rate = pints;
+	statep->hda_ad_info.ad_play.ad_max_chs = AUDIOHD_MAX_OUT_CHANNELS;
+	statep->hda_ad_info.ad_play.ad_bsize = AUDIOHD_BSIZE;
+
+	/* record capabilities */
+	statep->hda_ad_info.ad_record.ad_mixer_srs = audiohd_mixer_sample_rates;
+	statep->hda_ad_info.ad_record.ad_compat_srs = audiohd_comp_sample_rates;
+	statep->hda_ad_info.ad_record.ad_conv = &am_src2;
+	statep->hda_ad_info.ad_record.ad_sr_info = NULL;
+	statep->hda_ad_info.ad_record.ad_chs = audiohd_channels;
+	statep->hda_ad_info.ad_record.ad_int_rate = rints;
+	statep->hda_ad_info.ad_record.ad_max_chs = AUDIOHD_MAX_CHANNELS;
+	statep->hda_ad_info.ad_record.ad_bsize = AUDIOHD_BSIZE;
+
+	/* fill in device info strings */
+	(void) strcpy(statep->hda_dev_info.name, AUDIOHD_DEV_NAME);
+	(void) strcpy(statep->hda_dev_info.config, AUDIOHD_DEV_CONFIG);
+	(void) strcpy(statep->hda_dev_info.version, AUDIOHD_DEV_VERSION);
+
+	if (ddi_get_iblock_cookie(dip, (uint_t)0, &statep->hda_intr_cookie) !=
+	    DDI_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!init_state() cannot get iblock cookie");
+		return (AUDIO_FAILURE);
+	}
+	mutex_init(&statep->hda_mutex, NULL,
+	    MUTEX_DRIVER, statep->hda_intr_cookie);
+
+	statep->hda_rirb_rp = 0;
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_init_state() */
+
+/*
+ * audiohd_init_pci()
+ *
+ * Description
+ *	enable driver to access PCI configure space and memory
+ *	I/O space.
+ */
+static int
+audiohd_init_pci(audiohd_state_t *statep, ddi_device_acc_attr_t *acc_attr)
+{
+	uint16_t	cmdreg;
+	dev_info_t	*dip = statep->hda_dip;
+	audiohdl_t	ahandle = statep->hda_ahandle;
+
+	if (pci_config_setup(dip, &statep->hda_pci_handle) == DDI_FAILURE) {
+		audio_sup_log(ahandle, CE_WARN,
+		    "!map_regs() pci config mapping failed");
+		goto err_init_pci_exit1;
+	}
+
+	if (ddi_regs_map_setup(dip, 1, &statep->hda_reg_base, 0,
+	    AUDIOHD_MEMIO_LEN, acc_attr, &statep->hda_reg_handle) !=
+	    DDI_SUCCESS) {
+		audio_sup_log(ahandle, CE_WARN,
+		    "!map_regs() memory I/O mapping failed");
+		goto err_init_pci_exit2;
+	}
+
+	/*
+	 * HD audio control uses memory I/O only, enable it here.
+	 */
+	cmdreg = pci_config_get16(statep->hda_pci_handle, PCI_CONF_COMM);
+	pci_config_put16(statep->hda_pci_handle, PCI_CONF_COMM,
+	    cmdreg | PCI_COMM_MAE | PCI_COMM_ME);
+
+	/* set TCSEL to TC1 */
+	pci_config_put8(statep->hda_pci_handle, 0x44, 1);
+
+	return (AUDIO_SUCCESS);
+
+err_init_pci_exit2:
+	pci_config_teardown(&statep->hda_pci_handle);
+
+err_init_pci_exit1:
+	return (AUDIO_FAILURE);
+
+}	/* audiohd_init_pci() */
+
+
+/*
+ * audiohd_fini_pci()
+ *
+ * Description
+ *	Release mapping for PCI configure space.
+ */
+static void
+audiohd_fini_pci(audiohd_state_t *statep)
+{
+	if (statep->hda_reg_handle != NULL) {
+		ddi_regs_map_free(&statep->hda_reg_handle);
+		statep->hda_reg_handle = NULL;
+	}
+
+	if (statep->hda_pci_handle != NULL) {
+		pci_config_teardown(&statep->hda_pci_handle);
+		statep->hda_pci_handle = NULL;
+	}
+
+}	/* audiohd_fini_pci() */
+
+/*
+ * audiohd_stop_dma()
+ *
+ * Description
+ *	Stop all DMA behaviors of controllers, for command I/O
+ *	and each audio stream.
+ */
+static void
+audiohd_stop_dma(audiohd_state_t *statep)
+{
+	int	i;
+	uint_t	base;
+	uint8_t	bTmp;
+
+	AUDIOHD_REG_SET8(AUDIOHD_REG_CORBCTL, 0);
+	AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBCTL, 0);
+
+	base = AUDIOHD_REG_SD_BASE;
+	for (i = 0; i < statep->hda_streams_nums; i++) {
+		bTmp = AUDIOHD_REG_GET8(base + AUDIOHD_SDREG_OFFSET_CTL);
+
+		/* for input/output stream, it is the same */
+		bTmp &= ~AUDIOHDR_RIRBCTL_DMARUN;
+
+		AUDIOHD_REG_SET8(base + AUDIOHD_SDREG_OFFSET_CTL, bTmp);
+		base += AUDIOHD_REG_SD_LEN;
+	}
+
+	/* wait 40us for stream DMA to stop */
+	drv_usecwait(40);
+
+}	/* audiohd_stop_dma() */
+
+/*
+ * audiohd_reset_controller()
+ *
+ * Description:
+ *	This routine is just used to reset controller and
+ *	CODEC as well by HW reset bit in global control
+ *	register of HD controller.
+ */
+static int
+audiohd_reset_controller(audiohd_state_t *statep)
+{
+	int		i;
+	uint8_t	gctl;
+
+	/* reset controller */
+	AUDIOHD_REG_SET32(AUDIOHD_REG_GCTL, 0);  /* entering reset state */
+	for (i = 0; i < 60; i++) {
+		drv_usecwait(30);
+		gctl = AUDIOHD_REG_GET32(AUDIOHD_REG_GCTL) & AUDIOHDR_GCTL_CRST;
+		if (!gctl)
+			break;
+	}
+
+	if (gctl) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!reset_controller() failed to enter reset state");
+		return (AUDIO_FAILURE);
+	}
+
+	/* how long should we wait for reset ? */
+	drv_usecwait(300);
+
+	/* exit reset state */
+	AUDIOHD_REG_SET32(AUDIOHD_REG_GCTL, AUDIOHDR_GCTL_CRST);
+
+	for (i = 0; i < 60; i++) {
+		drv_usecwait(30);
+		gctl = AUDIOHD_REG_GET32(AUDIOHD_REG_GCTL) & AUDIOHDR_GCTL_CRST;
+		if (gctl)
+			break;
+	}
+
+	if (!gctl) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!reset_controller() failed to exit reset state");
+		return (AUDIO_FAILURE);
+	}
+
+	/* HD spec requires to wait 250us at least. we use 300us */
+	drv_usecwait(300);
+
+	/* enable unsolicited response */
+	AUDIOHD_REG_SET32(AUDIOHD_REG_GCTL,
+	    AUDIOHDR_GCTL_CRST |  AUDIOHDR_GCTL_URESPE);
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_reset_controller() */
+
+/*
+ * audiohd_alloc_dma_mem()
+ *
+ * Description:
+ *	This is an utility routine. It is used to allocate DMA
+ *	memory.
+ */
+static int
+audiohd_alloc_dma_mem(audiohd_state_t *statep, audiohd_dma_t *pdma,
+    size_t memsize, ddi_dma_attr_t *dma_attr_p, uint_t dma_flags)
+{
+	ddi_dma_cookie_t	cookie;
+	uint_t			count;
+	dev_info_t		*dip = statep->hda_dip;
+	audiohdl_t		ahandle = statep->hda_ahandle;
+
+	if (ddi_dma_alloc_handle(dip, dma_attr_p, DDI_DMA_SLEEP,
+	    (caddr_t)0, &pdma->ad_dmahdl) != DDI_SUCCESS) {
+		audio_sup_log(ahandle, CE_WARN,
+		    "!map_regs() ddi_dma_alloc_hanlde failed");
+		goto error_alloc_dma_exit1;
+	}
+
+	if (ddi_dma_mem_alloc(pdma->ad_dmahdl, memsize, &hda_dev_accattr,
+	    dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING),
+	    DDI_DMA_SLEEP, NULL, (caddr_t *)&pdma->ad_vaddr,
+	    &pdma->ad_real_sz, &pdma->ad_acchdl) != DDI_SUCCESS) {
+		audio_sup_log(ahandle, CE_WARN,
+		    "!map_regs() ddi_dma_mem_alloc failed");
+		goto error_alloc_dma_exit2;
+	}
+
+	if (ddi_dma_addr_bind_handle(pdma->ad_dmahdl, NULL,
+	    (caddr_t)pdma->ad_vaddr, pdma->ad_real_sz, dma_flags,
+	    DDI_DMA_SLEEP, NULL, &cookie, &count) != DDI_DMA_MAPPED) {
+		audio_sup_log(ahandle, CE_WARN,
+		    "!map_regs() ddi_dma_addr_bind_handle failed");
+		goto error_alloc_dma_exit3;
+	}
+
+	/*
+	 * there some bugs in the DDI framework and it is possible to
+	 * get multiple cookies
+	 */
+	if (count != 1) {
+		(void) ddi_dma_unbind_handle(pdma->ad_dmahdl);
+		audio_sup_log(ahandle, CE_WARN,
+		    "!map_regs() addr_bind_handle failed, cookies > 1");
+		goto error_alloc_dma_exit3;
+	}
+	pdma->ad_paddr = (uintptr_t)(cookie.dmac_address);
+	pdma->ad_req_sz = memsize;
+
+	return (AUDIO_SUCCESS);
+
+error_alloc_dma_exit3:
+	ddi_dma_mem_free(&pdma->ad_acchdl);
+
+error_alloc_dma_exit2:
+	ddi_dma_free_handle(&pdma->ad_dmahdl);
+
+error_alloc_dma_exit1:
+	return (AUDIO_FAILURE);
+
+}	/* audiohd_alloc_dma_mem() */
+
+/*
+ * audiohd_release_dma_mem()
+ *
+ * Description:
+ *	Release DMA memory.
+ */
+
+static void
+audiohd_release_dma_mem(audiohd_dma_t *pdma)
+{
+	if (pdma->ad_dmahdl != NULL) {
+		(void) ddi_dma_unbind_handle(pdma->ad_dmahdl);
+		pdma->ad_dmahdl = NULL;
+	}
+
+	if (pdma->ad_acchdl != NULL) {
+		ddi_dma_mem_free(&pdma->ad_acchdl);
+		pdma->ad_acchdl = NULL;
+	}
+
+	if (pdma->ad_dmahdl != NULL) {
+		ddi_dma_free_handle(&pdma->ad_dmahdl);
+		pdma->ad_dmahdl = NULL;
+	}
+
+}	/* audiohd_release_dma_mem() */
+
+/*
+ * audiohd_init_controller()
+ *
+ * Description:
+ *	This routine is used to initialize HD controller. It
+ *	allocates DMA memory for CORB/RIRB, buffer descriptor
+ *	list and cylic data buffer for both play and record
+ *	stream.
+ */
+static int
+audiohd_init_controller(audiohd_state_t *statep)
+{
+	uintptr_t	addr;
+	uint16_t	gcap;
+	int		retval;
+
+	ddi_dma_attr_t	dma_attr = {
+		DMA_ATTR_V0,		/* version */
+		0,			/* addr_lo */
+		0xffffffffffffffff,	/* addr_hi */
+		0x00000000ffffffff,	/* count_max */
+		128,			/* 128-byte alignment as HD spec */
+		0xfff,			/* burstsize */
+		1,			/* minxfer */
+		0xffffffff,		/* maxxfer */
+		0xffffffff,		/* seg */
+		1,			/* sgllen */
+		1,			/* granular */
+		0			/* flags */
+	};
+
+	gcap = AUDIOHD_REG_GET16(AUDIOHD_REG_GCAP);
+	statep->hda_input_streams = (gcap & AUDIOHDR_GCAP_INSTREAMS) >> 8;
+	statep->hda_output_streams = (gcap & AUDIOHDR_GCAP_OUTSTREAMS) >> 12;
+	statep->hda_streams_nums = statep->hda_input_streams +
+	    statep->hda_output_streams;
+
+	statep->hda_record_stag = 1;
+	statep->hda_play_stag = statep->hda_input_streams + 1;
+	statep->hda_record_regbase = AUDIOHD_REG_SD_BASE;
+	statep->hda_play_regbase = AUDIOHD_REG_SD_BASE + AUDIOHD_REG_SD_LEN *
+	    statep->hda_input_streams;
+
+	/* stop all dma before starting to reset controller */
+	audiohd_stop_dma(statep);
+
+	if (audiohd_reset_controller(statep) != AUDIO_SUCCESS)
+		return (AUDIO_FAILURE);
+
+	/* check codec */
+	statep->hda_codec_mask = AUDIOHD_REG_GET16(AUDIOHD_REG_STATESTS);
+	if (! statep->hda_codec_mask) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!init_controller() no codec exists");
+		goto err_init_ctlr_exit1;
+	}
+
+	/* allocate DMA for CORB */
+	retval = audiohd_alloc_dma_mem(statep, &statep->hda_dma_corb,
+	    AUDIOHD_CDBIO_CORB_LEN, &dma_attr,
+	    DDI_DMA_WRITE | DDI_DMA_CONSISTENT);
+	if (retval != AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!init_controller() failed to alloc DMA for CORB");
+		goto err_init_ctlr_exit1;
+	}
+
+	/* allocate DMA for RIRB */
+	retval = audiohd_alloc_dma_mem(statep, &statep->hda_dma_rirb,
+	    AUDIOHD_CDBIO_RIRB_LEN, &dma_attr,
+	    DDI_DMA_READ | DDI_DMA_CONSISTENT);
+	if (retval != AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!init_controller() failed to alloc DMA for RIRB");
+		goto err_init_ctlr_exit2;
+	}
+
+	/* allocate DMA for data buffer of playback stream */
+	retval = audiohd_alloc_dma_mem(statep, &statep->hda_dma_play_buf,
+	    statep->hda_pbuf_size * AUDIOHD_BDLE_NUMS, &dma_attr,
+	    DDI_DMA_WRITE | DDI_DMA_STREAMING);
+	if (retval != AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!init_controller() failed to alloc DMA for playback buf");
+		goto err_init_ctlr_exit3;
+	}
+
+	/* allocate DMA for data buffer of recording stream */
+	retval = audiohd_alloc_dma_mem(statep, &statep->hda_dma_record_buf,
+	    statep->hda_rbuf_size * AUDIOHD_BDLE_NUMS, &dma_attr,
+	    DDI_DMA_READ | DDI_DMA_STREAMING);
+	if (retval != AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!init_controller() failed to alloc DMA for recording buf");
+		goto err_init_ctlr_exit4;
+	}
+
+	/* allocate DMA for buffer descriptor list of playback stream */
+	retval = audiohd_alloc_dma_mem(statep, &statep->hda_dma_play_bd,
+	    sizeof (sd_bdle_t) * AUDIOHD_BDLE_NUMS, &dma_attr,
+	    DDI_DMA_WRITE | DDI_DMA_STREAMING);
+	if (retval != AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!init_controller() failed to alloc DMA for playback BDL");
+		goto err_init_ctlr_exit5;
+	}
+
+	/* allocate DMA for buffer descriptor list of recording stream */
+	retval = audiohd_alloc_dma_mem(statep, &statep->hda_dma_record_bd,
+	    sizeof (sd_bdle_t) * AUDIOHD_BDLE_NUMS, &dma_attr,
+	    DDI_DMA_WRITE | DDI_DMA_STREAMING);
+	if (retval != AUDIO_SUCCESS) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!init_controller() failed to alloc DMA for record BDL");
+		goto err_init_ctlr_exit6;
+	}
+
+	AUDIOHD_REG_SET32(AUDIOHD_REG_SYNC, 0); /* needn't sync stream */
+
+	/* Initialize RIRB */
+	addr = statep->hda_dma_rirb.ad_paddr;
+	AUDIOHD_REG_SET64(AUDIOHD_REG_RIRBLBASE, addr);
+	AUDIOHD_REG_SET16(AUDIOHD_REG_RIRBWP, AUDIOHDR_RIRBWP_RESET);
+	AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBSIZE, AUDIOHDR_RIRBSZ_256);
+	AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBCTL, AUDIOHDR_RIRBCTL_DMARUN);
+
+	/* initialize CORB */
+	addr = statep->hda_dma_corb.ad_paddr;
+	AUDIOHD_REG_SET16(AUDIOHD_REG_CORBRP, AUDIOHDR_CORBRP_RESET);
+	AUDIOHD_REG_SET64(AUDIOHD_REG_CORBLBASE, addr);
+	AUDIOHD_REG_SET8(AUDIOHD_REG_CORBSIZE, AUDIOHDR_CORBSZ_256);
+	AUDIOHD_REG_SET16(AUDIOHD_REG_CORBWP, 0);
+	AUDIOHD_REG_SET16(AUDIOHD_REG_CORBRP, 0);
+	AUDIOHD_REG_SET8(AUDIOHD_REG_CORBCTL, AUDIOHDR_CORBCTL_DMARUN);
+
+	return (AUDIO_SUCCESS);
+
+err_init_ctlr_exit6:
+	audiohd_release_dma_mem(&(statep->hda_dma_play_bd));
+
+err_init_ctlr_exit5:
+	audiohd_release_dma_mem(&(statep->hda_dma_record_buf));
+
+err_init_ctlr_exit4:
+	audiohd_release_dma_mem(&(statep->hda_dma_play_buf));
+
+err_init_ctlr_exit3:
+	audiohd_release_dma_mem(&(statep->hda_dma_rirb));
+
+err_init_ctlr_exit2:
+	audiohd_release_dma_mem(&(statep->hda_dma_corb));
+
+err_init_ctlr_exit1:
+	return (AUDIO_FAILURE);
+
+}	/* audiohd_init_controller() */
+
+/*
+ * audiohd_fini_controller()
+ *
+ * Description:
+ *	Releases DMA memory allocated in audiohd_init_controller()
+ */
+static void
+audiohd_fini_controller(audiohd_state_t *statep)
+{
+	audiohd_stop_dma(statep);
+	audiohd_release_dma_mem(&statep->hda_dma_rirb);
+	audiohd_release_dma_mem(&statep->hda_dma_corb);
+	audiohd_release_dma_mem(&statep->hda_dma_play_buf);
+	audiohd_release_dma_mem(&statep->hda_dma_record_buf);
+	audiohd_release_dma_mem(&statep->hda_dma_record_bd);
+	audiohd_release_dma_mem(&statep->hda_dma_play_bd);
+
+}	/* audiohd_fini_controller() */
+
+/*
+ * audiohd_create_codec()
+ *
+ * Description:
+ *	Searching for supported CODEC. If find, allocate memory
+ *	to hold codec structure.
+ */
+static int
+audiohd_create_codec(audiohd_state_t *statep)
+{
+	audiohd_hda_codec_t	*codec;
+	uint32_t	mask, type;
+	uint32_t	nid, nums;
+	uint32_t	i, j;
+	boolean_t	found = B_FALSE;
+
+	mask = statep->hda_codec_mask;
+	ASSERT(mask != 0);
+
+	codec = (audiohd_hda_codec_t *)kmem_zalloc(
+	    sizeof (audiohd_hda_codec_t), KM_SLEEP);
+
+	for (i = 0; i < AUDIOHD_CODEC_MAX; i++) {
+		if ((mask & (1 << i)) == 0)
+			continue;
+
+		codec->hc_addr = i;
+		codec->hc_vid = audioha_codec_verb_get(statep, i,
+		    AUDIOHDC_NODE_ROOT, AUDIOHDC_VERB_GET_PARAM,
+		    AUDIOHDC_PAR_VENDOR_ID);
+		codec->hc_revid = audioha_codec_verb_get(statep, i,
+		    AUDIOHDC_NODE_ROOT, AUDIOHDC_VERB_GET_PARAM,
+		    AUDIOHDC_PAR_REV_ID);
+
+		switch (codec->hc_vid) {
+
+		case AUDIOHD_VID_ALC880:
+		case AUDIOHD_VID_ALC883:
+		case AUDIOHD_VID_ALC885:
+			codec->hc_ops = &audiohd_alc880_ops;
+			found = B_TRUE;
+			break;
+
+		default:
+			audio_sup_log(statep->hda_ahandle, CE_WARN,
+			    "!unsupported audio codec: vid=0x%08x, rev=0x%08x",
+			    codec->hc_vid, codec->hc_revid);
+			break;
+		}
+
+		if (! found)
+			continue;
+
+		nums = audioha_codec_verb_get(statep, i, AUDIOHDC_NODE_ROOT,
+		    AUDIOHDC_VERB_GET_PARAM, AUDIOHDC_PAR_NODE_COUNT);
+		nid = (nums >> 16) & 0x000000ff;
+		nums = nums & 0x000000ff;
+
+		for (j = 0; j < nums; j++, nid++) {
+			type = audioha_codec_verb_get(statep, i, nid,
+			    AUDIOHDC_VERB_GET_PARAM,
+			    AUDIOHDC_PAR_FUNCTION_TYPE);
+			switch (type) {
+			case AUDIOHDC_AUDIO_FUNC_GROUP:
+				codec->hc_afg_id = nid;
+				break;
+			default:
+				break;
+			}
+		}
+
+		/* subsystem id is attached to funtion group */
+		codec->hc_sid = audioha_codec_verb_get(statep, i,
+		    codec->hc_afg_id, AUDIOHDC_VERB_GET_PARAM,
+		    AUDIOHDC_PAR_SUBSYS_ID);
+
+		audio_sup_log(statep->hda_ahandle, CE_NOTE,
+		    "!codec info: vid=0x%08x, sid=0x%08x, rev=0x%08x",
+		    codec->hc_vid, codec->hc_sid, codec->hc_revid);
+
+		statep->hda_codec = codec;
+
+		return (AUDIO_SUCCESS);
+	}
+
+	kmem_free(codec, sizeof (audiohd_hda_codec_t));
+	return (AUDIO_FAILURE);
+
+}	/* audiohd_create_codec() */
+
+/*
+ * audiohd_destroy_codec()
+ *
+ * Description:
+ *	destory codec structure, and release its memory
+ */
+static void
+audiohd_destroy_codec(audiohd_state_t *statep)
+{
+	kmem_free(statep->hda_codec, sizeof (audiohd_hda_codec_t));
+	statep->hda_codec = NULL;
+
+}	/* audiohd_destroy_codec() */
+
+
+/*
+ * audiohd_disable_intr()
+ *
+ * Description:
+ *	Disable all possible interrupts.
+ */
+static void
+audiohd_disable_intr(audiohd_state_t *statep)
+{
+	int		i;
+	uint32_t	base;
+
+	AUDIOHD_REG_SET32(AUDIOHD_REG_INTCTL, 0);
+	base = AUDIOHD_REG_SD_BASE;
+	for (i = 0; i < statep->hda_streams_nums; i++) {
+		AUDIOHD_REG_SET8(base + AUDIOHD_SDREG_OFFSET_STS,
+		    AUDIOHDR_SD_STS_INTRS);
+		base += AUDIOHD_REG_SD_LEN;
+	}
+	AUDIOHD_REG_SET32(AUDIOHD_REG_INTSTS, (uint32_t)(-1));
+
+}	/* audiohd_disable_intr() */
+
+
+/*
+ * audiohd_reset_stream()
+ *
+ * Description:
+ *	Reset specified stream
+ */
+static int
+audiohd_reset_stream(audiohd_state_t *statep, int stream)
+{
+	uint32_t	base;
+	uint8_t		bTmp;
+	int		i;
+
+	base = AUDIOHD_REG_SD_BASE + AUDIOHD_REG_SD_LEN * stream;
+	bTmp = AUDIOHD_REG_GET8(base + AUDIOHD_SDREG_OFFSET_CTL);
+
+	/* stop stream */
+	bTmp &= ~AUDIOHD_REG_RIRBSIZE;
+	AUDIOHD_REG_SET8(base + AUDIOHD_SDREG_OFFSET_CTL, bTmp);
+
+	/* wait 40us for stream to stop as HD spec */
+	drv_usecwait(40);
+
+	/* reset stream */
+	bTmp |= AUDIOHDR_SD_CTL_SRST;
+	AUDIOHD_REG_SET8(base + AUDIOHD_SDREG_OFFSET_CTL, bTmp);
+
+	for (i = 0; i < 50; i++) {
+		drv_usecwait(10);
+		bTmp = AUDIOHD_REG_GET8(base + AUDIOHD_SDREG_OFFSET_CTL);
+		bTmp &= AUDIOHDR_SD_CTL_SRST;
+		if (bTmp)
+			break;
+	}
+
+	if (!bTmp) {
+		audio_sup_log(NULL, CE_WARN, "!Failed to reset stream %d",
+		    stream);
+		return (AUDIO_FAILURE);
+	}
+
+	/* Need any RESET# assertion time, 300us ??? */
+	drv_usecwait(50);
+
+	/* exit reset stream */
+	bTmp &= ~AUDIOHDR_SD_CTL_SRST;
+	AUDIOHD_REG_SET8(base + AUDIOHD_SDREG_OFFSET_CTL, bTmp);
+
+	for (i = 0; i < 50; i++) {
+		drv_usecwait(10);
+		bTmp = AUDIOHD_REG_GET8(base + AUDIOHD_SDREG_OFFSET_CTL);
+		bTmp &= AUDIOHDR_SD_CTL_SRST;
+		if (!bTmp)
+			break;
+	}
+
+	if (bTmp) {
+		audio_sup_log(NULL, CE_WARN, "!Failed to exit reset state for"
+		    " stream %d, bTmp=0x%02x", stream, bTmp);
+		return (AUDIO_FAILURE);
+	}
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_reset_stream() */
+
+/*
+ * audiohd_preset_rbuf()
+ *
+ * Description:
+ *	Fill out entries of stream descriptor list for
+ *	recording.
+ */
+static void
+audiohd_preset_rbuf(audiohd_state_t *statep)
+{
+	sd_bdle_t	*entry;
+	uint64_t	 buf_phys_addr;
+	int		i;
+
+	entry = (sd_bdle_t *)(statep->hda_dma_record_bd.ad_vaddr);
+	buf_phys_addr = statep->hda_dma_record_buf.ad_paddr;
+
+	for (i = 0; i < AUDIOHD_BDLE_NUMS; i++) {
+		entry->sbde_addr = buf_phys_addr;
+		entry->sbde_len = statep->hda_rbuf_size;
+		entry->sbde_ioc = 1;
+		buf_phys_addr += statep->hda_rbuf_size;
+		entry++;
+	}
+
+	(void) ddi_dma_sync(statep->hda_dma_record_bd.ad_dmahdl, 0,
+	    sizeof (sd_bdle_t) * AUDIOHD_BDLE_NUMS, DDI_DMA_SYNC_FORDEV);
+
+}	/* audiohd_preset_rbuf() */
+
+/*
+ * audiohd_fill_pbuf()
+ *
+ * Description:
+ *	Get pending audio data, and fill out entries of stream
+ *	descriptor list for playback.
+ */
+static int
+audiohd_fill_pbuf(audiohd_state_t *statep)
+{
+	uint64_t	 buf_phys_addr;
+	sd_bdle_t	*entry;
+	char		*buf;
+	int		samples;
+	int		rs;
+	int		i;
+
+	entry = (sd_bdle_t *)(statep->hda_dma_play_bd.ad_vaddr);
+	buf = (char *)(statep->hda_dma_play_buf.ad_vaddr);
+	buf_phys_addr = statep->hda_dma_play_buf.ad_paddr;
+
+	/* assume that 2-channel, 16-bit */
+	samples = statep->hda_pbuf_size * AUDIOHD_BDLE_NUMS / 2;
+
+	mutex_exit(&statep->hda_mutex);
+	rs = am_get_audio(statep->hda_ahandle, buf, AUDIO_NO_CHANNEL, samples);
+	mutex_enter(&statep->hda_mutex);
+
+	/*
+	 * If we cannot get sample or playback already stopped before
+	 * we re-grab mutex
+	 */
+	if ((rs <= 0) || ((statep->hda_flags & AUDIOHD_PLAY_STARTED) == 0))
+		return (AUDIO_FAILURE);
+
+	for (i = 0; i < AUDIOHD_BDLE_NUMS; i++) {
+		entry->sbde_addr = buf_phys_addr;
+		entry->sbde_len = statep->hda_pbuf_size;
+		entry->sbde_ioc = 1;
+		buf_phys_addr += statep->hda_pbuf_size;
+		entry++;
+	}
+
+	(void) ddi_dma_sync(statep->hda_dma_play_bd.ad_dmahdl, 0,
+	    sizeof (sd_bdle_t) * AUDIOHD_BDLE_NUMS, DDI_DMA_SYNC_FORDEV);
+
+	if (rs == samples)
+		statep->hda_pbuf_pos = 0;
+	else
+		statep->hda_pbuf_pos = (rs << 1);
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_fill_pbuf() */
+
+/*
+ * audiohd_refill_pbuf()
+ *
+ * Description:
+ *	Called by interrupt handler.
+ */
+static void
+audiohd_refill_pbuf(audiohd_state_t *statep)
+{
+	int		rs;
+	int		pos;
+	char		*buf;
+	uint32_t	len;
+	uint32_t	regbase = statep->hda_play_regbase;
+
+	buf = (char *)(statep->hda_dma_play_buf.ad_vaddr);
+	buf += statep->hda_pbuf_pos;
+	pos = AUDIOHD_REG_GET32(regbase + AUDIOHD_SDREG_OFFSET_LPIB);
+	pos &= ~0x00000003;
+
+	if (pos > statep->hda_pbuf_pos) {
+		len = (pos - statep->hda_pbuf_pos) & ~0x00000003;
+	} else {
+		len = statep->hda_pbuf_size * AUDIOHD_BDLE_NUMS -
+		    statep->hda_pbuf_pos;
+		len &= ~0x00000003;
+	}
+	mutex_exit(&statep->hda_mutex);
+	rs = am_get_audio(statep->hda_ahandle, buf, AUDIO_NO_CHANNEL, len / 2);
+	mutex_enter(&statep->hda_mutex);
+
+	if (rs > 0) {
+		statep->hda_flags &= ~AUDIOHD_PLAY_EMPTY;
+		statep->hda_pbuf_pos += (rs << 1);
+		if (statep->hda_pbuf_pos >= statep->hda_pbuf_size *
+		    AUDIOHD_BDLE_NUMS)
+			statep->hda_pbuf_pos = 0;
+		return;
+	}
+
+	/* We didn't get any sample */
+	if ((statep->hda_flags & AUDIOHD_PLAY_EMPTY) == 0)
+		statep->hda_flags |= AUDIOHD_PLAY_EMPTY;
+	else {
+		/* once again, we don't get samples, stop it */
+		AUDIOHD_REG_SET8(regbase + AUDIOHD_SDREG_OFFSET_CTL, 0);
+		statep->hda_flags &= ~(AUDIOHD_PLAY_EMPTY |
+		    AUDIOHD_PLAY_STARTED);
+
+		/* shutdown the mixer */
+		mutex_exit(&statep->hda_mutex);
+		am_play_shutdown(statep->hda_ahandle, NULL);
+		mutex_enter(&statep->hda_mutex);
+	}
+
+}	/* audiohd_refill_pbuf() */
+
+
+/*
+ * audiohd_get_rbuf()
+ *
+ * Description:
+ *	Called by interrupt handler.
+ */
+static void
+audiohd_get_rbuf(audiohd_state_t *statep)
+{
+	uint32_t	regbase;
+	uint32_t	len;
+	char		*buf;
+	int		pos;
+
+	regbase = statep->hda_record_regbase;
+	pos = AUDIOHD_REG_GET32(regbase + AUDIOHD_SDREG_OFFSET_LPIB);
+	pos &= ~0x00000003;
+	buf = (char *)statep->hda_dma_record_buf.ad_vaddr;
+	buf += statep->hda_rbuf_pos;
+
+	if (pos > statep->hda_rbuf_pos) {
+		len = (pos - statep->hda_rbuf_pos) & ~0x00000003;
+		mutex_exit(&statep->hda_mutex);
+		am_send_audio(statep->hda_ahandle, buf, AUDIO_NO_CHANNEL,
+		    len / 2);
+		mutex_enter(&statep->hda_mutex);
+		statep->hda_rbuf_pos += len;
+		if (statep->hda_rbuf_pos >= statep->hda_rbuf_size *
+		    AUDIOHD_BDLE_NUMS)
+			statep->hda_rbuf_pos = 0;
+	} else {
+		len = statep->hda_rbuf_size * AUDIOHD_BDLE_NUMS -
+		    statep->hda_rbuf_pos;
+		mutex_exit(&statep->hda_mutex);
+		am_send_audio(statep->hda_ahandle, buf, AUDIO_NO_CHANNEL,
+		    len / 2);
+		mutex_enter(&statep->hda_mutex);
+		statep->hda_rbuf_pos = 0;
+	}
+
+}	/* audiohd_get_rbuf() */
+
+/*
+ * auidohd_set_gain()
+ *
+ * Description:
+ */
+static int
+audiohd_set_gain(audiohd_state_t *statep, int dir, int gain, int channel)
+{
+	int rc;
+
+	if (gain > AUDIO_MAX_GAIN) {
+		gain = AUDIO_MAX_GAIN;
+	} else if (gain < AUDIO_MIN_GAIN) {
+		gain = AUDIO_MIN_GAIN;
+	}
+
+	/*
+	 * SADA uses 255 as the max volume, but HD spec us 0x3f
+	 * adjust vlaue of gain
+	 */
+	gain = gain * AUDIOHDC_GAIN_MAX / AUDIO_MAX_GAIN;
+
+	rc = AUDIOHD_CODEC_SET_GAIN(statep, dir, gain, channel);
+	return (rc);
+
+}	/* audiohd_set_gain() */
+
+/*
+ * audiohd_set_port()
+ *
+ * Description:
+ *
+ */
+static int
+audiohd_set_port(audiohd_state_t *statep, int dir, int port)
+{
+	int rc;
+
+	rc = AUDIOHD_CODEC_SET_PORT(statep, dir, port);
+
+	return (rc);
+
+}	/* audiohd_set_port() */
+
+/*
+ * audiohd_mute_outputs()
+ */
+static void
+audiohd_mute_outputs(audiohd_state_t *statep, boolean_t mute)
+{
+	(void) AUDIOHD_CODEC_MUTE_OUTPUTS(statep, mute);
+
+}	/* audiohd_mute_outputs() */
+
+/*
+ * audiohd_set_monitor_gain()
+ *
+ * Description:
+ *
+ */
+static int
+audiohd_set_monitor_gain(audiohd_state_t *statep, int gain)
+{
+	int	ret;
+
+	ASSERT(statep);
+
+	if (gain > AUDIO_MAX_GAIN) {
+		gain = AUDIO_MAX_GAIN;
+	} else if (gain < AUDIO_MIN_GAIN) {
+		gain = AUDIO_MIN_GAIN;
+	}
+	gain = gain * AUDIOHDC_GAIN_MAX / AUDIO_MAX_GAIN;
+	statep->hda_monitor_gain = gain;
+
+	if (statep->hda_in_ports == AUDIO_NONE)
+		ret = AUDIO_SUCCESS;
+	else
+		ret = AUDIOHD_CODEC_SET_MON_GAIN(statep, gain);
+
+	return (ret);
+
+}	/* audiohd_set_monitor_gain() */
+
+/*
+ * audiohd_12bit_verb_to_codec()
+ *
+ * Description:
+ *
+ */
+static int
+audiohd_12bit_verb_to_codec(audiohd_state_t *statep, uint8_t caddr, uint8_t nid,
+    uint16_t cmd, uint8_t param)
+{
+	uint32_t	verb;
+	uint16_t	wptr;
+	uint16_t	rptr;
+
+	ASSERT((cmd & 0xfff000ff) == 0);
+
+	wptr = AUDIOHD_REG_GET16(AUDIOHD_REG_CORBWP) & AUDIOHD_CMDIO_ENT_MASK;
+	rptr = AUDIOHD_REG_GET16(AUDIOHD_REG_CORBRP) & AUDIOHD_CMDIO_ENT_MASK;
+
+	wptr++;
+	wptr &= AUDIOHD_CMDIO_ENT_MASK;
+
+	/* overflow */
+	if (wptr == rptr) {
+		return (AUDIO_FAILURE);
+	}
+
+	verb = (caddr & 0x0f) << 28;
+	verb |= nid << 20;
+	verb |= cmd << 8;
+	verb |= param;
+
+	*((uint32_t *)(statep->hda_dma_corb.ad_vaddr) + wptr) = verb;
+	AUDIOHD_REG_SET16(AUDIOHD_REG_CORBWP, wptr);
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_12bit_verb_to_codec() */
+
+/*
+ * audiohd_4bit_verb_to_codec()
+ *
+ * Description:
+ *
+ */
+static int
+audiohd_4bit_verb_to_codec(audiohd_state_t *statep, uint8_t caddr, uint8_t nid,
+    uint32_t cmd, uint16_t param)
+{
+	uint32_t	verb;
+	uint16_t	wptr;
+	uint16_t	rptr;
+
+	ASSERT((cmd & 0xfff000ff) == 0);
+
+	wptr = AUDIOHD_REG_GET16(AUDIOHD_REG_CORBWP) & AUDIOHD_CMDIO_ENT_MASK;
+	rptr = AUDIOHD_REG_GET16(AUDIOHD_REG_CORBRP) & AUDIOHD_CMDIO_ENT_MASK;
+
+	wptr++;
+	wptr &= AUDIOHD_CMDIO_ENT_MASK;
+
+	/* overflow */
+	if (wptr == rptr) {
+		return (AUDIO_FAILURE);
+	}
+
+	verb = (caddr & 0x0f) << 28;
+	verb |= nid << 20;
+	verb |= cmd << 16;
+	verb |= param;
+
+	*((uint32_t *)(statep->hda_dma_corb.ad_vaddr) + wptr) = verb;
+	AUDIOHD_REG_SET16(AUDIOHD_REG_CORBWP, wptr);
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_4bit_verb_to_codec() */
+
+/*
+ * audiohd_response_from_codec()
+ *
+ * Description:
+ *
+ */
+static int
+audiohd_response_from_codec(audiohd_state_t *statep, uint32_t *resp,
+    uint32_t *respex)
+{
+	uint16_t	wptr;
+	uint16_t	rptr;
+	uint32_t	*lp;
+
+	wptr = AUDIOHD_REG_GET16(AUDIOHD_REG_RIRBWP) & 0x00ff;
+	rptr = statep->hda_rirb_rp;
+
+	if (rptr == wptr) {
+		return (AUDIO_FAILURE);
+	}
+
+	rptr++;
+	rptr &= 0x00ff;
+
+	lp = (uint32_t *)(statep->hda_dma_rirb.ad_vaddr) + (rptr << 1);
+	*resp = *(lp);
+	*respex = *(lp + 1);
+
+	statep->hda_rirb_rp = rptr;
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_response_from_codec() */
+
+
+/*
+ * audioha_codec_verb_get()
+ */
+static uint32_t
+audioha_codec_verb_get(void *arg, uint8_t caddr, uint8_t nid, uint16_t verb,
+    uint8_t param)
+{
+	audiohd_state_t	*statep = (audiohd_state_t *)arg;
+	uint32_t	resp;
+	uint32_t	respex;
+	int		ret;
+	int		i;
+
+	ret = audiohd_12bit_verb_to_codec(statep, caddr, nid, verb, param);
+	if (ret != AUDIO_SUCCESS) {
+		return (uint32_t)(-1);
+	}
+
+	for (i = 0; i < 50; i++) {
+		drv_usecwait(30);
+		ret = audiohd_response_from_codec(statep, &resp, &respex);
+		if (((respex & AUDIOHD_BDLE_RIRB_SDI) == caddr) &&
+		    ((respex & AUDIOHD_BDLE_RIRB_UNSOLICIT) == 0) &&
+		    (ret == AUDIO_SUCCESS))
+			break;
+	}
+
+	if (ret == AUDIO_SUCCESS) {
+		return (resp);
+	}
+
+	audio_sup_log(NULL, CE_WARN, "!%s: verb_get() timeout when get "
+	    " response from codec: nid=%d, verb=0x%04x, param=0x%04x",
+	    audiohd_name, nid, verb, param);
+
+	return ((uint32_t)(-1));
+
+}	/* audioha_codec_verb_get() */
+
+
+/*
+ * audioha_codec_4bit_verb_get()
+ */
+static uint32_t
+audioha_codec_4bit_verb_get(void *arg, uint8_t caddr, uint8_t nid, uint16_t
+    verb, uint16_t param)
+{
+	audiohd_state_t	*statep = (audiohd_state_t *)arg;
+	uint32_t	resp;
+	uint32_t	respex;
+	int		ret;
+	int		i;
+
+	ret = audiohd_4bit_verb_to_codec(statep, caddr, nid, verb, param);
+	if (ret != AUDIO_SUCCESS) {
+		return (uint32_t)(-1);
+	}
+
+	for (i = 0; i < 50; i++) {
+		drv_usecwait(30);
+		ret = audiohd_response_from_codec(statep, &resp, &respex);
+		if (((respex & AUDIOHD_BDLE_RIRB_SDI) == caddr) &&
+		    ((respex & AUDIOHD_BDLE_RIRB_UNSOLICIT) == 0) &&
+		    (ret == AUDIO_SUCCESS))
+			break;
+	}
+
+	if (ret == AUDIO_SUCCESS) {
+		return (resp);
+	}
+
+	audio_sup_log(NULL, CE_WARN, "!%s: verb_get() timeout when get "
+	    " response from codec: nid=%d, verb=0x%04x, param=0x%04x",
+	    audiohd_name, nid, verb, param);
+
+	return ((uint32_t)(-1));
+
+}	/* audioha_codec_4bit_verb_get() */
+
+
+/*
+ * audiohd_alc880_enable_play()
+ */
+static int
+audiohd_alc880_enable_play(audiohd_state_t *statep)
+{
+	uint32_t	lTmp;
+	uint_t		output_val;
+	uint_t		input_val;
+	uint_t		caddr = statep->hda_codec->hc_addr;
+
+	lTmp = audioha_codec_verb_get(statep, caddr, AUDIOHDC_NID(0x02),
+	    AUDIOHDC_VERB_SET_STREAM_CHANN, statep->hda_play_stag << 4);
+	if (lTmp == AUDIOHD_CODEC_FAILURE)
+		return (AUDIO_FAILURE);
+
+	output_val = AUDIOHDC_AMP_SET_OUTPUT;
+	output_val |= AUDIOHDC_AMP_SET_LEFT | AUDIOHDC_AMP_SET_RIGHT;
+	output_val |= AUDIOHDC_GAIN_MAX;
+
+	input_val = AUDIOHDC_AMP_SET_INPUT;
+	input_val |= AUDIOHDC_AMP_SET_LEFT | AUDIOHDC_AMP_SET_RIGHT;
+	input_val |= AUDIOHDC_GAIN_MAX;
+
+	/* output amp of DAC */
+	lTmp = audioha_codec_4bit_verb_get(statep, caddr, AUDIOHDC_NID(0x02),
+	    AUDIOHDC_VERB_SET_AMP_MUTE, output_val);
+
+	if (lTmp == AUDIOHD_CODEC_FAILURE)
+		return (AUDIO_FAILURE);
+
+	/* unmute input for DAC2 of mixer */
+	lTmp = audioha_codec_4bit_verb_get(statep, caddr, AUDIOHDC_NID(0xc),
+	    AUDIOHDC_VERB_SET_AMP_MUTE, input_val);
+
+	if (lTmp == AUDIOHD_CODEC_FAILURE)
+		return (AUDIO_FAILURE);
+
+	/* output amp of mixer */
+	(void) audioha_codec_4bit_verb_get(statep, caddr, AUDIOHDC_NID(0xc),
+	    AUDIOHDC_VERB_SET_AMP_MUTE, AUDIOHDC_AMP_SET_OUTPUT |
+	    AUDIOHDC_AMP_SET_LEFT | statep->hda_play_lgain);
+
+	(void) audioha_codec_4bit_verb_get(statep, caddr, AUDIOHDC_NID(0xc),
+	    AUDIOHDC_VERB_SET_AMP_MUTE, AUDIOHDC_AMP_SET_OUTPUT |
+	    AUDIOHDC_AMP_SET_RIGHT | statep->hda_play_rgain);
+
+	/* Unmute pin */
+	lTmp = audioha_codec_4bit_verb_get(statep, caddr, AUDIOHDC_NID(0x14),
+	    AUDIOHDC_VERB_SET_AMP_MUTE, output_val);
+	if (lTmp == AUDIOHD_CODEC_FAILURE)
+		return (AUDIO_FAILURE);
+
+	/* enable output for pin node 0x14 */
+	lTmp = audioha_codec_verb_get(statep, caddr, AUDIOHDC_NID(0x14),
+	    AUDIOHDC_VERB_GET_PIN_CTRL, 0);
+	if (lTmp == AUDIOHD_CODEC_FAILURE)
+		return (AUDIO_FAILURE);
+	lTmp = audioha_codec_verb_get(statep, caddr, AUDIOHDC_NID(0x14),
+	    AUDIOHDC_VERB_SET_PIN_CTRL, (lTmp |
+	    AUDIOHDC_PIN_CONTROL_OUT_ENABLE));
+	if (lTmp == AUDIOHD_CODEC_FAILURE)
+		return (AUDIO_FAILURE);
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_alc880_enable_play() */
+
+/*
+ * audiohd_alc880_enable_record()
+ */
+static int
+audiohd_alc880_enable_record(audiohd_state_t *statep)
+{
+	uint32_t	lTmp;
+	uint_t		val;
+	uint_t		caddr = statep->hda_codec->hc_addr;
+
+	/* for ADC node 0x9, set channel and stream tag */
+	lTmp = audioha_codec_verb_get(statep, caddr, AUDIOHDC_NID(0x09),
+	    AUDIOHDC_VERB_SET_STREAM_CHANN, statep->hda_record_stag << 4);
+	if (lTmp == AUDIOHD_CODEC_FAILURE)
+		return (AUDIO_FAILURE);
+
+	/* input amp of ADC node 0x9 */
+	val = AUDIOHDC_AMP_SET_INPUT;
+	val |= AUDIOHDC_AMP_SET_LEFT | AUDIOHDC_AMP_SET_RIGHT;
+	lTmp = audioha_codec_4bit_verb_get(statep, caddr, AUDIOHDC_NID(0x09),
+	    AUDIOHDC_VERB_SET_AMP_MUTE, val | AUDIOHDC_GAIN_MAX);
+	if (lTmp == AUDIOHD_CODEC_FAILURE)
+		return (AUDIO_FAILURE);
+
+	/*
+	 * enable gain for monitor path, from node 0x0B to node 0x0C,
+	 * In the input list of 0x0c, 0x0b node has index 1
+	 */
+	val |= (1 << AUDIOHDC_AMP_SET_INDEX_OFFSET) | statep->hda_monitor_gain;
+	lTmp = audioha_codec_4bit_verb_get(statep, caddr, AUDIOHDC_NID(0x0C),
+	    AUDIOHDC_VERB_SET_AMP_MUTE, val);
+	if (lTmp == AUDIOHD_CODEC_FAILURE) {
+		audio_sup_log(statep->hda_ahandle, CE_WARN,
+		    "!alc880_enable_record() failed to set monitor");
+	}
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_alc880_enable_record */
+
+/*
+ * audiohd_alc880_set_pcm_fmt()
+ */
+static int
+audiohd_alc880_set_pcm_fmt(audiohd_state_t *statep, int dir, uint_t format)
+{
+	uint32_t	lTmp;
+	uint_t		caddr = statep->hda_codec->hc_addr;
+
+	if (dir == AUDIO_PLAY) {
+		lTmp = audioha_codec_4bit_verb_get(statep, caddr,
+		    AUDIOHDC_NID(0x2), AUDIOHDC_VERB_SET_CONVERTER_FMT, format);
+	} else {
+		lTmp = audioha_codec_4bit_verb_get(statep, caddr,
+		    AUDIOHDC_NID(0x9), AUDIOHDC_VERB_SET_CONVERTER_FMT, format);
+	}
+
+	if (lTmp == AUDIOHD_CODEC_FAILURE)
+		return (AUDIO_FAILURE);
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_alc880_set_pcm_fmt() */
+
+/*
+ * audiohd_alc880_set_gain()
+ */
+static int
+audiohd_alc880_set_gain(audiohd_state_t *statep, int dir, int gain, int channel)
+{
+	uint32_t	lTmp;
+	uint_t		val;
+	uint_t		caddr = statep->hda_codec->hc_addr;
+
+	if (dir == AUDIO_PLAY) {
+		val = AUDIOHDC_AMP_SET_OUTPUT | gain;
+		if (channel == 0) {
+			/* left channel */
+			val |= AUDIOHDC_AMP_SET_LEFT;
+			statep->hda_play_lgain = gain;
+		} else {
+			/* right channel */
+			val |= AUDIOHDC_AMP_SET_RIGHT;
+			statep->hda_play_rgain = gain;
+		}
+		lTmp = audioha_codec_4bit_verb_get(statep, caddr,
+		    AUDIOHDC_NID(0xC), AUDIOHDC_VERB_SET_AMP_MUTE, val);
+	} else {
+		ASSERT(dir == AUDIO_RECORD);
+		val = AUDIOHDC_AMP_SET_INPUT | gain;
+		if (channel == 0) {
+			/* left channel */
+			val |= AUDIOHDC_AMP_SET_LEFT;
+			statep->hda_record_lgain = gain;
+		} else {
+			/* right channel */
+			val |= AUDIOHDC_AMP_SET_RIGHT;
+			statep->hda_record_rgain = gain;
+		}
+		lTmp = audioha_codec_4bit_verb_get(statep, caddr,
+		    AUDIOHDC_NID(0x9), AUDIOHDC_VERB_SET_AMP_MUTE, val);
+	}
+
+	if (lTmp == AUDIOHD_CODEC_FAILURE)
+		return (AUDIO_FAILURE);
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_alc880_set_gain() */
+
+/*
+ * audiohd_alc880_set_port()
+ */
+static int
+audiohd_alc880_set_port(audiohd_state_t *statep, int dir, int port)
+{
+	uint_t	val;
+	uint_t	nid_pin;
+	uint_t	tmp_port = 0;
+	uint_t	caddr = statep->hda_codec->hc_addr;
+
+	if (dir == AUDIO_PLAY) {
+
+		if (port == AUDIOHD_PORT_UNMUTE) {
+			port = statep->hda_out_ports;
+		}
+
+		val = AUDIOHDC_AMP_SET_OUTPUT;
+		val |= AUDIOHDC_AMP_SET_LEFT | AUDIOHDC_AMP_SET_RIGHT;
+		if (port & AUDIO_HEADPHONE) {
+			tmp_port |= AUDIO_HEADPHONE;
+		} else { /* mute */
+			val |= AUDIOHDC_AMP_SET_MUTE;
+		}
+
+		if (tmp_port != port)
+			return (AUDIO_FAILURE);
+
+		statep->hda_out_ports = tmp_port;
+
+		if (audioha_codec_4bit_verb_get(statep, caddr,
+		    AUDIOHDC_NID(0x14), AUDIOHDC_VERB_SET_AMP_MUTE, val) ==
+		    AUDIOHD_CODEC_FAILURE)
+			return (AUDIO_FAILURE);
+		else
+			return (AUDIO_SUCCESS);
+	}
+
+	/*
+	 * Now, deal with reocrding
+	 */
+	ASSERT(dir == AUDIO_RECORD);
+
+	switch (port) {
+	case AUDIO_NONE:
+		/* mute ADC node 0x09 */
+		val = AUDIOHDC_AMP_SET_INPUT | AUDIOHDC_AMP_SET_MUTE;
+		val |= AUDIOHDC_AMP_SET_LEFT | AUDIOHDC_AMP_SET_RIGHT;
+		(void) audioha_codec_4bit_verb_get(statep, caddr,
+		    AUDIOHDC_NID(0x9), AUDIOHDC_VERB_SET_AMP_MUTE, val);
+		statep->hda_in_ports = port;
+		return (AUDIO_SUCCESS);
+
+	case AUDIO_MICROPHONE:
+		tmp_port = 0;	/* MIC1 */
+		nid_pin = 0x18;
+		break;
+	case AUDIO_LINE_IN:
+		tmp_port = 2;	/* Line-in1 */
+		nid_pin = 0x1a;
+		break;
+	case AUDIO_CD:
+		tmp_port = 4;	/* CD in */
+		nid_pin = 0x1c;
+		break;
+	default:
+		return (AUDIO_FAILURE);
+	}
+
+	/* if ADC 0x09 is muted, we resume its gains */
+	if (statep->hda_in_ports == AUDIO_NONE) {
+		(void) audioha_codec_4bit_verb_get(statep, caddr,
+		    AUDIOHDC_NID(0x9), AUDIOHDC_VERB_SET_AMP_MUTE,
+		    (AUDIOHDC_AMP_SET_INPUT | AUDIOHDC_AMP_SET_LEFT |
+		    statep->hda_record_lgain));
+		(void) audioha_codec_4bit_verb_get(statep, caddr,
+		    AUDIOHDC_NID(0x9), AUDIOHDC_VERB_SET_AMP_MUTE,
+		    (AUDIOHDC_AMP_SET_INPUT | AUDIOHDC_AMP_SET_RIGHT |
+		    statep->hda_record_rgain));
+	}
+
+	switch (statep->hda_codec->hc_vid) {
+	case AUDIOHD_VID_ALC880:
+		/*
+		 * For ALC880, node 9 has multiple inputs,
+		 * we need to select the right one among
+		 * those inputs
+		 */
+		(void) audioha_codec_verb_get(statep, caddr,
+		    AUDIOHDC_NID(0x9), AUDIOHDC_VERB_SET_CONN_SEL,
+		    tmp_port);
+		break;
+
+	case AUDIOHD_VID_ALC883:
+	case AUDIOHD_VID_ALC885:
+		/*
+		 * For ALC883/885, node 9 has only one input,
+		 * which is a mixer with node number 0x22. So,
+		 * we mute all inputs except the one selected
+		 * by users. Note that all inputs are muted by
+		 * default, it is needed to mute the one being
+		 * used.
+		 */
+
+		/* mute old input port */
+		val = AUDIOHDC_AMP_SET_INPUT;
+		val |= AUDIOHDC_AMP_SET_LEFT | AUDIOHDC_AMP_SET_RIGHT;
+		val |= (statep->hda_in_ports << AUDIOHDC_AMP_SET_INDEX_OFFSET);
+
+		(void) audioha_codec_4bit_verb_get(statep, caddr,
+		    AUDIOHDC_NID(0x22), AUDIOHDC_VERB_SET_AMP_MUTE,
+		    (val | AUDIOHDC_AMP_SET_MUTE));
+
+		/* unmute new input port */
+		(void) audioha_codec_4bit_verb_get(statep, caddr,
+		    AUDIOHDC_NID(0x22), AUDIOHDC_VERB_SET_AMP_MUTE,
+		    val | (tmp_port << AUDIOHDC_AMP_SET_INDEX_OFFSET));
+		break;
+
+	default:
+		/* impossible to reach here */
+		break;
+	}
+
+	(void) audioha_codec_verb_get(statep, caddr, nid_pin,
+	    AUDIOHDC_VERB_SET_PIN_CTRL, AUDIOHDC_PIN_CONTROL_IN_ENABLE | 4);
+
+	statep->hda_in_ports = port;
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_alc880_set_port() */
+
+/*
+ * audiohd_alc880_mute_outputs()
+ */
+static int
+audiohd_alc880_mute_outputs(audiohd_state_t *statep, boolean_t mute)
+{
+	uint_t	val;
+	uint_t	caddr = statep->hda_codec->hc_addr;
+
+	if (mute) {
+		val = AUDIOHDC_AMP_SET_OUTPUT;
+		val |= AUDIOHDC_AMP_SET_LEFT | AUDIOHDC_AMP_SET_RIGHT;
+		val |= AUDIOHDC_AMP_SET_MUTE;
+	} else {
+		val = AUDIOHDC_AMP_SET_OUTPUT;
+		val |= AUDIOHDC_AMP_SET_LEFT | AUDIOHDC_AMP_SET_RIGHT;
+	}
+
+	(void) audioha_codec_4bit_verb_get(statep, caddr,
+		AUDIOHDC_NID(0x14), AUDIOHDC_VERB_SET_AMP_MUTE, val);
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_alc880_mute_outputs() */
+
+/*
+ * audiohd_alc880_set_monitor_gain()
+ */
+static int
+audiohd_alc880_set_monitor_gain(audiohd_state_t *statep, int gain)
+{
+	uint_t	val;
+	uint_t	index;
+	uint_t	caddr = statep->hda_codec->hc_addr;
+
+	switch (statep->hda_in_ports) {
+	case AUDIO_MICROPHONE:
+		index = 0;
+		break;
+	case AUDIO_LINE_IN:
+		index = 2;
+		break;
+	case AUDIO_CD:
+		index = 4;
+		break;
+	}
+
+	val = AUDIOHDC_AMP_SET_INPUT;
+	val |= AUDIOHDC_AMP_SET_LEFT | AUDIOHDC_AMP_SET_RIGHT;
+	val |= (index << AUDIOHDC_AMP_SET_INDEX_OFFSET);
+	val |= gain;
+
+	(void) audioha_codec_4bit_verb_get(statep, caddr,
+	    AUDIOHDC_NID(0xB), AUDIOHDC_VERB_SET_AMP_MUTE, val);
+
+	return (AUDIO_SUCCESS);
+
+}	/* audiohd_alc880_set_monitor_gain() */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/audio/sada/drv/audiohd/audiohd.conf	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,66 @@
+#
+# 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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Configuration file for the audiohd audio driver.
+#
+#	WARNING: This is an UNSTABLE configuration file. Its contents
+#		may change at any time.
+
+#
+# Uncomment cdrom to enable the audiohd driver to use the CDROM analog
+# input. 
+#
+# cdrom=1;
+
+#
+# play-interrupts sets the number of interrupts per second when playing.
+# This affects the resolution of various things, such as sample counts.
+# record-interrupts does the same for record interrupts.
+#
+# These may be tuned to get more accurate information by increasing the
+# count. However, the larger the interrupts per second the larger the
+# load on the system. So use this capability cautiously. The audiohd
+# driver enforces a maximum and minimum count.
+#
+# It should also be understood that not all interrupt rates are legal.
+# The hardware is restricted to DMA buffers being allocated on certain
+# boundaries. If those boundaries are violated the driver will not be
+# loaded and an error message is entered into the messages log
+#
+play-interrupts=175;
+record-interrupts=175;
+
+#
+# Uncomment reset-configuration to cause the audiohd driver's state to
+# be reset to the default when the driver is loaded. Otherwise this state
+# is retained across driver unload/reload cycles, but not across reboots.
+#
+#reset-configuration=1;
+
+#
+# We need change the priority so that we aren't high level interrupt.
+#
+interrupt-priorities=9;
--- a/usr/src/uts/common/sys/Makefile	Thu Jun 29 15:21:59 2006 -0700
+++ b/usr/src/uts/common/sys/Makefile	Thu Jun 29 20:57:57 2006 -0700
@@ -46,6 +46,7 @@
 	agpgart.h		\
 	asy.h			\
 	audio/audio810.h	\
+	audio/audiohd.h	\
 	bmc_intf.h		\
 	fd_debug.h		\
 	fdc.h			\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/audio/audiohd.h	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,88 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_SYS_AUDIOHD_H_
+#define	_SYS_AUDIOHD_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/thread.h>
+#include <sys/synch.h>
+#include <sys/kstat.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/audio.h>
+#include <sys/audio/audio_support.h>
+#include <sys/mixer.h>
+#include <sys/audio/audio_mixer.h>
+
+
+#define	AUDIOHD_SAMPR5510		5510
+#define	AUDIOHD_SAMPR6620		6620
+#define	AUDIOHD_SAMPR8000		8000
+#define	AUDIOHD_SAMPR9600		9600
+#define	AUDIOHD_SAMPR11025		11025
+#define	AUDIOHD_SAMPR16000		16000
+#define	AUDIOHD_SAMPR18900		18900
+#define	AUDIOHD_SAMPR22050		22050
+#define	AUDIOHD_SAMPR27420		27420
+#define	AUDIOHD_SAMPR32000		32000
+#define	AUDIOHD_SAMPR33075		33075
+#define	AUDIOHD_SAMPR37800		37800
+#define	AUDIOHD_SAMPR44100		44100
+#define	AUDIOHD_SAMPR48000		48000
+
+#define	AUDIOHD_SAMPLER_MAX	AUDIOHD_SAMPR48000
+#define	AUDIOHD_MIN_INTS	32
+#define	AUDIOHD_MAX_INTS	1500
+#define	AUDIOHD_INTS	50
+#define	AUDIOHD_MAX_PRECISION	AUDIO_PRECISION_16
+#define	AUDIOHD_MAX_CHANNELS	AUDIO_CHANNELS_STEREO
+#define	AUDIOHD_MAX_OUT_CHANNELS	AUDIO_CHANNELS_STEREO
+
+#define	AUDIOHD_BSIZE		8192
+#define	AUDIOHD_DEFAULT_SR	8000
+#define	AUDIOHD_DEFAULT_CH	AUDIO_CHANNELS_MONO
+#define	AUDIOHD_DEFAULT_PREC	AUDIO_PRECISION_8
+#define	AUDIOHD_DEFAULT_ENC		AUDIO_ENCODING_ULAW
+#define	AUDIOHD_DEFAULT_PGAIN	(AUDIO_MAX_GAIN * 3 / 4)
+#define	AUDIOHD_DEFAULT_RGAIN	127
+#define	AUDIOHD_DEFAULT_BAL			AUDIO_MID_BALANCE
+#define	AUDIOHD_DEFAULT_MONITOR_GAIN		0
+
+#define	AUDIOHD_DEV_NAME	"audiohd"
+#define	AUDIOHD_DEV_CONFIG	"hda audio config"
+#define	AUDIOHD_DEV_VERSION	"a"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _SYS_AUDIOHD_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/audio/impl/audiohd_impl.h	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,470 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#ifndef _SYS_AUDIOHD_IMPL_H_
+#define	_SYS_AUDIOHD_IMPL_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/thread.h>
+#include <sys/synch.h>
+#include <sys/kstat.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/audio.h>
+#include <sys/audio/audio_support.h>
+#include <sys/mixer.h>
+#include <sys/audio/audio_mixer.h>
+#include <sys/audio/audiohd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define	AUDIOHD_VID_ALC880	0x10ec0880
+#define	AUDIOHD_VID_ALC883	0x10ec0883
+#define	AUDIOHD_VID_ALC885	0x10ec0885
+
+#define	AUDIOHDC_NID(x)		x
+/*
+ * currently, only the format of 48K sample rate, 16-bit
+ * 2-channel is supported.
+ */
+#define	AUDIOHD_FMT_PCMOUT	0x0011
+#define	AUDIOHD_FMT_PCMIN	0x0011
+
+
+#define	AUDIOHD_CODEC_MAX	15
+#define	AUDIOHD_MEMIO_LEN	0x4000
+
+#define	AUDIOHD_BDLE_BUF_ALIGN	128
+#define	AUDIOHD_CMDIO_ENT_MASK	0x00ff	/* 256 entries for CORB/RIRB */
+#define	AUDIOHD_CDBIO_CORB_LEN	1024	/* 256 entries for CORB, 1024B */
+#define	AUDIOHD_CDBIO_RIRB_LEN	2048	/* 256 entries for RIRB, 2048B */
+#define	AUDIOHD_BDLE_NUMS	4	/* 4 entires for record/play BD list */
+
+#define	AUDIOHD_MOD_NAME	"HD Audio Driver"
+#define	AUDIOHD_IDNUM		0x6176
+#define	AUDIOHD_NAME		"SUNW,audiohd"
+#define	AUDIOHD_MINPACKET	(0)
+#define	AUDIOHD_MAXPACKET	(1024)
+#define	AUDIOHD_HIWATER		(64*1024)
+#define	AUDIOHD_LOWATER		(32*1024)
+
+#define	AUDIOHD_PORT_UNMUTE	(0xffffffff)
+
+/*
+ * Audio registers of high definition
+ */
+#define	AUDIOHD_REG_GCAP		0x00
+#define	AUDIOHDR_GCAP_OUTSTREAMS	0xf000
+#define	AUDIOHDR_GCAP_INSTREAMS		0x0f00
+#define	AUDIOHDR_GCAP_BSTREAMS		0x00f8
+#define	AUDIOHDR_GCAP_NSDO		0x0006
+#define	AUDIOHDR_GCAP_64OK		0x0001
+
+#define	AUDIOHD_REG_VMIN		0x02
+#define	AUDIOHD_REG_VMAJ		0x03
+#define	AUDIOHD_REG_OUTPAY		0x04
+#define	AUDIOHD_REG_INPAY		0x06
+#define	AUDIOHD_REG_GCTL		0x08
+#define	AUDIOHD_REG_WAKEEN		0x0C
+#define	AUDIOHD_REG_STATESTS		0x0E
+#define	AUDIOHD_STATESTS_BIT_SDINS	0x7F
+
+#define	AUDIOHD_REG_GSTS		0x10
+#define	AUDIOHD_REG_INTCTL		0x20
+#define	AUDIOHD_INTCTL_BIT_GIE		0x80000000
+#define	AUDIOHD_INTCTL_BIT_CIE		0x40000000
+#define	AUDIOHD_INTCTL_BIT_SIE		0x3FFFFFFF
+
+
+#define	AUDIOHD_REG_INTSTS		0x24
+#define	AUDIOHD_INTSTS_BIT_GIS		0x80000000
+#define	AUDIOHD_INTSTS_BIT_CIS		0x40000000
+#define	AUDIOHD_INTSTS_BIT_SINTS	(0x3fffffff)
+
+#define	AUDIOHD_REG_WALCLK		0x30
+#define	AUDIOHD_REG_SYNC		0x34
+
+#define	AUDIOHD_REG_CORBLBASE		0x40
+#define	AUDIOHD_REG_CORBUBASE		0x44
+#define	AUDIOHD_REG_CORBWP		0x48
+#define	AUDIOHD_REG_CORBRP		0x4A
+#define	AUDIOHD_REG_CORBCTL		0x4C
+#define	AUDIOHD_REG_CORBST		0x4D
+#define	AUDIOHD_REG_CORBSIZE		0x4E
+
+#define	AUDIOHD_REG_RIRBLBASE		0x50
+#define	AUDIOHD_REG_RIRBUBASE		0x54
+#define	AUDIOHD_REG_RIRBWP		0x58
+#define	AUDIOHD_REG_RINTCNT		0x5A
+#define	AUDIOHD_REG_RIRBCTL		0x5C
+#define	AUDIOHD_REG_RIRBSTS		0x5D
+#define	AUDIOHD_REG_RIRBSIZE		0x5E
+
+#define	AUDIOHD_REG_IC			0x60
+#define	AUDIOHD_REG_IR			0x64
+#define	AUDIOHD_REG_IRS			0x68
+#define	AUDIOHD_REG_DPLBASE		0x70
+#define	AUDIOHD_REG_DPUBASE		0x74
+
+#define	AUDIOHD_REG_SD_BASE		0x80
+#define	AUDIOHD_REG_SD_LEN		0x20
+
+/*
+ * Offset of Stream Descriptor Registers
+ */
+#define	AUDIOHD_SDREG_OFFSET_CTL		0x00
+#define	AUDIOHD_SDREG_OFFSET_STS		0x03
+#define	AUDIOHD_SDREG_OFFSET_LPIB		0x04
+#define	AUDIOHD_SDREG_OFFSET_CBL		0x08
+#define	AUDIOHD_SDREG_OFFSET_LVI		0x0c
+#define	AUDIOHD_SDREG_OFFSET_FIFOW		0x0e
+#define	AUDIOHD_SDREG_OFFSET_FIFOSIZE		0x10
+#define	AUDIOHD_SDREG_OFFSET_FORMAT		0x12
+#define	AUDIOHD_SDREG_OFFSET_BDLPL		0x18
+#define	AUDIOHD_SDREG_OFFSET_BDLPU		0x1c
+
+/* bits for stream descriptor control reg */
+#define	AUDIOHDR_SD_CTL_DEIE		0x000010
+#define	AUDIOHDR_SD_CTL_FEIE		0x000008
+#define	AUDIOHDR_SD_CTL_IOCE		0x000004
+#define	AUDIOHDR_SD_CTL_SRUN		0x000002
+#define	AUDIOHDR_SD_CTL_SRST		0x000001
+#define	AUDIOHDR_SD_CTL_INTS	\
+	(AUDIOHDR_SD_CTL_DEIE |	\
+	AUDIOHDR_SD_CTL_FEIE |	\
+	AUDIOHDR_SD_CTL_IOCE)
+
+
+/* bits for stream descriptor status register */
+#define	AUDIOHDR_SD_STS_BCIS		0x0004
+#define	AUDIOHDR_SD_STS_FIFOE		0x0008
+#define	AUDIOHDR_SD_STS_DESE		0x0010
+#define	AUDIOHDR_SD_STS_FIFORY		0x0020
+#define	AUDIOHDR_SD_STS_INTRS	\
+	(AUDIOHDR_SD_STS_BCIS | \
+	AUDIOHDR_SD_STS_FIFOE |	\
+	AUDIOHDR_SD_STS_DESE)
+
+
+/* bits for GCTL register */
+#define	AUDIOHDR_GCTL_CRST		0x00000001
+#define	AUDIOHDR_GCTL_URESPE		0x00000100
+
+/* bits for CORBRP register */
+#define	AUDIOHDR_CORBRP_RESET		0x8000
+#define	AUDIOHDR_CORBRP_WPTR		0x00ff
+
+/* bits for CORBCTL register */
+#define	AUDIOHDR_CORBCTL_CMEIE		0x01
+#define	AUDIOHDR_CORBCTL_DMARUN		0x02
+
+/* bits for CORB SIZE register */
+#define	AUDIOHDR_CORBSZ_8		0
+#define	AUDIOHDR_CORBSZ_16		1
+#define	AUDIOHDR_CORBSZ_256		2
+
+/* bits for RIRBCTL register */
+#define	AUDIOHDR_RIRBCTL_RINTCTL	0x01
+#define	AUDIOHDR_RIRBCTL_DMARUN		0x02
+#define	AUDIOHDR_RIRBCTL_RIRBOIC	0x04
+
+/* bits for RIRBWP register */
+#define	AUDIOHDR_RIRBWP_RESET		0x8000
+#define	AUDIOHDR_RIRBWP_WPTR		0x00ff
+
+/* bits for RIRB SIZE register */
+#define	AUDIOHDR_RIRBSZ_8		0
+#define	AUDIOHDR_RIRBSZ_16		1
+#define	AUDIOHDR_RIRBSZ_256		2
+
+#define	AUDIOHD_BDLE_RIRB_SDI		0x0000000f
+#define	AUDIOHD_BDLE_RIRB_UNSOLICIT	0x00000010
+
+/* HD spec: ID of Root node is 0 */
+#define	AUDIOHDC_NODE_ROOT		0x00
+
+/* HD spec: ID of audio function group is "1" */
+#define	AUDIOHDC_AUDIO_FUNC_GROUP	1
+
+/*
+ * 12-bit verbs
+ */
+#define	AUDIOHDC_VERB_GET_PARAM			0xf00
+
+#define	AUDIOHDC_VERB_GET_CONN_SEL		0xf01
+#define	AUDIOHDC_VERB_SET_CONN_SEL		0x701
+
+#define	AUDIOHDC_VERB_GET_CONN_LIST_ENT		0xf02
+#define	AUDIOHDC_VERB_GET_PROCESS_STATE		0xf03
+#define	AUDIOHDC_VERB_GET_SDI_SEL		0xf04
+#define	AUDIOHDC_VERB_GET_POWER_STATE		0xf05
+
+#define	AUDIOHDC_VERB_GET_STREAM_CHANN		0xf06
+#define	AUDIOHDC_VERB_SET_STREAM_CHANN		0x706
+
+#define	AUDIOHDC_VERB_GET_PIN_CTRL		0xf07
+#define	AUDIOHDC_VERB_SET_PIN_CTRL		0x707
+
+#define	AUDIOHDC_VERB_GET_UNS_ENABLE		0xf08
+#define	AUDIOHDC_VERB_GET_PIN_SENSE		0xf09
+#define	AUDIOHDC_VERB_GET_BEEP_GEN		0xf0a
+#define	AUDIOHDC_VERB_GET_DEFAULT_CONF		0xf1c
+
+/*
+ * 4-bit verbs
+ */
+#define	AUDIOHDC_VERB_GET_CONVERTER_FMT		0xa
+#define	AUDIOHDC_VERB_SET_CONVERTER_FMT		0x2
+
+#define	AUDIOHDC_VERB_GET_AMP_MUTE		0xb
+#define	AUDIOHDC_VERB_SET_AMP_MUTE		0x3
+
+/*
+ * parameters of nodes
+ */
+#define	AUDIOHDC_PAR_VENDOR_ID			0x00
+#define	AUDIOHDC_PAR_SUBSYS_ID			0x01
+#define	AUDIOHDC_PAR_REV_ID			0x02
+#define	AUDIOHDC_PAR_NODE_COUNT			0x04
+#define	AUDIOHDC_PAR_FUNCTION_TYPE		0x05
+#define	AUDIOHDC_PAR_AUDIO_FG_CAP		0x08
+#define	AUDIOHDC_PAR_AUDIO_WID_CAP		0x09
+#define	AUDIOHDC_PAR_PCM			0x0a
+#define	AUDIOHDC_PAR_STREAM			0x0b
+#define	AUDIOHDC_PAR_PIN_CAP			0x0c
+#define	AUDIOHDC_PAR_AMP_IN_CAP			0x0d
+#define	AUDIOHDC_PAR_CONNLIST_LEN		0x0e
+#define	AUDIOHDC_PAR_POWER_STATE		0x0f
+#define	AUDIOHDC_PAR_PROC_CAP			0x10
+#define	AUDIOHDC_PAR_GPIO_CAP			0x11
+#define	AUDIOHDC_PAR_AMP_OUT_CAP		0x12
+
+/*
+ * bits for get/set amplifier gain/mute
+ */
+#define	AUDIOHDC_AMP_SET_OUTPUT			0x8000
+#define	AUDIOHDC_AMP_SET_INPUT			0x4000
+#define	AUDIOHDC_AMP_SET_LEFT			0x2000
+#define	AUDIOHDC_AMP_SET_RIGHT			0x1000
+#define	AUDIOHDC_AMP_SET_INDEX_OFFSET		8
+#define	AUDIOHDC_AMP_SET_MUTE			0x0080
+#define	AUDIOHDC_AMP_SET_GAIN_MASK		0x007f
+#define	AUDIOHDC_AMP_SET_GAIN_MASK		0x007f
+#define	AUDIOHDC_GAIN_MAX			0x7f
+#define	AUDIOHDC_GAIN_BITS			7
+#define	AUDIOHDC_GAIN_DEFAULT			0x0f
+
+/*
+ * Bits for pin widget control verb
+ */
+#define	AUDIOHDC_PIN_CONTROL_HP_ENABLE		0x80
+#define	AUDIOHDC_PIN_CONTROL_OUT_ENABLE		0x40
+#define	AUDIOHDC_PIN_CONTROL_IN_ENABLE		0x20
+
+#define	AUDIOHD_CODEC_FAILURE	(uint32_t)(-1)
+
+struct audiohd_codec_ops;
+typedef struct  {
+	uint8_t		hc_addr;	/* codec address */
+	uint32_t	hc_vid;		/* vendor id and device id */
+	uint32_t	hc_revid;	/* revision id */
+
+	/*
+	 * although the following are the parameters/capabilities
+	 * of audio function group, but we just care about AFG,
+	 * therefore, it is no different that codec or AFG has
+	 * the parameters
+	 */
+	uint32_t	hc_afg_id;	/* id of AFG */
+	uint32_t	hc_sid;		/* sybsystem id for AFG */
+
+	struct audiohd_codec_ops *hc_ops;
+
+}audiohd_hda_codec_t;
+
+/*
+ * buffer descriptor list entry of stream descriptor
+ */
+typedef struct {
+	uint64_t	sbde_addr;
+	uint32_t	sbde_len;
+	uint32_t
+		sbde_ioc: 1,
+		reserved: 31;
+}sd_bdle_t;
+
+
+#define	AUDIOHD_PLAY_STARTED		0x00000001
+#define	AUDIOHD_PLAY_EMPTY		0x00000002
+#define	AUDIOHD_PLAY_PAUSED		0x00000004
+#define	AUDIOHD_RECORD_STARTED		0x00000008
+
+typedef struct {
+	ddi_dma_handle_t	ad_dmahdl;
+	ddi_acc_handle_t	ad_acchdl;
+	uintptr_t	ad_vaddr;	/* virtual addr */
+	uintptr_t	ad_paddr;	/* physical addr */
+	size_t		ad_req_sz;	/* required size of memory */
+	size_t		ad_real_sz;	/* real size of memory */
+} audiohd_dma_t;
+
+typedef struct {
+	audiohdl_t	hda_ahandle;
+	dev_info_t	*hda_dip;
+	kstat_t		*hda_ksp;
+	kmutex_t	hda_mutex;
+	uint32_t	hda_flags;
+
+	caddr_t		hda_reg_base;
+	ddi_acc_handle_t	hda_pci_handle;
+	ddi_acc_handle_t	hda_reg_handle;
+	ddi_iblock_cookie_t	hda_intr_cookie;
+
+	audiohd_dma_t	hda_dma_corb;
+	audiohd_dma_t	hda_dma_rirb;
+	audiohd_dma_t	hda_dma_play_bd;
+	audiohd_dma_t	hda_dma_play_buf;
+	audiohd_dma_t	hda_dma_record_bd;
+	audiohd_dma_t	hda_dma_record_buf;
+
+	int		hda_input_streams;	/* # of input stream */
+	int		hda_output_streams;	/* # of output stream */
+	int		hda_streams_nums;	/* # of stream */
+	int		hda_pbuf_pos;		/* play buffer position */
+	int		hda_rbuf_pos;		/* record buffer position */
+	uint8_t		hda_rirb_rp;		/* read pointer for rirb */
+	uint16_t	hda_codec_mask;
+
+	am_ad_info_t	hda_ad_info;
+	audio_info_t	hda_info_defaults;
+	audio_device_t	hda_dev_info;
+
+	int		hda_csamples;
+	int		hda_psamples;
+	int		hda_psample_rate;
+	int		hda_pchannels;
+	int		hda_pprecision;
+	int		hda_csample_rate;
+	int		hda_cchannels;
+	int		hda_cprecision;
+	int		hda_monitor_gain;
+	int		hda_pint_freq;	/* play intr frequence */
+	int		hda_rint_freq;	/* record intr frequence */
+	int		hda_pbuf_size;	/* play buffer size */
+	int		hda_rbuf_size;	/* record buffer size */
+
+	uint_t		hda_play_stag;	/* tag of playback stream */
+	uint_t		hda_record_stag;	/* tag of record stream */
+	uint_t		hda_play_regbase;	/* regbase for play stream */
+	uint_t		hda_record_regbase;	/* regbase for record stream */
+	uint_t		hda_play_lgain;	/* left gain for playback */
+	uint_t		hda_play_rgain;	/* right gain for playback */
+	uint_t		hda_record_lgain;	/* left gain for recording */
+	uint_t		hda_record_rgain;	/* right gain for recording */
+	uint_t		hda_play_format;
+	uint_t		hda_record_format;
+	uint_t		hda_out_ports;	/* active outputs */
+	uint_t		hda_in_ports;	/* active inputs */
+
+	audiohd_hda_codec_t	*hda_codec;
+} audiohd_state_t;
+
+struct audiohd_codec_ops {
+	int (*ac_enable_play)(audiohd_state_t *);
+	int (*ac_enable_record)(audiohd_state_t *);
+	int (*ac_set_pcm_fmt)(audiohd_state_t *, int, uint_t);
+	int (*ac_set_gain)(audiohd_state_t *, int, int, int);
+	int (*ac_set_port)(audiohd_state_t *, int, int);
+	int (*ac_mute_outputs)(audiohd_state_t *, boolean_t);
+	int (*ac_set_monitor_gain)(audiohd_state_t *, int);
+};
+
+#define	AUDIOHD_CODEC_ENABLE_PLAY(x) \
+	x->hda_codec->hc_ops->ac_enable_play(x)
+
+#define	AUDIOHD_CODEC_ENABLE_RECORD(x) \
+	x->hda_codec->hc_ops->ac_enable_record(x)
+
+#define	AUDIOHD_CODEC_SET_PCM_FORMAT(x, y, z) \
+	x->hda_codec->hc_ops->ac_set_pcm_fmt(x, y, z);
+
+#define	AUDIOHD_CODEC_SET_GAIN(x, y, z, w) \
+	x->hda_codec->hc_ops->ac_set_gain(x, y, z, w)
+
+#define	AUDIOHD_CODEC_SET_PORT(x, y, z) \
+	x->hda_codec->hc_ops->ac_set_port(x, y, z)
+
+#define	AUDIOHD_CODEC_MUTE_OUTPUTS(x, y) \
+	x->hda_codec->hc_ops->ac_mute_outputs(x, y)
+
+#define	AUDIOHD_CODEC_SET_MON_GAIN(x, y) \
+	x->hda_codec->hc_ops->ac_set_monitor_gain(x, y)
+
+
+/*
+ * Operation for high definition audio control system bus
+ * interface registers
+ */
+#define	AUDIOHD_REG_GET8(reg)	\
+	ddi_get8(statep->hda_reg_handle, \
+	(void *)((char *)statep->hda_reg_base + (reg)))
+
+#define	AUDIOHD_REG_GET16(reg)	\
+	ddi_get16(statep->hda_reg_handle, \
+	(void *)((char *)statep->hda_reg_base + (reg)))
+
+#define	AUDIOHD_REG_GET32(reg)	\
+	ddi_get32(statep->hda_reg_handle, \
+	(void *)((char *)statep->hda_reg_base + (reg)))
+
+#define	AUDIOHD_REG_GET64(reg)	\
+	ddi_get64(statep->hda_reg_handle, \
+	(void *)((char *)statep->hda_reg_base + (reg)))
+
+#define	AUDIOHD_REG_SET8(reg, val)	\
+	ddi_put8(statep->hda_reg_handle, \
+	(void *)((char *)statep->hda_reg_base + (reg)), (val))
+
+#define	AUDIOHD_REG_SET16(reg, val)	\
+	ddi_put16(statep->hda_reg_handle, \
+	(void *)((char *)statep->hda_reg_base + (reg)), (val))
+
+#define	AUDIOHD_REG_SET32(reg, val)	\
+	ddi_put32(statep->hda_reg_handle, \
+	(void *)((char *)statep->hda_reg_base + (reg)), (val))
+
+#define	AUDIOHD_REG_SET64(reg, val)	\
+	ddi_put64(statep->hda_reg_handle, \
+	(void *)((char *)statep->hda_reg_base + (reg)), (val))
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _SYS_AUDIOHD_IMPL_H_ */
--- a/usr/src/uts/i86pc/Makefile.i86pc.shared	Thu Jun 29 15:21:59 2006 -0700
+++ b/usr/src/uts/i86pc/Makefile.i86pc.shared	Thu Jun 29 20:57:57 2006 -0700
@@ -251,6 +251,7 @@
 DRV_KMODS	+= kb8042
 DRV_KMODS	+= pci-ide
 DRV_KMODS	+= audio810
+DRV_KMODS	+= audiohd
 
 DRV_KMODS_32	+= dnet
 DRV_KMODS	+= logi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/i86pc/audiohd/Makefile	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,95 @@
+#
+# 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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# uts/i86pc/audiohd/Makefile
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of high definition audio
+#	driver (audiohd) kernel module.
+#
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= audiohd
+OBJECTS		= $(AUDIOHD_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(AUDIOHD_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/io/audio/sada/drv/audiohd
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/i86pc/Makefile.i86pc
+
+# 
+#	Overrides, lint pass one enforcement 
+# 
+CFLAGS		+= $(CCVERBOSE)
+DEBUG_FLGS	=
+$(NOT_RELEASE_BUILD)DEBUG_DEFS	+= $(DEBUG_FLGS)
+
+#
+#	Depends on misc/audiosup
+#
+LDFLAGS		+= -dy -Nmisc/amsrc2 -Nmisc/audiosup -Nmisc/mixer
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+#	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)/i86pc/Makefile.targ
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Thu Jun 29 15:21:59 2006 -0700
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Thu Jun 29 20:57:57 2006 -0700
@@ -252,7 +252,7 @@
 #
 #	Machine Specific Driver Modules (/kernel/drv):
 #
-DRV_KMODS	+= audio1575 audio810 audiocs audiots
+DRV_KMODS	+= audio1575 audio810 audiohd audiocs audiots
 DRV_KMODS	+= bge bpp eri esp fas hme
 DRV_KMODS	+= openeepr options sd ses st
 DRV_KMODS	+= ssd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/audiohd/Makefile	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,152 @@
+#
+# 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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# uts/sparc/audiohd/Makefile
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of hight definition audio
+#	driver (audiohd) kernel module.
+#
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE = ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= audiohd
+OBJECTS		= $(AUDIOHD_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(AUDIOHD_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/io/audio/sada/drv/audiohd
+
+WARLOCK_OBJECTS = $(AUDIOHD_OBJS:%.o=%.ll)
+WARLOCK_OK	= $(MODULE).ok
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+# 
+#	Overrides, lint pass one enforcement 
+# 
+CFLAGS		+= $(CCVERBOSE)
+
+#
+#	Depends on misc/audiosup, misc/mixer
+#
+LDFLAGS		+= -dy -Nmisc/amsrc2 -Nmisc/mixer -Nmisc/audiosup
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE_64)
+
+#
+#       Overrides
+#
+ALL_BUILDS	= $(ALL_BUILDSONLY64)
+DEF_BUILDS	= $(DEF_BUILDSONLY64)
+CLEANLINTFILES	+= $(LINT32_FILES)
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS); \
+		$(RM) $(WARLOCK_OBJECTS) $(WARLOCK_OK)
+
+clobber:	$(CLOBBER_DEPS); \
+		$(RM) $(WARLOCK_OBJECTS) $(WARLOCK_OK)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS) lint32
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/sparc/Makefile.targ
+
+#
+#	Defines for local commands.
+#
+SCCS		= sccs
+TEST		= test
+WLCC		= wlcc
+TOUCH		= touch
+WARLOCK 	= warlock
+
+#
+#	Warlock targets
+#
+# NOTE: there will be warnings about q_lock which is the simulated
+# rwlock of the taskq framework
+#
+
+%.wlcmd:
+	$(TEST) -f $@ || $(SCCS) get $@
+
+warlock:	$(WARLOCK_OK)
+
+$(WARLOCK_OK):	$(WARLOCK_OBJECTS) warlock_ddi.files \
+	warlock_audiosup.files warlock_mixer.files warlock_amsrc2.files
+	$(WARLOCK) -c audiohd_with_sada.wlcmd $(WARLOCK_OBJECTS) \
+	../audiosup/audio_support.ll ../amsrc2/am_src2.ll \
+	../mixer/am_main.ll ../mixer/am_ad.ll ../mixer/am_ioctl.ll \
+	-l ../warlock/ddi_dki_impl.ll
+	$(TOUCH) $(WARLOCK_OK)
+
+%.ll: $(UTSBASE)/common/io/audio/sada/drv/audiohd/%.c
+	$(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
+
+warlock_standalone: $(WARLOCK_OBJECTS) warlock_ddi.files audiohd.wlcmd
+	$(WARLOCK) -c audiohd.wlcmd $(WARLOCK_OBJECTS) \
+	-l ../warlock/ddi_dki_impl.ll
+
+warlock_ddi.files:
+	@cd ../warlock; pwd; $(MAKE) warlock
+
+warlock_audiosup.files:
+	@cd ../audiosup; pwd; $(MAKE) warlock
+
+warlock_amsrc2.files:
+	@cd ../amsrc2; pwd; $(MAKE) warlock
+
+warlock_mixer.files:
+	@cd ../mixer; pwd; $(MAKE) warlock
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/audiohd/audiohd.wlcmd	Thu Jun 29 20:57:57 2006 -0700
@@ -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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#
+# warlock command file
+
+one	audiohd_state
+
+root	audiohd_ad_pause_play
+root	audiohd_ad_set_config
+root	audiohd_ad_set_format
+root	audiohd_ad_start_play
+root	audiohd_ad_start_record
+root	audiohd_ad_stop_play
+root	audiohd_ad_stop_record
+
+add	bus_ops::bus_add_eventcall	targets	warlock_dummy
+add	bus_ops::bus_get_eventcookie	targets	warlock_dummy
+add	bus_ops::bus_intr_ctl		targets	warlock_dummy
+add	bus_ops::bus_post_event		targets	warlock_dummy
+add	bus_ops::bus_remove_eventcall	targets	warlock_dummy
+add	bus_ops::bus_config		targets	warlock_dummy
+add	bus_ops::bus_unconfig		targets	warlock_dummy
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/audiohd/audiohd_with_sada.wlcmd	Thu Jun 29 20:57:57 2006 -0700
@@ -0,0 +1,130 @@
+#
+# 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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#
+# warlock command file
+
+one	audiohd_state_t
+one	audio_ch
+one	audio_apm_info
+one	audio_state
+one	am_apm_private
+
+# unused functions
+root	audio_sup_attach
+root	audio_sup_ch_to_minor
+root	audio_sup_close
+root	audio_sup_construct_minor
+root	audio_sup_detach
+root	audio_sup_devt_to_ch_type
+root	audio_sup_devt_to_instance
+root	audio_sup_free_persist_state
+root	audio_sup_get_channel_number
+root	audio_sup_get_dip
+root	audio_sup_get_info
+root	audio_sup_get_max_chs
+root	audio_sup_get_persist_state
+root	audio_sup_get_qptr_data
+root	audio_sup_get_qptr_instance
+root	audio_sup_free_qptr
+root	audio_sup_open
+root	audio_sup_rput
+root	audio_sup_rsvc
+root	audio_sup_save_audio_data
+root	audio_sup_set_persist_state
+root	audio_sup_set_qptr
+root	audio_sup_update_persist_key
+root	audio_sup_wput
+root	audio_sup_wsvc
+root	audio_sup_getinfo
+root	audio_sup_restore_state
+root	audio_sup_save_state
+
+
+# src stuff, warlock with src
+root	am_get_src_data
+root	am_hw_state_change
+root	am_set_src_data
+root	am_restore_state
+root	am_save_state
+
+# threads
+root	am_diag_loopback_task
+root	am_get_chinfo_task
+root	am_get_mode_task
+root	am_getinfo_task
+root	am_mixer_task_acknack
+root	am_mixerctl_getinfo_task
+root	am_mixerctl_setinfo_task
+root	am_multiple_open_task
+root	am_sample_rate_task
+root	am_set_chinfo_task
+root	am_set_mode_task
+root	am_setinfo_task
+root	am_single_open_task
+root	am_hw_task
+
+# interrupt handler
+
+# function pointers
+add	audio_ch::ch_rput			targets	am_rput
+add	audio_ch::ch_rsvc			targets	am_rsvc
+add	audio_ch::ch_wput			targets	am_wput
+add	audio_ch::ch_wsvc			targets	am_wsvc
+add	audio_apm_info::apm_open		targets	am_open_audio
+add	audio_apm_info::apm_close		targets	am_close_audio
+add	audio_apm_info::apm_open		targets	am_open_audioctl
+add	audio_apm_info::apm_close		targets	am_close_audioctl
+add	audio_apm_info::apm_restore_state	targets	am_restore_state
+add	audio_apm_info::apm_save_state		targets	am_save_state
+
+
+add	am_ad_entry::ad_set_config	targets	audiohd_ad_set_config
+add	am_ad_entry::ad_set_format	targets	audiohd_ad_set_format
+add	am_ad_entry::ad_start_play	targets	audiohd_ad_start_play
+add	am_ad_entry::ad_pause_play	targets	audiohd_ad_pause_play
+add	am_ad_entry::ad_stop_play	targets	audiohd_ad_stop_play
+add	am_ad_entry::ad_start_record	targets	audiohd_ad_start_record
+add	am_ad_entry::ad_stop_record	targets	audiohd_ad_stop_record
+add	am_ad_entry::ad_ioctl		targets	warlock_dummy
+add	am_ad_entry::ad_iocdata		targets	warlock_dummy
+
+
+add	bus_ops::bus_add_eventcall	targets	warlock_dummy
+add	bus_ops::bus_get_eventcookie	targets	warlock_dummy
+add	bus_ops::bus_intr_ctl		targets	warlock_dummy
+add	bus_ops::bus_post_event		targets	warlock_dummy
+add	bus_ops::bus_remove_eventcall	targets	warlock_dummy
+add	bus_ops::bus_config		targets	warlock_dummy
+add	bus_ops::bus_unconfig		targets	warlock_dummy
+
+add	am_ad_src_entry::ad_src_adjust	targets	am_src2_adjust
+add	am_ad_src_entry::ad_src_convert	targets	am_src2_convert
+add	am_ad_src_entry::ad_src_exit	targets	am_src2_exit
+add	am_ad_src_entry::ad_src_init	targets	am_src2_init
+add	am_ad_src_entry::ad_src_size	targets	am_src2_size
+add	am_ad_src_entry::ad_src_update	targets	am_src2_update
+
+assert	order audio_state::as_lock	audio_ch::ch_lock audiohd_state_t::hda_mutex
--- a/usr/src/uts/sparc/warlock/Makefile	Thu Jun 29 15:21:59 2006 -0700
+++ b/usr/src/uts/sparc/warlock/Makefile	Thu Jun 29 20:57:57 2006 -0700
@@ -118,6 +118,7 @@
 	@cd ../amsrc2; rm -f *.ll *.ok; $(MAKE) warlock
 	@cd ../audio1575; rm -f *.ll *.ok; $(MAKE) warlock
 	@cd ../audio810; rm -f *.ll *.ok; $(MAKE) warlock
+	@cd ../audiohd; rm -f *.ll *.ok; $(MAKE) warlock
 	@cd $(CLOSED)/uts/sparc/audiovia823x; rm -f *.ll *.ok; $(MAKE) warlock
 	@cd ../audiocs; rm -f *.ll *.ok; $(MAKE) warlock
 	@cd $(CLOSED)/uts/sparc/audioens; rm -f *.ll *.ok; $(MAKE) warlock