PSARC 2009/689 Audio DDI Simplifications
authorGarrett D'Amore <gdamore@opensolaris.org>
Tue, 16 Mar 2010 09:30:41 -0700
changeset 11936 54dc8a89ba0d
parent 11935 538c866aaac6
child 11937 ee1b786b1783
PSARC 2009/689 Audio DDI Simplifications PSARC 2009/674 Decoupling audio device interrupts 6921849 interrupt free audio 6921851 audio DDI simplifications 6930541 Synchronization issue between usb_ac and usb_as
usr/src/cmd/audio/audiotest/audiotest.c
usr/src/pkg/manifests/driver-audio-audioixp.mf
usr/src/pkg/manifests/driver-audio-audiovia823x.mf
usr/src/pkg/manifests/driver-audio.mf
usr/src/uts/common/io/audio/ac97/ac97.c
usr/src/uts/common/io/audio/drv/audio1575/audio1575.c
usr/src/uts/common/io/audio/drv/audio1575/audio1575.conf
usr/src/uts/common/io/audio/drv/audio1575/audio1575.h
usr/src/uts/common/io/audio/drv/audio810/audio810.c
usr/src/uts/common/io/audio/drv/audio810/audio810.conf
usr/src/uts/common/io/audio/drv/audio810/audio810.h
usr/src/uts/common/io/audio/drv/audiocmi/audiocmi.c
usr/src/uts/common/io/audio/drv/audiocmi/audiocmi.h
usr/src/uts/common/io/audio/drv/audioemu10k/audioemu10k.c
usr/src/uts/common/io/audio/drv/audioemu10k/audioemu10k.h
usr/src/uts/common/io/audio/drv/audioens/audioens.c
usr/src/uts/common/io/audio/drv/audioens/audioens.conf
usr/src/uts/common/io/audio/drv/audiohd/audiohd.c
usr/src/uts/common/io/audio/drv/audiohd/audiohd.conf
usr/src/uts/common/io/audio/drv/audiohd/audiohd.h
usr/src/uts/common/io/audio/drv/audioixp/audioixp.c
usr/src/uts/common/io/audio/drv/audioixp/audioixp.conf
usr/src/uts/common/io/audio/drv/audioixp/audioixp.h
usr/src/uts/common/io/audio/drv/audiols/audiols.c
usr/src/uts/common/io/audio/drv/audiols/audiols.h
usr/src/uts/common/io/audio/drv/audiop16x/audiop16x.c
usr/src/uts/common/io/audio/drv/audiop16x/audiop16x.h
usr/src/uts/common/io/audio/drv/audiopci/audiopci.c
usr/src/uts/common/io/audio/drv/audiopci/audiopci.conf
usr/src/uts/common/io/audio/drv/audiosolo/audiosolo.c
usr/src/uts/common/io/audio/drv/audiots/audiots.c
usr/src/uts/common/io/audio/drv/audiots/audiots.conf
usr/src/uts/common/io/audio/drv/audiots/audiots.h
usr/src/uts/common/io/audio/drv/audiovia823x/audiovia823x.c
usr/src/uts/common/io/audio/drv/audiovia823x/audiovia823x.conf
usr/src/uts/common/io/audio/drv/audiovia823x/audiovia823x.h
usr/src/uts/common/io/audio/drv/audiovia97/audiovia97.c
usr/src/uts/common/io/audio/drv/audiovia97/audiovia97.h
usr/src/uts/common/io/audio/impl/audio_client.c
usr/src/uts/common/io/audio/impl/audio_client.h
usr/src/uts/common/io/audio/impl/audio_ctrl.c
usr/src/uts/common/io/audio/impl/audio_ddi.c
usr/src/uts/common/io/audio/impl/audio_engine.c
usr/src/uts/common/io/audio/impl/audio_impl.h
usr/src/uts/common/io/audio/impl/audio_input.c
usr/src/uts/common/io/audio/impl/audio_output.c
usr/src/uts/common/io/usb/clients/audio/usb_ac/usb_ac.c
usr/src/uts/common/sys/audio/ac97.h
usr/src/uts/common/sys/audio/audio_driver.h
usr/src/uts/intel/audio1575/Makefile
usr/src/uts/intel/audioens/Makefile
usr/src/uts/intel/audioixp/Makefile
usr/src/uts/intel/audiopci/Makefile
usr/src/uts/intel/audiots/Makefile
usr/src/uts/intel/audiovia823x/Makefile
usr/src/uts/sparc/audio1575/Makefile
usr/src/uts/sparc/audiocs/Makefile
usr/src/uts/sparc/audioens/Makefile
usr/src/uts/sparc/audiopci/Makefile
usr/src/uts/sparc/audiots/Makefile
usr/src/uts/sun/io/audio/drv/audiocs/audio_4231.c
usr/src/uts/sun/io/audio/drv/audiocs/audio_4231.h
usr/src/uts/sun/io/audio/drv/audiocs/audio_4231_apcdma.c
usr/src/uts/sun/io/audio/drv/audiocs/audio_4231_eb2dma.c
usr/src/uts/sun/io/audio/drv/audiocs/audiocs.conf
--- a/usr/src/cmd/audio/audiotest/audiotest.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/cmd/audio/audiotest/audiotest.c	Tue Mar 16 09:30:41 2010 -0700
@@ -21,7 +21,7 @@
 /*
  * Copyright (C) 4Front Technologies 1996-2008.
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
@@ -386,14 +386,14 @@
 		perror(dn);
 		errno = err;
 		describe_error(errno);
-		return (0);
+		return (-1);
 	}
 
 	ainfo.dev = -1;
 	if (ioctl(fd, SNDCTL_AUDIOINFO, &ainfo) == -1) {
 		perror("SNDCTL_AUDIOINFO");
 		(void) close(fd);
-		return (1);
+		return (-1);
 	}
 
 	(void) printf(_("\n*** Scanning sound adapter #%d ***\n"),
@@ -405,13 +405,13 @@
 	if (!ainfo.enabled) {
 		(void) printf(_("  - Device not present - Skipping\n"));
 		(void) close(fd);
-		return (1);
+		return (0);
 	}
 
 	if (!(ainfo.caps & PCM_CAP_OUTPUT)) {
 		(void) printf(_("  - Skipping input only device\n"));
 		(void) close(fd);
-		return (1);
+		return (0);
 	}
 
 	(void) printf(_("  - Performing audio playback test... "));
@@ -419,6 +419,9 @@
 
 	code = testdsp(fd, flags, tcfg);
 	(void) close(fd);
+	if (code < 0) {
+		return (code);
+	}
 
 	return (code == 1);
 }
@@ -472,6 +475,7 @@
 	int maxdev;
 	int flags = 0;
 	int status = 0;
+	int errors = 0;
 	int numdev;
 	extern int optind;
 	testcfg_t	*tcfg;
@@ -540,12 +544,18 @@
 	do {
 		char *dn;
 		oss_audioinfo	ainfo;
+		int rv;
 
+		status = 0;
 		if (numdev > 0) {
 			for (t = 0; t < numdev; t++) {
 				dn = argv[optind + t];
-				if (!test_device(dn, flags, tcfg))
+				rv = test_device(dn, flags, tcfg);
+				if (rv < 0) {
+					errors++;
+				} else if (rv) {
 					status++;
+				}
 			}
 		} else {
 			for (t = 0; t < maxdev; t++) {
@@ -557,17 +567,21 @@
 					continue;
 				}
 				dn = ainfo.devnode;
-				if (!test_device(dn, flags, tcfg))
+				rv = test_device(dn, flags, tcfg);
+				if (rv < 0) {
+					errors++;
+				} else if (rv) {
 					status++;
+				}
 			}
 		}
 
-		if (status == 0)
+		if (errors == 0)
 			(void) printf(_("\n*** All tests completed OK ***\n"));
 		else
 			(void) printf(_("\n*** Errors were detected ***\n"));
 
-	} while (flags & TF_LOOP);
+	} while (status && (flags & TF_LOOP));
 
 	(void) close(mixerfd);
 
--- a/usr/src/pkg/manifests/driver-audio-audioixp.mf	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/pkg/manifests/driver-audio-audioixp.mf	Tue Mar 16 09:30:41 2010 -0700
@@ -46,7 +46,6 @@
     alias=pci1002,4370
 file path=kernel/drv/$(ARCH64)/audioixp group=sys
 file path=kernel/drv/audioixp group=sys
-file path=kernel/drv/audioixp.conf group=sys reboot-needed=false
 legacy pkg=SUNWadixp arch=$(ARCH) category=system \
     desc="SunOS audio device driver for ATI IXP integrated audio hardware" \
     hotline="Please contact your local service provider" \
--- a/usr/src/pkg/manifests/driver-audio-audiovia823x.mf	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/pkg/manifests/driver-audio-audiovia823x.mf	Tue Mar 16 09:30:41 2010 -0700
@@ -43,12 +43,10 @@
 driver name=audiovia823x alias=pci1106,3059
 file path=kernel/drv/$(ARCH64)/audiovia823x group=sys
 file path=kernel/drv/audiovia823x group=sys
-file path=kernel/drv/audiovia823x.conf group=sys reboot-needed=false
 legacy pkg=SUNWvia823x arch=$(ARCH) category=system \
     desc="SunOS audio device driver for VIA VT823x south bridges" \
     hotline="Please contact your local service provider" \
     name="SUNW Audio Driver for VIA VT823x" vendor="Sun Microsystems, Inc." \
     version=11.11,REV=2009.11.11
 license cr_Sun license=cr_Sun
-license lic_OSBL license=lic_OSBL
-license lic_OSBL_preamble license=lic_OSBL_preamble
+license lic_CDDL license=lic_CDDL
--- a/usr/src/pkg/manifests/driver-audio.mf	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/pkg/manifests/driver-audio.mf	Tue Mar 16 09:30:41 2010 -0700
@@ -58,14 +58,9 @@
 $(i386_ONLY)file path=kernel/drv/audio group=sys
 file path=kernel/drv/audio.conf group=sys reboot-needed=false
 $(i386_ONLY)file path=kernel/drv/audio1575 group=sys
-file path=kernel/drv/audio1575.conf group=sys reboot-needed=false
-$(sparc_ONLY)file path=kernel/drv/audiocs.conf group=sys reboot-needed=false
 $(i386_ONLY)file path=kernel/drv/audioens group=sys
-file path=kernel/drv/audioens.conf group=sys reboot-needed=false
 $(i386_ONLY)file path=kernel/drv/audiopci group=sys
-file path=kernel/drv/audiopci.conf group=sys reboot-needed=false
 $(i386_ONLY)file path=kernel/drv/audiots group=sys
-file path=kernel/drv/audiots.conf group=sys reboot-needed=false
 file path=kernel/misc/$(ARCH64)/ac97 group=sys mode=0755 reboot-needed=true
 $(i386_ONLY)file path=kernel/misc/ac97 group=sys mode=0755 reboot-needed=true
 legacy pkg=SUNWaudd arch=$(ARCH) category=system \
--- a/usr/src/uts/common/io/audio/ac97/ac97.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/ac97/ac97.c	Tue Mar 16 09:30:41 2010 -0700
@@ -21,7 +21,7 @@
 /*
  * Copyright (C) 4Front Technologies 1996-2008.
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -39,7 +39,7 @@
  * This is the initial value for many controls. This is
  * a 75% level.
  */
-#define	INIT_VAL_MAIN	((75 << 8) | 75)
+#define	INIT_VAL_MAIN	75
 #define	INIT_VAL_ST	((75 << 8) | 75)
 #define	INIT_VAL_MN	75
 #define	INIT_IGAIN_ST	((50 << 8) | 50)
@@ -102,8 +102,6 @@
 
 	uint16_t	shadow[NUM_SHADOW];
 
-	boolean_t	suspended;		/* true if suspended */
-	kt_did_t	resumer;		/* resumer if suspended */
 	uint32_t	flags;
 #define	AC97_FLAG_AMPLIFIER	(1 << 0)	/* ext. amp on by default */
 #define	AC97_FLAG_MICBOOST	(1 << 1)	/* micboost on by default */
@@ -128,7 +126,6 @@
 	void		(*codec_init)(ac97_t *);
 	void		(*codec_reset)(ac97_t *);
 
-	kmutex_t	ac_lock;
 	list_t		ctrls;
 
 	uint64_t	inputs;
@@ -657,13 +654,7 @@
 		SHADOW(ac, reg) = val;
 	}
 
-	/*
-	 * Don't touch hardware _unless_ if we are suspended, unless we
-	 * are in the process of resuming.
-	 */
-	if ((!ac->suspended) || (ac->resumer == ddi_get_kt_did())) {
-		ac->wr(ac->private, reg, val);
-	}
+	ac->wr(ac->private, reg, val);
 }
 
 /*
@@ -678,10 +669,7 @@
 	if ((reg < LAST_SHADOW_REG) && (reg > 0)) {
 		return (SHADOW(ac, reg));
 	}
-	if ((!ac->suspended) || (ac->resumer == ddi_get_kt_did())) {
-		return (ac->rd(ac->private, reg));
-	}
-	return (0);
+	return (ac->rd(ac->private, reg));
 }
 
 /*
@@ -739,16 +727,6 @@
 	for (int i = 2; i < LAST_SHADOW_REG; i += sizeof (uint16_t)) {
 		ac->wr(ac->private, i, SHADOW(ac, i));
 	}
-
-	/*
-	 * Then go and do the controls.  This is important because some of
-	 * the controls might use registers that aren't shadowed.  Doing it
-	 * a second time also may help guarantee that it all works.
-	 */
-	for (ac97_ctrl_t *ctrl = list_head(&ac->ctrls); ctrl;
-	    ctrl = list_next(&ac->ctrls, ctrl)) {
-		ctrl->actrl_write_fn(ctrl, ctrl->actrl_value);
-	}
 }
 
 /*
@@ -760,13 +738,11 @@
 {
 	ac97_ctrl_t	*ctrl;
 
-	mutex_enter(&ac->ac_lock);
 	for (ctrl = list_head(&ac->ctrls); ctrl;
 	    ctrl = list_next(&ac->ctrls, ctrl)) {
 		ctrl->actrl_value = ctrl->actrl_initval;
 		ctrl->actrl_write_fn(ctrl, ctrl->actrl_initval);
 	}
-	mutex_exit(&ac->ac_lock);
 }
 
 /*
@@ -1057,11 +1033,7 @@
 int
 ac97_control_get(ac97_ctrl_t *ctrl, uint64_t *value)
 {
-	ac97_t		*ac = ctrl->actrl_ac97;
-
-	mutex_enter(&ac->ac_lock);
 	*value = ctrl->actrl_value;
-	mutex_exit(&ac->ac_lock);
 
 	return (0);
 }
@@ -1069,7 +1041,6 @@
 int
 ac97_control_set(ac97_ctrl_t *ctrl, uint64_t value)
 {
-	ac97_t			*ac = ctrl->actrl_ac97;
 	uint8_t			v1, v2;
 
 	/* a bit of quick checking */
@@ -1100,10 +1071,8 @@
 		break;
 	}
 
-	mutex_enter(&ac->ac_lock);
 	ctrl->actrl_value = value;
 	ctrl->actrl_write_fn(ctrl, value);
-	mutex_exit(&ac->ac_lock);
 
 	return (0);
 }
@@ -1121,28 +1090,6 @@
 }
 
 /*
- * This simply sets a flag to block calls to the underlying
- * hardware driver to get or set hardware controls. This is usually
- * called just before a power down of devices. Once this gets called any
- * calls to set controls will not touch the real hardware. But
- * since all control updates are always saved in soft registers it
- * is a simple mater to update the hardware with the latest values
- * on resume which also unblocks calls to the hardware controls.
- */
-void
-ac97_suspend(ac97_t *ac)
-{
-	mutex_enter(&ac->ac_lock);
-
-	/* This will prevent any new operations from starting! */
-	ac->suspended = B_TRUE;
-	ac->resumer = 0;
-
-	/* XXX - should we powerdown codec's here?? */
-	mutex_exit(&ac->ac_lock);
-}
-
-/*
  * Reset the analog codec hardware
  *
  * Reset all analog AC97 hardware, input ADC's, output DAC's and MIXER.
@@ -1278,59 +1225,15 @@
 }
 
 /*
- * This will reset and re-initialize the device.
- * It has two modes of operation that affect how it handles
- * all controls.
- *
- * It re-initializes the device and then can either reset
- * all controls back to their initial values or it can
- * re-load all controls with their last updated values.
- *
- * initval         - If this is none zero then all controls will
- *                   be restored to their initial values.
+ * This will reset and re-initialize the device.  It is still incumbent
+ * on the caller (or the audio framework) to replay control settings!
  */
 void
 ac97_reset(ac97_t *ac)
 {
-	/* If we are about to suspend so no point in going on */
-	mutex_enter(&ac->ac_lock);
-	if (ac->suspended) {
-		mutex_exit(&ac->ac_lock);
-		return;
-	}
 	ac_analog_reset(ac);
 	ac_hw_reset(ac);
 	ac_restore(ac);
-
-	mutex_exit(&ac->ac_lock);
-}
-
-/*
- * Given the need to resume the hardware this reloads the base hardware
- * and then takes the stored values for each control and sends them
- * to the hardware again.
- */
-void
-ac97_resume(ac97_t *ac)
-{
-
-	/*
-	 * This should only be called when already suspended.
-	 * this takes us out of suspend state after it brings the
-	 * controls back to life.
-	 */
-	ASSERT(ac->suspended);
-	mutex_enter(&ac->ac_lock);
-	ac->resumer = ddi_get_kt_did();
-
-	/* We simply call reset since the operation is the same */
-	ac_analog_reset(ac);
-	ac_hw_reset(ac);
-	ac_restore(ac);
-
-	ac->resumer = 0;
-	ac->suspended = B_FALSE;
-	mutex_exit(&ac->ac_lock);
 }
 
 /*
@@ -1699,8 +1602,6 @@
 	list_create(&ac->ctrls, sizeof (struct ac97_ctrl),
 	    offsetof(struct ac97_ctrl, actrl_linkage));
 
-	mutex_init(&ac->ac_lock, NULL, MUTEX_DRIVER, NULL);
-
 #define	PROP_FLAG(prop, flag, def)				    \
 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, \
 	    (prop), (def))) {					    \
@@ -1808,7 +1709,6 @@
 	}
 
 	list_destroy(&ac->ctrls);
-	mutex_destroy(&ac->ac_lock);
 	kmem_free(ac, sizeof (ac97_t));
 }
 
--- a/usr/src/uts/common/io/audio/drv/audio1575/audio1575.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audio1575/audio1575.c	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -70,7 +70,7 @@
 /*
  * Entry point routine prototypes
  */
-static int audio1575_open(void *, int, unsigned *, unsigned *, caddr_t *);
+static int audio1575_open(void *, int, unsigned *, caddr_t *);
 static void audio1575_close(void *);
 static int audio1575_start(void *);
 static void audio1575_stop(void *);
@@ -97,11 +97,6 @@
 };
 
 /*
- * interrupt handler
- */
-static uint_t	audio1575_intr(caddr_t, caddr_t);
-
-/*
  * Local Routine Prototypes
  */
 static int audio1575_attach(dev_info_t *);
@@ -111,12 +106,7 @@
 
 static int audio1575_alloc_port(audio1575_state_t *, int, uint8_t);
 static void audio1575_free_port(audio1575_port_t *);
-static void audio1575_start_port(audio1575_port_t *);
-static void audio1575_stop_port(audio1575_port_t *);
-static void audio1575_reset_port(audio1575_port_t *);
-static void audio1575_update_port(audio1575_port_t *);
 
-static int audio1575_setup_intr(audio1575_state_t *);
 static int audio1575_codec_sync(audio1575_state_t *);
 static void audio1575_write_ac97(void *, uint8_t, uint16_t);
 static uint16_t audio1575_read_ac97(void *, uint8_t);
@@ -374,119 +364,6 @@
 	return (DDI_SUCCESS);
 }
 
-
-/*
- * audio1575_intr()
- *
- * Description:
- *	Interrupt service routine for both play and record. For play we
- *	get the next buffers worth of audio. For record we send it on to
- *	the mixer.
- *
- *	Each of buffer descriptor has a field IOC(interrupt on completion)
- *	When both this and the IOC bit of correspondent dma control register
- *	is set, it means that the controller should issue an interrupt upon
- *	completion of this buffer. Note that in the clearing of the interrupts
- *	below that the PCM IN and PCM out interrupts ar cleared by their
- *	respective control registers and not by writing a '1' to the INTRSR
- *	the interrupt status register. Only CPRINTR,SPINTR,and GPIOINTR
- *	require a '1' written to the INTRSR register to clear those
- *	interrupts. See comments below.
- *
- * 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
-audio1575_intr(caddr_t arg, caddr_t dontcare)
-{
-	audio1575_state_t	*statep = (void *)arg;
-	uint32_t		intrsr;
-	uint8_t			index;
-	audio1575_port_t	*consume = NULL;
-	audio1575_port_t	*produce = NULL;
-
-	_NOTE(ARGUNUSED(dontcare));
-
-	mutex_enter(&statep->lock);
-
-	intrsr = GET32(M1575_INTRSR_REG);
-
-	/* check if device is interrupting */
-	if (intrsr == 0) {
-		if (statep->ksp) {
-			/* increment the spurious ino5 interrupt cnt */
-			M1575_KIOP(statep)->intrs[KSTAT_INTR_SPURIOUS]++;
-		}
-
-		mutex_exit(&statep->lock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	/* update the kernel interrupt statistics */
-	if (statep->ksp) {
-		M1575_KIOP(statep)->intrs[KSTAT_INTR_HARD]++;
-	}
-
-	/*
-	 * The Uli M1575 generates an interrupt for each interrupt
-	 * type. therefore we only process one interrupt type
-	 * per invocation of the audio1575_intr() routine.
-	 * WARNING: DO NOT attempt to optimize this by looping
-	 * until the INTRSR register is clear as this will
-	 * generate spurious ino5 interrupts.
-	 */
-	if (GET16(M1575_PCMISR_REG) & M1575_PCMISR_BCIS) {
-		/* Clear PCM IN interrupt */
-		PUT16(M1575_PCMISR_REG, M1575_SR_CLR);
-		/*
-		 * Note: This interrupt is not cleared by writing a '1'
-		 * to the M1575_INTRSR_REG according to the M1575 Super I/O
-		 * data sheet on page 189.
-		 */
-
-		/* update the LVI -- we just set it to the current value - 1 */
-		index = GET8(M1575_PCMICIV_REG);
-		index = (index - 1) % M1575_BD_NUMS;
-		PUT8(M1575_PCMILVIV_REG, index);
-		produce = statep->ports[M1575_REC];
-
-	} else if (GET16(M1575_PCMOSR_REG) & M1575_PCMOSR_BCIS) {
-		/* Clear PCM OUT interrupt */
-		PUT16(M1575_PCMOSR_REG, M1575_SR_CLR);
-		/*
-		 * Note: This interrupt is not cleared by writing a '1'
-		 * to the M1575_INTRSR_REG according to the M1575 Super I/O
-		 * data sheet on page 189.
-		 */
-
-		/* update the LVI -- we just set it to the current value - 1 */
-		index = GET8(M1575_PCMOCIV_REG);
-		index = (index - 1) % M1575_BD_NUMS;
-		PUT8(M1575_PCMOLVIV_REG, index);
-		consume = statep->ports[M1575_PLAY];
-
-	} else {
-		/* Clear other interrupts (there should not be any) */
-		PUT32(M1575_INTRSR_REG, (intrsr & M1575_INTR_MASK));
-	}
-
-	mutex_exit(&statep->lock);
-
-	if (produce) {
-		audio_engine_produce(produce->engine);
-	}
-	if (consume) {
-		audio_engine_consume(consume->engine);
-	}
-
-	return (DDI_INTR_CLAIMED);
-}
-
 /*
  * audio1575_open()
  *
@@ -496,8 +373,7 @@
  * Arguments:
  *	void		*arg		The DMA engine to set up
  *	int		flag		Open flags
- *	unsigned	*fragfrp	Receives number of frames per fragment
- *	unsigned	*nfragsp	Receives number of fragments
+ *	unsigned	*nframesp	Receives number of frames
  *	caddr_t		*bufp		Receives kernel data buffer
  *
  * Returns:
@@ -505,23 +381,16 @@
  *	errno	on failure
  */
 static int
-audio1575_open(void *arg, int flag,
-    unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp)
+audio1575_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
 {
 	audio1575_port_t	*port = arg;
 
 	_NOTE(ARGUNUSED(flag));
 
-	port->started = B_FALSE;
 	port->count = 0;
-	*fragfrp = port->fragfr;
-	*nfragsp = M1575_BD_NUMS;
+	*nframesp = port->nframes;
 	*bufp = port->samp_kaddr;
 
-	mutex_enter(&port->statep->lock);
-	audio1575_reset_port(port);
-	mutex_exit(&port->statep->lock);
-
 	return (0);
 }
 
@@ -540,13 +409,7 @@
 static void
 audio1575_close(void *arg)
 {
-	audio1575_port_t	*port = arg;
-	audio1575_state_t	*statep = port->statep;
-
-	mutex_enter(&statep->lock);
-	audio1575_stop_port(port);
-	port->started = B_FALSE;
-	mutex_exit(&statep->lock);
+	_NOTE(ARGUNUSED(arg));
 }
 
 /*
@@ -566,10 +429,11 @@
 	audio1575_state_t	*statep = port->statep;
 
 	mutex_enter(&statep->lock);
-	if (port->started) {
-		audio1575_stop_port(port);
+	if (port->num == M1575_REC) {
+		SET32(M1575_DMACR_REG, M1575_DMACR_PCMIPAUSE);
+	} else {
+		SET32(M1575_DMACR_REG, M1575_DMACR_PCMOPAUSE);
 	}
-	port->started = B_FALSE;
 	mutex_exit(&statep->lock);
 }
 
@@ -592,14 +456,70 @@
 	audio1575_state_t	*statep = port->statep;
 
 	mutex_enter(&statep->lock);
-	if (!port->started) {
-		audio1575_start_port(port);
-		port->started = B_TRUE;
+
+	port->offset = 0;
+
+	if (port->num == M1575_REC) {
+		/* Uli FIFO madness ... */
+		SET32(M1575_FIFOCR1_REG, M1575_FIFOCR1_PCMIRST);
+		SET32(M1575_DMACR_REG, M1575_DMACR_PCMIPAUSE);
+
+		PUT8(M1575_PCMICR_REG, 0);
+		PUT8(M1575_PCMICR_REG, M1575_CR_RR);
+
+		PUT32(M1575_PCMIBDBAR_REG, port->bdl_paddr);
+		PUT8(M1575_PCMILVIV_REG, M1575_BD_NUMS - 1);
+
+		CLR32(M1575_DMACR_REG, M1575_DMACR_PCMIPAUSE);
+
+		/* ULi says do fifo resets here */
+		SET32(M1575_FIFOCR1_REG, M1575_FIFOCR1_PCMIRST);
+		CLR32(M1575_DMACR_REG, M1575_DMACR_PCMIPAUSE);
+		PUT8(M1575_PCMICR_REG, 0);
+		SET32(M1575_DMACR_REG, M1575_DMACR_PCMISTART);
+
+	} else {
+
+		uint32_t	scr;
+
+		/* Uli FIFO madness ... */
+		SET32(M1575_FIFOCR1_REG, M1575_FIFOCR1_PCMORST);
+		SET32(M1575_DMACR_REG, M1575_DMACR_PCMOPAUSE);
+
+		/* configure the number of channels properly */
+		scr = GET32(M1575_SCR_REG);
+		scr &= ~(M1575_SCR_6CHL_MASK | M1575_SCR_CHAMOD_MASK);
+		scr |= M1575_SCR_6CHL_2;	/* select our proper ordering */
+		switch (port->nchan) {
+		case 2:
+			scr |= M1575_SCR_CHAMOD_2;
+			break;
+		case 4:
+			scr |= M1575_SCR_CHAMOD_4;
+			break;
+		case 6:
+			scr |= M1575_SCR_CHAMOD_6;
+			break;
+		}
+		PUT32(M1575_SCR_REG, scr);
+
+		PUT8(M1575_PCMOCR_REG, 0);
+		PUT8(M1575_PCMOCR_REG, M1575_CR_RR);
+
+		PUT32(M1575_PCMOBDBAR_REG, port->bdl_paddr);
+		PUT8(M1575_PCMOLVIV_REG, M1575_BD_NUMS - 1);
+
+		CLR32(M1575_DMACR_REG, M1575_DMACR_PCMOPAUSE);
+		PUT8(M1575_PCMOCR_REG, 0);
+		SET32(M1575_DMACR_REG, M1575_DMACR_PCMOSTART);
 	}
+
 	mutex_exit(&statep->lock);
 	return (0);
 }
 
+
+
 /*
  * audio1575_format()
  *
@@ -678,10 +598,42 @@
 	audio1575_port_t	*port = arg;
 	audio1575_state_t	*statep = port->statep;
 	uint64_t		val;
+	uint8_t			civ;
+	unsigned		n;
+	int			civoff;
+	int			lvioff;
+	int			picoff;
 
 	mutex_enter(&statep->lock);
-	audio1575_update_port(port);
-	val = port->count + (port->picb / port->nchan);
+
+	if (port->num == M1575_REC) {
+		civoff = M1575_PCMICIV_REG;
+		lvioff = M1575_PCMILVIV_REG;
+		picoff = M1575_PCMIPICB_REG;
+	} else {
+		civoff = M1575_PCMOCIV_REG;
+		lvioff = M1575_PCMOLVIV_REG;
+		picoff = M1575_PCMOPICB_REG;
+	}
+
+	/*
+	 * Read the position counters.  We also take this opportunity
+	 * to update the last valid index to the one just previous to
+	 * the one we're working on (so we'll fully loop.)
+	 */
+	n = GET16(picoff);
+	civ = GET8(civoff);
+	PUT8(lvioff, (civ - 1) % M1575_BD_NUMS);
+
+	n = port->samp_size - (n * sizeof (int16_t));
+	if (n < port->offset) {
+		val = (port->samp_size - port->offset) + n;
+	} else {
+		val = n - port->offset;
+	}
+	port->offset = n;
+	port->count += (val / (port->nchan * sizeof (int16_t)));
+	val = port->count;
 	mutex_exit(&statep->lock);
 
 	return (val);
@@ -706,197 +658,6 @@
 }
 
 /*
- * audio1575_start_port()
- *
- * Description:
- *	This routine starts the DMA engine.
- *
- * Arguments:
- *	audio1575_port_t	*port	Port of DMA engine to start.
- */
-static void
-audio1575_start_port(audio1575_port_t *port)
-{
-	audio1575_state_t	*statep = port->statep;
-
-	ASSERT(mutex_owned(&statep->lock));
-
-	/* if suspended, then do nothing else */
-	if (statep->suspended) {
-		return;
-	}
-
-	if (port->num == M1575_REC) {
-		/* ULi says do fifo resets here */
-		SET32(M1575_FIFOCR1_REG, M1575_FIFOCR1_PCMIRST);
-		CLR32(M1575_DMACR_REG, M1575_DMACR_PCMIPAUSE);
-		PUT8(M1575_PCMICR_REG, M1575_PCMICR_IOCE);
-		SET32(M1575_DMACR_REG, M1575_DMACR_PCMISTART);
-	} else {
-		CLR32(M1575_DMACR_REG, M1575_DMACR_PCMOPAUSE);
-		PUT8(M1575_PCMOCR_REG, M1575_PCMOCR_IOCE);
-		SET32(M1575_DMACR_REG, M1575_DMACR_PCMOSTART);
-	}
-}
-
-/*
- * audio1575_stop_port()
- *
- * Description:
- *	This routine stops the DMA engine.
- *
- * Arguments:
- *	audio1575_port_t	*port	Port of DMA engine to stop.
- */
-static void
-audio1575_stop_port(audio1575_port_t *port)
-{
-	audio1575_state_t	*statep = port->statep;
-
-	ASSERT(mutex_owned(&statep->lock));
-
-	/* if suspended, then do nothing else */
-	if (statep->suspended) {
-		return;
-	}
-
-	if (port->num == M1575_REC) {
-		SET32(M1575_DMACR_REG, M1575_DMACR_PCMIPAUSE);
-	} else {
-		SET32(M1575_DMACR_REG, M1575_DMACR_PCMOPAUSE);
-	}
-}
-
-/*
- * audio1575_reset_port()
- *
- * Description:
- *	This routine resets the DMA engine pareparing it for work.
- *
- * Arguments:
- *	audio1575_port_t	*port	Port of DMA engine to reset.
- */
-static void
-audio1575_reset_port(audio1575_port_t *port)
-{
-	audio1575_state_t	*statep = port->statep;
-
-	ASSERT(mutex_owned(&statep->lock));
-
-	port->civ = 0;
-	port->picb = 0;
-
-	if (statep->suspended)
-		return;
-
-	if (port->num == M1575_REC) {
-		/* Uli FIFO madness ... */
-		SET32(M1575_FIFOCR1_REG, M1575_FIFOCR1_PCMIRST);
-		SET32(M1575_DMACR_REG, M1575_DMACR_PCMIPAUSE);
-
-		PUT8(M1575_PCMICR_REG, 0);
-		PUT8(M1575_PCMICR_REG, M1575_CR_RR | M1575_CR_IOCE);
-
-		PUT32(M1575_PCMIBDBAR_REG, port->bdl_paddr);
-		PUT8(M1575_PCMILVIV_REG, M1575_BD_NUMS - 1);
-
-		CLR32(M1575_DMACR_REG, M1575_DMACR_PCMIPAUSE);
-
-	} else {
-
-		uint32_t	scr;
-
-		/* Uli FIFO madness ... */
-		SET32(M1575_FIFOCR1_REG, M1575_FIFOCR1_PCMORST);
-		SET32(M1575_DMACR_REG, M1575_DMACR_PCMOPAUSE);
-
-		/* configure the number of channels properly */
-		scr = GET32(M1575_SCR_REG);
-		scr &= ~(M1575_SCR_6CHL_MASK | M1575_SCR_CHAMOD_MASK);
-		scr |= M1575_SCR_6CHL_2;	/* select our proper ordering */
-		switch (port->nchan) {
-		case 2:
-			scr |= M1575_SCR_CHAMOD_2;
-			break;
-		case 4:
-			scr |= M1575_SCR_CHAMOD_4;
-			break;
-		case 6:
-			scr |= M1575_SCR_CHAMOD_6;
-			break;
-		}
-		PUT32(M1575_SCR_REG, scr);
-
-		PUT8(M1575_PCMOCR_REG, 0);
-		PUT8(M1575_PCMOCR_REG, M1575_CR_RR | M1575_CR_IOCE);
-
-		PUT32(M1575_PCMOBDBAR_REG, port->bdl_paddr);
-		PUT8(M1575_PCMOLVIV_REG, M1575_BD_NUMS - 1);
-
-		CLR32(M1575_DMACR_REG, M1575_DMACR_PCMOPAUSE);
-	}
-}
-
-/*
- * audio1575_update_port()
- *
- * Description:
- *	This routine updates the ports frame counter from hardware, and
- *	gracefully handles wraps.
- *
- * Arguments:
- *	audio1575_port_t	*port		The port to update.
- */
-static void
-audio1575_update_port(audio1575_port_t *port)
-{
-	audio1575_state_t	*statep = port->statep;
-	uint8_t			civ;
-	uint16_t		picb;
-	unsigned		n;
-	int			civoff;
-	int			picoff;
-
-	if (port->num == M1575_REC) {
-		civoff = M1575_PCMICIV_REG;
-		picoff = M1575_PCMIPICB_REG;
-	} else {
-		civoff = M1575_PCMOCIV_REG;
-		picoff = M1575_PCMOPICB_REG;
-	}
-
-	if (statep->suspended) {
-		civ = 0;
-		picb = 0;
-	} else {
-		/*
-		 * We read the position counters, but we're careful to avoid
-		 * the situation where the position counter resets at the end
-		 * of a buffer.
-		 */
-		for (int i = 0; i < 2; i++) {
-			civ = GET8(civoff);
-			picb = GET16(picoff);
-			if (GET8(civoff) == civ) {
-				/*
-				 * Chip did not start a new index, so
-				 * the picb is valid.
-				 */
-				break;
-			}
-		}
-		if (civ >= port->civ) {
-			n = civ - port->civ;
-		} else {
-			n = civ + (M1575_BD_NUMS - port->civ);
-		}
-		port->count += (n * port->fragfr);
-	}
-	port->civ = civ;
-	port->picb = picb;
-}
-
-/*
  * audio1575_attach()
  *
  * Description:
@@ -945,11 +706,6 @@
 		goto error;
 	}
 
-	if (audio1575_setup_intr(statep) != DDI_SUCCESS) {
-		/* message already noted */
-		goto error;
-	}
-
 	/* Enable PCI I/O and Memory Spaces */
 	audio1575_pci_enable(statep);
 
@@ -1003,22 +759,6 @@
 		goto error;
 	}
 
-	/* set up kernel statistics */
-	if ((statep->ksp = kstat_create(M1575_NAME,
-	    ddi_get_instance(dip), M1575_NAME, "controller",
-	    KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT)) != NULL) {
-		kstat_install(statep->ksp);
-	}
-
-	/* Enable PCI Interrupts */
-	pci_config_put8(statep->pcih, M1575_PCIMISC_REG, M1575_PCIMISC_INTENB);
-
-	/* enable audio interrupts */
-	if (ddi_intr_enable(statep->ih) != DDI_SUCCESS) {
-		audio_dev_warn(adev, "ddi_intr_enable() failure");
-		goto error;
-	}
-
 	/* register with the framework */
 	if (audio_dev_register(adev) != DDI_SUCCESS) {
 		audio_dev_warn(adev, "unable to register with framework");
@@ -1066,82 +806,6 @@
 /* *********************** Local Routines *************************** */
 
 /*
- * audio1575_setup_intr()
- *
- * Description:
- *	This routine initializes the audio driver's interrupt handle and
- *	mutex.
- *
- * Arguments:
- *	audio1575_state_t	*state		The device's state structure
- *
- * Returns:
- *	DDI_SUCCESS		Interrupt handle & mutex initialized
- *	DDI_FAILURE		Interrupt handle & mutex not initialized
- */
-int
-audio1575_setup_intr(audio1575_state_t *statep)
-{
-	audio_dev_t		*adev;
-	dev_info_t		*dip;
-	uint_t			ipri;
-	int			actual;
-	int			rv;
-	int			itype;
-	int			count;
-	ddi_intr_handle_t	ih = NULL;
-
-	dip = statep->dip;
-	adev = statep->adev;
-
-	/* get supported interrupt types */
-	rv = ddi_intr_get_supported_types(dip, &itype);
-	if ((rv != DDI_SUCCESS) || (!(itype & DDI_INTR_TYPE_FIXED))) {
-		audio_dev_warn(adev, "Fixed type interrupts not supported");
-		return (DDI_FAILURE);
-	}
-
-	/* make sure we only have one fixed type interrupt */
-	rv = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &count);
-	if ((rv != DDI_SUCCESS) || (count != 1)) {
-		audio_dev_warn(adev, "No fixed interrupts");
-		return (DDI_FAILURE);
-	}
-
-	rv = ddi_intr_alloc(statep->dip, &ih, DDI_INTR_TYPE_FIXED,
-	    0, 1, &actual, DDI_INTR_ALLOC_STRICT);
-	if ((rv != DDI_SUCCESS) || (actual != 1)) {
-		audio_dev_warn(adev, "Can't alloc interrupt handle");
-		return (DDI_FAILURE);
-	}
-
-	/* test for a high level interrupt */
-	if (ddi_intr_get_pri(ih, &ipri) != DDI_SUCCESS) {
-		audio_dev_warn(adev, "Can't get interrupt priority");
-		(void) ddi_intr_free(ih);
-		return (DDI_FAILURE);
-	}
-	if (ipri >= ddi_intr_get_hilevel_pri()) {
-		audio_dev_warn(adev, "Unsupported high level interrupt");
-		(void) ddi_intr_free(ih);
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_add_handler(ih, audio1575_intr, statep, NULL) !=
-	    DDI_SUCCESS) {
-		audio_dev_warn(adev, "Can't add interrupt handler");
-		(void) ddi_intr_free(ih);
-		return (DDI_FAILURE);
-	}
-
-	statep->ih = ih;
-	mutex_init(&statep->lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-	mutex_init(&statep->ac_lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-
-	return (DDI_SUCCESS);
-}
-
-/*
  * audio1575_alloc_port()
  *
  * Description:
@@ -1165,11 +829,9 @@
 	uint_t			count;
 	int			dir;
 	unsigned		caps;
-	char			*prop;
 	audio_dev_t		*adev;
 	audio1575_port_t	*port;
 	uint32_t		*kaddr;
-	uint32_t		paddr;
 	int			rc;
 	dev_info_t		*dip;
 
@@ -1180,45 +842,27 @@
 	statep->ports[num] = port;
 	port->num = num;
 	port->statep = statep;
-	port->started = B_FALSE;
 	port->nchan = nchan;
 
 	if (num == M1575_REC) {
-		prop = "record-interrupts";
 		dir = DDI_DMA_READ;
 		caps = ENGINE_INPUT_CAP;
 		port->sync_dir = DDI_DMA_SYNC_FORKERNEL;
 	} else {
-		prop = "play-interrupts";
 		dir = DDI_DMA_WRITE;
 		caps = ENGINE_OUTPUT_CAP;
 		port->sync_dir = DDI_DMA_SYNC_FORDEV;
 	}
 
-	port->intrs = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, prop, M1575_INTS);
-
-	/* make sure the values are good */
-	if (port->intrs < M1575_MIN_INTS) {
-		audio_dev_warn(adev, "%s too low, %d, resetting to %d",
-		    prop, port->intrs, M1575_INTS);
-		port->intrs = M1575_INTS;
-	} else if (port->intrs > M1575_MAX_INTS) {
-		audio_dev_warn(adev, "%s too high, %d, resetting to %d",
-		    prop, port->intrs, M1575_INTS);
-		port->intrs = M1575_INTS;
-	}
-
 	/*
-	 * Figure out how much space we need.  Sample rate is 48kHz, and
-	 * we need to store 32 chunks.  (Note that this means that low
-	 * interrupt frequencies will require more RAM.  We could probably
-	 * do some cleverness to use a shorter BD list.)
+	 * We use one big sample area.  The sample area must be larger
+	 * than about 1.5 framework fragment sizes.  (Currently 480 *
+	 * 1.5 = 720 frames.)  This is necessary to ensure that we
+	 * don't have to involve an interrupt service routine on our
+	 * own, to keep the last valid index updated reasonably.
 	 */
-	port->fragfr = 48000 / port->intrs;
-	port->fragfr = M1575_ROUNDUP(port->fragfr, M1575_MOD_SIZE);
-	port->samp_size = port->fragfr * port->nchan * 2;
-	port->samp_size *= M1575_BD_NUMS;
+	port->nframes = 2048;
+	port->samp_size = port->nframes * port->nchan * sizeof (int16_t);
 
 	/* allocate dma handle */
 	rc = ddi_dma_alloc_handle(dip, &sample_buf_dma_attr, DDI_DMA_SLEEP,
@@ -1274,20 +918,17 @@
 	 * Wire up the BD list.  We do this *before* binding the BD list
 	 * so that we don't have to do an extra ddi_dma_sync.
 	 */
-	paddr = port->samp_paddr;
 	kaddr = (void *)port->bdl_kaddr;
 	for (int i = 0; i < M1575_BD_NUMS; i++) {
 
 		/* set base address of buffer */
-		ddi_put32(port->bdl_acch, kaddr, paddr);
+		ddi_put32(port->bdl_acch, kaddr, port->samp_paddr);
 		kaddr++;
 
 		/* set size in frames, and enable IOC interrupt */
 		ddi_put32(port->bdl_acch, kaddr,
-		    ((port->fragfr * port->nchan) | (1U << 31)));
+		    ((port->samp_size / sizeof (int16_t)) | (1U << 31)));
 		kaddr++;
-
-		paddr += (port->fragfr * port->nchan * 2);
 	}
 
 	rc = ddi_dma_addr_bind_handle(port->bdl_dmah, NULL, port->bdl_kaddr,
@@ -1319,7 +960,7 @@
  *	deallocates the DMA handles.
  *
  * Arguments:
- *	audio810_port_t	*port	The port structure for a DMA engine.
+ *	audio1575_port_t	*port	The port structure for a DMA engine.
  */
 static void
 audio1575_free_port(audio1575_port_t *port)
@@ -1628,8 +1269,7 @@
 
 	/*
 	 * clear the interrupt control and status register
-	 * READ/WRITE/READ workaround required
-	 * for buggy hardware
+	 * READ/WRITE/READ workaround required to flush PCI caches
 	 */
 
 	PUT32(M1575_INTRCR_REG, 0);
@@ -1693,10 +1333,7 @@
 	audio1575_state_t	*statep = arg;
 	int			i;
 
-	mutex_enter(&statep->ac_lock);
-
 	if (audio1575_codec_sync(statep) != DDI_SUCCESS) {
-		mutex_exit(&statep->ac_lock);
 		return;
 	}
 
@@ -1715,8 +1352,6 @@
 		drv_usecwait(1);
 	}
 
-	mutex_exit(&statep->ac_lock);
-
 	if (i < M1575_LOOP_CTR) {
 		(void) audio1575_read_ac97(statep, reg);
 	}
@@ -1744,9 +1379,7 @@
 	uint16_t		data = 0xffff;
 	int			i;
 
-	mutex_enter(&statep->ac_lock);
 	if ((audio1575_codec_sync(statep)) != DDI_SUCCESS) {
-		mutex_exit(&statep->ac_lock);
 		return (data);
 	}
 
@@ -1779,7 +1412,6 @@
 		}
 	}
 
-	mutex_exit(&statep->ac_lock);
 	return (data);
 }
 
@@ -1860,33 +1492,9 @@
 	}
 
 	/* allow ac97 operations again */
-	ac97_resume(statep->ac97);
-
-	mutex_enter(&statep->lock);
-
-	ASSERT(statep->suspended);
-	statep->suspended = B_FALSE;
-
-	for (int i = 0; i < M1575_NUM_PORTS; i++) {
-
-		audio1575_port_t *port = statep->ports[i];
+	ac97_reset(statep->ac97);
 
-		if (port != NULL) {
-			/* reset framework DMA engine buffer */
-			if (port->engine != NULL) {
-				audio_engine_reset(port->engine);
-			}
-
-			/* reset and initialize hardware ports */
-			audio1575_reset_port(port);
-			if (port->started) {
-				audio1575_start_port(port);
-			} else {
-				audio1575_stop_port(port);
-			}
-		}
-	}
-	mutex_exit(&statep->lock);
+	audio_dev_resume(adev);
 
 	return (DDI_SUCCESS);
 }
@@ -1910,18 +1518,7 @@
 
 	statep = ddi_get_driver_private(dip);
 
-	ac97_suspend(statep->ac97);
-
-	mutex_enter(&statep->lock);
-
-	statep->suspended = B_TRUE;
-
-	/*
-	 * stop all DMA operations
-	 */
-	audio1575_dma_stop(statep, B_FALSE);
-
-	mutex_exit(&statep->lock);
+	audio_dev_suspend(statep->adev);
 
 	return (DDI_SUCCESS);
 }
@@ -1935,9 +1532,6 @@
  *
  * Arguments:
  *	audio1575_state_t	*state	The device soft state.
- *
- * Returns:
- *	None
  */
 void
 audio1575_destroy(audio1575_state_t *statep)
@@ -1962,18 +1556,6 @@
 	/* Disable PCI I/O and Memory Spaces */
 	audio1575_pci_disable(statep);
 
-	if (statep->ih != NULL) {
-		(void) ddi_intr_disable(statep->ih);
-		(void) ddi_intr_remove_handler(statep->ih);
-		(void) ddi_intr_free(statep->ih);
-		mutex_destroy(&statep->lock);
-		mutex_destroy(&statep->ac_lock);
-	}
-
-	if (statep->ksp != NULL) {
-		kstat_delete(statep->ksp);
-	}
-
 	audio1575_free_port(statep->ports[M1575_PLAY]);
 	audio1575_free_port(statep->ports[M1575_REC]);
 
--- a/usr/src/uts/common/io/audio/drv/audio1575/audio1575.conf	Tue Mar 16 09:43:38 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# Configuration file for the audio1575 audio driver.
-#
-# WARNING: This is an UNSTABLE configuration file. Its contents
-#		may change at any time.
-#
-
-#
-# 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 audio1575
-# 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 count
-#
-
-play-interrupts=175;
-record-interrupts=175;
--- a/usr/src/uts/common/io/audio/drv/audio1575/audio1575.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audio1575/audio1575.h	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -36,10 +36,6 @@
 #define	M1575_NAME			"audio1575"
 #define	M1575_MOD_NAME			"M1575 audio driver"
 
-#define	M1575_INTS			(175)	/* default interrupt rate */
-#define	M1575_MIN_INTS			(25)	/* minimum interrupt rate */
-#define	M1575_MAX_INTS			(5000)	/* maximum interrupt rate */
-
 /*
  * Implementation specific header file for the audio1575 device driver.
  */
@@ -59,7 +55,6 @@
 #define	M1575_MOD_SIZE			(16)
 
 /* kstat interrupt counter define */
-#define	M1575_KIOP(X)			((kstat_intr_t *)(X->ksp->ks_data))
 #define	M1575_ROUNDUP(x, algn)		(((x) + ((algn) - 1)) & ~((algn) - 1))
 
 /* PCI CFG SPACE REGISTERS for Audio (Device 29, Function 0) */
@@ -365,17 +360,13 @@
 	uint32_t		bdl_paddr;
 
 	int			num;
-	unsigned		intrs;
-	unsigned		fragfr;
+	unsigned		nframes;
+	uint32_t		offset;
 	uint64_t		count;
 	uint8_t			nchan;
 
-	uint8_t			civ;
-	uint16_t		picb;
 	unsigned		sync_dir;
 
-	boolean_t		started;
-
 	audio_engine_t		*engine;
 };
 typedef struct audio1575_port audio1575_port_t;
@@ -386,22 +377,16 @@
  */
 struct audio1575_state	{
 	kmutex_t		lock;			/* intr mutex */
-	kmutex_t		ac_lock;		/* ac'97 mutex */
 	dev_info_t		*dip;			/* dev instance ptr */
 	audio_dev_t		*adev;			/* audio handle */
 	ac97_t			*ac97;			/* ac'97 handle */
 	audio1575_port_t	*ports[2];		/* DMA engines */
 
-	ddi_intr_handle_t	ih;			/* intr handle */
-
 	ddi_acc_handle_t	pcih;			/* pci config space */
 
 	ddi_acc_handle_t	regsh;			/* audio i/o regs */
 	caddr_t			regsp;			/* base of i/o regs */
 
-	kstat_t			*ksp;			/* kernel statistics */
-
-	boolean_t		suspended;		/* if DDI_SUSPENDed */
 	uint8_t			maxch;			/* maximum channels */
 };
 typedef struct audio1575_state audio1575_state_t;
--- a/usr/src/uts/common/io/audio/drv/audio810/audio810.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audio810/audio810.c	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -28,24 +28,20 @@
  * audio810 Audio Driver
  *
  * The driver is primarily targeted at providing audio support for the
- * W1100z and W2100z systems, which use the AMD 8111 audio core and
- * the Realtek ALC 655 codec. The ALC 655 chip supports only fixed 48k
- * sample rate. However, the audio core of AMD 8111 is completely
- * compatible to the Intel ICHx chips (Intel 8x0 chipsets), so the
- * driver can work for the ICHx.  We only support the 48k maximum
- * rate, since we only have a single PCM out channel.
+ * Intel ICHx family of AC'97 controllers and compatible parts (such
+ * as those from nVidia and AMD.)
  *
- * The AMD 8111 audio core, as an AC'97 controller, has independent
- * channels for PCM in, PCM out, mic in, modem in, and modem out.
- * The AC'97 controller is a PCI bus master with scatter/gather
- * support. Each channel has a DMA engine. Currently, we use only
- * the PCM in and PCM out channels. Each DMA engine uses one buffer
- * descriptor list. And the buffer descriptor list is an array of up
- * to 32 entries, each of which describes a data buffer. Each entry
- * contains a pointer to a data buffer, control bits, and the length
- * of the buffer being pointed to, where the length is expressed as
- * the number of samples. This, combined with the 16-bit sample size,
- * gives the actual physical length of the buffer.
+ * These audio parts have independent channels for PCM in, PCM out,
+ * mic in, and sometimes modem in, and modem out.  The AC'97
+ * controller is a PCI bus master with scatter/gather support. Each
+ * channel has a DMA engine. Currently, we use only the PCM in and PCM
+ * out channels. Each DMA engine uses one buffer descriptor list. And
+ * the buffer descriptor list is an array of up to 32 entries, each of
+ * which describes a data buffer.  Each entry contains a pointer to a
+ * data buffer, control bits, and the length of the buffer being
+ * pointed to, where the length is expressed as the number of
+ * samples. This, combined with the 16-bit sample size, gives the
+ * actual physical length of the buffer.
  *
  * A workaround for the AD1980 and AD1985 codec:
  *	Most vendors connect the surr-out of the codecs to the line-out jack.
@@ -60,6 +56,26 @@
  * 	NOTE:
  * 	This driver depends on the drv/audio and misc/ac97
  * 	modules being loaded first.
+ *
+ * The audio framework guarantees that our entry points are exclusive
+ * with suspend and resume.  This includes data flow and control entry
+ * points alike.
+ *
+ * The audio framework guarantees that only one control is being
+ * accessed on any given audio device at a time.
+ *
+ * The audio framework guarantees that entry points are themselves
+ * serialized for a given engine.
+ *
+ * We have no interrupt routine or other internal asynchronous routines.
+ *
+ * Our device uses completely separate registers for each engine,
+ * except for the start/stop registers, which are implemented in a
+ * manner that allows for them to be accessed concurrently safely from
+ * different threads.
+ *
+ * Hence, it turns out that we simply don't need any locking in this
+ * driver.
  */
 #include <sys/types.h>
 #include <sys/modctl.h>
@@ -83,7 +99,7 @@
 /*
  * Entry point routine prototypes
  */
-static int audio810_open(void *, int, unsigned *, unsigned *, caddr_t *);
+static int audio810_open(void *, int, unsigned *, caddr_t *);
 static void audio810_close(void *);
 static int audio810_start(void *);
 static void audio810_stop(void *);
@@ -111,11 +127,6 @@
 };
 
 /*
- * interrupt handler
- */
-static uint_t	audio810_intr(caddr_t);
-
-/*
  * Local Routine Prototypes
  */
 static int audio810_attach(dev_info_t *);
@@ -124,10 +135,6 @@
 static int audio810_suspend(dev_info_t *);
 
 static int audio810_alloc_port(audio810_state_t *, int, uint8_t);
-static void audio810_start_port(audio810_port_t *);
-static void audio810_stop_port(audio810_port_t *);
-static void audio810_reset_port(audio810_port_t *);
-static void audio810_update_port(audio810_port_t *);
 static int audio810_codec_sync(audio810_state_t *);
 static void audio810_write_ac97(void *, uint8_t, uint16_t);
 static uint16_t audio810_read_ac97(void *, uint8_t);
@@ -135,16 +142,13 @@
 static void audio810_unmap_regs(audio810_state_t *);
 static void audio810_stop_dma(audio810_state_t *);
 static int audio810_chip_init(audio810_state_t *);
+static void audio810_set_channels(audio810_state_t *);
 static void audio810_destroy(audio810_state_t *);
 
 /*
  * Global variables, but used only by this file.
  */
 
-/* driver name, so we don't have to call ddi_driver_name() or hard code strs */
-static char	*audio810_name = I810_NAME;
-
-
 /*
  * DDI Structures
  */
@@ -385,92 +389,6 @@
 }
 
 /*
- * audio810_intr()
- *
- * Description:
- *	Interrupt service routine for both play and record. For play we
- *	get the next buffers worth of audio. For record we send it on to
- *	the mixer.
- *
- *	Each of buffer descriptor has a field IOC(interrupt on completion)
- *	When both this and the IOC bit of correspondent dma control register
- *	is set, it means that the controller should issue an interrupt upon
- *	completion of this buffer.
- *	(AMD 8111 hypertransport I/O hub data sheet. 3.8.3 page 71)
- *
- * 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
-audio810_intr(caddr_t arg)
-{
-	audio810_state_t	*statep;
-	uint16_t		gsr;
-
-	statep = (void *)arg;
-	mutex_enter(&statep->inst_lock);
-
-	if (statep->suspended) {
-		mutex_exit(&statep->inst_lock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	gsr = I810_BM_GET32(I810_REG_GSR);
-
-	/* check if device is interrupting */
-	if ((gsr & I810_GSR_USE_INTR) == 0) {
-		mutex_exit(&statep->inst_lock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	for (int pnum = 0; pnum < I810_NUM_PORTS; pnum++) {
-		audio810_port_t	*port;
-		uint8_t		regoff, index;
-
-		port = statep->ports[pnum];
-		if (port == NULL) {
-			continue;
-		}
-		regoff = port->regoff;
-
-		if (!(I810_BM_GET8(port->stsoff) & I810_BM_SR_BCIS))
-			continue;
-
-		/* update the LVI -- we just set it to the current value - 1 */
-		index = I810_BM_GET8(regoff + I810_OFFSET_CIV);
-		index = (index - 1) % I810_BD_NUMS;
-
-		I810_BM_PUT8(regoff + I810_OFFSET_LVI, index);
-
-		/* clear any interrupt */
-		I810_BM_PUT8(port->stsoff,
-		    I810_BM_SR_LVBCI | I810_BM_SR_BCIS | I810_BM_SR_FIFOE);
-	}
-
-	/* update the kernel interrupt statistics */
-	if (statep->ksp) {
-		I810_KIOP(statep)->intrs[KSTAT_INTR_HARD]++;
-	}
-
-	mutex_exit(&statep->inst_lock);
-
-	/* notify the framework */
-	if (gsr & I810_GSR_INTR_PIN) {
-		audio_engine_produce(statep->ports[I810_PCM_IN]->engine);
-	}
-	if (gsr & I810_GSR_INTR_POUT) {
-		audio_engine_consume(statep->ports[I810_PCM_OUT]->engine);
-	}
-
-	return (DDI_INTR_CLAIMED);
-}
-
-/*
  * audio810_open()
  *
  * Description:
@@ -479,8 +397,7 @@
  * Arguments:
  *	void		*arg		The DMA engine to set up
  *	int		flag		Open flags
- *	unsigned	*fragfrp	Receives number of frames per fragment
- *	unsigned	*nfragsp	Receives number of fragments
+ *	unsigned	*nframes	Receives total number of frames
  *	caddr_t		*bufp		Receives kernel data buffer
  *
  * Returns:
@@ -488,23 +405,16 @@
  *	errno	on failure
  */
 static int
-audio810_open(void *arg, int flag, unsigned *fragfrp, unsigned *nfragsp,
-    caddr_t *bufp)
+audio810_open(void *arg, int flag, unsigned *nframes, caddr_t *bufp)
 {
 	audio810_port_t	*port = arg;
 
 	_NOTE(ARGUNUSED(flag));
 
-	port->started = B_FALSE;
 	port->count = 0;
-	*fragfrp = port->fragfr;
-	*nfragsp = port->nfrag;
+	*nframes = port->samp_frames;
 	*bufp = port->samp_kaddr;
 
-	mutex_enter(&port->statep->inst_lock);
-	audio810_reset_port(port);
-	mutex_exit(&port->statep->inst_lock);
-
 	return (0);
 }
 
@@ -522,13 +432,7 @@
 static void
 audio810_close(void *arg)
 {
-	audio810_port_t		*port = arg;
-	audio810_state_t	*statep = port->statep;
-
-	mutex_enter(&statep->inst_lock);
-	audio810_stop_port(port);
-	port->started = B_FALSE;
-	mutex_exit(&statep->inst_lock);
+	_NOTE(ARGUNUSED(arg));
 }
 
 /*
@@ -546,13 +450,11 @@
 {
 	audio810_port_t		*port = arg;
 	audio810_state_t	*statep = port->statep;
+	uint8_t			cr;
 
-	mutex_enter(&statep->inst_lock);
-	if (port->started) {
-		audio810_stop_port(port);
-	}
-	port->started = B_FALSE;
-	mutex_exit(&statep->inst_lock);
+	cr = I810_BM_GET8(port->regoff + I810_OFFSET_CR);
+	cr &= ~I810_BM_CR_RUN;
+	I810_BM_PUT8(port->regoff + I810_OFFSET_CR, cr);
 }
 
 /*
@@ -572,13 +474,41 @@
 {
 	audio810_port_t		*port = arg;
 	audio810_state_t	*statep = port->statep;
+	uint8_t			regoff, cr;
 
-	mutex_enter(&statep->inst_lock);
-	if (!port->started) {
-		audio810_start_port(port);
-		port->started = B_TRUE;
+	regoff = port->regoff;
+	port->offset = 0;
+
+	/* program multiple channel settings */
+	if (port->num == I810_PCM_OUT) {
+		audio810_set_channels(statep);
+
+		if (statep->quirk == QUIRK_SIS7012) {
+			/*
+			 * SiS 7012 has special unmute bit.
+			 */
+			I810_BM_PUT8(I810_REG_SISCTL, I810_SISCTL_UNMUTE);
+		}
 	}
-	mutex_exit(&statep->inst_lock);
+
+	/*
+	 * Perform full reset of the engine, but leave it turned off.
+	 */
+	I810_BM_PUT8(regoff + I810_OFFSET_CR, 0);
+	I810_BM_PUT8(regoff + I810_OFFSET_CR, I810_BM_CR_RST);
+
+	/* program the offset of the BD list */
+	I810_BM_PUT32(regoff + I810_OFFSET_BD_BASE, port->bdl_paddr);
+
+	/* we set the last index to the full count -- all buffers are valid */
+	I810_BM_PUT8(regoff + I810_OFFSET_LVI, I810_BD_NUMS - 1);
+
+	cr = I810_BM_GET8(regoff + I810_OFFSET_CR);
+	cr |= I810_BM_CR_RUN;
+	I810_BM_PUT8(regoff + I810_OFFSET_CR, cr);
+
+	(void) I810_BM_GET8(regoff + I810_OFFSET_CR);
+
 	return (0);
 }
 
@@ -660,23 +590,35 @@
 {
 	audio810_port_t		*port = arg;
 	audio810_state_t	*statep = port->statep;
+	uint8_t			regoff = port->regoff;
 	uint64_t		val;
-	uint16_t		picb;
-	uint64_t		count;
-	uint8_t			nchan;
+	uint32_t		offset;
+	uint8_t			civ;
+
+	/*
+	 * Read the position counters.  We also take this opportunity
+	 * to update the last valid index to the one just previous to
+	 * the one we're working on (so we'll fully loop.)
+	 */
+	offset = I810_BM_GET16(port->picboff);
+	civ = I810_BM_GET8(regoff + I810_OFFSET_CIV);
+	I810_BM_PUT8(port->regoff + I810_OFFSET_LVI, (civ - 1) % I810_BD_NUMS);
 
-	mutex_enter(&statep->inst_lock);
-	audio810_update_port(port);
-	count = port->count;
-	picb = port->picb;
-	nchan = port->nchan;
-	mutex_exit(&statep->inst_lock);
+	/* SiS counts in bytes, all others in words. */
+	if (statep->quirk != QUIRK_SIS7012)
+		offset *= 2;
+
+	/* counter is reversed */
+	offset = port->samp_size - offset;
 
-	if (statep->quirk == QUIRK_SIS7012) {
-		val = count + picb / (2 * nchan);
+	if (offset < port->offset) {
+		val = (port->samp_size - port->offset) + offset;
 	} else {
-		val = count + (picb / nchan);
+		val = offset - port->offset;
 	}
+	port->offset = offset;
+	port->count += (val / (port->nchan * 2));
+	val = port->count;
 
 	return (val);
 }
@@ -712,14 +654,16 @@
  *	void	*arg		The DMA engine to query
  *
  * Returns:
- *	Play ahead in frames (4 fragments).
+ *	Play ahead in frames.
  */
 static unsigned
 audio810_playahead(void *arg)
 {
 	audio810_port_t *port = arg;
+	audio810_state_t	*statep = port->statep;
 
-	return (4 * port->fragfr);
+	/* Older ICH is likely to be emulated, deeper (40 ms) playahead */
+	return (statep->quirk == QUIRK_OLDICH ? 1920 : 0);
 }
 
 
@@ -727,210 +671,6 @@
 /* *********************** Local Routines *************************** */
 
 /*
- * audio810_start_port()
- *
- * Description:
- *	This routine starts the DMA engine.
- *
- * Arguments:
- *	audio810_port_t	*port		Port of DMA engine to start.
- */
-static void
-audio810_start_port(audio810_port_t *port)
-{
-	audio810_state_t	*statep = port->statep;
-	uint8_t			cr;
-
-	ASSERT(mutex_owned(&statep->inst_lock));
-
-	/* if suspended, then do nothing else */
-	if (statep->suspended) {
-		return;
-	}
-
-	cr = I810_BM_GET8(port->regoff + I810_OFFSET_CR);
-	cr |= I810_BM_CR_IOCE;
-	I810_BM_PUT8(port->regoff + I810_OFFSET_CR, cr);
-	cr |= I810_BM_CR_RUN;
-	I810_BM_PUT8(port->regoff + I810_OFFSET_CR, cr);
-}
-
-/*
- * audio810_stop_port()
- *
- * Description:
- *	This routine stops the DMA engine.
- *
- * Arguments:
- *	audio810_port_t	*port		Port of DMA engine to stop.
- */
-static void
-audio810_stop_port(audio810_port_t *port)
-{
-	audio810_state_t	*statep = port->statep;
-	uint8_t			cr;
-
-	ASSERT(mutex_owned(&statep->inst_lock));
-
-	/* if suspended, then do nothing else */
-	if (statep->suspended) {
-		return;
-	}
-
-	cr = I810_BM_GET8(port->regoff + I810_OFFSET_CR);
-	cr &= ~I810_BM_CR_RUN;
-	I810_BM_PUT8(port->regoff + I810_OFFSET_CR, cr);
-}
-
-/*
- * audio810_reset_port()
- *
- * Description:
- *	This routine resets the DMA engine pareparing it for work.
- *
- * Arguments:
- *	audio810_port_t	*port		Port of DMA engine to reset.
- */
-static void
-audio810_reset_port(audio810_port_t *port)
-{
-	audio810_state_t	*statep = port->statep;
-	uint32_t		gcr;
-
-	ASSERT(mutex_owned(&statep->inst_lock));
-
-	port->civ = 0;
-	port->picb = 0;
-
-	if (statep->suspended)
-		return;
-
-	/*
-	 * Make sure we put once in stereo, to ensure we always start from
-	 * front left.
-	 */
-	if (port->num == I810_PCM_OUT) {
-
-		if (statep->quirk == QUIRK_SIS7012) {
-			/*
-			 * SiS 7012 needs its own special multichannel config.
-			 */
-			gcr = I810_BM_GET32(I810_REG_GCR);
-			gcr &= ~I810_GCR_SIS_CHANNELS_MASK;
-			I810_BM_PUT32(I810_REG_GCR, gcr);
-			delay(drv_usectohz(50000));	/* 50 msec */
-
-			switch (statep->maxch) {
-			case 2:
-				gcr |= I810_GCR_SIS_2_CHANNELS;
-				break;
-			case 4:
-				gcr |= I810_GCR_SIS_4_CHANNELS;
-				break;
-			case 6:
-				gcr |= I810_GCR_SIS_6_CHANNELS;
-				break;
-			}
-			I810_BM_PUT32(I810_REG_GCR, gcr);
-			delay(drv_usectohz(50000));	/* 50 msec */
-
-			/*
-			 * SiS 7012 has special unmute bit.
-			 */
-			I810_BM_PUT8(I810_REG_SISCTL, I810_SISCTL_UNMUTE);
-
-		} else {
-
-			/*
-			 * All other devices work the same.
-			 */
-			gcr = I810_BM_GET32(I810_REG_GCR);
-			gcr &= ~I810_GCR_CHANNELS_MASK;
-
-			I810_BM_PUT32(I810_REG_GCR, gcr);
-			delay(drv_usectohz(50000));	/* 50 msec */
-
-			switch (statep->maxch) {
-			case 2:
-				gcr |= I810_GCR_2_CHANNELS;
-				break;
-			case 4:
-				gcr |= I810_GCR_4_CHANNELS;
-				break;
-			case 6:
-				gcr |= I810_GCR_6_CHANNELS;
-				break;
-			}
-			I810_BM_PUT32(I810_REG_GCR, gcr);
-			delay(drv_usectohz(50000));	/* 50 msec */
-		}
-	}
-
-	/*
-	 * Perform full reset of the engine, but leave it turned off.
-	 */
-	I810_BM_PUT8(port->regoff + I810_OFFSET_CR, 0);
-	I810_BM_PUT8(port->regoff + I810_OFFSET_CR, I810_BM_CR_RST);
-
-	/* program the offset of the BD list */
-	I810_BM_PUT32(port->regoff + I810_OFFSET_BD_BASE, port->bdl_paddr);
-
-	/* we set the last index to the full count -- all buffers are valid */
-	I810_BM_PUT8(port->regoff + I810_OFFSET_LVI, I810_BD_NUMS - 1);
-}
-
-/*
- * audio810_update_port()
- *
- * Description:
- *	This routine updates the ports frame counter from hardware, and
- *	gracefully handles wraps.
- *
- * Arguments:
- *	audio810_port_t	*port		The port to update.
- */
-static void
-audio810_update_port(audio810_port_t *port)
-{
-	audio810_state_t	*statep = port->statep;
-	uint8_t			regoff = port->regoff;
-	uint8_t			civ;
-	uint16_t		picb;
-	unsigned		n;
-
-	if (statep->suspended) {
-		civ = 0;
-		picb = 0;
-	} else {
-		/*
-		 * We read the position counters, but we're careful to avoid
-		 * the situation where the position counter resets at the end
-		 * of a buffer.
-		 */
-		for (int i = 0; i < 2; i++) {
-			civ = I810_BM_GET8(regoff + I810_OFFSET_CIV);
-			picb = I810_BM_GET16(port->picboff);
-			if (I810_BM_GET8(regoff + I810_OFFSET_CIV) == civ) {
-				/*
-				 * Chip did not start a new index,
-				 * so the picb is valid.
-				 */
-				break;
-			}
-		}
-
-		if (civ >= port->civ) {
-			n = civ - port->civ;
-		} else {
-			n = civ + (I810_BD_NUMS - port->civ);
-		}
-		port->count += (n * port->fragfr);
-	}
-	port->civ = civ;
-	port->picb = picb;
-}
-
-/*
  * audio810_attach()
  *
  * Description:
@@ -959,30 +699,13 @@
 	uint8_t			nch;
 	int			maxch;
 
-	/* we don't support high level interrupts in the driver */
-	if (ddi_intr_hilevel(dip, 0) != 0) {
-		cmn_err(CE_WARN, "!%s: unsupported high level interrupt",
-		    audio810_name);
-		return (DDI_FAILURE);
-	}
-
 	/* allocate the soft state structure */
 	statep = kmem_zalloc(sizeof (*statep), KM_SLEEP);
 	ddi_set_driver_private(dip, statep);
 
-	/* get iblock cookie information */
-	if (ddi_get_iblock_cookie(dip, 0, &statep->iblock) != DDI_SUCCESS) {
-		cmn_err(CE_WARN, "!%s: cannot get iblock cookie",
-		    audio810_name);
-		kmem_free(statep, sizeof (*statep));
-		return (DDI_FAILURE);
-	}
-	mutex_init(&statep->inst_lock, NULL, MUTEX_DRIVER, statep->iblock);
-	mutex_init(&statep->ac_lock, NULL, MUTEX_DRIVER, statep->iblock);
-
 	if ((adev = audio_dev_alloc(dip, 0)) == NULL) {
-		cmn_err(CE_WARN, "!%s: unable to allocate audio dev",
-		    audio810_name);
+		cmn_err(CE_WARN, "!%s%d: unable to allocate audio dev",
+		    ddi_driver_name(dip), ddi_get_instance(dip));
 		goto error;
 	}
 	statep->adev = adev;
@@ -1015,6 +738,7 @@
 	case 0x80862415:
 		name = "Intel AC'97";
 		vers = "ICH";
+		statep->quirk = QUIRK_OLDICH;
 		break;
 	case 0x80862425:
 		name = "Intel AC'97";
@@ -1160,21 +884,6 @@
 		goto error;
 	}
 
-	/* set up kernel statistics */
-	if ((statep->ksp = kstat_create(I810_NAME, ddi_get_instance(dip),
-	    I810_NAME, "controller", KSTAT_TYPE_INTR, 1,
-	    KSTAT_FLAG_PERSISTENT)) != NULL) {
-		kstat_install(statep->ksp);
-	}
-
-	/* set up the interrupt handler */
-	if (ddi_add_intr(dip, 0, &statep->iblock,
-	    NULL, audio810_intr, (caddr_t)statep) != DDI_SUCCESS) {
-		audio_dev_warn(adev, "bad interrupt specification");
-		goto error;
-	}
-	statep->intr_added = B_TRUE;
-
 	if (audio_dev_register(adev) != DDI_SUCCESS) {
 		audio_dev_warn(adev, "unable to register with framework");
 		goto error;
@@ -1221,43 +930,33 @@
 	/* Restore the audio810 chip's state */
 	if (audio810_chip_init(statep) != DDI_SUCCESS) {
 		/*
-		 * Note that PM gurus say we should return
-		 * success here.  Failure of audio shouldn't
-		 * be considered FATAL to the system.  The
-		 * upshot is that audio will not progress.
+		 * Note that PM gurus say we should return success
+		 * here.  Failure of audio shouldn't be considered
+		 * FATAL to the system.
+		 *
+		 * It turns out that the only way that the
+		 * audio810_chip_init fails is that the codec won't
+		 * re-initialize.  Audio streams may or may not make
+		 * progress; setting changes may or may not have the
+		 * desired effect.  What we'd really to do at this
+		 * point is use FMA to offline the part.  In the
+		 * meantime, we just muddle on logging the error.
+		 *
+		 * Note that returning from this routine without
+		 * allowing the audio_dev_resume() to take place can
+		 * have bad effects, as the framework does not know
+		 * what to do in the event of a failure of this
+		 * nature.  (It may be unsafe to call ENG_CLOSE(), for
+		 * example.)
 		 */
-		audio_dev_warn(adev, "DDI_RESUME failed to init chip");
-		return (DDI_SUCCESS);
+		audio_dev_warn(adev, "failure to resume codec");
 	}
 
-	/* allow ac97 operations again */
-	ac97_resume(statep->ac97);
-
-	mutex_enter(&statep->inst_lock);
-
-	ASSERT(statep->suspended);
-	statep->suspended = B_FALSE;
-
-	for (int i = 0; i < I810_NUM_PORTS; i++) {
-
-		audio810_port_t *port = statep->ports[i];
+	/* Reset the AC'97 codec. */
+	ac97_reset(statep->ac97);
 
-		if (port != NULL) {
-			/* reset framework DMA engine buffer */
-			if (port->engine != NULL) {
-				audio_engine_reset(port->engine);
-			}
-
-			/* reset and initialize hardware ports */
-			audio810_reset_port(port);
-			if (port->started) {
-				audio810_start_port(port);
-			} else {
-				audio810_stop_port(port);
-			}
-		}
-	}
-	mutex_exit(&statep->inst_lock);
+	/* And let the framework know we're ready for business again. */
+	audio_dev_resume(statep->adev);
 
 	return (DDI_SUCCESS);
 }
@@ -1313,19 +1012,11 @@
 	statep = ddi_get_driver_private(dip);
 	ASSERT(statep != NULL);
 
-	ac97_suspend(statep->ac97);
-
-	mutex_enter(&statep->inst_lock);
-
-	ASSERT(statep->suspended == B_FALSE);
+	audio_dev_suspend(statep->adev);
 
-	statep->suspended = B_TRUE; /* stop new ops */
-
-	/* stop DMA engines */
+	/* stop DMA engines - should be redundant (paranoia) */
 	audio810_stop_dma(statep);
 
-	mutex_exit(&statep->inst_lock);
-
 	return (DDI_SUCCESS);
 }
 
@@ -1351,11 +1042,8 @@
 	uint_t			count;
 	int			dir;
 	unsigned		caps;
-	char			*prop;
-	char			*nfprop;
 	audio_dev_t		*adev;
 	audio810_port_t		*port;
-	uint32_t		paddr;
 	int			rc;
 	dev_info_t		*dip;
 	i810_bd_entry_t		*bdentry;
@@ -1366,22 +1054,17 @@
 	port = kmem_zalloc(sizeof (*port), KM_SLEEP);
 	statep->ports[num] = port;
 	port->statep = statep;
-	port->started = B_FALSE;
 	port->nchan = nchan;
 	port->num = num;
 
 	switch (num) {
 	case I810_PCM_IN:
-		prop = "record-interrupts";
-		nfprop = "record-fragments";
 		dir = DDI_DMA_READ;
 		caps = ENGINE_INPUT_CAP;
 		port->sync_dir = DDI_DMA_SYNC_FORKERNEL;
 		port->regoff = I810_BASE_PCM_IN;
 		break;
 	case I810_PCM_OUT:
-		prop = "play-interrupts";
-		nfprop = "play-fragments";
 		dir = DDI_DMA_WRITE;
 		caps = ENGINE_OUTPUT_CAP;
 		port->sync_dir = DDI_DMA_SYNC_FORDEV;
@@ -1403,45 +1086,15 @@
 		port->picboff = port->regoff + I810_OFFSET_PICB;
 	}
 
-	port->intrs = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, prop, I810_INTS);
-
-	/* make sure the values are good */
-	if (port->intrs < I810_MIN_INTS) {
-		audio_dev_warn(adev, "%s too low, %d, resetting to %d",
-		    prop, port->intrs, I810_INTS);
-		port->intrs = I810_INTS;
-	} else if (port->intrs > I810_MAX_INTS) {
-		audio_dev_warn(adev, "%s too high, %d, resetting to %d",
-		    prop, port->intrs, I810_INTS);
-		port->intrs = I810_INTS;
-	}
-
-	port->nfrag = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, nfprop, I810_NFRAGS);
-
 	/*
-	 * Note that fragments must divide evenly into I810_BD_NUMS (32).
-	 * We also insist that the value be larger than our "playahead".
+	 * We use one big sample area.  The sample area must be larger
+	 * than about 1.5 framework fragment sizes.  (Currently 480 *
+	 * 1.5 = 720 frames.)  This is necessary to ensure that we
+	 * don't have to involve an interrupt service routine on our
+	 * own, to keep the last valid index updated reasonably.
 	 */
-	if (port->nfrag <= 8) {
-		port->nfrag = 8;
-	} else if (port->nfrag <= 16) {
-		port->nfrag = 16;
-	} else {
-		port->nfrag = I810_BD_NUMS;
-	}
-
-	/*
-	 * Figure out how much space we need.  Sample rate is 48kHz, and
-	 * we need to store 32 chunks.  (Note that this means that low
-	 * interrupt frequencies will require more RAM.  We could probably
-	 * do some cleverness to use a shorter BD list.)
-	 */
-	port->fragfr = 48000 / port->intrs;
-	port->fragfr = I810_ROUNDUP(port->fragfr, I810_MOD_SIZE);
-	port->fragsz = port->fragfr * port->nchan * 2;
-	port->samp_size = port->fragsz * port->nfrag;
+	port->samp_frames = 4096;
+	port->samp_size = port->samp_frames * port->nchan * sizeof (int16_t);
 
 	/* allocate dma handle */
 	rc = ddi_dma_alloc_handle(dip, &sample_buf_dma_attr, DDI_DMA_SLEEP,
@@ -1506,26 +1159,18 @@
 	/*
 	 * Wire up the BD list.
 	 */
-	paddr = port->samp_paddr;
 	bdentry = (void *)port->bdl_kaddr;
 	for (int i = 0; i < I810_BD_NUMS; i++) {
 
 		/* set base address of buffer */
-		ddi_put32(port->bdl_acch, &bdentry->buf_base, paddr);
-		/*
-		 * SiS 7012 counts samples in bytes, all other count
-		 * in words.
-		 */
+		ddi_put32(port->bdl_acch, &bdentry->buf_base,
+		    port->samp_paddr);
+		/* SiS 7012 counts in bytes, all others in words */
 		ddi_put16(port->bdl_acch, &bdentry->buf_len,
-		    statep->quirk == QUIRK_SIS7012 ? port->fragsz :
-		    port->fragsz / 2);
-		ddi_put16(port->bdl_acch, &bdentry->buf_cmd,
-		    BUF_CMD_IOC | BUF_CMD_BUP);
-		paddr += port->fragsz;
-		if ((i % port->nfrag) == (port->nfrag - 1)) {
-			/* handle wrap */
-			paddr = port->samp_paddr;
-		}
+		    statep->quirk == QUIRK_SIS7012 ? port->samp_size :
+		    port->samp_size / 2);
+		ddi_put16(port->bdl_acch, &bdentry->buf_cmd, BUF_CMD_BUP);
+
 		bdentry++;
 	}
 	(void) ddi_dma_sync(port->bdl_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
@@ -1742,8 +1387,7 @@
  * audio810_chip_init()
  *
  * Description:
- *	This routine initializes the AMD 8111 audio controller.
- *	codec.
+ *	This routine initializes the audio controller.
  *
  * Arguments:
  *	audio810_state_t	*state		The device's state structure
@@ -1828,6 +1472,72 @@
 }
 
 /*
+ * audio810_set_channels()
+ *
+ * Description:
+ *	This routine initializes the multichannel configuration.
+ *
+ * Arguments:
+ *	audio810_state_t	*state		The device's state structure
+ */
+static void
+audio810_set_channels(audio810_state_t *statep)
+{
+	uint32_t	gcr;
+
+	/*
+	 * Configure multi-channel.
+	 */
+	if (statep->quirk == QUIRK_SIS7012) {
+		/*
+		 * SiS 7012 needs its own special multichannel config.
+		 */
+		gcr = I810_BM_GET32(I810_REG_GCR);
+		gcr &= ~I810_GCR_SIS_CHANNELS_MASK;
+		I810_BM_PUT32(I810_REG_GCR, gcr);
+		delay(drv_usectohz(50000));	/* 50 msec */
+
+		switch (statep->maxch) {
+		case 2:
+			gcr |= I810_GCR_SIS_2_CHANNELS;
+			break;
+		case 4:
+			gcr |= I810_GCR_SIS_4_CHANNELS;
+			break;
+		case 6:
+			gcr |= I810_GCR_SIS_6_CHANNELS;
+			break;
+		}
+		I810_BM_PUT32(I810_REG_GCR, gcr);
+		delay(drv_usectohz(50000));	/* 50 msec */
+	} else {
+
+		/*
+		 * All other devices work the same.
+		 */
+		gcr = I810_BM_GET32(I810_REG_GCR);
+		gcr &= ~I810_GCR_CHANNELS_MASK;
+
+		I810_BM_PUT32(I810_REG_GCR, gcr);
+		delay(drv_usectohz(50000));	/* 50 msec */
+
+		switch (statep->maxch) {
+		case 2:
+			gcr |= I810_GCR_2_CHANNELS;
+			break;
+		case 4:
+			gcr |= I810_GCR_4_CHANNELS;
+			break;
+		case 6:
+			gcr |= I810_GCR_6_CHANNELS;
+			break;
+		}
+		I810_BM_PUT32(I810_REG_GCR, gcr);
+		delay(drv_usectohz(50000));	/* 50 msec */
+	}
+}
+
+/*
  * audio810_stop_dma()
  *
  * Description:
@@ -1901,11 +1611,9 @@
 {
 	audio810_state_t	*statep = arg;
 
-	mutex_enter(&statep->ac_lock);
 	if (audio810_codec_sync(statep) == DDI_SUCCESS) {
 		I810_AM_PUT16(reg, data);
 	}
-	mutex_exit(&statep->ac_lock);
 
 	(void) audio810_read_ac97(statep, reg);
 }
@@ -1929,11 +1637,9 @@
 	audio810_state_t	*statep = arg;
 	uint16_t		val = 0xffff;
 
-	mutex_enter(&statep->ac_lock);
 	if (audio810_codec_sync(statep) == DDI_SUCCESS) {
 		val = I810_AM_GET16(reg);
 	}
-	mutex_exit(&statep->ac_lock);
 	return (val);
 }
 
@@ -1953,14 +1659,6 @@
 	/* stop DMA engines */
 	audio810_stop_dma(statep);
 
-	if (statep->intr_added) {
-		ddi_remove_intr(statep->dip, 0, NULL);
-	}
-
-	if (statep->ksp) {
-		kstat_delete(statep->ksp);
-	}
-
 	for (int i = 0; i < I810_NUM_PORTS; i++) {
 		audio810_free_port(statep->ports[i]);
 	}
@@ -1973,7 +1671,5 @@
 	if (statep->adev)
 		audio_dev_free(statep->adev);
 
-	mutex_destroy(&statep->inst_lock);
-	mutex_destroy(&statep->ac_lock);
 	kmem_free(statep, sizeof (*statep));
 }
--- a/usr/src/uts/common/io/audio/drv/audio810/audio810.conf	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audio810/audio810.conf	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # Configuration file for the audio810 audio driver.
@@ -28,24 +28,6 @@
 #		may change at any time.
 
 #
-# 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 audio810
-# 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=120;
-# record-interrupts=120;
-
-#
 # The presence of the ac97-speaker property enables the use of a monoaural
 # output, normally intended for use with a speaker phone.  Most systems
 # do not connect this to anything.  The value of the property indicates
--- a/usr/src/uts/common/io/audio/drv/audio810/audio810.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audio810/audio810.h	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -36,11 +36,6 @@
 #define	I810_NAME			"audio810"
 #define	I810_MOD_NAME			"audio810 audio driver"
 
-#define	I810_INTS			(120)	/* default interrupt rate */
-#define	I810_MIN_INTS			(24)	/* minimum interrupt rate */
-#define	I810_MAX_INTS			(500)	/* maximum interrupt rate */
-#define	I810_NFRAGS			(8)	/* default # fragments */
-
 /*
  * Misc. defines
  */
@@ -50,7 +45,6 @@
 #define	I810_MOD_SIZE			(16)
 
 #define	I810_ROUNDUP(x, algn)		(((x) + ((algn) - 1)) & ~((algn) - 1))
-#define	I810_KIOP(X)			((kstat_intr_t *)(X->ksp->ks_data))
 
 /* The size of each entry of "reg" property is 5 integers */
 #define	I810_INTS_PER_REG_PROP		5
@@ -156,6 +150,7 @@
 	int			num;
 	ddi_dma_handle_t	samp_dmah;
 	ddi_acc_handle_t	samp_acch;
+	uint32_t		samp_frames;
 	size_t			samp_size;
 	caddr_t			samp_kaddr;
 	uint32_t		samp_paddr;
@@ -166,22 +161,15 @@
 	caddr_t			bdl_kaddr;
 	uint32_t		bdl_paddr;
 
-	unsigned		intrs;
-	unsigned		fragfr;
-	unsigned		fragsz;
+	uint32_t		offset;
 	uint64_t		count;
-	uint8_t			nfrag;
 	uint8_t			nchan;
 
 	uint8_t			regoff;
 	uint8_t			stsoff;		/* status offset */
 	uint8_t			picboff;	/* picb offset */
-	uint8_t			civ;
-	uint16_t		picb;
 	unsigned		sync_dir;
 
-	boolean_t		started;
-
 	audio_engine_t		*engine;
 };
 typedef struct audio810_port audio810_port_t;
@@ -200,6 +188,7 @@
 
 typedef enum i810_quirk {
 	QUIRK_NONE = 0,
+	QUIRK_OLDICH,		/* likely emulated, needs deeper playahead */
 	QUIRK_SIS7012,		/* weird registers and such */
 } i810_quirk_t;
 
@@ -207,9 +196,6 @@
  * audio810_state_t	-per instance state and operation data
  */
 struct audio810_state {
-	kmutex_t		inst_lock;	/* state protection lock */
-	kmutex_t		ac_lock;
-	ddi_iblock_cookie_t	iblock;
 	dev_info_t		*dip;	/* used by audio810_getinfo() */
 	audio_dev_t		*adev;
 	ac97_t			*ac97;
@@ -222,8 +208,6 @@
 
 	kstat_t			*ksp;		/* kernel statistics */
 
-	boolean_t		intr_added;
-	boolean_t		suspended;	/* suspend/resume state */
 	uint8_t			maxch;
 	i810_quirk_t		quirk;
 };
--- a/usr/src/uts/common/io/audio/drv/audiocmi/audiocmi.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiocmi/audiocmi.c	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
@@ -89,66 +89,39 @@
 	0			/* dma_attr_flags */
 };
 
-static uint_t
-cmpci_intr(caddr_t arg1, caddr_t arg2)
-{
-	cmpci_dev_t	*dev = (void *)arg1;
 
-	uint32_t	intstat, intctrl, intclear;
-	void		(*cb0)(audio_engine_t *) = NULL;
-	void		(*cb1)(audio_engine_t *) = NULL;
-	uint_t		rv;
+static int
+cmpci_open(void *arg, int flag, uint_t *nframesp, caddr_t *bufp)
+{
+	cmpci_port_t *port = arg;
+	cmpci_dev_t *dev = port->dev;
 
-	_NOTE(ARGUNUSED(arg2));
-
-	rv = DDI_INTR_UNCLAIMED;
+	_NOTE(ARGUNUSED(flag));
 
 	mutex_enter(&dev->mutex);
-	if (dev->suspended) {
-		mutex_exit(&dev->mutex);
-		return (rv);
-	}
 
-	intclear = 0;
-	intstat = GET32(dev, REG_INTSTAT);
-	intctrl = GET32(dev, REG_INTCTRL);
-	if ((intstat & INTSTAT_CH0_INT) && (intctrl & INTCTRL_CH0_EN)) {
-		intclear |= INTCTRL_CH0_EN;
-		cb0 = dev->port[0].callb;
-	}
-	if ((intstat & INTSTAT_CH1_INT) && (intctrl & INTCTRL_CH1_EN)) {
-		intclear |= INTCTRL_CH1_EN;
-		cb1 = dev->port[1].callb;
-	}
+	*nframesp = port->nframes;
+	*bufp = port->kaddr;
 
-	/* toggle the bits that we are going to handle */
-	if (intclear) {
-		CLR32(dev, REG_INTCTRL, intclear);
-		SET32(dev, REG_INTCTRL, intclear);
-		rv = DDI_INTR_CLAIMED;
-
-		KSINTR(dev)->intrs[KSTAT_INTR_HARD]++;
-	}
-
+	port->count = 0;
 	mutex_exit(&dev->mutex);
 
-	if (cb0) {
-		(*cb0)(dev->port[0].engine);
-	}
-	if (cb1) {
-		(*cb1)(dev->port[1].engine);
-	}
-
-	return (rv);
+	return (0);
 }
 
 static void
-cmpci_reset_port(cmpci_port_t *port)
+cmpci_close(void *arg)
 {
-	cmpci_dev_t *dev = port->dev;
+	_NOTE(ARGUNUSED(arg));
+}
 
-	if (dev->suspended)
-		return;
+static int
+cmpci_start(void *arg)
+{
+	cmpci_port_t	*port = arg;
+	cmpci_dev_t	*dev = port->dev;
+
+	mutex_enter(&dev->mutex);
 
 	port->offset = 0;
 
@@ -222,7 +195,7 @@
 
 	PUT32(dev, port->reg_paddr, port->paddr);
 	PUT16(dev, port->reg_bufsz, (port->bufsz / 4) - 1);
-	PUT16(dev, port->reg_fragsz, (port->fragfr *  port->nchan / 2) - 1);
+	PUT16(dev, port->reg_fragsz, (port->bufsz  / 4) - 1);
 
 	/* Analog output */
 	if (port->capture) {
@@ -231,77 +204,33 @@
 	} else {
 		CLR32(dev, REG_FUNCTRL0, port->fc0_rec_bit);
 	}
-}
-
-static void
-cmpci_start_port(cmpci_port_t *port)
-{
-	cmpci_dev_t	*dev = port->dev;
-
-	if (dev->suspended)
-		return;
 
 	SET32(dev, REG_FUNCTRL0, port->fc0_en_bit);
-	SET32(dev, REG_INTCTRL, port->int_en_bit);
-}
-
-static void
-cmpci_stop_port(cmpci_port_t *port)
-{
-	cmpci_dev_t	*dev = port->dev;
-
-	if (dev->suspended)
-		return;
-
-	CLR32(dev, REG_FUNCTRL0, port->fc0_en_bit);
-	CLR32(dev, REG_INTCTRL, port->int_en_bit);
-}
+	mutex_exit(&dev->mutex);
 
-static int
-cmpci_open(void *arg, int flag, uint_t *fragfrp, uint_t *nfp, caddr_t *bufp)
-{
-	cmpci_port_t *port = arg;
-	cmpci_dev_t *dev = port->dev;
-
-	_NOTE(ARGUNUSED(flag));
-
-	mutex_enter(&dev->mutex);
-
-	*fragfrp = port->fragfr;
-	*nfp = port->nfrags;
-	*bufp = port->kaddr;
-
-	port->count = 0;
-	port->open = B_TRUE;
-
-	cmpci_reset_port(port);
-	cmpci_start_port(port);
-
-	mutex_exit(&dev->mutex);
 	return (0);
 }
 
 static void
-cmpci_close(void *arg)
+cmpci_stop(void *arg)
 {
-	cmpci_port_t *port = arg;
-	cmpci_dev_t *dev = port->dev;
+	cmpci_port_t	*port = arg;
+	cmpci_dev_t	*dev = port->dev;
 
 	mutex_enter(&dev->mutex);
-	port->open = B_FALSE;
-	cmpci_stop_port(port);
+	CLR32(dev, REG_FUNCTRL0, port->fc0_en_bit);
 	mutex_exit(&dev->mutex);
 }
 
-static void
-cmpci_update_port(cmpci_port_t *port)
+static uint64_t
+cmpci_count(void *arg)
 {
+	cmpci_port_t	*port = arg;
 	cmpci_dev_t	*dev = port->dev;
-	uint32_t	count;
+	uint64_t	count;
 	uint32_t	offset;
 
-	if ((dev->suspended) || (!port->open))
-		return;
+	mutex_enter(&dev->mutex);
 
 	/* this gives us the offset in dwords */
 	offset = (port->bufsz / 4) - (GET16(dev, port->reg_bufsz) + 1);
@@ -314,19 +243,6 @@
 	}
 	port->count += count;
 	port->offset = offset;
-}
-
-static uint64_t
-cmpci_count(void *arg)
-{
-	cmpci_port_t	*port = arg;
-	cmpci_dev_t	*dev = port->dev;
-	uint64_t	count;
-
-	mutex_enter(&dev->mutex);
-	cmpci_update_port(port);
-
-	/* the count is in dwords */
 	count = port->count;
 
 	mutex_exit(&dev->mutex);
@@ -338,41 +254,6 @@
 	return (count / (port->nchan / 2));
 }
 
-
-static int
-cmpci_setup_interrupts(cmpci_dev_t *dev)
-{
-	int actual;
-	uint_t ipri;
-
-	if ((ddi_intr_alloc(dev->dip, &dev->ihandle, DDI_INTR_TYPE_FIXED,
-	    0, 1, &actual, DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) ||
-	    (actual != 1)) {
-		audio_dev_warn(dev->adev, "can't alloc intr handle");
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_get_pri(dev->ihandle, &ipri) != DDI_SUCCESS) {
-		audio_dev_warn(dev->adev,  "can't determine intr priority");
-		(void) ddi_intr_free(dev->ihandle);
-		dev->ihandle = NULL;
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_add_handler(dev->ihandle, cmpci_intr, dev,
-	    NULL) != DDI_SUCCESS) {
-		audio_dev_warn(dev->adev, "can't add intr handler");
-		(void) ddi_intr_free(dev->ihandle);
-		dev->ihandle = NULL;
-		return (DDI_FAILURE);
-	}
-
-	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-
-	return (DDI_SUCCESS);
-}
-
-
 #define	MASK(nbits)	((1 << (nbits)) - 1)
 #define	SCALE(val, nbits)	\
 	((uint8_t)((((val) * MASK(nbits)) / 100)) << (8 - (nbits)))
@@ -405,9 +286,6 @@
 	uint64_t	recsrcs;
 	uint64_t	monsrcs;
 
-	if (dev->suspended)
-		return;
-
 	/* reset all mix values */
 	outmix = inmix[0] = inmix[1] = 0;
 
@@ -814,8 +692,8 @@
 	AUDIO_ENGINE_VERSION,		/* version number */
 	cmpci_open,
 	cmpci_close,
-	NULL,		/* start */
-	NULL,		/* stop */
+	cmpci_start,
+	cmpci_stop,
 	cmpci_count,
 	cmpci_format,
 	cmpci_channels,
@@ -831,13 +709,6 @@
 {
 	audio_dev_t	*adev = dev->adev;
 	int		playch;
-	int		intrs;
-
-	dev->pintrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, "play-interrupts", DEFINTS);
-
-	dev->rintrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, "record-interrupts", DEFINTS);
 
 	playch  = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
 	    DDI_PROP_DONTPASS, "channels", dev->maxch);
@@ -877,68 +748,44 @@
 		case 0:
 			caps = ENGINE_INPUT_CAP;
 			dmaflags = DDI_DMA_READ | DDI_DMA_CONSISTENT;
-			port->callb = audio_engine_produce;
 			port->reg_paddr = REG_CH0_PADDR;
 			port->reg_bufsz = REG_CH0_BUFSZ;
 			port->reg_fragsz = REG_CH0_FRAGSZ;
 			port->fc0_rst_bit = FUNCTRL0_CH0_RST;
 			port->fc0_rec_bit = FUNCTRL0_CH0_REC;
 			port->fc0_en_bit = FUNCTRL0_CH0_EN;
-			port->int_en_bit = INTCTRL_CH0_EN;
 			port->sync_dir = DDI_DMA_SYNC_FORKERNEL;
 			port->capture = B_TRUE;
 			port->fc1_rate_mask = FUNCTRL1_ADC_RATE_48K;
 			port->chformat_mask = CHFORMAT_CH0_16ST;
 			port->nchan = 2;
-			intrs = dev->rintrs;
 			break;
 
 		case 1:
 			caps = ENGINE_OUTPUT_CAP;
 			dmaflags = DDI_DMA_WRITE | DDI_DMA_CONSISTENT;
-			port->callb = audio_engine_consume;
 			port->reg_paddr = REG_CH1_PADDR;
 			port->reg_bufsz = REG_CH1_BUFSZ;
 			port->reg_fragsz = REG_CH1_FRAGSZ;
 			port->fc0_rst_bit = FUNCTRL0_CH1_RST;
 			port->fc0_rec_bit = FUNCTRL0_CH1_REC;
 			port->fc0_en_bit = FUNCTRL0_CH1_EN;
-			port->int_en_bit = INTCTRL_CH1_EN;
 			port->sync_dir = DDI_DMA_SYNC_FORDEV;
 			port->capture = B_FALSE;
 			port->fc1_rate_mask = FUNCTRL1_DAC_RATE_48K;
 			port->chformat_mask = CHFORMAT_CH1_16ST;
 			port->nchan = playch;
-			intrs = dev->pintrs;
 			break;
 		}
 
 		/*
-		 * Calculate fragfr, nfrags, buf.
-		 *
-		 * 48 as minimum is chosen to ensure that we will have
-		 * at least 4 fragments.  512 is just an arbitrary
-		 * limit, and at the smallest frame size will result
-		 * in no more than 176 fragments.
-		 */
-		intrs = min(512, max(48, intrs));
-
-		/*
-		 * Two fragments are enough to get ping-pong buffers.
-		 * The hardware could support considerably more than
-		 * this, but it just wastes memory.
-		 */
-		port->nfrags = 2;
-
-		/*
 		 * For efficiency, we'd like to have the fragments
 		 * evenly divisble by 64 bytes.  Since frames are
 		 * already evenly divisble by 4 (16-bit stereo), this
 		 * is adequate.  For a typical configuration (175 Hz
 		 * requested) this will translate to 166 Hz.
 		 */
-		port->fragfr = P2ROUNDUP((48000 / intrs), 16);
-		port->nframes = port->nfrags * port->fragfr;
+		port->nframes = 2048;
 		port->bufsz = port->nframes * port->nchan * 2;
 
 		if (ddi_dma_alloc_handle(dev->dip, &dma_attr, DDI_DMA_DONTWAIT,
@@ -973,13 +820,6 @@
 
 	cmpci_add_controls(dev);
 
-	dev->ksp = kstat_create(ddi_driver_name(dev->dip),
-	    ddi_get_instance(dev->dip), ddi_driver_name(dev->dip),
-	    "controller", KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
-	if (dev->ksp != NULL) {
-		kstat_install(dev->ksp);
-	}
-
 	cmpci_reset(dev);
 	cmpci_configure_mixer(dev);
 
@@ -994,16 +834,7 @@
 void
 cmpci_destroy(cmpci_dev_t *dev)
 {
-	if (dev->ihandle != NULL) {
-		(void) ddi_intr_disable(dev->ihandle);
-		(void) ddi_intr_remove_handler(dev->ihandle);
-		(void) ddi_intr_free(dev->ihandle);
-		mutex_destroy(&dev->mutex);
-	}
-
-	if (dev->ksp != NULL) {
-		kstat_delete(dev->ksp);
-	}
+	mutex_destroy(&dev->mutex);
 
 	/* free up ports, including DMA resources for ports */
 	for (int i = 0; i < PORT_MAX; i++) {
@@ -1069,6 +900,7 @@
 
 	dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
 	dev->dip = dip;
+	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, NULL);
 
 	ddi_set_driver_private(dip, dev);
 
@@ -1130,17 +962,11 @@
 		break;
 	}
 
-	if (cmpci_setup_interrupts(dev) != DDI_SUCCESS) {
-		audio_dev_warn(dev->adev, "can't register interrupts");
-		goto err_exit;
-	}
-
 	if (cmpci_init(dev) != DDI_SUCCESS) {
 		audio_dev_warn(dev->adev, "can't init device");
 		goto err_exit;
 	}
 
-	(void) ddi_intr_enable(dev->ihandle);
 	return (DDI_SUCCESS);
 
 err_exit:
@@ -1151,27 +977,14 @@
 static int
 cmpci_resume(cmpci_dev_t *dev)
 {
-	audio_engine_reset(dev->port[0].engine);
-	audio_engine_reset(dev->port[1].engine);
-
 	mutex_enter(&dev->mutex);
-	dev->suspended = B_FALSE;
-
 	cmpci_reset(dev);
 	/* wait one millisecond, to give reset a chance to get up */
 	drv_usecwait(1000);
-
-	cmpci_configure_mixer(dev);
-
-	for (int i = 0; i < PORT_MAX; i++) {
-		cmpci_port_t *port = &dev->port[i];
+	mutex_exit(&dev->mutex);
 
-		cmpci_reset_port(port);
-		if (port->open) {
-			cmpci_start_port(port);
-		}
-	}
-	mutex_exit(&dev->mutex);
+	audio_dev_resume(dev->adev);
+
 	return (DDI_SUCCESS);
 }
 
@@ -1183,9 +996,6 @@
 
 	mutex_enter(&dev->mutex);
 
-	/* disable interrupts */
-	CLR32(dev, REG_INTCTRL, INTCTRL_CH1_EN | INTCTRL_CH0_EN);
-
 	/* disable channels */
 	PUT32(dev, REG_FUNCTRL0, 0);
 
@@ -1197,23 +1007,6 @@
 }
 
 static int
-cmpci_suspend(cmpci_dev_t *dev)
-{
-	mutex_enter(&dev->mutex);
-
-	cmpci_update_port(&dev->port[0]);
-	cmpci_stop_port(&dev->port[0]);
-
-	cmpci_update_port(&dev->port[1]);
-	cmpci_stop_port(&dev->port[1]);
-
-	dev->suspended = B_TRUE;
-	mutex_exit(&dev->mutex);
-
-	return (DDI_SUCCESS);
-}
-
-static int
 cmpci_quiesce(dev_info_t *dip)
 {
 	cmpci_dev_t	*dev;
@@ -1222,9 +1015,6 @@
 		return (DDI_FAILURE);
 	}
 
-	/* disable interrupts */
-	PUT32(dev, REG_INTCTRL, 0);
-
 	/* disable channels */
 	PUT32(dev, REG_FUNCTRL0, 0);
 
@@ -1265,7 +1055,9 @@
 		return (cmpci_detach(dev));
 
 	case DDI_SUSPEND:
-		return (cmpci_suspend(dev));
+		audio_dev_suspend(dev->adev);
+		return (DDI_SUCCESS);
+
 	default:
 		return (DDI_FAILURE);
 	}
--- a/usr/src/uts/common/io/audio/drv/audiocmi/audiocmi.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiocmi/audiocmi.h	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
@@ -265,8 +265,6 @@
 	ddi_dma_handle_t	dmah;
 	caddr_t			kaddr;
 	uint32_t		paddr;
-	unsigned		fragfr;
-	unsigned		nfrags;
 	unsigned		nframes;
 	unsigned		bufsz;
 	unsigned		nchan;
@@ -311,8 +309,6 @@
 
 	int			maxch;
 
-	boolean_t		suspended;
-
 	kmutex_t		mutex;
 	cmpci_port_t		port[PORT_MAX];
 	cmpci_ctrl_t		controls[CTL_NUM];
@@ -345,8 +341,6 @@
 #define	CLR32(dev, offset, v)	PUT32(dev, offset, GET32(dev, offset) & ~(v))
 #define	SET32(dev, offset, v)	PUT32(dev, offset, GET32(dev, offset) | (v))
 
-#define	KSINTR(dev)	((kstat_intr_t *)((dev)->ksp->ks_data))
-
 #define	BIT(n)		(1U << (n))
 
 #endif	/* _AUDIOCMI_H */
--- a/usr/src/uts/common/io/audio/drv/audioemu10k/audioemu10k.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audioemu10k/audioemu10k.c	Tue Mar 16 09:30:41 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -109,9 +109,6 @@
 static uint8_t side_routing[MAX_SENDS] = {
 	SEND_SIDEL, SEND_SIDER, 0x3f, 0x3f
 };
-static uint8_t no_routing[MAX_SENDS] = {
-	0x3f, 0x3f, 0x3f, 0x3f
-};
 
 /*
  * SB Live! cannot do DMA above 2G addresses. Audigy/2/4 have special 8k page
@@ -142,7 +139,7 @@
 static int emu10k_detach(emu10k_devc_t *);
 static int emu10k_suspend(emu10k_devc_t *);
 
-static int emu10k_open(void *, int, unsigned *, unsigned *, caddr_t *);
+static int emu10k_open(void *, int, unsigned *, caddr_t *);
 static void emu10k_close(void *);
 static int emu10k_start(void *);
 static void emu10k_stop(void *);
@@ -157,9 +154,7 @@
 static void emu10k_write_ac97(void *, uint8_t, uint16_t);
 static int emu10k_alloc_port(emu10k_devc_t *, int);
 static void emu10k_destroy(emu10k_devc_t *);
-static int emu10k_setup_intrs(emu10k_devc_t *);
 static int emu10k_hwinit(emu10k_devc_t *);
-static uint_t emu10k_intr(caddr_t, caddr_t);
 static void emu10k_init_effects(emu10k_devc_t *);
 
 static audio_engine_ops_t emu10k_engine_ops = {
@@ -290,58 +285,6 @@
 	emu10k_write_reg(devc, reg, 0, value);
 }
 
-static uint_t
-emu10k_intr(caddr_t argp, caddr_t nocare)
-{
-	emu10k_devc_t *devc = (void *) argp;
-	emu10k_portc_t *portc;
-	uint32_t status;
-	audio_engine_t *cons = NULL, *prod = NULL;
-
-
-	_NOTE(ARGUNUSED (nocare));
-
-	mutex_enter(&devc->mutex);
-	if (devc->suspended) {
-		mutex_exit(&devc->mutex);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	status = INL(devc, devc->regs + INTPEND);
-
-	if (status == 0) {
-		mutex_exit(&devc->mutex);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	if (status & INT_CL) {	/* channel loop */
-		emu10k_write_reg(devc, CLIPL, 0, (1U << 8));
-		OUTL(devc, INT_CL, devc->regs + INTPEND);
-		portc = devc->portc[EMU10K_PLAY];
-		if (portc->active) {
-			cons = portc->engine;
-		}
-	}
-	if (status & (INT_AF|INT_AH|INT_MF|INT_MH)) {	/* ADC interrupt */
-		OUTL(devc, INT_AF|INT_AH|INT_MF|INT_MH, devc->regs + INTPEND);
-		portc = devc->portc[EMU10K_REC];
-		if (portc->active) {
-			prod = portc->engine;
-		}
-	}
-
-	mutex_exit(&devc->mutex);
-
-	if (cons) {
-		audio_engine_consume(cons);
-	}
-	if (prod) {
-		audio_engine_produce(prod);
-	}
-
-	return (DDI_INTR_CLAIMED);
-}
-
 /*
  * Audio routines
  */
@@ -443,68 +386,19 @@
 	emu10k_write_reg(devc, PEFE_PITCHAMOUNT, voice, 0x00);
 }
 
-static void
-emu10k_setup_silence(emu10k_portc_t *portc, int voice)
-{
-	emu10k_devc_t *devc = portc->devc;
-
-	emu10k_write_reg(devc, VEDS, voice, 0x0);	/* OFF */
-	emu10k_write_reg(devc, VTFT, voice, 0xffff);
-	emu10k_write_reg(devc, CVCF, voice, 0xffff);
-
-	/* set stereo */
-	emu10k_write_reg(devc, CPF, voice, 0x8000);
-
-	/* SDL, ST, CA */
-	emu10k_write_reg(devc, SDL, voice, portc->fragfr);
-	emu10k_write_reg(devc, SCSA, voice, 0);
-	emu10k_write_reg(devc, PTAB, voice, 0);
-	emu10k_write_reg(devc, QKBCA, voice, 0);
-
-	emu10k_write_reg(devc, Z1, voice, 0);
-	emu10k_write_reg(devc, Z2, voice, 0);
-
-	/* This is really a physical address */
-	emu10k_write_reg(devc, MAPA, voice,
-	    0x1fff | (devc->silence_paddr << 1));
-	emu10k_write_reg(devc, MAPB, voice,
-	    0x1fff | (devc->silence_paddr << 1));
-
-	emu10k_write_reg(devc, VTFT, voice, 0x0000ffff);
-	emu10k_write_reg(devc, CVCF, voice, 0x0000ffff);
-	emu10k_write_reg(devc, MEHA, voice, 0);
-	emu10k_write_reg(devc, MEDS, voice, 0x7f);
-	emu10k_write_reg(devc, MLV, voice, 0x8000);
-	emu10k_write_reg(devc, VLV, voice, 0x8000);
-	emu10k_write_reg(devc, VFM, voice, 0);
-	emu10k_write_reg(devc, TMFQ, voice, 0);
-	emu10k_write_reg(devc, VVFQ, voice, 0);
-	emu10k_write_reg(devc, MEV, voice, 0x8000);
-	emu10k_write_reg(devc, VEHA, voice, 0x7f7f);	/* OK */
-	/* No volume envelope delay (OK) */
-	emu10k_write_reg(devc, VEV, voice, 0x8000);
-	emu10k_write_reg(devc, PEFE_FILTERAMOUNT, voice, 0x7f);
-	emu10k_write_reg(devc, PEFE_PITCHAMOUNT, voice, 0x00);
-}
-
 int
-emu10k_open(void *arg, int flag,
-    unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp)
+emu10k_open(void *arg, int flag, unsigned *nframes, caddr_t *bufp)
 {
 	emu10k_portc_t *portc = arg;
 	emu10k_devc_t *devc = portc->devc;
 
 	_NOTE(ARGUNUSED(flag));
 
-	portc->started = B_FALSE;
 	portc->active = B_FALSE;
-	*fragfrp = portc->fragfr;
-	*nfragsp = portc->nfrags;
+	*nframes = portc->nframes;
 	*bufp = portc->buf_kaddr;
 
 	mutex_enter(&devc->mutex);
-	if (!devc->suspended)
-		portc->reset_port(portc);
 	portc->count = 0;
 	mutex_exit(&devc->mutex);
 
@@ -514,14 +408,7 @@
 void
 emu10k_close(void *arg)
 {
-	emu10k_portc_t *portc = arg;
-	emu10k_devc_t *devc = portc->devc;
-
-	mutex_enter(&devc->mutex);
-	if (!devc->suspended)
-		portc->stop_port(portc);
-	portc->started = B_FALSE;
-	mutex_exit(&devc->mutex);
+	_NOTE(ARGUNUSED(arg));
 }
 
 int
@@ -531,11 +418,8 @@
 	emu10k_devc_t *devc = portc->devc;
 
 	mutex_enter(&devc->mutex);
-	if (!portc->started) {
-		if (!devc->suspended)
-			portc->start_port(portc);
-		portc->started = B_TRUE;
-	}
+	portc->reset_port(portc);
+	portc->start_port(portc);
 	mutex_exit(&devc->mutex);
 	return (0);
 }
@@ -547,11 +431,7 @@
 	emu10k_devc_t *devc = portc->devc;
 
 	mutex_enter(&devc->mutex);
-	if (portc->started) {
-		if (!devc->suspended)
-			portc->stop_port(portc);
-		portc->started = B_FALSE;
-	}
+	portc->stop_port(portc);
 	mutex_exit(&devc->mutex);
 }
 
@@ -596,8 +476,7 @@
 	uint64_t count;
 
 	mutex_enter(&devc->mutex);
-	if (!devc->suspended)
-		portc->update_port(portc);
+	portc->update_port(portc);
 	count = portc->count;
 	mutex_exit(&devc->mutex);
 
@@ -804,17 +683,6 @@
 	emu10k_prepare_voice(devc, 6);
 	emu10k_prepare_voice(devc, 7);
 
-	emu10k_prepare_voice(devc, 8);
-	emu10k_prepare_voice(devc, 9);
-
-	/* arrange to receive full loop interrupts on channel 8 */
-	emu10k_write_reg(devc, CLIEL, 0, (1U << 8));
-
-	/* initialize our position counter... */
-	portc->pos =
-	    (emu10k_read_reg(devc, QKBCA, 0) & 0xffffff) -
-	    (portc->memptr >> 2);
-
 	/* Trigger playback on all voices */
 	emu10k_write_reg(devc, VEDS, 0, 0x7f7f);
 	emu10k_write_reg(devc, VEDS, 1, 0x7f7f);
@@ -824,8 +692,6 @@
 	emu10k_write_reg(devc, VEDS, 5, 0x7f7f);
 	emu10k_write_reg(devc, VEDS, 6, 0x7f7f);
 	emu10k_write_reg(devc, VEDS, 7, 0x7f7f);
-	emu10k_write_reg(devc, VEDS, 8, 0x7f7f);
-	emu10k_write_reg(devc, VEDS, 9, 0x7f7f);
 
 	portc->active = B_TRUE;
 }
@@ -843,8 +709,6 @@
 	emu10k_stop_voice(devc, 5);
 	emu10k_stop_voice(devc, 6);
 	emu10k_stop_voice(devc, 7);
-	emu10k_stop_voice(devc, 8);
-	emu10k_stop_voice(devc, 9);
 
 	portc->active = B_FALSE;
 }
@@ -870,16 +734,7 @@
 		emu10k_reset_pair(portc, 0, front_routing, 0);
 		emu10k_reset_pair(portc, 2, surr_routing, offs);
 	}
-	emu10k_setup_silence(portc, 8);
-	emu10k_setup_silence(portc, 9);
 
-	/*
-	 * This way we can use voices 8 and 9 for timing, we have
-	 * programmed them to be just the size of a single fragment,
-	 * that way when they loop we get a clean interrupt.
-	 */
-	emu10k_write_routing(devc, 8, no_routing);
-	emu10k_write_routing(devc, 9, no_routing);
 	portc->pos = 0;
 }
 
@@ -896,13 +751,23 @@
 	 */
 	pos = emu10k_read_reg(devc, QKBCA, 0) & 0xffffff;
 	pos -= (portc->memptr >> 2);
+	if (pos > portc->nframes) {
+		/*
+		 * This should never happen!  If it happens, we should
+		 * throw an FMA fault.  (When we support FMA.)  For now
+		 * we just assume the device is stuck, and report no
+		 * change in position.
+		 */
+		pos = portc->pos;
+	}
+	ASSERT(pos <= portc->nframes);
 
-	if (pos <= portc->pos) {
-		cnt = portc->nframes - portc->pos;
-		cnt += pos;
+	if (pos < portc->pos) {
+		cnt = (portc->nframes - portc->pos) + pos;
 	} else {
 		cnt = (pos - portc->pos);
 	}
+	ASSERT(cnt <= portc->nframes);
 	if (portc->dopos) {
 		emu10k_vars[0] = portc->pos;
 		emu10k_vars[1] = pos;
@@ -910,11 +775,6 @@
 		emu10k_vars[3] = cnt;
 		portc->dopos = 0;
 	}
-	if (cnt > portc->nframes) {
-		printf("Got bogus count %u\n", cnt);
-		cnt = portc->fragfr;
-	}
-	ASSERT(cnt <= portc->nframes);
 	portc->count += cnt;
 	portc->pos = pos;
 }
@@ -925,10 +785,6 @@
 	emu10k_devc_t *devc = portc->devc;
 	uint32_t tmp;
 
-	/* Intr enable */
-	OUTL(devc, INL(devc, devc->regs + IE) | IE_MB | IE_AB,
-	    devc->regs + IE);
-
 	tmp = 0;			/* setup 48Kz */
 	if (devc->feature_mask & (SB_AUDIGY|SB_AUDIGY2|SB_AUDIGY2VAL))
 		tmp |= 0x30;		/* Left/right channel enable */
@@ -976,8 +832,6 @@
 	emu10k_write_reg(devc, ADCBS, 0, sz);
 	emu10k_write_reg(devc, ADCSR, 0, 0);	/* reset for phase */
 	portc->pos = 0;
-	OUTL(devc, INL(devc, devc->regs + IE) & ~(IE_MB | IE_AB),
-	    devc->regs + IE);
 }
 
 void
@@ -1015,7 +869,6 @@
 	portc = kmem_zalloc(sizeof (*portc), KM_SLEEP);
 	devc->portc[num] = portc;
 	portc->devc = devc;
-	portc->started = B_FALSE;
 
 	portc->memptr = devc->audio_memptr;
 	devc->audio_memptr += (DMABUF_SIZE + 4095) & ~4095;
@@ -1032,9 +885,7 @@
 		portc->update_port = emu10k_update_rec;
 		/* This is the minimum record buffer size. */
 		portc->buf_size = 4096;
-		portc->nfrags = 2;
-		portc->nframes = 4096 / 4;
-		portc->fragfr = portc->nframes / portc->nfrags;
+		portc->nframes = portc->buf_size / 4;
 		break;
 	case EMU10K_PLAY:
 		portc->syncdir = DDI_DMA_SYNC_FORDEV;
@@ -1045,10 +896,8 @@
 		portc->stop_port = emu10k_stop_play;
 		portc->reset_port = emu10k_reset_play;
 		portc->update_port = emu10k_update_play;
-		/* XXX: this could probably be tunable */
-		portc->nfrags = 2;
-		portc->fragfr = 288;
-		portc->nframes = portc->nfrags * portc->fragfr;
+		/* This could probably be tunable. */
+		portc->nframes = 2048;
 		portc->buf_size = portc->nframes * portc->channels * 2;
 		break;
 	default:
@@ -1122,54 +971,10 @@
 	return (DDI_SUCCESS);
 }
 
-int
-emu10k_setup_intrs(emu10k_devc_t *devc)
-{
-	uint_t ipri;
-	int actual;
-	int rv;
-	ddi_intr_handle_t ih[1];
-
-	rv = ddi_intr_alloc(devc->dip, ih, DDI_INTR_TYPE_FIXED,
-	    0, 1, &actual, DDI_INTR_ALLOC_STRICT);
-	if ((rv != DDI_SUCCESS) || (actual != 1)) {
-		audio_dev_warn(devc->adev,
-		    "Can't alloc interrupt handle (rv %d actual %d)",
-		    rv, actual);
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_get_pri(ih[0], &ipri) != DDI_SUCCESS) {
-		audio_dev_warn(devc->adev, "Can't get interrupt priority");
-		(void) ddi_intr_free(ih[0]);
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_add_handler(ih[0], emu10k_intr, devc, NULL) !=
-	    DDI_SUCCESS) {
-		audio_dev_warn(devc->adev, "Can't add interrupt handler");
-		(void) ddi_intr_free(ih[0]);
-		return (DDI_FAILURE);
-	}
-
-	devc->ih = ih[0];
-	mutex_init(&devc->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-	return (DDI_SUCCESS);
-}
-
 void
 emu10k_destroy(emu10k_devc_t *devc)
 {
-	if (devc->ih != NULL) {
-		(void) ddi_intr_disable(devc->ih);
-		(void) ddi_intr_remove_handler(devc->ih);
-		(void) ddi_intr_free(devc->ih);
-		mutex_destroy(&devc->mutex);
-	}
-
-	if (devc->ksp) {
-		kstat_delete(devc->ksp);
-	}
+	mutex_destroy(&devc->mutex);
 
 	if (devc->silence_paddr) {
 		(void) ddi_dma_unbind_handle(devc->silence_dmah);
@@ -1282,38 +1087,6 @@
 	}
 }
 
-static void
-emu10k_refresh_mixer(emu10k_devc_t *devc)
-{
-	uint32_t val;
-	uint32_t set;
-
-	for (int gpr = 0; gpr < MAX_GPR; gpr++) {
-		if (devc->gpr_shadow[gpr].valid) {
-			emu10k_write_reg(devc, gpr + GPR0, 0,
-			    devc->gpr_shadow[gpr].value);
-		}
-	}
-
-	set = devc->ctrls[CTL_JACK3].val;
-	if (devc->feature_mask & SB_INVSP) {
-		set = !set;
-	}
-
-	if (devc->feature_mask & (SB_AUDIGY|SB_AUDIGY2|SB_AUDIGY2VAL)) {
-		val = INL(devc, devc->regs + 0x18);
-		val &= ~A_IOCFG_GPOUT0;
-		val |= set ? 0x44 : 0x40;
-		OUTL(devc, val, devc->regs + 0x18);
-
-	} else if (devc->feature_mask & SB_LIVE) {
-		val = INL(devc, devc->regs + HCFG);
-		val &= ~HCFG_GPOUT0;
-		val |= set ? HCFG_GPOUT0 : 0;
-		OUTL(devc, val, devc->regs + HCFG);
-	}
-}
-
 int
 emu10k_hwinit(emu10k_devc_t *devc)
 {
@@ -1337,6 +1110,7 @@
 	emu10k_write_reg(devc, ADCBS, 0, 0x0);
 	emu10k_write_reg(devc, ADCBA, 0, 0x0);
 
+	/* Ensure all interrupts are disabled */
 	OUTL(devc, 0, devc->regs + IE);
 	emu10k_write_reg(devc, CLIEL, 0, 0x0);
 	emu10k_write_reg(devc, CLIEH, 0, 0x0);
@@ -1550,9 +1324,7 @@
 	ASSERT(gpr < MAX_GPR);
 	devc->gpr_shadow[gpr].valid = B_TRUE;
 	devc->gpr_shadow[gpr].value = value;
-	if (!devc->suspended) {
-		emu10k_write_reg(devc, gpr + GPR0, 0, value);
-	}
+	emu10k_write_reg(devc, gpr + GPR0, 0, value);
 }
 
 static int
@@ -1659,19 +1431,17 @@
 	if (devc->feature_mask & SB_INVSP) {
 		set_val = !set_val;
 	}
-	if (!devc->suspended) {
-		if (devc->feature_mask & (SB_AUDIGY|SB_AUDIGY2|SB_AUDIGY2VAL)) {
-			val = INL(devc, devc->regs + 0x18);
-			val &= ~A_IOCFG_GPOUT0;
-			val |= set_val ? 0x44 : 0x40;
-			OUTL(devc, val, devc->regs + 0x18);
+	if (devc->feature_mask & (SB_AUDIGY|SB_AUDIGY2|SB_AUDIGY2VAL)) {
+		val = INL(devc, devc->regs + 0x18);
+		val &= ~A_IOCFG_GPOUT0;
+		val |= set_val ? 0x44 : 0x40;
+		OUTL(devc, val, devc->regs + 0x18);
 
-		} else if (devc->feature_mask & SB_LIVE) {
-			val = INL(devc, devc->regs + HCFG);
-			val &= ~HCFG_GPOUT0;
-			val |= set_val ? HCFG_GPOUT0 : 0;
-			OUTL(devc, val, devc->regs + HCFG);
-		}
+	} else if (devc->feature_mask & SB_LIVE) {
+		val = INL(devc, devc->regs + HCFG);
+		val &= ~HCFG_GPOUT0;
+		val |= set_val ? HCFG_GPOUT0 : 0;
+		OUTL(devc, val, devc->regs + HCFG);
 	}
 	mutex_exit(&devc->mutex);
 	return (0);
@@ -2240,8 +2010,7 @@
 	audio_dev_set_description(devc->adev, namebuf);
 	audio_dev_set_version(devc->adev, model);
 
-	if (emu10k_setup_intrs(devc) != DDI_SUCCESS)
-		goto error;
+	mutex_init(&devc->mutex, NULL, MUTEX_DRIVER, 0);
 
 	/* allocate static page table memory */
 
@@ -2260,7 +2029,7 @@
 	    &devc->pt_dmah) != DDI_SUCCESS) {
 		audio_dev_warn(devc->adev,
 		    "failed to allocate page table handle");
-		return (DDI_FAILURE);
+		goto error;
 	}
 
 	if (ddi_dma_mem_alloc(devc->pt_dmah, devc->max_pages * 4,
@@ -2269,7 +2038,7 @@
 	    DDI_SUCCESS) {
 		audio_dev_warn(devc->adev,
 		    "failed to allocate memory for page table");
-		return (DDI_FAILURE);
+		goto error;
 	}
 
 	if (ddi_dma_addr_bind_handle(devc->pt_dmah, NULL,
@@ -2277,7 +2046,7 @@
 	    DDI_DMA_SLEEP, NULL, &cookie, &count) != DDI_SUCCESS) {
 		audio_dev_warn(devc->adev,
 		    "failed binding page table DMA handle");
-		return (DDI_FAILURE);
+		goto error;
 	}
 
 	devc->page_map = (void *)devc->pt_kaddr;
@@ -2289,7 +2058,7 @@
 	    &devc->silence_dmah) != DDI_SUCCESS) {
 		audio_dev_warn(devc->adev,
 		    "failed to allocate silent page handle");
-		return (DDI_FAILURE);
+		goto error;
 	}
 
 	if (ddi_dma_mem_alloc(devc->silence_dmah, 4096,
@@ -2298,7 +2067,7 @@
 	    &devc->silence_acch) != DDI_SUCCESS) {
 		audio_dev_warn(devc->adev,
 		    "failed to allocate silent page memory");
-		return (DDI_FAILURE);
+		goto error;
 	}
 
 	(void) ddi_dma_sync(devc->silence_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
@@ -2308,7 +2077,7 @@
 	    DDI_DMA_SLEEP, NULL, &cookie, &count) != DDI_SUCCESS) {
 		audio_dev_warn(devc->adev,
 		    "failed binding silent page DMA handle");
-		return (DDI_FAILURE);
+		goto error;
 	}
 
 	devc->silence_paddr = cookie.dmac_address;
@@ -2346,19 +2115,11 @@
 
 	emu10k_create_controls(devc);
 
-	/* set up kernel statistics */
-	if ((devc->ksp = kstat_create(EMU10K_NAME, ddi_get_instance(dip),
-	    EMU10K_NAME, "controller", KSTAT_TYPE_INTR,
-	    1, KSTAT_FLAG_PERSISTENT)) != NULL) {
-		kstat_install(devc->ksp);
-	}
-
 	if (audio_dev_register(devc->adev) != DDI_SUCCESS) {
 		audio_dev_warn(devc->adev, "unable to register audio device");
 		goto error;
 	}
 
-	(void) ddi_intr_enable(devc->ih);
 	ddi_report_dev(dip);
 
 	return (DDI_SUCCESS);
@@ -2372,15 +2133,9 @@
 emu10k_resume(dev_info_t *dip)
 {
 	emu10k_devc_t *devc;
-	emu10k_portc_t *portc;
 
 	devc = ddi_get_driver_private(dip);
 
-	for (int i = 0; i < EMU10K_NUM_PORTC; i++) {
-		portc = devc->portc[i];
-		audio_engine_reset(portc->engine);
-	}
-
 	mutex_enter(&devc->mutex);
 	if (emu10k_hwinit(devc) != DDI_SUCCESS) {
 		mutex_exit(&devc->mutex);
@@ -2393,27 +2148,12 @@
 		return (DDI_SUCCESS);
 	}
 
-	emu10k_refresh_mixer(devc);
-
-	devc->suspended = B_FALSE;
-
-	for (int i = 0; i < EMU10K_NUM_PORTC; i++) {
-
-		portc = devc->portc[i];
-
-		portc->stop_port(portc);
-
-		portc->dopos = 1;
-		if (portc->started) {
-			portc->reset_port(portc);
-			portc->start_port(portc);
-		}
-	}
-
 	mutex_exit(&devc->mutex);
 
 	/* resume ac97 */
-	ac97_resume(devc->ac97);
+	ac97_reset(devc->ac97);
+
+	audio_dev_resume(devc->adev);
 
 	return (DDI_SUCCESS);
 }
@@ -2431,50 +2171,7 @@
 int
 emu10k_suspend(emu10k_devc_t *devc)
 {
-	ac97_suspend(devc->ac97);
-
-	mutex_enter(&devc->mutex);
-
-	devc->suspended = B_TRUE;
-
-	emu10k_write_reg(devc, CLIEL, 0, 0);
-	emu10k_write_reg(devc, CLIEH, 0, 0);
-	if (!(devc->feature_mask & SB_LIVE)) {
-		emu10k_write_reg(devc, HLIEL, 0, 0x0);
-		emu10k_write_reg(devc, HLIEH, 0, 0x0);
-	}
-	OUTL(devc, 0, devc->regs + IE);	/* Intr enable (all off) */
-
-	for (int i = 0; i < EMU10K_NUM_PORTC; i++) {
-		emu10k_portc_t *portc = devc->portc[i];
-		portc->stop_port(portc);
-	}
-
-	/* stop all voices */
-	for (int i = 0; i < 64; i++) {
-		emu10k_write_reg(devc, VEDS, i, 0);
-	}
-	for (int i = 0; i < 64; i++) {
-		emu10k_write_reg(devc, VTFT, i, 0);
-		emu10k_write_reg(devc, CVCF, i, 0);
-		emu10k_write_reg(devc, PTAB, i, 0);
-		emu10k_write_reg(devc, CPF, i, 0);
-	}
-	/*
-	 * Turn off the hardware
-	 */
-	OUTL(devc,
-	    HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK |
-	    HCFG_MUTEBUTTONENABLE, devc->regs + HCFG);
-
-	/* stop ADC recording */
-	emu10k_write_reg(devc, ADCSR, 0, 0x0);
-	emu10k_write_reg(devc, ADCBA, 0, 0x0);
-	emu10k_write_reg(devc, ADCBA, 0, 0x0);
-
-	emu10k_write_reg(devc, PTBA, 0, 0);
-
-	mutex_exit(&devc->mutex);
+	audio_dev_suspend(devc->adev);
 
 	return (DDI_SUCCESS);
 }
@@ -2593,7 +2290,6 @@
 	/*
 	 * Turn off the hardware
 	 */
-	OUTL(devc, 0, devc->regs + IE);	/* Intr enable (all off) */
 	OUTL(devc,
 	    HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK |
 	    HCFG_MUTEBUTTONENABLE, devc->regs + HCFG);
--- a/usr/src/uts/common/io/audio/drv/audioemu10k/audioemu10k.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audioemu10k/audioemu10k.h	Tue Mar 16 09:30:41 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -362,7 +362,6 @@
 
 	boolean_t		started;
 	boolean_t		active;
-	unsigned		fragfr;
 	unsigned		nframes;
 	unsigned		nfrags;
 	unsigned		fragsz;
@@ -384,13 +383,10 @@
 struct _emu10k_devc_t {
 	dev_info_t		*dip;
 	audio_dev_t		*adev;
-	kstat_t			*ksp;
-	boolean_t		suspended;
 	ddi_acc_handle_t	pcih;
 	ddi_acc_handle_t	regsh;
 	caddr_t			regs;
 	kmutex_t		mutex;
-	ddi_intr_handle_t	ih;
 
 	/*
 	 * Page table
@@ -446,8 +442,6 @@
 #define	INL(devc, reg)		ddi_get32(devc->regsh, (void *)(reg))
 #define	OUTL(devc, val, reg)	ddi_put32(devc->regsh, (void *)(reg), (val))
 
-#define	EMU10K_KIOP(X)	((kstat_intr_t *)(X->ksp->ks_data))
-
 #endif	/* _KERNEL */
 
 #endif /* EMU10K_H */
--- a/usr/src/uts/common/io/audio/drv/audioens/audioens.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audioens/audioens.c	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
@@ -47,12 +47,6 @@
 #include "audioens.h"
 
 /*
- * The original OSS driver used a single duplex engine and a separate
- * playback only engine.  Instead, we expose three engines, one for input
- * and two for output.
- */
-
-/*
  * Set the latency to 32, 64, 96, 128 clocks - some APCI97 devices exhibit
  * garbled audio in some cases and setting the latency to higer values fixes it
  * Values: 32, 64, 96, 128 - Default: 64 (or defined by bios)
@@ -84,15 +78,11 @@
 #define	ECTIVA_ES1938		0x8938
 
 #define	DEFRATE			48000
-#define	DEFINTS			75
 #define	DRVNAME			"audioens"
 
 typedef struct audioens_port
 {
 	/* Audio parameters */
-	boolean_t		trigger;
-	boolean_t		suspended;
-
 	int			speed;
 
 	int			num;
@@ -105,8 +95,6 @@
 	ddi_acc_handle_t	acch;
 	ddi_dma_handle_t	dmah;
 	int			nchan;
-	unsigned		fragfr;
-	unsigned		nfrags;
 	unsigned		nframes;
 	unsigned		frameno;
 	uint64_t		count;
@@ -122,13 +110,6 @@
 	uint16_t		devid;
 	uint8_t			revision;
 	dev_info_t		*dip;
-	boolean_t		enabled;
-
-
-	int			pintrs;
-	int			rintrs;
-
-	kstat_t			*ksp;
 
 	audioens_port_t		port[PORT_MAX + 1];
 
@@ -136,7 +117,6 @@
 
 	caddr_t			regs;
 	ddi_acc_handle_t	acch;
-	ddi_intr_handle_t	ihandle[1];
 } audioens_dev_t;
 
 static ddi_device_acc_attr_t acc_attr = {
@@ -153,15 +133,9 @@
 
 /*
  * The hardware appears to be able to address up to 16-bits worth of longwords,
- * giving a total address space of 256K.  Note, however, that we will restrict
- * this further when we do fragment and memory allocation.  At its very highest
- * clock rate (48 kHz) and sample size (16-bit stereo), and lowest interrupt
- * rate (32 Hz), we only need 6000 bytes per fragment.
- *
- * So with an allocated buffer size of 64K, we can support at least 10 frags,
- * which is more than enough.  (The legacy Sun driver used only 2 fragments.)
+ * giving a total address space of 256K.  But we need substantially less.
  */
-#define	AUDIOENS_BUF_LEN	(65536)
+#define	AUDIOENS_BUF_LEN	(16384)
 
 static ddi_dma_attr_t dma_attr = {
 	DMA_ATTR_VERSION,	/* dma_attr_version */
@@ -196,13 +170,7 @@
 #define	CLR32(dev, offset, v)	PUT32(dev, offset, GET32(dev, offset) & ~(v))
 #define	SET32(dev, offset, v)	PUT32(dev, offset, GET32(dev, offset) | (v))
 
-#define	KSINTR(dev)	((kstat_intr_t *)((dev)->ksp->ks_data))
-
 static void audioens_init_hw(audioens_dev_t *);
-static void audioens_init_port(audioens_port_t *);
-static void audioens_start_port(audioens_port_t *);
-static void audioens_stop_port(audioens_port_t *);
-static void audioens_update_port(audioens_port_t *);
 
 static uint16_t
 audioens_rd97(void *dev_, uint8_t wAddr)
@@ -422,105 +390,6 @@
 	return (GET32(dev, offs));
 }
 
-static uint_t
-audioens_intr(caddr_t arg1, caddr_t arg2)
-{
-	audioens_dev_t *dev = (void *)arg1;
-	int stats;
-	int tmp;
-	unsigned char ackbits = 0;
-	audioens_port_t *port;
-	audio_engine_t *do_dac, *do_adc;
-
-	_NOTE(ARGUNUSED(arg2));
-
-	/*
-	 * NB: The old audioens didn't report spurious interrupts.  On
-	 * a system with shared interrupts (typical!) there will
-	 * normally be lots of these (each time the "other" device
-	 * interrupts).
-	 *
-	 * Also, because of the way the interrupt chain handling
-	 * works, reporting of spurious interrupts is probably not
-	 * terribly useful.
-	 *
-	 * However, we can count interrupts where the master interrupt
-	 * bit is set but none of the ackbits that we are prepared to
-	 * process is set.  That is probably useful.
-	 */
-	mutex_enter(&dev->mutex);
-	if (!dev->enabled) {
-
-		mutex_exit(&dev->mutex);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	stats = GET32(dev, CONC_dSTATUS_OFF);
-
-	if (!(stats & CONC_STATUS_PENDING)) {	/* No interrupt pending */
-		mutex_exit(&dev->mutex);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	do_dac = do_adc = NULL;
-
-	/* DAC1 (synth) interrupt */
-	if (stats & CONC_STATUS_DAC1INT) {
-
-		ackbits |= CONC_SERCTL_DAC1IE;
-		port = &dev->port[PORT_DAC];
-		if (port->trigger) {
-			do_dac = port->engine;
-		}
-	}
-
-	/* DAC2 interrupt */
-	if (stats & CONC_STATUS_DAC2INT) {
-
-		ackbits |= CONC_SERCTL_DAC2IE;
-	}
-
-	/* ADC interrupt */
-	if (stats & CONC_STATUS_ADCINT) {
-
-		ackbits |= CONC_SERCTL_ADCIE;
-		port = &dev->port[PORT_ADC];
-
-		if (port->trigger) {
-			do_adc = port->engine;
-		}
-	}
-
-	/* UART interrupt - we shouldn't get this! */
-	if (stats & CONC_STATUS_UARTINT) {
-		uint8_t uart_stat = GET8(dev, CONC_bUARTCSTAT_OFF);
-		while (uart_stat & CONC_UART_RXRDY)
-			uart_stat = GET8(dev, CONC_bUARTCSTAT_OFF);
-	}
-
-	/* Ack the interrupt */
-	tmp = GET8(dev, CONC_bSERCTL_OFF);
-	PUT8(dev, CONC_bSERCTL_OFF, tmp & (~ackbits));	/* Clear bits */
-	PUT8(dev, CONC_bSERCTL_OFF, tmp | ackbits);	/* Turn them back on */
-
-	if (dev->ksp) {
-		if (ackbits == 0) {
-			KSINTR(dev)->intrs[KSTAT_INTR_SPURIOUS]++;
-		} else {
-			KSINTR(dev)->intrs[KSTAT_INTR_HARD]++;
-		}
-	}
-
-	mutex_exit(&dev->mutex);
-
-	if (do_dac)
-		audio_engine_consume(do_dac);
-	if (do_adc)
-		audio_engine_produce(do_adc);
-
-	return (DDI_INTR_CLAIMED);
-}
-
 /*
  * Audio routines
  */
@@ -549,14 +418,34 @@
 	return (port->speed);
 }
 
-static void
-audioens_init_port(audioens_port_t *port)
+static int
+audioens_open(void *arg, int flag, unsigned *nframes, caddr_t *bufp)
 {
+	audioens_port_t	*port = arg;
 	audioens_dev_t	*dev = port->dev;
-	unsigned tmp;
+
+	_NOTE(ARGUNUSED(flag));
+
+	mutex_enter(&dev->mutex);
+
+	port->nframes = AUDIOENS_BUF_LEN / (port->nchan * sizeof (int16_t));
+	port->count = 0;
+
+	*nframes = port->nframes;
+	*bufp = port->kaddr;
+	mutex_exit(&dev->mutex);
 
-	if (port->suspended)
-		return;
+	return (0);
+}
+
+static int
+audioens_start(void *arg)
+{
+	audioens_port_t *port = arg;
+	audioens_dev_t *dev = port->dev;
+	uint32_t tmp;
+
+	mutex_enter(&dev->mutex);
 
 	switch (port->num) {
 	case PORT_DAC:
@@ -589,8 +478,12 @@
 		    port->nframes - 1);
 
 		/* Set # of frames between interrupts */
-		PUT16(dev, CONC_wDAC1IC_OFF, port->fragfr - 1);
-		PUT16(dev, CONC_wDAC2IC_OFF, port->fragfr - 1);
+		PUT16(dev, CONC_wDAC1IC_OFF, port->nframes - 1);
+		PUT16(dev, CONC_wDAC2IC_OFF, port->nframes - 1);
+
+		SET8(dev, CONC_bDEVCTL_OFF,
+		    CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_DAC1_EN);
+
 		break;
 
 	case PORT_ADC:
@@ -615,104 +508,13 @@
 		    port->nframes - 1);
 
 		/* Set # of frames between interrupts */
-		PUT16(dev, CONC_wADCIC_OFF, port->fragfr - 1);
+		PUT16(dev, CONC_wADCIC_OFF, port->nframes - 1);
 
+		SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
 		break;
 	}
 
 	port->frameno = 0;
-}
-
-static int
-audioens_open(void *arg, int flag, unsigned *fragfrp, unsigned *nfragsp,
-    caddr_t *bufp)
-{
-	audioens_port_t	*port = arg;
-	audioens_dev_t	*dev = port->dev;
-	int intrs;
-
-	_NOTE(ARGUNUSED(flag));
-
-	mutex_enter(&dev->mutex);
-
-	if (port->num == PORT_ADC) {
-		intrs = dev->rintrs;
-	} else {
-		intrs = dev->pintrs;
-	}
-
-	/* interrupt at least at 25 Hz, and not more than 250 Hz */
-	intrs = min(250, max(25, intrs));
-
-	port->fragfr = (port->speed / intrs);
-	port->nfrags = AUDIOENS_BUF_LEN /
-	    (port->fragfr * port->nchan * sizeof (int16_t));
-	port->nfrags = max(4, min(port->nfrags, 1024));
-	port->nframes = port->nfrags * port->fragfr;
-	port->trigger = B_FALSE;
-	port->count = 0;
-
-	audioens_init_port(port);
-
-	*fragfrp = port->fragfr;
-	*nfragsp = port->nfrags;
-	*bufp = port->kaddr;
-	mutex_exit(&dev->mutex);
-
-	return (0);
-}
-
-static void
-audioens_start_port(audioens_port_t *port)
-{
-	audioens_dev_t *dev = port->dev;
-
-	if (!port->suspended) {
-		switch (port->num) {
-		case PORT_DAC:
-			SET8(dev, CONC_bDEVCTL_OFF,
-			    CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_DAC1_EN);
-			SET8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_DAC1IE);
-			break;
-		case PORT_ADC:
-			SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
-			SET8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_ADCIE);
-			break;
-		}
-	}
-}
-
-static void
-audioens_stop_port(audioens_port_t *port)
-{
-	audioens_dev_t *dev = port->dev;
-
-	if (!port->suspended) {
-		switch (port->num) {
-		case PORT_DAC:
-			CLR8(dev, CONC_bDEVCTL_OFF,
-			    CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_DAC1_EN);
-			CLR8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_DAC1IE);
-			break;
-		case PORT_ADC:
-			CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
-			CLR8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_ADCIE);
-			break;
-		}
-	}
-}
-
-static int
-audioens_start(void *arg)
-{
-	audioens_port_t *port = arg;
-	audioens_dev_t *dev = port->dev;
-
-	mutex_enter(&dev->mutex);
-	if (!port->trigger) {
-		port->trigger = B_TRUE;
-		audioens_start_port(port);
-	}
 	mutex_exit(&dev->mutex);
 
 	return (0);
@@ -725,16 +527,24 @@
 	audioens_dev_t *dev = port->dev;
 
 	mutex_enter(&dev->mutex);
-	if (port->trigger) {
-		port->trigger = B_FALSE;
-		audioens_stop_port(port);
+	switch (port->num) {
+	case PORT_DAC:
+		CLR8(dev, CONC_bDEVCTL_OFF,
+		    CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_DAC1_EN);
+		break;
+	case PORT_ADC:
+		CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
+		break;
 	}
 	mutex_exit(&dev->mutex);
 }
 
-static void
-audioens_update_port(audioens_port_t *port)
+static uint64_t
+audioens_count(void *arg)
 {
+	audioens_port_t *port = arg;
+	audioens_dev_t *dev = port->dev;
+	uint64_t val;
 	uint32_t page, offs;
 	int frameno, n;
 
@@ -750,6 +560,7 @@
 		break;
 	}
 
+	mutex_enter(&dev->mutex);
 	/*
 	 * Note that the current frame counter is in the high nybble.
 	 */
@@ -759,30 +570,17 @@
 	    frameno + port->nframes - port->frameno;
 	port->frameno = frameno;
 	port->count += n;
-}
 
-static uint64_t
-audioens_count(void *arg)
-{
-	audioens_port_t *port = arg;
-	audioens_dev_t *dev = port->dev;
-	uint64_t val;
-
-	mutex_enter(&dev->mutex);
-	if (!port->suspended) {
-		audioens_update_port(port);
-	}
 	val = port->count;
 	mutex_exit(&dev->mutex);
+
 	return (val);
 }
 
 static void
 audioens_close(void *arg)
 {
-	audioens_port_t *port = arg;
-
-	audioens_stop(port);
+	_NOTE(ARGUNUSED(arg));
 }
 
 static void
@@ -793,7 +591,7 @@
 	_NOTE(ARGUNUSED(nframes));
 
 	if (port->num == PORT_ADC) {
-		(void) ddi_dma_sync(port->dmah, 0, 0, DDI_DMA_SYNC_FORCPU);
+		(void) ddi_dma_sync(port->dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL);
 	} else {
 		(void) ddi_dma_sync(port->dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
 	}
@@ -850,12 +648,6 @@
 
 	SRCInit(dev);
 
-#if 0
-	PUT8(dev, CONC_bSERCTL_OFF, 0x00);
-	PUT8(dev, CONC_bNMIENA_OFF, 0x00); /* NMI off */
-	PUT8(dev, CONC_wNMISTAT_OFF, 0x00); /* PUT8? */
-#endif
-
 	/*
 	 * Turn on CODEC (UART and joystick left disabled)
 	 */
@@ -889,8 +681,6 @@
 		/* we want to run each channel independently */
 		CLR32(dev, CONC_dSTATUS_OFF, CONC_STATUS_ECHO);
 	}
-
-	dev->enabled = B_TRUE;
 }
 
 static int
@@ -919,12 +709,6 @@
 		return (DDI_FAILURE);
 	}
 
-	dev->pintrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, "play-interrupts", DEFINTS);
-
-	dev->rintrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, "record-interrupts", DEFINTS);
-
 	for (int i = 0; i <= PORT_MAX; i++) {
 		audioens_port_t *port;
 		unsigned caps;
@@ -999,13 +783,6 @@
 	/*
 	 * Set up kstats for interrupt reporting.
 	 */
-	dev->ksp = kstat_create(ddi_driver_name(dev->dip),
-	    ddi_get_instance(dev->dip), ddi_driver_name(dev->dip),
-	    "controller", KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
-	if (dev->ksp != NULL) {
-		kstat_install(dev->ksp);
-	}
-
 	if (audio_dev_register(dev->osdev) != DDI_SUCCESS) {
 		audio_dev_warn(dev->osdev,
 		    "unable to register with audio framework");
@@ -1015,54 +792,12 @@
 	return (DDI_SUCCESS);
 }
 
-int
-audioens_setup_interrupts(audioens_dev_t *dev)
-{
-	int actual;
-	uint_t ipri;
-
-	if ((ddi_intr_alloc(dev->dip, dev->ihandle, DDI_INTR_TYPE_FIXED,
-	    0, 1, &actual, DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) ||
-	    (actual != 1)) {
-		audio_dev_warn(dev->osdev, "can't alloc intr handle");
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_get_pri(dev->ihandle[0], &ipri) != DDI_SUCCESS) {
-		audio_dev_warn(dev->osdev,  "can't determine intr priority");
-		(void) ddi_intr_free(dev->ihandle[0]);
-		dev->ihandle[0] = NULL;
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_add_handler(dev->ihandle[0], audioens_intr, dev,
-	    NULL) != DDI_SUCCESS) {
-		audio_dev_warn(dev->osdev, "can't add intr handler");
-		(void) ddi_intr_free(dev->ihandle[0]);
-		dev->ihandle[0] = NULL;
-		return (DDI_FAILURE);
-	}
-
-	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-
-	return (DDI_SUCCESS);
-}
-
 void
 audioens_destroy(audioens_dev_t *dev)
 {
 	int	i;
 
-	if (dev->ihandle[0] != NULL) {
-		(void) ddi_intr_disable(dev->ihandle[0]);
-		(void) ddi_intr_remove_handler(dev->ihandle[0]);
-		(void) ddi_intr_free(dev->ihandle[0]);
-		mutex_destroy(&dev->mutex);
-	}
-
-	if (dev->ksp != NULL) {
-		kstat_delete(dev->ksp);
-	}
+	mutex_destroy(&dev->mutex);
 
 	/* free up ports, including DMA resources for ports */
 	for (i = 0; i <= PORT_MAX; i++) {
@@ -1109,10 +844,12 @@
 	dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
 	dev->dip = dip;
 	ddi_set_driver_private(dip, dev);
+	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, NULL);
 
 	if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
 		audio_dev_warn(dev->osdev, "pci_config_setup failed");
 		kmem_free(dev, sizeof (*dev));
+		mutex_destroy(&dev->mutex);
 		return (DDI_FAILURE);
 	}
 
@@ -1197,19 +934,12 @@
 		goto err_exit;
 	}
 
-	if (audioens_setup_interrupts(dev) != DDI_SUCCESS) {
-		audio_dev_warn(dev->osdev, "can't register interrupts");
-		goto err_exit;
-	}
-
 	/* This allocates and configures the engines */
 	if (audioens_init(dev) != DDI_SUCCESS) {
 		audio_dev_warn(dev->osdev, "can't init device");
 		goto err_exit;
 	}
 
-	(void) ddi_intr_enable(dev->ihandle[0]);
-
 	pci_config_teardown(&pcih);
 
 	ddi_report_dev(dip);
@@ -1249,8 +979,6 @@
 	PUT8(dev, CONC_bDEVCTL_OFF, tmp);
 	PUT8(dev, CONC_bDEVCTL_OFF, tmp);
 
-	dev->enabled = B_FALSE;
-
 	mutex_exit(&dev->mutex);
 
 	audioens_destroy(dev);
@@ -1258,68 +986,24 @@
 	return (DDI_SUCCESS);
 }
 
-/*ARGSUSED*/
 static int
 audioens_resume(audioens_dev_t *dev)
 {
-	/* ask framework to reset/relocate engine data */
-	for (int i = 0; i <= PORT_MAX; i++) {
-		audio_engine_reset(dev->port[i].engine);
-	}
-
 	/* reinitialize hardware */
 	audioens_init_hw(dev);
 
 	/* restore AC97 state */
-	ac97_resume(dev->ac97);
-
-	/* restart ports */
-	mutex_enter(&dev->mutex);
-	for (int i = 0; i < PORT_MAX; i++) {
-		audioens_port_t	*port = &dev->port[i];
-		port->suspended = B_FALSE;
-		audioens_init_port(port);
-		/* possibly start it up if was going when we suspended */
-		if (port->trigger) {
-			audioens_start_port(port);
+	ac97_reset(dev->ac97);
 
-		}
-	}
-	mutex_exit(&dev->mutex);
-	for (int i = 0; i < PORT_MAX; i++) {
-		audioens_port_t	*port = &dev->port[i];
-		/* signal callbacks on resume */
-		if (!port->trigger)
-			continue;
-		if (port->num == PORT_ADC) {
-			audio_engine_produce(port->engine);
-		} else {
-			audio_engine_consume(port->engine);
-		}
-	}
+	audio_dev_resume(dev->osdev);
+
 	return (DDI_SUCCESS);
 }
 
-/*ARGSUSED*/
 static int
 audioens_suspend(audioens_dev_t *dev)
 {
-	/*
-	 * Stop all engines/DMA data.
-	 */
-	mutex_enter(&dev->mutex);
-	for (int i = 0; i <= PORT_MAX; i++) {
-		audioens_stop_port(&dev->port[i]);
-		audioens_update_port(&dev->port[i]);
-		dev->port[i].suspended = B_TRUE;
-	}
-	dev->enabled = B_FALSE;
-	mutex_exit(&dev->mutex);
-
-	/*
-	 * Framework needs to save off AC'97 state.
-	 */
-	ac97_suspend(dev->ac97);
+	audio_dev_suspend(dev->osdev);
 
 	return (DDI_SUCCESS);
 }
--- a/usr/src/uts/common/io/audio/drv/audioens/audioens.conf	Tue Mar 16 09:43:38 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# Configuration file for the audioens audio driver.
-#
-#	WARNING: This is an UNSTABLE configuration file. Its contents
-#		may change at any time.
-
-#
-# 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 audioens
-# 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 then the value specified
-# will be ignored.
-#
-play-interrupts=75;
-record-interrupts=75;
-
-#
-# Uncomment reset-configuration to cause the audioens 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;
--- a/usr/src/uts/common/io/audio/drv/audiohd/audiohd.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiohd/audiohd.c	Tue Mar 16 09:30:41 2010 -0700
@@ -29,8 +29,8 @@
 #include <sys/pci.h>
 #include "audiohd.h"
 
-#define	DEFINTS			175
 #define	DRVNAME			"audiohd"
+
 /*
  * Module linkage routines for the kernel
  */
@@ -631,9 +631,7 @@
 	ddi_report_dev(dip);
 
 	/* enable interrupt */
-	AUDIOHD_REG_SET32(AUDIOHD_REG_INTCTL,
-	    AUDIOHD_INTCTL_BIT_GIE |
-	    AUDIOHD_INTCTL_BIT_SIE);
+	AUDIOHD_REG_SET32(AUDIOHD_REG_INTCTL, AUDIOHD_INTCTL_BIT_GIE);
 	return (DDI_SUCCESS);
 error:
 	audiohd_destroy(statep);
@@ -984,14 +982,14 @@
 		if (!path)
 			continue;
 		switch (path->path_type) {
-			case PLAY:
-				audiohd_init_play_path(path);
-				break;
-			case RECORD:
-				audiohd_init_record_path(path);
-				break;
-			default:
-				break;
+		case PLAY:
+			audiohd_init_play_path(path);
+			break;
+		case RECORD:
+			audiohd_init_record_path(path);
+			break;
+		default:
+			break;
 		}
 	}
 	statep->in_port = 0;
@@ -1032,7 +1030,7 @@
 	if (!bTmp) {
 		audio_dev_warn(statep->adev, "Failed to reset stream %d",
 		    port->index);
-		return (DDI_FAILURE);
+		return (EIO);
 	}
 
 	/* Empirical testing time, which works well */
@@ -1055,7 +1053,7 @@
 		audio_dev_warn(statep->adev,
 		    "Failed to exit reset state for"
 		    " stream %d, bTmp=0x%02x", port->index, bTmp);
-		return (DDI_FAILURE);
+		return (EIO);
 	}
 
 	AUDIOHD_REG_SET32(regbase + AUDIOHD_SDREG_OFFSET_BDLPL,
@@ -1064,8 +1062,7 @@
 	    (uint32_t)(port->bdl_paddr >> 32));
 	AUDIOHD_REG_SET16(regbase + AUDIOHD_SDREG_OFFSET_LVI,
 	    AUDIOHD_BDLE_NUMS - 1);
-	AUDIOHD_REG_SET32(regbase + AUDIOHD_SDREG_OFFSET_CBL,
-	    port->samp_size * AUDIOHD_BDLE_NUMS);
+	AUDIOHD_REG_SET32(regbase + AUDIOHD_SDREG_OFFSET_CBL, port->bufsize);
 
 	AUDIOHD_REG_SET16(regbase + AUDIOHD_SDREG_OFFSET_FORMAT,
 	    port->format << 4 | port->nchan - 1);
@@ -1080,73 +1077,40 @@
 	    AUDIOHD_PLAY_CTL_OFF,
 	    (port->index) << AUDIOHD_PLAY_TAG_OFF);
 
-	return (DDI_SUCCESS);
+	return (0);
 }
 
 static int
-audiohd_engine_open(void *arg, int flag,
-    unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp)
+audiohd_engine_open(void *arg, int flag, unsigned *nframes, caddr_t *bufp)
 {
 	audiohd_port_t	*port = arg;
-	audiohd_state_t	*statep = port->statep;
 
 	_NOTE(ARGUNUSED(flag));
 
-	mutex_enter(&statep->hda_mutex);
-	(void) audiohd_reset_port(port);
-	mutex_exit(&statep->hda_mutex);
-
-	port->started = B_FALSE;
 	port->count = 0;
 	port->curpos = 0;
-	*fragfrp = port->fragfr;
-	*nfragsp = AUDIOHD_BDLE_NUMS;
+	*nframes = port->nframes;
 	*bufp = port->samp_kaddr;
 
 	return (0);
 }
 
-static void
-audiohd_start_port(audiohd_port_t *port)
-{
-	audiohd_state_t	*statep = port->statep;
-
-	ASSERT(mutex_owned(&statep->hda_mutex));
-	/* if suspended, then do nothing else */
-	if (statep->suspended) {
-		return;
-	}
-
-	/* Enable interrupt and start DMA */
-	AUDIOHD_REG_SET8(port->regoff + AUDIOHD_SDREG_OFFSET_CTL,
-	    AUDIOHDR_SD_CTL_INTS | AUDIOHDR_SD_CTL_SRUN);
-}
-
-static void
-audiohd_stop_port(audiohd_port_t *port)
-{
-	audiohd_state_t	*statep = port->statep;
-
-	ASSERT(mutex_owned(&statep->hda_mutex));
-	/* if suspended, then do nothing else */
-	if (statep->suspended) {
-		return;
-	}
-	AUDIOHD_REG_SET8(port->regoff + AUDIOHD_SDREG_OFFSET_CTL, 0);
-}
-
 static int
 audiohd_engine_start(void *arg)
 {
 	audiohd_port_t		*port = arg;
 	audiohd_state_t		*statep = port->statep;
+	int			rv;
 
 	mutex_enter(&statep->hda_mutex);
-	if (!port->started) {
-		audiohd_start_port(port);
-		port->started = B_TRUE;
-		port->triggered = B_TRUE;
+
+	if ((rv = audiohd_reset_port(port)) != 0) {
+		return (rv);
 	}
+	/* Start DMA */
+	AUDIOHD_REG_SET8(port->regoff + AUDIOHD_SDREG_OFFSET_CTL,
+	    AUDIOHDR_SD_CTL_SRUN);
+
 	mutex_exit(&statep->hda_mutex);
 	return (0);
 }
@@ -1158,17 +1122,14 @@
 	audiohd_state_t		*statep = port->statep;
 
 	mutex_enter(&statep->hda_mutex);
-	if (port->started) {
-		audiohd_stop_port(port);
-	}
-	port->started = B_FALSE;
+	AUDIOHD_REG_SET8(port->regoff + AUDIOHD_SDREG_OFFSET_CTL, 0);
 	mutex_exit(&statep->hda_mutex);
 }
 
 static void
 audiohd_update_port(audiohd_port_t *port)
 {
-	int			pos;
+	uint32_t		pos;
 	uint32_t		len;
 	audiohd_state_t		*statep = port->statep;
 
@@ -1176,9 +1137,10 @@
 	/* Convert the position into a frame count */
 	pos /= (port->nchan * 2);
 
-	if (pos >= port->curpos)
+	ASSERT(pos <= port->nframes);
+	if (pos >= port->curpos) {
 		len = (pos - port->curpos);
-	else {
+	} else {
 		len = pos + port->nframes - port->curpos;
 	}
 
@@ -1195,8 +1157,7 @@
 	uint64_t	val;
 
 	mutex_enter(&statep->hda_mutex);
-	if (port->started && !statep->suspended)
-		audiohd_update_port(port);
+	audiohd_update_port(port);
 	val = port->count;
 	mutex_exit(&statep->hda_mutex);
 	return (val);
@@ -1205,14 +1166,7 @@
 static void
 audiohd_engine_close(void *arg)
 {
-	audiohd_port_t		*port = arg;
-	audiohd_state_t		*statep = port->statep;
-
-	mutex_enter(&statep->hda_mutex);
-	audiohd_stop_port(port);
-	port->started = B_FALSE;
-	port->triggered = B_FALSE;
-	mutex_exit(&statep->hda_mutex);
+	_NOTE(ARGUNUSED(arg));
 }
 
 static void
@@ -1222,8 +1176,7 @@
 
 	_NOTE(ARGUNUSED(nframes));
 
-	(void) ddi_dma_sync(port->samp_dmah, 0,
-	    0, port->sync_dir);
+	(void) ddi_dma_sync(port->samp_dmah, 0, 0, port->sync_dir);
 
 }
 
@@ -1247,11 +1200,8 @@
 audiohd_get_value(void *arg, uint64_t *val)
 {
 	audiohd_ctrl_t	*pc = arg;
-	audiohd_state_t	*statep = pc->statep;
-
-	mutex_enter(&statep->hda_mutex);
+
 	*val = pc->val;
-	mutex_exit(&statep->hda_mutex);
 	return (0);
 }
 
@@ -5121,7 +5071,6 @@
 	audiohd_port_t		*port;
 	int			dir;
 	unsigned		caps;
-	char			*prop;
 	int			rc;
 	audio_dev_t		*adev;
 	dev_info_t		*dip;
@@ -5156,13 +5105,10 @@
 
 	for (i = 0; i < PORT_MAX; i++) {
 		port = kmem_zalloc(sizeof (*port), KM_SLEEP);
-		port->started = B_FALSE;
-		port->triggered = B_FALSE;
 		statep->port[i] = port;
 		port->statep = statep;
 		switch (i) {
 		case PORT_ADC:
-			prop = "record-interrupts";
 			dir = DDI_DMA_READ | DDI_DMA_CONSISTENT;
 			caps = ENGINE_INPUT_CAP;
 			port->sync_dir = DDI_DMA_SYNC_FORKERNEL;
@@ -5171,7 +5117,6 @@
 			port->regoff = AUDIOHD_REG_SD_BASE;
 			break;
 		case PORT_DAC:
-			prop = "play-interrupts";
 			dir = DDI_DMA_WRITE | DDI_DMA_CONSISTENT;
 			caps = ENGINE_OUTPUT_CAP;
 			port->sync_dir = DDI_DMA_SYNC_FORDEV;
@@ -5185,29 +5130,10 @@
 			return (DDI_FAILURE);
 		}
 
-		port->intrs = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
-		    DDI_PROP_DONTPASS, prop, AUDIOHD_INTS);
-
-		/* make sure the values are good */
-		if (port->intrs < AUDIOHD_MIN_INTS) {
-			audio_dev_warn(adev, "%s too low, %d, resetting to %d",
-			    prop, port->intrs, AUDIOHD_INTS);
-			port->intrs = AUDIOHD_INTS;
-		} else if (port->intrs > AUDIOHD_MAX_INTS) {
-			audio_dev_warn(adev, "%s too high, %d, resetting to %d",
-			    prop, port->intrs, AUDIOHD_INTS);
-			port->intrs = AUDIOHD_INTS;
-		}
-
 		port->format = AUDIOHD_FMT_PCM;
-		port->fragfr = 48000 / port->intrs;
-		port->fragfr = AUDIOHD_ROUNDUP(port->fragfr,
-		    AUDIOHD_FRAGFR_ALIGN);
-		port->samp_size = port->fragfr * port->nchan * 2;
-		port->samp_size = AUDIOHD_ROUNDUP(port->samp_size,
-		    AUDIOHD_BDLE_BUF_ALIGN);
-		port->nframes = port->samp_size * AUDIOHD_BDLE_NUMS /
-		    (port->nchan * 2);
+		port->nframes = 1024 * AUDIOHD_BDLE_NUMS;
+		port->fragsize = 1024 * port->nchan * 2;
+		port->bufsize = port->nframes * port->nchan * 2;
 
 		/* allocate dma handle */
 		rc = ddi_dma_alloc_handle(dip, &dma_attr, DDI_DMA_SLEEP,
@@ -5228,17 +5154,13 @@
 		 * complex architectures with nested IO caches,
 		 * reliance on this flag might lead to failure.
 		 */
-		rc = ddi_dma_mem_alloc(port->samp_dmah, port->samp_size *
-		    AUDIOHD_BDLE_NUMS,
-		    &hda_dev_accattr,
-		    DDI_DMA_CONSISTENT | IOMEM_DATA_UNCACHED,
+		rc = ddi_dma_mem_alloc(port->samp_dmah, port->bufsize,
+		    &hda_dev_accattr, DDI_DMA_CONSISTENT | IOMEM_DATA_UNCACHED,
 		    DDI_DMA_SLEEP, NULL, &port->samp_kaddr,
 		    &real_size, &port->samp_acch);
 		if (rc == DDI_FAILURE) {
-			if (ddi_dma_mem_alloc(port->samp_dmah,
-			    port->samp_size * AUDIOHD_BDLE_NUMS,
-			    &hda_dev_accattr,
-			    DDI_DMA_CONSISTENT,
+			if (ddi_dma_mem_alloc(port->samp_dmah, port->bufsize,
+			    &hda_dev_accattr, DDI_DMA_CONSISTENT,
 			    DDI_DMA_SLEEP, NULL,
 			    &port->samp_kaddr, &real_size,
 			    &port->samp_acch) != DDI_SUCCESS) {
@@ -5302,9 +5224,9 @@
 
 		for (j = 0; j < AUDIOHD_BDLE_NUMS; j++) {
 			entry->sbde_addr = buf_phys_addr;
-			entry->sbde_len = port->samp_size;
+			entry->sbde_len = port->fragsize;
 			entry->sbde_ioc = 1;
-			buf_phys_addr += port->samp_size;
+			buf_phys_addr += port->fragsize;
 			entry++;
 		}
 		(void) ddi_dma_sync(port->bdl_dmah, 0, sizeof (sd_bdle_t) *
@@ -5415,32 +5337,6 @@
 }
 
 /*
- * restore_play_and_record()
- */
-static void
-audiohd_restore_play_and_record(audiohd_state_t *statep)
-{
-	int		i;
-	audiohd_port_t	*port;
-
-	mutex_enter(&statep->hda_mutex);
-	for (i = 0; i < PORT_MAX; i++) {
-		port = statep->port[i];
-		if (port == NULL)
-			continue;
-
-		audio_engine_reset(port->engine);
-		if (port->triggered) {
-			(void) audiohd_reset_port(port);
-			audiohd_start_port(port);
-		} else {
-			audiohd_stop_port(port);
-
-		}
-	}
-	mutex_exit(&statep->hda_mutex);
-}
-/*
  * audiohd_reset_pins_ur_cap()
  * Description:
  * 	Enable the unsolicited response of the pins which have the unsolicited
@@ -5539,20 +5435,18 @@
 	/* reset to enable the capability of unsolicited response for pin */
 	audiohd_reset_pins_ur_cap(statep);
 	/* Enable interrupt */
-	AUDIOHD_REG_SET32(AUDIOHD_REG_INTCTL,
-	    AUDIOHD_INTCTL_BIT_GIE |
-	    AUDIOHD_INTCTL_BIT_SIE);
+	AUDIOHD_REG_SET32(AUDIOHD_REG_INTCTL, AUDIOHD_INTCTL_BIT_GIE);
 	/* clear the unsolicited response interrupt */
 	rirbsts = AUDIOHD_REG_GET8(AUDIOHD_REG_RIRBSTS);
 	AUDIOHD_REG_SET8(AUDIOHD_REG_RIRBSTS, rirbsts);
-	mutex_exit(&statep->hda_mutex);
-
-	audiohd_restore_play_and_record(statep);
+	/* set widget power to D0 */
+	audiohd_change_widget_power_state(statep, AUDIOHD_PW_D0);
+
 	audiohd_configure_output(statep);
 	audiohd_configure_input(statep);
-
-	/* set widget power to D0 */
-	audiohd_change_widget_power_state(statep, AUDIOHD_PW_D0);
+	mutex_exit(&statep->hda_mutex);
+
+	audio_dev_resume(statep->adev);
 
 	return (DDI_SUCCESS);
 }	/* audiohd_resume */
@@ -5563,6 +5457,8 @@
 static int
 audiohd_suspend(audiohd_state_t *statep)
 {
+	audio_dev_suspend(statep->adev);
+
 	mutex_enter(&statep->hda_mutex);
 	statep->suspended = B_TRUE;
 
@@ -5580,22 +5476,38 @@
 /*
  * audiohd_disable_pin()
  */
-static int
+static void
 audiohd_disable_pin(audiohd_state_t *statep, int caddr, wid_t wid)
 {
-	AUDIOHD_DISABLE_PIN_OUT(statep, caddr, wid);
-	return (DDI_SUCCESS);
+	uint32_t	tmp;
+
+	tmp = audioha_codec_verb_get(statep, caddr, wid,
+	    AUDIOHDC_VERB_GET_PIN_CTRL, 0);
+	if (tmp == AUDIOHD_CODEC_FAILURE)
+		return;
+	tmp = audioha_codec_verb_get(statep, caddr, wid,
+	    AUDIOHDC_VERB_SET_PIN_CTRL,
+	    (tmp & ~AUDIOHDC_PIN_CONTROL_OUT_ENABLE));
 }
 
 /*
  * audiohd_enable_pin()
  */
-static int
+static void
 audiohd_enable_pin(audiohd_state_t *statep, int caddr, wid_t wid)
 {
-	AUDIOHD_ENABLE_PIN_OUT(statep, caddr, wid);
-	return (DDI_SUCCESS);
+	uint32_t	tmp;
+
+	tmp = audioha_codec_verb_get(statep, caddr, wid,
+	    AUDIOHDC_VERB_GET_PIN_CTRL, 0);
+	if (tmp == AUDIOHD_CODEC_FAILURE)
+		return;
+	tmp = audioha_codec_verb_get(statep, caddr, wid,
+	    AUDIOHDC_VERB_SET_PIN_CTRL,
+	    tmp | AUDIOHDC_PIN_CONTROL_OUT_ENABLE |
+	    AUDIOHDC_PIN_CONTROL_HP_ENABLE);
 }
+
 /*
  * audiohd_change_speaker_state()
  */
@@ -5618,8 +5530,7 @@
 				widget = path->codec->widget[wid];
 				pin = (audiohd_pin_t *)widget->priv;
 				if (pin->device == DTYPE_SPEAKER) {
-					(void) audiohd_enable_pin(
-					    statep,
+					audiohd_enable_pin(statep,
 					    path->codec->index,
 					    pin->wid);
 				}
@@ -5631,8 +5542,7 @@
 				widget = path->codec->widget[wid];
 				pin = (audiohd_pin_t *)widget->priv;
 				if (pin->device == DTYPE_SPEAKER) {
-					(void) audiohd_disable_pin(
-					    statep,
+					audiohd_disable_pin(statep,
 					    path->codec->index,
 					    pin->wid);
 				}
@@ -5830,15 +5740,11 @@
 {
 	audiohd_state_t	*statep = (void *)arg1;
 	uint32_t	status;
-	uint32_t	regbase;
 	uint32_t	resp, respex;
-	uint8_t		sdstatus, rirbsts;
+	uint8_t		rirbsts;
 	int		i, ret;
 
 	_NOTE(ARGUNUSED(arg2))
-	audio_engine_t	*do_adc = NULL;
-	audio_engine_t	*do_dac = NULL;
-
 
 	mutex_enter(&statep->hda_mutex);
 	if (statep->suspended) {
@@ -5889,22 +5795,6 @@
 		}
 	}
 
-	/* 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 (i < statep->hda_input_streams)
-			do_adc = statep->port[PORT_ADC]->engine;
-		else
-			do_dac = statep->port[PORT_DAC]->engine;
-	}
-
 	/* update the kernel interrupt statistics */
 	if (statep->hda_ksp) {
 		((kstat_intr_t *)
@@ -5913,10 +5803,6 @@
 
 	mutex_exit(&statep->hda_mutex);
 
-	if (do_adc)
-		audio_engine_produce(do_adc);
-	if (do_dac)
-		audio_engine_consume(do_dac);
 	return (DDI_INTR_CLAIMED);
 }	/* audiohd_intr() */
 
--- a/usr/src/uts/common/io/audio/drv/audiohd/audiohd.conf	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiohd/audiohd.conf	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #
@@ -28,22 +28,5 @@
 #	WARNING: This is an UNSTABLE configuration file. Its contents
 #		may change at any time.
 
-#
-# 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;
 audiohd_beep=1;
 msi_enable=1;
--- a/usr/src/uts/common/io/audio/drv/audiohd/audiohd.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiohd/audiohd.h	Tue Mar 16 09:30:41 2010 -0700
@@ -56,10 +56,6 @@
 #define	NO_SPDIF	0x00000004
 #define	EN_PIN_BEEP	0x00000008
 
-#define	AUDIOHD_INTS		50
-#define	AUDIOHD_MAX_INTS	1500
-#define	AUDIOHD_MIN_INTS	32
-
 #define	AUDIOHD_DEV_CONFIG	"onboard1"
 #define	AUDIOHD_DEV_VERSION	"a"
 
@@ -179,7 +175,6 @@
 #define	AUDIOHD_CODEC_TYPE_MASK	0x000000ff
 
 #define	AUDIOHD_ROUNDUP(x, algn)	(((x) + ((algn) - 1)) & ~((algn) - 1))
-#define	AUDIOHD_FRAGFR_ALIGN	64
 #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 */
@@ -267,11 +262,6 @@
 #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
@@ -680,21 +670,18 @@
 	uint8_t			nchan;
 	int			index;
 	uint16_t		regoff;
-	boolean_t		started;
-	boolean_t		triggered;
 
-	unsigned		fragfr;
 	unsigned		nframes;
+	size_t			bufsize;
+	size_t			fragsize;
 	uint64_t		count;
 	int			curpos;
-	int			intrs;
 
 	uint_t			format;
 	unsigned		sync_dir;
 
 	ddi_dma_handle_t	samp_dmah;
 	ddi_acc_handle_t	samp_acch;
-	size_t			samp_size;
 	caddr_t			samp_kaddr;
 	uint64_t		samp_paddr;
 
@@ -817,10 +804,6 @@
 	audio_dev_t	*adev;
 	uint32_t	devid;
 
-
-	int		hda_pint_freq;	/* play intr frequence */
-	int		hda_rint_freq;	/* record intr frequence */
-
 	int		hda_input_streams;	/* # of input stream */
 	int		hda_output_streams;	/* # of output stream */
 	int		hda_streams_nums;	/* # of stream */
@@ -910,43 +893,6 @@
 
 
 /*
- * enable a pin widget to output
- */
-#define	AUDIOHD_ENABLE_PIN_OUT(statep, caddr, wid) \
-{ \
-	uint32_t	lTmp; \
-\
-	lTmp = audioha_codec_verb_get(statep, caddr, wid, \
-	    AUDIOHDC_VERB_GET_PIN_CTRL, 0); \
-	if (lTmp == AUDIOHD_CODEC_FAILURE) \
-		return (DDI_FAILURE); \
-	lTmp = audioha_codec_verb_get(statep, caddr, wid, \
-	    AUDIOHDC_VERB_SET_PIN_CTRL, \
-	    (lTmp | AUDIOHDC_PIN_CONTROL_OUT_ENABLE | \
-	    AUDIOHDC_PIN_CONTROL_HP_ENABLE)); \
-	if (lTmp == AUDIOHD_CODEC_FAILURE) \
-		return (DDI_FAILURE); \
-}
-
-/*
- * disable output pin
- */
-#define	AUDIOHD_DISABLE_PIN_OUT(statep, caddr, wid) \
-{ \
-	uint32_t	lTmp; \
-\
-	lTmp = audioha_codec_verb_get(statep, caddr, wid, \
-	    AUDIOHDC_VERB_GET_PIN_CTRL, 0); \
-	if (lTmp == AUDIOHD_CODEC_FAILURE) \
-		return (DDI_FAILURE); \
-	lTmp = audioha_codec_verb_get(statep, caddr, wid, \
-	    AUDIOHDC_VERB_SET_PIN_CTRL, \
-	    (lTmp & ~AUDIOHDC_PIN_CONTROL_OUT_ENABLE)); \
-	if (lTmp == AUDIOHD_CODEC_FAILURE) \
-		return (DDI_FAILURE); \
-}
-
-/*
  * enable a pin widget to input
  */
 #define	AUDIOHD_ENABLE_PIN_IN(statep, caddr, wid) \
--- a/usr/src/uts/common/io/audio/drv/audioixp/audioixp.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audioixp/audioixp.c	Tue Mar 16 09:30:41 2010 -0700
@@ -67,7 +67,7 @@
 /*
  * Entry point routine prototypes
  */
-static int audioixp_open(void *, int, unsigned *, unsigned *, caddr_t *);
+static int audioixp_open(void *, int, unsigned *, caddr_t *);
 static void audioixp_close(void *);
 static int audioixp_start(void *);
 static void audioixp_stop(void *);
@@ -107,19 +107,11 @@
 };
 
 /*
- * interrupt handler
- */
-static uint_t	audioixp_intr(caddr_t);
-
-/*
  * Local Routine Prototypes
  */
 static int audioixp_attach(dev_info_t *);
 static int audioixp_detach(dev_info_t *);
 static int audioixp_alloc_port(audioixp_state_t *, int);
-static void audioixp_start_port(audioixp_port_t *);
-static void audioixp_stop_port(audioixp_port_t *);
-static void audioixp_reset_port(audioixp_port_t *);
 static void audioixp_update_port(audioixp_port_t *);
 
 static int audioixp_codec_sync(audioixp_state_t *);
@@ -357,20 +349,6 @@
 	}
 }
 
-static void
-audioixp_stop_dma(audioixp_state_t *statep)
-{
-	CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
-	CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
-}
-
-static void
-audioixp_disable_intr(audioixp_state_t *statep)
-{
-	PUT32(IXP_AUDIO_INT, GET32(IXP_AUDIO_INT));
-	PUT32(IXP_AUDIO_INT_EN, 0);
-}
-
 /*
  * quiesce(9E) entry point.
  *
@@ -388,11 +366,11 @@
 	statep = ddi_get_driver_private(dip);
 	ASSERT(statep != NULL);
 
-	/* disable HW interrupt */
-	audioixp_disable_intr(statep);
-
 	/* stop DMA engines */
-	audioixp_stop_dma(statep);
+	CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT);
+	CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
+	CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN);
+	CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
 
 	return (DDI_SUCCESS);
 }
@@ -405,135 +383,28 @@
 	statep = ddi_get_driver_private(dip);
 	ASSERT(statep != NULL);
 
-	ac97_suspend(statep->ac97);
-	mutex_enter(&statep->inst_lock);
-
-	statep->suspended = B_TRUE;
-
-	audioixp_disable_intr(statep);
-	audioixp_stop_dma(statep);
-
-	mutex_exit(&statep->inst_lock);
-	return (DDI_SUCCESS);
-}
+	audio_dev_suspend(statep->adev);
 
-static void
-audioixp_resume_port(audioixp_port_t *port)
-{
-	if (port != NULL) {
-		if (port->engine != NULL) {
-			audio_engine_reset(port->engine);
-		}
-	}
-	audioixp_reset_port(port);
-	if (port->started) {
-		audioixp_start_port(port);
-	} else {
-		audioixp_stop_port(port);
-	}
+	return (DDI_SUCCESS);
 }
 
 static int
 audioixp_resume(dev_info_t *dip)
 {
 	audioixp_state_t		*statep;
-	audio_dev_t			*adev;
-	audioixp_port_t			*rec_port, *play_port;
 
 	statep = ddi_get_driver_private(dip);
-	adev = statep->adev;
 	ASSERT(statep != NULL);
 
 	if (audioixp_chip_init(statep) != DDI_SUCCESS) {
-		audio_dev_warn(adev, "DDI_RESUME failed to init chip");
+		audio_dev_warn(statep->adev, "DDI_RESUME failed to init chip");
 		return (DDI_SUCCESS);
 	}
 
-	ac97_resume(statep->ac97);
-	mutex_enter(&statep->inst_lock);
-	statep->suspended = B_FALSE;
-
-	rec_port = statep->rec_port;
-	play_port = statep->play_port;
-
-	audioixp_resume_port(rec_port);
-	audioixp_resume_port(play_port);
-
-	mutex_exit(&statep->inst_lock);
-	return (DDI_SUCCESS);
-}
-/*
- * audioixp_intr()
- *
- * Description:
- *	Interrupt service routine for both play and record. For play we
- *	get the next buffers worth of audio. For record we send it on to
- *	the mixer.
- *
- *	There's a hardware pointer which indicate memory location where
- *	the hardware is processing. We check this pointer to decide whether
- *	to handle the buffer and how many buffers should be handled.
- *	Refer to ATI IXP400/450 Register Reference Manual, page 193,194.
- *
- * 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
-audioixp_intr(caddr_t arg)
-{
-	audioixp_state_t	*statep;
-	uint32_t		sr;
-	int			claimed = DDI_INTR_UNCLAIMED;
+	ac97_reset(statep->ac97);
+	audio_dev_resume(statep->adev);
 
-	statep = (void *)arg;
-	mutex_enter(&statep->inst_lock);
-
-	sr = GET32(IXP_AUDIO_INT);
-
-	/* PCM in interrupt */
-	if (sr & IXP_AUDIO_INT_IN_DMA) {
-		claimed = DDI_INTR_CLAIMED;
-		PUT32(IXP_AUDIO_INT, IXP_AUDIO_INT_IN_DMA);
-	}
-
-	/* PCM out interrupt */
-	if (sr & IXP_AUDIO_INT_OUT_DMA) {
-		claimed = DDI_INTR_CLAIMED;
-		PUT32(IXP_AUDIO_INT, IXP_AUDIO_INT_OUT_DMA);
-	}
-
-	/* system is too busy to process the input stream, ignore it */
-	if (sr & IXP_AUDIO_INT_IN_DMA_OVERFLOW) {
-		claimed = DDI_INTR_CLAIMED;
-		PUT32(IXP_AUDIO_INT, IXP_AUDIO_INT_IN_DMA_OVERFLOW);
-	}
-
-	/* System is too busy, ignore it */
-	if (sr & IXP_AUDIO_INT_OUT_DMA_UNDERFLOW) {
-		claimed = DDI_INTR_CLAIMED;
-		PUT32(IXP_AUDIO_INT, IXP_AUDIO_INT_OUT_DMA_UNDERFLOW);
-	}
-
-	/* update the kernel interrupt statistics */
-	if ((claimed == DDI_INTR_CLAIMED) && statep->ksp) {
-		IXP_KIOP(statep)->intrs[KSTAT_INTR_HARD]++;
-	}
-
-	mutex_exit(&statep->inst_lock);
-
-	if (sr & IXP_AUDIO_INT_IN_DMA) {
-		audio_engine_produce(statep->rec_port->engine);
-	}
-	if (sr & IXP_AUDIO_INT_OUT_DMA) {
-		audio_engine_consume(statep->play_port->engine);
-	}
-
-	return (claimed);
+	return (DDI_SUCCESS);
 }
 
 /*
@@ -545,8 +416,7 @@
  * Arguments:
  *	void		*arg		The DMA engine to set up
  *	int		flag		Open flags
- *	unsigned	*fragfrp	Receives number of frames per fragment
- *	unsigned	*nfragsp	Receives number of fragments
+ *	unsigned	*nframesp	Receives number of frames
  *	caddr_t		*bufp		Receives kernel data buffer
  *
  * Returns:
@@ -554,8 +424,7 @@
  *	errno	on failure
  */
 static int
-audioixp_open(void *arg, int flag,
-    unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp)
+audioixp_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
 {
 	audioixp_port_t	*port = arg;
 
@@ -564,14 +433,9 @@
 	port->started = B_FALSE;
 	port->count = 0;
 	port->offset = 0;
-	*fragfrp = port->fragfr;
-	*nfragsp = IXP_BD_NUMS;
+	*nframesp = port->nframes;
 	*bufp = port->samp_kaddr;
 
-	mutex_enter(&port->statep->inst_lock);
-	audioixp_reset_port(port);
-	mutex_exit(&port->statep->inst_lock);
-
 	return (0);
 }
 
@@ -589,13 +453,7 @@
 static void
 audioixp_close(void *arg)
 {
-	audioixp_port_t		*port = arg;
-	audioixp_state_t	*statep = port->statep;
-
-	mutex_enter(&statep->inst_lock);
-	audioixp_stop_port(port);
-	port->started = B_FALSE;
-	mutex_exit(&statep->inst_lock);
+	_NOTE(ARGUNUSED(arg));
 }
 
 /*
@@ -615,10 +473,13 @@
 	audioixp_state_t	*statep = port->statep;
 
 	mutex_enter(&statep->inst_lock);
-	if (port->started) {
-		audioixp_stop_port(port);
+	if (port->num == IXP_REC) {
+		CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN);
+		CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
+	} else {
+		CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT);
+		CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
 	}
-	port->started = B_FALSE;
 	mutex_exit(&statep->inst_lock);
 }
 
@@ -641,9 +502,53 @@
 	audioixp_state_t	*statep = port->statep;
 
 	mutex_enter(&statep->inst_lock);
-	if (!port->started) {
-		audioixp_start_port(port);
-		port->started = B_TRUE;
+
+	port->offset = 0;
+
+	if (port->num == IXP_REC) {
+		PUT32(IXP_AUDIO_FIFO_FLUSH, IXP_AUDIO_FIFO_FLUSH_IN);
+		SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_INTER_IN);
+
+		SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
+		PUT32(IXP_AUDIO_IN_DMA_LINK_P,
+		    port->bdl_paddr | IXP_AUDIO_IN_DMA_LINK_P_EN);
+
+		SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN);
+	} else {
+		uint32_t slot = GET32(IXP_AUDIO_OUT_DMA_SLOT_EN_THRESHOLD);
+		PUT32(IXP_AUDIO_FIFO_FLUSH, IXP_AUDIO_FIFO_FLUSH_OUT);
+		/* clear all slots */
+		slot &= ~ (IXP_AUDIO_OUT_DMA_SLOT_3 |
+		    IXP_AUDIO_OUT_DMA_SLOT_4 |
+		    IXP_AUDIO_OUT_DMA_SLOT_5 |
+		    IXP_AUDIO_OUT_DMA_SLOT_6 |
+		    IXP_AUDIO_OUT_DMA_SLOT_7 |
+		    IXP_AUDIO_OUT_DMA_SLOT_8 |
+		    IXP_AUDIO_OUT_DMA_SLOT_9 |
+		    IXP_AUDIO_OUT_DMA_SLOT_10 |
+		    IXP_AUDIO_OUT_DMA_SLOT_11 |
+		    IXP_AUDIO_OUT_DMA_SLOT_12);
+		/* enable AC'97 output slots (depending on output channels) */
+		slot |= IXP_AUDIO_OUT_DMA_SLOT_3 |
+		    IXP_AUDIO_OUT_DMA_SLOT_4;
+		if (port->nchan >= 4) {
+			slot |= IXP_AUDIO_OUT_DMA_SLOT_6 |
+			    IXP_AUDIO_OUT_DMA_SLOT_9;
+		}
+		if (port->nchan >= 6) {
+			slot |= IXP_AUDIO_OUT_DMA_SLOT_7 |
+			    IXP_AUDIO_OUT_DMA_SLOT_8;
+		}
+
+		PUT32(IXP_AUDIO_OUT_DMA_SLOT_EN_THRESHOLD, slot);
+
+		SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_INTER_OUT);
+
+		SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
+		PUT32(IXP_AUDIO_OUT_DMA_LINK_P,
+		    port->bdl_paddr | IXP_AUDIO_OUT_DMA_LINK_P_EN);
+
+		SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT);
 	}
 	mutex_exit(&statep->inst_lock);
 	return (0);
@@ -778,7 +683,6 @@
 	uint_t			count;
 	int			dir;
 	unsigned		caps;
-	char			*prop;
 	audio_dev_t		*adev;
 	audioixp_port_t		*port;
 	uint32_t		paddr;
@@ -797,7 +701,6 @@
 	switch (num) {
 	case IXP_REC:
 		statep->rec_port = port;
-		prop = "record-interrupts";
 		dir = DDI_DMA_READ;
 		caps = ENGINE_INPUT_CAP;
 		port->sync_dir = DDI_DMA_SYNC_FORKERNEL;
@@ -805,7 +708,6 @@
 		break;
 	case IXP_PLAY:
 		statep->play_port = port;
-		prop = "play-interrupts";
 		dir = DDI_DMA_WRITE;
 		caps = ENGINE_OUTPUT_CAP;
 		port->sync_dir = DDI_DMA_SYNC_FORDEV;
@@ -836,29 +738,10 @@
 		return (DDI_FAILURE);
 	}
 
-	port->intrs = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, prop, IXP_INTS);
-
-	/* make sure the values are good */
-	if (port->intrs < IXP_MIN_INTS) {
-		audio_dev_warn(adev, "%s too low, %d, resetting to %d",
-		    prop, port->intrs, IXP_INTS);
-		port->intrs = IXP_INTS;
-	} else if (port->intrs > IXP_MAX_INTS) {
-		audio_dev_warn(adev, "%s too high, %d, resetting to %d",
-		    prop, port->intrs, IXP_INTS);
-		port->intrs = IXP_INTS;
-	}
-
-	/*
-	 * Figure out how much space we need.  Sample rate is 48kHz, and
-	 * we need to store 8 chunks.  (Note that this means that low
-	 * interrupt frequencies will require more RAM.)
-	 */
-	port->fragfr = 48000 / port->intrs;
-	port->fragfr = IXP_ROUNDUP(port->fragfr, IXP_MOD_SIZE);
+	port->nframes = 4096;
+	port->fragfr = port->nframes / IXP_BD_NUMS;
 	port->fragsz = port->fragfr * port->nchan * 2;
-	port->samp_size = port->fragsz * IXP_BD_NUMS;
+	port->samp_size = port->nframes * port->nchan * 2;
 
 	/* allocate dma handle */
 	rc = ddi_dma_alloc_handle(dip, &sample_buf_dma_attr, DDI_DMA_SLEEP,
@@ -992,130 +875,6 @@
 }
 
 /*
- * audioixp_start_port()
- *
- * Description:
- *	This routine starts the DMA engine.
- *
- * Arguments:
- *	audioixp_port_t	*port		Port of DMA engine to start.
- */
-static void
-audioixp_start_port(audioixp_port_t *port)
-{
-	audioixp_state_t	*statep = port->statep;
-
-	ASSERT(mutex_owned(&statep->inst_lock));
-
-	/* if suspended, then do nothing else */
-	if (statep->suspended) {
-		return;
-	}
-
-	if (port->num == IXP_REC) {
-		SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN);
-	} else {
-		SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT);
-	}
-}
-
-/*
- * audioixp_stop_port()
- *
- * Description:
- *	This routine stops the DMA engine.
- *
- * Arguments:
- *	audioixp_port_t	*port		Port of DMA engine to stop.
- */
-static void
-audioixp_stop_port(audioixp_port_t *port)
-{
-	audioixp_state_t	*statep = port->statep;
-
-	ASSERT(mutex_owned(&statep->inst_lock));
-
-	/* if suspended, then do nothing else */
-	if (statep->suspended) {
-		return;
-	}
-	if (port->num == IXP_REC) {
-		CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN);
-	} else {
-		CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT);
-	}
-}
-
-/*
- * audioixp_reset_port()
- *
- * Description:
- *	This routine resets the DMA engine pareparing it for work.
- *
- * Arguments:
- *	audioixp_port_t	*port		Port of DMA engine to reset.
- */
-static void
-audioixp_reset_port(audioixp_port_t *port)
-{
-	audioixp_state_t	*statep = port->statep;
-
-	ASSERT(mutex_owned(&statep->inst_lock));
-
-	port->offset = 0;
-
-	if (statep->suspended)
-		return;
-
-	/*
-	 * Perform full reset of the engine, and enable its interrupts
-	 * but leave it turned off.
-	 */
-	if (port->num == IXP_REC) {
-		PUT32(IXP_AUDIO_FIFO_FLUSH, IXP_AUDIO_FIFO_FLUSH_IN);
-		SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_INTER_IN);
-
-		SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
-		PUT32(IXP_AUDIO_IN_DMA_LINK_P,
-		    port->bdl_paddr | IXP_AUDIO_IN_DMA_LINK_P_EN);
-
-	} else {
-		uint32_t slot = GET32(IXP_AUDIO_OUT_DMA_SLOT_EN_THRESHOLD);
-		PUT32(IXP_AUDIO_FIFO_FLUSH, IXP_AUDIO_FIFO_FLUSH_OUT);
-		/* clear all slots */
-		slot &= ~ (IXP_AUDIO_OUT_DMA_SLOT_3 |
-		    IXP_AUDIO_OUT_DMA_SLOT_4 |
-		    IXP_AUDIO_OUT_DMA_SLOT_5 |
-		    IXP_AUDIO_OUT_DMA_SLOT_6 |
-		    IXP_AUDIO_OUT_DMA_SLOT_7 |
-		    IXP_AUDIO_OUT_DMA_SLOT_8 |
-		    IXP_AUDIO_OUT_DMA_SLOT_9 |
-		    IXP_AUDIO_OUT_DMA_SLOT_10 |
-		    IXP_AUDIO_OUT_DMA_SLOT_11 |
-		    IXP_AUDIO_OUT_DMA_SLOT_12);
-		/* enable AC'97 output slots (depending on output channels) */
-		slot |= IXP_AUDIO_OUT_DMA_SLOT_3 |
-		    IXP_AUDIO_OUT_DMA_SLOT_4;
-		if (port->nchan >= 4) {
-			slot |= IXP_AUDIO_OUT_DMA_SLOT_6 |
-			    IXP_AUDIO_OUT_DMA_SLOT_9;
-		}
-		if (port->nchan >= 6) {
-			slot |= IXP_AUDIO_OUT_DMA_SLOT_7 |
-			    IXP_AUDIO_OUT_DMA_SLOT_8;
-		}
-
-		PUT32(IXP_AUDIO_OUT_DMA_SLOT_EN_THRESHOLD, slot);
-
-		SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_INTER_OUT);
-
-		SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
-		PUT32(IXP_AUDIO_OUT_DMA_LINK_P,
-		    port->bdl_paddr | IXP_AUDIO_OUT_DMA_LINK_P_EN);
-	}
-}
-
-/*
  * audioixp_update_port()
  *
  * Description:
@@ -1135,9 +894,6 @@
 	uint32_t		offset;
 	uint32_t		paddr;
 
-	if (statep->suspended) {
-		return;
-	}
 	if (port->num == IXP_REC) {
 		regoff = IXP_AUDIO_IN_DMA_DT_CUR;
 	} else {
@@ -1453,13 +1209,6 @@
 		return (DDI_FAILURE);
 	}
 
-	/* enable interrupts */
-	PUT32(IXP_AUDIO_INT, 0xffffffff);
-	PUT32(
-	    IXP_AUDIO_INT_EN,
-	    IXP_AUDIO_INT_EN_IN_DMA_OVERFLOW |
-	    IXP_AUDIO_INT_EN_STATUS |
-	    IXP_AUDIO_INT_EN_OUT_DMA_UNDERFLOW);
 	return (DDI_SUCCESS);
 
 }	/* audioixp_chip_init() */
@@ -1489,27 +1238,11 @@
 	const char		*name;
 	const char		*rev;
 
-	/* we don't support high level interrupts in the driver */
-	if (ddi_intr_hilevel(dip, 0) != 0) {
-		cmn_err(CE_WARN,
-		    "!%s%d: unsupported high level interrupt",
-		    ddi_driver_name(dip), ddi_get_instance(dip));
-		return (DDI_FAILURE);
-	}
-
 	/* allocate the soft state structure */
 	statep = kmem_zalloc(sizeof (*statep), KM_SLEEP);
 	statep->dip = dip;
 	ddi_set_driver_private(dip, statep);
-
-	if (ddi_get_iblock_cookie(dip, 0, &statep->iblock) != DDI_SUCCESS) {
-		cmn_err(CE_WARN,
-		    "!%s%d: cannot get iblock cookie",
-		    ddi_driver_name(dip), ddi_get_instance(dip));
-		kmem_free(statep, sizeof (*statep));
-		return (DDI_FAILURE);
-	}
-	mutex_init(&statep->inst_lock, NULL, MUTEX_DRIVER, statep->iblock);
+	mutex_init(&statep->inst_lock, NULL, MUTEX_DRIVER, NULL);
 
 	/* allocate framework audio device */
 	if ((adev = audio_dev_alloc(dip, 0)) == NULL) {
@@ -1588,14 +1321,6 @@
 		}
 	}
 
-	/* set up kernel statistics */
-	if ((statep->ksp = kstat_create(IXP_NAME, ddi_get_instance(dip),
-	    IXP_NAME, "controller", KSTAT_TYPE_INTR, 1,
-	    KSTAT_FLAG_PERSISTENT)) != NULL) {
-		kstat_install(statep->ksp);
-	}
-
-
 	if (audioixp_chip_init(statep) != DDI_SUCCESS) {
 		audio_dev_warn(statep->adev, "failed to init chip");
 		goto error;
@@ -1607,13 +1332,6 @@
 		goto error;
 	}
 
-	/* set up the interrupt handler */
-	if (ddi_add_intr(dip, 0, &statep->iblock, NULL, audioixp_intr,
-	    (caddr_t)statep) != DDI_SUCCESS) {
-		audio_dev_warn(adev, "bad interrupt specification");
-	}
-	statep->intr_added = B_TRUE;
-
 	if (audio_dev_register(adev) != DDI_SUCCESS) {
 		audio_dev_warn(adev, "unable to register with framework");
 		goto error;
@@ -1666,26 +1384,14 @@
  * Arguments:
  *	audioixp_state_t	*state	The device soft state.
  */
-void
+static void
 audioixp_destroy(audioixp_state_t *statep)
 {
-	if (!statep->suspended) {
-		PUT32(IXP_AUDIO_INT, GET32(IXP_AUDIO_INT));
-		PUT32(IXP_AUDIO_INT_EN, 0);
-
-		/*
-		 * put the audio controller into quiet state, everything off
-		 */
-		CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
-		CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
-	}
-
-	if (statep->intr_added) {
-		ddi_remove_intr(statep->dip, 0, statep->iblock);
-	}
-	if (statep->ksp) {
-		kstat_delete(statep->ksp);
-	}
+	/*
+	 * put the audio controller into quiet state, everything off
+	 */
+	CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
+	CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
 
 	audioixp_free_port(statep->play_port);
 	audioixp_free_port(statep->rec_port);
--- a/usr/src/uts/common/io/audio/drv/audioixp/audioixp.conf	Tue Mar 16 09:43:38 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# Configuration file for the audioixp audio driver.
-#
-#	WARNING: This is an UNSTABLE configuration file. Its contents
-#		may change at any time.
-
-
-#
-# 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 audioixp
-# 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;
--- a/usr/src/uts/common/io/audio/drv/audioixp/audioixp.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audioixp/audioixp.h	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -44,12 +44,7 @@
 #define	IXP_PLAY		0
 #define	IXP_REC			1
 
-#define	IXP_ROUNDUP(x, algn)		(((x) + ((algn) - 1)) & ~((algn) - 1))
-#define	IXP_KIOP(X)			((kstat_intr_t *)(X->ksp->ks_data))
-
 #define	IXP_BD_NUMS			(8)
-#define	IXP_MOD_SIZE			(32)
-
 
 /*
  * PCI configuration registers and bits
@@ -214,7 +209,7 @@
 	caddr_t			bdl_kaddr;
 	uint32_t		bdl_paddr;
 
-	unsigned		intrs;
+	unsigned		nframes;
 	unsigned		fragfr;
 	unsigned		fragsz;
 	uint64_t		count;
@@ -245,7 +240,6 @@
  */
 struct audioixp_state {
 	kmutex_t		inst_lock;	/* state protection lock */
-	ddi_iblock_cookie_t	iblock;
 	dev_info_t		*dip;
 	audio_dev_t		*adev;		/* audio handle */
 	ac97_t			*ac97;
@@ -257,11 +251,8 @@
 	caddr_t			regsp;		/* base of audio mixer regs */
 
 	boolean_t		suspended;
-	boolean_t		intr_added;
 	boolean_t		swap_out;	/* swap line-out and sur-out */
 
-	kstat_t			*ksp;		/* kernel statistics */
-
 	uint32_t		ixp_codec_not_ready_bits; /* for codec detect */
 };
 typedef struct audioixp_state	 audioixp_state_t;
--- a/usr/src/uts/common/io/audio/drv/audiols/audiols.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiols/audiols.c	Tue Mar 16 09:30:41 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -77,7 +77,7 @@
 static int audigyls_detach(audigyls_dev_t *);
 static int audigyls_suspend(audigyls_dev_t *);
 
-static int audigyls_open(void *, int, unsigned *, unsigned *, caddr_t *);
+static int audigyls_open(void *, int, unsigned *, caddr_t *);
 static void audigyls_close(void *);
 static int audigyls_start(void *);
 static void audigyls_stop(void *);
@@ -92,14 +92,8 @@
 static uint16_t audigyls_read_ac97(void *, uint8_t);
 static void audigyls_write_ac97(void *, uint8_t, uint16_t);
 static int audigyls_alloc_port(audigyls_dev_t *, int);
-static void audigyls_start_port(audigyls_port_t *);
-static void audigyls_stop_port(audigyls_port_t *);
-static void audigyls_update_port(audigyls_port_t *);
-static void audigyls_reset_port(audigyls_port_t *);
 static void audigyls_destroy(audigyls_dev_t *);
-static int audigyls_setup_intrs(audigyls_dev_t *);
 static void audigyls_hwinit(audigyls_dev_t *);
-static uint_t audigyls_intr(caddr_t, caddr_t);
 static void audigyls_configure_mixer(audigyls_dev_t *dev);
 
 static audio_engine_ops_t audigyls_engine_ops = {
@@ -309,92 +303,12 @@
 	return (1);
 }
 
-static void
-audigyls_update_port(audigyls_port_t *port)
-{
-	audigyls_dev_t *dev = port->dev;
-	uint32_t	offset, n;
-
-	if (dev->suspended)
-		return;
-
-	if (port->direction == AUDIGYLS_PLAY_PORT) {
-		offset = read_chan(dev, CPFA, 0);
-	} else {
-		offset = read_chan(dev, CRFA, 2);
-	}
-
-
-	/* get the offset, and switch to frames */
-	offset /= (2 * sizeof (uint16_t));
-
-	if (offset >= port->offset) {
-		n = offset - port->offset;
-	} else {
-		n = offset + (port->buf_frames - port->offset);
-	}
-	port->offset = offset;
-	port->count += n;
-}
-
-static void
-check_play_intr(audigyls_dev_t *dev)
-{
-	audigyls_port_t *port = dev->port[AUDIGYLS_PLAY_PORT];
-
-	if (!port->started)
-		return;
-	audio_engine_consume(port->engine);
-}
-
-static void
-check_rec_intr(audigyls_dev_t *dev)
-{
-	audigyls_port_t *port = dev->port[AUDIGYLS_REC_PORT];
-
-	if (!port->started)
-		return;
-	audio_engine_produce(port->engine);
-}
-
-static uint_t
-audigyls_intr(caddr_t argp, caddr_t nocare)
-{
-	audigyls_dev_t	*dev = (void *)argp;
-	uint32_t	status;
-
-	_NOTE(ARGUNUSED(nocare));
-	status = INL(dev, IPR);
-
-	if (dev->suspended) {
-		OUTL(dev, IPR, status);		/* Acknowledge */
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	if (!(status & (INTR_IT1 | INTR_PCI))) {
-		/* No audio interrupts pending */
-		OUTL(dev, IPR, status);		/* Acknowledge */
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	check_play_intr(dev);
-	check_rec_intr(dev);
-
-	if (dev->ksp) {
-		AUDIGYLS_KIOP(dev)->intrs[KSTAT_INTR_HARD]++;
-	}
-
-	OUTL(dev, IPR, status);		/* Acknowledge */
-	return (DDI_INTR_CLAIMED);
-}
-
 /*
  * Audio routines
  */
 
 int
-audigyls_open(void *arg, int flag,
-    unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp)
+audigyls_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
 {
 	audigyls_port_t	 *port = arg;
 	audigyls_dev_t	 *dev = port->dev;
@@ -403,12 +317,9 @@
 
 	mutex_enter(&dev->mutex);
 
-	port->started = B_FALSE;
 	port->count = 0;
-	*fragfrp = port->fragfr;
-	*nfragsp = AUDIGYLS_NUM_FRAGS;
+	*nframesp = port->buf_frames;
 	*bufp = port->buf_kaddr;
-	audigyls_reset_port(port);
 	mutex_exit(&dev->mutex);
 
 	return (0);
@@ -417,13 +328,7 @@
 void
 audigyls_close(void *arg)
 {
-	audigyls_port_t *port = arg;
-	audigyls_dev_t	 *dev = port->dev;
-
-	mutex_enter(&dev->mutex);
-	audigyls_stop_port(port);
-	port->started = B_FALSE;
-	mutex_exit(&dev->mutex);
+	_NOTE(ARGUNUSED(arg));
 }
 
 int
@@ -431,12 +336,41 @@
 {
 	audigyls_port_t *port = arg;
 	audigyls_dev_t	*dev = port->dev;
+	uint32_t	tmp;
 
 	mutex_enter(&dev->mutex);
-	if (!port->started) {
-		audigyls_start_port(port);
-		port->started = B_TRUE;
+
+	port->offset = 0;
+
+	switch (port->direction) {
+	case AUDIGYLS_PLAY_PORT:
+		write_chan(dev, PTCA, 0, 0);
+		write_chan(dev, CPFA, 0, 0);
+		write_chan(dev, CPCAV, 0, 0);
+		write_chan(dev, PTCA, 1, 0);
+		write_chan(dev, CPFA, 1, 0);
+		write_chan(dev, CPCAV, 1, 0);
+		write_chan(dev, PTCA, 3, 0);
+		write_chan(dev, CPFA, 3, 0);
+		write_chan(dev, CPCAV, 3, 0);
+
+		tmp = read_reg(dev, SA);
+		tmp |= SA_SPA(0);
+		tmp |= SA_SPA(1);
+		tmp |= SA_SPA(3);
+		write_reg(dev, SA, tmp);
+		break;
+
+	case AUDIGYLS_REC_PORT:
+		write_chan(dev, CRFA, 2, 0);
+		write_chan(dev, CRCAV, 2, 0);
+
+		tmp = read_reg(dev, SA);
+		tmp |= SA_SRA(2);
+		write_reg(dev, SA, tmp);
+		break;
 	}
+
 	mutex_exit(&dev->mutex);
 	return (0);
 }
@@ -446,12 +380,26 @@
 {
 	audigyls_port_t	*port = arg;
 	audigyls_dev_t	*dev = port->dev;
+	uint32_t	tmp;
 
 	mutex_enter(&dev->mutex);
-	if (port->started) {
-		audigyls_stop_port(port);
-		port->started = B_FALSE;
+
+	switch (port->direction) {
+	case AUDIGYLS_PLAY_PORT:
+		tmp = read_reg(dev, SA);
+		tmp &= ~SA_SPA(0);
+		tmp &= ~SA_SPA(1);
+		tmp &= ~SA_SPA(3);
+		write_reg(dev, SA, tmp);
+		break;
+
+	case AUDIGYLS_REC_PORT:
+		tmp = read_reg(dev, SA);
+		tmp &= ~SA_SRA(2);
+		write_reg(dev, SA, tmp);
+		break;
 	}
+
 	mutex_exit(&dev->mutex);
 }
 
@@ -494,10 +442,27 @@
 	audigyls_port_t	*port = arg;
 	audigyls_dev_t	*dev = port->dev;
 	uint64_t	count;
+	uint32_t	offset, n;
 
 	mutex_enter(&dev->mutex);
-	if (!dev->suspended)
-		audigyls_update_port(port);
+
+	if (port->direction == AUDIGYLS_PLAY_PORT) {
+		offset = read_chan(dev, CPFA, 0);
+	} else {
+		offset = read_chan(dev, CRFA, 2);
+	}
+
+	/* get the offset, and switch to frames */
+	offset /= (2 * sizeof (uint16_t));
+
+	if (offset >= port->offset) {
+		n = offset - port->offset;
+	} else {
+		n = offset + (port->buf_frames - port->offset);
+	}
+	port->offset = offset;
+	port->count += n;
+
 	count = port->count;
 	mutex_exit(&dev->mutex);
 	return (count);
@@ -519,107 +484,6 @@
 
 /* private implementation bits */
 
-void
-audigyls_start_port(audigyls_port_t *port)
-{
-	audigyls_dev_t	*dev = port->dev;
-	uint32_t tmp;
-
-	ASSERT(mutex_owned(&dev->mutex));
-
-	if (dev->suspended || port->active)
-		return;
-
-	port->active = B_TRUE;
-	port->offset = 0;
-	dev->nactive++;
-
-	if (dev->nactive == 1) {
-		write_reg(dev, IT, dev->timer);
-		OUTL(dev, IER, INL(dev, IER) | INTR_IT1);
-	}
-
-	switch (port->direction) {
-	case AUDIGYLS_PLAY_PORT:
-		tmp = read_reg(dev, SA);
-		tmp |= SA_SPA(0);
-		tmp |= SA_SPA(1);
-		tmp |= SA_SPA(3);
-		write_reg(dev, SA, tmp);
-		break;
-
-	case AUDIGYLS_REC_PORT:
-		tmp = read_reg(dev, SA);
-		tmp |= SA_SRA(2);
-		write_reg(dev, SA, tmp);
-		break;
-	}
-
-}
-
-void
-audigyls_stop_port(audigyls_port_t *port)
-{
-	audigyls_dev_t	*dev = port->dev;
-	uint32_t tmp;
-
-	if (dev->suspended || !port->active)
-		return;
-
-	port->active = B_FALSE;
-	dev->nactive--;
-
-	switch (port->direction) {
-	case AUDIGYLS_PLAY_PORT:
-		tmp = read_reg(dev, SA);
-		tmp &= ~SA_SPA(0);
-		tmp &= ~SA_SPA(1);
-		tmp &= ~SA_SPA(3);
-		write_reg(dev, SA, tmp);
-		break;
-
-	case AUDIGYLS_REC_PORT:
-		tmp = read_reg(dev, SA);
-		tmp &= ~SA_SRA(2);
-		write_reg(dev, SA, tmp);
-		break;
-	}
-
-	if (dev->nactive == 0) {
-		OUTL(dev, IER, INL(dev, IER) & ~INTR_IT1);
-	}
-}
-
-void
-audigyls_reset_port(audigyls_port_t *port)
-{
-	audigyls_dev_t	*dev = port->dev;
-
-	ASSERT(mutex_owned(&dev->mutex));
-
-	if (dev->suspended)
-		return;
-
-	switch (port->direction) {
-	case AUDIGYLS_PLAY_PORT:
-		write_chan(dev, PTCA, 0, 0);
-		write_chan(dev, CPFA, 0, 0);
-		write_chan(dev, CPCAV, 0, 0);
-		write_chan(dev, PTCA, 1, 0);
-		write_chan(dev, CPFA, 1, 0);
-		write_chan(dev, CPCAV, 1, 0);
-		write_chan(dev, PTCA, 3, 0);
-		write_chan(dev, CPFA, 3, 0);
-		write_chan(dev, CPCAV, 3, 0);
-		break;
-
-	case AUDIGYLS_REC_PORT:
-		write_chan(dev, CRFA, 2, 0);
-		write_chan(dev, CRCAV, 2, 0);
-		break;
-	}
-}
-
 int
 audigyls_alloc_port(audigyls_dev_t *dev, int num)
 {
@@ -635,7 +499,6 @@
 	port = kmem_zalloc(sizeof (*port), KM_SLEEP);
 	dev->port[num] = port;
 	port->dev = dev;
-	port->started = B_FALSE;
 	port->direction = num;
 
 	switch (num) {
@@ -655,15 +518,8 @@
 		return (DDI_FAILURE);
 	}
 
-	/* figure out fragment configuration */
-	port->fragfr = 48000 / dev->intrs;
-	/* we want to make sure that we are aligning on reasonable chunks */
-	port->fragfr = (port->fragfr + 63) & ~(63);
-
-	/* 16 bit frames */
-	port->fragsz = port->fragfr * 2 * port->nchan;
-	port->buf_size = port->fragsz * AUDIGYLS_NUM_FRAGS;
-	port->buf_frames = port->fragfr * AUDIGYLS_NUM_FRAGS;
+	port->buf_frames = 2048;
+	port->buf_size = port->buf_frames * port->nchan * sizeof (int16_t);
 
 	/* Alloc buffers */
 	if (ddi_dma_alloc_handle(dev->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL,
@@ -699,42 +555,6 @@
 	return (DDI_SUCCESS);
 }
 
-int
-audigyls_setup_intrs(audigyls_dev_t *dev)
-{
-	uint_t			ipri;
-	int			actual;
-	int			rv;
-	ddi_intr_handle_t	ih[1];
-
-	rv = ddi_intr_alloc(dev->dip, ih, DDI_INTR_TYPE_FIXED,
-	    0, 1, &actual, DDI_INTR_ALLOC_STRICT);
-	if ((rv != DDI_SUCCESS) || (actual != 1)) {
-		audio_dev_warn(dev->adev,
-		    "Can't alloc interrupt handle (rv %d actual %d)",
-		    rv, actual);
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_get_pri(ih[0], &ipri) != DDI_SUCCESS) {
-		audio_dev_warn(dev->adev, "Can't get interrupt priority");
-		(void) ddi_intr_free(ih[0]);
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_add_handler(ih[0], audigyls_intr, dev, NULL) !=
-	    DDI_SUCCESS) {
-		audio_dev_warn(dev->adev, "Can't add interrupt handler");
-		(void) ddi_intr_free(ih[0]);
-		return (DDI_FAILURE);
-	}
-
-	dev->ih = ih[0];
-	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-	mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-	return (DDI_SUCCESS);
-}
-
 void
 audigyls_del_controls(audigyls_dev_t *dev)
 {
@@ -749,17 +569,8 @@
 void
 audigyls_destroy(audigyls_dev_t *dev)
 {
-	if (dev->ih != NULL) {
-		(void) ddi_intr_disable(dev->ih);
-		(void) ddi_intr_remove_handler(dev->ih);
-		(void) ddi_intr_free(dev->ih);
-		mutex_destroy(&dev->mutex);
-		mutex_destroy(&dev->low_mutex);
-	}
-
-	if (dev->ksp) {
-		kstat_delete(dev->ksp);
-	}
+	mutex_destroy(&dev->mutex);
+	mutex_destroy(&dev->low_mutex);
 
 	for (int i = 0; i < AUDIGYLS_NUM_PORT; i++) {
 		audigyls_port_t *port = dev->port[i];
@@ -868,7 +679,7 @@
 		}
 	}
 
-	OUTL(dev, IER, INTR_PCI);
+	OUTL(dev, IER, 0);
 	OUTL(dev, HC, 0x00000009);	/* Enable audio, use 48 kHz */
 
 	tmp = read_chan(dev, SRCTL, 0);
@@ -1051,7 +862,7 @@
 	if (dev->controls[CTL_LOOP].val) {
 		r = 0;
 		v1 = RECSEL_I2SOUT;
-		r |= (v1 << 28) | (v1 << 24) | (v1 << 20) | (v1 << 16) | v2;
+		r |= (v1 << 28) | (v1 << 24) | (v1 << 20) | (v1 << 16) | v1;
 	} else {
 		/*
 		 * You'd think this would be the same as the logic
@@ -1119,9 +930,8 @@
 
 	mutex_enter(&dev->mutex);
 	pc->val = val;
-	if (!dev->suspended) {
-		audigyls_configure_mixer(dev);
-	}
+	audigyls_configure_mixer(dev);
+
 	mutex_exit(&dev->mutex);
 
 	return (0);
@@ -1300,6 +1110,8 @@
 	dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
 	dev->dip = dip;
 	ddi_set_driver_private(dip, dev);
+	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, NULL);
 
 	if ((dev->adev = audio_dev_alloc(dip, 0)) == NULL) {
 		cmn_err(CE_WARN, "audio_dev_alloc failed");
@@ -1338,27 +1150,6 @@
 	dev->digital_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
 	    DDI_PROP_DONTPASS, "digital-enable", 0);
 
-	if (audigyls_setup_intrs(dev) != DDI_SUCCESS)
-		goto error;
-
-	dev->intrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, "interrupt-rate", AUDIGYLS_INTRS);
-
-	/* make sure the values are good */
-	if (dev->intrs < AUDIGYLS_MIN_INTRS) {
-		audio_dev_warn(dev->adev,
-		    "interrupt-rate too low, %d, reset to %d",
-		    dev->intrs, AUDIGYLS_INTRS);
-		dev->intrs = AUDIGYLS_INTRS;
-	} else if (dev->intrs > AUDIGYLS_MAX_INTRS) {
-		audio_dev_warn(dev->adev,
-		    "interrupt-rate too high, %d, reset to %d",
-		    dev->intrs, AUDIGYLS_INTRS);
-		dev->intrs = AUDIGYLS_INTRS;
-	}
-
-	dev->timer = (192000 / dev->intrs) << 16;
-
 	switch (subdevice) {
 	case 0x11021001:	/* SB0310 */
 	case 0x11021002:	/* SB0310 */
@@ -1453,19 +1244,11 @@
 
 	audigyls_configure_mixer(dev);
 
-	/* set up kernel statistics */
-	if ((dev->ksp = kstat_create(AUDIGYLS_NAME, ddi_get_instance(dip),
-	    AUDIGYLS_NAME, "controller", KSTAT_TYPE_INTR, 1,
-	    KSTAT_FLAG_PERSISTENT)) != NULL) {
-		kstat_install(dev->ksp);
-	}
-
 	if (audio_dev_register(dev->adev) != DDI_SUCCESS) {
 		audio_dev_warn(dev->adev, "unable to register with framework");
 		goto error;
 	}
 
-	(void) ddi_intr_enable(dev->ih);
 	ddi_report_dev(dip);
 
 	return (DDI_SUCCESS);
@@ -1479,38 +1262,17 @@
 audigyls_resume(dev_info_t *dip)
 {
 	audigyls_dev_t *dev;
-	audigyls_port_t *port;
 
 	dev = ddi_get_driver_private(dip);
 
-	for (int i = 0; i < AUDIGYLS_NUM_PORT; i++) {
-		port = dev->port[i];
-		audio_engine_reset(port->engine);
-	}
-
 	audigyls_hwinit(dev);
 
 	/* allow ac97 operations again */
 	if (dev->ac97)
-		ac97_resume(dev->ac97);
-
-	audigyls_configure_mixer(dev);
-
-	mutex_enter(&dev->mutex);
-	dev->suspended = B_FALSE;
-
-	for (int i = 0; i < AUDIGYLS_NUM_PORT; i++) {
+		ac97_reset(dev->ac97);
 
-		port = dev->port[i];
-
-		audigyls_reset_port(port);
+	audio_dev_resume(dev->adev);
 
-		if (port->started) {
-			audigyls_start_port(port);
-		}
-	}
-
-	mutex_exit(&dev->mutex);
 	return (DDI_SUCCESS);
 }
 
@@ -1527,17 +1289,8 @@
 int
 audigyls_suspend(audigyls_dev_t *dev)
 {
-	if (dev->ac97)
-		ac97_suspend(dev->ac97);
-
-	mutex_enter(&dev->mutex);
-	for (int i = 0; i < AUDIGYLS_NUM_PORT; i++) {
+	audio_dev_suspend(dev->adev);
 
-		audigyls_port_t *port = dev->port[i];
-		audigyls_stop_port(port);
-	}
-	dev->suspended = B_TRUE;
-	mutex_exit(&dev->mutex);
 	return (DDI_SUCCESS);
 }
 
@@ -1640,17 +1393,10 @@
 	audigyls_dev_t	*dev;
 	uint32_t status;
 
-	dev = ddi_get_driver_private(dip);
-
-	for (int i = 0; i < AUDIGYLS_NUM_PORT; i++) {
-
-		audigyls_port_t *port = dev->port[i];
-		audigyls_stop_port(port);
-	}
-
 	/*
 	 * Turn off the hardware
 	 */
+	dev = ddi_get_driver_private(dip);
 
 	write_reg(dev, SA, 0);
 	OUTL(dev, IER, 0);	/* Interrupt disable */
--- a/usr/src/uts/common/io/audio/drv/audiols/audiols.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiols/audiols.h	Tue Mar 16 09:30:41 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -45,20 +45,9 @@
 #define	AUDIGYLS_PLAY_PORT	0
 #define	AUDIGYLS_REC_PORT	1
 
-/*
- * Number of fragments must be multiple of 2 because the
- * hardware supports only full and half buffer interrupts. In
- * addition it looks like 8 fragments is the minimum.
- */
-#define	AUDIGYLS_NUM_FRAGS		(8*2)
-
 #define	PCI_VENDOR_ID_CREATIVE 		0x1102
 #define	PCI_DEVICE_ID_CREATIVE_AUDIGYLS 0x0007
 
-#define	AUDIGYLS_MAX_INTRS		256
-#define	AUDIGYLS_MIN_INTRS		24
-#define	AUDIGYLS_INTRS			100
-
 /*
  * PCI registers
  */
@@ -216,11 +205,7 @@
 	audio_engine_t *engine;
 
 	int			direction;
-	int			started;
-	boolean_t		active;
 
-	unsigned		fragfr;
-	unsigned		fragsz;
 	unsigned		nchan;
 
 	ddi_dma_handle_t	buf_dmah;	/* dma for buffers */
@@ -239,20 +224,15 @@
 	dev_info_t		*dip;
 	audio_dev_t		*adev;
 	ac97_t			*ac97;
-	kstat_t			*ksp;
-	unsigned		intrs;
-	unsigned		timer;
 
 	int			nactive;	/* Num active ports */
 	char			digital_enable;	/* Orange combo-jack mode */
 
-	boolean_t		suspended;
 	ddi_acc_handle_t	pcih;
 	ddi_acc_handle_t	regsh;
 	caddr_t			base;
 	kmutex_t		mutex;		/* For normal locking */
 	kmutex_t		low_mutex;	/* For low level routines */
-	ddi_intr_handle_t	ih;
 
 	audigyls_port_t		*port[AUDIGYLS_NUM_PORT];
 	audigyls_ctrl_t		controls[CTL_NUM];
@@ -277,6 +257,4 @@
 #define	OUTL(dev, reg, val)	\
 	ddi_put32(dev->regsh, (void *)(dev->base + reg), (val))
 
-#define	AUDIGYLS_KIOP(X)	((kstat_intr_t *)(X->ksp->ks_data))
-
 #endif /* AUDIGYLS_H */
--- a/usr/src/uts/common/io/audio/drv/audiop16x/audiop16x.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiop16x/audiop16x.c	Tue Mar 16 09:30:41 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -95,7 +95,7 @@
 static int p16x_detach(p16x_dev_t *);
 static int p16x_suspend(p16x_dev_t *);
 
-static int p16x_open(void *, int, unsigned *, unsigned *, caddr_t *);
+static int p16x_open(void *, int, unsigned *, caddr_t *);
 static void p16x_close(void *);
 static int p16x_start(void *);
 static void p16x_stop(void *);
@@ -109,13 +109,8 @@
 static uint16_t p16x_read_ac97(void *, uint8_t);
 static void p16x_write_ac97(void *, uint8_t, uint16_t);
 static int p16x_alloc_port(p16x_dev_t *, int);
-static void p16x_update_port(p16x_port_t *);
-static void p16x_start_port(p16x_port_t *);
-static void p16x_stop_port(p16x_port_t *);
 static void p16x_destroy(p16x_dev_t *);
-static int p16x_setup_intrs(p16x_dev_t *);
 static void p16x_hwinit(p16x_dev_t *);
-static uint_t p16x_intr(caddr_t, caddr_t);
 
 static audio_engine_ops_t p16x_engine_ops = {
 	AUDIO_ENGINE_VERSION,
@@ -138,10 +133,10 @@
 {
 	unsigned int val;
 
-	mutex_enter(&dev->low_mutex);
+	mutex_enter(&dev->mutex);
 	OUTL(dev, (reg << 16) | (chn & 0xffff), PTR);	/* Pointer */
 	val = INL(dev, DR);	/* Data */
-	mutex_exit(&dev->low_mutex);
+	mutex_exit(&dev->mutex);
 
 	return (val);
 }
@@ -150,10 +145,34 @@
 write_reg(p16x_dev_t *dev, int reg, int chn, unsigned int value)
 {
 
-	mutex_enter(&dev->low_mutex);
+	mutex_enter(&dev->mutex);
 	OUTL(dev, (reg << 16) | (chn & 0xffff), PTR);	/* Pointer */
 	OUTL(dev, value, DR);	/* Data */
-	mutex_exit(&dev->low_mutex);
+	mutex_exit(&dev->mutex);
+}
+
+static void
+set_reg_bits(p16x_dev_t *dev, int reg, int chn, unsigned int mask)
+{
+	unsigned int	val;
+	mutex_enter(&dev->mutex);
+	OUTL(dev, (reg << 16) | (chn & 0xffff), PTR);	/* Pointer */
+	val = INL(dev, DR);	/* Data */
+	val |= mask;
+	OUTL(dev, val, DR);	/* Data */
+	mutex_exit(&dev->mutex);
+}
+
+static void
+clear_reg_bits(p16x_dev_t *dev, int reg, int chn, unsigned int mask)
+{
+	unsigned int	val;
+	mutex_enter(&dev->mutex);
+	OUTL(dev, (reg << 16) | (chn & 0xffff), PTR);	/* Pointer */
+	val = INL(dev, DR);	/* Data */
+	val &= ~(mask);
+	OUTL(dev, val, DR);	/* Data */
+	mutex_exit(&dev->mutex);
 }
 
 static uint16_t
@@ -163,13 +182,11 @@
 	uint16_t value;
 	int i;
 
-	mutex_enter(&dev->low_mutex);
 	OUTB(dev, index, AC97A);
 	for (i = 0; i < 10000; i++)
 		if (INB(dev, AC97A) & 0x80)
 			break;
 	value = INW(dev, AC97D);
-	mutex_exit(&dev->low_mutex);
 	return (value);
 }
 
@@ -179,83 +196,51 @@
 	p16x_dev_t *dev = arg;
 	unsigned int i;
 
-	mutex_enter(&dev->low_mutex);
 	OUTB(dev, index, AC97A);
 	for (i = 0; i < 10000; i++)
 		if (INB(dev, AC97A) & 0x80)
 			break;
 	OUTW(dev, data, AC97D);
-	mutex_exit(&dev->low_mutex);
-}
-
-static uint_t
-p16x_intr(caddr_t argp, caddr_t nocare)
-{
-	p16x_dev_t	*dev = (void *)argp;
-	unsigned int	status;
-	audio_engine_t	*consume = NULL;
-	audio_engine_t	*produce = NULL;
-
-	_NOTE(ARGUNUSED(nocare));
-
-	mutex_enter(&dev->mutex);
-	if (dev->suspended) {
-		mutex_exit(&dev->mutex);
-		return (DDI_INTR_UNCLAIMED);
-	}
-	/* Read the interrupt status */
-	status = INL(dev, IP);
-	OUTL(dev, status, IP);	/* Acknowledge */
-
-	if (!(status & INTR_ALL)) {
-		mutex_exit(&dev->mutex);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	if (status & INTR_PCI) {
-		audio_dev_warn(dev->adev, "PCI error triggered, PCI status %x",
-		    pci_config_get16(dev->pcih, PCI_CONF_STAT));
-	}
-
-	if ((status & (INTR_PFF | INTR_PFH)) &&
-	    (dev->port[P16X_PLAY]->started)) {
-		consume = dev->port[P16X_PLAY]->engine;
-	}
-
-	if ((status & (INTR_RFF | INTR_RFH)) &&
-	    (dev->port[P16X_REC]->started)) {
-		produce = dev->port[P16X_REC]->engine;
-	}
-
-	mutex_exit(&dev->mutex);
-
-	if (consume) {
-		audio_engine_consume(consume);
-	}
-
-	if (produce) {
-		audio_engine_produce(produce);
-	}
-
-	return (DDI_INTR_CLAIMED);
 }
 
 /*
  * Audio routines
  */
 
-static void
-p16x_init_port(p16x_port_t *port)
+int
+p16x_open(void *arg, int flag, uint_t *nframes, caddr_t *bufp)
 {
+	p16x_port_t	*port = arg;
+
+	_NOTE(ARGUNUSED(flag));
+
+	port->count = 0;
+	*nframes = port->buf_frames;
+	*bufp = port->buf_kaddr;
+
+	return (0);
+}
+
+void
+p16x_close(void *arg)
+{
+	_NOTE(ARGUNUSED(arg));
+}
+
+int
+p16x_start(void *arg)
+{
+	p16x_port_t	*port = arg;
 	p16x_dev_t	*dev = port->dev;
 
-	if (port->suspended)
-		return;
+	port->offset = 0;
 
 	if (port->port_num == P16X_REC) {
 		write_reg(dev, CRFA, 0, 0);
 		write_reg(dev, CRCAV, 0, 0);
 
+		/* Enable rec channel */
+		set_reg_bits(dev, SA, 0, 0x100);
 	} else {
 		for (int i = 0; i < 3; i++) {
 			write_reg(dev, PTBA, i, 0);
@@ -266,73 +251,27 @@
 			write_reg(dev, CPCAV, i, 0);
 		}
 
+		/* Enable play channel */
+		set_reg_bits(dev, SA, 0, 0x7);
 	}
-}
-
-
-static int
-p16x_open(void *arg, int flag, uint_t *fragfrp, uint_t *nfp, caddr_t *bufp)
-{
-	p16x_port_t	*port = arg;
-	p16x_dev_t	*dev = port->dev;
-
-	_NOTE(ARGUNUSED(flag));
-
-	mutex_enter(&dev->mutex);
-
-	port->started = B_FALSE;
-	port->count = 0;
-	port->offset = 0;
-
-	p16x_init_port(port);
-
-	*fragfrp = port->fragfr;
-	*nfp = port->nfrags;
-	*bufp = port->buf_kaddr;
-	mutex_exit(&dev->mutex);
 
 	return (0);
 }
 
 void
-p16x_close(void *arg)
-{
-	p16x_port_t	 *port = arg;
-	p16x_dev_t	 *dev = port->dev;
-
-	mutex_enter(&dev->mutex);
-	p16x_stop_port(port);
-	port->started = B_FALSE;
-	mutex_exit(&dev->mutex);
-}
-
-int
-p16x_start(void *arg)
-{
-	p16x_port_t	*port = arg;
-	p16x_dev_t	*dev = port->dev;
-
-	mutex_enter(&dev->mutex);
-	if (!port->started) {
-		p16x_start_port(port);
-		port->started = B_TRUE;
-	}
-	mutex_exit(&dev->mutex);
-	return (0);
-}
-
-void
 p16x_stop(void *arg)
 {
 	p16x_port_t	*port = arg;
 	p16x_dev_t	*dev = port->dev;
 
-	mutex_enter(&dev->mutex);
-	if (port->started) {
-		p16x_stop_port(port);
-		port->started = B_FALSE;
+	if (port->port_num == P16X_REC) {
+		/* Disable rec channel */
+		clear_reg_bits(dev, SA, 0, 0x100);
+
+	} else {
+		/* Disable Play channel */
+		clear_reg_bits(dev, SA, 0, 0x7);
 	}
-	mutex_exit(&dev->mutex);
 }
 
 int
@@ -374,12 +313,25 @@
 	p16x_port_t	*port = arg;
 	p16x_dev_t	*dev = port->dev;
 	uint64_t	val;
+	uint32_t	offset, n;
 
-	mutex_enter(&dev->mutex);
-	if (port->started && !dev->suspended)
-		p16x_update_port(port);
+	if (port->port_num == P16X_PLAY) {
+		offset = read_reg(dev, CPFA, 0);
+	} else {
+		offset = read_reg(dev, CRFA, 0);
+	}
+
+	/* get the offset, and switch to frames */
+	offset /= (2 * sizeof (uint16_t));
+
+	if (offset >= port->offset) {
+		n = offset - port->offset;
+	} else {
+		n = offset + (port->buf_frames - port->offset);
+	}
+	port->offset = offset;
+	port->count += n;
 	val = port->count;
-	mutex_exit(&dev->mutex);
 
 	return (val);
 }
@@ -415,93 +367,6 @@
 
 /* private implementation bits */
 
-void
-p16x_update_port(p16x_port_t *port)
-{
-	p16x_dev_t	*dev = port->dev;
-	uint32_t	offset, n;
-
-	if (dev->suspended)
-		return;
-
-	if (port->port_num == P16X_PLAY) {
-		offset = read_reg(dev, CPFA, 0);
-	} else {
-		offset = read_reg(dev, CRFA, 0);
-	}
-
-	/* get the offset, and switch to frames */
-	offset /= (2 * sizeof (uint16_t));
-
-	if (offset >= port->offset) {
-		n = offset - port->offset;
-	} else {
-		n = offset + (port->buf_frames - port->offset);
-	}
-	port->offset = offset;
-	port->count += n;
-}
-
-void
-p16x_start_port(p16x_port_t *port)
-{
-	p16x_dev_t	*dev = port->dev;
-	unsigned int	tmp;
-
-	ASSERT(mutex_owned(&dev->mutex));
-
-	if (dev->suspended)
-		return;
-
-	if (port->port_num == P16X_REC) {
-		/* Enable Rec Channel */
-		tmp = read_reg(dev, SA, 0);
-		tmp |= 0x100;
-		write_reg(dev, SA, 0, tmp);
-		tmp = INL(dev, IE);
-		tmp |= INTR_REC;
-		OUTL(dev, tmp, IE);
-	} else {
-		/* Enable play channel and go */
-		tmp = read_reg(dev, SA, 0);
-		tmp |= 7;
-		write_reg(dev, SA, 0, tmp);
-		tmp = INL(dev, IE);
-		tmp |= INTR_PLAY;
-		OUTL(dev, tmp, IE);
-	}
-}
-
-void
-p16x_stop_port(p16x_port_t *port)
-{
-	p16x_dev_t	*dev = port->dev;
-	unsigned int tmp;
-
-
-	if (dev->suspended)
-		return;
-
-	if (port->port_num == P16X_REC) {
-		/* Disable rec channel */
-		tmp = read_reg(dev, SA, 0);
-		tmp &= ~0x100;
-		write_reg(dev, SA, 0, tmp);
-		tmp = INL(dev, IE);
-		tmp &= ~INTR_REC;
-		OUTL(dev, tmp, IE);
-
-	} else {
-		/* Disable Play channel */
-		tmp = read_reg(dev, SA, 0);
-		tmp &= ~7;
-		write_reg(dev, SA, 0, tmp);
-		tmp = INL(dev, IE);
-		tmp &= ~INTR_PLAY;
-		OUTL(dev, tmp, IE);
-	}
-}
-
 int
 p16x_alloc_port(p16x_dev_t *dev, int num)
 {
@@ -510,7 +375,6 @@
 	ddi_dma_cookie_t	cookie;
 	uint_t			count;
 	int			dir;
-	char			*prop;
 	unsigned		caps;
 	audio_dev_t		*adev;
 
@@ -518,11 +382,9 @@
 	port = kmem_zalloc(sizeof (*port), KM_SLEEP);
 	dev->port[num] = port;
 	port->dev = dev;
-	port->started = B_FALSE;
 
 	switch (num) {
 	case P16X_REC:
-		prop = "record-interrupts";
 		port->syncdir = DDI_DMA_SYNC_FORKERNEL;
 		caps = ENGINE_INPUT_CAP;
 		dir = DDI_DMA_READ;
@@ -530,7 +392,6 @@
 		port->nchan = 2;
 		break;
 	case P16X_PLAY:
-		prop = "play-interrupts";
 		port->syncdir = DDI_DMA_SYNC_FORDEV;
 		caps = ENGINE_OUTPUT_CAP;
 		dir = DDI_DMA_WRITE;
@@ -541,37 +402,16 @@
 		return (DDI_FAILURE);
 	}
 
-	/* figure out fragment configuration */
-	port->intrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, prop, P16X_DEF_INTRS);
-
-	/* make sure the values are good */
-	if (port->intrs < P16X_MIN_INTRS) {
-		audio_dev_warn(adev, "%s too low, %d, reset to %d",
-		    prop, port->intrs, P16X_MIN_INTRS);
-		port->intrs = P16X_MIN_INTRS;
-	} else if (port->intrs > P16X_MAX_INTRS) {
-		audio_dev_warn(adev, "%s too high, %d, reset to %d",
-		    prop, port->intrs, P16X_DEF_INTRS);
-		port->intrs = P16X_DEF_INTRS;
-	}
-
 	/*
-	 * This needs the very latest Boomer changes.
+	 * NB: The device operates in pairs of dwords at a time, for
+	 * performance reasons.  So make sure that our buffer is
+	 * arranged as a whole number of these.  The value below gives
+	 * a reasonably large buffer so we can support a deep
+	 * playahead if we need to (and we should avoid input
+	 * overruns.)
 	 */
-	port->nfrags = 2;
-	port->fragfr = 48000 / port->intrs;
-	/*
-	 * The device operates in pairs of dwords at a time, for
-	 * performance reasons.	 So make sure that our buffer is
-	 * arranged as a whole number of these.	 We could probably
-	 * fine tune by just ensuring that the overall buffer was 128
-	 * (64 for half and 64 for full), but this is simpler.
-	 */
-	port->fragfr = (port->fragfr + 63) & ~(63);
-	port->fragsz = port->fragfr * port->nchan * 2; /* 16 bit frames */
-	port->buf_size = port->nfrags * port->fragsz;
-	port->buf_frames = port->fragfr * port->nfrags;
+	port->buf_frames = 4096;
+	port->buf_size = port->buf_frames * port->nchan * sizeof (uint16_t);
 
 	/* now allocate buffers */
 	if (ddi_dma_alloc_handle(dev->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL,
@@ -610,17 +450,7 @@
 void
 p16x_destroy(p16x_dev_t *dev)
 {
-	if (dev->ih != NULL) {
-		(void) ddi_intr_disable(dev->ih);
-		(void) ddi_intr_remove_handler(dev->ih);
-		(void) ddi_intr_free(dev->ih);
-		mutex_destroy(&dev->mutex);
-		mutex_destroy(&dev->low_mutex);
-	}
-
-	if (dev->ksp) {
-		kstat_delete(dev->ksp);
-	}
+	mutex_destroy(&dev->mutex);
 
 	for (int i = 0; i < P16X_NUM_PORT; i++) {
 		p16x_port_t *port = dev->port[i];
@@ -709,42 +539,6 @@
 }
 
 int
-p16x_setup_intrs(p16x_dev_t *dev)
-{
-	uint_t			ipri;
-	int			actual;
-	int			rv;
-	ddi_intr_handle_t	ih[1];
-
-	rv = ddi_intr_alloc(dev->dip, ih, DDI_INTR_TYPE_FIXED,
-	    0, 1, &actual, DDI_INTR_ALLOC_STRICT);
-	if ((rv != DDI_SUCCESS) || (actual != 1)) {
-		audio_dev_warn(dev->adev,
-		    "Can't alloc interrupt handle (rv %d actual %d)",
-		    rv, actual);
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_get_pri(ih[0], &ipri) != DDI_SUCCESS) {
-		audio_dev_warn(dev->adev, "Can't get interrupt priority");
-		(void) ddi_intr_free(ih[0]);
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_add_handler(ih[0], p16x_intr, dev, NULL) !=
-	    DDI_SUCCESS) {
-		audio_dev_warn(dev->adev, "Can't add interrupt handler");
-		(void) ddi_intr_free(ih[0]);
-		return (DDI_FAILURE);
-	}
-
-	dev->ih = ih[0];
-	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-	mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-	return (DDI_SUCCESS);
-}
-
-int
 p16x_attach(dev_info_t *dip)
 {
 	uint16_t	vendor, device;
@@ -755,23 +549,7 @@
 	dev->dip = dip;
 	ddi_set_driver_private(dip, dev);
 
-	/* we don't support high level interrupts in the driver */
-	if (ddi_intr_hilevel(dip, 0) != 0) {
-		cmn_err(CE_WARN,
-		    "!%s%d: unsupported high level interrupt",
-		    ddi_driver_name(dip), ddi_get_instance(dip));
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_get_iblock_cookie(dip, 0, &dev->iblock) != DDI_SUCCESS) {
-		cmn_err(CE_WARN,
-		    "!%s%d: cannot get iblock cookie",
-		    ddi_driver_name(dip), ddi_get_instance(dip));
-		kmem_free(dev, sizeof (*dev));
-		return (DDI_FAILURE);
-	}
-	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, dev->iblock);
-	mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, dev->iblock);
+	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, NULL);
 
 	if ((dev->adev = audio_dev_alloc(dip, 0)) == NULL) {
 		cmn_err(CE_WARN, "audio_dev_alloc failed");
@@ -815,14 +593,6 @@
 
 	p16x_hwinit(dev);
 
-	/* set up the interrupt handler */
-	if (p16x_setup_intrs(dev) != DDI_SUCCESS) {
-		goto error;
-	}
-
-	/* Enable PCI interrupts */
-	OUTL(dev, INTR_PCI, IE);
-
 	dev->ac97 = ac97_allocate(dev->adev, dip,
 	    p16x_read_ac97, p16x_write_ac97, dev);
 	if (dev->ac97 == NULL) {
@@ -843,19 +613,11 @@
 
 	ac97_register_controls(dev->ac97);
 
-	/* set up kernel statistics */
-	if ((dev->ksp = kstat_create(P16X_NAME, ddi_get_instance(dip),
-	    P16X_NAME, "controller", KSTAT_TYPE_INTR, 1,
-	    KSTAT_FLAG_PERSISTENT)) != NULL) {
-		kstat_install(dev->ksp);
-	}
-
 	if (audio_dev_register(dev->adev) != DDI_SUCCESS) {
 		audio_dev_warn(dev->adev, "unable to register with framework");
 		goto error;
 	}
 
-	(void) ddi_intr_enable(dev->ih);
 	ddi_report_dev(dip);
 
 	return (DDI_SUCCESS);
@@ -874,29 +636,10 @@
 
 	p16x_hwinit(dev);
 
-	/* allow ac97 operations again */
-	ac97_resume(dev->ac97);
-
-	mutex_enter(&dev->mutex);
-	dev->suspended = B_FALSE;
-
-	for (int i = 0; i < P16X_NUM_PORT; i++) {
-
-		p16x_port_t *port = dev->port[i];
+	ac97_reset(dev->ac97);
 
-		if (port->engine != NULL)
-			audio_engine_reset(port->engine);
-
-		/* reset the port */
-		p16x_init_port(port);
+	audio_dev_resume(dev->adev);
 
-		if (port->started) {
-			p16x_start_port(port);
-		} else {
-			p16x_stop_port(port);
-		}
-	}
-	mutex_exit(&dev->mutex);
 	return (DDI_SUCCESS);
 }
 
@@ -913,21 +656,8 @@
 int
 p16x_suspend(p16x_dev_t *dev)
 {
-	ac97_suspend(dev->ac97);
-
-	mutex_enter(&dev->mutex);
-	for (int i = 0; i < P16X_NUM_PORT; i++) {
+	audio_dev_suspend(dev->adev);
 
-		p16x_port_t *port = dev->port[i];
-		p16x_stop_port(port);
-	}
-
-	write_reg(dev, SA, 0, 0);
-	OUTL(dev, 0x00, IE);	/* Interrupt disable */
-	OUTL(dev, 0x01, HC);
-
-	dev->suspended = B_TRUE;
-	mutex_exit(&dev->mutex);
 	return (DDI_SUCCESS);
 }
 
@@ -1031,14 +761,7 @@
 
 	dev = ddi_get_driver_private(dip);
 
-	for (int i = 0; i < P16X_NUM_PORT; i++) {
-
-		p16x_port_t *port = dev->port[i];
-		p16x_stop_port(port);
-	}
-
 	write_reg(dev, SA, 0, 0);
-	OUTL(dev, 0x00, IE);	    /* Interrupt disable */
 	OUTL(dev, 0x01, HC);
 
 	return (DDI_SUCCESS);
--- a/usr/src/uts/common/io/audio/drv/audiop16x/audiop16x.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiop16x/audiop16x.h	Tue Mar 16 09:30:41 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -46,10 +46,6 @@
 #define	CREATIVE_VENDOR_ID	0x1102
 #define	SB_P16X_ID		0x0006
 
-#define	P16X_MAX_INTRS	256
-#define	P16X_MIN_INTRS	24
-#define	P16X_DEF_INTRS	175
-
 typedef struct _p16x_dev_t p16x_dev_t;
 typedef struct _p16x_port_t p16x_port_t;
 
@@ -58,10 +54,7 @@
 	p16x_dev_t 		*dev;
 	audio_engine_t 		*engine;
 
-	unsigned		intrs;
 	caddr_t			base;
-	boolean_t		started;
-	boolean_t		suspended;
 
 	int			port_num;
 #define	P16X_PLAY		0
@@ -74,10 +67,6 @@
 	uint32_t		buf_frames;
 	int			syncdir;
 	int			nchan;
-	unsigned		fragfr;
-	unsigned		nfrags;
-	unsigned		fragsz;
-	unsigned		nframes;
 	uint64_t		count;
 	uint32_t		offset;
 };
@@ -87,16 +76,11 @@
 	dev_info_t		*dip;
 	audio_dev_t		*adev;
 	ac97_t			*ac97;
-	kstat_t			*ksp;
-	ddi_iblock_cookie_t	iblock;
 	boolean_t		suspended;
-	boolean_t		intr_added;
 	ddi_acc_handle_t	pcih;
 	ddi_acc_handle_t	regsh;
 	caddr_t			base;
-	kmutex_t		mutex;		/* For normal locking */
-	kmutex_t		low_mutex;	/* For low level routines */
-	ddi_intr_handle_t	ih;
+	kmutex_t		mutex;	/* For low level routines */
 
 	p16x_port_t 		*port[P16X_NUM_PORT];
 };
@@ -115,8 +99,6 @@
 #define	OUTB(dev, val, reg)	\
 	ddi_put8(dev->regsh, (void *)((char *)dev->base+(reg)), (val))
 
-#define	P16X_KIOP(X)	((kstat_intr_t *)(X->ksp->ks_data))
-
 /*
  * SB P16X Registers
  */
--- a/usr/src/uts/common/io/audio/drv/audiopci/audiopci.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiopci/audiopci.c	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
@@ -53,7 +53,6 @@
 #define	CREATIVE_VENDOR_ID	0x1102
 #define	ENSONIQ_ES1370		0x5000
 
-#define	DEFINTS			75
 #define	DRVNAME			"audiopci"
 
 #define	INPUT_MIC	0
@@ -75,8 +74,6 @@
 typedef struct audiopci_port
 {
 	/* Audio parameters */
-	boolean_t		trigger;
-
 	int			speed;
 	int			fmt;
 
@@ -90,14 +87,12 @@
 	uint32_t		paddr;
 	ddi_acc_handle_t	acch;
 	ddi_dma_handle_t	dmah;
-	unsigned		fragfr;
-	unsigned		nfrags;
 	unsigned		nframes;
 	unsigned		frameno;
 	uint64_t		count;
 
 	struct audiopci_dev	*dev;
-	audio_engine_t	*engine;
+	audio_engine_t		*engine;
 } audiopci_port_t;
 
 typedef enum {
@@ -130,11 +125,6 @@
 	kmutex_t		mutex;
 	uint16_t		devid;
 	dev_info_t		*dip;
-	boolean_t		enabled;
-	boolean_t		suspended;
-
-	int			pintrs;
-	int			rintrs;
 
 	uint8_t			ak_regs[0x20];
 	int			micbias;
@@ -147,14 +137,11 @@
 	audiopci_ctrl_t		*micbias;
 #endif
 
-	kstat_t			*ksp;
-
 	audiopci_port_t		port[PORT_MAX + 1];
 
 
 	caddr_t			regs;
 	ddi_acc_handle_t	acch;
-	ddi_intr_handle_t	ihandle[1];
 } audiopci_dev_t;
 
 static ddi_device_acc_attr_t acc_attr = {
@@ -171,15 +158,9 @@
 
 /*
  * The hardware appears to be able to address up to 16-bits worth of longwords,
- * giving a total address space of 256K.  Note, however, that we will restrict
- * this further when we do fragment and memory allocation.  At its very highest
- * clock rate (48 kHz) and sample size (16-bit stereo), and lowest interrupt
- * rate (32 Hz), we only need 6000 bytes per fragment.
- *
- * So with an allocated buffer size of 64K, we can support at least 10 frags,
- * which is more than enough.  (The legacy Sun driver used only 2 fragments.)
+ * giving a total address space of 256K.  But we need substantially less.
  */
-#define	AUDIOPCI_BUF_LEN	(65536)
+#define	AUDIOPCI_BUF_LEN	(16384)
 
 static ddi_dma_attr_t dma_attr = {
 	DMA_ATTR_VERSION,	/* dma_attr_version */
@@ -214,13 +195,8 @@
 #define	CLR16(dev, offset, v)	PUT16(dev, offset, GET16(dev, offset) & ~(v))
 #define	SET16(dev, offset, v)	PUT16(dev, offset, GET16(dev, offset) | (v))
 
-#define	KSINTR(dev)	((kstat_intr_t *)((dev)->ksp->ks_data))
-
 static void audiopci_init_hw(audiopci_dev_t *);
 static void audiopci_init_port(audiopci_port_t *);
-static void audiopci_start_port(audiopci_port_t *);
-static void audiopci_stop_port(audiopci_port_t *);
-static void audiopci_update_port(audiopci_port_t *);
 static uint16_t audiopci_dac_rate(int);
 static int audiopci_add_controls(audiopci_dev_t *);
 static void audiopci_del_controls(audiopci_dev_t *);
@@ -252,9 +228,6 @@
 {
 	uint8_t	wstat;
 
-	if (dev->suspended)
-		return;
-
 	/* shadow the value */
 	dev->ak_regs[addr] = data;
 
@@ -284,111 +257,6 @@
 	return (GET32(dev, offs));
 }
 
-static uint_t
-audiopci_intr(caddr_t arg1, caddr_t arg2)
-{
-	audiopci_dev_t *dev = (void *)arg1;
-	int stats;
-	int tmp;
-	unsigned char ackbits = 0;
-	audiopci_port_t *port;
-	audio_engine_t *do_syn, *do_dac, *do_adc;
-
-	_NOTE(ARGUNUSED(arg2));
-
-	/*
-	 * NB: The old driver didn't report spurious interrupts.  On
-	 * a system with shared interrupts (typical!) there will
-	 * normally be lots of these (each time the "other" device
-	 * interrupts).
-	 *
-	 * Also, because of the way the interrupt chain handling
-	 * works, reporting of spurious interrupts is probably not
-	 * terribly useful.
-	 *
-	 * However, we can count interrupts where the master interrupt
-	 * bit is set but none of the ackbits that we are prepared to
-	 * process is set.  That is probably useful.
-	 */
-	mutex_enter(&dev->mutex);
-	if (!dev->enabled) {
-
-		mutex_exit(&dev->mutex);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	stats = GET32(dev, CONC_dSTATUS_OFF);
-
-	if (!(stats & CONC_INTSTAT_PENDING)) {	/* No interrupt pending */
-		mutex_exit(&dev->mutex);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	do_syn = do_dac = do_adc = NULL;
-
-	/* synth interrupt */
-	if (stats & CONC_INTSTAT_SYNINT) {
-
-		ackbits |= CONC_SERCTL_SYNIE;
-		port = &dev->port[PORT_SYN];
-		if (port->trigger) {
-			do_syn = port->engine;
-		}
-	}
-
-	/* DAC interrupt */
-	if (stats & CONC_INTSTAT_DACINT) {
-
-		ackbits |= CONC_SERCTL_DACIE;
-		port = &dev->port[PORT_DAC];
-		if (port->trigger) {
-			do_dac = port->engine;
-		}
-	}
-
-	/* ADC interrupt */
-	if (stats & CONC_INTSTAT_ADCINT) {
-
-		ackbits |= CONC_SERCTL_ADCIE;
-		port = &dev->port[PORT_ADC];
-
-		if (port->trigger) {
-			do_adc = port->engine;
-		}
-	}
-
-	/* UART interrupt - we shouldn't get this! */
-	if (stats & CONC_INTSTAT_UARTINT) {
-		uint8_t uart_stat = GET8(dev, CONC_bUARTCSTAT_OFF);
-		while (uart_stat & CONC_UART_RXRDY)
-			uart_stat = GET8(dev, CONC_bUARTCSTAT_OFF);
-	}
-
-	/* Ack the interrupt */
-	tmp = GET8(dev, CONC_bSERCTL_OFF);
-	PUT8(dev, CONC_bSERCTL_OFF, tmp & (~ackbits));	/* Clear bits */
-	PUT8(dev, CONC_bSERCTL_OFF, tmp | ackbits);	/* Turn them back on */
-
-	if (dev->ksp) {
-		if (ackbits == 0) {
-			KSINTR(dev)->intrs[KSTAT_INTR_SPURIOUS]++;
-		} else {
-			KSINTR(dev)->intrs[KSTAT_INTR_HARD]++;
-		}
-	}
-
-	mutex_exit(&dev->mutex);
-
-	if (do_syn)
-		audio_engine_consume(do_syn);
-	if (do_dac)
-		audio_engine_consume(do_dac);
-	if (do_adc)
-		audio_engine_produce(do_adc);
-
-	return (DDI_INTR_CLAIMED);
-}
-
 /*
  * Audio routines
  */
@@ -421,9 +289,6 @@
 	audiopci_dev_t	*dev = port->dev;
 	unsigned tmp;
 
-	if (dev->suspended)
-		return;
-
 	switch (port->num) {
 	case PORT_DAC:
 
@@ -447,7 +312,7 @@
 		    port->nframes - 1);
 
 		/* Set # of frames between interrupts */
-		PUT16(dev, CONC_wDACIC_OFF, port->fragfr - 1);
+		PUT16(dev, CONC_wDACIC_OFF, port->nframes - 1);
 
 		break;
 
@@ -472,7 +337,7 @@
 		    port->nframes - 1);
 
 		/* Set # of frames between interrupts */
-		PUT16(dev, CONC_wSYNIC_OFF, port->fragfr - 1);
+		PUT16(dev, CONC_wSYNIC_OFF, port->nframes - 1);
 
 		break;
 
@@ -498,7 +363,7 @@
 		    port->nframes - 1);
 
 		/* Set # of frames between interrupts */
-		PUT16(dev, CONC_wADCIC_OFF, port->fragfr - 1);
+		PUT16(dev, CONC_wADCIC_OFF, port->nframes - 1);
 
 		break;
 	}
@@ -507,96 +372,22 @@
 }
 
 static int
-audiopci_open(void *arg, int flag, unsigned *fragfrp, unsigned *nfragsp,
-    caddr_t *bufp)
+audiopci_open(void *arg, int flag, unsigned *nframes, caddr_t *bufp)
 {
 	audiopci_port_t	*port = arg;
-	audiopci_dev_t	*dev = port->dev;
-	int intrs;
 
 	_NOTE(ARGUNUSED(flag));
 
-
-	mutex_enter(&dev->mutex);
-	switch (port->num) {
-	case PORT_ADC:
-		intrs = dev->rintrs;
-		break;
-	case PORT_DAC:
-		intrs = dev->pintrs;
-		break;
-	case PORT_SYN:
-		intrs = dev->pintrs;
-		break;
-	}
-
-	/* interrupt at least at 25 Hz, and not more than 250 Hz */
-	intrs = min(250, max(25, intrs));
-
 	/* NB: frame size = 4 (16-bit stereo) */
-	port->fragfr = (port->speed / intrs);
-	port->nfrags = AUDIOPCI_BUF_LEN / (port->fragfr * 4);
-	port->nfrags = max(4, min(port->nfrags, 1024));
-	port->nframes = port->nfrags * port->fragfr;
-	port->trigger = B_FALSE;
+	port->nframes = AUDIOPCI_BUF_LEN / 4;
 	port->count = 0;
 
-	audiopci_init_port(port);
-
-	*fragfrp = port->fragfr;
-	*nfragsp = port->nfrags;
+	*nframes = port->nframes;
 	*bufp = port->kaddr;
-	mutex_exit(&dev->mutex);
 
 	return (0);
 }
 
-static void
-audiopci_start_port(audiopci_port_t *port)
-{
-	audiopci_dev_t *dev = port->dev;
-
-	if (!dev->suspended) {
-		switch (port->num) {
-		case PORT_DAC:
-			SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_DAC_EN);
-			SET8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_DACIE);
-			break;
-		case PORT_SYN:
-			SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_SYN_EN);
-			SET8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_SYNIE);
-			break;
-		case PORT_ADC:
-			SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
-			SET8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_ADCIE);
-			break;
-		}
-	}
-}
-
-static void
-audiopci_stop_port(audiopci_port_t *port)
-{
-	audiopci_dev_t *dev = port->dev;
-
-	if (!dev->suspended) {
-		switch (port->num) {
-		case PORT_DAC:
-			CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_DAC_EN);
-			CLR8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_DACIE);
-			break;
-		case PORT_SYN:
-			CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_SYN_EN);
-			CLR8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_SYNIE);
-			break;
-		case PORT_ADC:
-			CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
-			CLR8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_ADCIE);
-			break;
-		}
-	}
-}
-
 static int
 audiopci_start(void *arg)
 {
@@ -604,9 +395,19 @@
 	audiopci_dev_t *dev = port->dev;
 
 	mutex_enter(&dev->mutex);
-	if (!port->trigger) {
-		port->trigger = B_TRUE;
-		audiopci_start_port(port);
+
+	audiopci_init_port(port);
+
+	switch (port->num) {
+	case PORT_DAC:
+		SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_DAC_EN);
+		break;
+	case PORT_SYN:
+		SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_SYN_EN);
+		break;
+	case PORT_ADC:
+		SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
+		break;
 	}
 	mutex_exit(&dev->mutex);
 
@@ -620,16 +421,26 @@
 	audiopci_dev_t *dev = port->dev;
 
 	mutex_enter(&dev->mutex);
-	if (port->trigger) {
-		port->trigger = B_FALSE;
-		audiopci_stop_port(port);
+	switch (port->num) {
+	case PORT_DAC:
+		CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_DAC_EN);
+		break;
+	case PORT_SYN:
+		CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_SYN_EN);
+		break;
+	case PORT_ADC:
+		CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
+		break;
 	}
 	mutex_exit(&dev->mutex);
 }
 
-static void
-audiopci_update_port(audiopci_port_t *port)
+static uint64_t
+audiopci_count(void *arg)
 {
+	audiopci_port_t *port = arg;
+	audiopci_dev_t *dev = port->dev;
+	uint64_t val;
 	uint32_t page, offs;
 	int frameno, n;
 
@@ -653,36 +464,24 @@
 	/*
 	 * Note that the current frame counter is in the high nybble.
 	 */
+	mutex_enter(&dev->mutex);
 	frameno = audiopci_readmem(port->dev, page, offs) >> 16;
+	mutex_exit(&dev->mutex);
+
 	n = frameno >= port->frameno ?
 	    frameno - port->frameno :
 	    frameno + port->nframes - port->frameno;
 	port->frameno = frameno;
 	port->count += n;
-}
 
-static uint64_t
-audiopci_count(void *arg)
-{
-	audiopci_port_t *port = arg;
-	audiopci_dev_t *dev = port->dev;
-	uint64_t val;
-
-	mutex_enter(&dev->mutex);
-	if (!dev->suspended) {
-		audiopci_update_port(port);
-	}
 	val = port->count;
-	mutex_exit(&dev->mutex);
 	return (val);
 }
 
 static void
 audiopci_close(void *arg)
 {
-	audiopci_port_t *port = arg;
-
-	audiopci_stop(port);
+	_NOTE(ARGUNUSED(arg));
 }
 
 static void
@@ -797,8 +596,6 @@
 	if (dev->micbias) {
 		SET16(dev, 2, CONC_DEVCTL_MICBIAS);
 	}
-
-	dev->enabled = B_TRUE;
 }
 
 static int
@@ -808,12 +605,6 @@
 
 	audiopci_init_hw(dev);
 
-	dev->pintrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, "play-interrupts", DEFINTS);
-
-	dev->rintrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
-	    DDI_PROP_DONTPASS, "record-interrupts", DEFINTS);
-
 	for (int i = 0; i <= PORT_MAX; i++) {
 		audiopci_port_t *port;
 		unsigned caps;
@@ -896,15 +687,6 @@
 		return (DDI_FAILURE);
 	}
 
-	/*
-	 * Set up kstats for interrupt reporting.
-	 */
-	dev->ksp = kstat_create(ddi_driver_name(dev->dip),
-	    ddi_get_instance(dev->dip), ddi_driver_name(dev->dip),
-	    "controller", KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
-	if (dev->ksp != NULL) {
-		kstat_install(dev->ksp);
-	}
 
 	if (audio_dev_register(dev->adev) != DDI_SUCCESS) {
 		audio_dev_warn(dev->adev,
@@ -915,54 +697,12 @@
 	return (DDI_SUCCESS);
 }
 
-int
-audiopci_setup_interrupts(audiopci_dev_t *dev)
-{
-	int actual;
-	uint_t ipri;
-
-	if ((ddi_intr_alloc(dev->dip, dev->ihandle, DDI_INTR_TYPE_FIXED,
-	    0, 1, &actual, DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) ||
-	    (actual != 1)) {
-		audio_dev_warn(dev->adev, "can't alloc intr handle");
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_get_pri(dev->ihandle[0], &ipri) != DDI_SUCCESS) {
-		audio_dev_warn(dev->adev,  "can't determine intr priority");
-		(void) ddi_intr_free(dev->ihandle[0]);
-		dev->ihandle[0] = NULL;
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_add_handler(dev->ihandle[0], audiopci_intr, dev,
-	    NULL) != DDI_SUCCESS) {
-		audio_dev_warn(dev->adev, "can't add intr handler");
-		(void) ddi_intr_free(dev->ihandle[0]);
-		dev->ihandle[0] = NULL;
-		return (DDI_FAILURE);
-	}
-
-	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-
-	return (DDI_SUCCESS);
-}
-
-void
+static void
 audiopci_destroy(audiopci_dev_t *dev)
 {
 	int	i;
 
-	if (dev->ihandle[0] != NULL) {
-		(void) ddi_intr_disable(dev->ihandle[0]);
-		(void) ddi_intr_remove_handler(dev->ihandle[0]);
-		(void) ddi_intr_free(dev->ihandle[0]);
-		mutex_destroy(&dev->mutex);
-	}
-
-	if (dev->ksp != NULL) {
-		kstat_delete(dev->ksp);
-	}
+	mutex_destroy(&dev->mutex);
 
 	/* free up ports, including DMA resources for ports */
 	for (i = 0; i <= PORT_MAX; i++) {
@@ -1046,11 +786,9 @@
 audiopci_get_value(void *arg, uint64_t *val)
 {
 	audiopci_ctrl_t	*pc = arg;
-	audiopci_dev_t	*dev = pc->dev;
 
-	mutex_enter(&dev->mutex);
 	*val = pc->val;
-	mutex_exit(&dev->mutex);
+
 	return (0);
 }
 
@@ -1425,7 +1163,7 @@
 	return (DDI_SUCCESS);
 }
 
-void
+static void
 audiopci_del_controls(audiopci_dev_t *dev)
 {
 	for (int i = 0; i < CTL_NUM; i++) {
@@ -1435,7 +1173,7 @@
 	}
 }
 
-int
+static int
 audiopci_attach(dev_info_t *dip)
 {
 	uint16_t pci_command, vendor, device;
@@ -1446,8 +1184,11 @@
 	dev->dip = dip;
 	ddi_set_driver_private(dip, dev);
 
+	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, NULL);
+
 	if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
 		audio_dev_warn(dev->adev, "pci_config_setup failed");
+		mutex_destroy(&dev->mutex);
 		kmem_free(dev, sizeof (*dev));
 		return (DDI_FAILURE);
 	}
@@ -1482,10 +1223,6 @@
 		goto err_exit;
 	}
 
-	if (audiopci_setup_interrupts(dev) != DDI_SUCCESS) {
-		audio_dev_warn(dev->adev, "can't register interrupts");
-		goto err_exit;
-	}
 
 	/* This allocates and configures the engines */
 	if (audiopci_init(dev) != DDI_SUCCESS) {
@@ -1493,8 +1230,6 @@
 		goto err_exit;
 	}
 
-	(void) ddi_intr_enable(dev->ihandle[0]);
-
 	pci_config_teardown(&pcih);
 
 	ddi_report_dev(dip);
@@ -1502,6 +1237,7 @@
 	return (DDI_SUCCESS);
 
 err_exit:
+	mutex_destroy(&dev->mutex);
 	pci_config_teardown(&pcih);
 
 	audiopci_destroy(dev);
@@ -1509,7 +1245,7 @@
 	return (DDI_FAILURE);
 }
 
-int
+static int
 audiopci_detach(audiopci_dev_t *dev)
 {
 	int tmp;
@@ -1534,8 +1270,6 @@
 	PUT8(dev, CONC_bDEVCTL_OFF, tmp);
 	PUT8(dev, CONC_bDEVCTL_OFF, tmp);
 
-	dev->enabled = B_FALSE;
-
 	mutex_exit(&dev->mutex);
 
 	audiopci_destroy(dev);
@@ -1546,55 +1280,17 @@
 static int
 audiopci_resume(audiopci_dev_t *dev)
 {
-	/* ask framework to reset/relocate engine data */
-	for (int i = 0; i <= PORT_MAX; i++) {
-		audio_engine_reset(dev->port[i].engine);
-	}
-
-	mutex_enter(&dev->mutex);
-	dev->suspended = B_FALSE;
-
 	/* reinitialize hardware */
 	audiopci_init_hw(dev);
 
-	/* restore mixer settings */
-	audiopci_configure_output(dev);
-	audiopci_configure_input(dev);
-
-	/* restart ports */
-	for (int i = 0; i < PORT_MAX; i++) {
-		audiopci_port_t	*port = &dev->port[i];
-		audiopci_init_port(port);
-		/* possibly start it up if was going when we suspended */
-		if (port->trigger) {
-			audiopci_start_port(port);
-
-			/* signal callbacks on resume */
-			if (port->num == PORT_ADC) {
-				audio_engine_produce(port->engine);
-			} else {
-				audio_engine_consume(port->engine);
-			}
-		}
-	}
-	mutex_exit(&dev->mutex);
+	audio_dev_resume(dev->adev);
 	return (DDI_SUCCESS);
 }
 
 static int
 audiopci_suspend(audiopci_dev_t *dev)
 {
-	/*
-	 * Stop all engines/DMA data.
-	 */
-	mutex_enter(&dev->mutex);
-	for (int i = 0; i <= PORT_MAX; i++) {
-		audiopci_stop_port(&dev->port[i]);
-		audiopci_update_port(&dev->port[i]);
-	}
-	dev->suspended = B_TRUE;
-	dev->enabled = B_FALSE;
-	mutex_exit(&dev->mutex);
+	audio_dev_suspend(dev->adev);
 
 	return (DDI_SUCCESS);
 }
--- a/usr/src/uts/common/io/audio/drv/audiopci/audiopci.conf	Tue Mar 16 09:43:38 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# Configuration file for the audiopci audio driver.
-#
-#	WARNING: This is an UNSTABLE configuration file. Its contents
-#		may change at any time.
-
-#
-# 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 audiopci
-# 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 then the value specified
-# will be ignored.
-#
-play-interrupts=75;
-record-interrupts=75;
--- a/usr/src/uts/common/io/audio/drv/audiosolo/audiosolo.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiosolo/audiosolo.c	Tue Mar 16 09:30:41 2010 -0700
@@ -24,7 +24,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -101,14 +101,11 @@
 
 /*
  * For the sake of simplicity, this driver fixes a few parameters with
- * constants.  If you want these values to be tunable, upgrade to a
- * nicer and newer device.  This is all tuned for 100 Hz (10
- * millisecs) latency.
+ * constants.
  */
 #define	SOLO_RATE	48000
-#define	SOLO_INTRS	100
-#define	SOLO_FRAGFR	(SOLO_RATE / SOLO_INTRS)
-#define	SOLO_NFRAGS	8
+#define	SOLO_FRAGFR	1024
+#define	SOLO_NFRAGS	2
 #define	SOLO_NCHAN	2
 #define	SOLO_SAMPSZ	2
 #define	SOLO_FRAGSZ	(SOLO_FRAGFR * (SOLO_NCHAN * SOLO_SAMPSZ))
@@ -147,6 +144,7 @@
 	uint32_t		paddr;
 
 	bool			started;
+	bool			trigger;
 	uint64_t		count;
 	uint16_t		offset;
 	int			syncdir;
@@ -340,8 +338,6 @@
 solo_intr(caddr_t arg1, caddr_t arg2)
 {
 	solo_dev_t	*dev = (void *)arg1;
-	audio_engine_t	*prod = NULL;
-	audio_engine_t	*cons = NULL;
 	uint8_t		status;
 	uint_t		rv = DDI_INTR_UNCLAIMED;
 
@@ -357,27 +353,17 @@
 	status = PORT_RD8(dev->io, 0x7);
 	if (status & 0x20) {
 		rv = DDI_INTR_CLAIMED;
-		cons = dev->play.engine;
 		/* ack the interrupt */
 		solo_setmixer(dev, 0x7a, solo_getmixer(dev, 0x7a) & ~0x80);
 	}
 
 	if (status & 0x10) {
 		rv = DDI_INTR_CLAIMED;
-		prod = dev->rec.engine;
 		/* ack the interrupt */
 		(void) PORT_RD8(dev->sb, 0xe);
 	}
 	mutex_exit(&dev->mutex);
 
-	if (cons) {
-		audio_engine_consume(cons);
-	}
-
-	if (prod) {
-		audio_engine_produce(prod);
-	}
-
 	return (rv);
 }
 
@@ -488,8 +474,7 @@
 
 	mutex_enter(&dev->mutex);
 	pc->val = val;
-	if (!dev->suspended)
-		solo_configure_mixer(dev);
+	solo_configure_mixer(dev);
 	mutex_exit(&dev->mutex);
 	return (0);
 }
@@ -508,8 +493,7 @@
 
 	mutex_enter(&dev->mutex);
 	pc->val = val;
-	if (!dev->suspended)
-		solo_configure_mixer(dev);
+	solo_configure_mixer(dev);
 	mutex_exit(&dev->mutex);
 	return (0);
 }
@@ -530,8 +514,7 @@
 
 	mutex_enter(&dev->mutex);
 	pc->val = val;
-	if (!dev->suspended)
-		solo_configure_mixer(dev);
+	solo_configure_mixer(dev);
 	mutex_exit(&dev->mutex);
 	return (0);
 }
@@ -544,8 +527,7 @@
 
 	mutex_enter(&dev->mutex);
 	pc->val = val;
-	if (!dev->suspended)
-		solo_configure_mixer(dev);
+	solo_configure_mixer(dev);
 	mutex_exit(&dev->mutex);
 	return (0);
 }
@@ -751,23 +733,45 @@
 	uint32_t	ptr;
 	uint32_t	count;
 	uint32_t	diff;
+	int		tries;
 
 	ASSERT(mutex_owned(&dev->mutex));
 
 	/*
 	 * During recording, this register is known to give back
 	 * garbage if it's not quiescent while being read.  This hack
-	 * attempts to work around it.
+	 * attempts to work around it.  We also suspend the DMA
+	 * while we do this, to minimize record distortion.
 	 */
-	ptr = PORT_RD32(dev->vc, 0);
-	count = PORT_RD16(dev->vc, 4);
-	diff = e->paddr + SOLO_BUFSZ - ptr - count;
-	if ((diff > 3) || (ptr < e->paddr) ||
-	    (ptr >= (e->paddr + SOLO_BUFSZ))) {
-		ptr = dev->last_capture;
-	} else {
-		dev->last_capture = ptr;
+	if (e->trigger) {
+		drv_usecwait(20);
+	}
+	for (tries = 10; tries; tries--) {
+		drv_usecwait(10);
+		ptr = PORT_RD32(dev->vc, 0);
+		count = PORT_RD16(dev->vc, 4);
+		diff = e->paddr + SOLO_BUFSZ - ptr - count;
+		if ((diff > 3) || (ptr < e->paddr) ||
+		    (ptr >= (e->paddr + SOLO_BUFSZ))) {
+			ptr = dev->last_capture;
+		} else {
+			break;
+		}
 	}
+	if (e->trigger) {
+		PORT_WR8(dev->vc, 0xf, 0);	/* restart DMA */
+	}
+	if (!tries) {
+		/*
+		 * Note, this is a pretty bad situation, because we'll
+		 * not have an accurate idea of our position.  But its
+		 * better than making a bad alteration.  If we had FMA
+		 * for audio devices, this would be a good point to
+		 * raise a fault.
+		 */
+		return;
+	}
+	dev->last_capture = ptr;
 	offset = ptr - e->paddr;
 	offset /= (SOLO_NCHAN * SOLO_SAMPSZ);
 
@@ -831,6 +835,7 @@
 	PORT_WR8(dev->vc, 0xf, 0);	/* start DMA */
 
 	dev->last_capture = e->paddr;
+	e->trigger = true;
 }
 
 static void
@@ -840,6 +845,7 @@
 
 	/* NB: We might be in quiesce, without a lock held */
 	solo_write(dev, 0xb8, solo_read(dev, 0xb8) & ~0x01);
+	e->trigger = false;
 }
 
 static void
@@ -900,6 +906,8 @@
 	v = solo_mixer_scale(dev, CTL_VOLUME);
 	v = v | (v << 4);
 	solo_setmixer(dev, 0x7c, v & 0xff);
+
+	e->trigger = true;
 }
 
 static void
@@ -910,6 +918,8 @@
 	/* NB: We might be in quiesce, without a lock held */
 	PORT_WR8(dev->io, 0x6, 0);
 	solo_setmixer(dev, 0x78, solo_getmixer(dev, 0x78) & ~0x03);
+
+	e->trigger = false;
 }
 
 /*
@@ -968,8 +978,7 @@
 	uint64_t	count;
 
 	mutex_enter(&dev->mutex);
-	if (!dev->suspended)
-		e->update(e);
+	e->update(e);
 	count = e->count;
 	mutex_exit(&dev->mutex);
 
@@ -977,16 +986,14 @@
 }
 
 static int
-solo_open(void *arg, int f, unsigned *ffr, unsigned *nfr, caddr_t *buf)
+solo_open(void *arg, int f, unsigned *nframes, caddr_t *buf)
 {
 	solo_engine_t	*e = arg;
 	solo_dev_t	*dev = e->dev;
 
 	_NOTE(ARGUNUSED(f));
 
-	/* NB: For simplicity, we just fix the interrupt rate at 100 Hz */
-	*ffr = SOLO_FRAGFR;
-	*nfr = SOLO_NFRAGS;
+	*nframes = SOLO_NFRAGS * SOLO_FRAGFR;
 	*buf = e->kaddr;
 
 	mutex_enter(&dev->mutex);
@@ -1004,8 +1011,7 @@
 	solo_dev_t	*dev = e->dev;
 
 	mutex_enter(&dev->mutex);
-	if (!dev->suspended)
-		e->stop(e);
+	e->stop(e);
 	e->started = false;
 	mutex_exit(&dev->mutex);
 }
@@ -1019,8 +1025,7 @@
 
 	mutex_enter(&dev->mutex);
 	if (!e->started) {
-		if (!dev->suspended)
-			e->start(e);
+		e->start(e);
 		e->started = true;
 	}
 	mutex_exit(&dev->mutex);
@@ -1036,8 +1041,7 @@
 
 	mutex_enter(&dev->mutex);
 	if (e->started) {
-		if (!dev->suspended)
-			e->stop(e);
+		e->stop(e);
 		e->started = false;
 	}
 	mutex_exit(&dev->mutex);
@@ -1332,14 +1336,9 @@
 static int
 solo_suspend(solo_dev_t *dev)
 {
+	audio_dev_suspend(dev->adev);
+
 	mutex_enter(&dev->mutex);
-	/* play */
-	solo_aud2_stop(&dev->play);
-	solo_aud2_update(&dev->play);
-	/* record */
-	solo_aud1_stop(&dev->rec);
-	solo_aud1_update(&dev->rec);
-
 	dev->suspended = true;
 	mutex_exit(&dev->mutex);
 
@@ -1349,43 +1348,16 @@
 static int
 solo_resume(solo_dev_t *dev)
 {
-	solo_engine_t	*e;
-	audio_engine_t	*prod = NULL;
-	audio_engine_t	*cons = NULL;
-
-	audio_engine_reset(dev->rec.engine);
-	audio_engine_reset(dev->play.engine);
-
 	mutex_enter(&dev->mutex);
 	if (!solo_init_hw(dev)) {
 		/* yikes! */
 		audio_dev_warn(dev->adev, "unable to resume audio!");
 		audio_dev_warn(dev->adev, "reboot or reload driver to reset");
-		mutex_exit(&dev->mutex);
-		return (DDI_SUCCESS);
 	}
 	dev->suspended = false;
-
-	/* record - audio 1 */
-	e = &dev->rec;
-	if (e->started) {
-		e->start(e);
-		prod = e->engine;
-	}
-
-	/* play - audio 2 */
-	e = &dev->play;
-	if (e->started) {
-		e->start(e);
-		cons = e->engine;
-	}
-
 	mutex_exit(&dev->mutex);
 
-	if (cons)
-		audio_engine_consume(cons);
-	if (prod)
-		audio_engine_produce(prod);
+	audio_dev_resume(dev->adev);
 
 	return (DDI_SUCCESS);
 }
--- a/usr/src/uts/common/io/audio/drv/audiots/audiots.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiots/audiots.c	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -103,6 +103,30 @@
  *		audio subsystem. All PM support is now removed.
  */
 
+/*
+ * Synchronization notes:
+ *
+ * The audio framework guarantees that our entry points are exclusive
+ * with suspend and resume.  This includes data flow and control entry
+ * points alike.
+ *
+ * The audio framework guarantees that only one control is being
+ * accessed on any given audio device at a time.
+ *
+ * The audio framework guarantees that entry points are themselves
+ * serialized for a given engine.
+ *
+ * We have no interrupt routine or other internal asynchronous routines.
+ *
+ * Our device uses completely separate registers for each engine,
+ * except for the start/stop registers, which are implemented in a
+ * manner that allows for them to be accessed concurrently safely from
+ * different threads.
+ *
+ * Hence, it turns out that we simply don't need any locking in this
+ * driver.
+ */
+
 #include <sys/modctl.h>
 #include <sys/kmem.h>
 #include <sys/pci.h>
@@ -124,7 +148,7 @@
 /*
  * Entry point routine prototypes
  */
-static int audiots_open(void *, int, unsigned *, unsigned *, caddr_t *);
+static int audiots_open(void *, int, unsigned *, caddr_t *);
 static void audiots_close(void *);
 static int audiots_start(void *);
 static void audiots_stop(void *);
@@ -159,16 +183,11 @@
 static uint16_t audiots_get_ac97(void *, uint8_t);
 static void audiots_set_ac97(void *, uint8_t, uint16_t);
 static int audiots_init_state(audiots_state_t *, dev_info_t *);
-static uint_t audiots_intr(caddr_t);
 static int audiots_map_regs(dev_info_t *, audiots_state_t *);
-static void audiots_update_port(audiots_port_t *);
-static void audiots_start_port(audiots_port_t *);
-static void audiots_stop_port(audiots_port_t *);
 static uint16_t audiots_read_ac97(audiots_state_t *, int);
 static void audiots_stop_everything(audiots_state_t *);
 static void audiots_destroy(audiots_state_t *);
 static int audiots_alloc_port(audiots_state_t *, int);
-static void audiots_reset_port(audiots_port_t *);
 
 /*
  * Global variables, but viewable only by this file.
@@ -177,9 +196,6 @@
 /* anchor for soft state structures */
 static void *audiots_statep;
 
-/* driver name, so we don't have to call ddi_driver_name() or hard code strs */
-static char *audiots_name = TS_NAME;
-
 /*
  * DDI Structures
  */
@@ -370,15 +386,7 @@
 	case DDI_RESUME:
 
 		/* we've already allocated the state structure so get ptr */
-		if ((state = ddi_get_soft_state(audiots_statep, instance)) ==
-		    NULL) {
-			/* this will probably panic */
-			cmn_err(CE_WARN,
-			    "!%s%d: RESUME get soft state failed",
-			    audiots_name, instance);
-			return (DDI_FAILURE);
-		}
-
+		state = ddi_get_soft_state(audiots_statep, instance);
 		ASSERT(dip == state->ts_dip);
 
 		/* suspend/resume resets the chip, so we have no more faults */
@@ -394,59 +402,29 @@
 
 		audiots_power_up(state);
 		audiots_chip_init(state);
-		ac97_resume(state->ts_ac97);
 
-		mutex_enter(&state->ts_lock);
-		/*
-		 * Initialize/reset ports.  Done under the lock, to
-		 * avoid race with interrupt service routine.
-		 */
-		state->ts_suspended = B_FALSE;
-		for (int i = 0; i < TS_NUM_PORTS; i++) {
-			audiots_port_t	*port = state->ts_ports[i];
-			if (port != NULL) {
-				/* relocate any streams properly */
-				if (port->tp_engine)
-					audio_engine_reset(port->tp_engine);
+		ac97_reset(state->ts_ac97);
 
-				/* do a hardware reset on the port */
-				audiots_reset_port(port);
-				if (port->tp_started) {
-					audiots_start_port(port);
-				} else {
-					audiots_stop_port(port);
-				}
-			}
-		}
-		mutex_exit(&state->ts_lock);
+		audio_dev_resume(state->ts_adev);
 
 		return (DDI_SUCCESS);
 
 	default:
-		cmn_err(CE_WARN, "!%s%d: attach() unknown command: 0x%x",
-		    audiots_name, instance, cmd);
 		return (DDI_FAILURE);
 	}
 
 	/* before we do anything make sure that we haven't had a h/w failure */
 	if (ddi_get_devstate(dip) == DDI_DEVSTATE_DOWN) {
 		cmn_err(CE_WARN, "%s%d: The audio hardware has "
-		    "been disabled.", audiots_name, instance);
+		    "been disabled.", ddi_driver_name(dip), instance);
 		cmn_err(CE_CONT, "Please reboot to restore audio.");
 		return (DDI_FAILURE);
 	}
 
-	/* we don't support high level interrupts in this driver */
-	if (ddi_intr_hilevel(dip, 0) != 0) {
-		cmn_err(CE_WARN, "!%s%d: unsupported high level interrupt",
-		    audiots_name, instance);
-		return (DDI_FAILURE);
-	}
-
 	/* allocate the state structure */
 	if (ddi_soft_state_zalloc(audiots_statep, instance) == DDI_FAILURE) {
 		cmn_err(CE_WARN, "!%s%d: soft state allocate failed",
-		    audiots_name, instance);
+		    ddi_driver_name(dip), instance);
 		return (DDI_FAILURE);
 	}
 
@@ -497,22 +475,6 @@
 		goto error;
 	}
 
-	/* set up kernel statistics */
-	state->ts_ksp = kstat_create(TS_NAME, instance, TS_NAME,
-	    "controller", KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
-	if (state->ts_ksp != NULL) {
-		kstat_install(state->ts_ksp);
-	}
-
-	/* set up the interrupt handler */
-	if (ddi_add_intr(dip, 0, NULL, NULL, audiots_intr,
-	    (caddr_t)state) != DDI_SUCCESS) {
-		audio_dev_warn(state->ts_adev,
-		    "failed to register interrupt handler");
-		goto error;
-	}
-	state->ts_flags |= TS_INTR_INSTALLED;
-
 	/* everything worked out, so report the device */
 	ddi_report_dev(dip);
 
@@ -548,7 +510,7 @@
 	/* get the state structure */
 	if ((state = ddi_get_soft_state(audiots_statep, instance)) == NULL) {
 		cmn_err(CE_WARN, "!%s%d: detach get soft state failed",
-		    audiots_name, instance);
+		    ddi_driver_name(dip), instance);
 		return (DDI_FAILURE);
 	}
 
@@ -557,19 +519,11 @@
 		break;
 	case DDI_SUSPEND:
 
-		ac97_suspend(state->ts_ac97);
-
-		mutex_enter(&state->ts_lock);
-
-		state->ts_suspended = B_TRUE;	/* stop new ops */
-
-		/* we may already be powered down, so only save state if up */
+		audio_dev_suspend(state->ts_adev);
 
 		/* stop playing and recording */
 		(void) audiots_stop_everything(state);
 
-		mutex_exit(&state->ts_lock);
-
 		return (DDI_SUCCESS);
 
 	default:
@@ -687,9 +641,6 @@
  *
  * Arguments:
  *	audiots_state_t	*state		The device's state structure
- *
- * Returns:
- *	void
  */
 static void
 audiots_chip_init(audiots_state_t *state)
@@ -865,105 +816,17 @@
 	/* save the device info pointer */
 	state->ts_dip = dip;
 
-	/* get the iblock cookie needed for interrupt context */
-	if (ddi_get_iblock_cookie(dip, 0, &state->ts_iblock) != DDI_SUCCESS) {
-		audio_dev_warn(state->ts_adev,
-		    "cannot get iblock cookie");
-		return (DDI_FAILURE);
-	}
-
-	/* initialize the state mutexes and condition variables */
-	mutex_init(&state->ts_lock, NULL, MUTEX_DRIVER, state->ts_iblock);
-	state->ts_flags |= TS_MUTEX_INIT;
-
 	for (int i = 0; i < TS_NUM_PORTS; i++) {
 		if (audiots_alloc_port(state, i) != DDI_SUCCESS) {
 			return (DDI_FAILURE);
 		}
 	}
-	/* init power management state */
-	state->ts_suspended = B_FALSE;
 
 	return (DDI_SUCCESS);
 
 }
 
 /*
- * audiots_intr()
- *
- * Description:
- *	Interrupt service routine for both play and record. For play we
- *	get the next buffers worth of audio. For record we send it on to
- *	the mixer.
- *
- *	NOTE: This device needs to make sure any PIO access required to clear
- *	its interrupt has made it out on the PCI bus before returning from its
- *	interrupt handler so that the interrupt has been deasserted. This is
- *	done by rereading the address engine interrupt register.
- *
- * Arguments:
- *	caddr_t		T	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
-audiots_intr(caddr_t T)
-{
-	audiots_state_t		*state = (void *)T;
-	audiots_regs_t		*regs = state->ts_regs;
-	ddi_acc_handle_t	handle = state->ts_acch;
-	uint32_t		interrupts;
-
-	mutex_enter(&state->ts_lock);
-
-	if (state->ts_suspended) {
-		mutex_exit(&state->ts_lock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	interrupts = ddi_get32(handle, &regs->aud_regs.ap_aint);
-	if (interrupts == 0) {
-		mutex_exit(&state->ts_lock);
-		/* no interrupts to process, so it's not us */
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	/*
-	 * Clear the interrupts to acknowledge.  Also, reread the
-	 * interrupt reg to ensure that PIO write has completed.
-	 */
-	ddi_put32(handle, &regs->aud_regs.ap_aint, interrupts);
-	(void) ddi_get32(handle, &regs->aud_regs.ap_aint);
-
-	/* update the kernel interrupt statistics */
-	if (state->ts_ksp) {
-		TS_KIOP(state)->intrs[KSTAT_INTR_HARD]++;
-	}
-
-	mutex_exit(&state->ts_lock);
-
-	for (int i = 0; i < TS_NUM_PORTS; i++) {
-		audiots_port_t	*port = state->ts_ports[i];
-
-		if (((interrupts & port->tp_int_mask) == 0) ||
-		    (!port->tp_started))
-			continue;
-
-		if (i == TS_INPUT_PORT) {
-			audio_engine_produce(port->tp_engine);
-		} else {
-			audio_engine_consume(port->tp_engine);
-		}
-	}
-
-	return (DDI_INTR_CLAIMED);
-
-}
-
-/*
  * audiots_map_regs()
  *
  * Description:
@@ -1055,7 +918,6 @@
 	audiots_port_t		*port;
 	dev_info_t		*dip = state->ts_dip;
 	audio_dev_t		*adev = state->ts_adev;
-	char			*prop;
 	int			dir;
 	unsigned		caps;
 	ddi_dma_cookie_t	cookie;
@@ -1068,49 +930,23 @@
 	state->ts_ports[num] = port;
 	port->tp_num = num;
 	port->tp_state = state;
-	port->tp_started = B_FALSE;
-	port->tp_rate = 48000;
+	port->tp_rate = TS_RATE;
 
 	if (num == TS_INPUT_PORT) {
-		prop = "record-interrupts";
 		dir = DDI_DMA_READ;
 		caps = ENGINE_INPUT_CAP;
 		port->tp_dma_stream = 31;
-		port->tp_int_stream = 2;
 		port->tp_sync_dir = DDI_DMA_SYNC_FORKERNEL;
 	} else {
-		prop = "play-interrupts";
 		dir = DDI_DMA_WRITE;
 		caps = ENGINE_OUTPUT_CAP;
 		port->tp_dma_stream = 0;
-		port->tp_int_stream = 1;
 		port->tp_sync_dir = DDI_DMA_SYNC_FORDEV;
 	}
-	port->tp_int_mask = (1U << port->tp_int_stream);
+
 	port->tp_dma_mask = (1U << port->tp_dma_stream);
-
-	/* get the number of interrupts per second */
-	port->tp_intrs = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, prop, TS_INTS);
-
-	/* make sure the values are good */
-	if (port->tp_intrs < TS_MIN_INTS) {
-		audio_dev_warn(adev, "%s too low, %d, resetting to %d",
-		    prop, port->tp_intrs, TS_INTS);
-		port->tp_intrs = TS_INTS;
-	} else if (port->tp_intrs > TS_MAX_INTS) {
-		audio_dev_warn(adev, "%s too high, %d, resetting to %d",
-		    prop, port->tp_intrs, TS_INTS);
-		port->tp_intrs = TS_INTS;
-	}
-
-	/*
-	 * Now allocate space.  We configure for the worst case.  The
-	 * worst (biggest) case is 48000 kHz, at 4 bytes per frame
-	 * (16-bit stereo), with the lowest interrupt frequency.  We
-	 * need two fragments though, and each half has to be rounded
-	 * up to allow for alignment considerations.
-	 */
+	port->tp_nframes = 4096;
+	port->tp_size = port->tp_nframes * TS_FRAMESZ;
 
 	/* allocate dma handle */
 	rc = ddi_dma_alloc_handle(dip, &audiots_attr, DDI_DMA_SLEEP,
@@ -1120,7 +956,7 @@
 		return (DDI_FAILURE);
 	}
 	/* allocate DMA buffer */
-	rc = ddi_dma_mem_alloc(port->tp_dmah, TS_BUFSZ, &ts_acc_attr,
+	rc = ddi_dma_mem_alloc(port->tp_dmah, port->tp_size, &ts_acc_attr,
 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &port->tp_kaddr,
 	    &port->tp_size, &port->tp_acch);
 	if (rc == DDI_FAILURE) {
@@ -1305,9 +1141,6 @@
  *	audiots_state_t	*state		The device's state structure
  *	int		reg		AC-97 register number
  *	uint16_t	value		The value to write
- *
- * Returns:
- *	void
  */
 static void
 audiots_set_ac97(void *arg, uint8_t reg8, uint16_t data)
@@ -1369,99 +1202,6 @@
 }	/* audiots_set_ac97() */
 
 /*
- * audiots_reset_port()
- *
- * Description:
- *	Initializes the hardware for a DMA engine.
- *	We only support stereo 16-bit linear PCM (signed native endian).
- *
- *	The audio core uses a single DMA buffer which is divided into two
- *	halves. An interrupt is generated when the middle of the buffer has
- *	been reached and at the end. The audio core resets the pointer back
- *	to the beginning automatically. After the interrupt the driver clears
- *	the buffer and asks the mixer for more audio samples. If there aren't
- *	enough then silence is played out.
- *
- * Arguments:
- *	audiots_port_t	*port		The DMA engine to reset
- *
- * Returns:
- *	void
- */
-static void
-audiots_reset_port(audiots_port_t *port)
-{
-	audiots_state_t		*state = port->tp_state;
-	ddi_acc_handle_t	handle = state->ts_acch;
-	audiots_regs_t		*regs = state->ts_regs;
-	audiots_aram_t		*aram;
-	audiots_eram_t		*eram;
-	unsigned		delta;
-	uint16_t		ctrl;
-	uint16_t		gvsel;
-	uint16_t		eso;
-
-	if (state->ts_suspended)
-		return;
-
-	port->tp_cso = 0;
-
-	gvsel = ERAM_WAVE_VOL | ERAM_PAN_0dB | ERAM_VOL_DEFAULT;
-	ctrl = ERAM_16_BITS | ERAM_STEREO | ERAM_LOOP_MODE | ERAM_SIGNED_PCM;
-	for (int i = 0; i < 2; i++) {
-
-		delta = (port->tp_rate << TS_SRC_SHIFT) / TS_RATE;
-
-		if (i == 0) {
-			/* first do the DMA stream */
-			aram = &regs->aud_ram[port->tp_dma_stream].aram;
-			eram = &regs->aud_ram[port->tp_dma_stream].eram;
-			if (port->tp_num == TS_INPUT_PORT) {
-				delta = (TS_RATE << TS_SRC_SHIFT) /
-				    port->tp_rate;
-			}
-			eso = port->tp_nframes - 1;
-		} else {
-			/* else do the interrupt stream */
-			aram = &regs->aud_ram[port->tp_int_stream].aram;
-			eram = &regs->aud_ram[port->tp_int_stream].eram;
-			/* interrupt stream is silent */
-			gvsel |= ERAM_VOL_MAX_ATTEN;
-			eso = port->tp_fragfr - 1;
-		}
-
-		/* program the sample rate */
-		ddi_put16(handle, &aram->aram_delta, (uint16_t)delta);
-
-		/* program the precision, number of channels and loop mode */
-		ddi_put16(handle, &eram->eram_ctrl_ec, ctrl);
-
-		/* program the volume settings */
-		ddi_put16(handle, &eram->eram_gvsel_pan_vol, gvsel);
-
-		/* set ALPHA and FMS to 0 */
-		ddi_put16(handle, &aram->aram_alpha_fms, 0x0);
-
-		/* set CSO to 0 */
-		ddi_put16(handle, &aram->aram_cso, 0x0);
-
-		/* set LBA */
-		ddi_put32(handle, &aram->aram_cptr_lba,
-		    port->tp_paddr & ARAM_LBA_MASK);
-
-		/* set ESO */
-		ddi_put16(handle, &aram->aram_eso, eso);
-	}
-
-	/* stop the DMA & interrupt engines */
-	ddi_put32(handle, &regs->aud_regs.ap_stop,
-	    port->tp_int_mask | port->tp_dma_mask);
-
-	/* enable interrupts */
-	OR_SET_WORD(handle, &regs->aud_regs.ap_ainten, port->tp_int_mask);
-}
-
-/*
  * audiots_open()
  *
  * Description:
@@ -1471,8 +1211,7 @@
  * Arguments:
  *	void		*arg		The DMA engine to set up
  *	int		flag		Open flags
- *	unsigned	*fragfrp	Receives number of frames per fragment
- *	unsigned	*nfragsp	Receives number of fragments
+ *	unsigned	*nframesp	Receives number of frames
  *	caddr_t		*bufp		Receives kernel data buffer
  *
  * Returns:
@@ -1480,40 +1219,17 @@
  *	errno	on failure
  */
 static int
-audiots_open(void *arg, int flag,
-    unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp)
+audiots_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
 {
 	audiots_port_t	*port = arg;
-	unsigned	nfrag;
 
 	_NOTE(ARGUNUSED(flag));
 
-	/*
-	 * Round up - we have to have a sample that is a whole number
-	 * of 64-bit words.  Since our frames are 4 bytes wide, we
-	 * just need an even number of frames.
-	 */
-	port->tp_fragfr = port->tp_rate / port->tp_intrs;
-	port->tp_fragfr = (port->tp_fragfr + 1) & ~1;
-	nfrag = port->tp_size / (port->tp_fragfr * TS_FRAMESZ);
-	port->tp_nframes = nfrag * port->tp_fragfr;
-	port->tp_started = B_FALSE;
 	port->tp_count = 0;
 	port->tp_cso = 0;
-	*fragfrp = port->tp_fragfr;
-	*nfragsp = nfrag;
+	*nframesp = port->tp_nframes;
 	*bufp = port->tp_kaddr;
 
-	/*
-	 * This should always be true because we used a worst case
-	 * assumption when calculating the port->tp_size.
-	 */
-	ASSERT((port->tp_fragfr * nfrag) <= port->tp_size);
-
-	mutex_enter(&port->tp_state->ts_lock);
-	audiots_reset_port(port);
-	mutex_exit(&port->tp_state->ts_lock);
-
 	return (0);
 }
 
@@ -1522,25 +1238,16 @@
  *
  * Description:
  *	Closes an audio DMA engine that was previously opened.  Since
- *	nobody is using it, we take this opportunity to possibly power
- *	down the entire device.
+ *	nobody is using it, we could take this opportunity to possibly power
+ *	down the entire device, or at least the DMA engine.
  *
  * Arguments:
  *	void	*arg		The DMA engine to shut down
- *
- * Returns:
- *	void
  */
 static void
 audiots_close(void *arg)
 {
-	audiots_port_t	*port = arg;
-	audiots_state_t	*state = port->tp_state;
-
-	mutex_enter(&state->ts_lock);
-	audiots_stop_port(port);
-	port->tp_started = B_FALSE;
-	mutex_exit(&state->ts_lock);
+	_NOTE(ARGUNUSED(arg));
 }
 
 /*
@@ -1552,9 +1259,6 @@
  *
  * Arguments:
  *	void	*arg		The DMA engine to stop
- *
- * Returns:
- *	void
  */
 static void
 audiots_stop(void *arg)
@@ -1562,12 +1266,8 @@
 	audiots_port_t	*port = arg;
 	audiots_state_t	*state = port->tp_state;
 
-	mutex_enter(&state->ts_lock);
-	if (port->tp_started) {
-		audiots_stop_port(port);
-	}
-	port->tp_started = B_FALSE;
-	mutex_exit(&state->ts_lock);
+	ddi_put32(state->ts_acch, &state->ts_regs->aud_regs.ap_stop,
+	    port->tp_dma_mask);
 }
 
 /*
@@ -1585,15 +1285,60 @@
 static int
 audiots_start(void *arg)
 {
-	audiots_port_t	*port = arg;
-	audiots_state_t	*state = port->tp_state;
+	audiots_port_t		*port = arg;
+	audiots_state_t		*state = port->tp_state;
+	ddi_acc_handle_t	handle = state->ts_acch;
+	audiots_regs_t		*regs = state->ts_regs;
+	audiots_aram_t		*aram;
+	audiots_eram_t		*eram;
+	unsigned		delta;
+	uint16_t		ctrl;
+	uint16_t		gvsel;
+	uint16_t		eso;
+
+	aram = &regs->aud_ram[port->tp_dma_stream].aram;
+	eram = &regs->aud_ram[port->tp_dma_stream].eram;
+
+	port->tp_cso = 0;
+
+	gvsel = ERAM_WAVE_VOL | ERAM_PAN_0dB | ERAM_VOL_DEFAULT;
+	ctrl = ERAM_16_BITS | ERAM_STEREO | ERAM_LOOP_MODE | ERAM_SIGNED_PCM;
+
+	delta = (port->tp_rate << TS_SRC_SHIFT) / TS_RATE;
+
+	if (port->tp_num == TS_INPUT_PORT) {
+		delta = (TS_RATE << TS_SRC_SHIFT) / port->tp_rate;
+	}
+	eso = port->tp_nframes - 1;
 
-	mutex_enter(&state->ts_lock);
-	if (!port->tp_started) {
-		audiots_start_port(port);
-		port->tp_started = B_TRUE;
-	}
-	mutex_exit(&state->ts_lock);
+	/* program the sample rate */
+	ddi_put16(handle, &aram->aram_delta, (uint16_t)delta);
+
+	/* program the precision, number of channels and loop mode */
+	ddi_put16(handle, &eram->eram_ctrl_ec, ctrl);
+
+	/* program the volume settings */
+	ddi_put16(handle, &eram->eram_gvsel_pan_vol, gvsel);
+
+	/* set ALPHA and FMS to 0 */
+	ddi_put16(handle, &aram->aram_alpha_fms, 0x0);
+
+	/* set CSO to 0 */
+	ddi_put16(handle, &aram->aram_cso, 0x0);
+
+	/* set LBA */
+	ddi_put32(handle, &aram->aram_cptr_lba,
+	    port->tp_paddr & ARAM_LBA_MASK);
+
+	/* set ESO */
+	ddi_put16(handle, &aram->aram_eso, eso);
+
+	/* stop the DMA engines */
+	ddi_put32(handle, &regs->aud_regs.ap_stop, port->tp_dma_mask);
+
+	/* now make sure it starts playing */
+	ddi_put32(handle, &regs->aud_regs.ap_start, port->tp_dma_mask);
+
 	return (0);
 }
 
@@ -1701,131 +1446,8 @@
 	audiots_port_t	*port = arg;
 	audiots_state_t	*state = port->tp_state;
 	uint64_t	val;
-
-	mutex_enter(&state->ts_lock);
-	audiots_update_port(port);
-
-	val = port->tp_count;
-	mutex_exit(&state->ts_lock);
-	return (val);
-}
-
-/*
- * audiots_sync()
- *
- * Description:
- *	This is called by the framework to synchronize DMA caches.
- *	We also leverage this do some endian swapping, because on SPARC
- *	the chip accesses the DMA region using 32-bit little-endian
- *	accesses.  Its not enough to just use the framework's sample
- *	conversion logic, because the channels will also be backwards.
- *
- * Arguments:
- *	void	*arg		The DMA engine to sync
- *
- * Returns:
- *	void
- */
-static void
-audiots_sync(void *arg, unsigned nframes)
-{
-	audiots_port_t *port = arg;
-	_NOTE(ARGUNUSED(nframes));
-
-	(void) ddi_dma_sync(port->tp_dmah, 0, 0, port->tp_sync_dir);
-}
-
-/*
- * audiots_start_port()
- *
- * Description:
- *	The audio core uses a single DMA buffer which is divided into two
- *	halves. An interrupt is generated when the middle of the buffer has
- *	been reached and at the end. The audio core resets the pointer back
- *	to the beginning automatically. After the interrupt the driver clears
- *	the buffer and asks the mixer for more audio samples. If there aren't
- *	enough then silence is played out.
- *
- * Arguments:
- *	audiots_port_t	*port		The DMA engine to start up
- *
- * Returns:
- *	void
- */
-static void
-audiots_start_port(audiots_port_t *port)
-{
-	audiots_state_t		*state = port->tp_state;
-	audiots_regs_t		*regs = state->ts_regs;
-	ddi_acc_handle_t	handle = state->ts_acch;
-
-	ASSERT(mutex_owned(&state->ts_lock));
-
-	/* if suspended then do nothing else */
-	if (state->ts_suspended)  {
-		return;
-	}
-
-	/* make sure it starts playing */
-	ddi_put32(handle, &regs->aud_regs.ap_start,
-	    port->tp_dma_mask | port->tp_int_mask);
-
-	ASSERT(mutex_owned(&state->ts_lock));
-}
-
-/*
- * audiots_stop_port()
- *
- * Description:
- *	This routine stops a DMA engine.
- *
- * Arguments:
- *	audiots_port_t	*port		The port to stop
- *
- * Returns:
- *	void
- */
-static void
-audiots_stop_port(audiots_port_t *port)
-{
-	audiots_state_t *state = port->tp_state;
-
-	ASSERT(mutex_owned(&state->ts_lock));
-
-	if (state->ts_suspended)
-		return;
-
-	ddi_put32(state->ts_acch, &state->ts_regs->aud_regs.ap_stop,
-	    port->tp_int_mask | port->tp_dma_mask);
-
-	ASSERT(mutex_owned(&state->ts_lock));
-}
-
-/*
- * audiots_update_port()
- *
- * Description:
- *	This routine updates the ports frame counter from hardware, and
- *	gracefully handles wraps.
- *
- * Arguments:
- *	audiots_port_t	*port		The port to stop
- *
- * Returns:
- *	void
- */
-static void
-audiots_update_port(audiots_port_t *port)
-{
-	audiots_state_t		*state = port->tp_state;
-
-	uint16_t		cso;
-	unsigned		n;
-
-	ASSERT(mutex_owned(&state->ts_lock));
-
-	if (state->ts_suspended)
-		return;
+	uint16_t	cso;
+	unsigned	n;
 
 	cso = ddi_get16(state->ts_acch,
 	    &state->ts_regs->aud_ram[port->tp_dma_stream].aram.aram_cso);
@@ -1836,6 +1458,27 @@
 
 	port->tp_cso = cso;
 	port->tp_count += n;
+	val = port->tp_count;
+
+	return (val);
+}
+
+/*
+ * audiots_sync()
+ *
+ * Description:
+ *	This is called by the framework to synchronize DMA caches.
+ *
+ * Arguments:
+ *	void	*arg		The DMA engine to sync
+ */
+static void
+audiots_sync(void *arg, unsigned nframes)
+{
+	audiots_port_t *port = arg;
+	_NOTE(ARGUNUSED(nframes));
+
+	(void) ddi_dma_sync(port->tp_dmah, 0, 0, port->tp_sync_dir);
 }
 
 /*
@@ -1858,9 +1501,6 @@
  *
  * Arguments:
  *	audiots_state_t	*state		The device's state structure
- *
- * Returns:
- *	void
  */
 static void
 audiots_stop_everything(audiots_state_t *state)
@@ -1887,9 +1527,6 @@
  *
  * Arguments:
  *	audiots_port_t	*port	The port structure for a device stream.
- *
- * Returns:
- *	None
  */
 void
 audiots_free_port(audiots_port_t *port)
@@ -1923,21 +1560,12 @@
  *
  * Arguments:
  *	audiots_state_t	*state	The device soft state.
- *
- * Returns:
- *	None
  */
 void
 audiots_destroy(audiots_state_t *state)
 {
 	audiots_stop_everything(state);
 
-	if (state->ts_flags & TS_INTR_INSTALLED)
-		ddi_remove_intr(state->ts_dip, 0, NULL);
-
-	if (state->ts_ksp)
-		kstat_delete(state->ts_ksp);
-
 	for (int i = 0; i < TS_NUM_PORTS; i++)
 		audiots_free_port(state->ts_ports[i]);
 
@@ -1953,9 +1581,5 @@
 	if (state->ts_adev)
 		audio_dev_free(state->ts_adev);
 
-	if (state->ts_flags & TS_MUTEX_INIT) {
-		mutex_destroy(&state->ts_lock);
-	}
-
 	ddi_soft_state_free(audiots_statep, ddi_get_instance(state->ts_dip));
 }
--- a/usr/src/uts/common/io/audio/drv/audiots/audiots.conf	Tue Mar 16 09:43:38 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# Configuration file for the audiots audio driver.
-#
-#	WARNING: This is an UNSTABLE configuration file. Its contents
-#		may change at any time.
-#
-
-#
-# 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 audiots
-# 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;
-
-#
-# ac97-amplifier enables the use of any onboard external amplifier.
-#
-#ac97-amplifier=1;
--- a/usr/src/uts/common/io/audio/drv/audiots/audiots.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiots/audiots.h	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -47,17 +47,6 @@
 #define	TS_RATE			(48000)
 #define	TS_STEREO		(2)		/* stereo */
 #define	TS_FRAMESZ		(4)		/* 16-bit stereo */
-/*
- * This is how much buffer space we at minimum need.  The worst
- * (biggest) case is 48000 kHz, at 4 bytes per frame (16-bit stereo),
- * with the lowest interrupt frequency.  48000 x 4 bytes per sample /
- * 24 is 8000 bytes per fragment.  Two such fragments would be 16000.
- * (At higher data rates, we get better buffering, with more frags.)
- */
-#define	TS_BUFSZ		(16000)		/* maximum buffer size */
-#define	TS_INTS			(175)		/* default interrupt rate */
-#define	TS_MIN_INTS		(24)		/* minimum interrupt rate */
-#define	TS_MAX_INTS		(2000)		/* maximum interrupt rate */
 
 /*
  * Misc. defines
@@ -77,7 +66,6 @@
 
 #define	TS_MAX_HW_CHANNELS	(32)
 
-#define	TS_KIOP(X)		((kstat_intr_t *)(X->ts_ksp->ks_data))
 #define	TS_WAIT_CNT		(512)
 #define	TS_LOOP_CNT		(10)
 #define	TS_DELAY_CNT		(25)
@@ -439,14 +427,10 @@
 	struct audiots_state	*tp_state;
 	int			tp_num;
 	int			tp_dma_stream;
-	int			tp_int_stream;
 
 	uint32_t		tp_dma_mask;
-	uint32_t		tp_int_mask;
 
 	boolean_t		tp_started;
-	unsigned		tp_intrs;
-	unsigned		tp_fragfr;
 	unsigned		tp_nframes;
 	unsigned		tp_rate;
 	uint64_t		tp_count;
@@ -467,10 +451,7 @@
  * audiots_state_t	- per instance state and operation data
  */
 struct audiots_state {
-	kmutex_t		ts_lock;	/* state protection lock */
-	ddi_iblock_cookie_t	ts_iblock;	/* iblock cookie */
 	uint_t			ts_flags;	/* flags */
-	kstat_t			*ts_ksp;	/* kernel statistics */
 	dev_info_t		*ts_dip;	/* used by ts_getinfo() */
 	audio_dev_t		*ts_adev;	/* audio device handle */
 	ac97_t			*ts_ac97;	/* ac97 common handle */
@@ -480,7 +461,6 @@
 
 	ddi_acc_handle_t	ts_pcih;	/* handle to config regs */
 	ddi_acc_handle_t	ts_acch;	/* handle to mapped regs */
-	boolean_t		ts_suspended;	/* power management state */
 
 	uint32_t		ts_devid;
 	uint8_t			ts_revid;	/* SB Chip Revision ID */
@@ -488,14 +468,7 @@
 };
 typedef struct audiots_state audiots_state_t;
 
-_NOTE(MUTEX_PROTECTS_DATA(audiots_state::ts_lock, audiots_state))
-_NOTE(READ_ONLY_DATA(audiots_state::ts_instance))
-_NOTE(READ_ONLY_DATA(audiots_state::ts_dip))
-_NOTE(READ_ONLY_DATA(audiots_state::ts_adev))
-
 /* audiots_state.ts_flags defines */
-#define	TS_MUTEX_INIT			0x0001u	/* mutex initialized */
-#define	TS_INTR_INSTALLED		0x0002u	/* intr handler installeld */
 #define	TS_AUDIO_READ_FAILED		0x0020u /* reading the AC97 register */
 						/* has stopped working */
 #define	TS_READ_FAILURE_PRINTED		0x0040u /* Flag to avoid flooding the */
--- a/usr/src/uts/common/io/audio/drv/audiovia823x/audiovia823x.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiovia823x/audiovia823x.c	Tue Mar 16 09:30:41 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -97,7 +97,7 @@
 static int auvia_detach(auvia_devc_t *);
 static int auvia_suspend(auvia_devc_t *);
 
-static int auvia_open(void *, int, unsigned *, unsigned *, caddr_t *);
+static int auvia_open(void *, int, unsigned *, caddr_t *);
 static void auvia_close(void *);
 static int auvia_start(void *);
 static void auvia_stop(void *);
@@ -110,15 +110,10 @@
 static uint16_t auvia_read_ac97(void *, uint8_t);
 static void auvia_write_ac97(void *, uint8_t, uint16_t);
 static int auvia_alloc_port(auvia_devc_t *, int);
-static void auvia_start_port(auvia_portc_t *);
-static void auvia_stop_port(auvia_portc_t *);
-static void auvia_update_port(auvia_portc_t *);
 static void auvia_reset_input(auvia_portc_t *);
 static void auvia_reset_output(auvia_portc_t *);
 static void auvia_destroy(auvia_devc_t *);
-static int auvia_setup_intrs(auvia_devc_t *);
 static void auvia_hwinit(auvia_devc_t *);
-static uint_t auvia_intr(caddr_t, caddr_t);
 
 static audio_engine_ops_t auvia_engine_ops = {
 	AUDIO_ENGINE_VERSION,
@@ -143,8 +138,6 @@
 	uint32_t val = 0;
 	int i;
 
-	mutex_enter(&devc->low_mutex);
-
 	val = ((uint32_t)index << 16) | CODEC_RD;
 	OUTL(devc, devc->base + REG_CODEC, val);
 	drv_usecwait(100);
@@ -166,12 +159,10 @@
 	val = INL(devc, devc->base + REG_CODEC);
 	OUTB(devc, devc->base + REG_CODEC + 3, 0x02);
 	if (((val & CODEC_INDEX) >> 16) == index) {
-		mutex_exit(&devc->low_mutex);
 		return (val & CODEC_DATA);
 	}
 
 failed:
-	mutex_exit(&devc->low_mutex);
 	return (0xffff);
 }
 
@@ -182,8 +173,6 @@
 	uint32_t val = 0;
 	int i = 0;
 
-	mutex_enter(&devc->low_mutex);
-
 	val = ((uint32_t)index << 16) | data | CODEC_WR;
 	OUTL(devc, devc->base + REG_CODEC, val);
 	drv_usecwait(100);
@@ -196,70 +185,6 @@
 		drv_usecwait(50);
 	}
 
-	mutex_exit(&devc->low_mutex);
-}
-
-static uint_t
-auvia_intr(caddr_t argp, caddr_t nocare)
-{
-	auvia_devc_t	*devc = (void *)argp;
-	auvia_portc_t	*portc;
-	uint8_t		status;
-	unsigned	intrs = 0;
-	boolean_t	claimed = B_FALSE;
-
-	_NOTE(ARGUNUSED(nocare));
-
-	mutex_enter(&devc->mutex);
-	if (devc->suspended) {
-		mutex_exit(&devc->mutex);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	for (int i = 0; i < AUVIA_NUM_PORTC; i++) {
-
-		portc = devc->portc[i];
-
-		status = INB(devc, portc->base + OFF_STATUS);
-		if ((status & STATUS_INTR) == 0) {
-			/* clear any other interrupts */
-			continue;
-		}
-
-		/*
-		 * NB: The old code did some goofy things to update
-		 * the last valid SGD.  However, since we don't ever
-		 * reach the last valid SGD (because we loop first), I
-		 * don't believe we need to do that.  It would appear
-		 * that NetBSD does the same.
-		 */
-		/* port interrupt */
-		if (portc->started) {
-			intrs |= (1U << i);
-		}
-		/* let the chip know we are acking the interrupt */
-		OUTB(devc, portc->base + OFF_STATUS, status);
-
-		claimed = B_TRUE;
-	}
-
-	mutex_exit(&devc->mutex);
-
-	if (!claimed) {
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	if (intrs & (1U << AUVIA_PLAY_SGD_NUM)) {
-		audio_engine_consume(devc->portc[AUVIA_PLAY_SGD_NUM]->engine);
-	}
-	if (intrs & (1U << AUVIA_REC_SGD_NUM)) {
-		audio_engine_produce(devc->portc[AUVIA_REC_SGD_NUM]->engine);
-	}
-	if (devc->ksp) {
-		AUVIA_KIOP(devc)->intrs[KSTAT_INTR_HARD]++;
-	}
-
-	return (DDI_INTR_CLAIMED);
 }
 
 /*
@@ -267,37 +192,23 @@
  */
 
 int
-auvia_open(void *arg, int flag,
-    unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp)
+auvia_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
 {
 	auvia_portc_t	 *portc = arg;
-	auvia_devc_t	 *devc = portc->devc;
 
 	_NOTE(ARGUNUSED(flag));
 
-	portc->started = B_FALSE;
 	portc->count = 0;
-	*fragfrp = portc->fragfr;
-	*nfragsp = AUVIA_NUM_SGD;
+	*nframesp = portc->nframes;
 	*bufp = portc->buf_kaddr;
 
-	mutex_enter(&devc->mutex);
-	portc->reset(portc);
-	mutex_exit(&devc->mutex);
-
 	return (0);
 }
 
 void
 auvia_close(void *arg)
 {
-	auvia_portc_t	 *portc = arg;
-	auvia_devc_t	 *devc = portc->devc;
-
-	mutex_enter(&devc->mutex);
-	auvia_stop_port(portc);
-	portc->started = B_FALSE;
-	mutex_exit(&devc->mutex);
+	_NOTE(ARGUNUSED(arg));
 }
 
 int
@@ -306,12 +217,8 @@
 	auvia_portc_t	*portc = arg;
 	auvia_devc_t	*devc = portc->devc;
 
-	mutex_enter(&devc->mutex);
-	if (!portc->started) {
-		auvia_start_port(portc);
-		portc->started = B_TRUE;
-	}
-	mutex_exit(&devc->mutex);
+	portc->reset(portc);
+	OUTB(devc, portc->base + OFF_CTRL, CTRL_START | CTRL_AUTOSTART);
 	return (0);
 }
 
@@ -321,12 +228,7 @@
 	auvia_portc_t	*portc = arg;
 	auvia_devc_t	*devc = portc->devc;
 
-	mutex_enter(&devc->mutex);
-	if (portc->started) {
-		auvia_stop_port(portc);
-		portc->started = B_FALSE;
-	}
-	mutex_exit(&devc->mutex);
+	OUTB(devc, portc->base + OFF_CTRL, CTRL_TERMINATE);
 }
 
 int
@@ -367,96 +269,34 @@
 {
 	auvia_portc_t	*portc = arg;
 	auvia_devc_t	*devc = portc->devc;
-	uint64_t	val;
+	uint32_t	pos;
+	uint32_t	n;
+
+	pos = INL(devc, portc->base + OFF_COUNT);
+	pos &= 0xffffff;
+	pos /= (sizeof (int16_t) * portc->nchan);
 
-	mutex_enter(&devc->mutex);
-	auvia_update_port(portc);
-	/*
-	 * The residual is in bytes.  We have to convert to frames,
-	 * and then subtract it from the fragment size to get the
-	 * number of frames processed.  It is somewhat unfortunate thta
-	 * this (the division) has to happen under the lock.  If we
-	 * restricted ourself to stereo out, this would be a simple
-	 * shift.
-	 */
-	val = portc->count +
-	    (portc->fragfr - (portc->resid / (portc->nchan * 2)));
-	mutex_exit(&devc->mutex);
+	if (pos >= portc->pos) {
+		n = portc->nframes - (pos - portc->pos);
+	} else {
+		n = portc->pos - pos;
+	}
+	portc->pos = pos;
+	portc->count += n;
 
-	return (val);
+	return (portc->count);
 }
 
 
 /* private implementation bits */
 
 void
-auvia_start_port(auvia_portc_t *portc)
-{
-	auvia_devc_t	*devc = portc->devc;
-
-	ASSERT(mutex_owned(&devc->mutex));
-
-	if (devc->suspended)
-		return;
-
-	/*
-	 * Start with autoinit and SGD flag
-	 * interrupts enabled.
-	 */
-	OUTB(devc, portc->base + OFF_CTRL,
-	    CTRL_START | CTRL_AUTOSTART | CTRL_FLAG);
-}
-
-void
-auvia_stop_port(auvia_portc_t *portc)
-{
-	auvia_devc_t	*devc = portc->devc;
-
-	if (devc->suspended)
-		return;
-
-	OUTB(devc, portc->base + OFF_CTRL, CTRL_TERMINATE);
-}
-
-void
-auvia_update_port(auvia_portc_t *portc)
-{
-	auvia_devc_t	*devc = portc->devc;
-	uint32_t	frag;
-	uint32_t	n;
-
-	ASSERT(mutex_owned(&devc->mutex));
-	if (devc->suspended) {
-		portc->cur_frag = 0;
-		portc->resid = portc->fragsz;
-		n = 0;
-	} else {
-		frag = INL(devc, portc->base + OFF_COUNT);
-		portc->resid = (frag & 0xffffff);
-		frag >>= 24;
-		frag &= 0xff;
-
-		if (frag >= portc->cur_frag) {
-			n = frag - portc->cur_frag;
-		} else {
-			n = frag + AUVIA_NUM_SGD - portc->cur_frag;
-		}
-		portc->count += (n * portc->fragfr);
-		portc->cur_frag = frag;
-	}
-}
-
-void
 auvia_reset_output(auvia_portc_t *portc)
 {
 	auvia_devc_t	*devc = portc->devc;
 	uint32_t	cmap;
 
-	portc->cur_frag = 0;
-	portc->resid = portc->fragsz;
-
-	if (devc->suspended)
-		return;
+	portc->pos = 0;
 
 	OUTB(devc, portc->base + OFF_CTRL, CTRL_TERMINATE);	/* Stop */
 	OUTL(devc, portc->base + OFF_DMA, portc->sgd_paddr);
@@ -504,11 +344,7 @@
 	auvia_devc_t	*devc = portc->devc;
 	uint32_t	fmt;
 
-	portc->cur_frag = 0;
-	portc->resid = portc->fragsz;
-
-	if (devc->suspended)
-		return;
+	portc->pos = 0;
 
 	OUTB(devc, portc->base + OFF_CTRL, CTRL_TERMINATE);	/* Stop */
 	OUTL(devc, portc->base + OFF_DMA, portc->sgd_paddr);
@@ -531,21 +367,17 @@
 	ddi_dma_cookie_t	cookie;
 	uint_t			count;
 	int			dir;
-	char			*prop;
 	unsigned		caps;
 	audio_dev_t		*adev;
 	uint32_t		*desc;
-	uint32_t		paddr;
 
 	adev = devc->adev;
 	portc = kmem_zalloc(sizeof (*portc), KM_SLEEP);
 	devc->portc[num] = portc;
 	portc->devc = devc;
-	portc->started = B_FALSE;
 
 	switch (num) {
 	case AUVIA_REC_SGD_NUM:
-		prop = "record-interrupts";
 		portc->base = devc->base + REG_RECBASE;
 		portc->syncdir = DDI_DMA_SYNC_FORKERNEL;
 		portc->nchan = 2;
@@ -554,7 +386,6 @@
 		dir = DDI_DMA_READ;
 		break;
 	case AUVIA_PLAY_SGD_NUM:
-		prop = "play-interrupts";
 		portc->base = devc->base + REG_PLAYBASE;
 		portc->syncdir = DDI_DMA_SYNC_FORDEV;
 		portc->nchan = 6;
@@ -569,24 +400,8 @@
 	/* make sure port is shut down */
 	OUTB(portc->devc, portc->base + OFF_CTRL, CTRL_TERMINATE);
 
-	/* figure out fragment configuration */
-	portc->intrs = ddi_prop_get_int(DDI_DEV_T_ANY, devc->dip,
-	    DDI_PROP_DONTPASS, prop, AUVIA_INTRS);
-
-	/* make sure the values are good */
-	if (portc->intrs < AUVIA_MIN_INTRS) {
-		audio_dev_warn(adev, "%s too low, %d, reset to %d",
-		    prop, portc->intrs, AUVIA_INTRS);
-		portc->intrs = AUVIA_INTRS;
-	} else if (portc->intrs > AUVIA_MAX_INTRS) {
-		audio_dev_warn(adev, "%s too high, %d, reset to %d",
-		    prop, portc->intrs, AUVIA_INTRS);
-		portc->intrs = AUVIA_INTRS;
-	}
-
-	portc->fragfr = 48000 / portc->intrs;
-	portc->fragsz = portc->fragfr * portc->nchan * 2;
-	portc->buf_size = portc->fragsz * AUVIA_NUM_SGD;
+	portc->nframes = 4096;
+	portc->buf_size = portc->nframes * portc->nchan * sizeof (int16_t);
 
 	/* first allocate up space for SGD list */
 	if (ddi_dma_alloc_handle(devc->dip, &dma_attr_sgd,
@@ -595,8 +410,7 @@
 		return (DDI_FAILURE);
 	}
 
-	if (ddi_dma_mem_alloc(portc->sgd_dmah,
-	    AUVIA_NUM_SGD * 2 * sizeof (uint32_t), &dev_attr,
+	if (ddi_dma_mem_alloc(portc->sgd_dmah, 2 * sizeof (uint32_t), &dev_attr,
 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &portc->sgd_kaddr,
 	    &len, &portc->sgd_acch) != DDI_SUCCESS) {
 		audio_dev_warn(adev, "failed to allocate SGD memory");
@@ -633,21 +447,11 @@
 	}
 	portc->buf_paddr = cookie.dmac_address;
 
-	/* now wire descriptors up */
+	/* now wire up descriptor -- just one */
 	desc = (void *)portc->sgd_kaddr;
-	paddr = portc->buf_paddr;
-	for (int i = 0; i < AUVIA_NUM_SGD; i++) {
-		uint32_t	flags;
-
-		flags = AUVIA_SGD_FLAG | portc->fragsz;
 
-		if (i == (AUVIA_NUM_SGD - 1)) {
-			flags |= AUVIA_SGD_EOL;
-		}
-		ddi_put32(portc->sgd_acch, desc++, paddr);
-		ddi_put32(portc->sgd_acch, desc++, flags);
-		paddr += portc->fragsz;
-	}
+	ddi_put32(portc->sgd_acch, desc++, portc->buf_paddr);
+	ddi_put32(portc->sgd_acch, desc++, AUVIA_SGD_EOL | portc->buf_size);
 
 	(void) ddi_dma_sync(portc->sgd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
 
@@ -663,57 +467,9 @@
 	return (DDI_SUCCESS);
 }
 
-int
-auvia_setup_intrs(auvia_devc_t *devc)
-{
-	uint_t			ipri;
-	int			actual;
-	int			rv;
-	ddi_intr_handle_t	ih[1];
-
-	rv = ddi_intr_alloc(devc->dip, ih, DDI_INTR_TYPE_FIXED,
-	    0, 1, &actual, DDI_INTR_ALLOC_STRICT);
-	if ((rv != DDI_SUCCESS) || (actual != 1)) {
-		audio_dev_warn(devc->adev,
-		    "Can't alloc interrupt handle (rv %d actual %d)",
-		    rv, actual);
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_get_pri(ih[0], &ipri) != DDI_SUCCESS) {
-		audio_dev_warn(devc->adev, "Can't get interrupt priority");
-		(void) ddi_intr_free(ih[0]);
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_add_handler(ih[0], auvia_intr, devc, NULL) !=
-	    DDI_SUCCESS) {
-		audio_dev_warn(devc->adev, "Can't add interrupt handler");
-		(void) ddi_intr_free(ih[0]);
-		return (DDI_FAILURE);
-	}
-
-	devc->ih = ih[0];
-	mutex_init(&devc->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-	mutex_init(&devc->low_mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-	return (DDI_SUCCESS);
-}
-
 void
 auvia_destroy(auvia_devc_t *devc)
 {
-	if (devc->ih != NULL) {
-		(void) ddi_intr_disable(devc->ih);
-		(void) ddi_intr_remove_handler(devc->ih);
-		(void) ddi_intr_free(devc->ih);
-		mutex_destroy(&devc->mutex);
-		mutex_destroy(&devc->low_mutex);
-	}
-
-	if (devc->ksp) {
-		kstat_delete(devc->ksp);
-	}
-
 	for (int i = 0; i < AUVIA_NUM_PORTC; i++) {
 		auvia_portc_t *portc = devc->portc[i];
 		if (!portc)
@@ -856,10 +612,6 @@
 		goto error;
 	}
 
-	if (auvia_setup_intrs(devc) != DDI_SUCCESS) {
-		goto error;
-	}
-
 	devc->ac97 = ac97_alloc(dip, auvia_read_ac97, auvia_write_ac97, devc);
 	if (devc->ac97 == NULL) {
 		audio_dev_warn(devc->adev, "failed to allocate ac97 handle");
@@ -871,19 +623,11 @@
 		goto error;
 	}
 
-	/* set up kernel statistics */
-	if ((devc->ksp = kstat_create(AUVIA_NAME, ddi_get_instance(dip),
-	    AUVIA_NAME, "controller", KSTAT_TYPE_INTR, 1,
-	    KSTAT_FLAG_PERSISTENT)) != NULL) {
-		kstat_install(devc->ksp);
-	}
-
 	if (audio_dev_register(devc->adev) != DDI_SUCCESS) {
 		audio_dev_warn(devc->adev, "unable to register with framework");
 		goto error;
 	}
 
-	(void) ddi_intr_enable(devc->ih);
 	ddi_report_dev(dip);
 
 	return (DDI_SUCCESS);
@@ -902,28 +646,10 @@
 
 	auvia_hwinit(devc);
 
-	/* allow ac97 operations again */
-	ac97_resume(devc->ac97);
-
-	mutex_enter(&devc->mutex);
-	devc->suspended = B_TRUE;
-	for (int i = 0; i < AUVIA_NUM_PORTC; i++) {
-
-		auvia_portc_t *portc = devc->portc[i];
+	ac97_reset(devc->ac97);
 
-		if (portc->engine != NULL)
-			audio_engine_reset(portc->engine);
-
-		/* reset the port */
-		portc->reset(portc);
+	audio_dev_resume(devc->adev);
 
-		if (portc->started) {
-			auvia_start_port(portc);
-		} else {
-			auvia_stop_port(portc);
-		}
-	}
-	mutex_exit(&devc->mutex);
 	return (DDI_SUCCESS);
 }
 
@@ -941,16 +667,8 @@
 int
 auvia_suspend(auvia_devc_t *devc)
 {
-	ac97_suspend(devc->ac97);
-
-	mutex_enter(&devc->mutex);
-	for (int i = 0; i < AUVIA_NUM_PORTC; i++) {
+	audio_dev_suspend(devc->adev);
 
-		auvia_portc_t *portc = devc->portc[i];
-		auvia_stop_port(portc);
-	}
-	devc->suspended = B_TRUE;
-	mutex_exit(&devc->mutex);
 	return (DDI_SUCCESS);
 }
 
@@ -1057,7 +775,7 @@
 	for (int i = 0; i < AUVIA_NUM_PORTC; i++) {
 
 		auvia_portc_t *portc = devc->portc[i];
-		auvia_stop_port(portc);
+		OUTB(devc, portc->base + OFF_CTRL, CTRL_TERMINATE);
 	}
 	return (DDI_SUCCESS);
 }
--- a/usr/src/uts/common/io/audio/drv/audiovia823x/audiovia823x.conf	Tue Mar 16 09:43:38 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# Configuration file for the audiovia823x audio driver.
-#
-#	WARNING: This is an UNSTABLE configuration file. Its contents
-#		may change at any time.
-
-#
-# 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 audiovia823x
-# driver enforces a maximum and minimum count.
-#
-play-interrupts=175;
-record-interrupts=175;
--- a/usr/src/uts/common/io/audio/drv/audiovia823x/audiovia823x.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiovia823x/audiovia823x.h	Tue Mar 16 09:30:41 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -62,10 +62,6 @@
 #define	AUVIA_NUM_PORTC		2
 #define	AUVIA_NUM_SGD		16	/* number of fragments */
 
-#define	AUVIA_MAX_INTRS		256
-#define	AUVIA_MIN_INTRS		24
-#define	AUVIA_INTRS		175
-
 #define	AUVIA_SGD_EOL		0x80000000
 #define	AUVIA_SGD_FLAG		0x40000000
 
@@ -127,7 +123,6 @@
 	auvia_devc_t		*devc;
 	audio_engine_t		*engine;
 	caddr_t			base;		/* base for registers */
-	boolean_t		started;
 	int			nchan;
 
 	ddi_dma_handle_t	sgd_dmah;	/* dma for descriptors */
@@ -142,11 +137,8 @@
 	size_t			buf_size;
 	int			syncdir;
 
-	unsigned		intrs;
-	unsigned		fragfr;
-	unsigned		fragsz;
-	unsigned		cur_frag;
-	unsigned		resid;
+	unsigned		nframes;
+	unsigned		pos;
 
 	uint64_t		count;
 
@@ -159,8 +151,6 @@
 	dev_info_t		*dip;
 	audio_dev_t		*adev;
 	ac97_t			*ac97;
-	kstat_t			*ksp;
-	boolean_t		suspended;
 
 	char			*chip_name;
 	int			chip_type;
@@ -172,9 +162,6 @@
 	ddi_acc_handle_t	regsh;
 	caddr_t			base;
 
-	kmutex_t		mutex;		/* For normal locking */
-	kmutex_t		low_mutex;	/* For low level routines */
-	ddi_intr_handle_t	ih;
 	auvia_portc_t		*portc[AUVIA_NUM_PORTC];
 };
 
--- a/usr/src/uts/common/io/audio/drv/audiovia97/audiovia97.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiovia97/audiovia97.c	Tue Mar 16 09:30:41 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -92,7 +92,7 @@
 static int via97_detach(via97_devc_t *);
 static int via97_suspend(via97_devc_t *);
 
-static int via97_open(void *, int, unsigned *, unsigned *, caddr_t *);
+static int via97_open(void *, int, unsigned *, caddr_t *);
 static void via97_close(void *);
 static int via97_start(void *);
 static void via97_stop(void *);
@@ -101,18 +101,13 @@
 static int via97_rate(void *);
 static uint64_t via97_count(void *);
 static void via97_sync(void *, unsigned);
+static uint_t via97_playahead(void *);
 
 static uint16_t via97_read_ac97(void *, uint8_t);
 static void via97_write_ac97(void *, uint8_t, uint16_t);
 static int via97_alloc_port(via97_devc_t *, int);
-static void via97_start_port(via97_portc_t *);
-static void via97_stop_port(via97_portc_t *);
-static void via97_update_port(via97_portc_t *);
-static void via97_reset_port(via97_portc_t *);
 static void via97_destroy(via97_devc_t *);
-static int via97_setup_intrs(via97_devc_t *);
 static void via97_hwinit(via97_devc_t *);
-static uint_t via97_intr(caddr_t, caddr_t);
 
 static audio_engine_ops_t via97_engine_ops = {
 	AUDIO_ENGINE_VERSION,
@@ -127,7 +122,7 @@
 	via97_sync,
 	NULL,
 	NULL,
-	NULL
+	via97_playahead
 };
 
 static uint16_t
@@ -140,7 +135,6 @@
 	if (index > 0x7F)
 		return (0xffff);
 
-	mutex_enter(&devc->low_mutex);
 	addr = (index << 16) + CODEC_RD;
 	OUTL(devc, devc->base + AC97CODEC, addr);
 	drv_usecwait(100);
@@ -153,7 +147,6 @@
 		drv_usecwait(50);
 	}
 	if (i == CODEC_TIMEOUT_COUNT) {
-		mutex_exit(&devc->low_mutex);
 		return (0xffff);
 	}
 
@@ -161,10 +154,8 @@
 	tmp = INL(devc, devc->base + AC97CODEC);
 	OUTB(devc, devc->base + AC97CODEC + 3, 0x02);
 	if (((tmp & CODEC_INDEX) >> 16) == index) {
-		mutex_exit(&devc->low_mutex);
 		return ((int)tmp & CODEC_DATA);
 	}
-	mutex_exit(&devc->low_mutex);
 	return (0xffff);
 }
 
@@ -175,7 +166,6 @@
 	int value = 0;
 	unsigned int i = 0;
 
-	mutex_enter(&devc->low_mutex);
 	value = (index << 16) + data;
 	OUTL(devc, devc->base + AC97CODEC, value);
 	drv_usecwait(100);
@@ -187,61 +177,6 @@
 			break;
 		drv_usecwait(50);
 	}
-	mutex_exit(&devc->low_mutex);
-}
-
-static uint_t
-via97_recintr(via97_devc_t *devc)
-{
-	int status;
-
-	status = INB(devc, devc->base + 0x10);
-
-	if (!(status & 0x01)) /* No interrupt */
-		return (B_FALSE);
-
-	audio_engine_produce(devc->portc[VIA97_REC_SGD_NUM]->engine);
-
-	OUTB(devc, devc->base + 0x10, status | 0x01); /* Ack */
-	return (B_TRUE);
-}
-
-static uint_t
-via97_playintr(via97_devc_t *devc)
-{
-	int status;
-
-	status = INB(devc, devc->base + 0x00);
-
-	if (!(status & 0x01)) /* No interrupt */
-		return (B_FALSE);
-
-	audio_engine_consume(devc->portc[VIA97_PLAY_SGD_NUM]->engine);
-
-	OUTB(devc, devc->base + 0x00, status | 0x01); /* Ack */
-	return (B_TRUE);
-}
-
-static uint_t
-via97_intr(caddr_t argp, caddr_t nocare)
-{
-	via97_devc_t	*devc = (void *)argp;
-
-	_NOTE(ARGUNUSED(nocare));
-
-	if (devc->suspended) {
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	if (!via97_recintr(devc) && !via97_playintr(devc)) {
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	if (devc->ksp) {
-		VIA97_KIOP(devc)->intrs[KSTAT_INTR_HARD]++;
-	}
-
-	return (DDI_INTR_CLAIMED);
 }
 
 /*
@@ -249,37 +184,23 @@
  */
 
 int
-via97_open(void *arg, int flag,
-    unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp)
+via97_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
 {
 	via97_portc_t	 *portc = arg;
-	via97_devc_t	 *devc = portc->devc;
 
 	_NOTE(ARGUNUSED(flag));
 
-	portc->started = B_FALSE;
 	portc->count = 0;
-	*fragfrp = portc->fragfr;
-	*nfragsp = VIA97_NUM_SGD;
+	*nframesp = portc->nframes;
 	*bufp = portc->buf_kaddr;
 
-	mutex_enter(&devc->mutex);
-	via97_reset_port(portc);
-	mutex_exit(&devc->mutex);
-
 	return (0);
 }
 
 void
 via97_close(void *arg)
 {
-	via97_portc_t	 *portc = arg;
-	via97_devc_t	 *devc = portc->devc;
-
-	mutex_enter(&devc->mutex);
-	via97_stop_port(portc);
-	portc->started = B_FALSE;
-	mutex_exit(&devc->mutex);
+	_NOTE(ARGUNUSED(arg));
 }
 
 int
@@ -288,12 +209,18 @@
 	via97_portc_t	*portc = arg;
 	via97_devc_t	*devc = portc->devc;
 
-	mutex_enter(&devc->mutex);
-	if (!portc->started) {
-		via97_start_port(portc);
-		portc->started = B_TRUE;
-	}
-	mutex_exit(&devc->mutex);
+	portc->pos = 0;
+
+	OUTB(devc, portc->base + 0x01, 0x40); /* Stop */
+	OUTL(devc, portc->base + 4, portc->sgd_paddr);
+	/* Set autostart at EOL, stereo, 16 bits */
+	OUTB(devc, portc->base + 0x02,
+	    0x80 |	/* Set autostart at EOL */
+	    0x20 |	/* 16 bits */
+	    0x10);	/* Stereo */
+
+	OUTB(devc, portc->base + 0x01, 0x80); /* Start */
+
 	return (0);
 }
 
@@ -303,12 +230,7 @@
 	via97_portc_t	*portc = arg;
 	via97_devc_t	*devc = portc->devc;
 
-	mutex_enter(&devc->mutex);
-	if (portc->started) {
-		via97_stop_port(portc);
-		portc->started = B_FALSE;
-	}
-	mutex_exit(&devc->mutex);
+	OUTB(devc, portc->base + 0x01, 0x40); /* Stop */
 }
 
 int
@@ -344,112 +266,45 @@
 	(void) ddi_dma_sync(portc->buf_dmah, 0, 0, portc->syncdir);
 }
 
+uint_t
+via97_playahead(void *arg)
+{
+	_NOTE(ARGUNUSED(arg));
+
+	/*
+	 * We see some situations where the default 1.5 fragments from
+	 * the framework is not enough.  800-900 frame jitter is not
+	 * uncommon.  Especially at startup.
+	 */
+	return (1024);
+}
+
 uint64_t
 via97_count(void *arg)
 {
 	via97_portc_t	*portc = arg;
 	via97_devc_t	*devc = portc->devc;
-	uint64_t	val;
+	uint32_t	pos;
+	uint32_t	n;
+
+	pos = INL(devc, portc->base + 0x0c) & 0xffffff;
+	/* convert from bytes to 16-bit stereo frames */
+	pos /= (sizeof (int16_t) * 2);
 
-	mutex_enter(&devc->mutex);
-	via97_update_port(portc);
-	/*
-	 * The residual is in bytes.  We have to convert to frames,
-	 * and then subtract it from the fragment size to get the
-	 * number of frames processed.  Note that we have 16 bit
-	 * stereo frames.
-	 */
-	val = portc->count +
-	    (portc->fragfr - (portc->resid / (2 * 2)));
-	mutex_exit(&devc->mutex);
+	if (pos >= portc->pos) {
+		n = portc->nframes - (pos - portc->pos);
+	} else {
+		n = portc->pos - pos;
+	}
+	portc->pos = pos;
+	portc->count += n;
 
-	return (val);
+	return (portc->count);
 }
 
 
 /* private implementation bits */
 
-void
-via97_start_port(via97_portc_t *portc)
-{
-	via97_devc_t	*devc = portc->devc;
-
-	ASSERT(mutex_owned(&devc->mutex));
-
-	if (devc->suspended)
-		return;
-	OUTB(devc, portc->base + 0x01, 0x80); /* Start */
-}
-
-void
-via97_stop_port(via97_portc_t *portc)
-{
-	via97_devc_t	*devc = portc->devc;
-
-	if (devc->suspended)
-		return;
-
-	OUTB(devc, portc->base + 0x01, 0x40); /* Stop */
-}
-
-void
-via97_update_port(via97_portc_t *portc)
-{
-/*
- * Unfortunately the controller seems to raise interrupt about 32 bytes before
- * the DMA pointer moves to a new fragment. This means that the bytes value
- * returned will be bogus during few samples before
- * the pointer wraps back to the beginning of buffer.
- */
-	via97_devc_t	*devc = portc->devc;
-	uint32_t	frag, resid;
-	uint32_t	n;
-
-	ASSERT(mutex_owned(&devc->mutex));
-	if (devc->suspended) {
-		portc->cur_frag = 0;
-		portc->resid = portc->fragsz;
-		n = 0;
-	} else {
-		resid = INL(devc, portc->base + 0x0c) & 0xffffff;
-		resid = portc->fragsz - resid;
-
-		frag =
-		    ((INL(devc, portc->base + 0x04) - portc->sgd_paddr) / 8) -
-		    1;
-
-		portc->resid = resid;
-
-		if (frag >= portc->cur_frag) {
-			n = frag - portc->cur_frag;
-		} else {
-			n = frag + VIA97_NUM_SGD - portc->cur_frag;
-		}
-		portc->count += (n * portc->fragfr);
-		portc->cur_frag = frag;
-	}
-}
-
-void
-via97_reset_port(via97_portc_t *portc)
-{
-	via97_devc_t	*devc = portc->devc;
-
-	portc->cur_frag = 0;
-	portc->resid = portc->fragsz;
-
-	if (devc->suspended)
-		return;
-
-	OUTB(devc, portc->base + 0x01, 0x40); /* Stop */
-	OUTL(devc, portc->base + 4, portc->sgd_paddr);
-	/* Set autostart at EOL, interrupt on FLAG, stereo, 16 bits */
-	OUTB(devc, portc->base + 0x02,
-	    0x81 |	/* Set autostart at EOL, interrupt on FLAG */
-	    0x20 |	/* 16 bits */
-	    0x10);	/* Stereo */
-}
-
 int
 via97_alloc_port(via97_devc_t *devc, int num)
 {
@@ -458,28 +313,23 @@
 	ddi_dma_cookie_t	cookie;
 	uint_t			count;
 	int			dir;
-	char			*prop;
 	unsigned		caps;
 	audio_dev_t		*adev;
 	uint32_t		*desc;
-	uint32_t		paddr;
 
 	adev = devc->adev;
 	portc = kmem_zalloc(sizeof (*portc), KM_SLEEP);
 	devc->portc[num] = portc;
 	portc->devc = devc;
-	portc->started = B_FALSE;
 	portc->base = devc->base + num * 0x10;
 
 	switch (num) {
 	case VIA97_REC_SGD_NUM:
-		prop = "record-interrupts";
 		portc->syncdir = DDI_DMA_SYNC_FORKERNEL;
 		caps = ENGINE_INPUT_CAP;
 		dir = DDI_DMA_READ;
 		break;
 	case VIA97_PLAY_SGD_NUM:
-		prop = "play-interrupts";
 		portc->syncdir = DDI_DMA_SYNC_FORDEV;
 		caps = ENGINE_OUTPUT_CAP;
 		dir = DDI_DMA_WRITE;
@@ -488,24 +338,9 @@
 		return (DDI_FAILURE);
 	}
 
-	/* figure out fragment configuration */
-	portc->intrs = ddi_prop_get_int(DDI_DEV_T_ANY, devc->dip,
-	    DDI_PROP_DONTPASS, prop, VIA97_INTRS);
-
-	/* make sure the values are good */
-	if (portc->intrs < VIA97_MIN_INTRS) {
-		audio_dev_warn(adev, "%s too low, %d, reset to %d",
-		    prop, portc->intrs, VIA97_INTRS);
-		portc->intrs = VIA97_INTRS;
-	} else if (portc->intrs > VIA97_MAX_INTRS) {
-		audio_dev_warn(adev, "%s too high, %d, reset to %d",
-		    prop, portc->intrs, VIA97_INTRS);
-		portc->intrs = VIA97_INTRS;
-	}
-
-	portc->fragfr = 48000 / portc->intrs;
-	portc->fragsz = portc->fragfr * 2 * 2; /* 16 bit stereo frames */
-	portc->buf_size = portc->fragsz * VIA97_NUM_SGD;
+	/* Simplicity -- a single contiguous looping buffer */
+	portc->nframes = 2048;
+	portc->buf_size = portc->nframes * sizeof (int16_t) * 2;
 
 	/* first allocate up space for SGD list */
 	if (ddi_dma_alloc_handle(devc->dip, &dma_attr_sgd,
@@ -514,8 +349,8 @@
 		return (DDI_FAILURE);
 	}
 
-	if (ddi_dma_mem_alloc(portc->sgd_dmah,
-	    VIA97_NUM_SGD * 2 *sizeof (uint32_t), &dev_attr,
+	/* a single SGD entry is only 8 bytes long */
+	if (ddi_dma_mem_alloc(portc->sgd_dmah, 8, &dev_attr,
 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &portc->sgd_kaddr,
 	    &len, &portc->sgd_acch) != DDI_SUCCESS) {
 		audio_dev_warn(adev, "failed to allocate SGD memory");
@@ -552,22 +387,10 @@
 	}
 	portc->buf_paddr = cookie.dmac_address;
 
-	/* now wire descriptors up */
+	/* now wire descriptor up -- we only use one (which has EOL set)! */
 	desc = (void *)portc->sgd_kaddr;
-	paddr = portc->buf_paddr;
-	for (int i = 0; i < VIA97_NUM_SGD; i++) {
-		uint32_t	flags;
-
-		flags = 0x40000000 | portc->fragsz;
-
-		if (i == (VIA97_NUM_SGD - 1)) {
-			flags |= 0x80000000; /* EOL */
-		}
-
-		ddi_put32(portc->sgd_acch, desc++, paddr);
-		ddi_put32(portc->sgd_acch, desc++, flags);
-		paddr += portc->fragsz;
-	}
+	ddi_put32(portc->sgd_acch, desc++, portc->buf_paddr);
+	ddi_put32(portc->sgd_acch, desc++, 0x80000000U | portc->buf_size);
 
 	OUTL(devc, portc->base + 4, portc->sgd_paddr);
 	(void) ddi_dma_sync(portc->sgd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
@@ -584,57 +407,9 @@
 	return (DDI_SUCCESS);
 }
 
-int
-via97_setup_intrs(via97_devc_t *devc)
-{
-	uint_t			ipri;
-	int			actual;
-	int			rv;
-	ddi_intr_handle_t	ih[1];
-
-	rv = ddi_intr_alloc(devc->dip, ih, DDI_INTR_TYPE_FIXED,
-	    0, 1, &actual, DDI_INTR_ALLOC_STRICT);
-	if ((rv != DDI_SUCCESS) || (actual != 1)) {
-		audio_dev_warn(devc->adev,
-		    "Can't alloc interrupt handle (rv %d actual %d)",
-		    rv, actual);
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_get_pri(ih[0], &ipri) != DDI_SUCCESS) {
-		audio_dev_warn(devc->adev, "Can't get interrupt priority");
-		(void) ddi_intr_free(ih[0]);
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_intr_add_handler(ih[0], via97_intr, devc, NULL) !=
-	    DDI_SUCCESS) {
-		audio_dev_warn(devc->adev, "Can't add interrupt handler");
-		(void) ddi_intr_free(ih[0]);
-		return (DDI_FAILURE);
-	}
-
-	devc->ih = ih[0];
-	mutex_init(&devc->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-	mutex_init(&devc->low_mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
-	return (DDI_SUCCESS);
-}
-
 void
 via97_destroy(via97_devc_t *devc)
 {
-	if (devc->ih != NULL) {
-		(void) ddi_intr_disable(devc->ih);
-		(void) ddi_intr_remove_handler(devc->ih);
-		(void) ddi_intr_free(devc->ih);
-		mutex_destroy(&devc->mutex);
-		mutex_destroy(&devc->low_mutex);
-	}
-
-	if (devc->ksp) {
-		kstat_delete(devc->ksp);
-	}
-
 	for (int i = 0; i < VIA97_NUM_PORTC; i++) {
 		via97_portc_t *portc = devc->portc[i];
 		if (!portc)
@@ -753,10 +528,6 @@
 		goto error;
 	}
 
-	if (via97_setup_intrs(devc) != DDI_SUCCESS) {
-		goto error;
-	}
-
 	devc->ac97 = ac97_alloc(dip, via97_read_ac97, via97_write_ac97, devc);
 	if (devc->ac97 == NULL) {
 		audio_dev_warn(devc->adev, "failed to allocate ac97 handle");
@@ -768,19 +539,11 @@
 		goto error;
 	}
 
-	/* set up kernel statistics */
-	if ((devc->ksp = kstat_create(VIA97_NAME, ddi_get_instance(dip),
-	    VIA97_NAME, "controller", KSTAT_TYPE_INTR, 1,
-	    KSTAT_FLAG_PERSISTENT)) != NULL) {
-		kstat_install(devc->ksp);
-	}
-
 	if (audio_dev_register(devc->adev) != DDI_SUCCESS) {
 		audio_dev_warn(devc->adev, "unable to register with framework");
 		goto error;
 	}
 
-	(void) ddi_intr_enable(devc->ih);
 	ddi_report_dev(dip);
 
 	return (DDI_SUCCESS);
@@ -799,28 +562,9 @@
 
 	via97_hwinit(devc);
 
-	/* allow ac97 operations again */
-	ac97_resume(devc->ac97);
-
-	mutex_enter(&devc->mutex);
-	devc->suspended = B_FALSE;
-	for (int i = 0; i < VIA97_NUM_PORTC; i++) {
-
-		via97_portc_t *portc = devc->portc[i];
+	ac97_reset(devc->ac97);
 
-		if (portc->engine != NULL)
-			audio_engine_reset(portc->engine);
-
-		/* reset the port */
-		via97_reset_port(portc);
-
-		if (portc->started) {
-			via97_start_port(portc);
-		} else {
-			via97_stop_port(portc);
-		}
-	}
-	mutex_exit(&devc->mutex);
+	audio_dev_resume(devc->adev);
 	return (DDI_SUCCESS);
 }
 
@@ -837,16 +581,7 @@
 int
 via97_suspend(via97_devc_t *devc)
 {
-	ac97_suspend(devc->ac97);
-
-	mutex_enter(&devc->mutex);
-	for (int i = 0; i < VIA97_NUM_PORTC; i++) {
-
-		via97_portc_t *portc = devc->portc[i];
-		via97_stop_port(portc);
-	}
-	devc->suspended = B_TRUE;
-	mutex_exit(&devc->mutex);
+	audio_dev_suspend(devc->adev);
 	return (DDI_SUCCESS);
 }
 
@@ -950,12 +685,6 @@
 
 	devc = ddi_get_driver_private(dip);
 
-	for (int i = 0; i < VIA97_NUM_PORTC; i++) {
-
-		via97_portc_t *portc = devc->portc[i];
-		via97_stop_port(portc);
-	}
-
 	/*
 	 * Turn off the hardware
 	 */
--- a/usr/src/uts/common/io/audio/drv/audiovia97/audiovia97.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/drv/audiovia97/audiovia97.h	Tue Mar 16 09:30:41 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -38,15 +38,10 @@
 #define	VIA97_NUM_PORTC		2
 #define	VIA97_PLAY_SGD_NUM	0
 #define	VIA97_REC_SGD_NUM	1
-#define	VIA97_NUM_SGD	512		/* Max number of SGD entries (4k/8) */
 
 #define	VIA_VENDOR_ID		0x1106
 #define	VIA_82C686		0x3058
 
-#define	VIA97_MAX_INTRS		256
-#define	VIA97_MIN_INTRS		24
-#define	VIA97_INTRS		175
-
 #define	CODEC_TIMEOUT_COUNT	500
 #define	AC97CODEC	0x80	/* Access AC97 Codec */
 #define	IN_CMD		0x01000000	/* busy in sending */
@@ -63,12 +58,9 @@
 	via97_devc_t *devc;
 	audio_engine_t *engine;
 
-	int started;
-	unsigned		intrs;
-	unsigned		fragfr;
-	unsigned		fragsz;
-	unsigned		cur_frag;
-	unsigned		resid;
+	int			started;
+	unsigned		nframes;
+	unsigned		pos;
 	caddr_t			base;
 
 	ddi_dma_handle_t	sgd_dmah;	/* dma for descriptors */
@@ -90,15 +82,10 @@
 	dev_info_t		*dip;
 	audio_dev_t		*adev;
 	ac97_t			*ac97;
-	kstat_t			*ksp;
 
-	boolean_t		suspended;
 	ddi_acc_handle_t	pcih;
 	ddi_acc_handle_t	regsh;
 	caddr_t			base;
-	kmutex_t		mutex;		/* For normal locking */
-	kmutex_t		low_mutex;	/* For low level routines */
-	ddi_intr_handle_t	ih;
 
 	via97_portc_t *portc[VIA97_NUM_PORTC];
 };
--- a/usr/src/uts/common/io/audio/impl/audio_client.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/impl/audio_client.c	Tue Mar 16 09:30:41 2010 -0700
@@ -21,7 +21,7 @@
 /*
  * Copyright (C) 4Front Technologies 1996-2008.
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -109,32 +109,32 @@
 	return (sp->s_user_parms->p_rate);
 }
 
-unsigned
+uint_t
 auclnt_get_fragsz(audio_stream_t *sp)
 {
 	return (sp->s_fragbytes);
 }
 
-unsigned
+uint_t
 auclnt_get_framesz(audio_stream_t *sp)
 {
 	return (sp->s_framesz);
 }
 
-unsigned
+uint_t
 auclnt_get_nfrags(audio_stream_t *sp)
 {
 	return (sp->s_nfrags);
 }
 
-unsigned
+uint_t
 auclnt_get_nframes(audio_stream_t *sp)
 {
 	return (sp->s_nframes);
 }
 
 void
-auclnt_set_latency(audio_stream_t *sp, unsigned frags, unsigned bytes)
+auclnt_set_latency(audio_stream_t *sp, uint_t frags, uint_t bytes)
 {
 	mutex_enter(&sp->s_lock);
 	sp->s_hintfrags = (uint16_t)frags;
@@ -154,13 +154,13 @@
 	return (sp->s_tail);
 }
 
-unsigned
+uint_t
 auclnt_get_hidx(audio_stream_t *sp)
 {
 	return (sp->s_hidx);
 }
 
-unsigned
+uint_t
 auclnt_get_tidx(audio_stream_t *sp)
 {
 	return (sp->s_tidx);
@@ -178,21 +178,21 @@
 	return (&c->c_ostream);
 }
 
-unsigned
+uint_t
 auclnt_get_count(audio_stream_t *sp)
 {
-	unsigned	count;
+	uint_t	count;
 
 	mutex_enter(&sp->s_lock);
 	ASSERT((sp->s_head - sp->s_tail) <= sp->s_nframes);
-	count = (unsigned)(sp->s_head - sp->s_tail);
+	count = (uint_t)(sp->s_head - sp->s_tail);
 	mutex_exit(&sp->s_lock);
 
 	return (count);
 }
 
-unsigned
-auclnt_consume(audio_stream_t *sp, unsigned n)
+uint_t
+auclnt_consume(audio_stream_t *sp, uint_t n)
 {
 	mutex_enter(&sp->s_lock);
 
@@ -212,12 +212,12 @@
 	return (n);
 }
 
-unsigned
-auclnt_consume_data(audio_stream_t *sp, caddr_t dst, unsigned n)
+uint_t
+auclnt_consume_data(audio_stream_t *sp, caddr_t dst, uint_t n)
 {
-	unsigned nframes;
-	unsigned framesz;
-	unsigned cnt;
+	uint_t nframes;
+	uint_t framesz;
+	uint_t cnt;
 	caddr_t	data;
 
 	mutex_enter(&sp->s_lock);
@@ -233,7 +233,7 @@
 	cnt = n = min(n, sp->s_head - sp->s_tail);
 	data = sp->s_data + (sp->s_tidx * framesz);
 	do {
-		unsigned nf, nb;
+		uint_t nf, nb;
 
 		nf = min(nframes - sp->s_tidx, n);
 		nb = nf * framesz;
@@ -259,8 +259,8 @@
 	return (cnt);
 }
 
-unsigned
-auclnt_produce(audio_stream_t *sp, unsigned n)
+uint_t
+auclnt_produce(audio_stream_t *sp, uint_t n)
 {
 	mutex_enter(&sp->s_lock);
 
@@ -280,12 +280,12 @@
 	return (n);
 }
 
-unsigned
-auclnt_produce_data(audio_stream_t *sp, caddr_t src, unsigned n)
+uint_t
+auclnt_produce_data(audio_stream_t *sp, caddr_t src, uint_t n)
 {
-	unsigned nframes;
-	unsigned framesz;
-	unsigned cnt;
+	uint_t nframes;
+	uint_t framesz;
+	uint_t cnt;
 	caddr_t data;
 
 	mutex_enter(&sp->s_lock);
@@ -301,7 +301,7 @@
 	cnt = n = min(n, nframes - (sp->s_head - sp->s_tail));
 	data = sp->s_data + (sp->s_hidx * framesz);
 	do {
-		unsigned nf, nb;
+		uint_t nf, nb;
 
 		nf = min(nframes - sp->s_hidx, n);
 		nb = nf * framesz;
@@ -332,10 +332,12 @@
 auclnt_read(audio_client_t *c, struct uio *uio)
 {
 	audio_stream_t	*sp = &c->c_istream;
-	unsigned	cnt;
+	uint_t		cnt;
 	int		rv = 0;
 	offset_t	loff;
 	int		eagain;
+	uint_t		tidx;
+	uint_t		framesz;
 
 	loff = uio->uio_loffset;
 	eagain = EAGAIN;
@@ -348,11 +350,13 @@
 		mutex_enter(&sp->s_lock);
 	}
 
+
+	framesz = sp->s_framesz;
+
 	ASSERT(sp->s_head >= sp->s_tail);
 	ASSERT(sp->s_tidx < sp->s_nframes);
-	ASSERT(sp->s_hidx < sp->s_nframes);
 
-	while (uio->uio_resid >= sp->s_framesz) {
+	while (uio->uio_resid >= framesz) {
 
 		while ((cnt = (sp->s_head - sp->s_tail)) == 0) {
 			if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) {
@@ -365,19 +369,22 @@
 			}
 		}
 
-		cnt = min(cnt, sp->s_nframes - sp->s_tidx);
-		cnt = min(cnt, (uio->uio_resid / sp->s_framesz));
+		tidx = sp->s_tidx;
+		cnt = min(cnt, sp->s_nframes - tidx);
+		cnt = min(cnt, (uio->uio_resid / framesz));
 
-		rv = uiomove(sp->s_data + (sp->s_tidx * sp->s_framesz),
-		    cnt * sp->s_framesz, UIO_READ, uio);
+		mutex_exit(&sp->s_lock);
+		rv = uiomove(sp->s_data + (tidx * framesz),
+		    cnt * framesz, UIO_READ, uio);
+
 		uio->uio_loffset = loff;
 		eagain = 0;
 
 		if (rv != 0) {
-			mutex_exit(&sp->s_lock);
 			return (rv);
 		}
 
+		mutex_enter(&sp->s_lock);
 		sp->s_tail += cnt;
 		sp->s_tidx += cnt;
 		if (sp->s_tidx == sp->s_nframes) {
@@ -400,21 +407,24 @@
 auclnt_write(audio_client_t *c, struct uio *uio)
 {
 	audio_stream_t *sp = &c->c_ostream;
-	unsigned	cnt;
+	uint_t		cnt;
 	int		rv = 0;
 	offset_t	loff;
 	int		eagain;
+	uint_t		framesz;
+	uint_t		hidx;
 
 	loff = uio->uio_loffset;
 	eagain = EAGAIN;
 
 	mutex_enter(&sp->s_lock);
 
+	framesz = sp->s_framesz;
+
 	ASSERT(sp->s_head >= sp->s_tail);
-	ASSERT(sp->s_tidx < sp->s_nframes);
 	ASSERT(sp->s_hidx < sp->s_nframes);
 
-	while (uio->uio_resid >= sp->s_framesz) {
+	while (uio->uio_resid >= framesz) {
 
 		while ((cnt = sp->s_nframes - (sp->s_head - sp->s_tail)) == 0) {
 			if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) {
@@ -427,19 +437,31 @@
 			}
 		}
 
-		cnt = min(cnt, sp->s_nframes - sp->s_hidx);
-		cnt = min(cnt, (uio->uio_resid / sp->s_framesz));
+		hidx = sp->s_hidx;
+		cnt = min(cnt, sp->s_nframes - hidx);
+		cnt = min(cnt, (uio->uio_resid / framesz));
 
-		rv = uiomove(sp->s_data + (sp->s_hidx * sp->s_framesz),
-		    cnt * sp->s_framesz, UIO_WRITE, uio);
+		/*
+		 * We have to drop the stream lock, because the
+		 * uiomove might require doing a page in, which could
+		 * get blocked behind the PIL of the audio processing
+		 * thread which also grabs the s_lock.  (Hence, there
+		 * is a risk of deadlock due to priority inversion.)
+		 */
+		mutex_exit(&sp->s_lock);
+
+		rv = uiomove(sp->s_data + (hidx * framesz),
+		    cnt * framesz, UIO_WRITE, uio);
+
 		uio->uio_loffset = loff;
 		eagain = 0;
 
 		if (rv != 0) {
-			mutex_exit(&sp->s_lock);
 			return (rv);
 		}
 
+		mutex_enter(&sp->s_lock);
+
 		sp->s_head += cnt;
 		sp->s_hidx += cnt;
 		if (sp->s_hidx == sp->s_nframes) {
@@ -509,12 +531,12 @@
 }
 
 void
-auclnt_get_output_qlen(audio_client_t *c, unsigned *slen, unsigned *flen)
+auclnt_get_output_qlen(audio_client_t *c, uint_t *slen, uint_t *flen)
 {
 	audio_stream_t	*sp = &c->c_ostream;
 	audio_engine_t	*e = sp->s_engine;
 	uint64_t	el, sl;
-	unsigned	cnt, er, sr;
+	uint_t		cnt, er, sr;
 
 	if (e == NULL) {
 		/* if no output engine, can't do it! */
@@ -533,13 +555,13 @@
 	er = e->e_rate;
 	sl = sp->s_cnv_cnt;
 	sr = sp->s_user_parms->p_rate;
-	cnt = (unsigned)(sp->s_head - sp->s_tail);
+	cnt = (uint_t)(sp->s_head - sp->s_tail);
 	mutex_exit(&sp->s_lock);
 	mutex_exit(&e->e_lock);
 
 	/* engine frames converted to stream rate, plus stream frames */
 	*slen = cnt;
-	*flen = ((unsigned)(((el * sr) / er) + sl));
+	*flen = ((uint_t)(((el * sr) / er) + sl));
 }
 
 int
@@ -1197,6 +1219,39 @@
 	return (c);
 }
 
+int
+auclnt_serialize(audio_client_t *c)
+{
+	mutex_enter(&c->c_lock);
+	while (c->c_serialize) {
+		if (cv_wait_sig(&c->c_cv, &c->c_lock) == 0) {
+			mutex_exit(&c->c_lock);
+			return (EINTR);
+		}
+	}
+	c->c_serialize = B_TRUE;
+	mutex_exit(&c->c_lock);
+	return (0);
+}
+
+void
+auclnt_unserialize(audio_client_t *c)
+{
+	mutex_enter(&c->c_lock);
+	ASSERT(c->c_serialize);
+	c->c_serialize = B_FALSE;
+	cv_broadcast(&c->c_cv);
+	mutex_exit(&c->c_lock);
+}
+
+void
+auclnt_hold(audio_client_t *c)
+{
+	mutex_enter(&c->c_lock);
+	c->c_refcnt++;
+	mutex_exit(&c->c_lock);
+}
+
 void
 auclnt_release(audio_client_t *c)
 {
@@ -1208,7 +1263,7 @@
 	mutex_exit(&c->c_lock);
 }
 
-unsigned
+uint_t
 auclnt_dev_get_serial(audio_dev_t *d)
 {
 	return (d->d_serial);
@@ -1240,7 +1295,7 @@
 
 
 int
-auclnt_open(audio_client_t *c, unsigned fmts, int oflag)
+auclnt_open(audio_client_t *c, uint_t fmts, int oflag)
 {
 	audio_stream_t	*sp;
 	audio_dev_t	*d = c->c_dev;
@@ -1412,11 +1467,11 @@
 	return (dev->d_vers);
 }
 
-unsigned
+uint_t
 auclnt_get_dev_capab(audio_dev_t *dev)
 {
 	uint32_t	flags;
-	unsigned	caps = 0;
+	uint_t		caps = 0;
 
 	flags = dev->d_flags;
 
@@ -1577,13 +1632,13 @@
 {
 	audio_ctrl_t *ctrl;
 
-	rw_enter(&d->d_ctrl_lock, RW_READER);
+	mutex_enter(&d->d_ctrl_lock);
 	for (ctrl = list_head(&d->d_controls); ctrl;
 	    ctrl = list_next(&d->d_controls, ctrl)) {
 		if (walker(ctrl, arg) == AUDIO_WALK_STOP)
 			break;
 	}
-	rw_exit(&d->d_ctrl_lock);
+	mutex_exit(&d->d_ctrl_lock);
 }
 
 /*
@@ -1604,15 +1659,15 @@
 	/* Verify argument */
 	ASSERT(d);
 
-	rw_enter(&d->d_ctrl_lock, RW_READER);
+	mutex_enter(&d->d_ctrl_lock);
 	for (ctrl = list_head(&d->d_controls); ctrl;
 	    ctrl = list_next(&d->d_controls, ctrl)) {
 		if (strcmp(ctrl->ctrl_name, name) == 0) {
-			rw_exit(&d->d_ctrl_lock);
+			mutex_exit(&d->d_ctrl_lock);
 			return (ctrl);
 		}
 	}
-	rw_exit(&d->d_ctrl_lock);
+	mutex_exit(&d->d_ctrl_lock);
 	return (NULL);
 }
 
--- a/usr/src/uts/common/io/audio/impl/audio_client.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/impl/audio_client.h	Tue Mar 16 09:30:41 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -94,26 +94,26 @@
 
 void auclnt_flush(audio_stream_t *);
 
-void auclnt_get_output_qlen(audio_client_t *, unsigned *, unsigned *);
+void auclnt_get_output_qlen(audio_client_t *, uint_t *, uint_t *);
 
-unsigned auclnt_get_fragsz(audio_stream_t *);
-unsigned auclnt_get_framesz(audio_stream_t *);
-unsigned auclnt_get_nfrags(audio_stream_t *);
-unsigned auclnt_get_nframes(audio_stream_t *);
-unsigned auclnt_get_count(audio_stream_t *);
+uint_t auclnt_get_fragsz(audio_stream_t *);
+uint_t auclnt_get_framesz(audio_stream_t *);
+uint_t auclnt_get_nfrags(audio_stream_t *);
+uint_t auclnt_get_nframes(audio_stream_t *);
+uint_t auclnt_get_count(audio_stream_t *);
 uint64_t auclnt_get_head(audio_stream_t *);
 uint64_t auclnt_get_tail(audio_stream_t *);
-unsigned auclnt_get_hidx(audio_stream_t *);
-unsigned auclnt_get_tidx(audio_stream_t *);
+uint_t auclnt_get_hidx(audio_stream_t *);
+uint_t auclnt_get_tidx(audio_stream_t *);
 
-void auclnt_set_latency(audio_stream_t *, unsigned, unsigned);
+void auclnt_set_latency(audio_stream_t *, uint_t, uint_t);
 
 audio_stream_t *auclnt_input_stream(audio_client_t *);
 audio_stream_t *auclnt_output_stream(audio_client_t *);
 
 int auclnt_get_oflag(audio_client_t *);
 
-int auclnt_open(audio_client_t *, unsigned, int);
+int auclnt_open(audio_client_t *, uint_t, int);
 void auclnt_close(audio_client_t *);
 
 void auclnt_register_ops(minor_t, audio_client_ops_t *);
@@ -124,10 +124,10 @@
 queue_t *auclnt_get_rq(audio_client_t *);
 queue_t *auclnt_get_wq(audio_client_t *);
 
-unsigned auclnt_produce(audio_stream_t *, unsigned);
-unsigned auclnt_produce_data(audio_stream_t *, caddr_t, unsigned);
-unsigned auclnt_consume(audio_stream_t *, unsigned);
-unsigned auclnt_consume_data(audio_stream_t *, caddr_t, unsigned);
+uint_t auclnt_produce(audio_stream_t *, uint_t);
+uint_t auclnt_produce_data(audio_stream_t *, caddr_t, uint_t);
+uint_t auclnt_consume(audio_stream_t *, uint_t);
+uint_t auclnt_consume_data(audio_stream_t *, caddr_t, uint_t);
 int auclnt_read(audio_client_t *, struct uio *);
 int auclnt_write(audio_client_t *, struct uio *);
 int auclnt_chpoll(audio_client_t *, short, int, short *, struct pollhead **);
@@ -159,7 +159,7 @@
 const char *auclnt_get_dev_description(audio_dev_t *);
 const char *auclnt_get_dev_version(audio_dev_t *);
 const char *auclnt_get_dev_hw_info(audio_dev_t *, void **);
-unsigned auclnt_get_dev_capab(audio_dev_t *);
+uint_t auclnt_get_dev_capab(audio_dev_t *);
 #define	AUDIO_CLIENT_CAP_PLAY		(1U << 0)
 #define	AUDIO_CLIENT_CAP_RECORD		(1U << 1)
 #define	AUDIO_CLIENT_CAP_DUPLEX		(1U << 2)
@@ -181,7 +181,7 @@
  * need, and its far lighter weight than forcing an asynchronous
  * callback on everything.
  */
-unsigned auclnt_dev_get_serial(audio_dev_t *);
+uint_t auclnt_dev_get_serial(audio_dev_t *);
 
 /*
  * Audio control functions for use by clients.
@@ -246,6 +246,9 @@
 
 audio_client_t *auclnt_hold_by_devt(dev_t);
 void auclnt_release(audio_client_t *);
+void auclnt_hold(audio_client_t *);
+int auclnt_serialize(audio_client_t *);
+void auclnt_unserialize(audio_client_t *);
 
 /*
  * Engine rlated accesses.  Note that normally clients don't need this level
@@ -256,7 +259,7 @@
 int auclnt_engine_get_format(audio_engine_t *);
 int auclnt_engine_get_rate(audio_engine_t *);
 int auclnt_engine_get_channels(audio_engine_t *);
-unsigned auclnt_engine_get_capab(audio_engine_t *);
+uint_t auclnt_engine_get_capab(audio_engine_t *);
 
 /*
  * Retrieve minor-specific data for the instance.  This allows for
--- a/usr/src/uts/common/io/audio/impl/audio_ctrl.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/impl/audio_ctrl.c	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -139,16 +139,15 @@
 		 * Also by doing this we can use the normal add code to do
 		 * what it normally does below.
 		 */
-		rw_enter(&d->d_ctrl_lock, RW_WRITER);
+		mutex_enter(&d->d_ctrl_lock);
 		list_remove(&d->d_controls, ctrl);
-		rw_exit(&d->d_ctrl_lock);
+		mutex_exit(&d->d_ctrl_lock);
 
 		audio_control_freenames(ctrl);
 		ctrl->ctrl_read_fn = NULL;
 		ctrl->ctrl_write_fn = NULL;
 		ctrl->ctrl_arg = NULL;
 		ctrl->ctrl_dev = NULL;
-		mutex_destroy(&ctrl->ctrl_lock);
 	}
 	new_desc = &ctrl->ctrl_des;
 
@@ -198,11 +197,9 @@
 		ctrl->ctrl_arg = arg;
 	}
 
-	mutex_init(&ctrl->ctrl_lock, NULL, MUTEX_DRIVER, NULL);
-
-	rw_enter(&d->d_ctrl_lock, RW_WRITER);
+	mutex_enter(&d->d_ctrl_lock);
 	list_insert_tail(&d->d_controls, ctrl);
-	rw_exit(&d->d_ctrl_lock);
+	mutex_exit(&d->d_ctrl_lock);
 
 	return (ctrl);
 
@@ -230,11 +227,9 @@
 	d = ctrl->ctrl_dev;
 	ASSERT(d);
 
-	rw_enter(&d->d_ctrl_lock, RW_WRITER);
+	mutex_enter(&d->d_ctrl_lock);
 	list_remove(&d->d_controls, ctrl);
-	rw_exit(&d->d_ctrl_lock);
-
-	mutex_destroy(&ctrl->ctrl_lock);
+	mutex_exit(&d->d_ctrl_lock);
 
 	audio_control_freenames(ctrl);
 	kmem_free(ctrl, sizeof (*ctrl));
@@ -289,26 +284,31 @@
 int
 audio_control_read(audio_ctrl_t *ctrl, uint64_t *value)
 {
-	uint64_t my_value;
-	int ret;
+	audio_dev_t	*d = ctrl->ctrl_dev;
+	uint64_t	my_value;
+	int		ret;
 
-	/* Verify arguments */
-	ASSERT(ctrl);
 	ASSERT(value);
-	ASSERT(ctrl->ctrl_dev);
+
+	mutex_enter(&d->d_ctrl_lock);
+	while (d->d_suspended) {
+		cv_wait(&d->d_ctrl_cv, &d->d_ctrl_lock);
+	}
 
 	if (!(ctrl->ctrl_flags & AUDIO_CTRL_FLAG_READABLE)) {
+		mutex_exit(&d->d_ctrl_lock);
 		return (ENXIO);
 	}
 
 	ASSERT(ctrl->ctrl_read_fn);
 
-	if ((ret = ctrl->ctrl_read_fn(ctrl->ctrl_arg, &my_value)) != 0) {
-		return (ret);
+	ret = ctrl->ctrl_read_fn(ctrl->ctrl_arg, &my_value);
+	mutex_exit(&d->d_ctrl_lock);
+
+	if (ret == 0) {
+		*value = my_value;
 	}
 
-	*value = my_value;
-
 	return (ret);
 }
 
@@ -328,20 +328,85 @@
 	int		ret;
 	audio_dev_t	*d = ctrl->ctrl_dev;
 
-	/* Verify arguments */
-	ASSERT(ctrl);
-	ASSERT(d);
+	mutex_enter(&d->d_ctrl_lock);
+	while (d->d_suspended) {
+		cv_wait(&d->d_ctrl_cv, &d->d_ctrl_lock);
+	}
 
 	if (!(ctrl->ctrl_flags & AUDIO_CTRL_FLAG_WRITEABLE)) {
+		mutex_exit(&d->d_ctrl_lock);
 		return (ENXIO);
 	}
 
 	ASSERT(ctrl->ctrl_write_fn);
 
 	ret = ctrl->ctrl_write_fn(ctrl->ctrl_arg, value);
+	if (ret == 0) {
+		ctrl->ctrl_saved = value;
+		ctrl->ctrl_saved_ok = B_TRUE;
+	}
+	mutex_exit(&d->d_ctrl_lock);
 
-	if (ret == 0)
+	if (ret == 0) {
 		audio_dev_update_controls(d);
+	}
 
 	return (ret);
 }
+
+/*
+ * This is used to save control values.
+ */
+int
+auimpl_save_controls(audio_dev_t *d)
+{
+	audio_ctrl_t	*ctrl;
+	list_t		*l;
+	int		ret;
+
+	ASSERT(mutex_owned(&d->d_ctrl_lock));
+	l = &d->d_controls;
+
+	for (ctrl = list_head(l); ctrl; ctrl = list_next(l, ctrl)) {
+		if ((!(ctrl->ctrl_flags & AUDIO_CTRL_FLAG_WRITEABLE)) ||
+		    (!(ctrl->ctrl_flags & AUDIO_CTRL_FLAG_WRITEABLE))) {
+			continue;
+		}
+		ret = ctrl->ctrl_read_fn(ctrl->ctrl_arg, &ctrl->ctrl_saved);
+		if (ret != 0) {
+			audio_dev_warn(d,
+			    "Unable to save value of control %s",
+			    ctrl->ctrl_name);
+			return (ret);
+		} else {
+			ctrl->ctrl_saved_ok = B_TRUE;
+		}
+	}
+	return (0);
+}
+
+int
+auimpl_restore_controls(audio_dev_t *d)
+{
+	audio_ctrl_t	*ctrl;
+	list_t		*l;
+	int		ret;
+	int		rv = 0;
+
+	ASSERT(mutex_owned(&d->d_ctrl_lock));
+	l = &d->d_controls;
+
+	for (ctrl = list_head(l); ctrl; ctrl = list_next(l, ctrl)) {
+		if (!ctrl->ctrl_saved_ok) {
+			continue;
+		}
+		ret = ctrl->ctrl_write_fn(ctrl->ctrl_arg, ctrl->ctrl_saved);
+		if (ret != 0) {
+			audio_dev_warn(d,
+			    "Unable to restore value of control %s",
+			    ctrl->ctrl_name);
+			rv = ret;
+		}
+	}
+	return (rv);
+}
--- a/usr/src/uts/common/io/audio/impl/audio_ddi.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/impl/audio_ddi.c	Tue Mar 16 09:30:41 2010 -0700
@@ -21,7 +21,7 @@
 /*
  * Copyright (C) 4Front Technologies 1996-2008.
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -275,7 +275,7 @@
 	 * avoids leaving record data stuck in queues.
 	 */
 	if (c->c_istream.s_engine != NULL)
-		audio_engine_produce(c->c_istream.s_engine);
+		auimpl_input_callback(c->c_istream.s_engine);
 
 	/* get a local hold on the device */
 	d = c->c_dev;
@@ -322,7 +322,7 @@
 	 * avoids leaving record data stuck in queues.
 	 */
 	if (c->c_istream.s_engine != NULL)
-		audio_engine_produce(c->c_istream.s_engine);
+		auimpl_input_callback(c->c_istream.s_engine);
 
 	/* get a local hold on the device */
 	d = c->c_dev;
@@ -358,7 +358,10 @@
 	if ((c = auclnt_hold_by_devt(dev)) == NULL) {
 		return (ENXIO);
 	}
-	rv = (c->c_write == NULL) ? ENXIO : c->c_write(c, uio, credp);
+	if ((rv = auclnt_serialize(c)) == 0) {
+		rv = (c->c_write == NULL) ? ENXIO : c->c_write(c, uio, credp);
+		auclnt_unserialize(c);
+	}
 	auclnt_release(c);
 
 	return (rv);
@@ -373,7 +376,10 @@
 	if ((c = auclnt_hold_by_devt(dev)) == NULL) {
 		return (ENXIO);
 	}
-	rv = (c->c_read == NULL) ? ENXIO : c->c_read(c, uio, credp);
+	if ((rv = auclnt_serialize(c)) == 0) {
+		rv = (c->c_read == NULL) ? ENXIO : c->c_read(c, uio, credp);
+		auclnt_unserialize(c);
+	}
 	auclnt_release(c);
 
 	return (rv);
--- a/usr/src/uts/common/io/audio/impl/audio_engine.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/impl/audio_engine.c	Tue Mar 16 09:30:41 2010 -0700
@@ -40,6 +40,16 @@
  * Audio Engine functions.
  */
 
+/*
+ * Globals
+ */
+uint_t		audio_intrhz = AUDIO_INTRHZ;
+/*
+ * We need to operate at fairly high interrupt priority to avoid
+ * underruns due to other less time sensitive processing.
+ */
+int		audio_priority = DDI_IPL_8;
+
 audio_dev_t *
 audio_dev_alloc(dev_info_t *dip, int instance)
 {
@@ -74,7 +84,8 @@
 	d->d_pcmvol = 100;
 	mutex_init(&d->d_lock, NULL, MUTEX_DRIVER, NULL);
 	cv_init(&d->d_cv, NULL, CV_DRIVER, NULL);
-	rw_init(&d->d_ctrl_lock, NULL, RW_DRIVER, NULL);
+	mutex_init(&d->d_ctrl_lock, NULL, MUTEX_DRIVER, NULL);
+	cv_init(&d->d_ctrl_cv, NULL, CV_DRIVER, NULL);
 	list_create(&d->d_clients, sizeof (struct audio_client),
 	    offsetof(struct audio_client, c_dev_linkage));
 	list_create(&d->d_engines, sizeof (struct audio_engine),
@@ -93,6 +104,7 @@
 audio_dev_free(audio_dev_t *d)
 {
 	struct audio_infostr *isp;
+
 	while ((isp = list_remove_head(&d->d_hwinfo)) != NULL) {
 		kmem_free(isp, sizeof (*isp));
 	}
@@ -103,9 +115,10 @@
 	list_destroy(&d->d_engines);
 	list_destroy(&d->d_controls);
 	list_destroy(&d->d_clients);
-	rw_destroy(&d->d_ctrl_lock);
+	mutex_destroy(&d->d_ctrl_lock);
 	mutex_destroy(&d->d_lock);
 	cv_destroy(&d->d_cv);
+	cv_destroy(&d->d_ctrl_cv);
 	kmem_free(d, sizeof (*d));
 }
 
@@ -136,72 +149,36 @@
 	}
 }
 
-void
-audio_engine_consume(audio_engine_t *e)
-{
-	mutex_enter(&e->e_lock);
-	e->e_tail = ENG_COUNT(e);
-	if (e->e_tail > e->e_head) {
-		/* want more data than we have, not much we can do */
-		e->e_errors++;
-		e->e_underruns++;
-	}
-	auimpl_output_callback(e);
-	mutex_exit(&e->e_lock);
-}
-
-void
-audio_engine_produce(audio_engine_t *e)
-{
-	mutex_enter(&e->e_lock);
-	e->e_head = ENG_COUNT(e);
-	if ((e->e_head - e->e_tail) > e->e_nframes) {
-		/* no room for engine data, not much we can do */
-		e->e_errors++;
-		e->e_overruns++;
-	}
-	auimpl_input_callback(e);
-	mutex_exit(&e->e_lock);
-}
-
-void
-audio_engine_reset(audio_engine_t *e)
+static void
+auimpl_engine_reset(audio_engine_t *e)
 {
 	char	*buf;
 	char	*ptr;
-	int	nfr;
-	int	tail;
+	int	nfr, resid, cnt;
+	int	tidx;
 
+	tidx = e->e_tidx;
+	nfr = min(e->e_head - e->e_tail, e->e_nframes);
+	buf = kmem_alloc(nfr * e->e_framesz, KM_SLEEP);
+	ptr = buf;
+	cnt = 0;
+
+	ASSERT(e->e_nframes);
 
-	if ((e->e_flags & (ENGINE_INPUT | ENGINE_OUTPUT)) == 0) {
-		/* engine not open, nothing to do */
-		return;
+	for (resid = nfr; resid; resid -= cnt) {
+		int	nbytes;
+
+		cnt = min((e->e_nframes - tidx), resid);
+		nbytes = cnt * e->e_framesz;
+
+		bcopy(e->e_data + (tidx * e->e_framesz), ptr, nbytes);
+		ptr += nbytes;
+		tidx += cnt;
+		if (tidx == e->e_nframes) {
+			tidx = 0;
+		}
 	}
 
-	buf = kmem_alloc(e->e_nbytes, KM_SLEEP);
-	ptr = buf;
-
-	mutex_enter(&e->e_lock);
-
-	tail = e->e_tidx;
-	nfr = min(e->e_head - e->e_tail, e->e_nframes);
-	while (nfr) {
-		int	cnt;
-		int	nbytes;
-
-		cnt = min((e->e_nframes - tail), nfr);
-		nbytes = cnt * e->e_framesz;
-
-		bcopy(e->e_data + (tail * e->e_framesz), ptr, nbytes);
-		ptr += nbytes;
-		tail += cnt;
-		if (tail >= e->e_framesz) {
-			tail -= e->e_framesz;
-		}
-		nfr -= cnt;
-	}
-
-	nfr = min(e->e_head - e->e_tail, e->e_nframes);
 	if (e->e_flags & ENGINE_INPUT) {
 		/* record */
 		e->e_hidx = 0;
@@ -214,16 +191,18 @@
 
 	/* relocate from scratch area to destination */
 	bcopy(buf, e->e_data + (e->e_tidx * e->e_framesz), nfr * e->e_framesz);
-	mutex_exit(&e->e_lock);
-
-	kmem_free(buf, e->e_nbytes);
+	kmem_free(buf, nfr * e->e_framesz);
 }
 
+static volatile uint_t auimpl_engno = 0;
+
 audio_engine_t *
-audio_engine_alloc(audio_engine_ops_t *ops, unsigned flags)
+audio_engine_alloc(audio_engine_ops_t *ops, uint_t flags)
 {
 	int i;
 	audio_engine_t *e;
+	char tname[32];
+	int num;
 
 	if (ops->audio_engine_version != AUDIO_ENGINE_VERSION) {
 		audio_dev_warn(NULL, "audio engine version mismatch: %d != %d",
@@ -238,7 +217,9 @@
 		return (NULL);
 	}
 	e->e_ops = *ops;
-	mutex_init(&e->e_lock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&e->e_lock, NULL, MUTEX_DRIVER,
+	    DDI_INTR_PRI(audio_priority));
+	cv_init(&e->e_cv, NULL, CV_DRIVER, NULL);
 	list_create(&e->e_streams, sizeof (struct audio_stream),
 	    offsetof(struct audio_stream, s_eng_linkage));
 
@@ -252,6 +233,10 @@
 		}
 	}
 
+	num = atomic_inc_uint_nv(&auimpl_engno);
+
+	(void) snprintf(tname, sizeof (tname), "audio_engine_%d", num);
+
 	e->e_flags = flags & ENGINE_DRIVER_FLAGS;
 	return (e);
 }
@@ -267,8 +252,10 @@
 			    sizeof (int32_t) * AUDIO_CHBUFS);
 		}
 	}
+
 	list_destroy(&e->e_streams);
 	mutex_destroy(&e->e_lock);
+	cv_destroy(&e->e_cv);
 	kmem_free(e, sizeof (*e));
 }
 
@@ -377,11 +364,12 @@
 {
 	audio_engine_t	*e = NULL;
 	list_t		*list;
-	unsigned	caps;
+	uint_t		caps;
 	int		priority = 0;
 	int		rv = ENODEV;
 	int		sampsz;
 	int		i;
+	int		fragfr;
 
 	/*
 	 * Engine selection:
@@ -411,6 +399,11 @@
 	 * and output engines.
 	 */
 
+	/* if engine suspended, wait for it not to be */
+	while (d->d_suspended) {
+		cv_wait(&d->d_ctrl_cv, &d->d_lock);
+	}
+
 again:
 
 	for (audio_engine_t *t = list_head(list); t; t = list_next(list, t)) {
@@ -418,12 +411,20 @@
 
 		/* make sure the engine can do what we want it to */
 		mutex_enter(&t->e_lock);
+
 		if ((((t->e_flags & caps) & caps) == 0) ||
 		    ((ENG_FORMAT(t) & fmts) == 0)) {
 			mutex_exit(&t->e_lock);
 			continue;
 		}
 
+		/* if in failed state, don't assign a new stream here */
+		if (t->e_failed) {
+			mutex_exit(&t->e_lock);
+			rv = EIO;
+			continue;
+		}
+
 		/* if engine is in exclusive use, can't do it */
 		if (t->e_flags & ENGINE_EXCLUSIVE) {
 			mutex_exit(&t->e_lock);
@@ -558,6 +559,13 @@
 		goto done;
 	}
 
+	fragfr = e->e_rate / audio_intrhz;
+	if ((fragfr > AUDIO_CHBUFS) || (fragfr < 1)) {
+		audio_dev_warn(d, "invalid fragment configration");
+		rv = EINVAL;
+		goto done;
+	}
+
 	/* sanity test a few values */
 	if ((e->e_nchan < 0) || (e->e_nchan > AUDIO_MAX_CHANNELS) ||
 	    (e->e_rate < 5000) || (e->e_rate > 192000)) {
@@ -566,52 +574,44 @@
 		goto done;
 	}
 
-	rv = ENG_OPEN(e, &e->e_fragfr, &e->e_nfrags, &e->e_data);
+	rv = ENG_OPEN(e, &e->e_nframes, &e->e_data);
 	if (rv != 0) {
 		audio_dev_warn(d, "unable to open engine");
 		goto done;
 	}
-	if ((e->e_fragfr < 1) || (e->e_data == NULL)) {
+	if ((e->e_nframes <= (fragfr * 2)) || (e->e_data == NULL)) {
 		audio_dev_warn(d, "improper engine configuration");
 		rv = EINVAL;
 		goto done;
 	}
 
-	if ((e->e_fragfr > AUDIO_CHBUFS) || (e->e_nfrags < 2)) {
-		rv = EINVAL;
-		audio_dev_warn(d, "invalid fragment configuration");
-		goto done;
-	}
-
 	e->e_framesz = e->e_nchan * sampsz;
-	e->e_fragbytes = e->e_fragfr * e->e_framesz;
-	e->e_nframes = e->e_nfrags * e->e_fragfr;
-	e->e_intrs = e->e_rate / e->e_fragfr;
-	e->e_nbytes = e->e_nframes * e->e_framesz;
+	e->e_intrs = audio_intrhz;
+	e->e_fragfr = fragfr;
 	e->e_head = 0;
 	e->e_tail = 0;
 	e->e_hidx = 0;
 	e->e_tidx = 0;
 	e->e_limiter_state = 0x10000;
-	bzero(e->e_data, e->e_nbytes);
+	bzero(e->e_data, e->e_nframes * e->e_framesz);
 
 	if (e->e_ops.audio_engine_playahead == NULL) {
-		e->e_playahead = (e->e_fragfr * 3) / 2;
+		e->e_playahead = (fragfr * 3) / 2;
 	} else {
 		e->e_playahead = ENG_PLAYAHEAD(e);
 		/*
 		 * Need to have at least a fragment plus some extra to
 		 * avoid underruns.
 		 */
-		if (e->e_playahead < ((e->e_fragfr * 3) / 2)) {
-			e->e_playahead = (e->e_fragfr * 3) / 2;
+		if (e->e_playahead < ((fragfr * 3) / 2)) {
+			e->e_playahead = (fragfr * 3) / 2;
 		}
 
 		/*
 		 * Impossible to queue more frames than FIFO can hold.
 		 */
 		if (e->e_playahead > e->e_nframes) {
-			e->e_playahead = (e->e_fragfr * 3) / 2;
+			e->e_playahead = (fragfr * 3) / 2;
 		}
 	}
 
@@ -632,24 +632,26 @@
 	 * starting up.
 	 */
 	if (flags & ENGINE_OUTPUT) {
-		auimpl_output_callback(e);
+		auimpl_output_preload(e);
 	}
 
 	/*
-	 * Start the engine up now.
-	 *
-	 * AC3: Note that this will need to be modified for AC3, since
-	 * for AC3 we can't start the device until we actually have
-	 * some data for it from the application.  Probably the best
-	 * way to do this would be to add a flag, ENGINE_DEFERRED or
-	 * somesuch.
+	 * Arrange for the engine to be started.  We defer this to the
+	 * periodic callback, to ensure that the start happens near
+	 * the edge of the periodic callback.  This is necessary to
+	 * ensure that the first fragment processed is about the same
+	 * size as the usual fragment size.  (Basically, the problem
+	 * is that we have only 10 msec resolution with the periodic
+	 * interface, whch is rather unfortunate.)
 	 */
-	if (e->e_ops.audio_engine_start != NULL) {
-		rv = ENG_START(e);
-		if (rv != 0) {
-			ENG_CLOSE(e);
-			goto done;
-		}
+	e->e_need_start = B_TRUE;
+
+	if (e->e_flags & ENGINE_OUTPUT) {
+		e->e_periodic = ddi_periodic_add(auimpl_output_callback, e,
+		    NANOSEC / audio_intrhz, audio_priority);
+	} else {
+		e->e_periodic = ddi_periodic_add(auimpl_input_callback, e,
+		    NANOSEC / audio_intrhz, audio_priority);
 	}
 
 ok:
@@ -670,6 +672,7 @@
 {
 	audio_engine_t	*e = sp->s_engine;
 	audio_dev_t	*d;
+	ddi_periodic_t	p = 0;
 
 	if (e == NULL)
 		return;
@@ -677,20 +680,24 @@
 	d = e->e_dev;
 
 	mutex_enter(&d->d_lock);
+	while (d->d_suspended) {
+		cv_wait(&d->d_ctrl_cv, &d->d_lock);
+	}
 	mutex_enter(&e->e_lock);
 	sp->s_engine = NULL;
 	list_remove(&e->e_streams, sp);
 	if (list_is_empty(&e->e_streams)) {
-		/* if last client holding engine open, close it all down */
-		if (e->e_ops.audio_engine_stop != NULL)
-			ENG_STOP(e);
+		ENG_STOP(e);
+		p = e->e_periodic;
 		e->e_flags &= ENGINE_DRIVER_FLAGS;
 		ENG_CLOSE(e);
 	}
 	mutex_exit(&e->e_lock);
-
 	cv_broadcast(&d->d_cv);
 	mutex_exit(&d->d_lock);
+	if (p != 0) {
+		ddi_periodic_delete(p);
+	}
 }
 
 int
@@ -720,6 +727,7 @@
 		start = 1;
 	}
 	d->d_index = start;
+
 	rw_enter(&auimpl_dev_lock, RW_WRITER);
 	l = &auimpl_devs_by_index;
 	for (srch = list_head(l); srch; srch = list_next(l, srch)) {
@@ -798,10 +806,8 @@
 	st->st_head.value.ui64 = e->e_head;
 	st->st_tail.value.ui64 = e->e_tail;
 	st->st_flags.value.ui32 = e->e_flags;
-	st->st_fragfr.value.ui32 = e->e_fragfr;
-	st->st_nfrags.value.ui32 = e->e_nfrags;
+	st->st_nbytes.value.ui32 = e->e_framesz * e->e_nframes;
 	st->st_framesz.value.ui32 = e->e_framesz;
-	st->st_nbytes.value.ui32 = e->e_nbytes;
 	st->st_hidx.value.ui32 = e->e_hidx;
 	st->st_tidx.value.ui32 = e->e_tidx;
 	st->st_format.value.ui32 = e->e_format;
@@ -814,6 +820,8 @@
 	st->st_stream_underruns.value.ui32 = e->e_stream_underruns;
 	st->st_stream_overruns.value.ui32 = e->e_stream_overruns;
 	st->st_suspended.value.ui32 = e->e_suspended;
+	st->st_failed.value.ui32 = e->e_failed;
+	st->st_playahead.value.ui32 = e->e_playahead;
 	mutex_exit(&e->e_lock);
 
 	return (0);
@@ -844,10 +852,8 @@
 	kstat_named_init(&st->st_head, "head", KSTAT_DATA_UINT64);
 	kstat_named_init(&st->st_tail, "tail", KSTAT_DATA_UINT64);
 	kstat_named_init(&st->st_flags, "flags", KSTAT_DATA_UINT32);
-	kstat_named_init(&st->st_fragfr, "fragfr", KSTAT_DATA_UINT32);
-	kstat_named_init(&st->st_nfrags, "nfrags", KSTAT_DATA_UINT32);
+	kstat_named_init(&st->st_nbytes, "nbytes", KSTAT_DATA_UINT32);
 	kstat_named_init(&st->st_framesz, "framesz", KSTAT_DATA_UINT32);
-	kstat_named_init(&st->st_nbytes, "nbytes", KSTAT_DATA_UINT32);
 	kstat_named_init(&st->st_hidx, "hidx", KSTAT_DATA_UINT32);
 	kstat_named_init(&st->st_tidx, "tidx", KSTAT_DATA_UINT32);
 	kstat_named_init(&st->st_format, "format", KSTAT_DATA_UINT32);
@@ -863,16 +869,18 @@
 	    KSTAT_DATA_UINT32);
 	kstat_named_init(&st->st_stream_underruns, "stream_underruns",
 	    KSTAT_DATA_UINT32);
+	kstat_named_init(&st->st_playahead, "playahead", KSTAT_DATA_UINT32);
 	kstat_named_init(&st->st_suspended, "suspended", KSTAT_DATA_UINT32);
+	kstat_named_init(&st->st_failed, "failed", KSTAT_DATA_UINT32);
 	kstat_install(e->e_ksp);
 }
 
 void
 audio_dev_add_engine(audio_dev_t *d, audio_engine_t *e)
 {
-	e->e_num = d->d_engno++;
+	mutex_enter(&d->d_lock);
 
-	mutex_enter(&d->d_lock);
+	e->e_num = d->d_engno++;
 
 	auimpl_engine_ksinit(d, e);
 
@@ -941,9 +949,7 @@
 	l = &auimpl_devs_by_index;
 	rw_enter(&auimpl_dev_lock, RW_READER);
 	for (d = list_head(l); d; d = list_next(l, d)) {
-		mutex_enter(&d->d_lock);
 		cont = walker(d, arg);
-		mutex_exit(&d->d_lock);
 		if (cont == AUDIO_WALK_STOP)
 			break;
 	}
@@ -960,9 +966,7 @@
 	l = &auimpl_devs_by_number;
 	rw_enter(&auimpl_dev_lock, RW_READER);
 	for (d = list_head(l); d; d = list_next(l, d)) {
-		mutex_enter(&d->d_lock);
 		cont = walker(d, arg);
-		mutex_exit(&d->d_lock);
 		if (cont == AUDIO_WALK_STOP)
 			break;
 	}
@@ -1004,10 +1008,10 @@
 	return (ENG_RATE(e));
 }
 
-unsigned
+uint_t
 auclnt_engine_get_capab(audio_engine_t *e)
 {
-	unsigned capab = 0;
+	uint_t capab = 0;
 
 	if (e->e_flags & ENGINE_INPUT_CAP) {
 		capab |= AUDIO_CLIENT_CAP_RECORD;
@@ -1018,33 +1022,6 @@
 	return (capab);
 }
 
-static void
-auimpl_walk_engines(int (*walker)(audio_engine_t *, void *), void *arg)
-{
-	audio_dev_t	*d;
-	audio_engine_t	*e;
-	list_t		*l1;
-	list_t		*l2;
-	boolean_t	done = B_FALSE;
-
-	rw_enter(&auimpl_dev_lock, RW_READER);
-	l1 = &auimpl_devs_by_index;
-	for (d = list_head(l1); d; d = list_next(l1, d)) {
-		mutex_enter(&d->d_lock);
-		l2 = &d->d_engines;
-		for (e = list_head(l2); e; e = list_next(l2, e)) {
-			if (walker(e, arg) == AUDIO_WALK_STOP) {
-				done = B_TRUE;
-				break;
-			}
-		}
-		mutex_exit(&d->d_lock);
-		if (done)
-			break;
-	}
-	rw_exit(&auimpl_dev_lock);
-}
-
 /*
  * This function suspends an engine.  The intent is to pause the
  * engine temporarily so that it does not underrun while user threads
@@ -1063,25 +1040,116 @@
  * driver gets resumed well in advance of the time when user threads
  * are ready to start operation.
  */
+static void
+auimpl_engine_suspend(audio_engine_t *e)
+{
+	ASSERT(mutex_owned(&e->e_lock));
+
+	if (e->e_failed || e->e_suspended) {
+		e->e_suspended = B_TRUE;
+		return;
+	}
+	e->e_suspended = B_TRUE;
+	if (e->e_flags & ENGINE_INPUT) {
+		e->e_head = ENG_COUNT(e);
+		ENG_STOP(e);
+	}
+	if (e->e_flags & ENGINE_OUTPUT) {
+		e->e_tail = ENG_COUNT(e);
+		ENG_STOP(e);
+	}
+}
+
+static void
+auimpl_engine_resume(audio_engine_t *e)
+{
+	ASSERT(mutex_owned(&e->e_lock));
+	ASSERT(e->e_suspended);
+
+	if (e->e_failed) {
+		/* No longer suspended, but still failed! */
+		e->e_suspended = B_FALSE;
+		return;
+	}
+
+	if (e->e_flags & (ENGINE_INPUT | ENGINE_OUTPUT)) {
+
+		auimpl_engine_reset(e);
+
+		if (e->e_flags & ENGINE_OUTPUT) {
+			auimpl_output_preload(e);
+		}
+
+		e->e_need_start = B_TRUE;
+	}
+	e->e_suspended = B_FALSE;
+	cv_broadcast(&e->e_cv);
+}
+
 static int
-auimpl_engine_suspend(audio_engine_t *e, void *dontcare)
+auimpl_dev_suspend(audio_dev_t *d, void *dontcare)
 {
+	list_t		*l;
+	audio_engine_t	*e;
+
 	_NOTE(ARGUNUSED(dontcare));
 
-	mutex_enter(&e->e_lock);
-	e->e_suspended = B_TRUE;
-	mutex_exit(&e->e_lock);
+	mutex_enter(&d->d_lock);
+	mutex_enter(&d->d_ctrl_lock);
+	if (d->d_suspended) {
+		d->d_suspended++;
+		mutex_exit(&d->d_ctrl_lock);
+		mutex_exit(&d->d_lock);
+		return (AUDIO_WALK_CONTINUE);
+	}
+
+	d->d_suspended++;
+
+	(void) auimpl_save_controls(d);
+	mutex_exit(&d->d_ctrl_lock);
+
+	l = &d->d_engines;
+	for (e = list_head(l); e != NULL; e = list_next(l, e)) {
+		mutex_enter(&e->e_lock);
+		auimpl_engine_suspend(e);
+		mutex_exit(&e->e_lock);
+	}
+	mutex_exit(&d->d_lock);
 
 	return (AUDIO_WALK_CONTINUE);
 }
 
 static int
-auimpl_engine_resume(audio_engine_t *e, void *dontcare)
+auimpl_dev_resume(audio_dev_t *d, void *dontcare)
 {
+	list_t		*l;
+	audio_engine_t	*e;
+
 	_NOTE(ARGUNUSED(dontcare));
-	mutex_enter(&e->e_lock);
-	e->e_suspended = B_FALSE;
-	mutex_exit(&e->e_lock);
+
+	mutex_enter(&d->d_lock);
+	mutex_enter(&d->d_ctrl_lock);
+
+	ASSERT(d->d_suspended);
+	d->d_suspended--;
+	if (d->d_suspended) {
+		mutex_exit(&d->d_ctrl_lock);
+		mutex_exit(&d->d_lock);
+		return (AUDIO_WALK_CONTINUE);
+	}
+
+	(void) auimpl_restore_controls(d);
+	cv_broadcast(&d->d_ctrl_cv);
+	mutex_exit(&d->d_ctrl_lock);
+
+	l = &d->d_engines;
+	for (e = list_head(l); e != NULL; e = list_next(l, e)) {
+		mutex_enter(&e->e_lock);
+		auimpl_engine_resume(e);
+		mutex_exit(&e->e_lock);
+	}
+	mutex_exit(&d->d_lock);
+
 	return (AUDIO_WALK_CONTINUE);
 }
 
@@ -1092,11 +1160,11 @@
 
 	switch (code) {
 	case CB_CODE_CPR_CHKPT:
-		auimpl_walk_engines(auimpl_engine_suspend, NULL);
+		auclnt_walk_devs(auimpl_dev_suspend, NULL);
 		return (B_TRUE);
 
 	case CB_CODE_CPR_RESUME:
-		auimpl_walk_engines(auimpl_engine_resume, NULL);
+		auclnt_walk_devs(auimpl_dev_resume, NULL);
 		return (B_TRUE);
 
 	default:
@@ -1104,6 +1172,18 @@
 	}
 }
 
+void
+audio_dev_suspend(audio_dev_t *d)
+{
+	(void) auimpl_dev_suspend(d, NULL);
+}
+
+void
+audio_dev_resume(audio_dev_t *d)
+{
+	(void) auimpl_dev_resume(d, NULL);
+}
+
 static callb_id_t	auimpl_cpr_id = 0;
 
 void
@@ -1236,22 +1316,3 @@
 		cmn_err(CE_NOTE, "%08x:%s", i - (i % wrap), line);
 	}
 }
-
-/*
- * The following two functions are a temporary workaround for CR6924018
- * in usb audio, and are not to be used for anything else, they WILL be
- * removed in the future.
- */
-void
-audio_engine_lock(audio_engine_t *e)
-{
-	mutex_enter(&e->e_lock);
-
-}
-
-void
-audio_engine_unlock(audio_engine_t *e)
-{
-	mutex_exit(&e->e_lock);
-
-}
--- a/usr/src/uts/common/io/audio/impl/audio_impl.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/impl/audio_impl.h	Tue Mar 16 09:30:41 2010 -0700
@@ -21,7 +21,7 @@
 /*
  * Copyright (C) 4Front Technologies 1996-2008.
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -42,6 +42,10 @@
 #define	AUDIO_VOL_SCALE		256
 #define	AUDIO_DB_SIZE		50
 
+#define	AUDIO_INTRHZ		100
+#define	AUDIO_INTRHZ_MIN	50	/* 20 msec max */
+#define	AUDIO_INTRHZ_MAX	500
+
 struct audio_parms {
 	int		p_format;
 	int		p_rate;
@@ -54,14 +58,10 @@
 	caddr_t			b_data;
 	uint64_t		b_head;
 	uint64_t		b_tail;
-	unsigned		b_hidx;		/* head % nframes */
-	unsigned		b_tidx;		/* tail % nframes */
-	unsigned		b_fragfr;	/* frames per frag */
-	unsigned		b_fragbytes;	/* bytes per frag */
-	unsigned		b_nframes;	/* total frames */
-	unsigned		b_nbytes;	/* total bytes */
-	unsigned		b_nfrags;	/* total frags */
-	unsigned		b_framesz;	/* bytes per frame  */
+	uint_t			b_hidx;		/* head % nframes */
+	uint_t			b_tidx;		/* tail % nframes */
+	uint_t			b_nframes;	/* total frames */
+	uint_t			b_framesz;	/* bytes per frame  */
 };
 
 /*
@@ -75,14 +75,14 @@
 #define	s_bufsz			s_buf.b_size
 #define	s_head			s_buf.b_head
 #define	s_tail			s_buf.b_tail
-#define	s_nfrags		s_buf.b_nfrags
 #define	s_framesz		s_buf.b_framesz
-#define	s_fragfr		s_buf.b_fragfr
-#define	s_fragbytes		s_buf.b_fragbytes
 #define	s_nframes		s_buf.b_nframes
-#define	s_nbytes		s_buf.b_nbytes
 #define	s_tidx			s_buf.b_tidx
 #define	s_hidx			s_buf.b_hidx
+	uint_t			s_nfrags;
+	uint_t			s_fragfr;
+	uint_t			s_nbytes;
+	uint_t			s_fragbytes;
 	ddi_umem_cookie_t	s_cookie;
 	uint32_t		s_allocsz;
 	uint32_t		s_hintsz;	/* latency hints */
@@ -102,7 +102,7 @@
 	 * Sample rate conversion (SRC) and format conversion details.
 	 */
 	struct grc3state	*s_src_state[AUDIO_MAX_CHANNELS];
-	unsigned		s_src_quality;
+	uint_t			s_src_quality;
 	int			s_cnv_max;
 	audio_cnv_func_t	s_converter;
 	uint32_t		*s_cnv_buf0;
@@ -152,7 +152,7 @@
 	/*
 	 * Other bits.
 	 */
-	unsigned		s_engcap;	/* ENGINE_xxx_CAP */
+	uint_t			s_engcap;	/* ENGINE_xxx_CAP */
 };
 
 /*
@@ -166,6 +166,14 @@
 	void			*c_private;
 
 	/*
+	 * We can keep a linked list of clients to "notify" so that
+	 * we can do this outside of locked context.
+	 */
+	audio_client_t		*c_next_input;
+	audio_client_t		*c_next_output;
+	audio_client_t		*c_next_drain;
+
+	/*
 	 * DDI support.
 	 */
 	major_t			c_major;
@@ -180,6 +188,7 @@
 	list_node_t		c_global_linkage;
 	list_node_t		c_dev_linkage;
 	int			c_refcnt;
+	boolean_t		c_serialize;
 
 	kmutex_t		c_lock;
 	kcondvar_t		c_cv;
@@ -188,7 +197,7 @@
 	/*
 	 * Client wide settings... e.g. ops vector, etc.
 	 */
-	unsigned		c_omode;	/* open mode */
+	uint_t			c_omode;	/* open mode */
 	pid_t			c_pid;		/* opening process id */
 	audio_dev_t		*c_dev;
 	cred_t			*c_cred;
@@ -220,7 +229,6 @@
 	kstat_named_t		st_head;
 	kstat_named_t		st_tail;
 	kstat_named_t		st_flags;
-	kstat_named_t		st_fragfr;
 	kstat_named_t		st_nfrags;
 	kstat_named_t		st_framesz;
 	kstat_named_t		st_nbytes;
@@ -235,9 +243,14 @@
 	kstat_named_t		st_engine_overruns;
 	kstat_named_t		st_stream_underruns;
 	kstat_named_t		st_stream_overruns;
+	kstat_named_t		st_playahead;
 	kstat_named_t		st_suspended;
+	kstat_named_t		st_failed;
 };
 
+typedef void (*audio_import_fn_t)(audio_engine_t *, uint_t, audio_stream_t *);
+typedef void (*audio_export_fn_t)(audio_engine_t *, uint_t, uint_t);
+
 /*
  * An audio engine corresponds to a single DMA transfer channel.  It can
  * represent either record or playback, but not both at the same time.
@@ -247,17 +260,17 @@
 struct audio_engine {
 	audio_engine_ops_t	e_ops;
 	void			*e_private;
-	unsigned		e_flags;
+	uint_t			e_flags;
 
 	/*
 	 * Mixing related fields.
 	 */
-	unsigned		e_limiter_state;
+	uint_t			e_limiter_state;
 	int32_t			*e_chbufs[AUDIO_MAX_CHANNELS];
-	unsigned		e_choffs[AUDIO_MAX_CHANNELS];
-	unsigned		e_chincr[AUDIO_MAX_CHANNELS];
-	void			(*e_export)(audio_engine_t *);
-	void			(*e_import)(audio_engine_t *, audio_stream_t *);
+	uint_t			e_choffs[AUDIO_MAX_CHANNELS];
+	uint_t			e_chincr[AUDIO_MAX_CHANNELS];
+	audio_export_fn_t	e_export;
+	audio_import_fn_t	e_import;
 
 	/*
 	 * Underlying physical buffer shared with device driver.
@@ -266,16 +279,12 @@
 #define	e_head			e_buf.b_head
 #define	e_tail			e_buf.b_tail
 #define	e_data			e_buf.b_data
-#define	e_fragfr		e_buf.b_fragfr
-#define	e_fragbytes		e_buf.b_fragbytes
 #define	e_framesz		e_buf.b_framesz
-#define	e_nbytes		e_buf.b_nbytes
 #define	e_nframes		e_buf.b_nframes
-#define	e_nfrags		e_buf.b_nfrags
 #define	e_hidx			e_buf.b_hidx
 #define	e_tidx			e_buf.b_tidx
-
-	unsigned		e_playahead;
+	uint_t			e_fragfr;
+	uint_t			e_playahead;
 
 	int			e_intrs;
 	int			e_errors;
@@ -300,6 +309,8 @@
 	 * Synchronization.
 	 */
 	kmutex_t		e_lock;
+	kcondvar_t		e_cv;
+	ddi_periodic_t		e_periodic;
 
 	/*
 	 * Linkage for per-device list.
@@ -313,7 +324,10 @@
 	 */
 	list_t			e_streams;
 	int			e_nrunning;
-	boolean_t		e_suspended;
+	int			e_suspended;
+	boolean_t		e_failed;
+
+	boolean_t		e_need_start;
 };
 
 struct audio_dev {
@@ -342,9 +356,12 @@
 	 */
 	kmutex_t		d_lock;
 	kcondvar_t		d_cv;
-	krwlock_t		d_ctrl_lock;	/* leaf lock */
+	kmutex_t		d_ctrl_lock;	/* leaf lock */
+	kcondvar_t		d_ctrl_cv;
 	krwlock_t		d_clnt_lock;
-	unsigned		d_refcnt;
+	uint_t			d_refcnt;
+	int			d_suspended;
+	boolean_t		d_failed;
 
 	/*
 	 * Lists of virtual clients, controls and engines.  Protected by
@@ -356,7 +373,7 @@
 	audio_ctrl_t		*d_pcmvol_ctrl;
 	uint64_t		d_pcmvol;
 
-	volatile unsigned	d_serial;
+	volatile uint_t		d_serial;
 
 	/*
 	 * Linkage onto global list of devices.
@@ -403,8 +420,9 @@
 	audio_ctrl_rd_t		ctrl_read_fn;
 	audio_ctrl_wr_t		ctrl_write_fn;
 	list_node_t		ctrl_linkage;
-	kmutex_t		ctrl_lock;
 	void			*ctrl_arg;
+	uint64_t		ctrl_saved;	/* the saved value */
+	boolean_t		ctrl_saved_ok;
 };
 
 
@@ -418,22 +436,23 @@
 int auimpl_format_setup(audio_stream_t *, audio_parms_t *);
 
 /* audio_output.c */
-void auimpl_export_16ne(audio_engine_t *);
-void auimpl_export_16oe(audio_engine_t *);
-void auimpl_export_24ne(audio_engine_t *);
-void auimpl_export_24oe(audio_engine_t *);
-void auimpl_export_32ne(audio_engine_t *);
-void auimpl_export_32oe(audio_engine_t *);
-void auimpl_output_callback(audio_engine_t *);
+void auimpl_export_16ne(audio_engine_t *, uint_t, uint_t);
+void auimpl_export_16oe(audio_engine_t *, uint_t, uint_t);
+void auimpl_export_24ne(audio_engine_t *, uint_t, uint_t);
+void auimpl_export_24oe(audio_engine_t *, uint_t, uint_t);
+void auimpl_export_32ne(audio_engine_t *, uint_t, uint_t);
+void auimpl_export_32oe(audio_engine_t *, uint_t, uint_t);
+void auimpl_output_callback(void *);
+void auimpl_output_preload(audio_engine_t *);
 
 /* audio_input.c */
-void auimpl_import_16ne(audio_engine_t *, audio_stream_t *);
-void auimpl_import_16oe(audio_engine_t *, audio_stream_t *);
-void auimpl_import_24ne(audio_engine_t *, audio_stream_t *);
-void auimpl_import_24oe(audio_engine_t *, audio_stream_t *);
-void auimpl_import_32ne(audio_engine_t *, audio_stream_t *);
-void auimpl_import_32oe(audio_engine_t *, audio_stream_t *);
-void auimpl_input_callback(audio_engine_t *);
+void auimpl_import_16ne(audio_engine_t *, uint_t, audio_stream_t *);
+void auimpl_import_16oe(audio_engine_t *, uint_t, audio_stream_t *);
+void auimpl_import_24ne(audio_engine_t *, uint_t, audio_stream_t *);
+void auimpl_import_24oe(audio_engine_t *, uint_t, audio_stream_t *);
+void auimpl_import_32ne(audio_engine_t *, uint_t, audio_stream_t *);
+void auimpl_import_32oe(audio_engine_t *, uint_t, audio_stream_t *);
+void auimpl_input_callback(void *);
 int auimpl_input_drain(audio_stream_t *);
 
 /* audio_client.c */
@@ -448,7 +467,12 @@
 int auimpl_set_pcmvol(void *, uint64_t);
 int auimpl_get_pcmvol(void *, uint64_t *);
 
+/* audio_ctrl.c */
+int auimpl_save_controls(audio_dev_t *);
+int auimpl_restore_controls(audio_dev_t *);
+
 /* audio_engine.c */
+extern int audio_priority;
 void auimpl_dev_init(void);
 void auimpl_dev_fini(void);
 void auimpl_dev_hold(audio_dev_t *);
@@ -478,7 +502,7 @@
 #define	ENG_QLEN(e)		E_OP(e, qlen)(E_PRV(e))
 #define	ENG_PLAYAHEAD(e)	E_OP(e, playahead)(E_PRV(e))
 #define	ENG_CLOSE(e)		E_OP(e, close)(E_PRV(e))
-#define	ENG_OPEN(e, s, nf, d) 	E_OP(e, open)(E_PRV(e), e->e_flags, s, nf, d)
+#define	ENG_OPEN(e, nf, d) 	E_OP(e, open)(E_PRV(e), e->e_flags, nf, d)
 #define	ENG_CHINFO(e, c, o, i)	E_OP(e, chinfo(E_PRV(e), c, o, i))
 
 /* audio_sun.c */
--- a/usr/src/uts/common/io/audio/impl/audio_input.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/impl/audio_input.c	Tue Mar 16 09:30:41 2010 -0700
@@ -21,7 +21,7 @@
 /*
  * Copyright (C) 4Front Technologies 1996-2008.
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -34,17 +34,16 @@
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
 #include <sys/sysmacros.h>
+#include <sys/sdt.h>
 #include "audio_impl.h"
 
 #define	DECL_AUDIO_IMPORT(NAME, TYPE, SWAP, SHIFT)			\
 void									\
-auimpl_import_##NAME(audio_engine_t *eng, audio_stream_t *sp)		\
+auimpl_import_##NAME(audio_engine_t *e, uint_t nfr, audio_stream_t *sp)	\
 {									\
-	int		fragfr = eng->e_fragfr;				\
-	int		nch = eng->e_nchan;				\
-	unsigned	tidx = eng->e_tidx;				\
-	int32_t 	*out = (void *)sp->s_cnv_src;			\
-	TYPE		*in = (void *)eng->e_data;			\
+	int		nch = e->e_nchan;				\
+	int32_t		*out = (void *)sp->s_cnv_src;			\
+	TYPE		*in = (void *)e->e_data;			\
 	int		ch = 0;						\
 	int		vol = sp->s_gain_eff;				\
 									\
@@ -52,13 +51,14 @@
 		TYPE 	*ip;						\
 		int32_t *op;						\
 		int 	i;						\
-		int 	incr = eng->e_chincr[ch];			\
+		int 	incr = e->e_chincr[ch];				\
+		uint_t	tidx = e->e_tidx;				\
 									\
 		/* get value and adjust next channel offset */		\
 		op = out++;						\
-		ip = in + eng->e_choffs[ch] + (tidx * incr);		\
+		ip = in + e->e_choffs[ch] + (tidx * incr);		\
 									\
-		i = fragfr;						\
+		i = nfr;						\
 									\
 		do {	/* for each frame */				\
 			int32_t	sample = (TYPE)SWAP(*ip);		\
@@ -68,9 +68,13 @@
 			scaled /= AUDIO_VOL_SCALE;			\
 									\
 			*op = scaled;					\
-			ip += incr;					\
 			op += nch;					\
 									\
+			ip += incr;					\
+			if (++tidx == e->e_nframes) {			\
+				tidx = 0;				\
+				ip = in + e->e_choffs[ch];		\
+			}						\
 		} while (--i);						\
 		ch++;							\
 	} while (ch < nch);						\
@@ -84,18 +88,16 @@
 DECL_AUDIO_IMPORT(24oe, int32_t, ddi_swap32, /* nop */)
 
 /*
- * Produce a fragment's worth of data.  This is called when the data in
- * the conversion buffer is exhausted, and we need to refill it from the
- * source buffer.  We always consume data from the client in quantities of
- * a fragment at a time (assuming that a fragment is available.)
+ * Produce capture data.  This takes data from the conversion buffer
+ * and copies it into the stream data buffer.
  */
 static void
-auimpl_produce_fragment(audio_stream_t *sp, unsigned count)
+auimpl_produce_data(audio_stream_t *sp, uint_t count)
 {
-	unsigned	nframes;
-	unsigned	framesz;
-	caddr_t		cnvsrc;
-	caddr_t		data;
+	uint_t	nframes;
+	uint_t	framesz;
+	caddr_t	cnvsrc;
+	caddr_t	data;
 
 	nframes = sp->s_nframes;
 	framesz = sp->s_framesz;
@@ -114,7 +116,6 @@
 		unsigned nf;
 		unsigned nb;
 
-		ASSERT(sp->s_hidx < nframes);
 		nf = min(nframes - sp->s_hidx, count);
 		nb = nf * framesz;
 
@@ -125,50 +126,92 @@
 		sp->s_head += nf;
 		count -= nf;
 		sp->s_samples += nf;
-		if (sp->s_hidx >= nframes) {
-			sp->s_hidx -= nframes;
-			data -= sp->s_nbytes;
+		if (sp->s_hidx == nframes) {
+			sp->s_hidx = 0;
+			data = sp->s_data;
 		}
 	} while (count);
 
 	ASSERT(sp->s_tail <= sp->s_head);
 	ASSERT(sp->s_hidx < nframes);
-	ASSERT(sp->s_tail <= sp->s_head);
-	ASSERT(sp->s_hidx < nframes);
 }
 
 void
-auimpl_input_callback(audio_engine_t *eng)
+auimpl_input_callback(void *arg)
 {
-	int		fragfr = eng->e_fragfr;
+	audio_engine_t	*e = arg;
+	uint_t		fragfr = e->e_fragfr;
+	audio_stream_t	*sp;
 	audio_client_t	*c;
+	audio_client_t	*clist = NULL;
+	list_t		*l = &e->e_streams;
+	uint64_t	h;
+
+	mutex_enter(&e->e_lock);
+
+	if (e->e_suspended || e->e_failed) {
+		mutex_exit(&e->e_lock);
+		return;
+	}
+
+	if (e->e_need_start) {
+		int rv;
+		if ((rv = ENG_START(e)) != 0) {
+			e->e_failed = B_TRUE;
+			mutex_exit(&e->e_lock);
+			audio_dev_warn(e->e_dev,
+			    "failed starting input, rv = %d", rv);
+			return;
+		}
+		e->e_need_start = B_FALSE;
+	}
+
+	h = ENG_COUNT(e);
+	ASSERT(h >= e->e_head);
+	if (h < e->e_head) {
+		/*
+		 * This is a sign of a serious bug.  We should
+		 * probably offline the device via FMA, if we ever
+		 * support FMA for audio devices.
+		 */
+		e->e_failed = B_TRUE;
+		ENG_STOP(e);
+		mutex_exit(&e->e_lock);
+		audio_dev_warn(e->e_dev,
+		    "device malfunction: broken capture sample counter");
+		return;
+	}
+	e->e_head = h;
+	ASSERT(e->e_head >= e->e_tail);
+
+	if ((e->e_head - e->e_tail) > e->e_nframes) {
+		/* no room for data, not much we can do */
+		e->e_errors++;
+		e->e_overruns++;
+	}
 
 	/* consume all fragments in the buffer */
-	while ((eng->e_head - eng->e_tail) > fragfr) {
+	while ((e->e_head - e->e_tail) > fragfr) {
 
 		/*
 		 * Consider doing the SYNC outside of the lock.
 		 */
-		ENG_SYNC(eng, fragfr);
+		ENG_SYNC(e, fragfr);
 
-		for (audio_stream_t *sp = list_head(&eng->e_streams);
-		    sp != NULL;
-		    sp = list_next(&eng->e_streams, sp)) {
+		for (sp = list_head(l); sp != NULL; sp = list_next(l, sp)) {
 			int space;
 			int count;
 
-			c = sp->s_client;
-
 			mutex_enter(&sp->s_lock);
 			/* skip over streams paused or not running */
-			if (sp->s_paused || (!sp->s_running) ||
-			    eng->e_suspended) {
+			if (sp->s_paused || !sp->s_running) {
 				mutex_exit(&sp->s_lock);
 				continue;
 			}
 			sp->s_cnv_src = sp->s_cnv_buf0;
 			sp->s_cnv_dst = sp->s_cnv_buf1;
-			eng->e_import(eng, sp);
+
+			e->e_import(e, fragfr, sp);
 
 			/*
 			 * Optionally convert fragment to requested sample
@@ -180,33 +223,56 @@
 				count = fragfr;
 			}
 
+			ASSERT(sp->s_head >= sp->s_tail);
 			space = sp->s_nframes - (sp->s_head - sp->s_tail);
 			if (count > space) {
-				eng->e_stream_overruns++;
-				eng->e_errors++;
+				e->e_stream_overruns++;
+				e->e_errors++;
 				sp->s_errors += count - space;
 				count = space;
 			}
 
-			auimpl_produce_fragment(sp, count);
+			auimpl_produce_data(sp, count);
 
 			/* wake blocked threads (blocking reads, etc.) */
 			cv_broadcast(&sp->s_cv);
 
 			mutex_exit(&sp->s_lock);
 
-			if (c->c_input != NULL) {
-				c->c_input(c);
+			/*
+			 * Add client to notification list.  We'll
+			 * process it after dropping the lock.
+			 */
+			c = sp->s_client;
+
+			if ((c->c_input != NULL) &&
+			    (c->c_next_input == NULL)) {
+				auclnt_hold(c);
+				c->c_next_input = clist;
+				clist = c;
 			}
 		}
 
 		/*
 		 * Update the tail pointer, and the data pointer.
 		 */
-		eng->e_tail += fragfr;
-		eng->e_tidx += fragfr;
-		if (eng->e_tidx >= eng->e_nframes) {
-			eng->e_tidx -= eng->e_nframes;
+		e->e_tail += fragfr;
+		e->e_tidx += fragfr;
+		if (e->e_tidx >= e->e_nframes) {
+			e->e_tidx -= e->e_nframes;
 		}
 	}
+
+	mutex_exit(&e->e_lock);
+
+	/*
+	 * Notify client personalities.
+	 */
+
+	while ((c = clist) != NULL) {
+		clist = c->c_next_input;
+		c->c_next_input = NULL;
+		c->c_input(c);
+		auclnt_release(c);
+	}
 }
--- a/usr/src/uts/common/io/audio/impl/audio_output.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/audio/impl/audio_output.c	Tue Mar 16 09:30:41 2010 -0700
@@ -21,7 +21,7 @@
 /*
  * Copyright (C) 4Front Technologies 1996-2008.
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -38,11 +38,10 @@
 
 #define	DECL_AUDIO_EXPORT(NAME, TYPE, SAMPLE)				\
 void									\
-auimpl_export_##NAME(audio_engine_t *eng)				\
+auimpl_export_##NAME(audio_engine_t *eng, uint_t nfr, uint_t froff)	\
 {									\
-	int		fragfr = eng->e_fragfr;				\
 	int		nch = eng->e_nchan;				\
-	unsigned	hidx = eng->e_hidx;				\
+	uint_t		hidx = eng->e_hidx;				\
 	TYPE		*out = (void *)eng->e_data;			\
 	int		ch = 0;						\
 									\
@@ -55,8 +54,9 @@
 		/* get value and adjust next channel offset */		\
 		op = out + eng->e_choffs[ch] + (hidx * incr);		\
 		ip = eng->e_chbufs[ch];					\
+		ip += froff;						\
 									\
-		i = fragfr;						\
+		i = nfr;						\
 									\
 		do {	/* for each frame */				\
 			int32_t sample = *ip;				\
@@ -85,18 +85,18 @@
 auimpl_output_limiter(audio_engine_t *eng)
 {
 	int k, t;
-	unsigned int q, amp, amp2;
+	uint_t q, amp, amp2;
 	int nchan = eng->e_nchan;
-	int fragfr = eng->e_fragfr;
+	uint_t fragfr = eng->e_fragfr;
 	int32_t **chbufs = eng->e_chbufs;
-	unsigned int statevar = eng->e_limiter_state;
+	uint_t statevar = eng->e_limiter_state;
 
 	for (t = 0; t < fragfr; t++) {
 
-		amp = (unsigned)ABS(chbufs[0][t]);
+		amp = (uint_t)ABS(chbufs[0][t]);
 
 		for (k = 1; k < nchan; k++)	{
-			amp2 = (unsigned)ABS(chbufs[k][t]);
+			amp2 = (uint_t)ABS(chbufs[k][t]);
 			if (amp2 > amp)
 				amp = amp2;
 		}
@@ -130,7 +130,7 @@
 		for (k = 0; k < nchan; k++) {
 			int32_t in = chbufs[k][t];
 			int32_t out = 0;
-			unsigned int p;
+			uint_t p;
 
 			if (in >= 0) {
 				p = in;
@@ -221,12 +221,12 @@
 static void
 auimpl_consume_fragment(audio_stream_t *sp)
 {
-	unsigned	count;
-	unsigned	avail;
-	unsigned	nframes;
-	unsigned	fragfr;
-	unsigned	framesz;
-	caddr_t		cnvbuf;
+	uint_t	count;
+	uint_t	avail;
+	uint_t	nframes;
+	uint_t	fragfr;
+	uint_t	framesz;
+	caddr_t	cnvbuf;
 
 	sp->s_cnv_src = sp->s_cnv_buf0;
 	sp->s_cnv_dst = sp->s_cnv_buf1;
@@ -247,8 +247,8 @@
 	 * do...while to minimize the number of tests.
 	 */
 	do {
-		unsigned n;
-		unsigned nbytes;
+		uint_t n;
+		uint_t nbytes;
 
 		n = min(nframes - sp->s_tidx, count);
 		nbytes = framesz * n;
@@ -272,9 +272,11 @@
 }
 
 static void
-auimpl_output_callback_impl(audio_engine_t *eng)
+auimpl_output_callback_impl(audio_engine_t *eng, audio_client_t **output,
+    audio_client_t **drain)
 {
-	int		fragfr = eng->e_fragfr;
+	uint_t	fragfr = eng->e_fragfr;
+	uint_t	resid;
 
 	/* clear any preexisting mix results */
 	for (int i = 0; i < eng->e_nchan; i++)
@@ -303,7 +305,7 @@
 
 		mutex_enter(&sp->s_lock);
 		/* skip over streams not running or paused */
-		if ((!sp->s_running) || (sp->s_paused) || eng->e_suspended) {
+		if ((!sp->s_running) || (sp->s_paused)) {
 			mutex_exit(&sp->s_lock);
 			continue;
 		}
@@ -402,12 +404,18 @@
 		 * the client's stream from engine.  So we're safe.
 		 */
 
-		if (c->c_output != NULL) {
-			c->c_output(c);
+		if (output && (c->c_output != NULL) &&
+		    (c->c_next_output == NULL)) {
+			auclnt_hold(c);
+			c->c_next_output = *output;
+			*output = c;
 		}
 
-		if (drained && (c->c_drain != NULL)) {
-			c->c_drain(c);
+		if (drain && drained && (c->c_drain != NULL) &&
+		    (c->c_next_drain == NULL)) {
+			auclnt_hold(c);
+			c->c_next_drain = *drain;
+			*drain = c;
 		}
 	}
 
@@ -417,19 +425,20 @@
 	auimpl_output_limiter(eng);
 
 	/*
-	 * Export the data (a whole fragment) to the device.
+	 * Export the data (a whole fragment) to the device.  Deal
+	 * properly with wraps.  Note that the test and subtraction is
+	 * faster for dealing with wrap than modulo.
 	 */
-	eng->e_export(eng);
-
-	/*
-	 * Update the head and offset.  The head counts without
-	 * wrapping, whereas the offset wraps.  Note that the test +
-	 * subtraction is faster for dealing with wrap than modulo.
-	 */
-	eng->e_head += fragfr;
-	eng->e_hidx += fragfr;
-	if (eng->e_hidx >= eng->e_nframes)
-		eng->e_hidx -= eng->e_nframes;
+	resid = fragfr;
+	do {
+		uint_t part = min(resid, eng->e_nframes - eng->e_hidx);
+		eng->e_export(eng, part, fragfr - resid);
+		eng->e_head += part;
+		eng->e_hidx += part;
+		if (eng->e_hidx == eng->e_nframes)
+			eng->e_hidx = 0;
+		resid -= part;
+	} while (resid);
 
 	/*
 	 * Consider doing the SYNC outside of the lock.
@@ -442,15 +451,105 @@
  */
 
 void
-auimpl_output_callback(audio_engine_t *eng)
+auimpl_output_callback(void *arg)
 {
-	int64_t cnt;
+	audio_engine_t	*e = arg;
+	int64_t		cnt;
+	audio_client_t	*c;
+	audio_client_t	*output = NULL;
+	audio_client_t	*drain = NULL;
+	uint64_t	t;
+
+	mutex_enter(&e->e_lock);
+
+	if (e->e_suspended || e->e_failed) {
+		mutex_exit(&e->e_lock);
+		return;
+	}
 
-	cnt = eng->e_head - eng->e_tail;
+	if (e->e_need_start) {
+		int rv;
+		if ((rv = ENG_START(e)) != 0) {
+			e->e_failed = B_TRUE;
+			mutex_exit(&e->e_lock);
+			audio_dev_warn(e->e_dev,
+			    "failed starting output, rv = %d", rv);
+			return;
+		}
+		e->e_need_start = B_FALSE;
+	}
+
+	t = ENG_COUNT(e);
+	if (t < e->e_tail) {
+		/*
+		 * This is a sign of a serious bug.  We should
+		 * probably offline the device via FMA, if we ever
+		 * support FMA for audio devices.
+		 */
+		e->e_failed = B_TRUE;
+		ENG_STOP(e);
+		mutex_exit(&e->e_lock);
+		audio_dev_warn(e->e_dev,
+		    "device malfunction: broken play back sample counter");
+		return;
+
+	}
+	e->e_tail = t;
+
+	if (e->e_tail > e->e_head) {
+		/* want more than we have */
+		e->e_errors++;
+		e->e_underruns++;
+	}
+
+	cnt = e->e_head - e->e_tail;
 
 	/* stay a bit ahead */
-	while (cnt < eng->e_playahead) {
-		auimpl_output_callback_impl(eng);
-		cnt = eng->e_head - eng->e_tail;
+	while (cnt < e->e_playahead) {
+		auimpl_output_callback_impl(e, &output, &drain);
+		cnt = e->e_head - e->e_tail;
+	}
+	mutex_exit(&e->e_lock);
+
+	/*
+	 * Notify client personalities.
+	 */
+	while ((c = output) != NULL) {
+
+		output = c->c_next_output;
+		c->c_next_output = NULL;
+		c->c_output(c);
+		auclnt_release(c);
+	}
+
+	while ((c = drain) != NULL) {
+
+		drain = c->c_next_drain;
+		c->c_next_drain = NULL;
+		c->c_drain(c);
+		auclnt_release(c);
+	}
+
+}
+
+void
+auimpl_output_preload(audio_engine_t *e)
+{
+	int64_t	cnt;
+
+	ASSERT(mutex_owned(&e->e_lock));
+
+	if (e->e_tail > e->e_head) {
+		/* want more than we have */
+		e->e_errors++;
+		e->e_underruns++;
+		e->e_tail = e->e_head;
+	}
+	cnt = e->e_head - e->e_tail;
+
+	/* stay a bit ahead */
+	while (cnt < e->e_playahead) {
+		auimpl_output_callback_impl(e, NULL, NULL);
+		cnt = e->e_head - e->e_tail;
 	}
 }
--- a/usr/src/uts/common/io/usb/clients/audio/usb_ac/usb_ac.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/io/usb/clients/audio/usb_ac/usb_ac.c	Tue Mar 16 09:30:41 2010 -0700
@@ -326,7 +326,7 @@
 static int usb_audio_register(usb_ac_state_t *);
 static int usb_audio_unregister(usb_ac_state_t *);
 
-static int usb_engine_open(void *, int, unsigned *, unsigned *, caddr_t *);
+static int usb_engine_open(void *, int, unsigned *, caddr_t *);
 static void usb_engine_close(void *);
 static uint64_t usb_engine_count(void *);
 static int usb_engine_start(void *);
@@ -5340,7 +5340,6 @@
 	unsigned frames;
 	unsigned i;
 	size_t sz;
-	int bufcnt = 0;
 	caddr_t bp = buf;
 
 	mutex_enter(&engp->lock);
@@ -5362,15 +5361,12 @@
 
 		sz = (frames << engp->frsmshift) << engp->smszshift;
 
-		bufcnt++;
-
 		/* must move data before updating framework */
 		usb_eng_bufio(engp, bp, sz);
 		engp->frames += frames;
 		bp += sz;
 
 		mutex_exit(&engp->lock);
-		audio_engine_consume(engp->af_engp);
 	}
 
 	mutex_enter(&engp->lock);
@@ -5393,7 +5389,6 @@
 	unsigned frames;
 	unsigned i;
 	size_t sz;
-	int bufcnt = 0;
 	caddr_t bp = buf;
 
 	mutex_enter(&engp->lock);
@@ -5416,15 +5411,12 @@
 
 		sz = (frames << engp->frsmshift) << engp->smszshift;
 
-		bufcnt++;
-
 		/* must move data before updating framework */
 		usb_eng_bufio(engp, bp, sz);
 		engp->frames += frames;
 		bp += sz;
 
 		mutex_exit(&engp->lock);
-		audio_engine_produce(engp->af_engp);
 	}
 
 	mutex_enter(&engp->lock);
@@ -5439,15 +5431,14 @@
  * **************************************************************************
  * audio framework engine callbacks
  */
-/*ARGSUSED*/
 static int
-usb_engine_open(void *arg, int flag,
-    unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp)
+usb_engine_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
 {
 	usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
 	usb_ac_state_t *statep = engp->statep;
 	int rv = EIO;
 
+	_NOTE(ARGUNUSED(flag));
 
 	if (usb_ac_open(statep->usb_ac_dip) != USB_SUCCESS) {
 
@@ -5504,8 +5495,7 @@
 	engp->started = B_FALSE;
 	engp->busy = B_FALSE;
 
-	*fragfrp = engp->fragfr;
-	*nfragsp = engp->nfrags;
+	*nframesp = engp->nfrags * engp->fragfr;
 	*bufp = engp->bufp;
 
 	mutex_exit(&engp->lock);
@@ -5539,14 +5529,12 @@
 	usb_audio_eng_t *engp = (usb_audio_eng_t *)arg;
 	usb_ac_state_t *statep = engp->statep;
 
-	audio_engine_unlock(engp->af_engp);
 	mutex_enter(&engp->lock);
 	while (engp->busy) {
 		cv_wait(&engp->usb_audio_cv, &engp->lock);
 	}
 
 	mutex_exit(&engp->lock);
-	audio_engine_lock(engp->af_engp);
 
 	if (statep->flags & AD_SETUP) {
 		usb_ac_teardown(statep, engp);
--- a/usr/src/uts/common/sys/audio/ac97.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/sys/audio/ac97.h	Tue Mar 16 09:30:41 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -653,8 +653,6 @@
  * Bits common to both new style and old style initialization.
  */
 void ac97_free(ac97_t *);
-void ac97_suspend(ac97_t *);
-void ac97_resume(ac97_t *);
 void ac97_reset(ac97_t *);
 int ac97_num_channels(ac97_t *);
 
--- a/usr/src/uts/common/sys/audio/audio_driver.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/common/sys/audio/audio_driver.h	Tue Mar 16 09:30:41 2010 -0700
@@ -43,15 +43,14 @@
 
 struct audio_engine_ops {
 	int	audio_engine_version;
-#define	AUDIO_ENGINE_VERSION	1
+#define	AUDIO_ENGINE_VERSION	2
 
 	/*
 	 * Initialize engine, including buffer allocation.  Arguments
 	 * that are pointers are hints.  On return, they are updated with
 	 * the actual values configured by the driver.
 	 */
-	int	(*audio_engine_open)(void *, int flags,
-		    unsigned *fragfr, unsigned *nfrags, caddr_t *buf);
+	int	(*audio_engine_open)(void *, int, uint_t *, caddr_t *);
 	void	(*audio_engine_close)(void *);
 
 	/*
@@ -98,13 +97,13 @@
 	 * flags passed to ae_open()), and dealing with any partial
 	 * synchronization if any is needed.
 	 */
-	void	(*audio_engine_sync)(void *, unsigned);
+	void	(*audio_engine_sync)(void *, uint_t);
 
 	/*
 	 * The framework may like to know how deep the device queues data.
 	 * This can be used to provide a more accurate latency calculation.
 	 */
-	unsigned	(*audio_engine_qlen)(void *);
+	uint_t	(*audio_engine_qlen)(void *);
 
 	/*
 	 * If the driver doesn't use simple interleaving, then we need to
@@ -114,8 +113,8 @@
 	 * samples.  If this entry point is NULL, the framework assumes
 	 * that simple interlevaing is used instead.
 	 */
-	void	(*audio_engine_chinfo)(void *, int chan, unsigned *offset,
-	    unsigned *incr);
+	void	(*audio_engine_chinfo)(void *, int chan, uint_t *offset,
+	    uint_t *incr);
 
 	/*
 	 * The following entry point is used to determine the play ahead
@@ -123,9 +122,12 @@
 	 * or with a need for deeper queuing, implement this.  If not
 	 * implemented, the framework assumes 1.5 * fragfr.
 	 */
-	unsigned	(*audio_engine_playahead)(void *);
+	uint_t	(*audio_engine_playahead)(void *);
 };
 
+/*
+ * Drivers call these.
+ */
 void audio_init_ops(struct dev_ops *, const char *);
 void audio_fini_ops(struct dev_ops *);
 
@@ -136,7 +138,7 @@
 void audio_dev_set_version(audio_dev_t *, const char *);
 void audio_dev_add_info(audio_dev_t *, const char *);
 
-audio_engine_t *audio_engine_alloc(audio_engine_ops_t *, unsigned);
+audio_engine_t *audio_engine_alloc(audio_engine_ops_t *, uint_t);
 void audio_engine_set_private(audio_engine_t *, void *);
 void *audio_engine_get_private(audio_engine_t *);
 void audio_engine_free(audio_engine_t *);
@@ -145,20 +147,15 @@
 void audio_dev_remove_engine(audio_dev_t *, audio_engine_t *);
 int audio_dev_register(audio_dev_t *);
 int audio_dev_unregister(audio_dev_t *);
+void audio_dev_suspend(audio_dev_t *);
+void audio_dev_resume(audio_dev_t *);
 void audio_dev_warn(audio_dev_t *, const char *, ...);
+
 /* DEBUG ONLY */
 void audio_dump_bytes(const uint8_t *w, int dcount);
 void audio_dump_words(const uint16_t *w, int dcount);
 void audio_dump_dwords(const uint32_t *w, int dcount);
 
-/*
- * Drivers call these.
- */
-void audio_engine_consume(audio_engine_t *);
-void audio_engine_produce(audio_engine_t *);
-void audio_engine_reset(audio_engine_t *);
-void audio_engine_lock(audio_engine_t *);
-void audio_engine_unlock(audio_engine_t *);
 
 /* Engine flags */
 #define	ENGINE_OUTPUT_CAP	(1U << 2)
@@ -172,7 +169,6 @@
 #define	ENGINE_RUNNING		(1U << 19)
 #define	ENGINE_EXCLUSIVE	(1U << 20)	/* exclusive use, e.g. AC3 */
 #define	ENGINE_NDELAY		(1U << 21)	/* non-blocking open */
-#define	ENGINE_WAKE		(1U << 22)	/* wakeup tq running */
 
 /*
  * entry points used by legacy SADA drivers
--- a/usr/src/uts/intel/audio1575/Makefile	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/intel/audio1575/Makefile	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # uts/intel/audio1575/Makefile
@@ -40,7 +40,6 @@
 OBJECTS		= $(AUDIO1575_OBJS:%=$(OBJS_DIR)/%)
 LINTS		= $(AUDIO1575_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/io/audio/drv/audio1575
 
 #
 #	Include common rules.
@@ -55,9 +54,9 @@
 #
 #	Define targets
 #
-ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+ALL_TARGET	= $(BINARY)
 LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 #
 #	Default build targets.
--- a/usr/src/uts/intel/audioens/Makefile	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/intel/audioens/Makefile	Tue Mar 16 09:30:41 2010 -0700
@@ -21,7 +21,7 @@
 #
 # uts/intel/audioens/Makefile
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #	This makefile drives the production of the audioens driver.
@@ -39,7 +39,6 @@
 OBJECTS		= $(AUDIOENS_OBJS:%=$(OBJS_DIR)/%)
 LINTS		= $(AUDIOENS_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/io/audio/drv/audioens
 
 #
 #	Include common rules.
@@ -49,9 +48,9 @@
 #
 #	Define targets
 #
-ALL_TARGET	= $(BINARY) $(SRC_CONFFILE)
+ALL_TARGET	= $(BINARY)
 LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 LDFLAGS		+= -dy -Ndrv/audio -Nmisc/ac97
 
--- a/usr/src/uts/intel/audioixp/Makefile	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/intel/audioixp/Makefile	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # uts/intel/audioixp/Makefile
@@ -40,7 +40,6 @@
 OBJECTS		= $(AUDIOIXP_OBJS:%=$(OBJS_DIR)/%)
 LINTS		= $(AUDIOIXP_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/io/audio/drv/audioixp
 
 #
 #	Include common rules.
@@ -51,8 +50,6 @@
 #	Overrides, lint pass one enforcement 
 # 
 CFLAGS		+= $(CCVERBOSE)
-DEBUG_FLGS	=
-$(NOT_RELEASE_BUILD)DEBUG_DEFS	+= $(DEBUG_FLGS)
 
 #
 #	Depends on misc/audiosup
@@ -62,9 +59,9 @@
 #
 #	Define targets
 #
-ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+ALL_TARGET	= $(BINARY)
 LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 #
 #	Default build targets.
--- a/usr/src/uts/intel/audiopci/Makefile	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/intel/audiopci/Makefile	Tue Mar 16 09:30:41 2010 -0700
@@ -21,7 +21,7 @@
 #
 # uts/intel/audiopci/Makefile
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #	This makefile drives the production of the audiopci driver.
@@ -39,7 +39,6 @@
 OBJECTS		= $(AUDIOPCI_OBJS:%=$(OBJS_DIR)/%)
 LINTS		= $(AUDIOPCI_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/io/audio/drv/audiopci
 
 #
 #	Include common rules.
@@ -49,9 +48,9 @@
 #
 #	Define targets
 #
-ALL_TARGET	= $(BINARY) $(SRC_CONFFILE)
+ALL_TARGET	= $(BINARY)
 LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 LDFLAGS		+= -dy -Ndrv/audio
 
--- a/usr/src/uts/intel/audiots/Makefile	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/intel/audiots/Makefile	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # uts/intel/audiots/Makefile
@@ -39,7 +39,6 @@
 OBJECTS		= $(AUDIOTS_OBJS:%=$(OBJS_DIR)/%)
 LINTS		= $(AUDIOTS_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/io/audio/drv/audiots
 
 #
 #	Include common rules.
@@ -59,9 +58,9 @@
 #
 #	Define targets
 #
-ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+ALL_TARGET	= $(BINARY)
 LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 #
 #	Default build targets.
--- a/usr/src/uts/intel/audiovia823x/Makefile	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/intel/audiovia823x/Makefile	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # uts/intel/audiovia823x/Makefile
@@ -40,7 +40,6 @@
 OBJECTS		= $(AUDIOVIA823X_OBJS:%=$(OBJS_DIR)/%)
 LINTS		= $(AUDIOVIA823X_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/io/audio/drv/audiovia823x
 
 #
 #	Include common rules.
@@ -55,9 +54,9 @@
 #
 #	Define targets
 #
-ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+ALL_TARGET	= $(BINARY)
 LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 #
 #	Default build targets.
--- a/usr/src/uts/sparc/audio1575/Makefile	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/sparc/audio1575/Makefile	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # uts/sparc/audio1575/Makefile
@@ -39,7 +39,6 @@
 OBJECTS		= $(AUDIO1575_OBJS:%=$(OBJS_DIR)/%)
 LINTS		= $(AUDIO1575_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/io/audio/drv/audio1575
 
 #
 #	Include common rules.
@@ -59,16 +58,15 @@
 #
 #	Define targets
 #
-ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+ALL_TARGET	= $(BINARY)
 LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE_64)
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 #
 #       Overrides
 #
 ALL_BUILDS	= $(ALL_BUILDSONLY64)
 DEF_BUILDS	= $(DEF_BUILDSONLY64)
-CLEANLINTFILES	+= $(LINT32_FILES)
 
 #
 #	Default build targets.
@@ -85,7 +83,7 @@
 
 lint:		$(LINT_DEPS)
 
-modlintlib:	$(MODLINTLIB_DEPS) lint32
+modlintlib:	$(MODLINTLIB_DEPS)
 
 clean.lint:	$(CLEAN_LINT_DEPS)
 
--- a/usr/src/uts/sparc/audiocs/Makefile	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/sparc/audiocs/Makefile	Tue Mar 16 09:30:41 2010 -0700
@@ -21,7 +21,7 @@
 #
 # uts/sparc/audiocs/Makefile
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #	This makefile drives the production of the Crystal 4231
@@ -40,7 +40,6 @@
 OBJECTS		= $(AUDIOCS_OBJS:%=$(OBJS_DIR)/%)
 LINTS		= $(AUDIOCS_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/sun/io/audio/drv/audiocs
 
 #
 #	Include common rules.
@@ -50,9 +49,9 @@
 #
 #	Define targets
 #
-ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+ALL_TARGET	= $(BINARY)
 LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 #
 #	Overrides
--- a/usr/src/uts/sparc/audioens/Makefile	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/sparc/audioens/Makefile	Tue Mar 16 09:30:41 2010 -0700
@@ -21,7 +21,7 @@
 #
 # uts/sparc/audioens/Makefile
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #	This makefile drives the production of the audioens driver.
@@ -39,7 +39,6 @@
 OBJECTS		= $(AUDIOENS_OBJS:%=$(OBJS_DIR)/%)
 LINTS		= $(AUDIOENS_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/io/audio/drv/audioens
 
 #
 #	Include common rules.
@@ -49,9 +48,9 @@
 #
 #	Define targets
 #
-ALL_TARGET	= $(BINARY) $(SRC_CONFFILE)
+ALL_TARGET	= $(BINARY)
 LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 LDFLAGS		+= -dy -Ndrv/audio -Nmisc/ac97
 
--- a/usr/src/uts/sparc/audiopci/Makefile	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/sparc/audiopci/Makefile	Tue Mar 16 09:30:41 2010 -0700
@@ -21,7 +21,7 @@
 #
 # uts/sparc/audiopci/Makefile
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #	This makefile drives the production of the audiopci driver.
@@ -39,7 +39,6 @@
 OBJECTS		= $(AUDIOPCI_OBJS:%=$(OBJS_DIR)/%)
 LINTS		= $(AUDIOPCI_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/io/audio/drv/audiopci
 
 #
 #	Include common rules.
@@ -49,9 +48,9 @@
 #
 #	Define targets
 #
-ALL_TARGET	= $(BINARY) $(SRC_CONFFILE)
+ALL_TARGET	= $(BINARY)
 LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 LDFLAGS		+= -dy -Ndrv/audio
 
--- a/usr/src/uts/sparc/audiots/Makefile	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/sparc/audiots/Makefile	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # uts/sparc/audiots/Makefile
@@ -39,7 +39,6 @@
 OBJECTS		= $(AUDIOTS_OBJS:%=$(OBJS_DIR)/%)
 LINTS		= $(AUDIOTS_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/io/audio/drv/audiots
 
 #
 #	Include common rules.
@@ -59,16 +58,15 @@
 #
 #	Define targets
 #
-ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+ALL_TARGET	= $(BINARY)
 LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE_64)
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
 #
 #       Overrides
 #
 ALL_BUILDS	= $(ALL_BUILDSONLY64)
 DEF_BUILDS	= $(DEF_BUILDSONLY64)
-CLEANLINTFILES	+= $(LINT32_FILES)
 
 #
 #	Default build targets.
@@ -85,7 +83,7 @@
 
 lint:		$(LINT_DEPS)
 
-modlintlib:	$(MODLINTLIB_DEPS) lint32
+modlintlib:	$(MODLINTLIB_DEPS)
 
 clean.lint:	$(CLEAN_LINT_DEPS)
 
--- a/usr/src/uts/sun/io/audio/drv/audiocs/audio_4231.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/sun/io/audio/drv/audiocs/audio_4231.c	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -73,7 +73,7 @@
 /*
  * Entry point routine prototypes
  */
-static int audiocs_open(void *, int, unsigned *, unsigned *, caddr_t *);
+static int audiocs_open(void *, int, unsigned *, caddr_t *);
 static void audiocs_close(void *);
 static int audiocs_start(void *);
 static void audiocs_stop(void *);
@@ -82,7 +82,6 @@
 static int audiocs_rate(void *);
 static uint64_t audiocs_count(void *);
 static void audiocs_sync(void *, unsigned);
-static unsigned audiocs_qlen(void *);
 
 /*
  * Control callbacks.
@@ -106,9 +105,6 @@
 static int audiocs_chip_init(CS_state_t *);
 static int audiocs_alloc_engine(CS_state_t *, int);
 static void audiocs_free_engine(CS_engine_t *);
-static void audiocs_reset_engine(CS_engine_t *);
-static int audiocs_start_engine(CS_engine_t *);
-static void audiocs_stop_engine(CS_engine_t *);
 static void audiocs_get_ports(CS_state_t *);
 static void audiocs_configure_input(CS_state_t *);
 static void audiocs_configure_output(CS_state_t *);
@@ -130,6 +126,7 @@
 #define	SELIDX(s, idx)		audiocs_sel_index(s, idx)
 #define	PUTIDX(s, val, mask)	audiocs_put_index(s, val, mask)
 #endif
+#define	GETIDX(s)		ddi_get8((handle), &CS4231_IDR)
 
 #define	ORIDX(s, val, mask)						\
 	PUTIDX(s,							\
@@ -151,9 +148,9 @@
 	audiocs_channels,
 	audiocs_rate,
 	audiocs_sync,
-	audiocs_qlen,
+	NULL,
 	NULL,
-	NULL
+	NULL,
 };
 
 #define	OUTPUT_SPEAKER		0
@@ -470,22 +467,11 @@
 	if (state == NULL)
 		return;
 
-	/*
-	 * Unregister any interrupts. That way we can't get called by and
-	 * interrupt after the audio framework is removed.
-	 */
-	CS4231_DMA_REM_INTR(state);
-
 	for (int i = CS4231_PLAY; i <= CS4231_REC; i++) {
 		audiocs_free_engine(state->cs_engines[i]);
 	}
 	audiocs_del_controls(state);
 
-	/* free the kernel statistics structure */
-	if (state->cs_ksp) {
-		kstat_delete(state->cs_ksp);
-	}
-
 	if (state->cs_adev) {
 		audio_dev_free(state->cs_adev);
 	}
@@ -524,15 +510,8 @@
 	state->cs_dip = dip;
 	ddi_set_driver_private(dip, state);
 
-	/* get the iblock cookie needed for interrupt context */
-	if (ddi_get_iblock_cookie(dip, 0, &state->cs_iblock) != DDI_SUCCESS) {
-		audio_dev_warn(NULL, "cannot get iblock cookie");
-		kmem_free(state, sizeof (*state));
-		return (DDI_FAILURE);
-	}
-
 	/* now fill it in, initialize the state mutexs first */
-	mutex_init(&state->cs_lock, NULL, MUTEX_DRIVER, state->cs_iblock);
+	mutex_init(&state->cs_lock, NULL, MUTEX_DRIVER, NULL);
 
 	/*
 	 * audio state initialization... should always succeed,
@@ -562,18 +541,6 @@
 	/* chip init will have powered us up */
 	state->cs_powered = B_TRUE;
 
-	/* set up kernel statistics */
-	if ((state->cs_ksp = kstat_create(ddi_driver_name(dip),
-	    ddi_get_instance(dip), ddi_driver_name(dip),
-	    "controller", KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT)) != NULL) {
-		kstat_install(state->cs_ksp);
-	}
-
-	/* we're ready, set up the interrupt handler */
-	if (CS4231_DMA_ADD_INTR(state) != DDI_SUCCESS) {
-		mutex_exit(&state->cs_lock);
-		goto error;
-	}
 	mutex_exit(&state->cs_lock);
 
 	/* finally register with framework to kick everything off */
@@ -636,16 +603,6 @@
 
 	state->cs_suspended = B_FALSE;
 
-	for (int i = CS4231_PLAY; i <= CS4231_REC; i++) {
-		CS_engine_t	*eng = state->cs_engines[i];
-
-		audiocs_reset_engine(eng);
-		if (eng->ce_started) {
-			(void) audiocs_start_engine(eng);
-		} else {
-			audiocs_stop_engine(eng);
-		}
-	}
 	mutex_exit(&state->cs_lock);
 
 	/*
@@ -655,6 +612,8 @@
 	(void) pm_raise_power(dip, CS4231_COMPONENT, CS4231_PWR_ON);
 	(void) pm_idle_component(state->cs_dip, CS4231_COMPONENT);
 
+	audio_dev_resume(state->cs_adev);
+
 	return (DDI_SUCCESS);
 }
 
@@ -731,17 +690,13 @@
 	/* get the state structure */
 	state = ddi_get_driver_private(dip);
 
-	ASSERT(!mutex_owned(&state->cs_lock));
-
 	mutex_enter(&state->cs_lock);
 
 	ASSERT(!state->cs_suspended);
 
+	audio_dev_suspend(state->cs_adev);
+
 	if (state->cs_powered) {
-		/* stop playing and recording */
-		CS4231_DMA_STOP(state, state->cs_engines[CS4231_PLAY]);
-		CS4231_DMA_STOP(state, state->cs_engines[CS4231_REC]);
-
 		/* now we can power down the Codec */
 		audiocs_power_down(state);
 		state->cs_powered = B_FALSE;
@@ -749,7 +704,6 @@
 	state->cs_suspended = B_TRUE;	/* stop new ops */
 	mutex_exit(&state->cs_lock);
 
-	ASSERT(!mutex_owned(&state->cs_lock));
 	return (DDI_SUCCESS);
 }
 
@@ -1034,6 +988,7 @@
 		PUTIDX(state, 0, AFE2_VALID_MASK);
 	}
 
+
 	/* clear the play and capture interrupt flags */
 	SELIDX(state, AFS_REG);
 	ddi_put8(handle, &CS4231_STATUS, (AFS_RESET_STATUS));
@@ -1371,9 +1326,6 @@
 
 	ASSERT(mutex_owned(&state->cs_lock));
 
-	if (state->cs_suspended)
-		return;
-
 	inputs = state->cs_inputs->cc_val;
 	micboost = state->cs_micboost->cc_val;
 	r = (state->cs_igain->cc_val & 0xff);
@@ -1439,9 +1391,6 @@
 
 	ASSERT(mutex_owned(&state->cs_lock));
 
-	if (state->cs_suspended)
-		return;
-
 	outputs = state->cs_outputs->cc_val;
 
 	/* port selection */
@@ -1710,8 +1659,7 @@
  * Arguments:
  *	void		*arg		The DMA engine to set up
  *	int		flag		Open flags
- *	unsigned	*fragfrp	Receives number of frames per fragment
- *	unsigned	*nfragsp	Receives number of fragments
+ *	unsigned	*nframesp	Receives number of frames
  *	caddr_t		*bufp		Receives kernel data buffer
  *
  * Returns:
@@ -1719,8 +1667,7 @@
  *	errno	on failure
  */
 static int
-audiocs_open(void *arg, int flag,
-    unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp)
+audiocs_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
 {
 	CS_engine_t	*eng = arg;
 	CS_state_t	*state = eng->ce_state;
@@ -1738,16 +1685,10 @@
 		audio_dev_warn(state->cs_adev, "power up failed");
 	}
 
-	eng->ce_started = B_FALSE;
 	eng->ce_count = 0;
-
-	*fragfrp = eng->ce_fragfr;
-	*nfragsp = CS4231_NFRAGS;
+	*nframesp = CS4231_NFRAMES;
 	*bufp = eng->ce_kaddr;
 
-	mutex_enter(&state->cs_lock);
-	audiocs_reset_engine(eng);
-	mutex_exit(&state->cs_lock);
 	return (0);
 }
 
@@ -1768,11 +1709,6 @@
 	CS_engine_t	*eng = arg;
 	CS_state_t	*state = eng->ce_state;
 
-	mutex_enter(&state->cs_lock);
-	audiocs_stop_engine(eng);
-	eng->ce_started = B_FALSE;
-	mutex_exit(&state->cs_lock);
-
 	(void) pm_idle_component(state->cs_dip, CS4231_COMPONENT);
 }
 
@@ -1789,14 +1725,21 @@
 static void
 audiocs_stop(void *arg)
 {
-	CS_engine_t	*eng = arg;
-	CS_state_t	*state = eng->ce_state;
+	CS_engine_t		*eng = arg;
+	CS_state_t		*state = eng->ce_state;
+	ddi_acc_handle_t	handle = CODEC_HANDLE;
 
 	mutex_enter(&state->cs_lock);
-	if (eng->ce_started) {
-		audiocs_stop_engine(eng);
-		eng->ce_started = B_FALSE;
-	}
+	/*
+	 * Stop the DMA engine.
+	 */
+	CS4231_DMA_STOP(state, eng);
+
+	/*
+	 * Stop the codec.
+	 */
+	SELIDX(state, INTC_REG);
+	ANDIDX(state, ~(eng->ce_codec_en), INTC_VALID_MASK);
 	mutex_exit(&state->cs_lock);
 }
 
@@ -1815,18 +1758,45 @@
 static int
 audiocs_start(void *arg)
 {
-	CS_engine_t	*eng = arg;
-	CS_state_t	*state = eng->ce_state;
-	int		rv = 0;
+	CS_engine_t		*eng = arg;
+	CS_state_t		*state = eng->ce_state;
+	ddi_acc_handle_t	handle = CODEC_HANDLE;
+	uint8_t			mask;
+	uint8_t			value;
+	uint8_t			reg;
+	int			rv;
 
 	mutex_enter(&state->cs_lock);
-	if (!eng->ce_started) {
-		if (audiocs_start_engine(eng) == DDI_SUCCESS) {
-			eng->ce_started = B_TRUE;
-		} else {
-			rv = EIO;
-		}
+
+	if (eng->ce_num == CS4231_PLAY) {
+		/* sample rate only set on play side */
+		value = FS_48000 | PDF_STEREO | PDF_LINEAR16NE;
+		reg = FSDF_REG;
+		mask = FSDF_VALID_MASK;
+	} else {
+		value = CDF_STEREO | CDF_LINEAR16NE;
+		reg = CDF_REG;
+		mask = CDF_VALID_MASK;
 	}
+	eng->ce_curoff = 0;
+	eng->ce_curidx = 0;
+
+	SELIDX(state, reg | IAR_MCE);
+	PUTIDX(state, value, mask);
+
+	if (audiocs_poll_ready(state) != DDI_SUCCESS) {
+		rv = EIO;
+	} else if (CS4231_DMA_START(state, eng) != DDI_SUCCESS) {
+		rv = EIO;
+	} else {
+		/*
+		 * Start the codec.
+		 */
+		SELIDX(state, INTC_REG);
+		ORIDX(state, eng->ce_codec_en, INTC_VALID_MASK);
+		rv = 0;
+	}
+
 	mutex_exit(&state->cs_lock);
 	return (rv);
 }
@@ -1906,12 +1876,40 @@
 static uint64_t
 audiocs_count(void *arg)
 {
-	CS_engine_t	*eng = arg;
-	CS_state_t	*state = eng->ce_state;
-	uint64_t	val;
+	CS_engine_t		*eng = arg;
+	CS_state_t		*state = eng->ce_state;
+	uint64_t		val;
+	uint32_t		off;
 
 	mutex_enter(&state->cs_lock);
+
+	off = CS4231_DMA_ADDR(state, eng);
+	ASSERT(off >= eng->ce_paddr);
+	off -= eng->ce_paddr;
+
+	/*
+	 * Every now and then, we get a value that is just a wee bit
+	 * too large.  This seems to be a small value related to
+	 * prefetch.  Rather than believe it, we just assume the last
+	 * offset in the buffer.  This should allow us to handle
+	 * wraps, but without inserting bogus sample counts.
+	 */
+	if (off >= CS4231_BUFSZ) {
+		off = CS4231_BUFSZ - 4;
+	}
+
+	off /= 4;
+
+	val = (off >= eng->ce_curoff) ?
+	    off - eng->ce_curoff :
+	    off + CS4231_NFRAMES - eng->ce_curoff;
+
+	eng->ce_count += val;
+	eng->ce_curoff = off;
 	val = eng->ce_count;
+
+	/* while here, possibly reload the next address */
+	CS4231_DMA_RELOAD(state, eng);
 	mutex_exit(&state->cs_lock);
 
 	return (val);
@@ -1936,61 +1934,6 @@
 }
 
 /*
- * audiocs_qlen()
- *
- * Description:
- *	This is called by the framework to determine on-device queue length.
- *
- * Arguments:
- *	void	*arg		The DMA engine to query
- *
- * Returns:
- *	hardware queue length not reported by count (0 for this device)
- */
-static unsigned
-audiocs_qlen(void *arg)
-{
-	CS_engine_t	*eng = arg;
-
-	return (eng->ce_fragfr);
-}
-
-
-/*
- * audiocs_reset_engine()
- *
- * Description:
- *	This routine resets the DMA engine pareparing it for work.
- *
- * Arguments:
- *	CS_engine_t	*engine		DMA engine to stop.
- */
-void
-audiocs_reset_engine(CS_engine_t *eng)
-{
-	CS_state_t	*state = eng->ce_state;
-	uint8_t		mask;
-	uint8_t		value;
-	uint8_t		reg;
-
-	if (eng->ce_num == CS4231_PLAY) {
-		/* sample rate only set on play side */
-		value = FS_48000 | PDF_STEREO | PDF_LINEAR16NE;
-		reg = FSDF_REG;
-		mask = FSDF_VALID_MASK;
-	} else {
-		value = CDF_STEREO | CDF_LINEAR16NE;
-		reg = CDF_REG;
-		mask = CDF_VALID_MASK;
-	}
-
-	SELIDX(state, reg | IAR_MCE);
-	PUTIDX(state, value, mask);
-
-	(void) audiocs_poll_ready(state);
-}
-
-/*
  * audiocs_alloc_engine()
  *
  * Description:
@@ -2007,7 +1950,6 @@
 int
 audiocs_alloc_engine(CS_state_t *state, int num)
 {
-	char			*prop;
 	unsigned		caps;
 	int			dir;
 	int			rc;
@@ -2016,6 +1958,7 @@
 	CS_engine_t		*eng;
 	uint_t			ccnt;
 	ddi_dma_cookie_t	dmac;
+	size_t			bufsz;
 
 	static ddi_device_acc_attr_t buf_attr = {
 		DDI_DEVICE_ATTR_V0,
@@ -2033,14 +1976,12 @@
 
 	switch (num) {
 	case CS4231_REC:
-		prop = "record-interrupts";
 		dir = DDI_DMA_READ;
 		caps = ENGINE_INPUT_CAP;
 		eng->ce_syncdir = DDI_DMA_SYNC_FORKERNEL;
 		eng->ce_codec_en = INTC_CEN;
 		break;
 	case CS4231_PLAY:
-		prop = "play-interrupts";
 		dir = DDI_DMA_WRITE;
 		caps = ENGINE_OUTPUT_CAP;
 		eng->ce_syncdir = DDI_DMA_SYNC_FORDEV;
@@ -2053,32 +1994,6 @@
 	}
 	state->cs_engines[num] = eng;
 
-	eng->ce_intrs = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, prop, CS4231_INTS);
-
-	/* make sure the values are good */
-	if (eng->ce_intrs < CS4231_MIN_INTS) {
-		audio_dev_warn(adev, "%s too low, %d, resetting to %d",
-		    prop, eng->ce_intrs, CS4231_INTS);
-		eng->ce_intrs = CS4231_INTS;
-	} else if (eng->ce_intrs > CS4231_MAX_INTS) {
-		audio_dev_warn(adev, "%s too high, %d, resetting to %d",
-		    prop, eng->ce_intrs, CS4231_INTS);
-		eng->ce_intrs = CS4231_INTS;
-	}
-
-	/*
-	 * Figure out how much space we need.  Sample rate is 48kHz, and
-	 * we need to store 8 chunks.  (Note that this means that low
-	 * interrupt frequencies will require more RAM.  We could probably
-	 * do some cleverness to use a more dynamic list.)
-	 */
-	eng->ce_fragfr = 48000 / eng->ce_intrs;
-	eng->ce_fragfr &= ~(64 - 1);	/* align @ 64B boundaries */
-	eng->ce_fragfr = max(eng->ce_fragfr, 64);
-	eng->ce_fragsz = eng->ce_fragfr * 4;	/* each frame is 4 bytes */
-	eng->ce_size = eng->ce_fragsz * CS4231_NFRAGS;
-
 	/* allocate dma handle */
 	rc = ddi_dma_alloc_handle(dip, CS4231_DMA_ATTR(state), DDI_DMA_SLEEP,
 	    NULL, &eng->ce_dmah);
@@ -2087,9 +2002,9 @@
 		return (DDI_FAILURE);
 	}
 	/* allocate DMA buffer */
-	rc = ddi_dma_mem_alloc(eng->ce_dmah, eng->ce_size, &buf_attr,
+	rc = ddi_dma_mem_alloc(eng->ce_dmah, CS4231_BUFSZ, &buf_attr,
 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &eng->ce_kaddr,
-	    &eng->ce_size, &eng->ce_acch);
+	    &bufsz, &eng->ce_acch);
 	if (rc == DDI_FAILURE) {
 		audio_dev_warn(adev, "dma_mem_alloc failed");
 		return (DDI_FAILURE);
@@ -2097,7 +2012,7 @@
 
 	/* bind DMA buffer */
 	rc = ddi_dma_addr_bind_handle(eng->ce_dmah, NULL,
-	    eng->ce_kaddr, eng->ce_size, dir | DDI_DMA_CONSISTENT,
+	    eng->ce_kaddr, CS4231_BUFSZ, dir | DDI_DMA_CONSISTENT,
 	    DDI_DMA_SLEEP, NULL, &dmac, &ccnt);
 	if ((rc != DDI_DMA_MAPPED) || (ccnt != 1)) {
 		audio_dev_warn(adev,
@@ -2105,11 +2020,7 @@
 		return (DDI_FAILURE);
 	}
 
-	/* save off phys addresses for each frag */
-	for (int i = 0; i < CS4231_NFRAGS; i++) {
-		eng->ce_paddr[i] = dmac.dmac_address;
-		dmac.dmac_address += eng->ce_fragsz;
-	}
+	eng->ce_paddr = dmac.dmac_address;
 
 	eng->ce_engine = audio_engine_alloc(&audiocs_engine_ops, caps);
 	if (eng->ce_engine == NULL) {
@@ -2143,7 +2054,7 @@
 		audio_dev_remove_engine(adev, eng->ce_engine);
 		audio_engine_free(eng->ce_engine);
 	}
-	if (eng->ce_paddr[0]) {
+	if (eng->ce_paddr) {
 		(void) ddi_dma_unbind_handle(eng->ce_dmah);
 	}
 	if (eng->ce_acch) {
@@ -2156,83 +2067,6 @@
 }
 
 /*
- * audiocs_start_port()
- *
- * Description:
- *	This routine starts the DMA engine.
- *
- * Arguments:
- *	CS_engine_t	*eng		Port of DMA engine to start.
- *
- * Returns:
- *	DDI_SUCCESS	DMA engine started.
- *	DDI_FAILURE	DMA engine not started.
- */
-int
-audiocs_start_engine(CS_engine_t *eng)
-{
-	CS_state_t		*state = eng->ce_state;
-	ddi_acc_handle_t	handle = CODEC_HANDLE;
-
-	ASSERT(mutex_owned(&state->cs_lock));
-
-	/*
-	 * If we are suspended, we can't touch hardware.
-	 */
-	if (state->cs_suspended)
-		return (DDI_SUCCESS);
-
-	/*
-	 * Start the DMA engine.
-	 */
-	if (CS4231_DMA_START(state, eng) != DDI_SUCCESS)
-		return (DDI_FAILURE);
-
-	/*
-	 * Start the codec.
-	 */
-	SELIDX(state, INTC_REG);
-	ORIDX(state, eng->ce_codec_en, INTC_VALID_MASK);
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * audiocs_stop_engine()
- *
- * Description:
- *	This routine stop the DMA engine.
- *
- * Arguments:
- *	CS_engine_t	*eng		DMA engine to stop.
- */
-void
-audiocs_stop_engine(CS_engine_t *eng)
-{
-	CS_state_t	*state = eng->ce_state;
-	ddi_acc_handle_t	handle = CODEC_HANDLE;
-
-	ASSERT(mutex_owned(&state->cs_lock));
-
-	/*
-	 * If we are suspended, we can't touch hardware.
-	 */
-	if (state->cs_suspended)
-		return;
-
-	/*
-	 * Stop the DMA engine.
-	 */
-	CS4231_DMA_STOP(state, eng);
-
-	/*
-	 * Stop the codec.
-	 */
-	SELIDX(state, INTC_REG);
-	ANDIDX(state, ~(eng->ce_codec_en), INTC_VALID_MASK);
-}
-
-/*
  * audiocs_poll_ready()
  *
  * Description:
@@ -2311,9 +2145,6 @@
  *	ddi_acc_handle_t handle		A handle to the device's registers
  *	uint8_t		addr		The register address to program
  *	int		reg		The register to select
- *
- * Returns:
- *	void
  */
 void
 #ifdef	DEBUG
@@ -2364,9 +2195,6 @@
  *	CS_state_t	state		Handle to this device
  *	uint8_t		mask		Mask to not set reserved register bits
  *	int		val		The value to program
- *
- * Returns:
- *	void
  */
 void
 #ifdef DEBUG
--- a/usr/src/uts/sun/io/audio/drv/audiocs/audio_4231.h	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/sun/io/audio/drv/audiocs/audio_4231.h	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -55,10 +55,6 @@
 #define	CS4231_NAME		"audiocs"
 #define	CS4231_MOD_NAME		"CS4231 audio driver"
 
-#define	CS4231_INTS		(175)		/* default interrupt rate */
-#define	CS4231_MIN_INTS		(10)		/* minimum interrupt rate */
-#define	CS4231_MAX_INTS		(2000)		/* maximum interrupt rate */
-
 /*
  * Implementation specific header file for the audiocs device driver.
  */
@@ -148,15 +144,10 @@
 #define	APC_CINTR_ENABLE	(APC_CIE|APC_CXI_EN)
 #define	APC_COMMON_ENABLE	(APC_IE|APC_EIE)
 
-#define	APC_PLAY_ENABLE		(APC_PINTR_MASK|APC_COMMON_MASK|\
-			APC_PINTR_ENABLE|APC_COMMON_ENABLE|APC_PDMA_GO)
-
-#define	APC_PLAY_DISABLE	(APC_PINTR_MASK|APC_PINTR_ENABLE|APC_PDMA_GO)
-
-#define	APC_CAP_ENABLE		(APC_CINTR_MASK|APC_COMMON_MASK|\
-			APC_CINTR_ENABLE|APC_COMMON_ENABLE|APC_CDMA_GO)
-
-#define	APC_CAP_DISABLE		(APC_CINTR_MASK|APC_CINTR_ENABLE|APC_CDMA_GO)
+#define	APC_PLAY_ENABLE		(APC_PDMA_GO)
+#define	APC_PLAY_DISABLE	(APC_PDMA_GO)
+#define	APC_CAP_ENABLE		(APC_CDMA_GO)
+#define	APC_CAP_DISABLE		(APC_CDMA_GO)
 
 /*
  * These are the registers for the EBUS2 DMA channel interface to the
@@ -219,10 +210,10 @@
 #define	EB2_PCLEAR_RESET_VALUE	(EB2_READ|EB2_EN_NEXT|EB2_EN_CNT)
 #define	EB2_RCLEAR_RESET_VALUE	(EB2_WRITE|EB2_EN_NEXT|EB2_EN_CNT)
 
-#define	EB2_PLAY_ENABLE		(EB2_INT_EN|EB2_EN_DMA|EB2_EN_CNT|EB2_64|\
+#define	EB2_PLAY_ENABLE		(EB2_EN_DMA|EB2_EN_CNT|EB2_64|\
 					EB2_PCLEAR_RESET_VALUE)
 
-#define	EB2_REC_ENABLE		(EB2_INT_EN|EB2_EN_DMA|EB2_EN_CNT|EB2_64|\
+#define	EB2_REC_ENABLE		(EB2_EN_DMA|EB2_EN_CNT|EB2_64|\
 					EB2_RCLEAR_RESET_VALUE)
 
 #define	EB2_FIFO_DRAIN		(EB2_DRAIN|EB2_CYC_PENDING)
@@ -239,7 +230,10 @@
 #define	CS4231_300MS			(300*1000)
 #define	CS4231_PLAY			0
 #define	CS4231_REC			1
-#define	CS4231_NFRAGS			8
+#define	CS4231_NFRAMES			4096
+#define	CS4231_NFRAGS			2
+#define	CS4231_FRAGSZ			((CS4231_NFRAMES / CS4231_NFRAGS) * 4)
+#define	CS4231_BUFSZ			(CS4231_NFRAMES * 4)
 
 /*
  * Supported dma engines and the ops vector
@@ -305,19 +299,15 @@
 	audio_engine_t		*ce_engine;
 	int			ce_num;
 	unsigned		ce_syncdir;
-	unsigned		ce_intrs;
-	unsigned		ce_fragfr;
-	unsigned		ce_fragsz;
-	unsigned		ce_nframes;
-	unsigned		ce_cfrag;
 	boolean_t		ce_started;
 	uint64_t		ce_count;
 
-	size_t			ce_size;
 	caddr_t			ce_kaddr;
 	ddi_dma_handle_t	ce_dmah;
 	ddi_acc_handle_t	ce_acch;
-	uint32_t		ce_paddr[CS4231_NFRAGS];
+	uint32_t		ce_paddr;
+	uint32_t		ce_curoff;
+	int			ce_curidx;
 
 	/* registers (EB2 only) */
 	ddi_acc_handle_t	ce_regsh;
@@ -340,8 +330,6 @@
 struct CS_state {
 	kmutex_t		cs_lock;	/* state protection lock */
 	kcondvar_t		cs_cv;		/* suspend/resume cond. var. */
-	ddi_iblock_cookie_t	cs_iblock;	/* iblock cookie */
-	kstat_t			*cs_ksp;	/* kernel statistics */
 	dev_info_t		*cs_dip;	/* used by cs4231_getinfo() */
 	audio_dev_t		*cs_adev;	/* audio device state */
 
@@ -374,8 +362,6 @@
 	CS_ctrl_t		*cs_inputs;
 };
 
-#define	KIOP(X)			((kstat_intr_t *)(X->cs_ksp->ks_data))
-
 /*
  * DMA ops vector definition
  */
@@ -385,11 +371,11 @@
 	int	(*cs_dma_map_regs)(CS_state_t *);
 	void	(*cs_dma_unmap_regs)(CS_state_t *);
 	void	(*cs_dma_reset)(CS_state_t *);
-	int	(*cs_dma_add_intr)(CS_state_t *);
-	void	(*cs_dma_rem_intr)(CS_state_t *);
 	int 	(*cs_dma_start)(CS_engine_t *);
 	void	(*cs_dma_stop)(CS_engine_t *);
 	void	(*cs_dma_power)(CS_state_t *, int);
+	void	(*cs_dma_reload)(CS_engine_t *);
+	uint32_t	(*cs_dma_addr)(CS_engine_t *);
 };
 typedef struct cs4231_dma_ops cs4231_dma_ops_t;
 
@@ -399,12 +385,12 @@
 #define	CS4231_DMA_MAP_REGS(S)		((S)->cs_dma_ops->cs_dma_map_regs)(S)
 #define	CS4231_DMA_UNMAP_REGS(S)	((S)->cs_dma_ops->cs_dma_unmap_regs)(S)
 #define	CS4231_DMA_RESET(S)		((S)->cs_dma_ops->cs_dma_reset)(S)
-#define	CS4231_DMA_ADD_INTR(S)		((S)->cs_dma_ops->cs_dma_add_intr)(S)
-#define	CS4231_DMA_REM_INTR(S)		((S)->cs_dma_ops->cs_dma_rem_intr)(S)
 #define	CS4231_DMA_START(S, E)		((S)->cs_dma_ops->cs_dma_start)(E)
 #define	CS4231_DMA_STOP(S, E)		((S)->cs_dma_ops->cs_dma_stop)(E)
 #define	CS4231_DMA_POWER(S, L)		((S)->cs_dma_ops->cs_dma_power)(S, L)
 #define	CS4231_DMA_ATTR(S)		((S)->cs_dma_ops->cs_dma_attr)
+#define	CS4231_DMA_RELOAD(S, E)		((S)->cs_dma_ops->cs_dma_reload)(E)
+#define	CS4231_DMA_ADDR(S, E)		((S)->cs_dma_ops->cs_dma_addr)(E)
 
 /*
  * Useful bit twiddlers
--- a/usr/src/uts/sun/io/audio/drv/audiocs/audio_4231_apcdma.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/sun/io/audio/drv/audiocs/audio_4231_apcdma.c	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -61,22 +61,16 @@
 };
 
 /*
- * Local routines
- */
-static uint_t apc_intr(caddr_t);
-static void apc_load_fragment(CS_engine_t *);
-
-/*
  * DMA ops vector functions
  */
 static int apc_map_regs(CS_state_t *);
 static void apc_unmap_regs(CS_state_t *);
 static void apc_reset(CS_state_t *);
-static int apc_add_intr(CS_state_t *);
-static void apc_rem_intr(CS_state_t *);
 static int apc_start_engine(CS_engine_t *);
 static void apc_stop_engine(CS_engine_t *);
 static void apc_power(CS_state_t *, int);
+static void apc_reload(CS_engine_t *);
+static uint32_t apc_addr(CS_engine_t *);
 
 cs4231_dma_ops_t cs4231_apcdma_ops = {
 	"APC DMA controller",
@@ -84,11 +78,11 @@
 	apc_map_regs,
 	apc_unmap_regs,
 	apc_reset,
-	apc_add_intr,
-	apc_rem_intr,
 	apc_start_engine,
 	apc_stop_engine,
 	apc_power,
+	apc_reload,
+	apc_addr,
 };
 
 /*
@@ -182,69 +176,6 @@
 }	/* apc_reset() */
 
 /*
- * apc_add_intr()
- *
- * Description:
- *	Register the APC interrupts with the kernel.
- *
- *	NOTE: This does NOT turn on interrupts.
- *
- *	CAUTION: While the interrupts are added, the Codec interrupts are
- *		not enabled.
- *
- * Arguments:
- *	CS_state_t	*state	Pointer to the device's state structure
- *
- * Returns:
- *	DDI_SUCCESS		Registers successfully mapped
- *	DDI_FAILURE		Registers not successfully mapped
- */
-static int
-apc_add_intr(CS_state_t *state)
-{
-	dev_info_t	*dip = state->cs_dip;
-
-	/* first we make sure this isn't a high level interrupt */
-	if (ddi_intr_hilevel(dip, 0) != 0) {
-		audio_dev_warn(state->cs_adev,
-		    "unsupported high level interrupt");
-		return (DDI_FAILURE);
-	}
-
-	/* okay to register the interrupt */
-	if (ddi_add_intr(dip, 0, NULL, NULL, apc_intr, (caddr_t)state) !=
-	    DDI_SUCCESS) {
-		audio_dev_warn(state->cs_adev, "bad interrupt specification");
-		return (DDI_FAILURE);
-	}
-
-	return (DDI_SUCCESS);
-
-}	/* apc_add_intr() */
-
-/*
- * apc_rem_intr()
- *
- * Description:
- *	Unregister the APC interrupts from the kernel.
- *
- *	CAUTION: While the interrupts are removed, the Codec interrupts are
- *		not disabled, but then, they never should have been on in
- *		the first place.
- *
- * Arguments:
- *	CS_state_t	*state	Pointer to the device's state structure
- *
- * Returns:
- *	void
- */
-static void
-apc_rem_intr(CS_state_t *state)
-{
-	ddi_remove_intr(state->cs_dip, 0, NULL);
-}	/* apc_rem_intr() */
-
-/*
  * apc_start_engine()
  *
  * Description:
@@ -279,10 +210,10 @@
 	ASSERT(mutex_owned(&state->cs_lock));
 
 	if (eng->ce_num == CS4231_PLAY) {
-		enable = APC_PLAY_ENABLE;
+		enable = APC_PDMA_GO;
 		dirty = APC_PD;
 	} else {
-		enable = APC_CAP_ENABLE;
+		enable = APC_CDMA_GO;
 		dirty = APC_CD;
 	}
 
@@ -301,7 +232,7 @@
 	/*
 	 * Program the first fragment.
 	 */
-	apc_load_fragment(eng);
+	apc_reload(eng);
 
 	/*
 	 * Start the DMA engine, including interrupts.
@@ -309,9 +240,9 @@
 	OR_SET_WORD(handle, &APC_DMACSR, enable);
 
 	/*
-	 * Program the second fragment.
+	 * Program the double buffering.
 	 */
-	apc_load_fragment(eng);
+	apc_reload(eng);
 
 	return (DDI_SUCCESS);
 }
@@ -338,7 +269,6 @@
 	CS_state_t		*state = eng->ce_state;
 	ddi_acc_handle_t	handle = APC_HANDLE;
 	uint32_t		reg;
-	uint32_t		intren;
 	uint32_t		abort;
 	uint32_t		drainbit;
 	uint32_t		disable;
@@ -346,20 +276,15 @@
 	ASSERT(mutex_owned(&state->cs_lock));
 
 	if (eng->ce_num == CS4231_PLAY) {
-		intren = APC_PINTR_ENABLE;
 		abort = APC_P_ABORT;
 		drainbit = APC_PM;
 		disable = APC_PLAY_DISABLE;
 	} else {
-		intren = APC_CINTR_ENABLE;
 		abort = APC_C_ABORT;
 		drainbit = APC_CX;
 		disable = APC_CAP_DISABLE;
 	}
 
-	/* clear the interrupts so the ISR doesn't get involved */
-	AND_SET_WORD(handle, &APC_DMACSR, ~intren);
-
 	/* first, abort the DMA engine */
 	OR_SET_WORD(handle, &APC_DMACSR, abort);
 
@@ -391,9 +316,6 @@
  * Arguments:
  *	CS_state_t	*state		Ptr to the device's state structure
  *	int		level		Power level to set
- *
- * Returns:
- *	void
  */
 static void
 apc_power(CS_state_t *state, int level)
@@ -417,119 +339,8 @@
 }	/* apc_power() */
 
 
-/* *******  Local Routines ************************************************** */
-
-/*
- * apc_intr()
- *
- * Description:
- *	APC interrupt service routine, which services both play and capture
- *	interrupts. First we find out why there was an interrupt, then we
- *	take the appropriate action.
- *
- *	Because this ISR deals with both play and record interrupts we have
- *	to be careful to not lose an interrupt. So we service the record
- *	interrupt first and save the incoming data until later. This is all
- *	done without releasing the lock, thus there can be no race conditions.
- *	Then we process the play interrupt. While processing the play interrupt
- *	we have to release the lock. When this happens we send recorded data
- *	to the mixer and then get the next chunk of data to play. If there
- *	wasn't a play interrupt then we finish by sending the recorded data,
- *	if any.
- *
- * Arguments:
- *	caddr_t		T	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
-apc_intr(caddr_t T)
-{
-	CS_state_t		*state = (void *)T;
-	ddi_acc_handle_t	handle = APC_HANDLE;
-	uint_t			csr;
-	int			rc = DDI_INTR_UNCLAIMED;
-
-	/* the state must be protected */
-	mutex_enter(&state->cs_lock);
-
-	if (state->cs_suspended) {
-		mutex_exit(&state->cs_lock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	/* get the APC CSR */
-	csr = ddi_get32(handle, &APC_DMACSR);
-
-	/* make sure this device sent the interrupt */
-	if (!(csr & APC_IP)) {
-		if (csr & APC_PMI_EN) {
-			/*
-			 * Clear device generated interrupt while play is
-			 * active (Only seen while playing and insane mode
-			 * switching)
-			 */
-			mutex_exit(&state->cs_lock);
-			return (DDI_INTR_CLAIMED);
-		} else {
-			/* nope, this isn't our interrupt */
-			mutex_exit(&state->cs_lock);
-			return (DDI_INTR_UNCLAIMED);
-		}
-	}
-
-	/* clear all interrupts we captured this time */
-	ddi_put32(handle, &APC_DMACSR, csr);
-
-	if (csr & APC_CINTR_MASK) {
-		/* try to load the next record buffer */
-		apc_load_fragment(state->cs_engines[CS4231_REC]);
-		rc = DDI_INTR_CLAIMED;
-	}
-
-	if (csr & APC_PINTR_MASK) {
-		/* try to load the next play buffer */
-		apc_load_fragment(state->cs_engines[CS4231_PLAY]);
-		rc = DDI_INTR_CLAIMED;
-	}
-
-done:
-
-	/* APC error interrupt, not sure what to do here */
-	if (csr & APC_EI) {
-		audio_dev_warn(state->cs_adev, "error interrupt: 0x%x", csr);
-		rc = DDI_INTR_CLAIMED;
-	}
-
-	/* update the kernel interrupt statistics */
-	if (state->cs_ksp) {
-		if (rc == DDI_INTR_CLAIMED) {
-			KIOP(state)->intrs[KSTAT_INTR_HARD]++;
-		}
-	}
-
-	mutex_exit(&state->cs_lock);
-
-	if (csr & APC_CINTR_MASK) {
-		CS_engine_t	*eng = state->cs_engines[CS4231_REC];
-		if (eng->ce_started)
-			audio_engine_produce(eng->ce_engine);
-	}
-	if (csr & APC_PINTR_MASK) {
-		CS_engine_t	*eng = state->cs_engines[CS4231_PLAY];
-		if (eng->ce_started)
-			audio_engine_consume(eng->ce_engine);
-	}
-
-	return (rc);
-
-}	/* apc_intr() */
-
 static void
-apc_load_fragment(CS_engine_t *eng)
+apc_reload(CS_engine_t *eng)
 {
 	CS_state_t		*state = eng->ce_state;
 	ddi_acc_handle_t	handle = APC_HANDLE;
@@ -556,12 +367,40 @@
 	(void) ddi_get32(handle, nva);
 
 	/* write the address of the next fragment */
-	ddi_put32(handle, nva, eng->ce_paddr[eng->ce_cfrag]);
+	ddi_put32(handle, nva,
+	    eng->ce_paddr + (CS4231_FRAGSZ * eng->ce_curidx));
+	eng->ce_curidx++;
+	eng->ce_curidx %= CS4231_NFRAGS;
 
 	/* now program the NC reg., which enables the state machine */
-	ddi_put32(handle, nc, eng->ce_fragsz);
+	ddi_put32(handle, nc, CS4231_FRAGSZ);
+}
 
-	eng->ce_cfrag++;
-	eng->ce_cfrag %= CS4231_NFRAGS;
-	eng->ce_count += eng->ce_fragfr;
+/*
+ * apc_addr()
+ *
+ * Description:
+ *	This routine returns the current DMA address for the engine (the
+ *	next address being accessed).
+ *
+ * Arguments:
+ *	CS_engine_t	*eng		The engine
+ *
+ * Returns:
+ *	Physical DMA address for current transfer.
+ */
+static uint32_t
+apc_addr(CS_engine_t *eng)
+{
+	CS_state_t		*state = eng->ce_state;
+	ddi_acc_handle_t	handle = APC_HANDLE;
+	uint32_t		*va;	/* VA reg */
+
+	if (eng->ce_num == CS4231_PLAY) {
+		va = &APC_DMAPVA;
+	} else {
+		va = &APC_DMACVA;
+	}
+
+	return (ddi_get32(handle, va));
 }
--- a/usr/src/uts/sun/io/audio/drv/audiocs/audio_4231_eb2dma.c	Tue Mar 16 09:43:38 2010 -0600
+++ b/usr/src/uts/sun/io/audio/drv/audiocs/audio_4231_eb2dma.c	Tue Mar 16 09:30:41 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -67,22 +67,16 @@
 };
 
 /*
- * Local routines
- */
-static uint_t eb2_intr(caddr_t);
-static void eb2_load_fragment(CS_engine_t *);
-
-/*
  * DMA ops vector functions
  */
 static int eb2_map_regs(CS_state_t *);
 static void eb2_unmap_regs(CS_state_t *);
 static void eb2_reset(CS_state_t *);
-static int eb2_add_intr(CS_state_t *);
-static void eb2_rem_intr(CS_state_t *);
 static int eb2_start_engine(CS_engine_t *);
 static void eb2_stop_engine(CS_engine_t *);
 static void eb2_power(CS_state_t *, int);
+static void eb2_reload(CS_engine_t *);
+static uint32_t eb2_addr(CS_engine_t *);
 
 cs4231_dma_ops_t cs4231_eb2dma_ops = {
 	"EB2 DMA controller",
@@ -90,11 +84,11 @@
 	eb2_map_regs,
 	eb2_unmap_regs,
 	eb2_reset,
-	eb2_add_intr,
-	eb2_rem_intr,
 	eb2_start_engine,
 	eb2_stop_engine,
 	eb2_power,
+	eb2_reload,
+	eb2_addr,
 };
 
 /*
@@ -177,9 +171,6 @@
  *
  * Arguments:
  *	CS_state_t	*state	The device's state
- *
- * Returns:
- *	void
  */
 static void
 eb2_unmap_regs(CS_state_t *state)
@@ -205,9 +196,6 @@
  * Arguments:
  *	dev_info_t	*dip	Pointer to the device's devinfo structure
  *	CS_state_t	*state	The device's state structure
- *
- * Returns:
- *	void
  */
 static void
 eb2_reset(CS_state_t *state)
@@ -242,80 +230,6 @@
 }	/* eb2_reset() */
 
 /*
- * eb2_add_intr()
- *
- * Description:
- *	Register the EB2 interrupts with the kernel.
- *
- *	NOTE: This does NOT turn on interrupts.
- *
- *	CAUTION: While the interrupts are added, the Codec interrupts are
- *		not enabled.
- *
- * Arguments:
- *	CS_state_t	*state	Pointer to the device's state structure
- *
- * Returns:
- *	DDI_SUCCESS		Interrupts added
- *	DDI_FAILURE		Interrupts not added
- */
-static int
-eb2_add_intr(CS_state_t *state)
-{
-	dev_info_t	*dip = state->cs_dip;
-
-	/* first we make sure these aren't high level interrupts */
-	if (ddi_intr_hilevel(dip, 0) != 0) {
-		audio_dev_warn(state->cs_adev, "unsupported hi level intr 0");
-		return (DDI_FAILURE);
-	}
-	if (ddi_intr_hilevel(dip, 1) != 0) {
-		audio_dev_warn(state->cs_adev, "unsupported hi level intr 1");
-		return (DDI_FAILURE);
-	}
-
-	/* okay to register the interrupts */
-	if (ddi_add_intr(dip, 0, NULL, NULL, eb2_intr,
-	    (caddr_t)state->cs_engines[CS4231_REC]) != DDI_SUCCESS) {
-		audio_dev_warn(state->cs_adev, "bad record interrupt spec");
-		return (DDI_FAILURE);
-	}
-
-	if (ddi_add_intr(dip, 1, NULL, NULL, eb2_intr,
-	    (caddr_t)state->cs_engines[CS4231_PLAY]) != DDI_SUCCESS) {
-		audio_dev_warn(state->cs_adev, "play interrupt spec");
-		ddi_remove_intr(dip, 0, NULL);
-		return (DDI_FAILURE);
-	}
-
-	return (DDI_SUCCESS);
-
-}	/* eb2_add_intr() */
-
-/*
- * eb2_rem_intr()
- *
- * Description:
- *	Unregister the EB2 interrupts from the kernel.
- *
- *	CAUTION: While the interrupts are removed, the Codec interrupts are
- *		not disabled, but then, they never should have been on in
- *		the first place.
- *
- * Arguments:
- *	CS_state_t	*state	Pointer to the device's soft state
- *
- * Returns:
- *	void
- */
-static void
-eb2_rem_intr(CS_state_t *state)
-{
-	ddi_remove_intr(state->cs_dip, 0, NULL);
-	ddi_remove_intr(state->cs_dip, 1, NULL);
-}	/* eb2_rem_intr() */
-
-/*
  * eb2_start_engine()
  *
  * Description:
@@ -375,7 +289,7 @@
 	/*
 	 * Program the DMA engine.
 	 */
-	eb2_load_fragment(eng);
+	eb2_reload(eng);
 
 	/*
 	 * Start playing before we load the next fragment.
@@ -383,9 +297,9 @@
 	OR_SET_WORD(handle, &regs->eb2csr, enable);
 
 	/*
-	 * Program a 2nd fragment.
+	 * Program the next address, too.
 	 */
-	eb2_load_fragment(eng);
+	eb2_reload(eng);
 
 	return (DDI_SUCCESS);
 
@@ -401,9 +315,6 @@
  *
  * Arguments:
  *	CS_engine_t	*eng	The engine to stop
- *
- * Returns:
- *	void
  */
 static void
 eb2_stop_engine(CS_engine_t *eng)
@@ -449,9 +360,6 @@
  * Arguments:
  *	CS_state_t	*state		Ptr to the device's state structure
  *	int		level		Power level to set
- *
- * Returns:
- *	void
  */
 static void
 eb2_power(CS_state_t *state, int level)
@@ -466,90 +374,18 @@
 
 }	/* eb2_power() */
 
-
-/* *******  Local Routines ************************************************** */
-
 /*
- * eb2_intr()
+ * eb2_reload()
  *
  * Description:
- *	EB2 interrupt serivce routine. First we find out why there was an
- *	interrupt, then we take the appropriate action.
+ *	This routine reloads the DMA address, so that we can continue
+ *	double buffer round-robin fashion.
  *
  * Arguments:
- *	caddr_t		T	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
+ *	CS_engine_t	*eng		The engine
  */
-static uint_t
-eb2_intr(caddr_t T)
-{
-	CS_engine_t		*eng = (void *)T;
-	CS_state_t		*state = eng->ce_state;
-	cs4231_eb2regs_t	*regs = eng->ce_eb2regs;
-	ddi_acc_handle_t	handle = eng->ce_regsh;
-	uint32_t		csr;
-	boolean_t		doit = B_FALSE;
-
-	/* the state must be protected */
-	mutex_enter(&state->cs_lock);
-	if (state->cs_suspended) {
-		mutex_exit(&state->cs_lock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	/* get the EB2 CSR */
-	csr = ddi_get32(handle, &regs->eb2csr);
-
-	/* make sure this device sent the interrupt */
-	if (!(csr & EB2_INT_PEND)) {
-		mutex_exit(&state->cs_lock);
-		/* nope, this isn't our interrupt */
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	/* clear all interrupts we captured at this time */
-	ddi_put32(handle, &regs->eb2csr, (csr|EB2_TC));
-
-	if (csr & EB2_TC) {
-
-		/* try to load the next audio buffer */
-		eb2_load_fragment(eng);
-
-		/* if engine was started, then we want to consume later */
-		doit = eng->ce_started;
-
-	} else if (csr & EB2_ERR_PEND) {
-		audio_dev_warn(state->cs_adev, "error intr: 0x%x", csr);
-
-	} else {
-		audio_dev_warn(state->cs_adev, "unknown intr: 0x%x", csr);
-	}
-
-	/* update the kernel interrupt statisitcs */
-	if (state->cs_ksp) {
-		KIOP(state)->intrs[KSTAT_INTR_HARD]++;
-	}
-
-	mutex_exit(&state->cs_lock);
-
-	if (doit) {
-		if (eng->ce_num == CS4231_PLAY) {
-			audio_engine_consume(eng->ce_engine);
-		} else {
-			audio_engine_produce(eng->ce_engine);
-		}
-	}
-
-	return (DDI_INTR_CLAIMED);
-
-}	/* eb2_intr() */
-
 static void
-eb2_load_fragment(CS_engine_t *eng)
+eb2_reload(CS_engine_t *eng)
 {
 	ddi_acc_handle_t	handle = eng->ce_regsh;
 	cs4231_eb2regs_t	*regs = eng->ce_eb2regs;
@@ -562,12 +398,34 @@
 	/*
 	 * For eb2 we first program the Next Byte Count Register.
 	 */
-	ddi_put32(handle, &regs->eb2bcr, eng->ce_fragsz);
+	ddi_put32(handle, &regs->eb2bcr, CS4231_FRAGSZ);
 
 	/* now program the Next Address Register */
-	ddi_put32(handle, &regs->eb2acr, eng->ce_paddr[eng->ce_cfrag]);
+	ddi_put32(handle, &regs->eb2acr,
+	    eng->ce_paddr + (CS4231_FRAGSZ * eng->ce_curidx));
+
+	eng->ce_curidx++;
+	eng->ce_curidx %= CS4231_NFRAGS;
+}
 
-	eng->ce_cfrag++;
-	eng->ce_cfrag %= CS4231_NFRAGS;
-	eng->ce_count += eng->ce_fragfr;
+/*
+ * eb2_addr()
+ *
+ * Description:
+ *	This routine returns the current DMA address for the engine (the
+ *	next address being accessed).
+ *
+ * Arguments:
+ *	CS_engine_t	*eng		The engine
+ *
+ * Returns:
+ *	Physical DMA address for current transfer.
+ */
+static uint32_t
+eb2_addr(CS_engine_t *eng)
+{
+	ddi_acc_handle_t	handle = eng->ce_regsh;
+	cs4231_eb2regs_t	*regs = eng->ce_eb2regs;
+
+	return (ddi_get32(handle, &regs->eb2acr));
 }
--- a/usr/src/uts/sun/io/audio/drv/audiocs/audiocs.conf	Tue Mar 16 09:43:38 2010 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# Configuration file for the audiocs audio driver.
-#
-#	WARNING: This is an UNSTABLE configuration file. Its contents
-#		may change at any time.
-#
-
-#
-# 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 interrupt rate the larger the load on
-# the system. So use this cautiously. The audiocs 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;