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
--- 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, ®s->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, ®s->aud_regs.ap_aint, interrupts);
- (void) ddi_get32(handle, ®s->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 = ®s->aud_ram[port->tp_dma_stream].aram;
- eram = ®s->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 = ®s->aud_ram[port->tp_int_stream].aram;
- eram = ®s->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, ®s->aud_regs.ap_stop,
- port->tp_int_mask | port->tp_dma_mask);
-
- /* enable interrupts */
- OR_SET_WORD(handle, ®s->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 = ®s->aud_ram[port->tp_dma_stream].aram;
+ eram = ®s->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, ®s->aud_regs.ap_stop, port->tp_dma_mask);
+
+ /* now make sure it starts playing */
+ ddi_put32(handle, ®s->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, ®s->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, ®s->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, ®s->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, ®s->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, ®s->eb2bcr, eng->ce_fragsz);
+ ddi_put32(handle, ®s->eb2bcr, CS4231_FRAGSZ);
/* now program the Next Address Register */
- ddi_put32(handle, ®s->eb2acr, eng->ce_paddr[eng->ce_cfrag]);
+ ddi_put32(handle, ®s->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, ®s->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;