summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorjmcneill <jmcneill@NetBSD.org>2011-11-23 23:07:28 +0000
committerjmcneill <jmcneill@NetBSD.org>2011-11-23 23:07:28 +0000
commit18b5c52f17290f01443243e7e025d1e67dcb1cbf (patch)
tree836affb0c4230ed099599af258cbf8aa7a5701e6 /sys/dev
parent58e34a5e74d184d06dc31a4c218e09b3c05df23f (diff)
Merge jmcneill-audiomp3 branch, which is derived from ad-audiomp2. From
the original ad-audiomp branch notes: Add MP locking to the audio drivers. Making the audio drivers MP safe is necessary before efforts can be made to make the VM system MP safe. The are two locks per device instance, an ISR lock and a character device lock. The ISR lock replaces calls to splaudio()/splx(), and will be held across calls to device methods which were called at splaudio() before (e.g. trigger_output). The character device lock is held across calls to nearly all of the methods, excluding some only used for initialization, e.g. get_locks. Welcome to 5.99.57.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/TODO.audiomp58
-rw-r--r--sys/dev/acpi/joy_acpi.c8
-rw-r--r--sys/dev/acpi/mpu_acpi.c6
-rw-r--r--sys/dev/auconv.c24
-rw-r--r--sys/dev/auconv.h4
-rw-r--r--sys/dev/audio.c1084
-rw-r--r--sys/dev/audio_if.h16
-rw-r--r--sys/dev/audiovar.h27
-rw-r--r--sys/dev/aurateconv.c12
-rw-r--r--sys/dev/bluetooth/btsco.c60
-rw-r--r--sys/dev/ebus/cs4231_ebus.c22
-rw-r--r--sys/dev/ic/ac97.c87
-rw-r--r--sys/dev/ic/ac97var.h6
-rw-r--r--sys/dev/ic/ad1848.c43
-rw-r--r--sys/dev/ic/ad1848var.h9
-rw-r--r--sys/dev/ic/am7930.c12
-rw-r--r--sys/dev/ic/am7930var.h5
-rw-r--r--sys/dev/ic/attimer.c13
-rw-r--r--sys/dev/ic/cs4231.c18
-rw-r--r--sys/dev/ic/cs4231var.h6
-rw-r--r--sys/dev/ic/interwave.c50
-rw-r--r--sys/dev/ic/interwavevar.h11
-rw-r--r--sys/dev/ic/joy.c97
-rw-r--r--sys/dev/ic/joyvar.h3
-rw-r--r--sys/dev/ic/mpu.c47
-rw-r--r--sys/dev/ic/mpuvar.h3
-rw-r--r--sys/dev/ic/msm6258.c30
-rw-r--r--sys/dev/ic/opl.c54
-rw-r--r--sys/dev/ic/oplvar.h5
-rw-r--r--sys/dev/ic/tms320av110.c39
-rw-r--r--sys/dev/ic/tms320av110var.h5
-rw-r--r--sys/dev/isa/ad1848_isa.c37
-rw-r--r--sys/dev/isa/ad1848var.h6
-rw-r--r--sys/dev/isa/aria.c38
-rw-r--r--sys/dev/isa/cms.c5
-rw-r--r--sys/dev/isa/ess.c130
-rw-r--r--sys/dev/isa/essvar.h10
-rw-r--r--sys/dev/isa/gus.c198
-rw-r--r--sys/dev/isa/ics2101.c9
-rw-r--r--sys/dev/isa/joy_ess.c5
-rw-r--r--sys/dev/isa/joy_isa.c15
-rw-r--r--sys/dev/isa/midi_pcppi.c45
-rw-r--r--sys/dev/isa/mpu_isa.c13
-rw-r--r--sys/dev/isa/mpu_sb.c9
-rw-r--r--sys/dev/isa/mpu_ym.c8
-rw-r--r--sys/dev/isa/opl_ess.c7
-rw-r--r--sys/dev/isa/opl_isa.c18
-rw-r--r--sys/dev/isa/opl_sb.c9
-rw-r--r--sys/dev/isa/pas.c11
-rw-r--r--sys/dev/isa/pcppi.c86
-rw-r--r--sys/dev/isa/pcppivar.h10
-rw-r--r--sys/dev/isa/sb.c7
-rw-r--r--sys/dev/isa/sb_isa.c9
-rw-r--r--sys/dev/isa/sbdsp.c196
-rw-r--r--sys/dev/isa/sbdspvar.h10
-rw-r--r--sys/dev/isa/wss.c38
-rw-r--r--sys/dev/isa/ym.c112
-rw-r--r--sys/dev/isa/ymvar.h7
-rw-r--r--sys/dev/isapnp/gus_isapnp.c17
-rw-r--r--sys/dev/isapnp/joy_isapnp.c17
-rw-r--r--sys/dev/isapnp/mpu_isapnp.c14
-rw-r--r--sys/dev/midi.c959
-rw-r--r--sys/dev/midi_if.h5
-rw-r--r--sys/dev/midictl.c414
-rw-r--r--sys/dev/midictl.h9
-rw-r--r--sys/dev/midisyn.c148
-rw-r--r--sys/dev/midisynvar.h3
-rw-r--r--sys/dev/midivar.h44
-rw-r--r--sys/dev/mulaw.c25
-rw-r--r--sys/dev/ofisa/joy_ofisa.c19
-rw-r--r--sys/dev/pad/pad.c126
-rw-r--r--sys/dev/pad/padvar.h7
-rw-r--r--sys/dev/pad/padvol.c11
-rw-r--r--sys/dev/pad/padvol.h13
-rw-r--r--sys/dev/pci/auacer.c84
-rw-r--r--sys/dev/pci/auich.c106
-rw-r--r--sys/dev/pci/auixp.c111
-rw-r--r--sys/dev/pci/auixpvar.h4
-rw-r--r--sys/dev/pci/autri.c80
-rw-r--r--sys/dev/pci/autrivar.h4
-rw-r--r--sys/dev/pci/auvia.c214
-rw-r--r--sys/dev/pci/auviavar.h6
-rw-r--r--sys/dev/pci/azalia.c121
-rw-r--r--sys/dev/pci/azalia.h7
-rw-r--r--sys/dev/pci/azalia_codec.c58
-rw-r--r--sys/dev/pci/cmpci.c83
-rw-r--r--sys/dev/pci/cmpcivar.h6
-rw-r--r--sys/dev/pci/cs4280.c70
-rw-r--r--sys/dev/pci/cs4281.c42
-rw-r--r--sys/dev/pci/cs428x.c57
-rw-r--r--sys/dev/pci/cs428x.h12
-rw-r--r--sys/dev/pci/eap.c177
-rw-r--r--sys/dev/pci/eapvar.h81
-rw-r--r--sys/dev/pci/emuxki.c297
-rw-r--r--sys/dev/pci/emuxkivar.h6
-rw-r--r--sys/dev/pci/esa.c134
-rw-r--r--sys/dev/pci/esavar.h5
-rw-r--r--sys/dev/pci/esm.c101
-rw-r--r--sys/dev/pci/esmvar.h9
-rw-r--r--sys/dev/pci/eso.c298
-rw-r--r--sys/dev/pci/esovar.h7
-rw-r--r--sys/dev/pci/fms.c86
-rw-r--r--sys/dev/pci/fmsvar.h6
-rw-r--r--sys/dev/pci/gcscaudio.c81
-rw-r--r--sys/dev/pci/hdaudio/hdafg.c51
-rw-r--r--sys/dev/pci/hdaudio/hdaudio.c8
-rw-r--r--sys/dev/pci/hdaudio/hdaudio_pci.c6
-rw-r--r--sys/dev/pci/joy_eap.c10
-rw-r--r--sys/dev/pci/joy_eso.c7
-rw-r--r--sys/dev/pci/joy_pci.c29
-rw-r--r--sys/dev/pci/mpu_cmpci.c7
-rw-r--r--sys/dev/pci/mpu_eso.c7
-rw-r--r--sys/dev/pci/mpu_fms.c7
-rw-r--r--sys/dev/pci/mpu_yds.c7
-rw-r--r--sys/dev/pci/neo.c77
-rw-r--r--sys/dev/pci/opl_eso.c5
-rw-r--r--sys/dev/pci/sv.c214
-rw-r--r--sys/dev/pci/svvar.h4
-rw-r--r--sys/dev/pci/yds.c82
-rw-r--r--sys/dev/pci/ydsvar.h4
-rw-r--r--sys/dev/sbus/cs4231_sbus.c23
-rw-r--r--sys/dev/sbus/dbri.c97
-rw-r--r--sys/dev/sbus/dbrivar.h5
-rw-r--r--sys/dev/sequencer.c757
-rw-r--r--sys/dev/sequencervar.h25
-rw-r--r--sys/dev/tc/bba.c64
-rw-r--r--sys/dev/usb/uaudio.c103
-rw-r--r--sys/dev/usb/umidi.c35
-rw-r--r--sys/dev/usb/umidivar.h5
129 files changed, 5371 insertions, 3364 deletions
diff --git a/sys/dev/TODO.audiomp b/sys/dev/TODO.audiomp
new file mode 100644
index 00000000000..99881388ba2
--- /dev/null
+++ b/sys/dev/TODO.audiomp
@@ -0,0 +1,58 @@
+driver status tested
+===============================================================================
+arch/amiga/dev/aucc.c done
+arch/amiga/dev/repulse.c done
+arch/amiga/dev/toccata.c done
+arch/arm/iomd/vidcaudio.c done
+arcm/arm/xscale/pxa2x0_ac97.c done
+arch/dreamcast/dev/g2/aica.c done
+arch/hp700/gsc/harmony.c done
+arch/hpcmips/vr/vraiu.c done
+arch/macppc/dev/awacs.c done port-macppc
+arch/macppc/dev/snapper.c done port-macppc, TAS3004 only
+arch/prep/isa/paud_isa.c done
+arch/sgimips/hpc/haltwo.c done
+arch/sgimips/mace/mavb.c done
+arch/sparc/dev/audioamd.c done
+arch/x68k/dev/vs.c done
+arch/zaurus/dev/zaudio.c done
+dev/bluetooth/btsco.c done
+dev/ebus/cs4231_ebus.c done port-sparc64
+dev/ic/interwave.c done
+dev/ic/mpu.c done
+dev/ic/opl.c done
+dev/ic/tms320av110.c done
+dev/isa/aria.c done
+dev/isa/ess.c done port-shark
+dev/isa/gus.c done
+dev/isa/pas.c done
+dev/isa/sb.c done port-i386
+dev/isa/wss.c done port-i386
+dev/isa/ym.c done port-i386
+dev/isapnp/mpu_isapnp.c done
+dev/pad/pad.c done
+dev/pci/auacer.c done
+dev/pci/auich.c done port-amd64
+dev/pci/auixp.c done
+dev/pci/autri.c done port-sparc64
+dev/pci/auvia.c done
+dev/pci/azalia.c done port-i386
+dev/pci/cmpci.c done
+dev/pci/cs4280.c done port-i386
+dev/pci/cs4281.c done
+dev/pci/eap.c done port-i386
+dev/pci/emuxki.c done port-amd64
+dev/pci/esa.c done
+dev/pci/esm.c done
+dev/pci/eso.c done
+dev/pci/fms.c done
+dev/pci/gcscaudio.c done
+dev/pci/neo.c done
+dev/pci/sv.c done
+dev/pci/yds.c done
+dev/pci/hdaudio/hdafg.c done port-i386, port-amd64
+dev/sbus/cs4231_sbus.c done port-sparc, port-sparc64
+dev/sbus/dbri.c done port-sparc
+dev/tc/bba.c done
+dev/usb/uaudio.c done port-amd64
+dev/usb/umidi.c
diff --git a/sys/dev/acpi/joy_acpi.c b/sys/dev/acpi/joy_acpi.c
index 5ad6cf6203d..eb0f9e6598f 100644
--- a/sys/dev/acpi/joy_acpi.c
+++ b/sys/dev/acpi/joy_acpi.c
@@ -1,4 +1,4 @@
-/* $NetBSD: joy_acpi.c,v 1.10 2010/03/05 14:00:17 jruoho Exp $ */
+/* $NetBSD: joy_acpi.c,v 1.11 2011/11/23 23:07:31 jmcneill Exp $ */
/*
* Copyright (c) 2002 Jared D. McNeill <jmcneill@invisible.ca>
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: joy_acpi.c,v 1.10 2010/03/05 14:00:17 jruoho Exp $");
+__KERNEL_RCSID(0, "$NetBSD: joy_acpi.c,v 1.11 2011/11/23 23:07:31 jmcneill Exp $");
#include <sys/param.h>
#include <sys/device.h>
@@ -45,6 +45,7 @@ static void joy_acpi_attach(device_t, device_t, void *);
struct joy_acpi_softc {
struct joy_softc sc_joy;
+ kmutex_t sc_lock;
};
CFATTACH_DECL_NEW(joy_acpi, sizeof(struct joy_acpi_softc), joy_acpi_match,
@@ -109,6 +110,9 @@ joy_acpi_attach(device_t parent, device_t self, void *aux)
goto out;
}
+ mutex_init(&asc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ sc->sc_lock = &asc->sc_lock;
+
joyattach(sc);
out:
diff --git a/sys/dev/acpi/mpu_acpi.c b/sys/dev/acpi/mpu_acpi.c
index b31d9068c71..83e89f2bbb6 100644
--- a/sys/dev/acpi/mpu_acpi.c
+++ b/sys/dev/acpi/mpu_acpi.c
@@ -1,4 +1,4 @@
-/* $NetBSD: mpu_acpi.c,v 1.10 2010/03/05 14:00:17 jruoho Exp $ */
+/* $NetBSD: mpu_acpi.c,v 1.11 2011/11/23 23:07:31 jmcneill Exp $ */
/*
* Copyright (c) 2002 Jared D. McNeill <jmcneill@invisible.ca>
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mpu_acpi.c,v 1.10 2010/03/05 14:00:17 jruoho Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mpu_acpi.c,v 1.11 2011/11/23 23:07:31 jmcneill Exp $");
#include <sys/param.h>
#include <sys/device.h>
@@ -122,7 +122,7 @@ mpu_acpi_attach(device_t parent, device_t self, void *aux)
sc->arg = isa_intr_establish(aa->aa_ic, irq->ar_irq,
(irq->ar_type == ACPI_EDGE_SENSITIVE) ? IST_EDGE : IST_LEVEL,
- IPL_AUDIO, mpu_intr, sc);
+ IPL_SCHED, mpu_intr, sc);
out:
acpi_resource_cleanup(&res);
diff --git a/sys/dev/auconv.c b/sys/dev/auconv.c
index 1cdfa440395..9300eb76e6c 100644
--- a/sys/dev/auconv.c
+++ b/sys/dev/auconv.c
@@ -1,4 +1,4 @@
-/* $NetBSD: auconv.c,v 1.24 2011/09/07 00:11:58 jmcneill Exp $ */
+/* $NetBSD: auconv.c,v 1.25 2011/11/23 23:07:31 jmcneill Exp $ */
/*
* Copyright (c) 1996 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: auconv.c,v 1.24 2011/09/07 00:11:58 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: auconv.c,v 1.25 2011/11/23 23:07:31 jmcneill Exp $");
#include <sys/types.h>
#include <sys/audioio.h>
@@ -224,7 +224,8 @@ stream_filter_set_inputbuffer(stream_filter_t *this, audio_stream_t *stream)
stream_filter_t *
auconv_nocontext_filter_factory(
- int (*fetch_to)(stream_fetcher_t *, audio_stream_t *, int))
+ int (*fetch_to)(struct audio_softc *, stream_fetcher_t *,
+ audio_stream_t *, int))
{
stream_filter_t *this;
@@ -249,7 +250,7 @@ auconv_nocontext_filter_dtor(struct stream_filter *this)
#define DEFINE_FILTER(name) \
static int \
-name##_fetch_to(stream_fetcher_t *, audio_stream_t *, int); \
+name##_fetch_to(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int); \
stream_filter_t * \
name(struct audio_softc *sc, const audio_params_t *from, \
const audio_params_t *to) \
@@ -257,7 +258,8 @@ name(struct audio_softc *sc, const audio_params_t *from, \
return auconv_nocontext_filter_factory(name##_fetch_to); \
} \
static int \
-name##_fetch_to(stream_fetcher_t *self, audio_stream_t *dst, int max_used)
+name##_fetch_to(struct audio_softc *sc, stream_fetcher_t *self, \
+ audio_stream_t *dst, int max_used)
DEFINE_FILTER(change_sign8)
{
@@ -265,7 +267,7 @@ DEFINE_FILTER(change_sign8)
int m, err;
this = (stream_filter_t *)self;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
return err;
m = dst->end - dst->start;
m = min(m, max_used);
@@ -282,7 +284,7 @@ DEFINE_FILTER(change_sign16)
this = (stream_filter_t *)self;
max_used = (max_used + 1) & ~1; /* round up to even */
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
return err;
m = (dst->end - dst->start) & ~1;
m = min(m, max_used);
@@ -309,7 +311,7 @@ DEFINE_FILTER(swap_bytes)
this = (stream_filter_t *)self;
max_used = (max_used + 1) & ~1; /* round up to even */
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
return err;
m = (dst->end - dst->start) & ~1;
m = min(m, max_used);
@@ -327,7 +329,7 @@ DEFINE_FILTER(swap_bytes_change_sign16)
this = (stream_filter_t *)self;
max_used = (max_used + 1) & ~1; /* round up to even */
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
return err;
m = (dst->end - dst->start) & ~1;
m = min(m, max_used);
@@ -354,7 +356,7 @@ DEFINE_FILTER(linear8_to_linear16)
this = (stream_filter_t *)self;
max_used = (max_used + 1) & ~1; /* round up to even */
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used / 2)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used / 2)))
return err;
m = (dst->end - dst->start) & ~1;
m = min(m, max_used);
@@ -415,7 +417,7 @@ DEFINE_FILTER(linear16_to_linear8)
int m, err, enc_src, enc_dst;
this = (stream_filter_t *)self;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used * 2)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used * 2)))
return err;
m = dst->end - dst->start;
m = min(m, max_used);
diff --git a/sys/dev/auconv.h b/sys/dev/auconv.h
index ba8d7eb9213..bb76d58953e 100644
--- a/sys/dev/auconv.h
+++ b/sys/dev/auconv.h
@@ -1,4 +1,4 @@
-/* $NetBSD: auconv.h,v 1.15 2008/04/28 20:23:46 martin Exp $ */
+/* $NetBSD: auconv.h,v 1.16 2011/11/23 23:07:31 jmcneill Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
extern void stream_filter_set_fetcher(stream_filter_t *, stream_fetcher_t *);
extern void stream_filter_set_inputbuffer(stream_filter_t *, audio_stream_t *);
extern stream_filter_t *auconv_nocontext_filter_factory
- (int (*)(stream_fetcher_t *, audio_stream_t *, int));
+ (int (*)(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int));
extern void auconv_nocontext_filter_dtor(struct stream_filter *);
#define FILTER_LOOP_PROLOGUE(SRC, SRCFRAME, DST, DSTFRAME, MAXUSED) \
do { \
diff --git a/sys/dev/audio.c b/sys/dev/audio.c
index d7a2b20d00e..4ad96aabf8d 100644
--- a/sys/dev/audio.c
+++ b/sys/dev/audio.c
@@ -1,4 +1,33 @@
-/* $NetBSD: audio.c,v 1.253 2011/09/06 01:16:44 jmcneill Exp $ */
+/* $NetBSD: audio.c,v 1.254 2011/11/23 23:07:31 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Doran.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
/*
* Copyright (c) 1991-1993 Regents of the University of California.
@@ -55,13 +84,78 @@
*/
/*
- * Todo:
- * - Add softaudio() isr processing for wakeup, poll, signals,
- * and silence fill.
+ * Locking: there are three locks.
+ *
+ * - sc_lock, provided by the underlying driver. This is an adaptive lock,
+ * returned in the second parameter to hw_if->get_locks(). It is known
+ * as the "thread lock".
+ *
+ * It serializes access to state in all places except the
+ * driver's interrupt service routine. This lock is taken from process
+ * context (example: access to /dev/audio). It is also taken from soft
+ * interrupt handlers in this module, primarily to serialize delivery of
+ * wakeups. This lock may be used/provided by modules external to the
+ * audio subsystem, so take care not to introduce a lock order problem.
+ * LONG TERM SLEEPS MUST NOT OCCUR WITH THIS LOCK HELD.
+ *
+ * - sc_intr_lock, provided by the underlying driver. This may be either a
+ * spinlock (at IPL_SCHED or IPL_VM) or an adaptive lock (IPL_NONE),
+ * returned in the first parameter to hw_if->get_locks(). It is known as
+ * the "interrupt lock".
+ *
+ * It provides atomic access to the device's hardware state, and to audio
+ * channel data that may be accessed by the hardware driver's ISR.
+ * In all places outside the ISR, sc_lock must be held before taking
+ * sc_intr_lock. This is to ensure that groups of hardware operations are
+ * made atomically. SLEEPS CANNOT OCCUR WITH THIS LOCK HELD.
+ *
+ * - sc_dvlock, private to this module. This is a custom reader/writer lock
+ * built on sc_lock and a condition variable. Some operations release
+ * sc_lock in order to allocate memory, to wait for in-flight I/O to
+ * complete, to copy to/from user context, etc. sc_dvlock serializes
+ * changes to filters and audio device settings while a read/write to the
+ * hardware is in progress. A write lock is taken only under exceptional
+ * circumstances, for example when opening /dev/audio or changing audio
+ * parameters. Long term sleeps and copy to/from user space may be done
+ * with this lock held.
+ *
+ * List of hardware interface methods, and which locks are held when each
+ * is called by this module:
+ *
+ * METHOD INTR THREAD NOTES
+ * ----------------------- ------- ------- -------------------------
+ * open x x
+ * close x x
+ * drain x x
+ * query_encoding - x
+ * set_params - x
+ * round_blocksize - x
+ * commit_settings - x
+ * init_output x x
+ * init_input x x
+ * start_output x x
+ * start_input x x
+ * halt_output x x
+ * halt_input x x
+ * speaker_ctl x x
+ * getdev - x
+ * setfd - x
+ * set_port - x
+ * get_port - x
+ * query_devinfo - x
+ * allocm - - Called at attach time
+ * freem - - Called at attach time
+ * round_buffersize - x
+ * mappage - - Mem. unchanged after attach
+ * get_props - x
+ * trigger_output x x
+ * trigger_input x x
+ * dev_ioctl - x
+ * get_locks - - Called at attach time
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.253 2011/09/06 01:16:44 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.254 2011/11/23 23:07:31 jmcneill Exp $");
#include "audio.h"
#if NAUDIO > 0
@@ -72,6 +166,7 @@ __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.253 2011/09/06 01:16:44 jmcneill Exp $")
#include <sys/vnode.h>
#include <sys/select.h>
#include <sys/poll.h>
+#include <sys/kmem.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/systm.h>
@@ -82,6 +177,7 @@ __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.253 2011/09/06 01:16:44 jmcneill Exp $")
#include <sys/audioio.h>
#include <sys/device.h>
#include <sys/intr.h>
+#include <sys/cpu.h>
#include <dev/audio_if.h>
#include <dev/audiovar.h>
@@ -124,7 +220,7 @@ paddr_t audio_mmap(struct audio_softc *, off_t, int);
int mixer_open(dev_t, struct audio_softc *, int, int, struct lwp *);
int mixer_close(struct audio_softc *, int, int, struct lwp *);
int mixer_ioctl(struct audio_softc *, u_long, void *, int, struct lwp *);
-static void mixer_remove(struct audio_softc *, struct lwp *);
+static void mixer_remove(struct audio_softc *);
static void mixer_signal(struct audio_softc *);
void audio_init_record(struct audio_softc *);
@@ -143,9 +239,6 @@ void audio_init_ringbuffer(struct audio_softc *,
struct audio_ringbuffer *, int);
int audio_initbufs(struct audio_softc *);
void audio_calcwater(struct audio_softc *);
-static inline int audio_sleep_timo(int *, const char *, int);
-static inline int audio_sleep(int *, const char *);
-static inline void audio_wakeup(int *);
int audio_drain(struct audio_softc *);
void audio_clear(struct audio_softc *);
static inline void audio_pint_silence
@@ -158,8 +251,6 @@ static int audio_setup_pfilters(struct audio_softc *, const audio_params_t *,
stream_filter_list_t *);
static int audio_setup_rfilters(struct audio_softc *, const audio_params_t *,
stream_filter_list_t *);
-static void audio_destruct_pfilters(struct audio_softc *);
-static void audio_destruct_rfilters(struct audio_softc *);
static void audio_stream_dtor(audio_stream_t *);
static int audio_stream_ctor(audio_stream_t *, const audio_params_t *, int);
static void stream_filter_list_append
@@ -199,6 +290,10 @@ static bool audio_can_capture(struct audio_softc *);
static void audio_softintr_rd(void *);
static void audio_softintr_wr(void *);
+static int audio_enter(dev_t, krw_t, struct audio_softc **);
+static void audio_exit(struct audio_softc *);
+static int audio_waitio(struct audio_softc *, kcondvar_t *);
+
struct portname {
const char *name;
int mask;
@@ -238,9 +333,9 @@ typedef struct uio_fetcher {
} uio_fetcher_t;
static void uio_fetcher_ctor(uio_fetcher_t *, struct uio *, int);
-static int uio_fetcher_fetch_to(stream_fetcher_t *,
+static int uio_fetcher_fetch_to(struct audio_softc *, stream_fetcher_t *,
audio_stream_t *, int);
-static int null_fetcher_fetch_to(stream_fetcher_t *,
+static int null_fetcher_fetch_to(struct audio_softc *, stream_fetcher_t *,
audio_stream_t *, int);
dev_type_open(audioopen);
@@ -254,7 +349,7 @@ dev_type_kqfilter(audiokqfilter);
const struct cdevsw audio_cdevsw = {
audioopen, audioclose, audioread, audiowrite, audioioctl,
- nostop, notty, audiopoll, audiommap, audiokqfilter, D_OTHER
+ nostop, notty, audiopoll, audiommap, audiokqfilter, D_OTHER | D_MPSAFE
};
/* The default audio mode: 8 kHz mono mu-law */
@@ -300,9 +395,20 @@ audioattach(device_t parent, device_t self, void *aux)
sa = aux;
hwp = sa->hwif;
hdlp = sa->hdl;
+
+ cv_init(&sc->sc_rchan, "audiord");
+ cv_init(&sc->sc_wchan, "audiowr");
+ cv_init(&sc->sc_lchan, "audiolk");
+
+ if (hwp == 0 || hwp->get_locks == 0) {
+ printf(": missing method\n");
+ panic("audioattach");
+ }
+
+ hwp->get_locks(hdlp, &sc->sc_intr_lock, &sc->sc_lock);
+
#ifdef DIAGNOSTIC
- if (hwp == 0 ||
- hwp->query_encoding == 0 ||
+ if (hwp->query_encoding == 0 ||
hwp->set_params == 0 ||
(hwp->start_output == 0 && hwp->trigger_output == 0) ||
(hwp->start_input == 0 && hwp->trigger_input == 0) ||
@@ -322,11 +428,11 @@ audioattach(device_t parent, device_t self, void *aux)
sc->hw_if = hwp;
sc->hw_hdl = hdlp;
sc->sc_dev = parent;
- sc->sc_opencnt = 0;
- sc->sc_writing = sc->sc_waitcomp = 0;
sc->sc_lastinfovalid = false;
+ mutex_enter(sc->sc_lock);
props = audio_get_props(sc);
+ mutex_exit(sc->sc_lock);
if (props & AUDIO_PROP_FULLDUPLEX)
aprint_normal(": full duplex");
@@ -345,6 +451,14 @@ audioattach(device_t parent, device_t self, void *aux)
aprint_naive("\n");
aprint_normal("\n");
+ /*
+ * XXX Would like to not hold the sc_lock around this whole block
+ * escpially for audio_alloc_ring(), except that the latter calls
+ * ->round_blocksize() which demands the thread lock to be taken.
+ *
+ * Revisit.
+ */
+ mutex_enter(sc->sc_lock);
if (audio_can_playback(sc)) {
error = audio_alloc_ring(sc, &sc->sc_pr,
AUMODE_PLAY, AU_RING_SIZE);
@@ -368,15 +482,17 @@ audioattach(device_t parent, device_t self, void *aux)
sc->sc_lastgain = 128;
- if ((error = audio_set_defaults(sc, 0))) {
+ error = audio_set_defaults(sc, 0);
+ mutex_exit(sc->sc_lock);
+ if (error != 0) {
aprint_error("audioattach: audio_set_defaults() failed\n");
sc->hw_if = NULL;
return;
}
- sc->sc_sih_rd = softint_establish(SOFTINT_SERIAL,
+ sc->sc_sih_rd = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE,
audio_softintr_rd, sc);
- sc->sc_sih_wr = softint_establish(SOFTINT_SERIAL,
+ sc->sc_sih_wr = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE,
audio_softintr_wr, sc);
iclass = mclass = oclass = rclass = -1;
@@ -402,6 +518,7 @@ audioattach(device_t parent, device_t self, void *aux)
* names from the mixer descriptions. We'll need them to decode the
* mixer descriptions on the next pass through the loop.
*/
+ mutex_enter(sc->sc_lock);
for(mi.index = 0; ; mi.index++) {
if (hwp->query_devinfo(hdlp, &mi) != 0)
break;
@@ -420,6 +537,13 @@ audioattach(device_t parent, device_t self, void *aux)
rclass = mi.mixer_class;
}
}
+ mutex_exit(sc->sc_lock);
+
+ /* Allocate save area. Ensure non-zero allocation. */
+ sc->sc_nmixer_states = mi.index;
+ sc->sc_mixer_state = kmem_alloc(sizeof(mixer_ctrl_t) *
+ sc->sc_nmixer_states + 1, KM_SLEEP);
+
/*
* This is where we assign each control in the "audio" model, to the
* underlying "mixer" control. We walk through the whole list once,
@@ -427,9 +551,11 @@ audioattach(device_t parent, device_t self, void *aux)
*/
record_master_found = 0;
record_source_found = 0;
+ mutex_enter(sc->sc_lock);
for(mi.index = 0; ; mi.index++) {
if (hwp->query_devinfo(hdlp, &mi) != 0)
break;
+ KASSERT(mi.index < sc->sc_nmixer_states);
if (mi.type == AUDIO_MIXER_CLASS)
continue;
if (mi.mixer_class == iclass) {
@@ -500,6 +626,7 @@ audioattach(device_t parent, device_t self, void *aux)
}
}
}
+ mutex_exit(sc->sc_lock);
DPRINTF(("audio_attach: inputs ports=0x%x, input master=%d, "
"output ports=0x%x, output master=%d\n",
sc->sc_inports.allports, sc->sc_inports.master,
@@ -542,7 +669,9 @@ audioactivate(device_t self, enum devact act)
switch (act) {
case DVACT_DEACTIVATE:
+ mutex_enter(sc->sc_lock);
sc->sc_dying = true;
+ mutex_exit(sc->sc_lock);
return 0;
default:
return EOPNOTSUPP;
@@ -553,13 +682,34 @@ int
audiodetach(device_t self, int flags)
{
struct audio_softc *sc;
- int maj, mn;
- int s;
+ int maj, mn, i;
sc = device_private(self);
DPRINTF(("audio_detach: sc=%p flags=%d\n", sc, flags));
+ /* Start draining existing accessors of the device. */
+ mutex_enter(sc->sc_lock);
sc->sc_dying = true;
+ cv_broadcast(&sc->sc_wchan);
+ cv_broadcast(&sc->sc_rchan);
+ mutex_exit(sc->sc_lock);
+
+ /* locate the major number */
+ maj = cdevsw_lookup_major(&audio_cdevsw);
+
+ /*
+ * Nuke the vnodes for any open instances (calls close).
+ * Will wait until any activity on the device nodes has ceased.
+ *
+ * XXXAD NOT YET.
+ *
+ * XXXAD NEED TO PREVENT NEW REFERENCES THROUGH AUDIO_ENTER().
+ */
+ mn = device_unit(self);
+ vdevgone(maj, mn | SOUND_DEVICE, mn | SOUND_DEVICE, VCHR);
+ vdevgone(maj, mn | AUDIO_DEVICE, mn | AUDIO_DEVICE, VCHR);
+ vdevgone(maj, mn | AUDIOCTL_DEVICE, mn | AUDIOCTL_DEVICE, VCHR);
+ vdevgone(maj, mn | MIXER_DEVICE, mn | MIXER_DEVICE, VCHR);
pmf_event_deregister(self, PMFE_AUDIO_VOLUME_DOWN,
audio_volume_down, true);
@@ -569,38 +719,28 @@ audiodetach(device_t self, int flags)
audio_volume_toggle, true);
#ifdef AUDIO_PM_IDLE
- callout_stop(&sc->sc_idle_counter);
+ callout_halt(&sc->sc_idle_counter, sc->sc_lock);
device_active_deregister(self, audio_activity);
#endif
pmf_device_deregister(self);
- wakeup(&sc->sc_wchan);
- wakeup(&sc->sc_rchan);
- s = splaudio();
- if (--sc->sc_refcnt >= 0) {
- if (tsleep(&sc->sc_refcnt, PZERO, "auddet", hz * 120))
- printf("audiodetach: %s didn't detach\n",
- device_xname(sc->dev));
- }
- splx(s);
-
/* free resources */
audio_free_ring(sc, &sc->sc_pr);
audio_free_ring(sc, &sc->sc_rr);
- audio_destruct_pfilters(sc);
- audio_destruct_rfilters(sc);
-
- /* locate the major number */
- maj = cdevsw_lookup_major(&audio_cdevsw);
-
- /* Nuke the vnodes for any open instances (calls close). */
- mn = device_unit(self);
- vdevgone(maj, mn | SOUND_DEVICE, mn | SOUND_DEVICE, VCHR);
- vdevgone(maj, mn | AUDIO_DEVICE, mn | AUDIO_DEVICE, VCHR);
- vdevgone(maj, mn | AUDIOCTL_DEVICE, mn | AUDIOCTL_DEVICE, VCHR);
- vdevgone(maj, mn | MIXER_DEVICE, mn | MIXER_DEVICE, VCHR);
+ for (i = 0; i < sc->sc_nrfilters; i++) {
+ sc->sc_rfilters[i]->dtor(sc->sc_rfilters[i]);
+ sc->sc_rfilters[i] = NULL;
+ audio_stream_dtor(&sc->sc_rstreams[i]);
+ }
+ sc->sc_nrfilters = 0;
+ for (i = 0; i < sc->sc_npfilters; i++) {
+ sc->sc_pfilters[i]->dtor(sc->sc_pfilters[i]);
+ sc->sc_pfilters[i] = NULL;
+ audio_stream_dtor(&sc->sc_pstreams[i]);
+ }
+ sc->sc_npfilters = 0;
if (sc->sc_sih_rd) {
softint_disestablish(sc->sc_sih_rd);
@@ -617,6 +757,10 @@ audiodetach(device_t self, int flags)
seldestroy(&sc->sc_rsel);
seldestroy(&sc->sc_wsel);
+ cv_destroy(&sc->sc_rchan);
+ cv_destroy(&sc->sc_wchan);
+ cv_destroy(&sc->sc_lchan);
+
return 0;
}
@@ -705,7 +849,8 @@ audio_printsc(struct audio_softc *sc)
{
printf("hwhandle %p hw_if %p ", sc->hw_hdl, sc->hw_if);
printf("open 0x%x mode 0x%x\n", sc->sc_open, sc->sc_mode);
- printf("rchan 0x%x wchan 0x%x ", sc->sc_rchan, sc->sc_wchan);
+ printf("rchan 0x%x wchan 0x%x ", cv_has_waiters(&sc->sc_rchan),
+ cv_has_waiters(&sc->sc_wchan));
printf("rring used 0x%x pring used=%d\n",
audio_stream_get_used(&sc->sc_rr.s),
audio_stream_get_used(&sc->sc_pr.s));
@@ -740,10 +885,9 @@ audio_alloc_ring(struct audio_softc *sc, struct audio_ringbuffer *r,
if (hw->round_buffersize)
bufsize = hw->round_buffersize(hdl, direction, bufsize);
if (hw->allocm)
- r->s.start = hw->allocm(hdl, direction, bufsize,
- M_DEVBUF, M_WAITOK);
+ r->s.start = hw->allocm(hdl, direction, bufsize);
else
- r->s.start = malloc(bufsize, M_DEVBUF, M_WAITOK);
+ r->s.start = kmem_alloc(bufsize, KM_SLEEP);
if (r->s.start == 0)
return ENOMEM;
r->s.bufsize = bufsize;
@@ -757,9 +901,9 @@ audio_free_ring(struct audio_softc *sc, struct audio_ringbuffer *r)
return;
if (sc->hw_if->freem)
- sc->hw_if->freem(sc->hw_hdl, r->s.start, M_DEVBUF);
+ sc->hw_if->freem(sc->hw_hdl, r->s.start, r->s.bufsize);
else
- free(r->s.start, M_DEVBUF);
+ kmem_free(r->s.start, r->s.bufsize);
r->s.start = 0;
}
@@ -767,17 +911,16 @@ static int
audio_setup_pfilters(struct audio_softc *sc, const audio_params_t *pp,
stream_filter_list_t *pfilters)
{
- stream_filter_t *pf[AUDIO_MAX_FILTERS];
- audio_stream_t ps[AUDIO_MAX_FILTERS];
+ stream_filter_t *pf[AUDIO_MAX_FILTERS], *of[AUDIO_MAX_FILTERS];
+ audio_stream_t ps[AUDIO_MAX_FILTERS], os[AUDIO_MAX_FILTERS];
const audio_params_t *from_param;
audio_params_t *to_param;
- int i, n;
+ int i, n, onfilters;
- while (sc->sc_writing) {
- sc->sc_waitcomp = 1;
- (void)tsleep(sc, 0, "audioch", 10*hz);
- }
+ KASSERT(mutex_owned(sc->sc_lock));
+ /* Construct new filters. */
+ mutex_exit(sc->sc_lock);
memset(pf, 0, sizeof(pf));
memset(ps, 0, sizeof(ps));
from_param = pp;
@@ -801,18 +944,22 @@ audio_setup_pfilters(struct audio_softc *sc, const audio_params_t *pp,
pf[i]->dtor(pf[i]);
audio_stream_dtor(&ps[i]);
}
- sc->sc_waitcomp = 0;
+ mutex_enter(sc->sc_lock);
return EINVAL;
}
+ mutex_enter(sc->sc_lock);
- audio_destruct_pfilters(sc);
+ /* Swap in new filters. */
+ mutex_enter(sc->sc_intr_lock);
+ memcpy(of, sc->sc_pfilters, sizeof(of));
+ memcpy(os, sc->sc_pstreams, sizeof(os));
+ onfilters = sc->sc_npfilters;
memcpy(sc->sc_pfilters, pf, sizeof(pf));
memcpy(sc->sc_pstreams, ps, sizeof(ps));
sc->sc_npfilters = pfilters->req_size;
for (i = 0; i < pfilters->req_size; i++) {
pf[i]->set_inputbuffer(pf[i], &sc->sc_pstreams[i]);
}
-
/* hardware format and the buffer near to userland */
if (pfilters->req_size <= 0) {
sc->sc_pr.s.param = *pp;
@@ -821,6 +968,16 @@ audio_setup_pfilters(struct audio_softc *sc, const audio_params_t *pp,
sc->sc_pr.s.param = pfilters->filters[0].param;
sc->sc_pustream = &sc->sc_pstreams[0];
}
+ mutex_exit(sc->sc_intr_lock);
+
+ /* Destroy old filters. */
+ mutex_exit(sc->sc_lock);
+ for (i = 0; i < onfilters; i++) {
+ of[i]->dtor(of[i]);
+ audio_stream_dtor(&os[i]);
+ }
+ mutex_enter(sc->sc_lock);
+
#ifdef AUDIO_DEBUG
printf("%s: HW-buffer=%p pustream=%p\n",
__func__, &sc->sc_pr.s, sc->sc_pustream);
@@ -832,7 +989,6 @@ audio_setup_pfilters(struct audio_softc *sc, const audio_params_t *pp,
audio_print_params("[HW]", &sc->sc_pr.s.param);
#endif /* AUDIO_DEBUG */
- sc->sc_waitcomp = 0;
return 0;
}
@@ -840,12 +996,16 @@ static int
audio_setup_rfilters(struct audio_softc *sc, const audio_params_t *rp,
stream_filter_list_t *rfilters)
{
- stream_filter_t *rf[AUDIO_MAX_FILTERS];
- audio_stream_t rs[AUDIO_MAX_FILTERS];
+ stream_filter_t *rf[AUDIO_MAX_FILTERS], *of[AUDIO_MAX_FILTERS];
+ audio_stream_t rs[AUDIO_MAX_FILTERS], os[AUDIO_MAX_FILTERS];
const audio_params_t *to_param;
audio_params_t *from_param;
- int i;
+ int i, onfilters;
+ KASSERT(mutex_owned(sc->sc_lock));
+
+ /* Construct new filters. */
+ mutex_exit(sc->sc_lock);
memset(rf, 0, sizeof(rf));
memset(rs, 0, sizeof(rs));
for (i = 0; i < rfilters->req_size; i++) {
@@ -874,17 +1034,22 @@ audio_setup_rfilters(struct audio_softc *sc, const audio_params_t *rp,
rf[i]->dtor(rf[i]);
audio_stream_dtor(&rs[i]);
}
+ mutex_enter(sc->sc_lock);
return EINVAL;
}
+ mutex_enter(sc->sc_lock);
- audio_destruct_rfilters(sc);
+ /* Swap in new filters. */
+ mutex_enter(sc->sc_intr_lock);
+ memcpy(of, sc->sc_rfilters, sizeof(of));
+ memcpy(os, sc->sc_rstreams, sizeof(os));
+ onfilters = sc->sc_nrfilters;
memcpy(sc->sc_rfilters, rf, sizeof(rf));
memcpy(sc->sc_rstreams, rs, sizeof(rs));
sc->sc_nrfilters = rfilters->req_size;
for (i = 1; i < rfilters->req_size; i++) {
rf[i]->set_inputbuffer(rf[i], &sc->sc_rstreams[i - 1]);
}
-
/* hardware format and the buffer near to userland */
if (rfilters->req_size <= 0) {
sc->sc_rr.s.param = *rp;
@@ -893,6 +1058,8 @@ audio_setup_rfilters(struct audio_softc *sc, const audio_params_t *rp,
sc->sc_rr.s.param = rfilters->filters[0].param;
sc->sc_rustream = &sc->sc_rstreams[rfilters->req_size - 1];
}
+ mutex_exit(sc->sc_intr_lock);
+
#ifdef AUDIO_DEBUG
printf("%s: HW-buffer=%p pustream=%p\n",
__func__, &sc->sc_rr.s, sc->sc_rustream);
@@ -903,33 +1070,16 @@ audio_setup_rfilters(struct audio_softc *sc, const audio_params_t *rp,
audio_print_params(num, &sc->sc_rstreams[i].param);
}
#endif /* AUDIO_DEBUG */
- return 0;
-}
-static void
-audio_destruct_pfilters(struct audio_softc *sc)
-{
- int i;
-
- for (i = 0; i < sc->sc_npfilters; i++) {
- sc->sc_pfilters[i]->dtor(sc->sc_pfilters[i]);
- sc->sc_pfilters[i] = NULL;
- audio_stream_dtor(&sc->sc_pstreams[i]);
+ /* Destroy old filters. */
+ mutex_exit(sc->sc_lock);
+ for (i = 0; i < onfilters; i++) {
+ of[i]->dtor(of[i]);
+ audio_stream_dtor(&os[i]);
}
- sc->sc_npfilters = 0;
-}
-
-static void
-audio_destruct_rfilters(struct audio_softc *sc)
-{
- int i;
+ mutex_enter(sc->sc_lock);
- for (i = 0; i < sc->sc_nrfilters; i++) {
- sc->sc_rfilters[i]->dtor(sc->sc_rfilters[i]);
- sc->sc_rfilters[i] = NULL;
- audio_stream_dtor(&sc->sc_rstreams[i]);
- }
- sc->sc_nrfilters = 0;
+ return 0;
}
static void
@@ -937,7 +1087,7 @@ audio_stream_dtor(audio_stream_t *stream)
{
if (stream->start != NULL)
- free(stream->start, M_DEVBUF);
+ kmem_free(stream->start, stream->bufsize);
memset(stream, 0, sizeof(audio_stream_t));
}
@@ -948,7 +1098,7 @@ audio_stream_ctor(audio_stream_t *stream, const audio_params_t *param, int size)
size = min(size, AU_RING_SIZE);
stream->bufsize = size;
- stream->start = malloc(size, M_DEVBUF, M_NOWAIT);
+ stream->start = kmem_alloc(size, KM_SLEEP);
if (stream->start == NULL)
return ENOMEM;
frame_size = (param->precision + 7) / 8 * param->channels;
@@ -1013,24 +1163,116 @@ stream_filter_list_prepend(stream_filter_list_t *list,
list->req_size++;
}
-int
-audioopen(dev_t dev, int flags, int ifmt, struct lwp *l)
+/*
+ * Look up audio device and acquire locks for device access.
+ */
+static int
+audio_enter(dev_t dev, krw_t rw, struct audio_softc **scp)
{
struct audio_softc *sc;
- int error;
+ /* First, find the device and take sc_lock. */
sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
if (sc == NULL)
return ENXIO;
-
- if (sc->sc_dying)
+ mutex_enter(sc->sc_lock);
+ if (sc->sc_dying) {
+ mutex_exit(sc->sc_lock);
return EIO;
+ }
- device_active(sc->dev, DVA_SYSTEM);
+ /* Acquire device access lock. */
+ switch (rw) {
+ case RW_WRITER:
+ while (__predict_false(sc->sc_dvlock != 0)) {
+ cv_wait(&sc->sc_lchan, sc->sc_lock);
+ }
+ sc->sc_dvlock = -1;
+ break;
+ case RW_READER:
+ while (__predict_false(sc->sc_dvlock < 0)) {
+ cv_wait(&sc->sc_lchan, sc->sc_lock);
+ }
+ sc->sc_dvlock++;
+ break;
+ default:
+ panic("audio_enter");
+ }
+
+ *scp = sc;
+ return 0;
+}
+
+/*
+ * Release reference to device acquired with audio_enter().
+ */
+static void
+audio_exit(struct audio_softc *sc)
+{
- sc->sc_opencnt++;
+ KASSERT(mutex_owned(sc->sc_lock));
+ KASSERT(sc->sc_dvlock != 0);
- sc->sc_refcnt++;
+ /* Release device level lock. */
+ if (__predict_false(sc->sc_dvlock < 0)) {
+ sc->sc_dvlock = 0;
+ } else {
+ sc->sc_dvlock--;
+ }
+ cv_broadcast(&sc->sc_lchan);
+ mutex_exit(sc->sc_lock);
+}
+
+/*
+ * Wait for I/O to complete, releasing device lock.
+ */
+static int
+audio_waitio(struct audio_softc *sc, kcondvar_t *chan)
+{
+ int error;
+ krw_t rw;
+
+ KASSERT(mutex_owned(sc->sc_lock));
+
+ /* Release device level lock while sleeping. */
+ if (__predict_false(sc->sc_dvlock < 0)) {
+ sc->sc_dvlock = 0;
+ rw = RW_WRITER;
+ } else {
+ KASSERT(sc->sc_dvlock > 0);
+ sc->sc_dvlock--;
+ rw = RW_READER;
+ }
+ cv_broadcast(&sc->sc_lchan);
+
+ /* Wait for pending I/O to complete. */
+ error = cv_wait_sig(chan, sc->sc_lock);
+
+ /* Re-acquire device level lock. */
+ if (__predict_false(rw == RW_WRITER)) {
+ while (__predict_false(sc->sc_dvlock != 0)) {
+ cv_wait(&sc->sc_lchan, sc->sc_lock);
+ }
+ sc->sc_dvlock = -1;
+ } else {
+ while (__predict_false(sc->sc_dvlock < 0)) {
+ cv_wait(&sc->sc_lchan, sc->sc_lock);
+ }
+ sc->sc_dvlock++;
+ }
+
+ return error;
+}
+
+int
+audioopen(dev_t dev, int flags, int ifmt, struct lwp *l)
+{
+ struct audio_softc *sc;
+ int error;
+
+ if ((error = audio_enter(dev, RW_WRITER, &sc)) != 0)
+ return error;
+ device_active(sc->dev, DVA_SYSTEM);
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
@@ -1046,8 +1288,8 @@ audioopen(dev_t dev, int flags, int ifmt, struct lwp *l)
error = ENXIO;
break;
}
- if (--sc->sc_refcnt < 0)
- wakeup(&sc->sc_refcnt);
+ audio_exit(sc);
+
return error;
}
@@ -1057,10 +1299,9 @@ audioclose(dev_t dev, int flags, int ifmt, struct lwp *l)
struct audio_softc *sc;
int error;
- sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
-
+ if ((error = audio_enter(dev, RW_WRITER, &sc)) != 0)
+ return error;
device_active(sc->dev, DVA_SYSTEM);
-
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
@@ -1076,8 +1317,7 @@ audioclose(dev_t dev, int flags, int ifmt, struct lwp *l)
error = ENXIO;
break;
}
-
- sc->sc_opencnt--;
+ audio_exit(sc);
return error;
}
@@ -1088,14 +1328,8 @@ audioread(dev_t dev, struct uio *uio, int ioflag)
struct audio_softc *sc;
int error;
- sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
- if (sc == NULL)
- return ENXIO;
-
- if (sc->sc_dying)
- return EIO;
-
- sc->sc_refcnt++;
+ if ((error = audio_enter(dev, RW_READER, &sc)) != 0)
+ return error;
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
@@ -1109,8 +1343,8 @@ audioread(dev_t dev, struct uio *uio, int ioflag)
error = ENXIO;
break;
}
- if (--sc->sc_refcnt < 0)
- wakeup(&sc->sc_refcnt);
+ audio_exit(sc);
+
return error;
}
@@ -1120,14 +1354,8 @@ audiowrite(dev_t dev, struct uio *uio, int ioflag)
struct audio_softc *sc;
int error;
- sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
- if (sc == NULL)
- return ENXIO;
-
- if (sc->sc_dying)
- return EIO;
-
- sc->sc_refcnt++;
+ if ((error = audio_enter(dev, RW_READER, &sc)) != 0)
+ return error;
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
@@ -1141,8 +1369,8 @@ audiowrite(dev_t dev, struct uio *uio, int ioflag)
error = ENXIO;
break;
}
- if (--sc->sc_refcnt < 0)
- wakeup(&sc->sc_refcnt);
+ audio_exit(sc);
+
return error;
}
@@ -1151,12 +1379,23 @@ audioioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
{
struct audio_softc *sc;
int error;
+ krw_t rw;
- sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
- if (sc->sc_dying)
- return EIO;
+ /* Figure out which lock type we need. */
+ switch (cmd) {
+ case AUDIO_FLUSH:
+ case AUDIO_SETINFO:
+ case AUDIO_DRAIN:
+ case AUDIO_SETFD:
+ rw = RW_WRITER;
+ break;
+ default:
+ rw = RW_READER;
+ break;
+ }
- sc->sc_refcnt++;
+ if ((error = audio_enter(dev, rw, &sc)) != 0)
+ return error;
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
@@ -1174,8 +1413,8 @@ audioioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
error = ENXIO;
break;
}
- if (--sc->sc_refcnt < 0)
- wakeup(&sc->sc_refcnt);
+ audio_exit(sc);
+
return error;
}
@@ -1185,11 +1424,15 @@ audiopoll(dev_t dev, int events, struct lwp *l)
struct audio_softc *sc;
int revents;
- sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
- if (sc->sc_dying)
- return POLLHUP;
-
- sc->sc_refcnt++;
+ /* Don't bother with device level lock here. */
+ sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
+ if (sc == NULL)
+ return ENXIO;
+ mutex_enter(sc->sc_lock);
+ if (sc->sc_dying) {
+ mutex_exit(sc->sc_lock);
+ return EIO;
+ }
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
@@ -1203,8 +1446,8 @@ audiopoll(dev_t dev, int events, struct lwp *l)
revents = POLLERR;
break;
}
- if (--sc->sc_refcnt < 0)
- wakeup(&sc->sc_refcnt);
+ mutex_exit(sc->sc_lock);
+
return revents;
}
@@ -1214,11 +1457,15 @@ audiokqfilter(dev_t dev, struct knote *kn)
struct audio_softc *sc;
int rv;
+ /* Don't bother with device level lock here. */
sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
- if (sc->sc_dying)
- return 1;
-
- sc->sc_refcnt++;
+ if (sc == NULL)
+ return ENXIO;
+ mutex_enter(sc->sc_lock);
+ if (sc->sc_dying) {
+ mutex_exit(sc->sc_lock);
+ return EIO;
+ }
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
@@ -1231,8 +1478,8 @@ audiokqfilter(dev_t dev, struct knote *kn)
default:
rv = 1;
}
- if (--sc->sc_refcnt < 0)
- wakeup(&sc->sc_refcnt);
+ mutex_exit(sc->sc_lock);
+
return rv;
}
@@ -1242,13 +1489,15 @@ audiommap(dev_t dev, off_t off, int prot)
struct audio_softc *sc;
paddr_t error;
- sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
- if (sc->sc_dying)
- return -1;
-
+ /*
+ * Acquire a reader lock. audio_mmap() will drop sc_lock
+ * in order to allow the device's mmap routine to sleep.
+ * Although not yet possible, we want to prevent memory
+ * from being allocated or freed out from under us.
+ */
+ if ((error = audio_enter(dev, RW_READER, &sc)) != 0)
+ return 1;
device_active(sc->dev, DVA_SYSTEM); /* XXXJDM */
-
- sc->sc_refcnt++;
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
@@ -1262,8 +1511,7 @@ audiommap(dev_t dev, off_t off, int prot)
error = -1;
break;
}
- if (--sc->sc_refcnt < 0)
- wakeup(&sc->sc_refcnt);
+ audio_exit(sc);
return error;
}
@@ -1388,45 +1636,6 @@ audio_calcwater(struct audio_softc *sc)
}
}
-static inline int
-audio_sleep_timo(int *chan, const char *label, int timo)
-{
- int st;
-
- if (label == NULL)
- label = "audio";
-
- DPRINTFN(3, ("audio_sleep_timo: chan=%p, label=%s, timo=%d\n",
- chan, label, timo));
- *chan = 1;
- st = tsleep(chan, PWAIT | PCATCH, label, timo);
- *chan = 0;
-#ifdef AUDIO_DEBUG
- if (st != 0 && st != EINTR)
- DPRINTF(("audio_sleep: woke up st=%d\n", st));
-#endif
- return st;
-}
-
-static inline int
-audio_sleep(int *chan, const char *label)
-{
-
- return audio_sleep_timo(chan, label, 0);
-}
-
-/* call at splaudio() */
-static inline void
-audio_wakeup(int *chan)
-{
-
- DPRINTFN(3, ("audio_wakeup: chan=%p, *chan=%d\n", chan, *chan));
- if (*chan) {
- wakeup(chan);
- *chan = 0;
- }
-}
-
int
audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
struct lwp *l)
@@ -1435,6 +1644,8 @@ audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
u_int mode;
const struct audio_hw_if *hw;
+ KASSERT(mutex_owned(sc->sc_lock));
+
hw = sc->hw_if;
if (hw == NULL)
return ENXIO;
@@ -1447,23 +1658,25 @@ audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
return EBUSY;
if (hw->open != NULL) {
+ mutex_enter(sc->sc_intr_lock);
error = hw->open(sc->hw_hdl, flags);
+ mutex_exit(sc->sc_intr_lock);
if (error)
return error;
}
sc->sc_async_audio = 0;
- sc->sc_rchan = 0;
- sc->sc_wchan = 0;
sc->sc_sil_count = 0;
sc->sc_rbus = false;
sc->sc_pbus = false;
sc->sc_eof = 0;
sc->sc_playdrop = 0;
+ mutex_enter(sc->sc_intr_lock);
sc->sc_full_duplex =
(flags & (FWRITE|FREAD)) == (FWRITE|FREAD) &&
(audio_get_props(sc) & AUDIO_PROP_FULLDUPLEX);
+ mutex_exit(sc->sc_intr_lock);
mode = 0;
if (flags & FREAD) {
@@ -1512,10 +1725,12 @@ audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
return 0;
bad:
+ mutex_enter(sc->sc_intr_lock);
if (hw->close != NULL)
hw->close(sc->hw_hdl);
sc->sc_open = 0;
sc->sc_mode = 0;
+ mutex_exit(sc->sc_intr_lock);
sc->sc_full_duplex = 0;
return error;
}
@@ -1526,13 +1741,14 @@ bad:
void
audio_init_record(struct audio_softc *sc)
{
- int s;
- s = splaudio();
+ KASSERT(mutex_owned(sc->sc_lock));
+
+ mutex_enter(sc->sc_intr_lock);
if (sc->hw_if->speaker_ctl &&
(!sc->sc_full_duplex || (sc->sc_mode & AUMODE_PLAY) == 0))
sc->hw_if->speaker_ctl(sc->hw_hdl, SPKR_OFF);
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
}
/*
@@ -1541,13 +1757,14 @@ audio_init_record(struct audio_softc *sc)
void
audio_init_play(struct audio_softc *sc)
{
- int s;
- s = splaudio();
+ KASSERT(mutex_owned(sc->sc_lock));
+
+ mutex_enter(sc->sc_intr_lock);
sc->sc_wstamp = sc->sc_pr.stamp;
if (sc->hw_if->speaker_ctl)
sc->hw_if->speaker_ctl(sc->hw_hdl, SPKR_ON);
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
}
int
@@ -1555,19 +1772,19 @@ audio_drain(struct audio_softc *sc)
{
struct audio_ringbuffer *cb;
int error, drops;
- int s;
int i, used;
+ KASSERT(mutex_owned(sc->sc_lock));
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
DPRINTF(("audio_drain: enter busy=%d\n", sc->sc_pbus));
cb = &sc->sc_pr;
if (cb->mmapped)
return 0;
used = audio_stream_get_used(&sc->sc_pr.s);
- s = splaudio();
for (i = 0; i < sc->sc_npfilters; i++)
used += audio_stream_get_used(&sc->sc_pstreams[i]);
- splx(s);
if (used <= 0)
return 0;
@@ -1580,10 +1797,8 @@ audio_drain(struct audio_softc *sc)
cc = cb->blksize - (inp - cb->s.start) % cb->blksize;
audio_fill_silence(&cb->s.param, inp, cc);
- s = splaudio();
cb->s.inp = audio_stream_add_inp(&cb->s, inp, cc);
error = audiostartp(sc);
- splx(s);
if (error)
return error;
}
@@ -1601,20 +1816,15 @@ audio_drain(struct audio_softc *sc)
#endif
drops = cb->drops;
error = 0;
- s = splaudio();
while (cb->drops == drops && !error) {
DPRINTF(("audio_drain: used=%d, drops=%ld\n",
audio_stream_get_used(&sc->sc_pr.s), cb->drops));
- /*
- * When the process is exiting, it ignores all signals and
- * we can't interrupt this sleep, so we set a timeout
- * just in case.
- */
- error = audio_sleep_timo(&sc->sc_wchan, "aud_dr", 30*hz);
+ mutex_exit(sc->sc_intr_lock);
+ error = audio_waitio(sc, &sc->sc_wchan);
+ mutex_enter(sc->sc_intr_lock);
if (sc->sc_dying)
error = EIO;
}
- splx(s);
return error;
}
@@ -1627,11 +1837,12 @@ audio_close(struct audio_softc *sc, int flags, int ifmt,
struct lwp *l)
{
const struct audio_hw_if *hw;
- int s;
+
+ KASSERT(mutex_owned(sc->sc_lock));
DPRINTF(("audio_close: sc=%p\n", sc));
hw = sc->hw_if;
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
/* Stop recording. */
if ((flags & FREAD) && sc->sc_rbus) {
/*
@@ -1657,16 +1868,13 @@ audio_close(struct audio_softc *sc, int flags, int ifmt,
hw->halt_output(sc->hw_hdl);
sc->sc_pbus = false;
}
-
if (hw->close != NULL)
hw->close(sc->hw_hdl);
-
sc->sc_open = 0;
sc->sc_mode = 0;
- sc->sc_async_audio = 0;
sc->sc_full_duplex = 0;
- splx(s);
- DPRINTF(("audio_close: done\n"));
+ mutex_exit(sc->sc_intr_lock);
+ sc->sc_async_audio = 0;
return 0;
}
@@ -1677,7 +1885,9 @@ audio_read(struct audio_softc *sc, struct uio *uio, int ioflag)
struct audio_ringbuffer *cb;
const uint8_t *outp;
uint8_t *inp;
- int error, s, used, cc, n;
+ int error, used, cc, n;
+
+ KASSERT(mutex_owned(sc->sc_lock));
cb = &sc->sc_rr;
if (cb->mmapped)
@@ -1698,26 +1908,24 @@ audio_read(struct audio_softc *sc, struct uio *uio, int ioflag)
*/
if (!sc->sc_full_duplex && (sc->sc_mode & AUMODE_PLAY)) {
while (uio->uio_resid > 0 && !error) {
- s = splaudio();
for(;;) {
+ /*
+ * No need to lock, as any wakeup will be
+ * held for us while holding sc_lock.
+ */
cc = sc->sc_pr.stamp - sc->sc_wstamp;
if (cc > 0)
break;
DPRINTF(("audio_read: stamp=%lu, wstamp=%lu\n",
sc->sc_pr.stamp, sc->sc_wstamp));
- if (ioflag & IO_NDELAY) {
- splx(s);
+ if (ioflag & IO_NDELAY)
return EWOULDBLOCK;
- }
- error = audio_sleep(&sc->sc_rchan, "aud_hr");
+ error = audio_waitio(sc, &sc->sc_rchan);
if (sc->sc_dying)
error = EIO;
- if (error) {
- splx(s);
+ if (error)
return error;
- }
}
- splx(s);
if (uio->uio_resid < cc)
cc = uio->uio_resid;
@@ -1729,34 +1937,28 @@ audio_read(struct audio_softc *sc, struct uio *uio, int ioflag)
return error;
}
+ mutex_enter(sc->sc_intr_lock);
while (uio->uio_resid > 0 && !error) {
- s = splaudio();
while ((used = audio_stream_get_used(sc->sc_rustream)) <= 0) {
- if (!sc->sc_rbus && !sc->sc_rr.pause) {
+ if (!sc->sc_rbus && !sc->sc_rr.pause)
error = audiostartr(sc);
- if (error) {
- splx(s);
- return error;
- }
- }
- if (ioflag & IO_NDELAY) {
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
+ if (error)
+ return error;
+ if (ioflag & IO_NDELAY)
return EWOULDBLOCK;
- }
DPRINTFN(2, ("audio_read: sleep used=%d\n", used));
- error = audio_sleep(&sc->sc_rchan, "aud_rd");
+ error = audio_waitio(sc, &sc->sc_rchan);
if (sc->sc_dying)
error = EIO;
- if (error) {
- splx(s);
+ if (error)
return error;
- }
+ mutex_enter(sc->sc_intr_lock);
}
outp = sc->sc_rustream->outp;
inp = sc->sc_rustream->inp;
cb->copying = true;
- splx(s);
/*
* cc is the amount of data in the sc_rustream excluding
@@ -1767,37 +1969,41 @@ audio_read(struct audio_softc *sc, struct uio *uio, int ioflag)
DPRINTFN(1,("audio_read: outp=%p, cc=%d\n", outp, cc));
n = uio->uio_resid;
+ mutex_exit(sc->sc_intr_lock);
+ mutex_exit(sc->sc_lock);
error = uiomove(__UNCONST(outp), cc, uio);
+ mutex_enter(sc->sc_lock);
+ mutex_enter(sc->sc_intr_lock);
n -= uio->uio_resid; /* number of bytes actually moved */
- s = splaudio();
sc->sc_rustream->outp = audio_stream_add_outp
(sc->sc_rustream, outp, n);
cb->copying = false;
- splx(s);
}
+ mutex_exit(sc->sc_intr_lock);
return error;
}
void
audio_clear(struct audio_softc *sc)
{
- int s;
- s = splaudio();
+ KASSERT(mutex_owned(sc->sc_lock));
+
+ mutex_enter(sc->sc_intr_lock);
if (sc->sc_rbus) {
- audio_wakeup(&sc->sc_rchan);
+ cv_broadcast(&sc->sc_rchan);
sc->hw_if->halt_input(sc->hw_hdl);
sc->sc_rbus = false;
sc->sc_rr.pause = false;
}
if (sc->sc_pbus) {
- audio_wakeup(&sc->sc_wchan);
+ cv_broadcast(&sc->sc_wchan);
sc->hw_if->halt_output(sc->hw_hdl);
sc->sc_pbus = false;
sc->sc_pr.pause = false;
}
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
}
void
@@ -1900,21 +2106,28 @@ audio_silence_copyout(struct audio_softc *sc, int n, struct uio *uio)
error = 0;
while (n > 0 && uio->uio_resid > 0 && !error) {
k = min(n, min(uio->uio_resid, sizeof zerobuf));
+ mutex_exit(sc->sc_lock);
error = uiomove(zerobuf, k, uio);
+ mutex_enter(sc->sc_lock);
n -= k;
}
+
return error;
}
static int
-uio_fetcher_fetch_to(stream_fetcher_t *self, audio_stream_t *p,
- int max_used)
+uio_fetcher_fetch_to(struct audio_softc *sc, stream_fetcher_t *self,
+ audio_stream_t *p, int max_used)
{
uio_fetcher_t *this;
int size;
int stream_space;
int error;
+ KASSERT(mutex_owned(sc->sc_lock));
+ KASSERT(!cpu_intr_p());
+ KASSERT(!cpu_softintr_p());
+
this = (uio_fetcher_t *)self;
this->last_used = audio_stream_get_used(p);
if (this->last_used >= this->usedhigh)
@@ -1930,16 +2143,22 @@ uio_fetcher_fetch_to(stream_fetcher_t *self, audio_stream_t *p,
/* the first fragment of the space */
stream_space = p->end - p->inp;
if (stream_space >= size) {
+ mutex_exit(sc->sc_lock);
error = uiomove(p->inp, size, this->uio);
+ mutex_enter(sc->sc_lock);
if (error)
return error;
p->inp = audio_stream_add_inp(p, p->inp, size);
} else {
+ mutex_exit(sc->sc_lock);
error = uiomove(p->inp, stream_space, this->uio);
+ mutex_enter(sc->sc_lock);
if (error)
return error;
p->inp = audio_stream_add_inp(p, p->inp, stream_space);
+ mutex_exit(sc->sc_lock);
error = uiomove(p->start, size - stream_space, this->uio);
+ mutex_enter(sc->sc_lock);
if (error)
return error;
p->inp = audio_stream_add_inp(p, p->inp, size - stream_space);
@@ -1949,7 +2168,7 @@ uio_fetcher_fetch_to(stream_fetcher_t *self, audio_stream_t *p,
}
static int
-null_fetcher_fetch_to(stream_fetcher_t *self,
+null_fetcher_fetch_to(struct audio_softc *sc, stream_fetcher_t *self,
audio_stream_t *p, int max_used)
{
@@ -1974,7 +2193,9 @@ audio_write(struct audio_softc *sc, struct uio *uio, int ioflag)
stream_fetcher_t *fetcher;
stream_filter_t *filter;
uint8_t *inp, *einp;
- int saveerror, error, s, n, cc, used;
+ int saveerror, error, n, cc, used;
+
+ KASSERT(mutex_owned(sc->sc_lock));
DPRINTFN(2,("audio_write: sc=%p count=%zu used=%d(hi=%d)\n",
sc, uio->uio_resid, audio_stream_get_used(sc->sc_pustream),
@@ -2025,62 +2246,49 @@ audio_write(struct audio_softc *sc, struct uio *uio, int ioflag)
}
error = 0;
+ mutex_enter(sc->sc_intr_lock);
while (uio->uio_resid > 0 && !error) {
- s = splaudio();
/* wait if the first buffer is occupied */
while ((used = audio_stream_get_used(sc->sc_pustream))
>= cb->usedhigh) {
DPRINTFN(2, ("audio_write: sleep used=%d lowat=%d "
"hiwat=%d\n", used,
cb->usedlow, cb->usedhigh));
- if (ioflag & IO_NDELAY) {
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
+ if (ioflag & IO_NDELAY)
return EWOULDBLOCK;
- }
- error = audio_sleep(&sc->sc_wchan, "aud_wr");
+ error = audio_waitio(sc, &sc->sc_wchan);
if (sc->sc_dying)
error = EIO;
- if (error) {
- splx(s);
+ if (error)
return error;
- }
+ mutex_enter(sc->sc_intr_lock);
}
inp = cb->s.inp;
cb->copying = true;
stream = cb->s;
used = stream.used;
- splx(s);
-
- /*
- * write to the sc_pustream as much as possible
- *
- * work with a temporary audio_stream_t to narrow
- * splaudio() enclosure
- */
-
- sc->sc_writing = 1;
+ /* Write to the sc_pustream as much as possible. */
+ mutex_exit(sc->sc_intr_lock);
if (sc->sc_npfilters > 0) {
filter = sc->sc_pfilters[0];
filter->set_fetcher(filter, &ufetcher.base);
fetcher = &sc->sc_pfilters[sc->sc_npfilters - 1]->base;
cc = cb->blksize * 2;
- error = fetcher->fetch_to(fetcher, &stream, cc);
+ error = fetcher->fetch_to(sc, fetcher, &stream, cc);
if (error != 0) {
fetcher = &ufetcher.base;
cc = sc->sc_pustream->end - sc->sc_pustream->start;
- error = fetcher->fetch_to(fetcher, sc->sc_pustream, cc);
+ error = fetcher->fetch_to(sc, fetcher,
+ sc->sc_pustream, cc);
}
} else {
fetcher = &ufetcher.base;
cc = stream.end - stream.start;
- error = fetcher->fetch_to(fetcher, &stream, cc);
+ error = fetcher->fetch_to(sc, fetcher, &stream, cc);
}
- sc->sc_writing = 0;
- if (sc->sc_waitcomp)
- wakeup(sc);
-
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
if (sc->sc_npfilters > 0) {
cb->fstamp += ufetcher.last_used
- audio_stream_get_used(sc->sc_pustream);
@@ -2118,12 +2326,12 @@ audio_write(struct audio_softc *sc, struct uio *uio, int ioflag)
error = saveerror;
}
}
- splx(s);
if (cc != 0) {
DPRINTFN(1, ("audio_write: fill %d\n", cc));
audio_fill_silence(&cb->s.param, einp, cc);
}
}
+ mutex_exit(sc->sc_intr_lock);
return error;
}
@@ -2135,9 +2343,11 @@ audio_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag,
const struct audio_hw_if *hw;
struct audio_offset *ao;
u_long stamp;
- int error, s, offs, fd;
+ int error, offs, fd;
bool rbus, pbus;
+ KASSERT(mutex_owned(sc->sc_lock));
+
DPRINTF(("audio_ioctl(%lu,'%c',%lu)\n",
IOCPARM_LEN(cmd), (char)IOCGROUP(cmd), cmd&0xff));
hw = sc->hw_if;
@@ -2153,10 +2363,12 @@ audio_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag,
case FIOASYNC:
if (*(int *)addr) {
- if (sc->sc_async_audio)
- return EBUSY;
- sc->sc_async_audio = l->l_proc;
- DPRINTF(("audio_ioctl: FIOASYNC %p\n", l->l_proc));
+ if (sc->sc_async_audio != 0)
+ error = EBUSY;
+ else
+ sc->sc_async_audio = curproc->p_pid;
+ DPRINTF(("audio_ioctl: FIOASYNC pid %d\n",
+ curproc->p_pid));
} else
sc->sc_async_audio = 0;
break;
@@ -2166,10 +2378,10 @@ audio_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag,
rbus = sc->sc_rbus;
pbus = sc->sc_pbus;
audio_clear(sc);
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
error = audio_initbufs(sc);
if (error) {
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
return error;
}
if ((sc->sc_mode & AUMODE_PLAY) && !sc->sc_pbus && pbus)
@@ -2177,7 +2389,7 @@ audio_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag,
if (!error &&
(sc->sc_mode & AUMODE_RECORD) && !sc->sc_rbus && rbus)
error = audiostartr(sc);
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
break;
/*
@@ -2197,12 +2409,12 @@ audio_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag,
*/
case AUDIO_GETIOFFS:
ao = (struct audio_offset *)addr;
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
/* figure out where next DMA will start */
stamp = sc->sc_rustream == &sc->sc_rr.s
? sc->sc_rr.stamp : sc->sc_rr.fstamp;
offs = sc->sc_rustream->inp - sc->sc_rustream->start;
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
ao->samples = stamp;
ao->deltablks =
(stamp / sc->sc_rr.blksize) -
@@ -2213,13 +2425,13 @@ audio_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag,
case AUDIO_GETOOFFS:
ao = (struct audio_offset *)addr;
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
/* figure out where next DMA will start */
stamp = sc->sc_pustream == &sc->sc_pr.s
? sc->sc_pr.stamp : sc->sc_pr.fstamp;
offs = sc->sc_pustream->outp - sc->sc_pustream->start
+ sc->sc_pr.blksize;
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
ao->samples = stamp;
ao->deltablks =
(stamp / sc->sc_pr.blksize) -
@@ -2255,9 +2467,11 @@ audio_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag,
case AUDIO_DRAIN:
DPRINTF(("AUDIO_DRAIN\n"));
+ mutex_enter(sc->sc_intr_lock);
error = audio_drain(sc);
if (!error && hw->drain)
error = hw->drain(sc->hw_hdl);
+ mutex_exit(sc->sc_intr_lock);
break;
case AUDIO_GETDEV:
@@ -2317,13 +2531,14 @@ int
audio_poll(struct audio_softc *sc, int events, struct lwp *l)
{
int revents;
- int s;
int used;
+ KASSERT(mutex_owned(sc->sc_lock));
+
DPRINTF(("audio_poll: events=0x%x mode=%d\n", events, sc->sc_mode));
revents = 0;
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
if (events & (POLLIN | POLLRDNORM)) {
used = audio_stream_get_used(sc->sc_rustream);
/*
@@ -2350,6 +2565,7 @@ audio_poll(struct audio_softc *sc, int events, struct lwp *l)
(used <= sc->sc_pr.usedlow))
revents |= events & (POLLOUT | POLLWRNORM);
}
+ mutex_exit(sc->sc_intr_lock);
if (revents == 0) {
if (events & (POLLIN | POLLRDNORM))
@@ -2359,7 +2575,6 @@ audio_poll(struct audio_softc *sc, int events, struct lwp *l)
selrecord(l, &sc->sc_wsel);
}
- splx(s);
return revents;
}
@@ -2367,28 +2582,26 @@ static void
filt_audiordetach(struct knote *kn)
{
struct audio_softc *sc;
- int s;
sc = kn->kn_hook;
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
}
static int
filt_audioread(struct knote *kn, long hint)
{
struct audio_softc *sc;
- int s;
sc = kn->kn_hook;
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
if (!sc->sc_full_duplex && (sc->sc_mode & AUMODE_PLAY))
kn->kn_data = sc->sc_pr.stamp - sc->sc_wstamp;
else
kn->kn_data = audio_stream_get_used(sc->sc_rustream)
- sc->sc_rr.usedlow;
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
return kn->kn_data > 0;
}
@@ -2400,12 +2613,11 @@ static void
filt_audiowdetach(struct knote *kn)
{
struct audio_softc *sc;
- int s;
sc = kn->kn_hook;
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
SLIST_REMOVE(&sc->sc_wsel.sel_klist, kn, knote, kn_selnext);
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
}
static int
@@ -2413,14 +2625,13 @@ filt_audiowrite(struct knote *kn, long hint)
{
struct audio_softc *sc;
audio_stream_t *stream;
- int s;
sc = kn->kn_hook;
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
stream = sc->sc_pustream;
kn->kn_data = (stream->end - stream->start)
- audio_stream_get_used(stream);
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
return kn->kn_data > 0;
}
@@ -2432,7 +2643,6 @@ int
audio_kqfilter(struct audio_softc *sc, struct knote *kn)
{
struct klist *klist;
- int s;
switch (kn->kn_filter) {
case EVFILT_READ:
@@ -2451,9 +2661,9 @@ audio_kqfilter(struct audio_softc *sc, struct knote *kn)
kn->kn_hook = sc;
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
return 0;
}
@@ -2463,7 +2673,10 @@ audio_mmap(struct audio_softc *sc, off_t off, int prot)
{
const struct audio_hw_if *hw;
struct audio_ringbuffer *cb;
- int s;
+ paddr_t rv;
+
+ KASSERT(mutex_owned(sc->sc_lock));
+ KASSERT(sc->sc_dvlock < 0);
DPRINTF(("audio_mmap: off=%lld, prot=%d\n", (long long)off, prot));
hw = sc->hw_if;
@@ -2500,21 +2713,25 @@ audio_mmap(struct audio_softc *sc, off_t off, int prot)
if (cb == &sc->sc_pr) {
audio_fill_silence(&cb->s.param, cb->s.start,
cb->s.bufsize);
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
sc->sc_pustream = &cb->s;
if (!sc->sc_pbus && !sc->sc_pr.pause)
(void)audiostartp(sc);
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
} else {
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
sc->sc_rustream = &cb->s;
if (!sc->sc_rbus && !sc->sc_rr.pause)
(void)audiostartr(sc);
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
}
}
- return hw->mappage(sc->hw_hdl, cb->s.start, off, prot);
+ mutex_exit(sc->sc_lock);
+ rv = hw->mappage(sc->hw_hdl, cb->s.start, off, prot);
+ mutex_enter(sc->sc_lock);
+
+ return rv;
}
int
@@ -2522,6 +2739,9 @@ audiostartr(struct audio_softc *sc)
{
int error;
+ KASSERT(mutex_owned(sc->sc_lock));
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
DPRINTF(("audiostartr: start=%p used=%d(hi=%d) mmapped=%d\n",
sc->sc_rr.s.start, audio_stream_get_used(&sc->sc_rr.s),
sc->sc_rr.usedhigh, sc->sc_rr.mmapped));
@@ -2550,6 +2770,9 @@ audiostartp(struct audio_softc *sc)
int error;
int used;
+ KASSERT(mutex_owned(sc->sc_lock));
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
used = audio_stream_get_used(&sc->sc_pr.s);
DPRINTF(("audiostartp: start=%p used=%d(hi=%d blk=%d) mmapped=%d\n",
sc->sc_pr.s.start, used, sc->sc_pr.usedhigh,
@@ -2559,7 +2782,7 @@ audiostartp(struct audio_softc *sc)
return EINVAL;
if (!sc->sc_pr.mmapped && used < sc->sc_pr.blksize) {
- wakeup(&sc->sc_wchan);
+ cv_broadcast(&sc->sc_wchan);
DPRINTF(("%s: wakeup and return\n", __func__));
return 0;
}
@@ -2592,10 +2815,11 @@ audiostartp(struct audio_softc *sc)
* the requested area nothing is done; so when the whole buffer is
* silent nothing happens. When the writer starts again sc_sil_count
* is set to 0.
- */
-/* XXX
+ *
+ * XXX
* Putting silence into the output buffer should not really be done
- * at splaudio, but there is no softaudio level to do it at yet.
+ * from the device interrupt handler. Consider deferring to the soft
+ * interrupt.
*/
static inline void
audio_pint_silence(struct audio_softc *sc, struct audio_ringbuffer *cb,
@@ -2603,6 +2827,8 @@ audio_pint_silence(struct audio_softc *sc, struct audio_ringbuffer *cb,
{
uint8_t *s, *e, *p, *q;
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
if (sc->sc_sil_count > 0) {
s = sc->sc_sil_start; /* start of silence */
e = s + sc->sc_sil_count; /* end of sil., may be beyond end */
@@ -2638,36 +2864,40 @@ static void
audio_softintr_rd(void *cookie)
{
struct audio_softc *sc = cookie;
- struct proc *p;
-
- audio_wakeup(&sc->sc_rchan);
- selnotify(&sc->sc_rsel, 0, 0);
- if (sc->sc_async_audio != NULL) {
- DPRINTFN(3, ("audio_softintr_rd: sending SIGIO %p\n",
- sc->sc_async_audio));
+ proc_t *p;
+ pid_t pid;
+
+ mutex_enter(sc->sc_lock);
+ cv_broadcast(&sc->sc_rchan);
+ selnotify(&sc->sc_rsel, 0, NOTE_SUBMIT);
+ if ((pid = sc->sc_async_audio) != 0) {
+ DPRINTFN(3, ("audio_softintr_rd: sending SIGIO %d\n", pid));
mutex_enter(proc_lock);
- if ((p = sc->sc_async_audio) != NULL)
+ if ((p = proc_find(pid)) != NULL)
psignal(p, SIGIO);
mutex_exit(proc_lock);
}
+ mutex_exit(sc->sc_lock);
}
static void
audio_softintr_wr(void *cookie)
{
struct audio_softc *sc = cookie;
- struct proc *p;
-
- audio_wakeup(&sc->sc_wchan);
- selnotify(&sc->sc_wsel, 0, 0);
- if (sc->sc_async_audio != NULL) {
- DPRINTFN(3, ("audio_softintr_wr: sending SIGIO %p\n",
- sc->sc_async_audio));
+ proc_t *p;
+ pid_t pid;
+
+ mutex_enter(sc->sc_lock);
+ cv_broadcast(&sc->sc_wchan);
+ selnotify(&sc->sc_wsel, 0, NOTE_SUBMIT);
+ if ((pid = sc->sc_async_audio) != 0) {
+ DPRINTFN(3, ("audio_softintr_wr: sending SIGIO %d\n", pid));
mutex_enter(proc_lock);
- if ((p = sc->sc_async_audio) != NULL)
+ if ((p = proc_find(pid)) != NULL)
psignal(p, SIGIO);
mutex_exit(proc_lock);
}
+ mutex_exit(sc->sc_lock);
}
/*
@@ -2690,6 +2920,9 @@ audio_pint(void *v)
int error;
sc = v;
+
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
if (!sc->sc_open)
return; /* ignore interrupt if not open */
@@ -2755,7 +2988,7 @@ audio_pint(void *v)
cc = cb->s.end - cb->s.start;
if (blksize * 2 < cc)
cc = blksize * 2;
- fetcher->fetch_to(fetcher, &cb->s, cc);
+ fetcher->fetch_to(sc, fetcher, &cb->s, cc);
cb->fstamp += used - audio_stream_get_used(sc->sc_pustream);
used = audio_stream_get_used(&cb->s);
}
@@ -2804,7 +3037,7 @@ audio_pint(void *v)
}
/* Possible to return one or more "phantom blocks" now. */
- if (!sc->sc_full_duplex && sc->sc_rchan)
+ if (!sc->sc_full_duplex)
softint_schedule(sc->sc_sih_rd);
}
@@ -2828,6 +3061,9 @@ audio_rint(void *v)
sc = v;
cb = &sc->sc_rr;
+
+ KASSERT(mutex_owned(sc->sc_intr_lock));
+
if (!sc->sc_open)
return; /* ignore interrupt if not open */
@@ -2884,7 +3120,7 @@ audio_rint(void *v)
used = audio_stream_get_used(sc->sc_rustream);
cc = sc->sc_rustream->end - sc->sc_rustream->start;
error = last_fetcher->fetch_to
- (last_fetcher, sc->sc_rustream, cc);
+ (sc, last_fetcher, sc->sc_rustream, cc);
cb->fstamp += audio_stream_get_used(sc->sc_rustream) - used;
/* XXX what should do for error? */
}
@@ -2991,6 +3227,8 @@ audio_set_defaults(struct audio_softc *sc, u_int mode)
{
struct audio_info ai;
+ KASSERT(mutex_owned(sc->sc_lock));
+
/* default parameters */
sc->sc_rparams = audio_default;
sc->sc_pparams = audio_default;
@@ -3016,6 +3254,8 @@ int
au_set_lr_value(struct audio_softc *sc, mixer_ctrl_t *ct, int l, int r)
{
+ KASSERT(mutex_owned(sc->sc_lock));
+
ct->type = AUDIO_MIXER_VALUE;
ct->un.value.num_channels = 2;
ct->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
@@ -3037,6 +3277,8 @@ au_set_gain(struct audio_softc *sc, struct au_mixer_ports *ports,
u_int mask;
int nset;
+ KASSERT(mutex_owned(sc->sc_lock));
+
if (balance == AUDIO_MID_BALANCE) {
l = r = gain;
} else if (balance < AUDIO_MID_BALANCE) {
@@ -3109,6 +3351,8 @@ au_get_lr_value(struct audio_softc *sc, mixer_ctrl_t *ct, int *l, int *r)
{
int error;
+ KASSERT(mutex_owned(sc->sc_lock));
+
ct->un.value.num_channels = 2;
if (sc->hw_if->get_port(sc->hw_hdl, ct) == 0) {
*l = ct->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
@@ -3131,6 +3375,8 @@ au_get_gain(struct audio_softc *sc, struct au_mixer_ports *ports,
int i, l, r, n;
int lgain, rgain;
+ KASSERT(mutex_owned(sc->sc_lock));
+
lgain = AUDIO_MAX_GAIN / 2;
rgain = AUDIO_MAX_GAIN / 2;
if (ports->index == -1) {
@@ -3213,6 +3459,8 @@ au_set_port(struct audio_softc *sc, struct au_mixer_ports *ports, u_int port)
mixer_ctrl_t ct;
int i, error, use_mixerout;
+ KASSERT(mutex_owned(sc->sc_lock));
+
use_mixerout = 1;
if (port == 0) {
if (ports->allports == 0)
@@ -3268,6 +3516,8 @@ au_get_port(struct audio_softc *sc, struct au_mixer_ports *ports)
mixer_ctrl_t ct;
int i, aumask;
+ KASSERT(mutex_owned(sc->sc_lock));
+
if (ports->index == -1)
return 0;
ct.dev = ports->index;
@@ -3302,7 +3552,7 @@ audiosetinfo(struct audio_softc *sc, struct audio_info *ai)
struct audio_prinfo *r, *p;
const struct audio_hw_if *hw;
audio_stream_t *oldpus, *oldrus;
- int s, setmode;
+ int setmode;
int error;
int np, nr;
unsigned int blks;
@@ -3312,6 +3562,8 @@ audiosetinfo(struct audio_softc *sc, struct audio_info *ai)
bool cleared, modechange, pausechange;
u_char balance;
+ KASSERT(mutex_owned(sc->sc_lock));
+
hw = sc->hw_if;
if (hw == NULL) /* HW has not attached */
return ENXIO;
@@ -3625,7 +3877,7 @@ cleanup:
if (cleared || pausechange) {
int init_error;
- s = splaudio();
+ mutex_enter(sc->sc_intr_lock);
init_error = audio_initbufs(sc);
if (init_error) goto err;
if (sc->sc_pr.blksize != oldpblksize ||
@@ -3641,7 +3893,7 @@ cleanup:
rbus && !sc->sc_rbus)
init_error = audiostartr(sc);
err:
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
if (init_error)
return init_error;
}
@@ -3676,6 +3928,8 @@ audiogetinfo(struct audio_softc *sc, struct audio_info *ai, int buf_only_mode)
struct audio_prinfo *r, *p;
const struct audio_hw_if *hw;
+ KASSERT(mutex_owned(sc->sc_lock));
+
r = &ai->record;
p = &ai->play;
hw = sc->hw_if;
@@ -3778,6 +4032,9 @@ int
mixer_open(dev_t dev, struct audio_softc *sc, int flags,
int ifmt, struct lwp *l)
{
+
+ KASSERT(mutex_owned(sc->sc_lock));
+
if (sc->hw_if == NULL)
return ENXIO;
@@ -3790,21 +4047,19 @@ mixer_open(dev_t dev, struct audio_softc *sc, int flags,
* Remove a process from those to be signalled on mixer activity.
*/
static void
-mixer_remove(struct audio_softc *sc, struct lwp *l)
+mixer_remove(struct audio_softc *sc)
{
struct mixer_asyncs **pm, *m;
- struct proc *p;
+ pid_t pid;
- if (l == NULL)
- return;
-
- p = l->l_proc;
+ KASSERT(mutex_owned(sc->sc_lock));
+ pid = curproc->p_pid;
for (pm = &sc->sc_async_mixer; *pm; pm = &(*pm)->next) {
- if ((*pm)->proc == p) {
+ if ((*pm)->pid == pid) {
m = *pm;
*pm = m->next;
- free(m, M_DEVBUF);
+ kmem_free(m, sizeof(*m));
return;
}
}
@@ -3817,10 +4072,12 @@ static void
mixer_signal(struct audio_softc *sc)
{
struct mixer_asyncs *m;
+ proc_t *p;
for (m = sc->sc_async_mixer; m; m = m->next) {
mutex_enter(proc_lock);
- psignal(m->proc, SIGIO);
+ if ((p = proc_find(m->pid)) != NULL)
+ psignal(p, SIGIO);
mutex_exit(proc_lock);
}
}
@@ -3834,8 +4091,10 @@ mixer_close(struct audio_softc *sc, int flags, int ifmt,
struct lwp *l)
{
+ KASSERT(mutex_owned(sc->sc_lock));
+
DPRINTF(("mixer_close: sc %p\n", sc));
- mixer_remove(sc, l);
+ mixer_remove(sc);
return 0;
}
@@ -3844,6 +4103,7 @@ mixer_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag,
struct lwp *l)
{
const struct audio_hw_if *hw;
+ struct mixer_asyncs *ma;
mixer_ctrl_t *mc;
int error;
@@ -3858,13 +4118,17 @@ mixer_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag,
switch (cmd) {
case FIOASYNC:
- mixer_remove(sc, l); /* remove old entry */
if (*(int *)addr) {
- struct mixer_asyncs *ma;
- ma = malloc(sizeof (struct mixer_asyncs),
- M_DEVBUF, M_WAITOK);
+ mutex_exit(sc->sc_lock);
+ ma = kmem_alloc(sizeof(struct mixer_asyncs), KM_SLEEP);
+ mutex_enter(sc->sc_lock);
+ } else {
+ ma = NULL;
+ }
+ mixer_remove(sc); /* remove old entry */
+ if (ma != NULL) {
ma->next = sc->sc_async_mixer;
- ma->proc = l->l_proc;
+ ma->pid = curproc->p_pid;
sc->sc_async_mixer = ma;
}
error = 0;
@@ -3885,8 +4149,7 @@ mixer_ioctl(struct audio_softc *sc, u_long cmd, void *addr, int flag,
DPRINTF(("AUDIO_MIXER_READ\n"));
mc = (mixer_ctrl_t *)addr;
- if (device_is_active(sc->sc_dev) ||
- sc->sc_mixer_state == NULL)
+ if (device_is_active(sc->sc_dev))
error = hw->get_port(sc->hw_hdl, mc);
else if (mc->dev >= sc->sc_nmixer_states)
error = ENXIO;
@@ -3969,31 +4232,12 @@ audio_mixer_capture(struct audio_softc *sc)
mixer_devinfo_t mi;
mixer_ctrl_t *mc;
- for (mi.index = 0; ; mi.index++)
- if (sc->hw_if->query_devinfo(sc->hw_hdl, &mi) != 0)
- break;
+ KASSERT(mutex_owned(sc->sc_lock));
-#ifdef DIAGNOSTIC
- if (sc->sc_mixer_state != NULL && sc->sc_nmixer_states != mi.index) {
- free(sc->sc_mixer_state, M_DEVBUF);
- sc->sc_mixer_state = NULL;
- }
-#endif
-
- sc->sc_nmixer_states = mi.index;
- if (sc->sc_mixer_state == NULL)
- sc->sc_mixer_state = malloc(
- sizeof(mixer_ctrl_t) * sc->sc_nmixer_states,
- M_DEVBUF, M_NOWAIT);
- if (sc->sc_mixer_state == NULL) {
- aprint_error("%s: couldn't allocate memory for mixer state\n",
- device_xname(sc->dev));
- return;
- }
-
- for (mi.index = 0; ; mi.index++) {
+ for (mi.index = 0;; mi.index++) {
if (sc->hw_if->query_devinfo(sc->hw_hdl, &mi) != 0)
break;
+ KASSERT(mi.index < sc->sc_nmixer_states);
if (mi.type == AUDIO_MIXER_CLASS)
continue;
mc = &sc->sc_mixer_state[mi.index];
@@ -4012,8 +4256,7 @@ audio_mixer_restore(struct audio_softc *sc)
mixer_devinfo_t mi;
mixer_ctrl_t *mc;
- if (sc->sc_mixer_state == NULL)
- return;
+ KASSERT(mutex_owned(sc->sc_lock));
for (mi.index = 0; ; mi.index++) {
if (sc->hw_if->query_devinfo(sc->hw_hdl, &mi) != 0)
@@ -4076,18 +4319,19 @@ audio_suspend(device_t dv, const pmf_qual_t *qual)
{
struct audio_softc *sc = device_private(dv);
const struct audio_hw_if *hwp = sc->hw_if;
- int (s);
- s = splaudio();
+ mutex_enter(sc->sc_lock);
audio_mixer_capture(sc);
+ mutex_enter(sc->sc_lock);
if (sc->sc_pbus == true)
hwp->halt_output(sc->hw_hdl);
if (sc->sc_rbus == true)
hwp->halt_input(sc->hw_hdl);
+ mutex_exit(sc->sc_lock);
#ifdef AUDIO_PM_IDLE
- callout_stop(&sc->sc_idle_counter);
+ callout_halt(&sc->sc_idle_counter, sc->sc_lock);
#endif
- splx(s);
+ mutex_exit(sc->sc_lock);
return true;
}
@@ -4096,17 +4340,18 @@ static bool
audio_resume(device_t dv, const pmf_qual_t *qual)
{
struct audio_softc *sc = device_private(dv);
- int s;
- s = splaudio();
+ mutex_enter(sc->sc_lock);
if (sc->sc_lastinfovalid)
audiosetinfo(sc, &sc->sc_lastinfo);
audio_mixer_restore(sc);
+ mutex_enter(sc->sc_intr_lock);
if ((sc->sc_pbus == true) && !sc->sc_pr.pause)
audiostartp(sc);
if ((sc->sc_rbus == true) && !sc->sc_rr.pause)
audiostartr(sc);
- splx(s);
+ mutex_exit(sc->sc_intr_lock);
+ mutex_exit(sc->sc_lock);
return true;
}
@@ -4119,22 +4364,20 @@ audio_volume_down(device_t dv)
int newgain;
u_int gain;
u_char balance;
- int s;
+ mutex_enter(sc->sc_lock);
if (sc->sc_outports.index == -1 && sc->sc_outports.master != -1) {
mi.index = sc->sc_outports.master;
mi.un.v.delta = 0;
- if (sc->hw_if->query_devinfo(sc->hw_hdl, &mi) != 0)
- return;
-
- s = splaudio();
- au_get_gain(sc, &sc->sc_outports, &gain, &balance);
- newgain = gain - mi.un.v.delta;
- if (newgain < AUDIO_MIN_GAIN)
- newgain = AUDIO_MIN_GAIN;
- au_set_gain(sc, &sc->sc_outports, newgain, balance);
- splx(s);
+ if (sc->hw_if->query_devinfo(sc->hw_hdl, &mi) == 0) {
+ au_get_gain(sc, &sc->sc_outports, &gain, &balance);
+ newgain = gain - mi.un.v.delta;
+ if (newgain < AUDIO_MIN_GAIN)
+ newgain = AUDIO_MIN_GAIN;
+ au_set_gain(sc, &sc->sc_outports, newgain, balance);
+ }
}
+ mutex_exit(sc->sc_lock);
}
static void
@@ -4144,22 +4387,20 @@ audio_volume_up(device_t dv)
mixer_devinfo_t mi;
u_int gain, newgain;
u_char balance;
- int s;
+ mutex_enter(sc->sc_lock);
if (sc->sc_outports.index == -1 && sc->sc_outports.master != -1) {
mi.index = sc->sc_outports.master;
mi.un.v.delta = 0;
- if (sc->hw_if->query_devinfo(sc->hw_hdl, &mi) != 0)
- return;
-
- s = splaudio();
- au_get_gain(sc, &sc->sc_outports, &gain, &balance);
- newgain = gain + mi.un.v.delta;
- if (newgain > AUDIO_MAX_GAIN)
- newgain = AUDIO_MAX_GAIN;
- au_set_gain(sc, &sc->sc_outports, newgain, balance);
- splx(s);
+ if (sc->hw_if->query_devinfo(sc->hw_hdl, &mi) == 0) {
+ au_get_gain(sc, &sc->sc_outports, &gain, &balance);
+ newgain = gain + mi.un.v.delta;
+ if (newgain > AUDIO_MAX_GAIN)
+ newgain = AUDIO_MAX_GAIN;
+ au_set_gain(sc, &sc->sc_outports, newgain, balance);
+ }
}
+ mutex_exit(sc->sc_lock);
}
static void
@@ -4168,9 +4409,8 @@ audio_volume_toggle(device_t dv)
struct audio_softc *sc = device_private(dv);
u_int gain, newgain;
u_char balance;
- int s;
- s = splaudio();
+ mutex_enter(sc->sc_lock);
au_get_gain(sc, &sc->sc_outports, &gain, &balance);
if (gain != 0) {
sc->sc_lastgain = gain;
@@ -4178,7 +4418,7 @@ audio_volume_toggle(device_t dv)
} else
newgain = sc->sc_lastgain;
au_set_gain(sc, &sc->sc_outports, newgain, balance);
- splx(s);
+ mutex_exit(sc->sc_lock);
}
static int
@@ -4187,6 +4427,8 @@ audio_get_props(struct audio_softc *sc)
const struct audio_hw_if *hw;
int props;
+ KASSERT(mutex_owned(sc->sc_lock));
+
hw = sc->hw_if;
props = hw->get_props(sc->hw_hdl);
diff --git a/sys/dev/audio_if.h b/sys/dev/audio_if.h
index 98e83653dbb..3cde6da48b1 100644
--- a/sys/dev/audio_if.h
+++ b/sys/dev/audio_if.h
@@ -1,4 +1,4 @@
-/* $NetBSD: audio_if.h,v 1.66 2009/09/29 15:58:54 sborrill Exp $ */
+/* $NetBSD: audio_if.h,v 1.67 2011/11/23 23:07:31 jmcneill Exp $ */
/*
* Copyright (c) 1994 Havard Eidnes.
@@ -36,8 +36,10 @@
#ifndef _SYS_DEV_AUDIO_IF_H_
#define _SYS_DEV_AUDIO_IF_H_
+
#include <sys/types.h>
#include <sys/audioio.h>
+#include <sys/mutex.h>
/* check we have an audio(4) configured into kernel */
#if defined(_KERNEL_OPT)
@@ -121,7 +123,8 @@ audio_stream_add_outp(audio_stream_t *s, const uint8_t *v, int diff)
* an interface to fill a audio stream buffer
*/
typedef struct stream_fetcher {
- int (*fetch_to)(struct stream_fetcher *, audio_stream_t *, int);
+ int (*fetch_to)(struct audio_softc *, struct stream_fetcher *,
+ audio_stream_t *, int);
} stream_fetcher_t;
/**
@@ -169,7 +172,6 @@ typedef struct stream_filter_list {
} filters[AUDIO_MAX_FILTERS];
} stream_filter_list_t;
-struct malloc_type;
struct audio_hw_if {
int (*open)(void *, int); /* open hardware */
void (*close)(void *); /* close hardware */
@@ -226,8 +228,8 @@ struct audio_hw_if {
int (*query_devinfo)(void *, mixer_devinfo_t *);
/* Allocate/free memory for the ring buffer. Usually malloc/free. */
- void *(*allocm)(void *, int, size_t, struct malloc_type *, int);
- void (*freem)(void *, void *, struct malloc_type *);
+ void *(*allocm)(void *, int, size_t);
+ void (*freem)(void *, void *, size_t);
size_t (*round_buffersize)(void *, int, size_t);
paddr_t (*mappage)(void *, void *, off_t, int);
@@ -238,9 +240,7 @@ struct audio_hw_if {
int (*trigger_input)(void *, void *, void *, int,
void (*)(void *), void *, const audio_params_t *);
int (*dev_ioctl)(void *, u_long, void *, int, struct lwp *);
- int (*powerstate)(void *, int);
-#define AUDIOPOWER_ON 1
-#define AUDIOPOWER_OFF 0
+ void (*get_locks)(void *, kmutex_t **, kmutex_t **);
};
struct audio_attach_args {
diff --git a/sys/dev/audiovar.h b/sys/dev/audiovar.h
index a7ff5e03ddb..e30b00c6c54 100644
--- a/sys/dev/audiovar.h
+++ b/sys/dev/audiovar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: audiovar.h,v 1.45 2008/04/28 20:23:46 martin Exp $ */
+/* $NetBSD: audiovar.h,v 1.46 2011/11/23 23:07:31 jmcneill Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -65,6 +65,9 @@
*/
#ifndef _SYS_DEV_AUDIOVAR_H_
#define _SYS_DEV_AUDIOVAR_H_
+
+#include <sys/condvar.h>
+
#include <dev/audio_if.h>
/*
@@ -130,17 +133,22 @@ struct audio_softc {
struct selinfo sc_wsel; /* write selector */
struct selinfo sc_rsel; /* read selector */
- struct proc *sc_async_audio; /* process who wants audio SIGIO */
+ pid_t sc_async_audio; /* process who wants audio SIGIO */
void *sc_sih_rd;
void *sc_sih_wr;
struct mixer_asyncs {
struct mixer_asyncs *next;
- struct proc *proc;
+ pid_t pid;
} *sc_async_mixer; /* processes who want mixer SIGIO */
- /* Sleep channels for reading and writing. */
- int sc_rchan;
- int sc_wchan;
+ /* Locks and sleep channels for reading, writing and draining. */
+ kmutex_t *sc_intr_lock;
+ kmutex_t *sc_lock;
+ kcondvar_t sc_rchan;
+ kcondvar_t sc_wchan;
+ kcondvar_t sc_lchan;
+ int sc_dvlock;
+ bool sc_dying;
bool sc_blkset; /* Blocksize has been set */
@@ -169,9 +177,6 @@ struct audio_softc {
audio_stream_t sc_pstreams[AUDIO_MAX_FILTERS];
stream_filter_t *sc_pfilters[AUDIO_MAX_FILTERS];
struct audio_ringbuffer sc_pr; /* Play ring */
- int sc_writing;
- int sc_waitcomp;
- int sc_changing;
/**
* hardware
@@ -203,10 +208,6 @@ struct audio_softc {
struct au_mixer_ports sc_inports, sc_outports;
int sc_monitor_port;
- int sc_refcnt;
- int sc_opencnt;
- bool sc_dying;
-
#ifdef AUDIO_INTR_TIME
u_long sc_pfirstintr; /* first time we saw a play interrupt */
int sc_pnintr; /* number of interrupts */
diff --git a/sys/dev/aurateconv.c b/sys/dev/aurateconv.c
index d296b2ae1f3..1a7220ff165 100644
--- a/sys/dev/aurateconv.c
+++ b/sys/dev/aurateconv.c
@@ -1,4 +1,4 @@
-/* $NetBSD: aurateconv.c,v 1.18 2008/04/28 20:23:46 martin Exp $ */
+/* $NetBSD: aurateconv.c,v 1.19 2011/11/23 23:07:31 jmcneill Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: aurateconv.c,v 1.18 2008/04/28 20:23:46 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: aurateconv.c,v 1.19 2011/11/23 23:07:31 jmcneill Exp $");
#include <sys/systm.h>
#include <sys/types.h>
@@ -65,7 +65,8 @@ typedef struct aurateconv {
int32_t next[AUDIO_MAX_CHANNELS];
} aurateconv_t;
-static int aurateconv_fetch_to(stream_fetcher_t *, audio_stream_t *, int);
+static int aurateconv_fetch_to(struct audio_softc *, stream_fetcher_t *,
+ audio_stream_t *, int);
static void aurateconv_dtor(stream_filter_t *);
static int aurateconv_slinear16_LE(aurateconv_t *, audio_stream_t *,
int, int, int);
@@ -160,7 +161,8 @@ aurateconv_dtor(struct stream_filter *this)
}
static int
-aurateconv_fetch_to(stream_fetcher_t *self, audio_stream_t *dst, int max_used)
+aurateconv_fetch_to(struct audio_softc *sc, stream_fetcher_t *self,
+ audio_stream_t *dst, int max_used)
{
aurateconv_t *this;
int m, err, frame_dst, frame_src;
@@ -179,7 +181,7 @@ aurateconv_fetch_to(stream_fetcher_t *self, audio_stream_t *dst, int max_used)
if (m <= 0)
m = frame_src;
- if ((err = this->base.prev->fetch_to(this->base.prev, this->base.src, m)))
+ if ((err = this->base.prev->fetch_to(sc, this->base.prev, this->base.src, m)))
return err;
m = (dst->end - dst->start) / frame_dst * frame_dst;
m = min(m, max_used);
diff --git a/sys/dev/bluetooth/btsco.c b/sys/dev/bluetooth/btsco.c
index f752fb88abc..031b38d5c78 100644
--- a/sys/dev/bluetooth/btsco.c
+++ b/sys/dev/bluetooth/btsco.c
@@ -1,4 +1,4 @@
-/* $NetBSD: btsco.c,v 1.24 2011/03/16 21:38:54 plunky Exp $ */
+/* $NetBSD: btsco.c,v 1.25 2011/11/23 23:07:31 jmcneill Exp $ */
/*-
* Copyright (c) 2006 Itronix Inc.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: btsco.c,v 1.24 2011/03/16 21:38:54 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: btsco.c,v 1.25 2011/11/23 23:07:31 jmcneill Exp $");
#include <sys/param.h>
#include <sys/audioio.h>
@@ -41,7 +41,7 @@ __KERNEL_RCSID(0, "$NetBSD: btsco.c,v 1.24 2011/03/16 21:38:54 plunky Exp $");
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/queue.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/mbuf.h>
#include <sys/proc.h>
#include <sys/socketvar.h>
@@ -97,6 +97,7 @@ struct btsco_softc {
device_t sc_audio; /* MI audio device */
void *sc_intr; /* interrupt cookie */
kcondvar_t sc_connect; /* connect wait */
+ kmutex_t sc_intr_lock; /* for audio */
/* Bluetooth */
bdaddr_t sc_laddr; /* local address */
@@ -161,10 +162,11 @@ static int btsco_setfd(void *, int);
static int btsco_set_port(void *, mixer_ctrl_t *);
static int btsco_get_port(void *, mixer_ctrl_t *);
static int btsco_query_devinfo(void *, mixer_devinfo_t *);
-static void *btsco_allocm(void *, int, size_t, struct malloc_type *, int);
-static void btsco_freem(void *, void *, struct malloc_type *);
+static void *btsco_allocm(void *, int, size_t);
+static void btsco_freem(void *, void *, size_t);
static int btsco_get_props(void *);
static int btsco_dev_ioctl(void *, u_long, void *, int, struct lwp *);
+static void btsco_get_locks(void *, kmutex_t **, kmutex_t **);
static const struct audio_hw_if btsco_if = {
btsco_open, /* open */
@@ -194,7 +196,7 @@ static const struct audio_hw_if btsco_if = {
NULL, /* trigger_output */
NULL, /* trigger_input */
btsco_dev_ioctl, /* dev_ioctl */
- NULL, /* powerstate */
+ btsco_get_locks, /* get_locks */
};
static const struct audio_device btsco_device = {
@@ -293,6 +295,7 @@ btsco_attach(device_t parent, device_t self, void *aux)
sc->sc_state = BTSCO_CLOSED;
sc->sc_name = device_xname(self);
cv_init(&sc->sc_connect, "connect");
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE);
/*
* copy in our configuration info
@@ -388,6 +391,7 @@ btsco_detach(device_t self, int flags)
}
cv_destroy(&sc->sc_connect);
+ mutex_destroy(&sc->sc_intr_lock);
return 0;
}
@@ -432,7 +436,6 @@ static void
btsco_sco_disconnected(void *arg, int err)
{
struct btsco_softc *sc = arg;
- int s;
DPRINTF("%s sc_state %d\n", sc->sc_name, sc->sc_state);
@@ -455,7 +458,7 @@ btsco_sco_disconnected(void *arg, int err)
* has completed so that when it tries to send more, we
* can indicate an error.
*/
- s = splaudio();
+ mutex_spin_enter(&sc->sc_intr_lock);
if (sc->sc_tx_pending > 0) {
sc->sc_tx_pending = 0;
(*sc->sc_tx_intr)(sc->sc_tx_intrarg);
@@ -464,7 +467,7 @@ btsco_sco_disconnected(void *arg, int err)
sc->sc_rx_want = 0;
(*sc->sc_rx_intr)(sc->sc_rx_intrarg);
}
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
break;
default:
@@ -495,17 +498,16 @@ static void
btsco_sco_complete(void *arg, int count)
{
struct btsco_softc *sc = arg;
- int s;
DPRINTFN(10, "%s count %d\n", sc->sc_name, count);
- s = splaudio();
+ mutex_spin_enter(&sc->sc_intr_lock);
if (sc->sc_tx_pending > 0) {
sc->sc_tx_pending -= count;
if (sc->sc_tx_pending == 0)
(*sc->sc_tx_intr)(sc->sc_tx_intrarg);
}
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
}
static void
@@ -520,11 +522,11 @@ static void
btsco_sco_input(void *arg, struct mbuf *m)
{
struct btsco_softc *sc = arg;
- int len, s;
+ int len;
DPRINTFN(10, "%s len=%d\n", sc->sc_name, m->m_pkthdr.len);
- s = splaudio();
+ mutex_spin_enter(&sc->sc_intr_lock);
if (sc->sc_rx_want == 0) {
m_freem(m);
} else {
@@ -550,7 +552,7 @@ btsco_sco_input(void *arg, struct mbuf *m)
if (sc->sc_rx_want == 0)
(*sc->sc_rx_intr)(sc->sc_rx_intrarg);
}
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
}
@@ -773,9 +775,9 @@ btsco_round_blocksize(void *hdl, int bs, int mode,
/*
* Start Output
*
- * We dont want to be calling the network stack at splaudio() so make
- * a note of what is to be sent, and schedule an interrupt to bundle
- * it up and queue it.
+ * We dont want to be calling the network stack with sc_intr_lock held
+ * so make a note of what is to be sent, and schedule an interrupt to
+ * bundle it up and queue it.
*/
static int
btsco_start_output(void *hdl, void *block, int blksize,
@@ -1012,17 +1014,16 @@ btsco_query_devinfo(void *hdl, mixer_devinfo_t *di)
* Allocate Ring Buffers.
*/
static void *
-btsco_allocm(void *hdl, int direction, size_t size,
- struct malloc_type *type, int flags)
+btsco_allocm(void *hdl, int direction, size_t size)
{
struct btsco_softc *sc = hdl;
void *addr;
DPRINTF("%s: size %d direction %d\n", sc->sc_name, size, direction);
- addr = malloc(size, type, flags);
+ addr = kmem_alloc(size, KM_SLEEP);
- if (direction == AUMODE_PLAY) {
+ if (addr != NULL && direction == AUMODE_PLAY) {
sc->sc_tx_buf = addr;
sc->sc_tx_refcnt = 0;
}
@@ -1040,7 +1041,7 @@ btsco_allocm(void *hdl, int direction, size_t size,
* This would be a memory leak but at least there is a warning..
*/
static void
-btsco_freem(void *hdl, void *addr, struct malloc_type *type)
+btsco_freem(void *hdl, void *addr, size_t size)
{
struct btsco_softc *sc = hdl;
int count = hz / 2;
@@ -1051,7 +1052,7 @@ btsco_freem(void *hdl, void *addr, struct malloc_type *type)
sc->sc_tx_buf = NULL;
while (sc->sc_tx_refcnt> 0 && count-- > 0)
- tsleep(sc, PWAIT, "drain", 1);
+ kpause("drain", false, 1, NULL);
if (sc->sc_tx_refcnt > 0) {
aprint_error("%s: ring buffer unreleased!\n", sc->sc_name);
@@ -1059,7 +1060,7 @@ btsco_freem(void *hdl, void *addr, struct malloc_type *type)
}
}
- free(addr, type);
+ kmem_free(addr, size);
}
static int
@@ -1069,6 +1070,15 @@ btsco_get_props(void *hdl)
return AUDIO_PROP_FULLDUPLEX;
}
+static void
+btsco_get_locks(void *hdl, kmutex_t **intr, kmutex_t **thread)
+{
+ struct btsco_softc *sc = hdl;
+
+ *intr = &sc->sc_intr_lock;
+ *thread = bt_lock;
+}
+
/*
* Handle private ioctl. We pass information out about how to talk
* to the device and mixer.
diff --git a/sys/dev/ebus/cs4231_ebus.c b/sys/dev/ebus/cs4231_ebus.c
index 11269d845b1..a906246ca4b 100644
--- a/sys/dev/ebus/cs4231_ebus.c
+++ b/sys/dev/ebus/cs4231_ebus.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cs4231_ebus.c,v 1.34 2011/06/02 00:23:28 christos Exp $ */
+/* $NetBSD: cs4231_ebus.c,v 1.35 2011/11/23 23:07:31 jmcneill Exp $ */
/*
* Copyright (c) 2002 Valeriy E. Ushakov
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cs4231_ebus.c,v 1.34 2011/06/02 00:23:28 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cs4231_ebus.c,v 1.35 2011/11/23 23:07:31 jmcneill Exp $");
#ifdef _KERNEL_OPT
#include "opt_sparc_arch.h"
@@ -38,8 +38,9 @@ __KERNEL_RCSID(0, "$NetBSD: cs4231_ebus.c,v 1.34 2011/06/02 00:23:28 christos Ex
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/device.h>
-#include <sys/malloc.h>
#include <sys/cpu.h>
+#include <sys/kmem.h>
+#include <sys/malloc.h>
#include <machine/autoconf.h>
@@ -122,7 +123,7 @@ const struct audio_hw_if audiocs_ebus_hw_if = {
cs4231_ebus_trigger_output,
cs4231_ebus_trigger_input,
NULL, /* dev_ioctl */
- NULL, /* powerstate */
+ ad1848_get_locks,
};
#ifdef AUDIO_DEBUG
@@ -247,6 +248,8 @@ cs4231_ebus_attach(device_t parent, device_t self, void *aux)
return;
}
+ ad1848_init_locks(&sc->sc_ad1848, IPL_SCHED);
+
/* establish interrupt channels */
for (i = 0; i < ea->ea_nintr; ++i)
bus_intr_establish(ea->ea_bustag,
@@ -540,6 +543,8 @@ cs4231_ebus_intr(void *arg)
ebsc = arg;
sc = &ebsc->sc_cs4231;
+ mutex_spin_enter(&sc->sc_ad1848.sc_intr_lock);
+
status = ADREAD(&sc->sc_ad1848, AD1848_STATUS);
#ifdef AUDIO_DEBUG
@@ -580,6 +585,7 @@ cs4231_ebus_intr(void *arg)
ret = 1;
}
+ mutex_spin_exit(&sc->sc_ad1848.sc_intr_lock);
return ret;
}
@@ -590,10 +596,10 @@ cs4231_ebus_pint(void *cookie)
struct cs4231_softc *sc = cookie;
struct cs_transfer *t = &sc->sc_playback;
- KERNEL_LOCK(1, NULL);
+ mutex_spin_enter(&sc->sc_ad1848.sc_intr_lock);
if (t->t_intr != NULL)
(*t->t_intr)(t->t_arg);
- KERNEL_UNLOCK_ONE(NULL);
+ mutex_spin_exit(&sc->sc_ad1848.sc_intr_lock);
return 0;
}
@@ -603,9 +609,9 @@ cs4231_ebus_rint(void *cookie)
struct cs4231_softc *sc = cookie;
struct cs_transfer *t = &sc->sc_capture;
- KERNEL_LOCK(1, NULL);
+ mutex_spin_enter(&sc->sc_ad1848.sc_intr_lock);
if (t->t_intr != NULL)
(*t->t_intr)(t->t_arg);
- KERNEL_UNLOCK_ONE(NULL);
+ mutex_spin_exit(&sc->sc_ad1848.sc_intr_lock);
return 0;
}
diff --git a/sys/dev/ic/ac97.c b/sys/dev/ic/ac97.c
index 93ed0adeb9e..18ea89766cf 100644
--- a/sys/dev/ic/ac97.c
+++ b/sys/dev/ic/ac97.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ac97.c,v 1.91 2009/07/13 12:54:11 kiyohara Exp $ */
+/* $NetBSD: ac97.c,v 1.92 2011/11/23 23:07:31 jmcneill Exp $ */
/* $OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $ */
/*
@@ -63,7 +63,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.91 2009/07/13 12:54:11 kiyohara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.92 2011/11/23 23:07:31 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -501,6 +501,8 @@ struct ac97_softc {
struct ac97_host_if *host_if;
+ kmutex_t *lock;
+
#define AUDIO_MAX_SOURCES (2 * AUDIO_SOURCE_INFO_SIZE)
#define MODEM_MAX_SOURCES (2 * MODEM_SOURCE_INFO_SIZE)
struct ac97_source_info audio_source_info[AUDIO_MAX_SOURCES];
@@ -930,6 +932,8 @@ static const char *ac97_register_names[0x80 / 2] = {
static void
ac97_read(struct ac97_softc *as, uint8_t reg, uint16_t *val)
{
+ KASSERT(mutex_owned(as->lock));
+
if (as->host_flags & AC97_HOST_DONT_READ &&
(reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
reg != AC97_REG_RESET)) {
@@ -945,6 +949,8 @@ ac97_read(struct ac97_softc *as, uint8_t reg, uint16_t *val)
static int
ac97_write(struct ac97_softc *as, uint8_t reg, uint16_t val)
{
+ KASSERT(mutex_owned(as->lock));
+
#ifndef AC97_IO_DEBUG
as->shadow_reg[reg >> 1] = val;
return as->host_if->write(as->host_if->arg, reg, val);
@@ -969,6 +975,8 @@ ac97_setup_defaults(struct ac97_softc *as)
int idx;
const struct ac97_source_info *si;
+ KASSERT(mutex_owned(as->lock));
+
memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
for (idx = 0; idx < AUDIO_SOURCE_INFO_SIZE; idx++) {
@@ -993,6 +1001,8 @@ ac97_restore_shadow(struct ac97_codec_if *self)
as = (struct ac97_softc *) self;
+ KASSERT(mutex_owned(as->lock));
+
if (as->type == AC97_CODEC_TYPE_AUDIO) {
/* restore AC97_REG_POWER */
ac97_write(as, AC97_REG_POWER, as->power_reg);
@@ -1092,6 +1102,8 @@ ac97_setup_source_info(struct ac97_softc *as)
struct ac97_source_info *si, *si2;
uint16_t value1, value2, value3;
+ KASSERT(mutex_owned(as->lock));
+
for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE(as); idx++) {
si = &as->source_info[ouridx];
if (as->type == AC97_CODEC_TYPE_MODEM) {
@@ -1210,13 +1222,13 @@ ac97_setup_source_info(struct ac97_softc *as)
/* backward compatibility */
int
-ac97_attach(struct ac97_host_if *host_if, device_t sc_dev)
+ac97_attach(struct ac97_host_if *host_if, device_t sc_dev, kmutex_t *lk)
{
- return ac97_attach_type(host_if, sc_dev, AC97_CODEC_TYPE_AUDIO);
+ return ac97_attach_type(host_if, sc_dev, AC97_CODEC_TYPE_AUDIO, lk);
}
int
-ac97_attach_type(struct ac97_host_if *host_if, device_t sc_dev, int type)
+ac97_attach_type(struct ac97_host_if *host_if, device_t sc_dev, int type, kmutex_t *lk)
{
struct ac97_softc *as;
int error, i, j;
@@ -1238,14 +1250,18 @@ ac97_attach_type(struct ac97_host_if *host_if, device_t sc_dev, int type)
as->codec_if.vtbl = &ac97civ;
as->host_if = host_if;
as->type = type;
+ as->lock = lk;
if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
free(as, M_DEVBUF);
return error;
}
+ mutex_enter(as->lock);
+
if (host_if->reset != NULL) {
if ((error = host_if->reset(host_if->arg))) {
+ mutex_exit(as->lock);
free(as, M_DEVBUF);
return error;
}
@@ -1295,6 +1311,8 @@ ac97_attach_type(struct ac97_host_if *host_if, device_t sc_dev, int type)
ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
+ mutex_exit(as->lock);
+
id = (id1 << 16) | id2;
aprint_normal_dev(sc_dev, "ac97: ");
@@ -1333,9 +1351,13 @@ ac97_attach_type(struct ac97_host_if *host_if, device_t sc_dev, int type)
as->ac97_clock = AC97_STANDARD_CLOCK;
+ mutex_enter(as->lock);
+
if (as->type == AC97_CODEC_TYPE_AUDIO) {
ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
if (as->ext_id != 0) {
+ mutex_exit(as->lock);
+
/* Print capabilities */
snprintb(flagbuf, sizeof(flagbuf),
"\20\20SECONDARY10\17SECONDARY01"
@@ -1364,6 +1386,8 @@ ac97_attach_type(struct ac97_host_if *host_if, device_t sc_dev, int type)
"AC97_POWER_EAMP bit\n");
}
+ mutex_enter(as->lock);
+
/* Enable and disable features */
ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
extstat &= ~AC97_EXT_AUDIO_DRA;
@@ -1414,6 +1438,8 @@ ac97_attach_type(struct ac97_host_if *host_if, device_t sc_dev, int type)
int err;
ac97_read(as, AC97_REG_EXT_MODEM_ID, &as->ext_mid);
+ mutex_exit(as->lock);
+
if (as->ext_mid == 0 || as->ext_mid == 0xffff) {
aprint_normal_dev(sc_dev, "no modem codec found\n");
return ENXIO;
@@ -1442,6 +1468,8 @@ ac97_attach_type(struct ac97_host_if *host_if, device_t sc_dev, int type)
if (err != 0)
goto setup_modem;
setup_modem:
+ mutex_enter(as->lock);
+
/* reset */
ac97_write(as, AC97_REG_EXT_MODEM_ID, 1);
@@ -1472,6 +1500,7 @@ setup_modem:
DELAY(1);
}
if (i <= 0) {
+ mutex_exit(as->lock);
printf("%s: codec not responding, status=0x%x\n",
device_xname(sc_dev), reg);
return ENXIO;
@@ -1486,6 +1515,7 @@ setup_modem:
reg &= ~AC97_GPIO_LINE1_OH;
ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
+ mutex_exit(as->lock);
err = sysctl_createv(&as->log, 0, NULL, &node_line1,
CTLFLAG_READWRITE, CTLTYPE_INT,
"line1",
@@ -1493,6 +1523,8 @@ setup_modem:
ac97_sysctl_verify, 0, as, 0,
CTL_HW, node->sysctl_num,
CTL_CREATE, CTL_EOL);
+ mutex_enter(as->lock);
+
if (err != 0)
goto sysctl_err;
as->offhook_line1_mib = node_line1->sysctl_num;
@@ -1505,6 +1537,7 @@ setup_modem:
reg &= ~AC97_GPIO_LINE2_OH;
ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
+ mutex_exit(as->lock);
err = sysctl_createv(&as->log, 0, NULL, &node_line2,
CTLFLAG_READWRITE, CTLTYPE_INT,
"line2",
@@ -1512,6 +1545,8 @@ setup_modem:
ac97_sysctl_verify, 0, as, 0,
CTL_HW, node->sysctl_num,
CTL_CREATE, CTL_EOL);
+ mutex_enter(as->lock);
+
if (err != 0)
goto sysctl_err;
as->offhook_line2_mib = node_line2->sysctl_num;
@@ -1585,6 +1620,8 @@ sysctl_err:
if (as->type == AC97_CODEC_TYPE_AUDIO)
ac97_write(as, AC97_REG_POWER, as->power_reg);
+ mutex_exit(as->lock);
+
return 0;
}
@@ -1594,10 +1631,14 @@ ac97_detach(struct ac97_codec_if *codec_if)
struct ac97_softc *as;
as = (struct ac97_softc *)codec_if;
+
+ mutex_enter(as->lock);
ac97_write(as, AC97_REG_POWER, AC97_POWER_IN | AC97_POWER_OUT
| AC97_POWER_MIXER | AC97_POWER_MIXER_VREF
| AC97_POWER_ACLINK | AC97_POWER_CLK | AC97_POWER_AUX
| POWER_EAMP_OFF(as));
+ mutex_exit(as->lock);
+
free(as, M_DEVBUF);
}
@@ -1607,6 +1648,9 @@ ac97_lock(struct ac97_codec_if *codec_if)
struct ac97_softc *as;
as = (struct ac97_softc *)codec_if;
+
+ KASSERT(mutex_owned(as->lock));
+
as->lock_counter++;
}
@@ -1616,6 +1660,9 @@ ac97_unlock(struct ac97_codec_if *codec_if)
struct ac97_softc *as;
as = (struct ac97_softc *)codec_if;
+
+ KASSERT(mutex_owned(as->lock));
+
as->lock_counter--;
}
@@ -1669,6 +1716,9 @@ ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
bool spdif;
as = (struct ac97_softc *)codec_if;
+
+ KASSERT(mutex_owned(as->lock));
+
if (cp->dev < 0 || cp->dev >= as->num_source_info)
return EINVAL;
si = &as->source_info[cp->dev];
@@ -1777,6 +1827,9 @@ ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, const char *class,
int idx;
as = (struct ac97_softc *)codec_if;
+
+ KASSERT(mutex_owned(as->lock));
+
for (idx = 0; idx < as->num_source_info; idx++) {
struct ac97_source_info *si = &as->source_info[idx];
if (ac97_str_equal(class, si->class) &&
@@ -1797,6 +1850,9 @@ ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
uint16_t val;
as = (struct ac97_softc *)codec_if;
+
+ KASSERT(mutex_owned(as->lock));
+
si = &as->source_info[cp->dev];
if (cp->dev < 0 || cp->dev >= as->num_source_info)
return EINVAL;
@@ -1875,6 +1931,9 @@ ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_int *rate)
uint16_t power_bit;
as = (struct ac97_softc *)codec_if;
+
+ KASSERT(mutex_owned(as->lock));
+
if (target == AC97_REG_PCM_MIC_ADC_RATE) {
if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
*rate = AC97_SINGLE_RATE;
@@ -1969,6 +2028,9 @@ ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
struct ac97_softc *as;
as = (struct ac97_softc *)codec_if;
+
+ KASSERT(mutex_owned(as->lock));
+
as->ac97_clock = clock;
}
@@ -1978,6 +2040,9 @@ ac97_get_extcaps(struct ac97_codec_if *codec_if)
struct ac97_softc *as;
as = (struct ac97_softc *)codec_if;
+
+ KASSERT(mutex_owned(as->lock));
+
return as->ext_id;
}
@@ -1987,6 +2052,8 @@ ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src)
struct ac97_source_info *si;
int ouridx, idx;
+ KASSERT(mutex_owned(as->lock));
+
if ((as->type == AC97_CODEC_TYPE_AUDIO &&
as->num_source_info >= AUDIO_MAX_SOURCES) ||
(as->type == AC97_CODEC_TYPE_MODEM &&
@@ -2064,6 +2131,8 @@ ac97_ad198x_init(struct ac97_softc *as)
int i;
uint16_t misc;
+ KASSERT(mutex_owned(as->lock));
+
ac97_read(as, AD1980_REG_MISC, &misc);
ac97_write(as, AD1980_REG_MISC,
misc | AD1980_MISC_LOSEL | AD1980_MISC_HPSEL);
@@ -2193,6 +2262,8 @@ ac97_vt1616_init(struct ac97_softc *as)
0x0000, 1, 12, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
};
+ KASSERT(mutex_owned(as->lock));
+
ac97_add_port(as, &sources[0]);
ac97_add_port(as, &sources[1]);
ac97_add_port(as, &sources[2]);
@@ -2203,6 +2274,8 @@ ac97_modem_offhook_set(struct ac97_softc *as, int line, int newval)
{
uint16_t val;
+ KASSERT(mutex_owned(as->lock));
+
val = as->shadow_reg[AC97_REG_GPIO_STATUS >> 1];
switch (newval) {
case 0:
@@ -2237,7 +2310,9 @@ ac97_sysctl_verify(SYSCTLFN_ARGS)
return EINVAL;
as->offhook_line1 = tmp;
+ mutex_enter(as->lock);
ac97_modem_offhook_set(as, AC97_GPIO_LINE1_OH, tmp);
+ mutex_exit(as->lock);
} else if (node.sysctl_num == as->offhook_line2_mib) {
tmp = as->offhook_line2;
node.sysctl_data = &tmp;
@@ -2249,7 +2324,9 @@ ac97_sysctl_verify(SYSCTLFN_ARGS)
return EINVAL;
as->offhook_line2 = tmp;
+ mutex_enter(as->lock);
ac97_modem_offhook_set(as, AC97_GPIO_LINE2_OH, tmp);
+ mutex_exit(as->lock);
}
return 0;
diff --git a/sys/dev/ic/ac97var.h b/sys/dev/ic/ac97var.h
index ed78b5d2094..bbfd7d4d7f0 100644
--- a/sys/dev/ic/ac97var.h
+++ b/sys/dev/ic/ac97var.h
@@ -1,4 +1,4 @@
-/* $NetBSD: ac97var.h,v 1.21 2009/05/12 14:25:17 cegger Exp $ */
+/* $NetBSD: ac97var.h,v 1.22 2011/11/23 23:07:32 jmcneill Exp $ */
/* $OpenBSD: ac97.h,v 1.4 2000/07/19 09:01:35 csapuntz Exp $ */
/*
@@ -93,8 +93,8 @@ struct ac97_codec_if {
};
struct device;
-int ac97_attach_type(struct ac97_host_if *, device_t, int);
-int ac97_attach(struct ac97_host_if *, device_t);
+int ac97_attach_type(struct ac97_host_if *, device_t, int, kmutex_t *);
+int ac97_attach(struct ac97_host_if *, device_t, kmutex_t *);
#define AC97_IS_FIXED_RATE(codec) \
!((codec)->vtbl->get_extcaps(codec) & AC97_EXT_AUDIO_VRA)
diff --git a/sys/dev/ic/ad1848.c b/sys/dev/ic/ad1848.c
index 0f6e8fa9e0a..4b82f0f7eb2 100644
--- a/sys/dev/ic/ad1848.c
+++ b/sys/dev/ic/ad1848.c
@@ -1,7 +1,7 @@
-/* $NetBSD: ad1848.c,v 1.30 2011/04/27 07:47:33 plunky Exp $ */
+/* $NetBSD: ad1848.c,v 1.31 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
- * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -91,11 +91,11 @@
* Portions of this code are from the VOXware support for the ad1848
* by Hannu Savolainen <hannu@voxware.pp.fi>
*
- * Portions also supplied from the SoundBlaster driver for NetBSD.
+ * Portions also ripped from the SoundBlaster driver for NetBSD.
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ad1848.c,v 1.30 2011/04/27 07:47:33 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ad1848.c,v 1.31 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -1051,9 +1051,6 @@ ad1848_open(void *addr, int flags)
return 0;
}
-/*
- * Close function is called at splaudio().
- */
void
ad1848_close(void *addr)
{
@@ -1085,13 +1082,12 @@ ad1848_commit_settings(void *addr)
struct ad1848_softc *sc;
int timeout;
u_char fs;
- int s;
sc = addr;
if (!sc->need_commit)
return 0;
- s = splaudio();
+ mutex_spin_enter(&sc->sc_intr_lock);
ad1848_mute_wave_output(sc, WAVE_MUTE0, 1);
@@ -1155,9 +1151,10 @@ ad1848_commit_settings(void *addr)
ad1848_mute_wave_output(sc, WAVE_MUTE0, 0);
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
sc->need_commit = 0;
+
return 0;
}
@@ -1288,3 +1285,29 @@ ad1848_halt_input(void *addr)
return 0;
}
+
+void
+ad1848_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct ad1848_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
+void
+ad1848_init_locks(struct ad1848_softc *sc, int ipl)
+{
+
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, ipl);
+}
+
+void
+ad1848_destroy_locks(struct ad1848_softc *sc)
+{
+
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
+}
diff --git a/sys/dev/ic/ad1848var.h b/sys/dev/ic/ad1848var.h
index 58f7ae4f7d7..e9d1f56e888 100644
--- a/sys/dev/ic/ad1848var.h
+++ b/sys/dev/ic/ad1848var.h
@@ -1,7 +1,7 @@
-/* $NetBSD: ad1848var.h,v 1.17 2011/06/02 00:23:28 christos Exp $ */
+/* $NetBSD: ad1848var.h,v 1.18 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
- * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -96,6 +96,8 @@ struct ad1848_volume {
struct ad1848_softc {
device_t sc_dev; /* base device */
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
bus_space_tag_t sc_iot; /* tag */
bus_space_handle_t sc_ioh; /* handle */
@@ -190,10 +192,13 @@ int ad1848_get_mic_gain(struct ad1848_softc *, struct ad1848_volume *);
void ad1848_mute_channel(struct ad1848_softc *, int, int);
int ad1848_to_vol(mixer_ctrl_t *, struct ad1848_volume *);
int ad1848_from_vol(mixer_ctrl_t *, struct ad1848_volume *);
+void ad1848_init_locks(struct ad1848_softc *, int);
+void ad1848_destroy_locks(struct ad1848_softc *);
int ad1848_halt_output(void *);
int ad1848_halt_input(void *);
paddr_t ad1848_mappage(void *, void *, off_t, int);
+void ad1848_get_locks(void *, kmutex_t **, kmutex_t **);
#ifdef AUDIO_DEBUG
void ad1848_dump_regs(struct ad1848_softc *);
diff --git a/sys/dev/ic/am7930.c b/sys/dev/ic/am7930.c
index d1af7cef278..364176a91f5 100644
--- a/sys/dev/ic/am7930.c
+++ b/sys/dev/ic/am7930.c
@@ -1,4 +1,4 @@
-/* $NetBSD: am7930.c,v 1.50 2007/10/19 11:59:46 ad Exp $ */
+/* $NetBSD: am7930.c,v 1.51 2011/11/23 23:07:32 jmcneill Exp $ */
/*
* Copyright (c) 1995 Rolf Grossmann
@@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: am7930.c,v 1.50 2007/10/19 11:59:46 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: am7930.c,v 1.51 2011/11/23 23:07:32 jmcneill Exp $");
#include "audio.h"
#if NAUDIO > 0
@@ -190,6 +190,8 @@ am7930_init(struct am7930_softc *sc, int flag)
AM7930_MCR4_INT_ENABLE);
}
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
}
int
@@ -288,7 +290,7 @@ am7930_commit_settings(void *addr)
struct am7930_softc *sc;
uint16_t ger, gr, gx, stgr;
uint8_t mmr2, mmr3;
- int s, level;
+ int level;
DPRINTF(("sa_commit.\n"));
sc = addr;
@@ -304,7 +306,7 @@ am7930_commit_settings(void *addr)
gr = gx_coeff[level];
}
- s = splaudio();
+ mutex_enter(&sc->sc_intr_lock);
mmr2 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR2);
if (sc->sc_out_port == AUDIOAMD_SPEAKER_VOL)
@@ -329,7 +331,7 @@ am7930_commit_settings(void *addr)
AM7930_IWRITE16(sc, AM7930_IREG_MAP_GR, gr);
AM7930_IWRITE16(sc, AM7930_IREG_MAP_GER, ger);
- splx(s);
+ mutex_exit(&sc->sc_intr_lock);
return 0;
}
diff --git a/sys/dev/ic/am7930var.h b/sys/dev/ic/am7930var.h
index 3294790fc2e..889484bae6c 100644
--- a/sys/dev/ic/am7930var.h
+++ b/sys/dev/ic/am7930var.h
@@ -1,4 +1,4 @@
-/* $NetBSD: am7930var.h,v 1.12 2011/06/04 01:27:57 tsutsui Exp $ */
+/* $NetBSD: am7930var.h,v 1.13 2011/11/23 23:07:32 jmcneill Exp $ */
struct am7930_softc;
@@ -24,6 +24,9 @@ struct am7930_softc {
uint8_t sc_mic_mute;
struct am7930_glue *sc_glue;
+
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
};
extern int am7930debug;
diff --git a/sys/dev/ic/attimer.c b/sys/dev/ic/attimer.c
index f979ff64418..fcd531d4a68 100644
--- a/sys/dev/ic/attimer.c
+++ b/sys/dev/ic/attimer.c
@@ -1,4 +1,4 @@
-/* $NetBSD: attimer.c,v 1.10 2009/04/07 22:30:09 dyoung Exp $ */
+/* $NetBSD: attimer.c,v 1.11 2011/11/23 23:07:32 jmcneill Exp $ */
/*
* Copyright (c) 2005 The NetBSD Foundation.
@@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: attimer.c,v 1.10 2009/04/07 22:30:09 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: attimer.c,v 1.11 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -79,6 +79,8 @@ attimer_detach(device_t self, int flags)
*
* There's not much at risk here, as there's about no chance to have a
* computer with more than one pcppi/attimer accessible.
+ *
+ * Caller provides locking for this routine.
*/
device_t
@@ -108,18 +110,19 @@ attimer_detach_speaker(device_t dev)
sc->sc_flags &= ~ATT_ATTACHED;
}
+/*
+ * Caller provides locking for this routine.
+ */
+
void
attimer_set_pitch(device_t dev, int pitch)
{
struct attimer_softc *sc = device_private(dev);
- int s;
- s = splhigh();
bus_space_write_1(sc->sc_iot, sc->sc_ioh, TIMER_MODE,
TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
bus_space_write_1(sc->sc_iot, sc->sc_ioh, TIMER_CNTR2,
TIMER_DIV(pitch) % 256);
bus_space_write_1(sc->sc_iot, sc->sc_ioh, TIMER_CNTR2,
TIMER_DIV(pitch) / 256);
- splx(s);
}
diff --git a/sys/dev/ic/cs4231.c b/sys/dev/ic/cs4231.c
index d7e03466ac9..67766cbeb35 100644
--- a/sys/dev/ic/cs4231.c
+++ b/sys/dev/ic/cs4231.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cs4231.c,v 1.26 2011/06/02 00:23:28 christos Exp $ */
+/* $NetBSD: cs4231.c,v 1.27 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
* Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cs4231.c,v 1.26 2011/06/02 00:23:28 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cs4231.c,v 1.27 2011/11/23 23:07:32 jmcneill Exp $");
#include "audio.h"
#if NAUDIO > 0
@@ -39,8 +39,9 @@ __KERNEL_RCSID(0, "$NetBSD: cs4231.c,v 1.26 2011/06/02 00:23:28 christos Exp $")
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/device.h>
-#include <sys/malloc.h>
#include <sys/bus.h>
+#include <sys/kmem.h>
+#include <sys/malloc.h>
#include <machine/autoconf.h>
#include <sys/cpu.h>
@@ -175,8 +176,7 @@ cs4231_common_attach(struct cs4231_softc *sc, device_t self,
}
void *
-cs4231_malloc(void *addr, int direction, size_t size,
- struct malloc_type *pool, int flags)
+cs4231_malloc(void *addr, int direction, size_t size)
{
struct cs4231_softc *sc;
bus_dma_tag_t dmatag;
@@ -184,7 +184,7 @@ cs4231_malloc(void *addr, int direction, size_t size,
sc = addr;
dmatag = sc->sc_dmatag;
- p = malloc(sizeof(*p), pool, flags);
+ p = kmem_alloc(sizeof(*p), KM_SLEEP);
if (p == NULL)
return NULL;
@@ -221,12 +221,12 @@ fail3:
fail2:
bus_dmamap_destroy(dmatag, p->dmamap);
fail1:
- free(p, pool);
+ kmem_free(p, size);
return NULL;
}
void
-cs4231_free(void *addr, void *ptr, struct malloc_type *pool)
+cs4231_free(void *addr, void *ptr, size_t size)
{
struct cs4231_softc *sc;
bus_dma_tag_t dmatag;
@@ -242,7 +242,7 @@ cs4231_free(void *addr, void *ptr, struct malloc_type *pool)
bus_dmamem_free(dmatag, p->segs, p->nsegs);
bus_dmamap_destroy(dmatag, p->dmamap);
*pp = p->next;
- free(p, pool);
+ kmem_free(p, size);
return;
}
printf("cs4231_free: rogue pointer\n");
diff --git a/sys/dev/ic/cs4231var.h b/sys/dev/ic/cs4231var.h
index 4bf600e078c..58a227e0f7c 100644
--- a/sys/dev/ic/cs4231var.h
+++ b/sys/dev/ic/cs4231var.h
@@ -1,4 +1,4 @@
-/* $NetBSD: cs4231var.h,v 1.9 2011/06/02 00:23:28 christos Exp $ */
+/* $NetBSD: cs4231var.h,v 1.10 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
* Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
@@ -108,7 +108,7 @@ int cs4231_get_port(void *, mixer_ctrl_t *);
int cs4231_query_devinfo(void *, mixer_devinfo_t *);
int cs4231_get_props(void *);
-void *cs4231_malloc(void *, int, size_t, struct malloc_type *, int);
-void cs4231_free(void *, void *, struct malloc_type *);
+void *cs4231_malloc(void *, int, size_t);
+void cs4231_free(void *, void *, size_t);
#endif /* _DEV_IC_CS4231VAR_H_ */
diff --git a/sys/dev/ic/interwave.c b/sys/dev/ic/interwave.c
index f1771540f31..bab58f12154 100644
--- a/sys/dev/ic/interwave.c
+++ b/sys/dev/ic/interwave.c
@@ -1,7 +1,7 @@
-/* $NetBSD: interwave.c,v 1.34 2009/03/14 15:36:17 dsl Exp $ */
+/* $NetBSD: interwave.c,v 1.35 2011/11/23 23:07:32 jmcneill Exp $ */
/*
- * Copyright (c) 1997, 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1997, 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Author: Kari Mettinen
@@ -29,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: interwave.c,v 1.34 2009/03/14 15:36:17 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: interwave.c,v 1.35 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -42,11 +42,12 @@ __KERNEL_RCSID(0, "$NetBSD: interwave.c,v 1.34 2009/03/14 15:36:17 dsl Exp $");
#include <sys/fcntl.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
-
#include <sys/cpu.h>
#include <sys/intr.h>
-#include <machine/pio.h>
#include <sys/audioio.h>
+
+#include <machine/pio.h>
+
#include <dev/audio_if.h>
#include <dev/mulaw.h>
@@ -114,6 +115,9 @@ iwintr(void *arg)
sc = arg;
val = 0;
intrs = 0;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
+
IW_READ_DIRECT_1(6, sc->p2xr_h, intrs); /* UISR */
/* codec ints */
@@ -151,8 +155,10 @@ iwintr(void *arg)
sc->sc_playintr(sc->sc_playarg);
val = 1;
}
- return val;
+ mutex_spin_exit(&sc->sc_intr_lock);
+
+ return val;
}
void
@@ -185,6 +191,9 @@ iwattach(struct iw_softc *sc)
sc->sc_dma_flags = 0;
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
/*
* We can only use a few selected irqs, see if we got one from pnp
* code that suits us.
@@ -192,11 +201,13 @@ iwattach(struct iw_softc *sc)
if (sc->sc_irq > 0) {
sc->sc_ih = isa_intr_establish(sc->sc_p2xr_ic,
- sc->sc_irq, IST_EDGE, IPL_AUDIO, iwintr, sc);
+ sc->sc_irq, IST_EDGE, IPL_SCHED, iwintr, sc);
got_irq = 1;
}
if (!got_irq) {
printf("\niwattach: couldn't get a suitable irq\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
printf("\n");
@@ -885,9 +896,6 @@ void
iw_trigger_dma(struct iw_softc *sc, u_char io)
{
u_char reg;
- int s;
-
- s = splaudio();
IW_READ_CODEC_1(CSR3I, reg);
IW_WRITE_CODEC_1(CSR3I, reg & ~(io == IW_DMA_PLAYBACK ? 0x10 : 0x20));
@@ -899,8 +907,6 @@ iw_trigger_dma(struct iw_softc *sc, u_char io)
/* let the counter run */
IW_READ_CODEC_1(CFIG2I, reg);
IW_WRITE_CODEC_1(CFIG2I, reg & ~(io << 4));
-
- splx(s);
}
void
@@ -1490,8 +1496,7 @@ iw_query_devinfo(void *addr, mixer_devinfo_t *dip)
void *
-iw_malloc(void *addr, int direction, size_t size,
- struct malloc_type *pool, int flags)
+iw_malloc(void *addr, int direction, size_t size)
{
struct iw_softc *sc;
int drq;
@@ -1501,13 +1506,14 @@ iw_malloc(void *addr, int direction, size_t size,
drq = sc->sc_playdrq;
else
drq = sc->sc_recdrq;
- return isa_malloc(sc->sc_ic, drq, size, pool, flags);
+ return isa_malloc(sc->sc_ic, drq, size, M_DEVBUF, M_WAITOK);
}
void
-iw_free(void *addr, void *ptr, struct malloc_type *pool)
+iw_free(void *addr, void *ptr, size_t size)
{
- isa_free(ptr, pool);
+
+ isa_free(ptr, M_DEVBUF);
}
size_t
@@ -1543,3 +1549,13 @@ iw_get_props(void *addr)
return AUDIO_PROP_MMAP |
(sc->sc_fullduplex ? AUDIO_PROP_FULLDUPLEX : 0);
}
+
+void
+iw_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct iw_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
diff --git a/sys/dev/ic/interwavevar.h b/sys/dev/ic/interwavevar.h
index 3d88e3ba029..7d9cad3ed11 100644
--- a/sys/dev/ic/interwavevar.h
+++ b/sys/dev/ic/interwavevar.h
@@ -1,7 +1,7 @@
-/* $NetBSD: interwavevar.h,v 1.16 2008/04/28 20:23:50 martin Exp $ */
+/* $NetBSD: interwavevar.h,v 1.17 2011/11/23 23:07:32 jmcneill Exp $ */
/*
- * Copyright (c) 1997, 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1997, 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Author: Kari Mettinen
@@ -78,6 +78,8 @@ struct iw_softc {
struct device sc_dev;
bus_space_tag_t sc_iot; /* bus cookie */
isa_chipset_tag_t sc_ic;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
int vers;
int revision;
@@ -231,10 +233,11 @@ int iw_get_port(void *, mixer_ctrl_t *);
int iw_query_devinfo(void *, mixer_devinfo_t *);
struct malloc_type;
-void * iw_malloc(void *, int, size_t, struct malloc_type *, int);
-void iw_free(void *,void *,struct malloc_type *);
+void * iw_malloc(void *, int, size_t);
+void iw_free(void *, void *, size_t);
size_t iw_round_buffersize(void *, int, size_t);
paddr_t iw_mappage(void *, void *, off_t, int);
int iw_get_props(void *);
+void iw_get_locks(void *, kmutex_t **, kmutex_t **);
#endif /* INTERWAVEVAR_H */
diff --git a/sys/dev/ic/joy.c b/sys/dev/ic/joy.c
index 7993f050695..7b90719e58d 100644
--- a/sys/dev/ic/joy.c
+++ b/sys/dev/ic/joy.c
@@ -1,4 +1,33 @@
-/* $NetBSD: joy.c,v 1.17 2008/03/26 18:27:07 xtraeme Exp $ */
+/* $NetBSD: joy.c,v 1.18 2011/11/23 23:07:32 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software developed for The NetBSD Foundation
+ * by Andrew Doran.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
/*-
* Copyright (c) 1995 Jean-Marc Zucconi
@@ -32,7 +61,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: joy.c,v 1.17 2008/03/26 18:27:07 xtraeme Exp $");
+__KERNEL_RCSID(0, "$NetBSD: joy.c,v 1.18 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -43,8 +72,8 @@ __KERNEL_RCSID(0, "$NetBSD: joy.c,v 1.17 2008/03/26 18:27:07 xtraeme Exp $");
#include <sys/event.h>
#include <sys/vnode.h>
#include <sys/bus.h>
-
#include <sys/joystick.h>
+
#include <dev/ic/joyvar.h>
/*
@@ -67,25 +96,34 @@ __KERNEL_RCSID(0, "$NetBSD: joy.c,v 1.17 2008/03/26 18:27:07 xtraeme Exp $");
extern struct cfdriver joy_cd;
-dev_type_open(joyopen);
-dev_type_close(joyclose);
-dev_type_read(joyread);
-dev_type_ioctl(joyioctl);
+static dev_type_open(joyopen);
+static dev_type_close(joyclose);
+static dev_type_read(joyread);
+static dev_type_ioctl(joyioctl);
const struct cdevsw joy_cdevsw = {
joyopen, joyclose, joyread, nowrite, joyioctl,
- nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
+ nostop, notty, nopoll, nommap, nokqfilter, D_OTHER | D_MPSAFE,
};
void
joyattach(struct joy_softc *sc)
{
- sc->timeout[0] = sc->timeout[1] = 0;
+
+ if (sc->sc_lock == NULL) {
+ panic("joyattach: no lock");
+ }
+
+ sc->timeout[0] = 0;
+ sc->timeout[1] = 0;
+
+ mutex_enter(sc->sc_lock);
bus_space_write_1(sc->sc_iot, sc->sc_ioh, 0, 0xff);
DELAY(10000); /* 10 ms delay */
aprint_normal_dev(sc->sc_dev, "joystick %sconnected\n",
(bus_space_read_1(sc->sc_iot, sc->sc_ioh, 0) & 0x0f) == 0x0f ?
"not " : "");
+ mutex_exit(sc->sc_lock);
}
int
@@ -101,7 +139,7 @@ joydetach(struct joy_softc *sc, int flags)
return 0;
}
-int
+static int
joyopen(dev_t dev, int flag, int mode, struct lwp *l)
{
int unit = JOYUNIT(dev);
@@ -112,26 +150,31 @@ joyopen(dev_t dev, int flag, int mode, struct lwp *l)
if (sc == NULL)
return ENXIO;
- if (sc->timeout[i])
+ mutex_enter(sc->sc_lock);
+ if (sc->timeout[i]) {
+ mutex_exit(sc->sc_lock);
return EBUSY;
-
+ }
sc->x_off[i] = sc->y_off[i] = 0;
sc->timeout[i] = JOY_TIMEOUT;
+ mutex_exit(sc->sc_lock);
return 0;
}
-int
+static int
joyclose(dev_t dev, int flag, int mode, struct lwp *l)
{
int unit = JOYUNIT(dev);
int i = JOYPART(dev);
struct joy_softc *sc = device_lookup_private(&joy_cd, unit);
+ mutex_enter(sc->sc_lock);
sc->timeout[i] = 0;
+ mutex_exit(sc->sc_lock);
return 0;
}
-int
+static int
joyread(dev_t dev, struct uio *uio, int flag)
{
int unit = JOYUNIT(dev);
@@ -139,11 +182,10 @@ joyread(dev_t dev, struct uio *uio, int flag)
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
struct joystick c;
- int i, s;
struct timeval start, now, diff;
- int state = 0, x = 0, y = 0;
+ int state = 0, x = 0, y = 0, i;
- s = splhigh(); /* XXX */
+ mutex_enter(sc->sc_lock);
bus_space_write_1(iot, ioh, 0, 0xff);
microtime(&start);
now = start; /* structure assignment */
@@ -163,7 +205,7 @@ joyread(dev_t dev, struct uio *uio, int flag)
break;
microtime(&now);
}
- splx(s); /* XXX */
+ mutex_exit(sc->sc_lock);
c.x = x ? sc->x_off[JOYPART(dev)] + x : 0x80000000;
c.y = y ? sc->y_off[JOYPART(dev)] + y : 0x80000000;
@@ -173,19 +215,22 @@ joyread(dev_t dev, struct uio *uio, int flag)
return uiomove(&c, sizeof(struct joystick), uio);
}
-int
+static int
joyioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
{
int unit = JOYUNIT(dev);
struct joy_softc *sc = device_lookup_private(&joy_cd, unit);
- int i = JOYPART(dev);
- int x;
+ int i = JOYPART(dev), x, error;
+ mutex_enter(sc->sc_lock);
+ error = 0;
switch (cmd) {
case JOY_SETTIMEOUT:
x = *(int *)data;
- if (x < 1 || x > 10000) /* 10ms maximum! */
- return EINVAL;
+ if (x < 1 || x > 10000) { /* 10ms maximum! */
+ error = EINVAL;
+ break;
+ }
sc->timeout[i] = x;
break;
case JOY_GETTIMEOUT:
@@ -204,7 +249,9 @@ joyioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
*(int *)data = sc->y_off[i];
break;
default:
- return ENXIO;
+ error = ENXIO;
+ break;
}
- return 0;
+ mutex_exit(sc->sc_lock);
+ return error;
}
diff --git a/sys/dev/ic/joyvar.h b/sys/dev/ic/joyvar.h
index 466200cabba..d7d741a3e78 100644
--- a/sys/dev/ic/joyvar.h
+++ b/sys/dev/ic/joyvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: joyvar.h,v 1.6 2008/03/26 18:27:07 xtraeme Exp $ */
+/* $NetBSD: joyvar.h,v 1.7 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
* Copyright (c) 1995 Jean-Marc Zucconi
@@ -40,6 +40,7 @@
struct joy_softc {
device_t sc_dev;
+ kmutex_t *sc_lock;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
int x_off[2], y_off[2];
diff --git a/sys/dev/ic/mpu.c b/sys/dev/ic/mpu.c
index a3bbda778c1..042502d650b 100644
--- a/sys/dev/ic/mpu.c
+++ b/sys/dev/ic/mpu.c
@@ -1,11 +1,11 @@
-/* $NetBSD: mpu.c,v 1.17 2008/04/28 20:23:50 martin Exp $ */
+/* $NetBSD: mpu.c,v 1.18 2011/11/23 23:07:32 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson (augustss@NetBSD.org).
+ * by Lennart Augustsson (augustss@NetBSD.org) and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mpu.c,v 1.17 2008/04/28 20:23:50 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mpu.c,v 1.18 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -81,6 +81,7 @@ static int mpu_open(void *, int,
static void mpu_close(void *);
static int mpu_output(void *, int);
static void mpu_getinfo(void *, struct midi_info *);
+static void mpu_get_locks(void *, kmutex_t **, kmutex_t **);
const struct midi_hw_if mpu_midi_hw_if = {
mpu_open,
@@ -88,6 +89,7 @@ const struct midi_hw_if mpu_midi_hw_if = {
mpu_output,
mpu_getinfo,
0, /* ioctl */
+ mpu_get_locks,
};
int
@@ -108,6 +110,11 @@ bad:
void
mpu_attach(struct mpu_softc *sc)
{
+
+ if (sc->lock == NULL) {
+ panic("mpu_attach: no lock");
+ }
+
midi_attach_mi(&mpu_midi_hw_if, sc, sc->sc_dev);
}
@@ -116,6 +123,8 @@ mpu_waitready(struct mpu_softc *sc)
{
int i;
+ KASSERT(mutex_owned(sc->lock));
+
for(i = 0; i < MPU_MAXWAIT; i++) {
if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_OUTPUT_BUSY))
return 0;
@@ -130,22 +139,20 @@ mpu_reset(struct mpu_softc *sc)
bus_space_tag_t iot = sc->iot;
bus_space_handle_t ioh = sc->ioh;
int i;
- int s;
+
+ KASSERT(mutex_owned(sc->lock));
if (mpu_waitready(sc)) {
DPRINTF(("%s: not ready\n", __func__));
return EIO;
}
- s = splaudio(); /* Don't let the interrupt get our ACK. */
bus_space_write_1(iot, ioh, MPU_COMMAND, MPU_RESET);
for(i = 0; i < 2*MPU_MAXWAIT; i++) {
if (!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY) &&
bus_space_read_1(iot, ioh, MPU_DATA) == MPU_ACK) {
- splx(s);
return 0;
}
}
- splx(s);
DPRINTF(("%s: No ACK\n", __func__));
return EIO;
}
@@ -158,6 +165,8 @@ mpu_open(void *addr, int flags, void (*iintr)(void *, int),
DPRINTF(("%s: sc=%p\n", __func__, sc));
+ KASSERT(mutex_owned(sc->lock));
+
if (sc->open)
return EBUSY;
#ifndef AUDIO_NO_POWER_CTL
@@ -186,6 +195,8 @@ mpu_close(void *addr)
DPRINTF(("%s: sc=%p\n", __func__, sc));
+ KASSERT(mutex_owned(sc->lock));
+
sc->open = 0;
sc->intr = 0;
mpu_reset(sc); /* exit UART mode */
@@ -203,6 +214,8 @@ mpu_readinput(struct mpu_softc *sc)
bus_space_handle_t ioh = sc->ioh;
int data;
+ KASSERT(mutex_owned(sc->lock));
+
while(!(MPU_GETSTATUS(iot, ioh) & MPU_INPUT_EMPTY)) {
data = bus_space_read_1(iot, ioh, MPU_DATA);
DPRINTFN(3, ("%s: sc=%p 0x%02x\n", __func__, sc, data));
@@ -215,13 +228,12 @@ static int
mpu_output(void *addr, int d)
{
struct mpu_softc *sc = addr;
- int s;
+
+ KASSERT(mutex_owned(sc->lock));
DPRINTFN(3, ("%s: sc=%p 0x%02x\n", __func__, sc, d));
if (!(MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY)) {
- s = splaudio();
mpu_readinput(sc);
- splx(s);
}
if (mpu_waitready(sc)) {
DPRINTF(("%s:: not ready\n", __func__));
@@ -236,15 +248,28 @@ mpu_getinfo(void *addr, struct midi_info *mi)
{
struct mpu_softc *sc = addr;
+ KASSERT(mutex_owned(sc->lock));
+
mi->name = sc->model;
mi->props = 0;
}
+static void
+mpu_get_locks(void *addr, kmutex_t **intr, kmutex_t **proc)
+{
+ struct mpu_softc *sc = addr;
+
+ *intr = sc->lock;
+ *proc = NULL;
+}
+
int
mpu_intr(void *addr)
{
struct mpu_softc *sc = addr;
+ KASSERT(mutex_owned(sc->lock));
+
if (MPU_GETSTATUS(sc->iot, sc->ioh) & MPU_INPUT_EMPTY) {
DPRINTF(("%s: no data\n", __func__));
return 0;
diff --git a/sys/dev/ic/mpuvar.h b/sys/dev/ic/mpuvar.h
index 3b7331b5ab6..9f3921b59de 100644
--- a/sys/dev/ic/mpuvar.h
+++ b/sys/dev/ic/mpuvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: mpuvar.h,v 1.10 2008/04/28 20:23:50 martin Exp $ */
+/* $NetBSD: mpuvar.h,v 1.11 2011/11/23 23:07:32 jmcneill Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -33,6 +33,7 @@ struct mpu_softc {
device_t sc_dev; /* base device */
bus_space_tag_t iot; /* tag */
bus_space_handle_t ioh; /* handle */
+ kmutex_t *lock;
const char *model;
int open;
void (*intr)(void *, int); /* midi input intr handler */
diff --git a/sys/dev/ic/msm6258.c b/sys/dev/ic/msm6258.c
index 8790f28c4b1..9d5d5733ce6 100644
--- a/sys/dev/ic/msm6258.c
+++ b/sys/dev/ic/msm6258.c
@@ -1,4 +1,4 @@
-/* $NetBSD: msm6258.c,v 1.16 2011/10/16 03:10:18 isaki Exp $ */
+/* $NetBSD: msm6258.c,v 1.17 2011/11/23 23:07:32 jmcneill Exp $ */
/*
* Copyright (c) 2001 Tetsuya Isaki. All rights reserved.
@@ -30,11 +30,11 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: msm6258.c,v 1.16 2011/10/16 03:10:18 isaki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: msm6258.c,v 1.17 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/systm.h>
#include <sys/device.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/select.h>
#include <sys/audioio.h>
@@ -51,7 +51,8 @@ struct msm6258_codecvar {
};
static stream_filter_t *msm6258_factory
- (int (*)(stream_fetcher_t *, audio_stream_t *, int));
+ (struct audio_softc *,
+ int (*)(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int));
static void msm6258_dtor(struct stream_filter *);
static inline uint8_t pcm2adpcm_step(struct msm6258_codecvar *, int16_t);
static inline int16_t adpcm2pcm_step(struct msm6258_codecvar *, uint8_t);
@@ -75,11 +76,12 @@ static const int adpcm_estimstep[16] = {
};
static stream_filter_t *
-msm6258_factory(int (*fetch_to)(stream_fetcher_t *, audio_stream_t *, int))
+msm6258_factory(struct audio_softc *asc,
+ int (*fetch_to)(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int))
{
struct msm6258_codecvar *this;
- this = malloc(sizeof(*this), M_DEVBUF, M_WAITOK | M_ZERO);
+ this = kmem_alloc(sizeof(struct msm6258_codecvar), KM_SLEEP);
this->base.base.fetch_to = fetch_to;
this->base.dtor = msm6258_dtor;
this->base.set_fetcher = stream_filter_set_fetcher;
@@ -91,7 +93,7 @@ static void
msm6258_dtor(struct stream_filter *this)
{
if (this != NULL)
- free(this, M_DEVBUF);
+ kmem_free(this, sizeof(struct msm6258_codecvar));
}
/*
@@ -132,15 +134,15 @@ pcm2adpcm_step(struct msm6258_codecvar *mc, int16_t a)
#define DEFINE_FILTER(name) \
static int \
-name##_fetch_to(stream_fetcher_t *, audio_stream_t *, int); \
+name##_fetch_to(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int); \
stream_filter_t * \
name(struct audio_softc *sc, const audio_params_t *from, \
const audio_params_t *to) \
{ \
- return msm6258_factory(name##_fetch_to); \
+ return msm6258_factory(sc, name##_fetch_to); \
} \
static int \
-name##_fetch_to(stream_fetcher_t *self, audio_stream_t *dst, int max_used)
+name##_fetch_to(struct audio_softc *asc, stream_fetcher_t *self, audio_stream_t *dst, int max_used)
DEFINE_FILTER(msm6258_slinear16_to_adpcm)
{
@@ -152,7 +154,7 @@ DEFINE_FILTER(msm6258_slinear16_to_adpcm)
this = (stream_filter_t *)self;
mc = (struct msm6258_codecvar *)self;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used * 4)))
+ if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used * 4)))
return err;
m = dst->end - dst->start;
m = min(m, max_used);
@@ -215,7 +217,7 @@ DEFINE_FILTER(msm6258_linear8_to_adpcm)
this = (stream_filter_t *)self;
mc = (struct msm6258_codecvar *)self;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used * 2)))
+ if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used * 2)))
return err;
m = dst->end - dst->start;
m = min(m, max_used);
@@ -286,7 +288,7 @@ DEFINE_FILTER(msm6258_adpcm_to_slinear16)
this = (stream_filter_t *)self;
mc = (struct msm6258_codecvar *)self;
max_used = (max_used + 3) & ~3; /* round up multiple of 4 */
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used / 4)))
+ if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used / 4)))
return err;
m = (dst->end - dst->start) & ~3;
m = min(m, max_used);
@@ -352,7 +354,7 @@ DEFINE_FILTER(msm6258_adpcm_to_linear8)
this = (stream_filter_t *)self;
mc = (struct msm6258_codecvar *)self;
max_used = (max_used + 1) & ~1; /* round up multiple of 4 */
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used / 2)))
+ if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used / 2)))
return err;
m = (dst->end - dst->start) & ~1;
m = min(m, max_used);
diff --git a/sys/dev/ic/opl.c b/sys/dev/ic/opl.c
index e2c505d31c0..dd67be7f905 100644
--- a/sys/dev/ic/opl.c
+++ b/sys/dev/ic/opl.c
@@ -1,11 +1,11 @@
-/* $NetBSD: opl.c,v 1.37 2009/09/01 21:48:02 jmcneill Exp $ */
+/* $NetBSD: opl.c,v 1.38 2011/11/23 23:07:32 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson (augustss@NetBSD.org).
+ * by Lennart Augustsson (augustss@NetBSD.org), and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: opl.c,v 1.37 2009/09/01 21:48:02 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: opl.c,v 1.38 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -44,7 +44,7 @@ __KERNEL_RCSID(0, "$NetBSD: opl.c,v 1.37 2009/09/01 21:48:02 jmcneill Exp $");
#include <sys/syslog.h>
#include <sys/device.h>
#include <sys/select.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/cpu.h>
#include <sys/bus.h>
@@ -142,24 +142,34 @@ opl_attach(struct opl_softc *sc)
{
int i;
- if (!opl_find(sc)) {
+ if (sc->lock == NULL) {
+ panic("opl_attach: no lock");
+ }
+
+ mutex_enter(sc->lock);
+ i = opl_find(sc);
+ mutex_exit(sc->lock);
+ if (i == 0) {
printf("\nopl: find failed\n");
return;
}
+ mutex_enter(sc->lock);
+ opl_reset(sc);
+ mutex_exit(sc->lock);
+
sc->syn.mets = &opl3_midi;
snprintf(sc->syn.name, sizeof(sc->syn.name), "%sYamaha OPL%d",
sc->syn.name, sc->model);
sc->syn.data = sc;
sc->syn.nvoice = sc->model == OPL_2 ? OPL2_NVOICE : OPL3_NVOICE;
+ sc->syn.lock = sc->lock;
midisyn_attach(&sc->mididev, &sc->syn);
/* Set up voice table */
for (i = 0; i < OPL3_NVOICE; i++)
sc->voices[i] = voicetab[i];
- opl_reset(sc);
-
aprint_normal(": model OPL%d", sc->model);
/* Set up panpot */
@@ -195,6 +205,9 @@ opl_command(struct opl_softc *sc, int offs, int addr, int data)
{
DPRINTFN(4, ("opl_command: sc=%p, offs=%d addr=0x%02x data=0x%02x\n",
sc, offs, addr, data));
+
+ KASSERT(!sc->lock || mutex_owned(sc->lock));
+
offs += sc->offs;
bus_space_write_1(sc->iot, sc->ioh, OPL_ADDR+offs, addr);
if (sc->model == OPL_2)
@@ -214,12 +227,12 @@ opl_match(bus_space_tag_t iot, bus_space_handle_t ioh, int offs)
struct opl_softc *sc;
int rv;
- sc = malloc(sizeof(*sc), M_TEMP, M_WAITOK|M_ZERO);
+ sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
sc->iot = iot;
sc->ioh = ioh;
sc->offs = offs;
rv = opl_find(sc);
- free(sc, M_TEMP);
+ kmem_free(sc, sizeof(*sc));
return rv;
}
@@ -286,6 +299,9 @@ void
opl_set_op_reg(struct opl_softc *sc, int base, int voice, int op, u_char value)
{
struct opl_voice *v = &sc->voices[voice];
+
+ KASSERT(mutex_owned(sc->lock));
+
opl_command(sc, v->iooffs, base + v->op[op], value);
}
@@ -293,6 +309,9 @@ void
opl_set_ch_reg(struct opl_softc *sc, int base, int voice, u_char value)
{
struct opl_voice *v = &sc->voices[voice];
+
+ KASSERT(mutex_owned(sc->lock));
+
opl_command(sc, v->iooffs, base + v->voiceno, value);
}
@@ -302,6 +321,8 @@ opl_load_patch(struct opl_softc *sc, int v)
{
const struct opl_operators *p = sc->voices[v].patch;
+ KASSERT(mutex_owned(sc->lock));
+
opl_set_op_reg(sc, OPL_AM_VIB, v, 0, p->ops[OO_CHARS+0]);
opl_set_op_reg(sc, OPL_AM_VIB, v, 1, p->ops[OO_CHARS+1]);
opl_set_op_reg(sc, OPL_KSL_LEVEL, v, 0, p->ops[OO_KSL_LEV+0]);
@@ -359,6 +380,8 @@ opl_reset(struct opl_softc *sc)
{
int i;
+ KASSERT(mutex_owned(sc->lock));
+
for (i = 1; i <= OPL_MAXREG; i++)
opl_command(sc, OPL_L, OPL_KEYON_BLOCK + i, 0);
@@ -378,6 +401,8 @@ oplsyn_open(midisyn *ms, int flags)
{
struct opl_softc *sc = ms->data;
+ KASSERT(mutex_owned(sc->lock));
+
DPRINTFN(2, ("oplsyn_open: %d\n", flags));
#ifndef AUDIO_NO_POWER_CTL
@@ -397,6 +422,8 @@ oplsyn_close(midisyn *ms)
DPRINTFN(2, ("oplsyn_close:\n"));
+ KASSERT(mutex_owned(sc->lock));
+
/*opl_reset(ms->data);*/
if (sc->spkrctl)
sc->spkrctl(sc->spkrarg, 0);
@@ -424,6 +451,9 @@ void
oplsyn_reset(void *addr)
{
struct opl_softc *sc = addr;
+
+ KASSERT(mutex_owned(sc->lock));
+
DPRINTFN(3, ("oplsyn_reset:\n"));
opl_reset(sc);
}
@@ -489,6 +519,8 @@ oplsyn_setv(midisyn *ms,
u_int8_t r20m, r20c, r40m, r40c, rA0, rB0;
u_int8_t vol0, vol1;
+ KASSERT(mutex_owned(sc->lock));
+
DPRINTFN(3, ("%s: %p %d %u %d\n", __func__, sc, voice,
mp, level_cB));
@@ -586,6 +618,8 @@ oplsyn_releasev(midisyn *ms, uint_fast16_t voice, uint_fast8_t vel)
struct opl_softc *sc = ms->data;
struct opl_voice *v;
+ KASSERT(mutex_owned(sc->lock));
+
DPRINTFN(1, ("%s: %p %d\n", __func__, sc, voice));
#ifdef DIAGNOSTIC
diff --git a/sys/dev/ic/oplvar.h b/sys/dev/ic/oplvar.h
index 30bc1b5bda3..43a41ae58ec 100644
--- a/sys/dev/ic/oplvar.h
+++ b/sys/dev/ic/oplvar.h
@@ -1,7 +1,7 @@
-/* $NetBSD: oplvar.h,v 1.15 2008/04/28 20:23:51 martin Exp $ */
+/* $NetBSD: oplvar.h,v 1.16 2011/11/23 23:07:32 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -44,6 +44,7 @@ struct opl_softc {
struct midi_softc mididev;
bus_space_tag_t iot;
bus_space_handle_t ioh;
+ kmutex_t *lock;
int offs;
int model;
#define OPL_2 2
diff --git a/sys/dev/ic/tms320av110.c b/sys/dev/ic/tms320av110.c
index 621dd303217..eb28cddffd2 100644
--- a/sys/dev/ic/tms320av110.c
+++ b/sys/dev/ic/tms320av110.c
@@ -1,4 +1,4 @@
-/* $NetBSD: tms320av110.c,v 1.21 2008/04/28 20:23:51 martin Exp $ */
+/* $NetBSD: tms320av110.c,v 1.22 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tms320av110.c,v 1.21 2008/04/28 20:23:51 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tms320av110.c,v 1.22 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -72,6 +72,7 @@ int tav_set_port(void *, mixer_ctrl_t *);
int tav_get_port(void *, mixer_ctrl_t *);
int tav_query_devinfo(void *, mixer_devinfo_t *);
int tav_get_props(void *);
+void tav_get_locks(void *, kmutex_t **, kmutex_t **);
const struct audio_hw_if tav_audio_if = {
tav_open,
@@ -98,7 +99,10 @@ const struct audio_hw_if tav_audio_if = {
0 /* round_buffersize */, /* optional */
0 /* mappage */, /* optional */
tav_get_props,
- 0 /* dev_ioctl */ /* optional */
+ 0, /* trigger_output */
+ 0, /* trigger_input */
+ 0, /* dev_ioctl */ /* optional */
+ tav_get_locks,
};
void
@@ -146,6 +150,9 @@ tms320av110_intr(void *p)
uint16_t intlist;
sc = p;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
+
intlist = tav_read_short(sc->sc_iot, sc->sc_ioh, TAV_INTR)
/* & tav_read_short(sc->sc_iot, sc->sc_ioh, TAV_INTR_EN)*/;
@@ -161,9 +168,11 @@ tms320av110_intr(void *p)
}
if (intlist & TAV_INTR_PCM_OUTPUT_UNDERFLOW) {
- wakeup(sc);
+ cv_broadcast(&sc->sc_cv);
}
+ mutex_spin_exit(&sc->sc_intr_lock);
+
return 1;
}
@@ -211,8 +220,10 @@ tav_drain(void *hdl)
iot = sc->sc_iot;
ioh = sc->sc_ioh;
+ mutex_spin_enter(&sc->sc_intr_lock);
+
/*
- * tsleep waiting for underflow interrupt.
+ * wait for underflow interrupt.
*/
if (tav_read_short(iot, ioh, TAV_BUFF)) {
mask = tav_read_short(iot, ioh, TAV_INTR_EN);
@@ -220,8 +231,10 @@ tav_drain(void *hdl)
mask|TAV_INTR_PCM_OUTPUT_UNDERFLOW);
/* still more than zero? */
- if (tav_read_short(iot, ioh, TAV_BUFF))
- (void)tsleep(sc, PCATCH, "tavdrain", 32*hz);
+ if (tav_read_short(iot, ioh, TAV_BUFF)) {
+ (void)cv_timedwait_sig(&sc->sc_cv,
+ &sc->sc_intr_lock, 32*hz);
+ }
/* can be really that long for mpeg */
@@ -230,6 +243,8 @@ tav_drain(void *hdl)
mask & ~TAV_INTR_PCM_OUTPUT_UNDERFLOW);
}
+ mutex_spin_exit(&sc->sc_intr_lock);
+
return 0;
}
@@ -371,6 +386,16 @@ tav_get_props(void *hdl)
return 0;
}
+void
+tav_get_locks(void *hdl, kmutex_t **intr, kmutex_t **thread)
+{
+ struct tav_softc *sc;
+
+ sc = hdl;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
int
tav_set_params(void *hdl, int setmode, int usemode, audio_params_t *p,
audio_params_t *r, stream_filter_list_t *pfil, stream_filter_list_t *rfil)
diff --git a/sys/dev/ic/tms320av110var.h b/sys/dev/ic/tms320av110var.h
index 3548c2ef7db..b8874746c4c 100644
--- a/sys/dev/ic/tms320av110var.h
+++ b/sys/dev/ic/tms320av110var.h
@@ -1,4 +1,4 @@
-/* $NetBSD: tms320av110var.h,v 1.10 2008/04/28 20:23:51 martin Exp $ */
+/* $NetBSD: tms320av110var.h,v 1.11 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -46,6 +46,9 @@
struct tav_softc {
struct device sc_dev;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
+ kcondvar_t sc_cv;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
diff --git a/sys/dev/isa/ad1848_isa.c b/sys/dev/isa/ad1848_isa.c
index 7218cec6e62..53c18519d51 100644
--- a/sys/dev/isa/ad1848_isa.c
+++ b/sys/dev/isa/ad1848_isa.c
@@ -1,7 +1,7 @@
-/* $NetBSD: ad1848_isa.c,v 1.37 2011/06/02 12:51:52 nonaka Exp $ */
+/* $NetBSD: ad1848_isa.c,v 1.38 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
- * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -95,7 +95,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ad1848_isa.c,v 1.37 2011/06/02 12:51:52 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ad1848_isa.c,v 1.38 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -105,11 +105,10 @@ __KERNEL_RCSID(0, "$NetBSD: ad1848_isa.c,v 1.37 2011/06/02 12:51:52 nonaka Exp $
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/buf.h>
-
#include <sys/cpu.h>
#include <sys/bus.h>
-
#include <sys/audioio.h>
+#include <sys/malloc.h>
#include <dev/audio_if.h>
#include <dev/auconv.h>
@@ -502,8 +501,10 @@ ad1848_isa_open(void *addr, int flags)
#ifndef AUDIO_NO_POWER_CTL
/* Power-up chip */
- if (isc->powerctl)
+ if (isc->powerctl) {
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
isc->powerctl(isc->powerarg, flags);
+ }
#endif
/* Init and mute wave output */
@@ -512,8 +513,10 @@ ad1848_isa_open(void *addr, int flags)
error = ad1848_open(sc, flags);
if (error) {
#ifndef AUDIO_NO_POWER_CTL
- if (isc->powerctl)
+ if (isc->powerctl) {
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
isc->powerctl(isc->powerarg, 0);
+ }
#endif
goto bad;
}
@@ -530,9 +533,6 @@ bad:
return error;
}
-/*
- * Close function is called at splaudio().
- */
void
ad1848_isa_close(void *addr)
{
@@ -546,8 +546,10 @@ ad1848_isa_close(void *addr)
#ifndef AUDIO_NO_POWER_CTL
/* Power-down chip */
- if (isc->powerctl)
+ if (isc->powerctl) {
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
isc->powerctl(isc->powerarg, 0);
+ }
#endif
if (isc->sc_playdrq != -1)
@@ -694,6 +696,9 @@ ad1848_isa_intr(void *arg)
isc = arg;
sc = &isc->sc_ad1848;
+
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
retval = 0;
/* Get intr status */
status = ADREAD(sc, AD1848_STATUS);
@@ -734,9 +739,7 @@ void *
ad1848_isa_malloc(
void *addr,
int direction,
- size_t size,
- struct malloc_type *pool,
- int flags)
+ size_t size)
{
struct ad1848_isa_softc *isc;
int drq;
@@ -746,14 +749,14 @@ ad1848_isa_malloc(
drq = isc->sc_playdrq;
else
drq = isc->sc_recdrq;
- return isa_malloc(isc->sc_ic, drq, size, pool, flags);
+ return isa_malloc(isc->sc_ic, drq, size, M_DEVBUF, M_WAITOK);
}
void
-ad1848_isa_free(void *addr, void *ptr, struct malloc_type *pool)
+ad1848_isa_free(void *addr, void *ptr, size_t size)
{
- isa_free(ptr, pool);
+ isa_free(ptr, M_DEVBUF);
}
size_t
diff --git a/sys/dev/isa/ad1848var.h b/sys/dev/isa/ad1848var.h
index f0b8662d299..1647ed8fc2b 100644
--- a/sys/dev/isa/ad1848var.h
+++ b/sys/dev/isa/ad1848var.h
@@ -1,4 +1,4 @@
-/* $NetBSD: ad1848var.h,v 1.43 2008/04/28 20:23:51 martin Exp $ */
+/* $NetBSD: ad1848var.h,v 1.44 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -114,8 +114,8 @@ int ad1848_isa_halt_input(void *);
int ad1848_isa_intr(void *);
-void *ad1848_isa_malloc(void *, int, size_t, struct malloc_type *, int);
-void ad1848_isa_free(void *, void *, struct malloc_type *);
+void *ad1848_isa_malloc(void *, int, size_t);
+void ad1848_isa_free(void *, void *, size_t);
size_t ad1848_isa_round_buffersize(void *, int, size_t);
paddr_t ad1848_isa_mappage(void *, void *, off_t, int);
int ad1848_isa_get_props(void *);
diff --git a/sys/dev/isa/aria.c b/sys/dev/isa/aria.c
index 85174129432..8c4f3ba73b3 100644
--- a/sys/dev/isa/aria.c
+++ b/sys/dev/isa/aria.c
@@ -1,4 +1,4 @@
-/* $NetBSD: aria.c,v 1.33 2010/07/27 05:38:18 jakllsch Exp $ */
+/* $NetBSD: aria.c,v 1.34 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
* Copyright (c) 1995, 1996, 1998 The NetBSD Foundation, Inc.
@@ -50,7 +50,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: aria.c,v 1.33 2010/07/27 05:38:18 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: aria.c,v 1.34 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -61,17 +61,15 @@ __KERNEL_RCSID(0, "$NetBSD: aria.c,v 1.33 2010/07/27 05:38:18 jakllsch Exp $");
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/fcntl.h>
-
#include <sys/cpu.h>
#include <sys/bus.h>
-
#include <sys/audioio.h>
+
#include <dev/audio_if.h>
#include <dev/auconv.h>
-
#include <dev/mulaw.h>
-#include <dev/isa/isavar.h>
+#include <dev/isa/isavar.h>
#include <dev/isa/ariareg.h>
#ifdef AUDIO_DEBUG
@@ -96,6 +94,8 @@ struct aria_mixmaster {
struct aria_softc {
struct device sc_dev; /* base device */
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
void *sc_ih; /* interrupt vectoring */
bus_space_tag_t sc_iot; /* Tag on 'da bus. */
bus_space_handle_t sc_ioh; /* Handle of iospace */
@@ -154,6 +154,7 @@ int aria_commit_settings(void *);
int aria_set_params(void *, int, int, audio_params_t *, audio_params_t *,
stream_filter_list_t *, stream_filter_list_t *);
int aria_get_props(void *);
+void aria_get_locks(void *, kmutex_t **, kmutex_t **);
int aria_start_output(void *, void *, int, void (*)(void *), void*);
int aria_start_input(void *, void *, int, void (*)(void *), void*);
@@ -227,7 +228,7 @@ const struct audio_hw_if aria_hw_if = {
NULL,
NULL,
NULL,
- NULL,
+ aria_get_locks,
};
/*
@@ -412,8 +413,11 @@ ariaattach(device_t parent, device_t self, void *aux)
sc->sc_ioh = ioh;
sc->sc_ic = ia->ia_ic;
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
- IST_EDGE, IPL_AUDIO, aria_intr, sc);
+ IST_EDGE, IPL_SCHED, aria_intr, sc);
DPRINTF(("isa_intr_establish() returns (%p)\n", sc->sc_ih));
@@ -1065,6 +1069,9 @@ aria_intr(void *arg)
u_short address;
sc = arg;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
+
iot = sc->sc_iot;
ioh = sc->sc_ioh;
pdata = sc->sc_pdiobuffer;
@@ -1072,8 +1079,10 @@ aria_intr(void *arg)
#if 0 /* XXX -- BAD BAD BAD (That this is #define'd out */
DPRINTF(("Checking to see if this is our intr\n"));
- if ((inw(iobase) & 1) != 0x1)
+ if ((inw(iobase) & 1) != 0x1) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0; /* not for us */
+ }
#endif
sc->sc_interrupts++;
@@ -1104,6 +1113,7 @@ aria_intr(void *arg)
aria_sendcmd(sc, ARIADSPC_TRANSCOMPLETE, -1, -1, -1);
+ mutex_spin_exit(&sc->sc_intr_lock);
return 1;
}
@@ -1657,3 +1667,13 @@ mute:
}
return 0;
}
+
+static void
+aria_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct aria_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
diff --git a/sys/dev/isa/cms.c b/sys/dev/isa/cms.c
index e6d6cad461d..13470761d75 100644
--- a/sys/dev/isa/cms.c
+++ b/sys/dev/isa/cms.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cms.c,v 1.18 2008/04/28 20:23:52 martin Exp $ */
+/* $NetBSD: cms.c,v 1.19 2011/11/23 23:07:32 jmcneill Exp $ */
/*
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cms.c,v 1.18 2008/04/28 20:23:52 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cms.c,v 1.19 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -189,6 +189,7 @@ cms_attach(device_t parent, device_t self, void *aux)
strcpy(ms->name, "Creative Music System");
ms->nvoice = CMS_NVOICES;
ms->data = sc;
+ ms->lock = &sc->sc_lock;
/* use the synthesiser */
midisyn_attach(&sc->sc_mididev, ms);
diff --git a/sys/dev/isa/ess.c b/sys/dev/isa/ess.c
index 1e9f7f8f76a..02f61defdd4 100644
--- a/sys/dev/isa/ess.c
+++ b/sys/dev/isa/ess.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ess.c,v 1.78 2010/05/22 16:35:00 tsutsui Exp $ */
+/* $NetBSD: ess.c,v 1.79 2011/11/23 23:07:32 jmcneill Exp $ */
/*
* Copyright 1997
@@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ess.c,v 1.78 2010/05/22 16:35:00 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ess.c,v 1.79 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -76,12 +76,12 @@ __KERNEL_RCSID(0, "$NetBSD: ess.c,v 1.78 2010/05/22 16:35:00 tsutsui Exp $");
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/kernel.h>
-
#include <sys/cpu.h>
#include <sys/intr.h>
#include <sys/bus.h>
-
#include <sys/audioio.h>
+#include <sys/malloc.h>
+
#include <dev/audio_if.h>
#include <dev/auconv.h>
#include <dev/mulaw.h>
@@ -147,8 +147,8 @@ int ess_getdev(void *, struct audio_device *);
int ess_set_port(void *, mixer_ctrl_t *);
int ess_get_port(void *, mixer_ctrl_t *);
-void *ess_malloc(void *, int, size_t, struct malloc_type *, int);
-void ess_free(void *, void *, struct malloc_type *);
+void *ess_malloc(void *, int, size_t);
+void ess_free(void *, void *, size_t);
size_t ess_round_buffersize(void *, int, size_t);
paddr_t ess_mappage(void *, void *, off_t, int);
@@ -156,6 +156,7 @@ paddr_t ess_mappage(void *, void *, off_t, int);
int ess_query_devinfo(void *, mixer_devinfo_t *);
int ess_1788_get_props(void *);
int ess_1888_get_props(void *);
+void ess_get_locks(void *, kmutex_t **, kmutex_t **);
void ess_speaker_on(struct ess_softc *);
void ess_speaker_off(struct ess_softc *);
@@ -240,7 +241,7 @@ const struct audio_hw_if ess_1788_hw_if = {
ess_audio1_trigger_output,
ess_audio1_trigger_input,
NULL,
- NULL,
+ ess_get_locks,
};
const struct audio_hw_if ess_1888_hw_if = {
@@ -271,7 +272,7 @@ const struct audio_hw_if ess_1888_hw_if = {
ess_audio2_trigger_output,
ess_audio1_trigger_input,
NULL,
- NULL,
+ ess_get_locks,
};
#define ESS_NFORMATS 8
@@ -811,9 +812,6 @@ int
ess_setup_sc(struct ess_softc *sc, int doinit)
{
- callout_init(&sc->sc_poll1_ch, 0);
- callout_init(&sc->sc_poll2_ch, 0);
-
/* Reset the chip. */
if (ess_reset(sc) != 0) {
DPRINTF(("ess_setup_sc: couldn't reset chip\n"));
@@ -925,10 +923,15 @@ essattach(struct ess_softc *sc, int enablejoy)
aprint_normal(": ESS Technology ES%s [version 0x%04x]\n",
essmodel[sc->sc_model], sc->sc_version);
+ callout_init(&sc->sc_poll1_ch, CALLOUT_MPSAFE);
+ callout_init(&sc->sc_poll2_ch, CALLOUT_MPSAFE);
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
sc->sc_audio1.polled = sc->sc_audio1.irq == -1;
if (!sc->sc_audio1.polled) {
sc->sc_audio1.ih = isa_intr_establish(sc->sc_ic,
- sc->sc_audio1.irq, sc->sc_audio1.ist, IPL_AUDIO,
+ sc->sc_audio1.irq, sc->sc_audio1.ist, IPL_SCHED,
ess_audio1_intr, sc);
aprint_normal_dev(sc->sc_dev,
"audio1 interrupting at irq %d\n", sc->sc_audio1.irq);
@@ -939,21 +942,21 @@ essattach(struct ess_softc *sc, int enablejoy)
if (isa_drq_alloc(sc->sc_ic, sc->sc_audio1.drq) != 0) {
aprint_error_dev(sc->sc_dev, "can't reserve drq %d\n",
sc->sc_audio1.drq);
- return;
+ goto fail;
}
if (isa_dmamap_create(sc->sc_ic, sc->sc_audio1.drq,
sc->sc_audio1.maxsize, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
aprint_error_dev(sc->sc_dev, "can't create map for drq %d\n",
sc->sc_audio1.drq);
- return;
+ goto fail;
}
if (!ESS_USE_AUDIO1(sc->sc_model)) {
sc->sc_audio2.polled = sc->sc_audio2.irq == -1;
if (!sc->sc_audio2.polled) {
sc->sc_audio2.ih = isa_intr_establish(sc->sc_ic,
- sc->sc_audio2.irq, sc->sc_audio2.ist, IPL_AUDIO,
+ sc->sc_audio2.irq, sc->sc_audio2.ist, IPL_SCHED,
ess_audio2_intr, sc);
aprint_normal_dev(sc->sc_dev,
"audio2 interrupting at irq %d\n",
@@ -966,14 +969,14 @@ essattach(struct ess_softc *sc, int enablejoy)
if (isa_drq_alloc(sc->sc_ic, sc->sc_audio2.drq) != 0) {
aprint_error_dev(sc->sc_dev, "can't reserve drq %d\n",
sc->sc_audio2.drq);
- return;
+ goto fail;
}
if (isa_dmamap_create(sc->sc_ic, sc->sc_audio2.drq,
sc->sc_audio2.maxsize, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
aprint_error_dev(sc->sc_dev, "can't create map for drq %d\n",
sc->sc_audio2.drq);
- return;
+ goto fail;
}
}
@@ -1070,6 +1073,14 @@ essattach(struct ess_softc *sc, int enablejoy)
if (essdebug > 0)
ess_printsc(sc);
#endif
+
+ return;
+
+ fail:
+ callout_destroy(&sc->sc_poll1_ch);
+ callout_destroy(&sc->sc_poll2_ch);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
}
/*
@@ -1079,6 +1090,7 @@ essattach(struct ess_softc *sc, int enablejoy)
int
ess_open(void *addr, int flags)
{
+
return 0;
}
@@ -1103,8 +1115,17 @@ ess_close(void *addr)
int
ess_drain(void *addr)
{
+ struct ess_softc *sc;
+
+ sc = addr;
+ mutex_exit(&sc->sc_lock);
+ kpause("essdr", FALSE, hz/20, &sc->sc_intr_lock); /* XXX */
+ if (!mutex_tryenter(&sc->sc_lock)) {
+ mutex_spin_exit(&sc->sc_intr_lock);
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
+ }
- tsleep(addr, PWAIT | PCATCH, "essdr", hz/20); /* XXX */
return 0;
}
@@ -1529,23 +1550,32 @@ ess_audio1_intr(void *arg)
{
struct ess_softc *sc;
uint8_t reg;
+ int rv;
sc = arg;
DPRINTFN(1,("ess_audio1_intr: intr=%p\n", sc->sc_audio1.intr));
+ mutex_spin_enter(&sc->sc_intr_lock);
+
/* Check and clear interrupt on Audio1. */
reg = EREAD1(sc->sc_iot, sc->sc_ioh, ESS_DSP_RW_STATUS);
- if ((reg & ESS_DSP_READ_OFLOW) == 0)
+ if ((reg & ESS_DSP_READ_OFLOW) == 0) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
+ }
reg = EREAD1(sc->sc_iot, sc->sc_ioh, ESS_CLEAR_INTR);
sc->sc_audio1.nintr++;
if (sc->sc_audio1.active) {
(*sc->sc_audio1.intr)(sc->sc_audio1.arg);
- return 1;
+ rv = 1;
} else
- return 0;
+ rv = 0;
+
+ mutex_spin_exit(&sc->sc_intr_lock);
+
+ return rv;
}
int
@@ -1553,14 +1583,19 @@ ess_audio2_intr(void *arg)
{
struct ess_softc *sc;
uint8_t reg;
+ int rv;
sc = arg;
DPRINTFN(1,("ess_audio2_intr: intr=%p\n", sc->sc_audio2.intr));
+ mutex_spin_enter(&sc->sc_intr_lock);
+
/* Check and clear interrupt on Audio2. */
reg = ess_read_mix_reg(sc, ESS_MREG_AUDIO2_CTRL2);
- if ((reg & ESS_AUDIO2_CTRL2_IRQ_LATCH) == 0)
+ if ((reg & ESS_AUDIO2_CTRL2_IRQ_LATCH) == 0) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
+ }
reg &= ~ESS_AUDIO2_CTRL2_IRQ_LATCH;
ess_write_mix_reg(sc, ESS_MREG_AUDIO2_CTRL2, reg);
@@ -1568,9 +1603,13 @@ ess_audio2_intr(void *arg)
if (sc->sc_audio2.active) {
(*sc->sc_audio2.intr)(sc->sc_audio2.arg);
- return 1;
+ rv = 1;
} else
- return 0;
+ rv = 0;
+
+ mutex_spin_exit(&sc->sc_intr_lock);
+
+ return rv;
}
void
@@ -1580,8 +1619,12 @@ ess_audio1_poll(void *addr)
int dmapos, dmacount;
sc = addr;
- if (!sc->sc_audio1.active)
+ mutex_spin_enter(&sc->sc_intr_lock);
+
+ if (!sc->sc_audio1.active) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return;
+ }
sc->sc_audio1.nintr++;
@@ -1601,6 +1644,7 @@ ess_audio1_poll(void *addr)
(*sc->sc_audio1.intr)(sc->sc_audio1.arg, dmacount);
#endif
+ mutex_spin_exit(&sc->sc_intr_lock);
callout_reset(&sc->sc_poll1_ch, hz / 30, ess_audio1_poll, sc);
}
@@ -1611,8 +1655,12 @@ ess_audio2_poll(void *addr)
int dmapos, dmacount;
sc = addr;
- if (!sc->sc_audio2.active)
+ mutex_spin_enter(&sc->sc_intr_lock);
+
+ if (!sc->sc_audio2.active) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return;
+ }
sc->sc_audio2.nintr++;
@@ -1632,6 +1680,7 @@ ess_audio2_poll(void *addr)
(*sc->sc_audio2.intr)(sc->sc_audio2.arg, dmacount);
#endif
+ mutex_spin_exit(&sc->sc_intr_lock);
callout_reset(&sc->sc_poll2_ch, hz / 30, ess_audio2_poll, sc);
}
@@ -2135,8 +2184,7 @@ ess_query_devinfo(void *addr, mixer_devinfo_t *dip)
}
void *
-ess_malloc(void *addr, int direction, size_t size,
- struct malloc_type *pool, int flags)
+ess_malloc(void *addr, int direction, size_t size)
{
struct ess_softc *sc;
int drq;
@@ -2146,14 +2194,14 @@ ess_malloc(void *addr, int direction, size_t size,
drq = sc->sc_audio2.drq;
else
drq = sc->sc_audio1.drq;
- return (isa_malloc(sc->sc_ic, drq, size, pool, flags));
+ return (isa_malloc(sc->sc_ic, drq, size, M_DEVBUF, M_WAITOK));
}
void
-ess_free(void *addr, void *ptr, struct malloc_type *pool)
+ess_free(void *addr, void *ptr, size_t size)
{
- isa_free(ptr, pool);
+ isa_free(ptr, M_DEVBUF);
}
size_t
@@ -2194,6 +2242,17 @@ ess_1888_get_props(void *addr)
return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
}
+void
+ess_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct ess_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
+
/* ============================================
* Generic functions for ess, not used by audio h/w i/f
* =============================================
@@ -2584,16 +2643,13 @@ ess_write_mix_reg(struct ess_softc *sc, u_char reg, u_char val)
{
bus_space_tag_t iot;
bus_space_handle_t ioh;
- int s;
DPRINTFN(2,("ess_write_mix_reg: %x=%x\n", reg, val));
iot = sc->sc_iot;
ioh = sc->sc_ioh;
- s = splaudio();
EWRITE1(iot, ioh, ESS_MIX_REG_SELECT, reg);
EWRITE1(iot, ioh, ESS_MIX_REG_DATA, val);
- splx(s);
}
/*
@@ -2604,15 +2660,12 @@ ess_read_mix_reg(struct ess_softc *sc, u_char reg)
{
bus_space_tag_t iot;
bus_space_handle_t ioh;
- int s;
u_char val;
iot = sc->sc_iot;
ioh = sc->sc_ioh;
- s = splaudio();
EWRITE1(iot, ioh, ESS_MIX_REG_SELECT, reg);
val = EREAD1(iot, ioh, ESS_MIX_REG_DATA);
- splx(s);
DPRINTFN(2,("ess_read_mix_reg: %x=%x\n", reg, val));
return val;
@@ -2638,12 +2691,9 @@ ess_read_multi_mix_reg(struct ess_softc *sc, u_char reg,
{
bus_space_tag_t iot;
bus_space_handle_t ioh;
- int s;
iot = sc->sc_iot;
ioh = sc->sc_ioh;
- s = splaudio();
EWRITE1(iot, ioh, ESS_MIX_REG_SELECT, reg);
bus_space_read_multi_1(iot, ioh, ESS_MIX_REG_DATA, datap, count);
- splx(s);
}
diff --git a/sys/dev/isa/essvar.h b/sys/dev/isa/essvar.h
index 16888c85a1c..f5917433bc5 100644
--- a/sys/dev/isa/essvar.h
+++ b/sys/dev/isa/essvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: essvar.h,v 1.25 2010/05/22 16:35:00 tsutsui Exp $ */
+/* $NetBSD: essvar.h,v 1.26 2011/11/23 23:07:32 jmcneill Exp $ */
/*
* Copyright 1997
* Digital Equipment Corporation. All rights reserved.
@@ -33,7 +33,7 @@
*/
/*
-** @(#) $RCSfile: essvar.h,v $ $Revision: 1.25 $ (SHARK) $Date: 2010/05/22 16:35:00 $
+** @(#) $RCSfile: essvar.h,v $ $Revision: 1.26 $ (SHARK) $Date: 2011/11/23 23:07:32 $
**
**++
**
@@ -127,9 +127,11 @@ struct ess_softc
isa_chipset_tag_t sc_ic;
bus_space_tag_t sc_iot; /* tag */
bus_space_handle_t sc_ioh; /* handle */
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
- struct callout sc_poll1_ch; /* audio1 poll */
- struct callout sc_poll2_ch; /* audio2 poll */
+ callout_t sc_poll1_ch; /* audio1 poll */
+ callout_t sc_poll2_ch; /* audio2 poll */
int sc_iobase; /* I/O port base address */
diff --git a/sys/dev/isa/gus.c b/sys/dev/isa/gus.c
index 2de4e9be473..d3a83e56407 100644
--- a/sys/dev/isa/gus.c
+++ b/sys/dev/isa/gus.c
@@ -1,7 +1,7 @@
-/* $NetBSD: gus.c,v 1.106 2011/07/02 13:14:46 mrg Exp $ */
+/* $NetBSD: gus.c,v 1.107 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
- * Copyright (c) 1996, 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996, 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -88,10 +88,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gus.c,v 1.106 2011/07/02 13:14:46 mrg Exp $");
-
-#include "gus.h"
-#if NGUS > 0
+__KERNEL_RCSID(0, "$NetBSD: gus.c,v 1.107 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -103,28 +100,27 @@ __KERNEL_RCSID(0, "$NetBSD: gus.c,v 1.106 2011/07/02 13:14:46 mrg Exp $");
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/fcntl.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/kernel.h>
-
#include <sys/cpu.h>
#include <sys/intr.h>
#include <sys/bus.h>
-
#include <sys/audioio.h>
+
#include <dev/audio_if.h>
#include <dev/mulaw.h>
#include <dev/auconv.h>
-#include <dev/isa/isavar.h>
-#include <dev/isa/isadmavar.h>
-
#include <dev/ic/ics2101reg.h>
#include <dev/ic/cs4231reg.h>
#include <dev/ic/ad1848reg.h>
+
+#include <dev/isa/isavar.h>
+#include <dev/isa/isadmavar.h>
#include <dev/isa/ics2101var.h>
#include <dev/isa/ad1848var.h>
#include <dev/isa/cs4231var.h>
-#include "gusreg.h"
+#include <dev/isa/gusreg.h>
#ifdef AUDIO_DEBUG
#define STATIC /* empty; for debugging symbols */
@@ -132,6 +128,8 @@ __KERNEL_RCSID(0, "$NetBSD: gus.c,v 1.106 2011/07/02 13:14:46 mrg Exp $");
#define STATIC static
#endif
+#define GUS_MAX_BLOCKSIZE 65536
+
/*
* Software state of a single "voice" on the GUS
*/
@@ -173,6 +171,8 @@ struct gus_voice {
struct gus_softc {
struct device sc_dev; /* base device */
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
void *sc_ih; /* interrupt vector */
bus_space_tag_t sc_iot; /* tag */
isa_chipset_tag_t sc_ic; /* ISA chipset info */
@@ -569,10 +569,6 @@ static const unsigned short gus_log_volumes[512] = {
#define GUS_PREC_BYTES (sc->sc_precision >> 3) /* precision to bytes */
-/* splgus() must be splaudio() */
-
-#define splgus splaudio
-
/*
* Interface to higher level audio driver
*/
@@ -605,7 +601,7 @@ const struct audio_hw_if gus_hw_if = {
NULL,
NULL,
NULL,
- NULL,
+ ad1848_get_locks,
};
static const struct audio_hw_if gusmax_hw_if = {
@@ -636,7 +632,7 @@ static const struct audio_hw_if gusmax_hw_if = {
NULL,
NULL,
NULL,
- NULL,
+ ad1848_get_locks,
};
/*
@@ -743,7 +739,7 @@ gus_test_iobase (bus_space_tag_t iot, int iobase)
{
bus_space_handle_t ioh1, ioh2, ioh3, ioh4;
u_char s1, s2;
- int s, rv;
+ int rv;
rv = 0;
/* Map i/o space */
@@ -764,7 +760,6 @@ gus_test_iobase (bus_space_tag_t iot, int iobase)
* Reset GUS to an initial state before we do anything.
*/
- s = splgus();
delay(500);
SELECT_GUS_REG(iot, ioh2, GUSREG_RESET);
@@ -777,8 +772,6 @@ gus_test_iobase (bus_space_tag_t iot, int iobase)
delay(500);
- splx(s);
-
/*
* See if we can write to the board's memory
*/
@@ -821,12 +814,13 @@ gusattach(device_t parent, device_t self, void *aux)
bus_space_handle_t ioh1, ioh2, ioh3, ioh4;
int iobase, i;
unsigned char c, m;
- int d = -1, s;
+ int d = -1;
const struct audio_hw_if *hwif;
sc = (void *) self;
ia = aux;
- callout_init(&sc->sc_dmaout_ch, 0);
+ callout_init(&sc->sc_dmaout_ch, CALLOUT_MPSAFE);
+ ad1848_init_locks(&sc->sc_codec.sc_ad1848, IPL_SCHED);
sc->sc_iot = iot = ia->ia_iot;
sc->sc_ic = ia->ia_ic;
@@ -865,18 +859,20 @@ gusattach(device_t parent, device_t self, void *aux)
delay(500);
+ mutex_spin_enter(&sc->sc_intr_lock);
+
c = bus_space_read_1(iot, ioh3, GUS_BOARD_REV);
if (c != 0xff)
sc->sc_revision = c;
else
sc->sc_revision = 0;
-
SELECT_GUS_REG(iot, ioh2, GUSREG_RESET);
bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0x00);
gusreset(sc, GUS_MAX_VOICES); /* initialize all voices */
gusreset(sc, GUS_MIN_VOICES); /* then set to just the ones we use */
+ mutex_spin_exit(&sc->sc_intr_lock);
/*
* Setup the IRQ and DRQ lines in software, using values from
@@ -910,8 +906,6 @@ gusattach(device_t parent, device_t self, void *aux)
* The order of these operations is very magical.
*/
- s = splhigh(); /* XXX needed? */
-
bus_space_write_1(iot, ioh1, GUS_REG_CONTROL, GUS_REG_IRQCTL);
bus_space_write_1(iot, ioh1, GUS_MIX_CONTROL, m);
bus_space_write_1(iot, ioh1, GUS_IRQCTL_CONTROL, 0x00);
@@ -936,8 +930,6 @@ gusattach(device_t parent, device_t self, void *aux)
(m | GUSMASK_LATCHES) & ~(GUSMASK_LINE_OUT|GUSMASK_LINE_IN));
bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, 0x00);
- splx(s);
-
sc->sc_mixcontrol =
(m | GUSMASK_LATCHES) & ~(GUSMASK_LINE_OUT|GUSMASK_LINE_IN);
@@ -947,12 +939,14 @@ gusattach(device_t parent, device_t self, void *aux)
if (isa_drq_alloc(sc->sc_ic, sc->sc_playdrq) != 0) {
aprint_error_dev(&sc->sc_dev, "can't reserve drq %d\n",
sc->sc_playdrq);
+ ad1848_destroy_locks(&sc->sc_codec.sc_ad1848);
return;
}
if (isa_dmamap_create(sc->sc_ic, sc->sc_playdrq,
- sc->sc_play_maxsize, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
+ sc->sc_play_maxsize, BUS_DMA_WAITOK|BUS_DMA_ALLOCNOW)) {
aprint_error_dev(&sc->sc_dev, "can't create map for drq %d\n",
sc->sc_playdrq);
+ ad1848_destroy_locks(&sc->sc_codec.sc_ad1848);
return;
}
}
@@ -962,12 +956,14 @@ gusattach(device_t parent, device_t self, void *aux)
if (isa_drq_alloc(sc->sc_ic, sc->sc_recdrq) != 0) {
aprint_error_dev(&sc->sc_dev, "can't reserve drq %d\n",
sc->sc_recdrq);
+ ad1848_destroy_locks(&sc->sc_codec.sc_ad1848);
return;
}
if (isa_dmamap_create(sc->sc_ic, sc->sc_recdrq,
- sc->sc_req_maxsize, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
+ sc->sc_req_maxsize, BUS_DMA_WAITOK|BUS_DMA_ALLOCNOW)) {
aprint_error_dev(&sc->sc_dev, "can't create map for drq %d\n",
sc->sc_recdrq);
+ ad1848_destroy_locks(&sc->sc_codec.sc_ad1848);
return;
}
}
@@ -1039,11 +1035,8 @@ gusattach(device_t parent, device_t self, void *aux)
* Setup a default interrupt handler
*/
- /* XXX we shouldn't have to use splgus == splclock, nor should
- * we use IPL_CLOCK.
- */
sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
- IST_EDGE, IPL_AUDIO, gusintr, sc /* sc->sc_gusdsp */);
+ IST_EDGE, IPL_SCHED, gusintr, sc /* sc->sc_gusdsp */);
/*
* Set some default values
@@ -1072,6 +1065,10 @@ gusattach(device_t parent, device_t self, void *aux)
SELECT_GUS_REG(iot, ioh2, GUSREG_PAN_POS);
bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, GUS_PAN_FULL_RIGHT);
+ /* set up buffer to hold the deinterleave, if necessary
+ for stereo output */
+ sc->sc_deintr_buf = kmem_alloc(GUS_MAX_BLOCKSIZE>>1, KM_SLEEP);
+
/*
* Attach to the generic audio layer
*/
@@ -1200,7 +1197,7 @@ gusmax_dma_output(void *addr, void *tbuf, int size,
}
/*
- * called at splgus() from interrupt handler.
+ * called from interrupt handler.
*/
void
stereo_dmaintr(void *arg)
@@ -1212,6 +1209,8 @@ stereo_dmaintr(void *arg)
sc = arg;
sa = &sc->sc_stereo;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
/*
* Put other half in its place, then call the real interrupt routine :)
*/
@@ -1243,8 +1242,6 @@ stereo_dmaintr(void *arg)
/*
* Start up DMA output to the card.
- * Called at splgus/splaudio already, either from intr handler or from
- * generic audio code.
*/
int
gus_dma_output(void *addr, void *tbuf, int size,
@@ -1345,7 +1342,7 @@ gusmax_close(void *addr)
}
/*
- * Close out device stuff. Called at splgus() from generic audio layer.
+ * Close out device stuff.
*/
void
gusclose(void *addr)
@@ -1364,10 +1361,6 @@ gusclose(void *addr)
}
sc->sc_flags &= ~(GUS_OPEN|GUS_LOCKED|GUS_DMAOUT_ACTIVE|GUS_DMAIN_ACTIVE);
- if (sc->sc_deintr_buf) {
- free(sc->sc_deintr_buf, M_DEVBUF);
- sc->sc_deintr_buf = NULL;
- }
/* turn off speaker, etc. */
/* make sure the voices shut up: */
@@ -1405,6 +1398,9 @@ gusintr(void *arg)
#ifdef DIAGNOSTIC
gusintrcnt++;
#endif
+
+ mutex_spin_enter(&sc->sc_codec.sc_ad1848.sc_intr_lock);
+
if (HAS_CODEC(sc))
retval = ad1848_isa_intr(&sc->sc_codec);
if ((intr = bus_space_read_1(iot, ioh1, GUS_IRQ_STATUS)) & GUSMASK_IRQ_DMATC) {
@@ -1428,8 +1424,9 @@ gusintr(void *arg)
#endif
retval += gus_voice_intr(sc);
}
- if (retval)
- return 1;
+
+ mutex_spin_exit(&sc->sc_codec.sc_ad1848.sc_intr_lock);
+
return retval;
}
@@ -1459,16 +1456,16 @@ gus_dmaout_timeout(void *arg)
struct gus_softc *sc;
bus_space_tag_t iot;
bus_space_handle_t ioh2;
- int s;
sc = arg;
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
printf("%s: dmaout timeout\n", device_xname(&sc->sc_dev));
+
/*
* Stop any DMA.
*/
- s = splgus();
+ mutex_spin_enter(&sc->sc_codec.sc_ad1848.sc_intr_lock);
SELECT_GUS_REG(iot, ioh2, GUSREG_DMA_CONTROL);
bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, 0);
#if 0
@@ -1477,7 +1474,7 @@ gus_dmaout_timeout(void *arg)
#endif
gus_dmaout_dointr(sc);
- splx(s);
+ mutex_spin_exit(&sc->sc_codec.sc_ad1848.sc_intr_lock);
}
@@ -1492,6 +1489,8 @@ gus_dmaout_intr(struct gus_softc *sc)
bus_space_tag_t iot;
bus_space_handle_t ioh2;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
/*
@@ -1514,6 +1513,8 @@ gus_dmaout_dointr(struct gus_softc *sc)
bus_space_tag_t iot;
bus_space_handle_t ioh2;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
/* sc->sc_dmaoutcnt - 1 because DMA controller counts from zero?. */
@@ -1679,6 +1680,8 @@ gus_voice_intr(struct gus_softc *sc)
int ignore, voice, rval;
unsigned char intr, status;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
ignore = 0;
@@ -1905,6 +1908,8 @@ gus_continue_playing(struct gus_softc *sc, int voice)
bus_space_tag_t iot;
bus_space_handle_t ioh2;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
/*
* stop this voice from interrupting while we work.
*/
@@ -1998,7 +2003,7 @@ gus_continue_playing(struct gus_softc *sc, int voice)
}
/*
- * Send/receive data into GUS's DRAM using DMA. Called at splgus()
+ * Send/receive data into GUS's DRAM using DMA.
*/
STATIC void
gusdmaout(struct gus_softc *sc, int flags,
@@ -2008,6 +2013,8 @@ gusdmaout(struct gus_softc *sc, int flags,
bus_space_tag_t iot;
bus_space_handle_t ioh2;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
DMAPRINTF(("gusdmaout flags=%x scflags=%x\n", flags, sc->sc_flags));
c = (unsigned char) flags;
iot = sc->sc_iot;
@@ -2070,8 +2077,7 @@ gusdmaout(struct gus_softc *sc, int flags,
}
/*
- * Start a voice playing on the GUS. Called from interrupt handler at
- * splgus().
+ * Start a voice playing on the GUS.
*/
STATIC void
@@ -2083,6 +2089,8 @@ gus_start_voice(struct gus_softc *sc, int voice, int intrs)
u_long current;
u_long end;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
/*
@@ -2168,7 +2176,7 @@ gus_start_voice(struct gus_softc *sc, int voice, int intrs)
}
/*
- * Stop a given voice. called at splgus()
+ * Stop a given voice.
*/
STATIC void
gus_stop_voice(struct gus_softc *sc, int voice, int intrs_too)
@@ -2176,6 +2184,8 @@ gus_stop_voice(struct gus_softc *sc, int voice, int intrs_too)
bus_space_tag_t iot;
bus_space_handle_t ioh2;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
sc->sc_voc[voice].voccntl |= GUSMASK_VOICE_STOPPED |
@@ -2210,7 +2220,7 @@ gus_stop_voice(struct gus_softc *sc, int voice, int intrs_too)
/*
- * Set the volume of a given voice. Called at splgus().
+ * Set the volume of a given voice.
*/
STATIC void
gus_set_volume(struct gus_softc *sc, int voice, int volume)
@@ -2219,6 +2229,8 @@ gus_set_volume(struct gus_softc *sc, int voice, int volume)
bus_space_handle_t ioh2;
unsigned int gusvol;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
gusvol = gus_log_volumes[volume < 512 ? volume : 511];
@@ -2269,15 +2281,12 @@ gusmax_set_params(void *addr, int setmode, int usemode, audio_params_t *p,
}
int
-gus_set_params(
- void *addr,
- int setmode, int usemode,
- audio_params_t *p, audio_params_t *r,
- stream_filter_list_t *pfil, stream_filter_list_t *rfil)
+gus_set_params(void *addr,int setmode, int usemode, audio_params_t *p,
+ audio_params_t *r, stream_filter_list_t *pfil,
+ stream_filter_list_t *rfil)
{
audio_params_t hw;
struct gus_softc *sc;
- int s;
sc = addr;
switch (p->encoding) {
@@ -2292,7 +2301,7 @@ gus_set_params(
return EINVAL;
}
- s = splaudio();
+ mutex_spin_enter(&sc->sc_intr_lock);
if (p->precision == 8) {
sc->sc_voc[GUS_VOICE_LEFT].voccntl &= ~GUSMASK_DATA_SIZE16;
@@ -2306,8 +2315,6 @@ gus_set_params(
sc->sc_precision = p->precision;
sc->sc_channels = p->channels;
- splx(s);
-
if (p->sample_rate > gus_max_frequency[sc->sc_voices - GUS_MIN_VOICES])
p->sample_rate = gus_max_frequency[sc->sc_voices - GUS_MIN_VOICES];
if (setmode & AUMODE_RECORD)
@@ -2315,6 +2322,8 @@ gus_set_params(
if (setmode & AUMODE_PLAY)
sc->sc_orate = p->sample_rate;
+ mutex_spin_exit(&sc->sc_intr_lock);
+
hw = *p;
/* clear req_size before setting a filter to avoid confliction
* in gusmax_set_params() */
@@ -2385,14 +2394,6 @@ gus_round_blocksize(void *addr, int blocksize,
blocksize = (blocksize / GUS_BUFFER_MULTIPLE + 1) *
GUS_BUFFER_MULTIPLE;
- /* set up temporary buffer to hold the deinterleave, if necessary
- for stereo output */
- if (sc->sc_deintr_buf) {
- free(sc->sc_deintr_buf, M_DEVBUF);
- sc->sc_deintr_buf = NULL;
- }
- sc->sc_deintr_buf = malloc(blocksize>>1, M_DEVBUF, M_WAITOK);
-
sc->sc_blocksize = blocksize;
/* multi-buffering not quite working yet. */
sc->sc_nbufs = /*GUS_MEM_FOR_BUFFERS / blocksize*/ 2;
@@ -2448,26 +2449,24 @@ gusmax_commit_settings(void *addr)
}
/*
- * Commit the settings. Called at normal IPL.
+ * Commit the settings.
*/
int
gus_commit_settings(void *addr)
{
struct gus_softc *sc;
- int s;
sc = addr;
DPRINTF(("gus_commit_settings called (gain = %d)\n",sc->sc_ogain));
-
- s = splgus();
-
+ mutex_spin_enter(&sc->sc_codec.sc_ad1848.sc_intr_lock);
gus_set_recrate(sc, sc->sc_irate);
gus_set_volume(sc, GUS_VOICE_LEFT, sc->sc_ogain);
gus_set_volume(sc, GUS_VOICE_RIGHT, sc->sc_ogain);
gus_set_samprate(sc, GUS_VOICE_LEFT, sc->sc_orate);
gus_set_samprate(sc, GUS_VOICE_RIGHT, sc->sc_orate);
- splx(s);
+ mutex_spin_exit(&sc->sc_codec.sc_ad1848.sc_intr_lock);
+
gus_set_chan_addrs(sc);
return 0;
@@ -2508,7 +2507,7 @@ gus_set_chan_addrs(struct gus_softc *sc)
}
/*
- * Set the sample rate of the given voice. Called at splgus().
+ * Set the sample rate of the given voice.
*/
STATIC void
gus_set_samprate(struct gus_softc *sc, int voice, int freq)
@@ -2518,6 +2517,8 @@ gus_set_samprate(struct gus_softc *sc, int voice, int freq)
unsigned int fc;
u_long temp, f;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
f = (u_long) freq;
@@ -2545,7 +2546,7 @@ gus_set_samprate(struct gus_softc *sc, int voice, int freq)
/*
* Set the sample rate of the recording frequency. Formula is from the GUS
- * SDK. Called at splgus().
+ * SDK.
*/
STATIC void
gus_set_recrate(struct gus_softc *sc, u_long rate)
@@ -2554,6 +2555,8 @@ gus_set_recrate(struct gus_softc *sc, u_long rate)
bus_space_handle_t ioh2;
u_char realrate;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
DPRINTF(("gus_set_recrate %lu\n", rate));
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
@@ -2657,7 +2660,7 @@ gus_mic_ctl(void *addr, int newstate)
}
/*
- * Set the end address of a give voice. Called at splgus()
+ * Set the end address of a give voice.
*/
STATIC void
gus_set_endaddr(struct gus_softc *sc, int voice, u_long addr)
@@ -2665,6 +2668,8 @@ gus_set_endaddr(struct gus_softc *sc, int voice, u_long addr)
bus_space_tag_t iot;
bus_space_handle_t ioh2;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
sc->sc_voc[voice].end_addr = addr;
@@ -2681,7 +2686,7 @@ gus_set_endaddr(struct gus_softc *sc, int voice, u_long addr)
#ifdef GUSPLAYDEBUG
/*
- * Set current address. called at splgus()
+ * Set current address.
*/
STATIC void
gus_set_curaddr(struct gus_softc *sc, int voice, u_long addr)
@@ -2689,6 +2694,8 @@ gus_set_curaddr(struct gus_softc *sc, int voice, u_long addr)
bus_space_tag_t iot;
bus_space_handle_t ioh2;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
sc->sc_voc[voice].current_addr = addr;
@@ -2706,7 +2713,7 @@ gus_set_curaddr(struct gus_softc *sc, int voice, u_long addr)
}
/*
- * Get current GUS playback address. Called at splgus().
+ * Get current GUS playback address.
*/
STATIC u_long
gus_get_curaddr(struct gus_softc *sc, int voice)
@@ -2715,6 +2722,8 @@ gus_get_curaddr(struct gus_softc *sc, int voice)
bus_space_handle_t ioh2;
u_long addr;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
bus_space_write_1(iot, ioh2, GUS_VOICE_SELECT, (unsigned char) voice);
@@ -2808,13 +2817,14 @@ gusreset(struct gus_softc *sc, int voices)
bus_space_handle_t ioh1;
bus_space_handle_t ioh2;
bus_space_handle_t ioh4;
- int i,s;
+ int i;
+
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
iot = sc->sc_iot;
ioh1 = sc->sc_ioh1;
ioh2 = sc->sc_ioh2;
ioh4 = sc->sc_ioh4;
- s = splgus();
/*
* Reset the GF1 chip
@@ -2928,8 +2938,6 @@ gusreset(struct gus_softc *sc, int voices)
SELECT_GUS_REG(iot, ioh2, GUSREG_RESET);
bus_space_write_1(iot, ioh2, GUS_DATA_HIGH, GUSMASK_MASTER_RESET | GUSMASK_DAC_ENABLE |
GUSMASK_IRQ_ENABLE);
-
- splx(s);
}
@@ -3029,7 +3037,7 @@ gusmax_dma_input(void *addr, void *tbuf, int size,
/*
* Start sampling the input source into the requested DMA buffer.
- * Called at splgus(), either from top-half or from interrupt handler.
+ * Called from top-half or from interrupt handler.
*/
int
gus_dma_input(void *addr, void *tbuf, int size,
@@ -3045,6 +3053,8 @@ gus_dma_input(void *addr, void *tbuf, int size,
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
/*
* Sample SIZE bytes of data from the card, into buffer at BUF.
*/
@@ -3088,6 +3098,8 @@ gus_dmain_intr(struct gus_softc *sc)
void (*callback)(void *);
void *arg;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
DMAPRINTF(("gus_dmain_intr called\n"));
if (sc->sc_dmainintr) {
isa_dmadone(sc->sc_ic, sc->sc_recdrq);
@@ -3129,7 +3141,7 @@ gusmax_halt_in_dma(void *addr)
}
/*
- * Stop any DMA output. Called at splgus().
+ * Stop any DMA output.
*/
int
gus_halt_out_dma(void *addr)
@@ -3142,6 +3154,9 @@ gus_halt_out_dma(void *addr)
sc = addr;
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
+
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
/*
* Make sure the GUS _isn't_ setup for DMA
*/
@@ -3167,7 +3182,7 @@ gus_halt_out_dma(void *addr)
}
/*
- * Stop any DMA output. Called at splgus().
+ * Stop any DMA output.
*/
int
gus_halt_in_dma(void *addr)
@@ -3181,6 +3196,8 @@ gus_halt_in_dma(void *addr)
iot = sc->sc_iot;
ioh2 = sc->sc_ioh2;
+ KASSERT(mutex_owned(&sc->sc_codec.sc_ad1848.sc_intr_lock));
+
/*
* Make sure the GUS _isn't_ setup for DMA
*/
@@ -4138,6 +4155,3 @@ gus_init_ics2101(struct gus_softc *sc)
gusics_linein_mute(ic, 0);
return;
}
-
-
-#endif /* NGUS */
diff --git a/sys/dev/isa/ics2101.c b/sys/dev/isa/ics2101.c
index 298afee97a1..fae8582f6c6 100644
--- a/sys/dev/isa/ics2101.c
+++ b/sys/dev/isa/ics2101.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ics2101.c,v 1.16 2009/03/14 21:04:20 dsl Exp $ */
+/* $NetBSD: ics2101.c,v 1.17 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ics2101.c,v 1.16 2009/03/14 21:04:20 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ics2101.c,v 1.17 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -78,7 +78,6 @@ ics2101_mix_doit(struct ics2101_softc *sc, u_int chan, u_int side, u_int value,
unsigned char ctrl_addr;
unsigned char attn_addr;
unsigned char normal;
- int s;
if (/* chan < ICSMIX_CHAN_0 || */ chan > ICSMIX_CHAN_5)
return;
@@ -119,15 +118,11 @@ ics2101_mix_doit(struct ics2101_softc *sc, u_int chan, u_int side, u_int value,
normal = 0x02;
}
- s = splaudio();
-
bus_space_write_1(iot, sc->sc_selio_ioh, sc->sc_selio, ctrl_addr);
bus_space_write_1(iot, sc->sc_dataio_ioh, sc->sc_dataio, normal);
bus_space_write_1(iot, sc->sc_selio_ioh, sc->sc_selio, attn_addr);
bus_space_write_1(iot, sc->sc_dataio_ioh, sc->sc_dataio, (unsigned char) value);
-
- splx(s);
}
void
diff --git a/sys/dev/isa/joy_ess.c b/sys/dev/isa/joy_ess.c
index 1804c3604e8..5d9800b2c71 100644
--- a/sys/dev/isa/joy_ess.c
+++ b/sys/dev/isa/joy_ess.c
@@ -1,7 +1,7 @@
-/* $NetBSD: joy_ess.c,v 1.5 2008/03/26 18:27:07 xtraeme Exp $ */
+/* $NetBSD: joy_ess.c,v 1.6 2011/11/23 23:07:32 jmcneill Exp $ */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: joy_ess.c,v 1.5 2008/03/26 18:27:07 xtraeme Exp $");
+__KERNEL_RCSID(0, "$NetBSD: joy_ess.c,v 1.6 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -42,6 +42,7 @@ joy_ess_attach(device_t parent, device_t self, void *aux)
sc->sc_iot = esc->sc_joy_iot;
sc->sc_ioh = esc->sc_joy_ioh;
sc->sc_dev = self;
+ sc->sc_lock = &esc->sc_lock;
joyattach(sc);
}
diff --git a/sys/dev/isa/joy_isa.c b/sys/dev/isa/joy_isa.c
index 97470ed4c9a..252d4ee9903 100644
--- a/sys/dev/isa/joy_isa.c
+++ b/sys/dev/isa/joy_isa.c
@@ -1,4 +1,4 @@
-/* $NetBSD: joy_isa.c,v 1.12 2008/03/26 18:27:07 xtraeme Exp $ */
+/* $NetBSD: joy_isa.c,v 1.13 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
* Copyright (c) 1995 Jean-Marc Zucconi
@@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: joy_isa.c,v 1.12 2008/03/26 18:27:07 xtraeme Exp $");
+__KERNEL_RCSID(0, "$NetBSD: joy_isa.c,v 1.13 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -48,10 +48,15 @@ __KERNEL_RCSID(0, "$NetBSD: joy_isa.c,v 1.12 2008/03/26 18:27:07 xtraeme Exp $")
#define JOY_NPORTS 1
+struct joy_isa_softc {
+ struct joy_softc *sc;
+ kmutex_t sc_lock;
+};
+
static int joy_isa_probe(device_t, cfdata_t, void *);
static void joy_isa_attach(device_t, device_t, void *);
-CFATTACH_DECL_NEW(joy_isa, sizeof(struct joy_softc),
+CFATTACH_DECL_NEW(joy_isa, sizeof(struct joy_isa_softc),
joy_isa_probe, joy_isa_attach, NULL, NULL);
static int
@@ -97,6 +102,7 @@ static void
joy_isa_attach(device_t parent, device_t self, void *aux)
{
struct joy_softc *sc = device_private(self);
+ struct joy_isa_softc *isc = device_private(self);
struct isa_attach_args *ia = aux;
aprint_normal("\n");
@@ -110,5 +116,8 @@ joy_isa_attach(device_t parent, device_t self, void *aux)
return;
}
+ mutex_init(&isc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ sc->sc_lock = &isc->sc_lock;
+
joyattach(sc);
}
diff --git a/sys/dev/isa/midi_pcppi.c b/sys/dev/isa/midi_pcppi.c
index 3dc3865ae4a..c304bb1d3fb 100644
--- a/sys/dev/isa/midi_pcppi.c
+++ b/sys/dev/isa/midi_pcppi.c
@@ -1,11 +1,11 @@
-/* $NetBSD: midi_pcppi.c,v 1.23 2009/04/10 10:18:50 mlelstv Exp $ */
+/* $NetBSD: midi_pcppi.c,v 1.24 2011/11/23 23:07:32 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson (augustss@NetBSD.org).
+ * by Lennart Augustsson (augustss@NetBSD.org), and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,20 +30,19 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: midi_pcppi.c,v 1.23 2009/04/10 10:18:50 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: midi_pcppi.c,v 1.24 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/errno.h>
#include <sys/device.h>
-#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/conf.h>
#include <sys/select.h>
#include <sys/audioio.h>
#include <sys/midiio.h>
-
+#include <sys/tty.h>
#include <sys/bus.h>
#include <dev/isa/pcppivar.h>
@@ -64,16 +63,16 @@ static int midi_pcppi_match(device_t, cfdata_t , void *);
static void midi_pcppi_attach(device_t, device_t, void *);
static int midi_pcppi_detach(device_t, int);
-void midi_pcppi_on (midisyn *, uint_fast16_t, midipitch_t, int16_t);
-void midi_pcppi_off (midisyn *, uint_fast16_t, uint_fast8_t);
-void midi_pcppi_close(midisyn *);
-static void midi_pcppi_repitchv(midisyn *, uint_fast16_t, midipitch_t);
+static void midi_pcppi_on (midisyn *, uint_fast16_t, midipitch_t, int16_t);
+static void midi_pcppi_off (midisyn *, uint_fast16_t, uint_fast8_t);
+static void midi_pcppi_close(midisyn *);
+static void midi_pcppi_repitchv(midisyn *, uint_fast16_t, midipitch_t);
CFATTACH_DECL3_NEW(midi_pcppi, sizeof(struct midi_pcppi_softc),
midi_pcppi_match, midi_pcppi_attach, midi_pcppi_detach, NULL, NULL, NULL,
DVF_DETACH_SHUTDOWN);
-struct midisyn_methods midi_pcppi_hw = {
+static struct midisyn_methods midi_pcppi_hw = {
.close = midi_pcppi_close,
.attackv = midi_pcppi_on,
.releasev = midi_pcppi_off,
@@ -101,6 +100,7 @@ midi_pcppi_attach(device_t parent, device_t self, void *aux)
strcpy(ms->name, "PC speaker");
ms->nvoice = 1;
ms->data = pa->pa_cookie;
+ ms->lock = &tty_lock;
midi_pcppi_attached++;
@@ -121,37 +121,44 @@ midi_pcppi_detach(device_t self, int flags)
return mididetach(self, flags);
}
-void
+static void
midi_pcppi_on(midisyn *ms,
uint_fast16_t voice, midipitch_t mp, int16_t level)
{
pcppi_tag_t t = ms->data;
- pcppi_bell(t,
- MIDIHZ18_TO_HZ(MIDIPITCH_TO_HZ18(mp)),
- MAX_DURATION * hz, 0);
+ KASSERT(mutex_owned(&tty_lock));
+
+ pcppi_bell_locked(t, MIDIHZ18_TO_HZ(MIDIPITCH_TO_HZ18(mp)),
+ MAX_DURATION * hz, 0);
}
-void
+static void
midi_pcppi_off(midisyn *ms, uint_fast16_t voice, uint_fast8_t vel)
{
pcppi_tag_t t = ms->data;
+ KASSERT(mutex_owned(&tty_lock));
+
/*printf("OFF %p %d\n", t, note >> 16);*/
- pcppi_bell(t, 0, 0, 0);
+ pcppi_bell_locked(t, 0, 0, 0);
}
-void
+static void
midi_pcppi_close(midisyn *ms)
{
pcppi_tag_t t = ms->data;
+ KASSERT(mutex_owned(&tty_lock));
+
/* Make sure we are quiet. */
- pcppi_bell(t, 0, 0, 0);
+ pcppi_bell_locked(t, 0, 0, 0);
}
static void
midi_pcppi_repitchv(midisyn *ms, uint_fast16_t voice, midipitch_t newpitch)
{
+ KASSERT(mutex_owned(&tty_lock));
+
midi_pcppi_on(ms, voice, newpitch, 64);
}
diff --git a/sys/dev/isa/mpu_isa.c b/sys/dev/isa/mpu_isa.c
index 1e63eef6fbf..22ac4dd0b2f 100644
--- a/sys/dev/isa/mpu_isa.c
+++ b/sys/dev/isa/mpu_isa.c
@@ -1,11 +1,11 @@
-/* $NetBSD: mpu_isa.c,v 1.20 2008/04/28 20:23:52 martin Exp $ */
+/* $NetBSD: mpu_isa.c,v 1.21 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
- * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson.
+ * by Lennart Augustsson and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mpu_isa.c,v 1.20 2008/04/28 20:23:52 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mpu_isa.c,v 1.21 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -52,6 +52,7 @@ struct mpu_isa_softc {
device_t sc_dev;
struct mpu_softc sc_mpu; /* generic part */
void *sc_ih; /* ISA interrupt handler */
+ kmutex_t sc_lock;
};
static int mpu_isa_match(device_t, cfdata_t, void *);
@@ -114,9 +115,11 @@ mpu_isa_attach(device_t parent, device_t self, void *aux)
}
sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
- IST_EDGE, IPL_AUDIO, mpu_intr, &sc->sc_mpu);
+ IST_EDGE, IPL_SCHED, mpu_intr, &sc->sc_mpu);
sc->sc_mpu.model = "Roland MPU-401 MIDI UART";
sc->sc_dev = self;
+ sc->sc_mpu.lock = &sc->sc_lock;
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SCHED);
mpu_attach(&sc->sc_mpu);
}
diff --git a/sys/dev/isa/mpu_sb.c b/sys/dev/isa/mpu_sb.c
index 4f14f11e26a..006c3c797ad 100644
--- a/sys/dev/isa/mpu_sb.c
+++ b/sys/dev/isa/mpu_sb.c
@@ -1,11 +1,11 @@
-/* $NetBSD: mpu_sb.c,v 1.15 2008/04/28 20:23:52 martin Exp $ */
+/* $NetBSD: mpu_sb.c,v 1.16 2011/11/23 23:07:32 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson (augustss@NetBSD.org).
+ * by Lennart Augustsson (augustss@NetBSD.org) and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mpu_sb.c,v 1.15 2008/04/28 20:23:52 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mpu_sb.c,v 1.16 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -83,6 +83,7 @@ mpu_sb_attach(device_t parent, device_t self, void *aux)
sc->iot = ssc->sc_mpu_iot;
sc->model = "SB MPU-401 MIDI UART";
sc->sc_dev = self;
+ sc->lock = &ssc->sc_intr_lock;
mpu_attach(sc);
}
diff --git a/sys/dev/isa/mpu_ym.c b/sys/dev/isa/mpu_ym.c
index 211f18d5978..91eb917186d 100644
--- a/sys/dev/isa/mpu_ym.c
+++ b/sys/dev/isa/mpu_ym.c
@@ -1,7 +1,7 @@
-/* $NetBSD: mpu_ym.c,v 1.15 2008/04/28 20:23:52 martin Exp $ */
+/* $NetBSD: mpu_ym.c,v 1.16 2011/11/23 23:07:32 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mpu_ym.c,v 1.15 2008/04/28 20:23:52 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mpu_ym.c,v 1.16 2011/11/23 23:07:32 jmcneill Exp $");
#define NMPU_YM 1
@@ -43,7 +43,6 @@ __KERNEL_RCSID(0, "$NetBSD: mpu_ym.c,v 1.15 2008/04/28 20:23:52 martin Exp $");
#include <sys/conf.h>
#include <sys/audioio.h>
#include <sys/midiio.h>
-
#include <sys/bus.h>
#include <dev/audio_if.h>
@@ -96,6 +95,7 @@ mpu_ym_attach(device_t parent, device_t self, void *aux)
sc->model = YM_IS_SA3(ssc) ?
"OPL3-SA3 MPU-401 MIDI UART" : "OPL3-SA2 MPU-401 MIDI UART";
sc->sc_dev = self;
+ sc->lock = &ssc->sc_ad1848.sc_ad1848.sc_intr_lock;
mpu_attach(sc);
}
diff --git a/sys/dev/isa/opl_ess.c b/sys/dev/isa/opl_ess.c
index 27570bd7714..9c3ae17383f 100644
--- a/sys/dev/isa/opl_ess.c
+++ b/sys/dev/isa/opl_ess.c
@@ -1,7 +1,7 @@
-/* $NetBSD: opl_ess.c,v 1.16 2008/04/28 20:23:52 martin Exp $ */
+/* $NetBSD: opl_ess.c,v 1.17 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
- * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: opl_ess.c,v 1.16 2008/04/28 20:23:52 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: opl_ess.c,v 1.17 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -85,6 +85,7 @@ opl_ess_attach(device_t parent, device_t self, void *aux)
sc->offs = 0;
sc->spkrctl = ess_speaker_ctl;
sc->spkrarg = ssc;
+ sc->lock = &ssc->sc_intr_lock;
strcpy(sc->syn.name, "ESS ");
opl_attach(sc);
diff --git a/sys/dev/isa/opl_isa.c b/sys/dev/isa/opl_isa.c
index e487568f327..ccc2a3dde6c 100644
--- a/sys/dev/isa/opl_isa.c
+++ b/sys/dev/isa/opl_isa.c
@@ -1,11 +1,11 @@
-/* $NetBSD: opl_isa.c,v 1.19 2008/04/28 20:23:52 martin Exp $ */
+/* $NetBSD: opl_isa.c,v 1.20 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
- * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson.
+ * by Lennart Augustsson, and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: opl_isa.c,v 1.19 2008/04/28 20:23:52 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: opl_isa.c,v 1.20 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -59,7 +59,12 @@ __KERNEL_RCSID(0, "$NetBSD: opl_isa.c,v 1.19 2008/04/28 20:23:52 martin Exp $");
int opl_isa_match(device_t, cfdata_t, void *);
void opl_isa_attach(device_t, device_t, void *);
-CFATTACH_DECL_NEW(opl_isa, sizeof(struct opl_softc),
+struct opl_isa_softc {
+ struct opl_softc sc_opl;
+ kmutex_t sc_lock;
+};
+
+CFATTACH_DECL_NEW(opl_isa, sizeof(struct opl_isa_softc),
opl_isa_match, opl_isa_attach, NULL, NULL);
int
@@ -97,6 +102,7 @@ void
opl_isa_attach(device_t parent, device_t self, void *aux)
{
struct opl_softc *sc = device_private(self);
+ struct opl_isa_softc *isa = device_private(self);
struct isa_attach_args *ia = aux;
sc->mididev.dev = self;
@@ -108,6 +114,8 @@ opl_isa_attach(device_t parent, device_t self, void *aux)
return;
}
sc->offs = 0;
+ sc->lock = &isa->sc_lock;
+ mutex_init(&isa->sc_lock, MUTEX_DEFAULT, IPL_NONE);
opl_attach(sc);
}
diff --git a/sys/dev/isa/opl_sb.c b/sys/dev/isa/opl_sb.c
index ea0150707e0..bb7d72b0018 100644
--- a/sys/dev/isa/opl_sb.c
+++ b/sys/dev/isa/opl_sb.c
@@ -1,11 +1,11 @@
-/* $NetBSD: opl_sb.c,v 1.18 2008/04/28 20:23:52 martin Exp $ */
+/* $NetBSD: opl_sb.c,v 1.19 2011/11/23 23:07:32 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson (augustss@NetBSD.org).
+ * by Lennart Augustsson (augustss@NetBSD.org) and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: opl_sb.c,v 1.18 2008/04/28 20:23:52 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: opl_sb.c,v 1.19 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -83,6 +83,7 @@ opl_sb_attach(device_t parent, device_t self, void *aux)
sc->offs = 0;
sc->spkrctl = sbdsp_speaker_ctl;
sc->spkrarg = ssc;
+ sc->lock = &ssc->sc_intr_lock;
strcpy(sc->syn.name, "SB ");
opl_attach(sc);
diff --git a/sys/dev/isa/pas.c b/sys/dev/isa/pas.c
index 309d518a2c9..3d6b4658773 100644
--- a/sys/dev/isa/pas.c
+++ b/sys/dev/isa/pas.c
@@ -1,4 +1,4 @@
-/* $NetBSD: pas.c,v 1.68 2010/03/24 01:13:30 dyoung Exp $ */
+/* $NetBSD: pas.c,v 1.69 2011/11/23 23:07:32 jmcneill Exp $ */
/*
* Copyright (c) 1991-1993 Regents of the University of California.
@@ -57,7 +57,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pas.c,v 1.68 2010/03/24 01:13:30 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pas.c,v 1.69 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -150,7 +150,7 @@ const struct audio_hw_if pas_hw_if = {
sbdsp_trigger_output,
sbdsp_trigger_input,
0,
- NULL,
+ sbdsp_get_locks,
};
/* The Address Translation code is used to convert I/O register addresses to
@@ -472,10 +472,13 @@ pasattach(device_t parent, device_t self, void *aux)
return;
}
+ mutex_init(&sc->sc_sbdsp.sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_sbdsp.sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
sc->sc_sbdsp.sc_ic = ia->ia_ic;
sc->sc_sbdsp.sc_iobase = iobase;
sc->sc_sbdsp.sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
- IST_EDGE, IPL_AUDIO, sbdsp_intr, &sc->sc_sbdsp);
+ IST_EDGE, IPL_SCHED, sbdsp_intr, &sc->sc_sbdsp);
aprint_normal(" ProAudio Spectrum %s [rev %d] ", pasnames[sc->model],
sc->rev);
diff --git a/sys/dev/isa/pcppi.c b/sys/dev/isa/pcppi.c
index 452d7ca1eb4..b1b2125734d 100644
--- a/sys/dev/isa/pcppi.c
+++ b/sys/dev/isa/pcppi.c
@@ -1,4 +1,4 @@
-/* $NetBSD: pcppi.c,v 1.37 2011/05/24 09:28:03 mrg Exp $ */
+/* $NetBSD: pcppi.c,v 1.38 2011/11/23 23:07:32 jmcneill Exp $ */
/*
* Copyright (c) 1996 Carnegie-Mellon University.
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pcppi.c,v 1.37 2011/05/24 09:28:03 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pcppi.c,v 1.38 2011/11/23 23:07:32 jmcneill Exp $");
#include "attimer.h"
@@ -42,6 +42,7 @@ __KERNEL_RCSID(0, "$NetBSD: pcppi.c,v 1.37 2011/05/24 09:28:03 mrg Exp $");
#include <sys/bus.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
+#include <sys/tty.h>
#include <dev/ic/attimervar.h>
@@ -66,16 +67,14 @@ CFATTACH_DECL3_NEW(pcppi, sizeof(struct pcppi_softc),
DVF_DETACH_SHUTDOWN);
static int pcppisearch(device_t, cfdata_t, const int *, void *);
-static void pcppi_bell_stop_unlocked(void*);
-static void pcppi_bell_stop(void*);
+static void pcppi_bell_stop(struct pcppi_softc *);
+static void pcppi_bell_callout(void *);
#if NATTIMER > 0
static void pcppi_attach_speaker(device_t);
static void pcppi_detach_speaker(struct pcppi_softc *);
#endif
-#define PCPPIPRI (PZERO - 1)
-
int
pcppi_match(device_t parent, cfdata_t match, void *aux)
{
@@ -175,6 +174,7 @@ pcppi_isa_attach(device_t parent, device_t self, void *aux)
void
pcppi_childdet(device_t self, device_t child)
{
+
/* we hold no child references, so do nothing */
}
@@ -196,14 +196,16 @@ pcppi_detach(device_t self, int flags)
#if NPCKBD > 0
pckbd_unhook_bell(pcppi_pckbd_bell, sc);
#endif
+ mutex_spin_enter(&tty_lock);
pcppi_bell_stop(sc);
+ mutex_spin_exit(&tty_lock);
- callout_stop(&sc->sc_bell_ch);
+ callout_halt(&sc->sc_bell_ch, NULL);
callout_destroy(&sc->sc_bell_ch);
- bus_space_unmap(sc->sc_iot, sc->sc_ppi_ioh, sc->sc_size);
- mutex_destroy(&sc->sc_lock);
- cv_destroy(&sc->sc_stop_cv);
+ cv_destroy(&sc->sc_slp);
+
+ bus_space_unmap(sc->sc_iot, sc->sc_ppi_ioh, sc->sc_size);
return 0;
}
@@ -214,12 +216,11 @@ pcppi_attach(struct pcppi_softc *sc)
struct pcppi_attach_args pa;
device_t self = sc->sc_dv;
- callout_init(&sc->sc_bell_ch, 0);
-
- sc->sc_bellactive = sc->sc_bellpitch = sc->sc_slp = 0;
+ callout_init(&sc->sc_bell_ch, CALLOUT_MPSAFE);
+ callout_setfunc(&sc->sc_bell_ch, pcppi_bell_callout, sc);
+ cv_init(&sc->sc_slp, "bell");
- mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
- cv_init(&sc->sc_stop_cv, "bell");
+ sc->sc_bellactive = sc->sc_bellpitch = 0;
#if NPCKBD > 0
/* Provide a beeper for the PC Keyboard, if there isn't one already. */
@@ -274,21 +275,27 @@ pcppi_attach_speaker(device_t self)
void
pcppi_bell(pcppi_tag_t self, int pitch, int period, int slp)
{
+
+ mutex_spin_enter(&tty_lock);
+ pcppi_bell_locked(self, pitch, period, slp);
+ mutex_spin_exit(&tty_lock);
+}
+
+void
+pcppi_bell_locked(pcppi_tag_t self, int pitch, int period, int slp)
+{
struct pcppi_softc *sc = self;
- mutex_enter(&sc->sc_lock);
if (sc->sc_bellactive) {
if (sc->sc_timeout) {
sc->sc_timeout = 0;
callout_stop(&sc->sc_bell_ch);
}
- if (sc->sc_slp)
- cv_broadcast(&sc->sc_stop_cv);
+ cv_broadcast(&sc->sc_slp);
}
if (pitch == 0 || period == 0) {
- pcppi_bell_stop_unlocked(sc);
+ pcppi_bell_stop(sc);
sc->sc_bellpitch = 0;
- mutex_exit(&sc->sc_lock);
return;
}
if (!sc->sc_bellactive || sc->sc_bellpitch != pitch) {
@@ -306,24 +313,32 @@ pcppi_bell(pcppi_tag_t self, int pitch, int period, int slp)
sc->sc_bellactive = 1;
if (slp & PCPPI_BELL_POLL) {
delay((period * 1000000) / hz);
- pcppi_bell_stop_unlocked(sc);
+ pcppi_bell_stop(sc);
} else {
sc->sc_timeout = 1;
- callout_reset(&sc->sc_bell_ch, period, pcppi_bell_stop, sc);
+ callout_schedule(&sc->sc_bell_ch, period);
if (slp & PCPPI_BELL_SLEEP) {
- sc->sc_slp = 1;
- cv_wait_sig(&sc->sc_stop_cv, &sc->sc_lock);
- sc->sc_slp = 0;
+ cv_wait_sig(&sc->sc_slp, &tty_lock);
}
}
- mutex_exit(&sc->sc_lock);
}
static void
-pcppi_bell_stop_unlocked(void *arg)
+pcppi_bell_callout(void *arg)
{
struct pcppi_softc *sc = arg;
+ mutex_spin_enter(&tty_lock);
+ if (sc->sc_timeout != 0) {
+ pcppi_bell_stop(sc);
+ }
+ mutex_spin_exit(&tty_lock);
+}
+
+static void
+pcppi_bell_stop(struct pcppi_softc *sc)
+{
+
sc->sc_timeout = 0;
/* disable bell */
@@ -331,18 +346,7 @@ pcppi_bell_stop_unlocked(void *arg)
bus_space_read_1(sc->sc_iot, sc->sc_ppi_ioh, 0)
& ~PIT_SPKR);
sc->sc_bellactive = 0;
- if (sc->sc_slp)
- cv_broadcast(&sc->sc_stop_cv);
-}
-
-static void
-pcppi_bell_stop(void *arg)
-{
- struct pcppi_softc *sc = arg;
-
- mutex_enter(&sc->sc_lock);
- pcppi_bell_stop_unlocked(arg);
- mutex_exit(&sc->sc_lock);
+ cv_broadcast(&sc->sc_slp);
}
#if NPCKBD > 0
@@ -351,10 +355,12 @@ pcppi_pckbd_bell(void *arg, u_int pitch, u_int period, u_int volume,
int poll)
{
+ KASSERT(mutex_owned(&tty_lock));
+
/*
* Comes in as ms, goes out at ticks; volume ignored.
*/
- pcppi_bell(arg, pitch, (period * hz) / 1000,
+ pcppi_bell_locked(arg, pitch, (period * hz) / 1000,
poll ? PCPPI_BELL_POLL : 0);
}
#endif /* NPCKBD > 0 */
diff --git a/sys/dev/isa/pcppivar.h b/sys/dev/isa/pcppivar.h
index 84d239e93a8..dccff22f949 100644
--- a/sys/dev/isa/pcppivar.h
+++ b/sys/dev/isa/pcppivar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: pcppivar.h,v 1.10 2011/05/03 04:27:13 mrg Exp $ */
+/* $NetBSD: pcppivar.h,v 1.11 2011/11/23 23:07:32 jmcneill Exp $ */
/*
* Copyright (c) 1996 Carnegie-Mellon University.
@@ -44,14 +44,11 @@ struct pcppi_softc {
bus_size_t sc_size;
device_t sc_timer;
- struct callout sc_bell_ch;
-
int sc_bellactive, sc_bellpitch;
- int sc_slp;
int sc_timeout;
- kmutex_t sc_lock;
- kcondvar_t sc_stop_cv;
+ kcondvar_t sc_slp;
+ callout_t sc_bell_ch;
};
void pcppi_attach(struct pcppi_softc *);
@@ -61,5 +58,6 @@ int pcppi_detach(device_t, int);
#define PCPPI_BELL_POLL 0x02 /* synchronous; poll for complete */
void pcppi_bell(pcppi_tag_t, int, int, int);
+void pcppi_bell_locked(pcppi_tag_t, int, int, int);
#endif /* ! _PCPPIVAR_H_ */
diff --git a/sys/dev/isa/sb.c b/sys/dev/isa/sb.c
index 72b16fd9c2e..8967ad2e29a 100644
--- a/sys/dev/isa/sb.c
+++ b/sys/dev/isa/sb.c
@@ -1,4 +1,4 @@
-/* $NetBSD: sb.c,v 1.88 2008/03/15 21:09:02 cube Exp $ */
+/* $NetBSD: sb.c,v 1.89 2011/11/23 23:07:32 jmcneill Exp $ */
/*
* Copyright (c) 1991-1993 Regents of the University of California.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sb.c,v 1.88 2008/03/15 21:09:02 cube Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sb.c,v 1.89 2011/11/23 23:07:32 jmcneill Exp $");
#include "midi.h"
@@ -69,6 +69,7 @@ const struct midi_hw_if sb_midi_hw_if = {
sbdsp_midi_output,
sbdsp_midi_getinfo,
0, /* ioctl */
+ sbdsp_get_locks,
};
#endif
@@ -106,7 +107,7 @@ const struct audio_hw_if sb_hw_if = {
sbdsp_trigger_output,
sbdsp_trigger_input,
NULL,
- NULL,
+ sbdsp_get_locks,
};
/*
diff --git a/sys/dev/isa/sb_isa.c b/sys/dev/isa/sb_isa.c
index 91e12dccaf1..fb41807c95f 100644
--- a/sys/dev/isa/sb_isa.c
+++ b/sys/dev/isa/sb_isa.c
@@ -1,4 +1,4 @@
-/* $NetBSD: sb_isa.c,v 1.36 2008/03/15 21:09:02 cube Exp $ */
+/* $NetBSD: sb_isa.c,v 1.37 2011/11/23 23:07:32 jmcneill Exp $ */
/*
* Copyright (c) 1991-1993 Regents of the University of California.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sb_isa.c,v 1.36 2008/03/15 21:09:02 cube Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sb_isa.c,v 1.37 2011/11/23 23:07:32 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -171,8 +171,11 @@ sb_isa_attach(device_t parent, device_t self, void *aux)
return;
}
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
- IST_EDGE, IPL_AUDIO, sbdsp_intr, sc);
+ IST_EDGE, IPL_SCHED, sbdsp_intr, sc);
sbattach(sc);
}
diff --git a/sys/dev/isa/sbdsp.c b/sys/dev/isa/sbdsp.c
index 103b7a5b756..0bd65a838df 100644
--- a/sys/dev/isa/sbdsp.c
+++ b/sys/dev/isa/sbdsp.c
@@ -1,7 +1,7 @@
-/* $NetBSD: sbdsp.c,v 1.134 2010/02/24 22:37:58 dyoung Exp $ */
+/* $NetBSD: sbdsp.c,v 1.135 2011/11/23 23:07:32 jmcneill Exp $ */
/*-
- * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -74,7 +74,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sbdsp.c,v 1.134 2010/02/24 22:37:58 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sbdsp.c,v 1.135 2011/11/23 23:07:32 jmcneill Exp $");
#include "midi.h"
#include "mpu.h"
@@ -88,7 +88,7 @@ __KERNEL_RCSID(0, "$NetBSD: sbdsp.c,v 1.134 2010/02/24 22:37:58 dyoung Exp $");
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/buf.h>
-
+#include <sys/malloc.h>
#include <sys/cpu.h>
#include <sys/intr.h>
#include <sys/bus.h>
@@ -362,6 +362,9 @@ sbdsp_attach(struct sbdsp_softc *sc)
int i, error;
u_int v;
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
+
sbdsp_set_in_ports(sc, 1 << SB_MIC_VOL);
if (sc->sc_mixer_model != SBM_NONE) {
@@ -401,6 +404,9 @@ sbdsp_attach(struct sbdsp_softc *sc)
sc->in_filter = 0; /* no filters turned on, please */
}
+ mutex_spin_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
+
aprint_naive("\n");
aprint_normal(": dsp v%d.%02d%s\n",
SBVER_MAJOR(sc->sc_version), SBVER_MINOR(sc->sc_version),
@@ -414,7 +420,7 @@ sbdsp_attach(struct sbdsp_softc *sc)
sc->sc_drq8_maxsize = isa_dmamaxsize(sc->sc_ic,
sc->sc_drq8);
error = isa_dmamap_create(sc->sc_ic, sc->sc_drq8,
- sc->sc_drq8_maxsize, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW);
+ sc->sc_drq8_maxsize, BUS_DMA_WAITOK|BUS_DMA_ALLOCNOW);
if (error) {
aprint_error_dev(sc->sc_dev,
"can't create map for drq %d\n", sc->sc_drq8);
@@ -426,7 +432,7 @@ sbdsp_attach(struct sbdsp_softc *sc)
sc->sc_drq16_maxsize = isa_dmamaxsize(sc->sc_ic,
sc->sc_drq16);
error = isa_dmamap_create(sc->sc_ic, sc->sc_drq16,
- sc->sc_drq16_maxsize, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW);
+ sc->sc_drq16_maxsize, BUS_DMA_WAITOK|BUS_DMA_ALLOCNOW);
if (error) {
aprint_error_dev(sc->sc_dev,
"can't create map for drq %d\n", sc->sc_drq16);
@@ -445,7 +451,11 @@ sbdsp_resume(device_t dv, const pmf_qual_t *qual)
struct sbdsp_softc *sc = device_private(dv);
/* Reset the mixer. */
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
sbdsp_mix_write(sc, SBP_MIX_RESET, SBP_MIX_RESET);
+ mutex_spin_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
return true;
}
@@ -455,16 +465,13 @@ sbdsp_mix_write(struct sbdsp_softc *sc, int mixerport, int val)
{
bus_space_tag_t iot;
bus_space_handle_t ioh;
- int s;
iot = sc->sc_iot;
ioh = sc->sc_ioh;
- s = splaudio();
bus_space_write_1(iot, ioh, SBP_MIXER_ADDR, mixerport);
delay(20);
bus_space_write_1(iot, ioh, SBP_MIXER_DATA, val);
delay(30);
- splx(s);
}
int
@@ -473,16 +480,13 @@ sbdsp_mix_read(struct sbdsp_softc *sc, int mixerport)
bus_space_tag_t iot;
bus_space_handle_t ioh;
int val;
- int s;
iot = sc->sc_iot;
ioh = sc->sc_ioh;
- s = splaudio();
bus_space_write_1(iot, ioh, SBP_MIXER_ADDR, mixerport);
delay(20);
val = bus_space_read_1(iot, ioh, SBP_MIXER_DATA);
delay(30);
- splx(s);
return val;
}
@@ -578,6 +582,7 @@ sbdsp_set_params(
int mode;
sc = addr;
+
if (sc->sc_open == SB_OPEN_MIDI)
return EBUSY;
@@ -788,6 +793,7 @@ sbdsp_set_ifilter(void *addr, int which)
int mixval;
sc = addr;
+
mixval = sbdsp_mix_read(sc, SBP_INFILTER) & ~SBP_IFILTER_MASK;
switch (which) {
case 0:
@@ -830,6 +836,9 @@ sbdsp_set_in_ports(struct sbdsp_softc *sc, int mask)
int bitsl, bitsr;
int sbport;
+ KASSERT(mutex_owned(&sc->sc_lock));
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
if (sc->sc_open == SB_OPEN_MIDI)
return EBUSY;
@@ -1087,7 +1096,10 @@ void
sbdsp_pause(struct sbdsp_softc *sc)
{
- (void) tsleep(sbdsp_pause, PWAIT, "sbpause", hz / 8);
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+ mutex_spin_exit(&sc->sc_intr_lock);
+ (void)kpause("sbpause", false, hz/8, &sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
}
/*
@@ -1539,9 +1551,12 @@ sbdsp_intr(void *arg)
DPRINTFN(2, ("sbdsp_intr: intr8=%p, intr16=%p\n",
sc->sc_intr8, sc->sc_intr16));
+
+ mutex_spin_enter(&sc->sc_intr_lock);
if (ISSB16CLASS(sc)) {
irq = sbdsp_mix_read(sc, SBP_IRQ_STATUS);
if ((irq & (SBP_IRQ_DMA8 | SBP_IRQ_DMA16 | SBP_IRQ_MPU401)) == 0) {
+ mutex_spin_exit(&sc->sc_intr_lock);
DPRINTF(("sbdsp_intr: Spurious interrupt 0x%x\n", irq));
return 0;
}
@@ -1569,6 +1584,8 @@ sbdsp_intr(void *arg)
mpu_intr(sc_mpu);
}
#endif
+
+ mutex_spin_exit(&sc->sc_intr_lock);
return 1;
}
@@ -1589,6 +1606,9 @@ sbdsp_set_mixer_gain(struct sbdsp_softc *sc, int port)
{
int src, gain;
+ KASSERT(mutex_owned(&sc->sc_lock));
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
switch(sc->sc_mixer_model) {
case SBM_NONE:
return;
@@ -1694,8 +1714,12 @@ sbdsp_mixer_set_port(void *addr, mixer_ctrl_t *cp)
int mask, bits;
int lmask, rmask, lbits, rbits;
int mute, swap;
+ int error;
sc = addr;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+
if (sc->sc_open == SB_OPEN_MIDI)
return EBUSY;
@@ -1705,37 +1729,50 @@ sbdsp_mixer_set_port(void *addr, mixer_ctrl_t *cp)
if (sc->sc_mixer_model == SBM_NONE)
return EINVAL;
+ mutex_spin_enter(&sc->sc_intr_lock);
+ error = 0;
+
switch (cp->dev) {
case SB_TREBLE:
case SB_BASS:
if (sc->sc_mixer_model == SBM_CT1345 ||
sc->sc_mixer_model == SBM_CT1XX5) {
- if (cp->type != AUDIO_MIXER_ENUM)
+ if (cp->type != AUDIO_MIXER_ENUM) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return EINVAL;
+ }
switch (cp->dev) {
case SB_TREBLE:
sbdsp_set_ifilter(addr, cp->un.ord ? SB_TREBLE : 0);
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
case SB_BASS:
sbdsp_set_ifilter(addr, cp->un.ord ? SB_BASS : 0);
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
}
}
case SB_PCSPEAKER:
case SB_INPUT_GAIN:
case SB_OUTPUT_GAIN:
- if (!ISSBM1745(sc))
- return EINVAL;
+ if (!ISSBM1745(sc)) {
+ error = EINVAL;
+ break;
+ }
case SB_MIC_VOL:
case SB_LINE_IN_VOL:
- if (sc->sc_mixer_model == SBM_CT1335)
- return EINVAL;
+ if (sc->sc_mixer_model == SBM_CT1335) {
+ error = EINVAL;
+ break;
+ }
case SB_VOICE_VOL:
case SB_MIDI_VOL:
case SB_CD_VOL:
case SB_MASTER_VOL:
- if (cp->type != AUDIO_MIXER_VALUE)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_VALUE) {
+ error = EINVAL;
+ break;
+ }
/*
* All the mixer ports are stereo except for the microphone.
@@ -1745,15 +1782,19 @@ sbdsp_mixer_set_port(void *addr, mixer_ctrl_t *cp)
switch (cp->dev) {
case SB_MIC_VOL:
- if (cp->un.value.num_channels != 1)
- return EINVAL;
+ if (cp->un.value.num_channels != 1) {
+ error = EINVAL;
+ break;
+ }
lgain = rgain = SB_ADJUST_MIC_GAIN(sc,
cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
break;
case SB_PCSPEAKER:
- if (cp->un.value.num_channels != 1)
- return EINVAL;
+ if (cp->un.value.num_channels != 1) {
+ error = EINVAL;
+ break;
+ }
/* fall into */
case SB_INPUT_GAIN:
case SB_OUTPUT_GAIN:
@@ -1767,41 +1808,49 @@ sbdsp_mixer_set_port(void *addr, mixer_ctrl_t *cp)
cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
break;
case 2:
- if (sc->sc_mixer_model == SBM_CT1335)
- return EINVAL;
+ if (sc->sc_mixer_model == SBM_CT1335) {
+ error = EINVAL;
+ break;
+ }
lgain = SB_ADJUST_GAIN(sc,
cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]);
rgain = SB_ADJUST_GAIN(sc,
cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]);
break;
default:
- return EINVAL;
+ error = EINVAL;
+ break;
}
break;
}
- sc->gain[cp->dev][SB_LEFT] = lgain;
- sc->gain[cp->dev][SB_RIGHT] = rgain;
-
- sbdsp_set_mixer_gain(sc, cp->dev);
+ if (error == 0) {
+ sc->gain[cp->dev][SB_LEFT] = lgain;
+ sc->gain[cp->dev][SB_RIGHT] = rgain;
+ sbdsp_set_mixer_gain(sc, cp->dev);
+ }
break;
case SB_RECORD_SOURCE:
if (ISSBM1745(sc)) {
if (cp->type != AUDIO_MIXER_SET)
- return EINVAL;
- return sbdsp_set_in_ports(sc, cp->un.mask);
+ error = EINVAL;
+ else
+ error = sbdsp_set_in_ports(sc, cp->un.mask);
} else {
if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
- sc->in_port = cp->un.ord;
- return sbdsp_set_in_ports(sc, 1 << cp->un.ord);
+ error = EINVAL;
+ else {
+ sc->in_port = cp->un.ord;
+ error = sbdsp_set_in_ports(sc, 1 << cp->un.ord);
+ }
}
break;
case SB_AGC:
if (!ISSBM1745(sc) || cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
- sbdsp_mix_write(sc, SB16P_AGC, cp->un.ord & 1);
+ error = EINVAL;
+ else
+ sbdsp_mix_write(sc, SB16P_AGC, cp->un.ord & 1);
break;
case SB_CD_OUT_MUTE:
@@ -1813,8 +1862,10 @@ sbdsp_mixer_set_port(void *addr, mixer_ctrl_t *cp)
case SB_LINE_OUT_MUTE:
mask = SB16P_SW_LINE;
omute:
- if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_ENUM) {
+ error = EINVAL;
+ break;
+ }
bits = sbdsp_mix_read(sc, SB16P_OSWITCH);
sc->gain[cp->dev][SB_LR] = cp->un.ord != 0;
if (cp->un.ord)
@@ -1843,8 +1894,10 @@ sbdsp_mixer_set_port(void *addr, mixer_ctrl_t *cp)
lmask = SB16P_SW_MIDI_L;
rmask = SB16P_SW_MIDI_R;
imute:
- if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_ENUM) {
+ error = EINVAL;
+ break;
+ }
mask = lmask | rmask;
lbits = sbdsp_mix_read(sc, SB16P_ISWITCH_L) & ~mask;
rbits = sbdsp_mix_read(sc, SB16P_ISWITCH_R) & ~mask;
@@ -1870,10 +1923,12 @@ sbdsp_mixer_set_port(void *addr, mixer_ctrl_t *cp)
break;
default:
- return EINVAL;
+ error = EINVAL;
+ break;
}
- return 0;
+ mutex_spin_exit(&sc->sc_intr_lock);
+ return error;
}
int
@@ -1882,6 +1937,9 @@ sbdsp_mixer_get_port(void *addr, mixer_ctrl_t *cp)
struct sbdsp_softc *sc;
sc = addr;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+
if (sc->sc_open == SB_OPEN_MIDI)
return EBUSY;
@@ -1890,6 +1948,8 @@ sbdsp_mixer_get_port(void *addr, mixer_ctrl_t *cp)
if (sc->sc_mixer_model == SBM_NONE)
return EINVAL;
+ mutex_spin_enter(&sc->sc_intr_lock);
+
switch (cp->dev) {
case SB_TREBLE:
case SB_BASS:
@@ -1898,21 +1958,27 @@ sbdsp_mixer_get_port(void *addr, mixer_ctrl_t *cp)
switch (cp->dev) {
case SB_TREBLE:
cp->un.ord = sbdsp_get_ifilter(addr) == SB_TREBLE;
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
case SB_BASS:
cp->un.ord = sbdsp_get_ifilter(addr) == SB_BASS;
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
}
}
case SB_PCSPEAKER:
case SB_INPUT_GAIN:
case SB_OUTPUT_GAIN:
- if (!ISSBM1745(sc))
+ if (!ISSBM1745(sc)) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return EINVAL;
+ }
case SB_MIC_VOL:
case SB_LINE_IN_VOL:
- if (sc->sc_mixer_model == SBM_CT1335)
+ if (sc->sc_mixer_model == SBM_CT1335) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return EINVAL;
+ }
case SB_VOICE_VOL:
case SB_MIDI_VOL:
case SB_CD_VOL:
@@ -1920,8 +1986,10 @@ sbdsp_mixer_get_port(void *addr, mixer_ctrl_t *cp)
switch (cp->dev) {
case SB_MIC_VOL:
case SB_PCSPEAKER:
- if (cp->un.value.num_channels != 1)
+ if (cp->un.value.num_channels != 1) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return EINVAL;
+ }
/* fall into */
default:
switch (cp->un.value.num_channels) {
@@ -1936,6 +2004,7 @@ sbdsp_mixer_get_port(void *addr, mixer_ctrl_t *cp)
sc->gain[cp->dev][SB_RIGHT];
break;
default:
+ mutex_spin_exit(&sc->sc_intr_lock);
return EINVAL;
}
break;
@@ -1950,8 +2019,10 @@ sbdsp_mixer_get_port(void *addr, mixer_ctrl_t *cp)
break;
case SB_AGC:
- if (!ISSBM1745(sc))
+ if (!ISSBM1745(sc)) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return EINVAL;
+ }
cp->un.ord = sbdsp_mix_read(sc, SB16P_AGC);
break;
@@ -1970,9 +2041,12 @@ sbdsp_mixer_get_port(void *addr, mixer_ctrl_t *cp)
break;
default:
+ mutex_spin_exit(&sc->sc_intr_lock);
return EINVAL;
}
+ mutex_spin_exit(&sc->sc_intr_lock);
+
return 0;
}
@@ -1986,6 +2060,8 @@ sbdsp_mixer_query_devinfo(void *addr, mixer_devinfo_t *dip)
DPRINTF(("sbdsp_mixer_query_devinfo: model=%d index=%d\n",
sc->sc_mixer_model, dip->index));
+ KASSERT(mutex_owned(&sc->sc_lock));
+
if (sc->sc_mixer_model == SBM_NONE)
return ENXIO;
@@ -2272,8 +2348,7 @@ sbdsp_mixer_query_devinfo(void *addr, mixer_devinfo_t *dip)
}
void *
-sb_malloc(void *addr, int direction, size_t size,
- struct malloc_type *pool, int flags)
+sb_malloc(void *addr, int direction, size_t size)
{
struct sbdsp_softc *sc;
int drq;
@@ -2283,14 +2358,14 @@ sb_malloc(void *addr, int direction, size_t size,
drq = sc->sc_drq8;
else
drq = sc->sc_drq16;
- return isa_malloc(sc->sc_ic, drq, size, pool, flags);
+ return isa_malloc(sc->sc_ic, drq, size, M_DEVBUF, M_WAITOK);
}
void
-sb_free(void *addr, void *ptr, struct malloc_type *pool)
+sb_free(void *addr, void *ptr, size_t size)
{
- isa_free(ptr, pool);
+ isa_free(ptr, M_DEVBUF);
}
size_t
@@ -2327,6 +2402,16 @@ sbdsp_get_props(void *addr)
(sc->sc_fullduplex ? AUDIO_PROP_FULLDUPLEX : 0);
}
+void
+sbdsp_get_locks(void *addr, kmutex_t **intr, kmutex_t **proc)
+{
+ struct sbdsp_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *proc = &sc->sc_lock;
+}
+
#if NMPU > 0
/*
* MIDI related routines.
@@ -2403,9 +2488,10 @@ sbdsp_midi_intr(void *addr)
struct sbdsp_softc *sc;
sc = addr;
+
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
sc->sc_intrm(sc->sc_argm, sbdsp_rdsp(sc));
return (0);
}
-
#endif
-
diff --git a/sys/dev/isa/sbdspvar.h b/sys/dev/isa/sbdspvar.h
index d78cbd33915..bf21bcc4696 100644
--- a/sys/dev/isa/sbdspvar.h
+++ b/sys/dev/isa/sbdspvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: sbdspvar.h,v 1.60 2009/05/12 09:10:15 cegger Exp $ */
+/* $NetBSD: sbdspvar.h,v 1.61 2011/11/23 23:07:33 jmcneill Exp $ */
/*
* Copyright (c) 1991-1993 Regents of the University of California.
@@ -97,6 +97,8 @@ struct sbdsp_softc {
bus_space_tag_t sc_iot; /* tag */
bus_space_handle_t sc_ioh; /* handle */
void *sc_ih; /* interrupt vectoring */
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
/* XXX These are only for setting chip configuration registers. */
int sc_iobase; /* I/O port base address */
@@ -246,13 +248,13 @@ int sbdsp_mixer_set_port(void *, mixer_ctrl_t *);
int sbdsp_mixer_get_port(void *, mixer_ctrl_t *);
int sbdsp_mixer_query_devinfo(void *, mixer_devinfo_t *);
-void *sb_malloc(void *, int, size_t, struct malloc_type *, int);
-void sb_free(void *, void *, struct malloc_type *);
+void *sb_malloc(void *, int, size_t);
+void sb_free(void *, void *, size_t);
size_t sb_round_buffersize(void *, int, size_t);
paddr_t sb_mappage(void *, void *, off_t, int);
int sbdsp_get_props(void *);
-
+void sbdsp_get_locks(void *, kmutex_t **, kmutex_t **);
int sbdsp_midi_open(void *, int, void (*iintr)(void *, int),
void (*ointr)(void *), void *);
diff --git a/sys/dev/isa/wss.c b/sys/dev/isa/wss.c
index 66519ca75a6..64c8cff6f6e 100644
--- a/sys/dev/isa/wss.c
+++ b/sys/dev/isa/wss.c
@@ -1,4 +1,4 @@
-/* $NetBSD: wss.c,v 1.69 2011/06/02 13:02:40 nonaka Exp $ */
+/* $NetBSD: wss.c,v 1.70 2011/11/23 23:07:33 jmcneill Exp $ */
/*
* Copyright (c) 1994 John Brezak
@@ -36,18 +36,17 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wss.c,v 1.69 2011/06/02 13:02:40 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wss.c,v 1.70 2011/11/23 23:07:33 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/errno.h>
-
#include <sys/cpu.h>
#include <sys/intr.h>
#include <sys/bus.h>
-
#include <sys/audioio.h>
+
#include <dev/audio_if.h>
#include <dev/isa/isavar.h>
@@ -74,6 +73,7 @@ struct audio_device wss_device = {
"WSS"
};
+int wss_intr(void *);
int wss_getdev(void *, struct audio_device *);
int wss_mixer_set_port(void *, mixer_ctrl_t *);
@@ -112,7 +112,7 @@ const struct audio_hw_if wss_hw_if = {
ad1848_isa_trigger_output,
ad1848_isa_trigger_input,
NULL,
- NULL, /* powerstate */
+ ad1848_get_locks,
};
/*
@@ -128,10 +128,13 @@ wssattach(struct wss_softc *sc)
#endif
ac = &sc->sc_ad1848.sc_ad1848;
+
+ ad1848_init_locks(ac, IPL_SCHED);
+
madattach(sc);
sc->sc_ad1848.sc_ih = isa_intr_establish(sc->wss_ic, sc->wss_irq,
- IST_EDGE, IPL_AUDIO, ad1848_isa_intr, &sc->sc_ad1848);
+ IST_EDGE, IPL_SCHED, wss_intr, &sc->sc_ad1848);
ad1848_isa_attach(&sc->sc_ad1848);
@@ -173,6 +176,23 @@ wssattach(struct wss_softc *sc)
}
int
+wss_intr(void *addr)
+{
+ struct ad1848_isa_softc *sc;
+ int handled;
+
+ sc = addr;
+
+ mutex_spin_enter(&sc->sc_ad1848.sc_intr_lock);
+
+ handled = ad1848_isa_intr(sc);
+
+ mutex_spin_exit(&sc->sc_ad1848.sc_intr_lock);
+
+ return handled;
+}
+
+int
wss_getdev(void *addr, struct audio_device *retp)
{
@@ -388,7 +408,6 @@ mad_read(struct wss_softc *sc, int port)
{
u_int tmp;
int pwd;
- int s;
switch (sc->mad_chip_type) { /* Output password */
case MAD_82C928:
@@ -404,10 +423,8 @@ mad_read(struct wss_softc *sc, int port)
default:
panic("mad_read: Bad chip type=%d", sc->mad_chip_type);
}
- s = splaudio(); /* don't want an interrupt between outb&inb */
bus_space_write_1(sc->sc_iot, sc->mad_ioh, MC_PASSWD_REG, pwd);
tmp = bus_space_read_1(sc->sc_iot, sc->mad_ioh, port);
- splx(s);
return tmp;
}
@@ -415,7 +432,6 @@ void
mad_write(struct wss_softc *sc, int port, int value)
{
int pwd;
- int s;
switch (sc->mad_chip_type) { /* Output password */
case MAD_82C928:
@@ -431,10 +447,8 @@ mad_write(struct wss_softc *sc, int port, int value)
default:
panic("mad_write: Bad chip type=%d", sc->mad_chip_type);
}
- s = splaudio();
bus_space_write_1(sc->sc_iot, sc->mad_ioh, MC_PASSWD_REG, pwd);
bus_space_write_1(sc->sc_iot, sc->mad_ioh, port, value & 0xff);
- splx(s);
}
void
diff --git a/sys/dev/isa/ym.c b/sys/dev/isa/ym.c
index c54819eb28c..5d387374ba4 100644
--- a/sys/dev/isa/ym.c
+++ b/sys/dev/isa/ym.c
@@ -1,7 +1,7 @@
-/* $NetBSD: ym.c,v 1.41 2011/06/02 14:12:25 tsutsui Exp $ */
+/* $NetBSD: ym.c,v 1.42 2011/11/23 23:07:33 jmcneill Exp $ */
/*-
- * Copyright (c) 1999-2002 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999-2002, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ym.c,v 1.41 2011/06/02 14:12:25 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ym.c,v 1.42 2011/11/23 23:07:33 jmcneill Exp $");
#include "mpu_ym.h"
#include "opt_ym.h"
@@ -151,7 +151,8 @@ static void ym_restore_codec_regs(struct ym_softc *);
int ym_codec_power_ctl(void *, int);
static void ym_chip_powerdown(struct ym_softc *);
static void ym_chip_powerup(struct ym_softc *, int);
-void ym_powerdown_blocks(void *);
+static void ym_powerdown_blocks(struct ym_softc *);
+static void ym_powerdown_callout(void *);
void ym_power_ctl(struct ym_softc *, int, int);
#endif
@@ -194,7 +195,7 @@ const struct audio_hw_if ym_hw_if = {
ad1848_isa_trigger_output,
ad1848_isa_trigger_input,
NULL,
- NULL, /* powerstate */
+ ad1848_get_locks,
};
static inline int ym_read(struct ym_softc *, int);
@@ -211,7 +212,9 @@ ym_attach(struct ym_softc *sc)
struct audio_attach_args arg;
ac = &sc->sc_ad1848.sc_ad1848;
- callout_init(&sc->sc_powerdown_ch, 0);
+ callout_init(&sc->sc_powerdown_ch, CALLOUT_MPSAFE);
+ cv_init(&sc->sc_cv, "ym");
+ ad1848_init_locks(ac, IPL_SCHED);
/* Mute the output to reduce noise during initialization. */
ym_mute(sc, SA3_VOL_L, 1);
@@ -221,7 +224,7 @@ ym_attach(struct ym_softc *sc)
ac->chip_name = YM_IS_SA3(sc) ? "OPL3-SA3" : "OPL3-SA2";
sc->sc_ad1848.sc_ih = isa_intr_establish(sc->sc_ic, sc->ym_irq,
- IST_EDGE, IPL_AUDIO, ym_intr, sc);
+ IST_EDGE, IPL_SCHED, ym_intr, sc);
#ifndef AUDIO_NO_POWER_CTL
sc->sc_ad1848.powerctl = ym_codec_power_ctl;
@@ -279,6 +282,7 @@ ym_attach(struct ym_softc *sc)
#endif
/* This must be AFTER the attachment of sub-devices. */
+ mutex_spin_enter(&sc->sc_ad1848.sc_ad1848.sc_intr_lock);
ym_init(sc);
#ifndef AUDIO_NO_POWER_CTL
@@ -296,6 +300,7 @@ ym_attach(struct ym_softc *sc)
sc->sc_on_blocks |= YM_POWER_JOYSTICK; /* prevents chip powerdown */
#endif
ym_powerdown_blocks(sc);
+ mutex_spin_exit(&sc->sc_ad1848.sc_ad1848.sc_intr_lock);
if (!pmf_device_register(ac->sc_dev, ym_suspend, ym_resume)) {
aprint_error_dev(ac->sc_dev,
@@ -346,6 +351,8 @@ ym_init(struct ym_softc *sc)
{
uint8_t dpd, apd;
+ KASSERT(mutex_owned(&sc->sc_ad1848.sc_ad1848.sc_intr_lock));
+
/* Mute SoundBlaster output if possible. */
if (sc->sc_sb_ioh) {
bus_space_write_1(sc->sc_iot, sc->sc_sb_ioh, SBP_MIXER_ADDR,
@@ -521,6 +528,8 @@ ym_set_3d(struct ym_softc *sc, mixer_ctrl_t *cp,
{
uint8_t l, r, e;
+ KASSERT(mutex_owned(&sc->sc_ad1848.sc_ad1848.sc_intr_lock));
+
ad1848_to_vol(cp, val);
l = val->left;
@@ -573,6 +582,8 @@ ym_mixer_set_port(void *addr, mixer_ctrl_t *cp)
if (!YM_IS_SA3(sc) && YM_MIXER_SA3_ONLY(cp->dev))
return ENXIO;
+ mutex_spin_enter(&ac->sc_intr_lock);
+
#ifndef AUDIO_NO_POWER_CTL
/* Power-up chip */
ym_power_ctl(sc, YM_POWER_CODEC_CTL, 1);
@@ -693,6 +704,7 @@ out:
/* Power-down chip */
ym_power_ctl(sc, YM_POWER_CODEC_CTL, 0);
#endif
+ mutex_spin_exit(&ac->sc_intr_lock);
return error;
}
@@ -717,6 +729,7 @@ ym_mixer_get_port(void *addr, mixer_ctrl_t *cp)
* SA2 doesn't have hardware volume interrupt.
* Read current value and update every time.
*/
+ mutex_spin_enter(&ac->sc_intr_lock);
#ifndef AUDIO_NO_POWER_CTL
/* Power-up chip */
ym_power_ctl(sc, YM_POWER_CODEC_CTL, 1);
@@ -726,6 +739,7 @@ ym_mixer_get_port(void *addr, mixer_ctrl_t *cp)
/* Power-down chip */
ym_power_ctl(sc, YM_POWER_CODEC_CTL, 0);
#endif
+ mutex_spin_exit(&ac->sc_intr_lock);
}
ad1848_from_vol(cp, &sc->master_gain);
return 0;
@@ -1021,10 +1035,13 @@ ym_intr(void *arg)
u_int8_t ist;
int processed;
+ mutex_spin_enter(&sc->sc_ad1848.sc_ad1848.sc_intr_lock);
+
/* OPL3 timer is currently unused. */
if (((ist = ym_read(sc, SA3_IRQA_STAT)) &
~(SA3_IRQ_STAT_SB|SA3_IRQ_STAT_OPL3)) == 0) {
DPRINTF(("%s: ym_intr: spurious interrupt\n", DVNAME(sc)));
+ mutex_spin_exit(&sc->sc_ad1848.sc_ad1848.sc_intr_lock);
return 0;
}
@@ -1057,6 +1074,7 @@ ym_intr(void *arg)
}
} while (processed && (ist = ym_read(sc, SA3_IRQA_STAT)));
+ mutex_spin_exit(&sc->sc_ad1848.sc_ad1848.sc_intr_lock);
return 1;
}
@@ -1110,16 +1128,16 @@ static bool
ym_suspend(device_t self, const pmf_qual_t *qual)
{
struct ym_softc *sc = device_private(self);
- int s;
DPRINTF(("%s: ym_power_hook: suspend\n", DVNAME(sc)));
- s = splaudio();
+ mutex_spin_enter(&sc->sc_ad1848.sc_ad1848.sc_intr_lock);
/*
* suspending...
*/
- callout_stop(&sc->sc_powerdown_ch);
+ callout_halt(&sc->sc_powerdown_ch,
+ &sc->sc_ad1848.sc_ad1848.sc_intr_lock);
if (sc->sc_turning_off)
ym_powerdown_blocks(sc);
@@ -1139,7 +1157,7 @@ ym_suspend(device_t self, const pmf_qual_t *qual)
sc->sc_sa3_scan[SA3_PWR_MNG] = ym_read(sc, SA3_PWR_MNG);
if (sc->sc_on_blocks)
ym_chip_powerdown(sc);
- splx(s);
+ mutex_spin_exit(&sc->sc_ad1848.sc_ad1848.sc_intr_lock);
return true;
}
@@ -1148,11 +1166,10 @@ ym_resume(device_t self, const pmf_qual_t *qual)
{
struct ym_softc *sc = device_private(self);
int i, xmax;
- int s;
DPRINTF(("%s: ym_power_hook: resume\n", DVNAME(sc)));
- s = splaudio();
+ mutex_spin_enter(&sc->sc_ad1848.sc_ad1848.sc_intr_lock);
/*
* resuming...
*/
@@ -1175,7 +1192,7 @@ ym_resume(device_t self, const pmf_qual_t *qual)
ym_write(sc, SA3_PWR_MNG, sc->sc_sa3_scan[SA3_PWR_MNG]);
if (YM_IS_SA3(sc))
ym_write(sc, SA3_DPWRDWN, sc->sc_sa3_scan[SA3_DPWRDWN]);
- splx(s);
+ mutex_spin_exit(&sc->sc_ad1848.sc_ad1848.sc_intr_lock);
return true;
}
@@ -1189,6 +1206,7 @@ ym_codec_power_ctl(void *arg, int flags)
sc = arg;
ac = &sc->sc_ad1848.sc_ad1848;
DPRINTF(("%s: ym_codec_power_ctl: flags = 0x%x\n", DVNAME(sc), flags));
+ KASSERT(mutex_owned(&ac->sc_intr_lock));
if (flags != 0) {
parts = 0;
@@ -1211,8 +1229,6 @@ ym_codec_power_ctl(void *arg, int flags)
/*
* Enter Power Save mode or Global Power Down mode.
* Total dissipation becomes 5mA and 10uA (typ.) respective.
- *
- * This must be called at splaudio().
*/
static void
ym_chip_powerdown(struct ym_softc *sc)
@@ -1220,6 +1236,7 @@ ym_chip_powerdown(struct ym_softc *sc)
int i, xmax;
DPRINTF(("%s: ym_chip_powerdown\n", DVNAME(sc)));
+ KASSERT(mutex_owned(&sc->sc_ad1848.sc_ad1848.sc_intr_lock));
xmax = YM_IS_SA3(sc) ? YM_SAVE_REG_MAX_SA3 : YM_SAVE_REG_MAX_SA2;
@@ -1236,17 +1253,14 @@ ym_chip_powerdown(struct ym_softc *sc)
/*
* Power up from Power Save / Global Power Down Mode.
- *
- * We assume no ym interrupt shall occur, since the chip is
- * in power-down mode (or should be blocked by splaudio()).
*/
static void
ym_chip_powerup(struct ym_softc *sc, int nosleep)
{
- int wchan;
uint8_t pw;
DPRINTF(("%s: ym_chip_powerup\n", DVNAME(sc)));
+ KASSERT(mutex_owned(&sc->sc_ad1848.sc_ad1848.sc_intr_lock));
pw = ym_read(sc, SA3_PWR_MNG);
@@ -1260,7 +1274,8 @@ ym_chip_powerup(struct ym_softc *sc, int nosleep)
if (nosleep)
delay(100000);
else
- tsleep(&wchan, PWAIT, "ym_pu1", hz / 10);
+ kpause("ym_pu1", false, hz / 10,
+ &sc->sc_ad1848.sc_ad1848.sc_intr_lock);
pw &= ~(SA3_PWR_MNG_PSV | SA3_PWR_MNG_PDN);
ym_write(sc, SA3_PWR_MNG, pw);
@@ -1269,7 +1284,8 @@ ym_chip_powerup(struct ym_softc *sc, int nosleep)
if (nosleep)
delay(70000);
else
- tsleep(&wchan, PWAIT, "ym_pu2", hz / 14);
+ kpause("ym_pu1", false, hz / 10,
+ &sc->sc_ad1848.sc_ad1848.sc_intr_lock);
/* The chip is muted automatically --- unmute it now. */
ym_mute(sc, SA3_VOL_L, sc->master_mute);
@@ -1277,21 +1293,31 @@ ym_chip_powerup(struct ym_softc *sc, int nosleep)
}
/* callout handler for power-down */
-void
-ym_powerdown_blocks(void *arg)
+static void
+ym_powerdown_callout(void *arg)
{
struct ym_softc *sc;
+
+ sc = arg;
+
+ mutex_spin_enter(&sc->sc_ad1848.sc_ad1848.sc_intr_lock);
+ if ((sc->sc_in_power_ctl & YM_POWER_CTL_INUSE) == 0) {
+ ym_powerdown_blocks(sc);
+ }
+ mutex_spin_exit(&sc->sc_ad1848.sc_ad1848.sc_intr_lock);
+}
+
+static void
+ym_powerdown_blocks(struct ym_softc *sc)
+{
uint16_t parts;
uint16_t on_blocks;
uint8_t sv;
- int s;
- sc = arg;
on_blocks = sc->sc_on_blocks;
DPRINTF(("%s: ym_powerdown_blocks: turning_off 0x%x\n",
DVNAME(sc), sc->sc_turning_off));
-
- s = splaudio();
+ KASSERT(mutex_owned(&sc->sc_ad1848.sc_ad1848.sc_intr_lock));
on_blocks = sc->sc_on_blocks;
@@ -1336,8 +1362,6 @@ ym_powerdown_blocks(void *arg)
/* Restore the state of the chip. */
bus_space_write_1(sc->sc_iot, sc->sc_controlioh, SA3_CTL_INDEX, sv);
-
- splx(s);
}
/*
@@ -1346,31 +1370,26 @@ ym_powerdown_blocks(void *arg)
void
ym_power_ctl(struct ym_softc *sc, int parts, int onoff)
{
- int s;
int need_restore_codec;
+ KASSERT(mutex_owned(&sc->sc_ad1848.sc_ad1848.sc_intr_lock));
+
DPRINTF(("%s: ym_power_ctl: parts = 0x%x, %s\n",
DVNAME(sc), parts, onoff ? "on" : "off"));
-#ifdef DIAGNOSTIC
- if (curproc == NULL)
- panic("ym_power_ctl: no curproc");
-#endif
/* This function may sleep --- needs locking. */
while (sc->sc_in_power_ctl & YM_POWER_CTL_INUSE) {
sc->sc_in_power_ctl |= YM_POWER_CTL_WANTED;
DPRINTF(("%s: ym_power_ctl: sleeping\n", DVNAME(sc)));
- tsleep(&sc->sc_in_power_ctl, PWAIT, "ym_pc", 0);
+ cv_wait(&sc->sc_cv, &sc->sc_ad1848.sc_ad1848.sc_intr_lock);
DPRINTF(("%s: ym_power_ctl: awaken\n", DVNAME(sc)));
}
sc->sc_in_power_ctl |= YM_POWER_CTL_INUSE;
- /* Defeat softclock interrupts. */
- s = splsoftclock();
-
/* If ON requested to parts which are scheduled to OFF, cancel it. */
if (onoff && sc->sc_turning_off && (sc->sc_turning_off &= ~parts) == 0)
- callout_stop(&sc->sc_powerdown_ch);
+ callout_halt(&sc->sc_powerdown_ch,
+ &sc->sc_ad1848.sc_ad1848.sc_intr_lock);
if (!onoff && sc->sc_turning_off)
parts &= ~sc->sc_turning_off;
@@ -1380,9 +1399,8 @@ ym_power_ctl(struct ym_softc *sc, int parts, int onoff)
/* Cancel previous timeout if needed. */
if (parts != 0 && sc->sc_turning_off)
- callout_stop(&sc->sc_powerdown_ch);
-
- (void) splx(s);
+ callout_halt(&sc->sc_powerdown_ch,
+ &sc->sc_ad1848.sc_ad1848.sc_intr_lock);
if (parts == 0)
goto unlock; /* no work to do */
@@ -1401,8 +1419,6 @@ ym_power_ctl(struct ym_softc *sc, int parts, int onoff)
if (parts & YM_POWER_CODEC_CTL)
parts |= YM_POWER_CODEC_P | YM_POWER_CODEC_R;
- s = splaudio();
-
if (YM_IS_SA3(sc)) {
/* OPL3-SA3 */
ym_write(sc, SA3_DPWRDWN,
@@ -1418,8 +1434,6 @@ ym_power_ctl(struct ym_softc *sc, int parts, int onoff)
}
if (need_restore_codec)
ym_restore_codec_regs(sc);
-
- (void) splx(s);
} else {
/* Turning off is delayed. */
sc->sc_turning_off |= parts;
@@ -1428,11 +1442,11 @@ ym_power_ctl(struct ym_softc *sc, int parts, int onoff)
/* Schedule turning off. */
if (sc->sc_pow_mode != YM_POWER_NOSAVE && sc->sc_turning_off)
callout_reset(&sc->sc_powerdown_ch, hz * sc->sc_pow_timeout,
- ym_powerdown_blocks, sc);
+ ym_powerdown_callout, sc);
unlock:
if (sc->sc_in_power_ctl & YM_POWER_CTL_WANTED)
- wakeup(&sc->sc_in_power_ctl);
+ cv_broadcast(&sc->sc_cv);
sc->sc_in_power_ctl = 0;
}
#endif /* not AUDIO_NO_POWER_CTL */
diff --git a/sys/dev/isa/ymvar.h b/sys/dev/isa/ymvar.h
index 7a7b692d98b..fb915bac783 100644
--- a/sys/dev/isa/ymvar.h
+++ b/sys/dev/isa/ymvar.h
@@ -1,7 +1,7 @@
-/* $NetBSD: ymvar.h,v 1.12 2009/05/12 09:10:16 cegger Exp $ */
+/* $NetBSD: ymvar.h,v 1.13 2011/11/23 23:07:33 jmcneill Exp $ */
/*-
- * Copyright (c) 1999-2000, 2002 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999-2000, 2002, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -154,7 +154,8 @@ struct ym_softc {
bus_space_handle_t sc_opl_ioh;
bus_space_handle_t sc_sb_ioh; /* only used to disable it */
- struct callout sc_powerdown_ch;
+ callout_t sc_powerdown_ch;
+ kcondvar_t sc_cv;
int master_mute, mic_mute;
struct ad1848_volume master_gain;
diff --git a/sys/dev/isapnp/gus_isapnp.c b/sys/dev/isapnp/gus_isapnp.c
index 0dbcae1d3fa..5e27e562f55 100644
--- a/sys/dev/isapnp/gus_isapnp.c
+++ b/sys/dev/isapnp/gus_isapnp.c
@@ -1,7 +1,7 @@
-/* $NetBSD: gus_isapnp.c,v 1.35 2009/05/12 10:16:35 cegger Exp $ */
+/* $NetBSD: gus_isapnp.c,v 1.36 2011/11/23 23:07:33 jmcneill Exp $ */
/*
- * Copyright (c) 1997, 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1997, 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Author: Kari Mettinen
@@ -29,27 +29,21 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gus_isapnp.c,v 1.35 2009/05/12 10:16:35 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gus_isapnp.c,v 1.36 2011/11/23 23:07:33 jmcneill Exp $");
#include "guspnp.h"
#if NGUSPNP > 0
#include <sys/param.h>
-#include <sys/fcntl.h>
-#include <sys/vnode.h>
-#include <sys/poll.h>
-#include <sys/malloc.h>
-#include <sys/select.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/syslog.h>
#include <sys/device.h>
#include <sys/proc.h>
-
#include <sys/bus.h>
-
#include <sys/audioio.h>
+
#include <dev/audio_if.h>
#include <dev/audiovar.h>
#include <dev/mulaw.h>
@@ -61,7 +55,6 @@ __KERNEL_RCSID(0, "$NetBSD: gus_isapnp.c,v 1.35 2009/05/12 10:16:35 cegger Exp $
#include <dev/isapnp/isapnpvar.h>
#include <dev/isapnp/isapnpdevs.h>
-
#include <dev/ic/interwavevar.h>
#include <dev/ic/interwavereg.h>
@@ -98,7 +91,7 @@ static const struct audio_hw_if guspnp_hw_if = {
NULL, /* trigger_output */
NULL, /* trigger_input */
NULL, /* dev_ioctl */
- NULL, /* powerstate */
+ iw_get_locks,
};
CFATTACH_DECL(guspnp, sizeof(struct iw_softc),
diff --git a/sys/dev/isapnp/joy_isapnp.c b/sys/dev/isapnp/joy_isapnp.c
index e10b1482f0a..460e347f984 100644
--- a/sys/dev/isapnp/joy_isapnp.c
+++ b/sys/dev/isapnp/joy_isapnp.c
@@ -1,7 +1,7 @@
-/* $NetBSD: joy_isapnp.c,v 1.12 2008/04/28 20:23:53 martin Exp $ */
+/* $NetBSD: joy_isapnp.c,v 1.13 2011/11/23 23:07:33 jmcneill Exp $ */
/*-
- * Copyright (c) 1996 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: joy_isapnp.c,v 1.12 2008/04/28 20:23:53 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: joy_isapnp.c,v 1.13 2011/11/23 23:07:33 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -46,10 +46,15 @@ __KERNEL_RCSID(0, "$NetBSD: joy_isapnp.c,v 1.12 2008/04/28 20:23:53 martin Exp $
#include <dev/ic/joyvar.h>
+struct joy_isapnp_softc {
+ struct joy_softc sc_joy;
+ kmutex_t sc_lock;
+};
+
static int joy_isapnp_match(device_t, cfdata_t, void *);
static void joy_isapnp_attach(device_t, device_t, void *);
-CFATTACH_DECL_NEW(joy_isapnp, sizeof(struct joy_softc),
+CFATTACH_DECL_NEW(joy_isapnp, sizeof(struct joy_isapnp_softc),
joy_isapnp_match, joy_isapnp_attach, NULL, NULL);
static int
@@ -67,6 +72,7 @@ static void
joy_isapnp_attach(device_t parent, device_t self, void *aux)
{
struct joy_softc *sc = device_private(self);
+ struct joy_isapnp_softc *isc = device_private(self);
struct isapnp_attach_args *ipa = aux;
bus_space_handle_t ioh;
@@ -86,9 +92,12 @@ joy_isapnp_attach(device_t parent, device_t self, void *aux)
} else
ioh = ipa->ipa_io[0].h;
+ mutex_init(&isc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+
sc->sc_iot = ipa->ipa_iot;
sc->sc_ioh = ioh;
sc->sc_dev = self;
+ sc->sc_lock = &isc->sc_lock;
aprint_normal_dev(self, "%s %s\n", ipa->ipa_devident,
ipa->ipa_devclass);
diff --git a/sys/dev/isapnp/mpu_isapnp.c b/sys/dev/isapnp/mpu_isapnp.c
index 913b023b733..123036f88c0 100644
--- a/sys/dev/isapnp/mpu_isapnp.c
+++ b/sys/dev/isapnp/mpu_isapnp.c
@@ -1,7 +1,7 @@
-/* $NetBSD: mpu_isapnp.c,v 1.17 2008/03/27 10:22:01 xtraeme Exp $ */
+/* $NetBSD: mpu_isapnp.c,v 1.18 2011/11/23 23:07:33 jmcneill Exp $ */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mpu_isapnp.c,v 1.17 2008/03/27 10:22:01 xtraeme Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mpu_isapnp.c,v 1.18 2011/11/23 23:07:33 jmcneill Exp $");
#include "midi.h"
@@ -12,10 +12,9 @@ __KERNEL_RCSID(0, "$NetBSD: mpu_isapnp.c,v 1.17 2008/03/27 10:22:01 xtraeme Exp
#include <sys/syslog.h>
#include <sys/device.h>
#include <sys/proc.h>
-
#include <sys/bus.h>
-
#include <sys/audioio.h>
+
#include <dev/audio_if.h>
#include <dev/midi_if.h>
#include <dev/mulaw.h>
@@ -34,6 +33,7 @@ static void mpu_isapnp_attach(device_t, device_t, void *);
struct mpu_isapnp_softc {
void *sc_ih;
+ kmutex_t sc_lock;
struct mpu_softc sc_mpu;
};
@@ -65,11 +65,15 @@ mpu_isapnp_attach(device_t parent, device_t self, void *aux)
return;
}
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SCHED);
+
sc->sc_mpu.iot = ipa->ipa_iot;
sc->sc_mpu.ioh = ipa->ipa_io[0].h;
+ sc->sc_mpu.lock = &sc->sc_lock;
if (!mpu_find(&sc->sc_mpu)) {
aprint_error_dev(self, "find failed\n");
+ mutex_destroy(&sc->sc_lock);
return;
}
@@ -81,5 +85,5 @@ mpu_isapnp_attach(device_t parent, device_t self, void *aux)
midi_attach_mi(&mpu_midi_hw_if, &sc->sc_mpu, self);
sc->sc_ih = isa_intr_establish(ipa->ipa_ic, ipa->ipa_irq[0].num,
- ipa->ipa_irq[0].type, IPL_AUDIO, mpu_intr, &sc->sc_mpu);
+ ipa->ipa_irq[0].type, IPL_SCHED, mpu_intr, &sc->sc_mpu);
}
diff --git a/sys/dev/midi.c b/sys/dev/midi.c
index 787f131a556..1ef38561f02 100644
--- a/sys/dev/midi.c
+++ b/sys/dev/midi.c
@@ -1,12 +1,12 @@
-/* $NetBSD: midi.c,v 1.72 2010/07/27 14:34:33 jakllsch Exp $ */
+/* $NetBSD: midi.c,v 1.73 2011/11/23 23:07:31 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson (augustss@NetBSD.org) and (MIDI FST and Active
- * Sense handling) Chapman Flack (chap@NetBSD.org).
+ * by Lennart Augustsson (augustss@NetBSD.org), (MIDI FST and Active
+ * Sense handling) Chapman Flack (chap@NetBSD.org), and Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: midi.c,v 1.72 2010/07/27 14:34:33 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: midi.c,v 1.73 2011/11/23 23:07:31 jmcneill Exp $");
#include "midi.h"
#include "sequencer.h"
@@ -42,7 +42,6 @@ __KERNEL_RCSID(0, "$NetBSD: midi.c,v 1.72 2010/07/27 14:34:33 jakllsch Exp $");
#include <sys/vnode.h>
#include <sys/select.h>
#include <sys/poll.h>
-#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/callout.h>
@@ -81,41 +80,36 @@ int mididebug = 0;
#define DPRINTFN(n,x)
#endif
-static struct simplelock hwif_register_lock = SIMPLELOCK_INITIALIZER;
static struct midi_softc *hwif_softc = NULL;
-void midi_in(void *, int);
-void midi_out(void *);
-int midi_poll_out(struct midi_softc *);
-int midi_intr_out(struct midi_softc *);
-int midi_msg_out(struct midi_softc *,
- u_char **, u_char **, u_char **, u_char **);
-int midi_start_output(struct midi_softc *);
-int midi_sleep_timo(int *, const char *, int, struct simplelock *);
-int midi_sleep(int *, const char *, struct simplelock *);
-void midi_wakeup(int *);
-void midi_initbuf(struct midi_buffer *);
-void midi_xmt_asense(void *);
-void midi_rcv_asense(void *);
-void midi_softintr_rd(void *);
-void midi_softintr_wr(void *);
-
-int midiprobe(device_t, cfdata_t, void *);
-void midiattach(device_t, device_t, void *);
-int mididetach(device_t, int);
-int midiactivate(device_t, enum devact);
-
-dev_type_open(midiopen);
-dev_type_close(midiclose);
-dev_type_read(midiread);
-dev_type_write(midiwrite);
-dev_type_ioctl(midiioctl);
-dev_type_poll(midipoll);
-dev_type_kqfilter(midikqfilter);
+static void midi_in(void *, int);
+static void midi_out(void *);
+static int midi_poll_out(struct midi_softc *);
+static int midi_intr_out(struct midi_softc *);
+static int midi_msg_out(struct midi_softc *, u_char **, u_char **,
+ u_char **, u_char **);
+static int midi_start_output(struct midi_softc *);
+static void midi_initbuf(struct midi_buffer *);
+static void midi_xmt_asense(void *);
+static void midi_rcv_asense(void *);
+static void midi_softint(void *);
+
+static int midiprobe(device_t, cfdata_t, void *);
+static void midiattach(device_t, device_t, void *);
+int mididetach(device_t, int);
+static int midiactivate(device_t, enum devact);
+
+static dev_type_open(midiopen);
+static dev_type_close(midiclose);
+static dev_type_read(midiread);
+static dev_type_write(midiwrite);
+static dev_type_ioctl(midiioctl);
+static dev_type_poll(midipoll);
+static dev_type_kqfilter(midikqfilter);
const struct cdevsw midi_cdevsw = {
midiopen, midiclose, midiread, midiwrite, midiioctl,
- nostop, notty, midipoll, nommap, midikqfilter, D_OTHER,
+ nostop, notty, midipoll, nommap, midikqfilter, D_OTHER | D_MPSAFE
};
CFATTACH_DECL_NEW(midi, sizeof(struct midi_softc),
@@ -126,23 +120,31 @@ CFATTACH_DECL_NEW(midi, sizeof(struct midi_softc),
extern struct cfdriver midi_cd;
-int
+static int
midiprobe(device_t parent, cfdata_t match, void *aux)
{
- struct audio_attach_args *sa = aux;
+ struct audio_attach_args *sa;
+
+ sa = aux;
- DPRINTFN(2,("midiprobe: type=%d sa=%p hw=%p\n",
- sa->type, sa, sa->hwif));
- return (sa->type == AUDIODEV_TYPE_MIDI);
+ DPRINTFN(2,("midiprobe: type=%d sa=%p hw=%p\n", sa->type, sa,
+ sa->hwif));
+
+ return sa->type == AUDIODEV_TYPE_MIDI;
}
-void
+static void
midiattach(device_t parent, device_t self, void *aux)
{
- struct midi_softc *sc = device_private(self);
- struct audio_attach_args *sa = aux;
- const struct midi_hw_if *hwp = sa->hwif;
- void *hdlp = sa->hdl;
+ struct midi_softc *sc;
+ struct audio_attach_args *sa;
+ const struct midi_hw_if *hwp;
+ void *hdlp;
+
+ sc = device_private(self);
+ sa = aux;
+ hwp = sa->hwif;
+ hdlp = sa->hdl;
aprint_naive("\n");
@@ -169,14 +171,16 @@ midiattach(device_t parent, device_t self, void *aux)
"couldn't establish power handler\n");
}
-int
+static int
midiactivate(device_t self, enum devact act)
{
struct midi_softc *sc = device_private(self);
switch (act) {
case DVACT_DEACTIVATE:
+ mutex_enter(sc->lock);
sc->dying = 1;
+ mutex_exit(sc->lock);
return 0;
default:
return EOPNOTSUPP;
@@ -193,36 +197,43 @@ mididetach(device_t self, int flags)
pmf_device_deregister(self);
+ mutex_enter(sc->lock);
sc->dying = 1;
-
- wakeup(&sc->wchan);
- wakeup(&sc->rchan);
+ cv_broadcast(&sc->wchan);
+ cv_broadcast(&sc->rchan);
+ mutex_exit(sc->lock);
/* locate the major number */
maj = cdevsw_lookup_major(&midi_cdevsw);
- /* Nuke the vnodes for any open instances (calls close). */
+ /*
+ * Nuke the vnodes for any open instances (calls close).
+ * Will wait until any activity on the device nodes has ceased.
+ *
+ * XXXAD NOT YET.
+ *
+ * XXXAD NEED TO PREVENT NEW REFERENCES THROUGH AUDIO_ENTER().
+ */
mn = device_unit(self);
vdevgone(maj, mn, mn, VCHR);
- if ( !(sc->props & MIDI_PROP_NO_OUTPUT) ) {
+ if (!(sc->props & MIDI_PROP_NO_OUTPUT)) {
evcnt_detach(&sc->xmt.bytesDiscarded);
evcnt_detach(&sc->xmt.incompleteMessages);
}
- if ( sc->props & MIDI_PROP_CAN_INPUT ) {
+ if (sc->props & MIDI_PROP_CAN_INPUT) {
evcnt_detach(&sc->rcv.bytesDiscarded);
evcnt_detach(&sc->rcv.incompleteMessages);
}
- if (sc->sih_rd != NULL) {
- softint_disestablish(sc->sih_rd);
- sc->sih_rd = NULL;
- }
- if (sc->sih_wr != NULL) {
- softint_disestablish(sc->sih_wr);
- sc->sih_wr = NULL;
+ if (sc->sih != NULL) {
+ softint_disestablish(sc->sih);
+ sc->sih = NULL;
}
+ cv_destroy(&sc->wchan);
+ cv_destroy(&sc->rchan);
+
return (0);
}
@@ -230,33 +241,32 @@ void
midi_attach(struct midi_softc *sc, device_t parent)
{
struct midi_info mi;
- int s;
+ kmutex_t *dummy;
+
+ sc->hw_if->get_locks(sc->hw_hdl, &sc->lock, &dummy);
- callout_init(&sc->xmt_asense_co, 0);
- callout_init(&sc->rcv_asense_co, 0);
+ callout_init(&sc->xmt_asense_co, CALLOUT_MPSAFE);
+ callout_init(&sc->rcv_asense_co, CALLOUT_MPSAFE);
callout_setfunc(&sc->xmt_asense_co, midi_xmt_asense, sc);
callout_setfunc(&sc->rcv_asense_co, midi_rcv_asense, sc);
- simple_lock_init(&sc->out_lock);
- simple_lock_init(&sc->in_lock);
+
+ sc->sih = softint_establish(SOFTINT_CLOCK | SOFTINT_MPSAFE,
+ midi_softint, sc);
+
+ cv_init(&sc->rchan, "midird");
+ cv_init(&sc->wchan, "midiwr");
+
sc->dying = 0;
sc->isopen = 0;
-
sc->sc_dev = parent;
- sc->sih_rd = softint_establish(SOFTINT_SERIAL, midi_softintr_rd, sc);
- sc->sih_wr = softint_establish(SOFTINT_SERIAL, midi_softintr_wr, sc);
-
- s = splaudio();
- simple_lock(&hwif_register_lock);
- hwif_softc = sc;
+ mutex_enter(sc->lock);
sc->hw_if->getinfo(sc->hw_hdl, &mi);
- hwif_softc = NULL;
- simple_unlock(&hwif_register_lock);
- splx(s);
-
+ mutex_exit(sc->lock);
+
sc->props = mi.props;
-
- if ( !(sc->props & MIDI_PROP_NO_OUTPUT) ) {
+
+ if (!(sc->props & MIDI_PROP_NO_OUTPUT)) {
evcnt_attach_dynamic(&sc->xmt.bytesDiscarded,
EVCNT_TYPE_MISC, NULL,
device_xname(sc->dev), "xmt bytes discarded");
@@ -264,7 +274,7 @@ midi_attach(struct midi_softc *sc, device_t parent)
EVCNT_TYPE_MISC, NULL,
device_xname(sc->dev), "xmt incomplete msgs");
}
- if ( sc->props & MIDI_PROP_CAN_INPUT ) {
+ if (sc->props & MIDI_PROP_CAN_INPUT) {
evcnt_attach_dynamic(&sc->rcv.bytesDiscarded,
EVCNT_TYPE_MISC, NULL,
device_xname(sc->dev), "rcv bytes discarded");
@@ -276,8 +286,10 @@ midi_attach(struct midi_softc *sc, device_t parent)
aprint_normal(": %s\n", mi.name);
}
-void midi_register_hw_if_ext(struct midi_hw_if_ext *exthw) {
- if ( hwif_softc != NULL ) /* ignore calls resulting from non-init */
+void
+midi_register_hw_if_ext(struct midi_hw_if_ext *exthw)
+{
+ if (hwif_softc != NULL) /* ignore calls resulting from non-init */
hwif_softc->hw_if_ext = exthw; /* uses of getinfo */
}
@@ -285,63 +297,23 @@ int
midi_unit_count(void)
{
int i;
- for ( i = 0; i < midi_cd.cd_ndevs; ++i )
- if ( NULL == device_lookup(&midi_cd, i) )
+ for ( i = 0; i < midi_cd.cd_ndevs; ++i)
+ if (NULL == device_lookup(&midi_cd, i))
break;
return i;
}
-void
+static void
midi_initbuf(struct midi_buffer *mb)
{
mb->idx_producerp = mb->idx_consumerp = mb->idx;
mb->buf_producerp = mb->buf_consumerp = mb->buf;
}
+
#define PACK_MB_IDX(cat,len) (((cat)<<4)|(len))
#define MB_IDX_CAT(idx) ((idx)>>4)
#define MB_IDX_LEN(idx) ((idx)&0xf)
-int
-midi_sleep_timo(int *chan, const char *label, int timo, struct simplelock *lk)
-{
- int st;
-
- if (!label)
- label = "midi";
-
- DPRINTFN(8, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
- *chan = 1;
- st = ltsleep(chan, PWAIT | PCATCH, label, timo, lk);
- *chan = 0;
-#ifdef MIDI_DEBUG
- if (st != 0)
- printf("midi_sleep: %d\n", st);
-#endif
- return st;
-}
-
-int
-midi_sleep(int *chan, const char *label, struct simplelock *lk)
-{
- return midi_sleep_timo(chan, label, 0, lk);
-}
-
-void
-midi_wakeup(int *chan)
-{
- if (*chan) {
- DPRINTFN(8, ("midi_wakeup: %p\n", chan));
- wakeup(chan);
- *chan = 0;
- }
-}
-
-/* in midivar.h:
-#define MIDI_CAT_DATA 0
-#define MIDI_CAT_STATUS1 1
-#define MIDI_CAT_STATUS2 2
-#define MIDI_CAT_COMMON 3
-*/
static char const midi_cats[] = "\0\0\0\0\0\0\0\0\2\2\2\2\1\1\2\3";
#define MIDI_CAT(d) (midi_cats[((d)>>4)&15])
#define FST_RETURN(offp,endp,ret) \
@@ -427,30 +399,29 @@ midi_fst(struct midi_state *s, u_char c, enum fst_form form)
{
int syxpos = 0;
- if ( c >= 0xf8 ) { /* All realtime messages bypass state machine */
- if ( c == 0xf9 || c == 0xfd ) {
+ if (c >= 0xf8) { /* All realtime messages bypass state machine */
+ if (c == 0xf9 || c == 0xfd) {
DPRINTF( ("midi_fst: s=%p c=0x%02x undefined\n",
- s, c));
+ s, c));
s->bytesDiscarded.ev_count++;
return FST_ERR;
}
DPRINTFN(9, ("midi_fst: s=%p System Real-Time data=0x%02x\n",
- s, c));
+ s, c));
s->msg[2] = c;
FST_RETURN(2,3,FST_RT);
}
DPRINTFN(4, ("midi_fst: s=%p data=0x%02x state=%d\n",
- s, c, s->state));
-
- switch ( s->state | MIDI_CAT(c) ) { /* break ==> return FST_MORE */
+ s, c, s->state));
+ switch (s->state | MIDI_CAT(c)) { /* break ==> return FST_MORE */
case MIDI_IN_START | MIDI_CAT_COMMON:
case MIDI_IN_RUN1_1 | MIDI_CAT_COMMON:
case MIDI_IN_RUN2_2 | MIDI_CAT_COMMON:
case MIDI_IN_RXX2_2 | MIDI_CAT_COMMON:
s->msg[0] = c;
- switch ( c ) {
+ switch ( c) {
case 0xf0: s->state = MIDI_IN_SYX1_3; break;
case 0xf1: s->state = MIDI_IN_COM0_1; break;
case 0xf2: s->state = MIDI_IN_COM0_2; break;
@@ -462,7 +433,7 @@ midi_fst(struct midi_state *s, u_char c, enum fst_form form)
break;
case MIDI_IN_RUN1_1 | MIDI_CAT_STATUS1:
- if ( c == s->msg[0] ) {
+ if (c == s->msg[0]) {
s->state = MIDI_IN_RNX0_1;
break;
}
@@ -476,11 +447,11 @@ midi_fst(struct midi_state *s, u_char c, enum fst_form form)
case MIDI_IN_RUN2_2 | MIDI_CAT_STATUS2:
case MIDI_IN_RXX2_2 | MIDI_CAT_STATUS2:
- if ( c == s->msg[0] ) {
+ if (c == s->msg[0]) {
s->state = MIDI_IN_RNX0_2;
break;
}
- if ( (c ^ s->msg[0]) == 0x10 && (c & 0xe0) == 0x80 ) {
+ if ((c ^ s->msg[0]) == 0x10 && (c & 0xe0) == 0x80) {
s->state = MIDI_IN_RXX0_2;
s->msg[0] = c;
break;
@@ -524,7 +495,7 @@ midi_fst(struct midi_state *s, u_char c, enum fst_form form)
break;
case MIDI_IN_RUN1_2 | MIDI_CAT_DATA:
- if ( FST_CANON == form && 0 == c && (s->msg[0]&0xf0) == 0x90 ) {
+ if (FST_CANON == form && 0 == c && (s->msg[0]&0xf0) == 0x90) {
s->state = MIDI_IN_RXX2_2;
s->msg[0] ^= 0x10;
s->msg[2] = 64;
@@ -557,7 +528,7 @@ midi_fst(struct midi_state *s, u_char c, enum fst_form form)
case MIDI_IN_RNX1_2 | MIDI_CAT_DATA:
case MIDI_IN_RNY1_2 | MIDI_CAT_DATA:
- if ( FST_CANON == form && 0 == c && (s->msg[0]&0xf0) == 0x90 ) {
+ if (FST_CANON == form && 0 == c && (s->msg[0]&0xf0) == 0x90) {
s->state = MIDI_IN_RXX2_2;
s->msg[0] ^= 0x10;
s->msg[2] = 64;
@@ -569,9 +540,9 @@ midi_fst(struct midi_state *s, u_char c, enum fst_form form)
case MIDI_IN_RXX1_2 | MIDI_CAT_DATA:
case MIDI_IN_RXY1_2 | MIDI_CAT_DATA:
- if ( ( 0 == c && (s->msg[0]&0xf0) == 0x90)
+ if (( 0 == c && (s->msg[0]&0xf0) == 0x90)
|| (64 == c && (s->msg[0]&0xf0) == 0x80
- && FST_CANON != form) ) {
+ && FST_CANON != form)) {
s->state = MIDI_IN_RXX2_2;
s->msg[0] ^= 0x10;
s->msg[2] = 64 - c;
@@ -610,7 +581,7 @@ midi_fst(struct midi_state *s, u_char c, enum fst_form form)
case MIDI_IN_SYX0_3 | MIDI_CAT_STATUS1:
case MIDI_IN_SYX0_3 | MIDI_CAT_STATUS2:
s->state = MIDI_IN_START;
- if ( c == 0xf7 ) {
+ if (c == 0xf7) {
s->msg[syxpos] = c;
FST_RETURN(0,1+syxpos,FST_SYX);
}
@@ -620,8 +591,8 @@ midi_fst(struct midi_state *s, u_char c, enum fst_form form)
default:
protocol_violation:
DPRINTF(("midi_fst: unexpected %#02x in state %u\n",
- c, s->state));
- switch ( s->state ) {
+ c, s->state));
+ switch ( s->state) {
case MIDI_IN_RUN1_1: /* can only get here by seeing an */
case MIDI_IN_RUN2_2: /* INVALID System Common message */
case MIDI_IN_RXX2_2:
@@ -648,11 +619,10 @@ protocol_violation:
s->bytesDiscarded.ev_count++;
s->incompleteMessages.ev_count++;
break;
-#if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
default:
- printf("midi_fst: mishandled %#02x(%u) in state %u?!\n",
- c, MIDI_CAT(c), s->state);
-#endif
+ DPRINTF(("midi_fst: mishandled %#02x(%u) in state %u?!\n",
+ c, MIDI_CAT(c), s->state));
+ break;
}
s->state = MIDI_IN_START;
return FST_HUH;
@@ -660,62 +630,49 @@ protocol_violation:
return FST_MORE;
}
-void
-midi_softintr_rd(void *cookie)
+static void
+midi_softint(void *cookie)
{
- struct midi_softc *sc = cookie;
- struct proc *p;
-
- if (sc->async != NULL) {
- mutex_enter(proc_lock);
- if ((p = sc->async) != NULL)
- psignal(p, SIGIO);
- mutex_exit(proc_lock);
- }
- midi_wakeup(&sc->rchan);
- selnotify(&sc->rsel, 0, 0); /* filter will spin if locked */
-}
+ struct midi_softc *sc;
+ proc_t *p;
+ pid_t pid;
-void
-midi_softintr_wr(void *cookie)
-{
- struct midi_softc *sc = cookie;
- struct proc *p;
+ sc = cookie;
- if (sc->async != NULL) {
- mutex_enter(proc_lock);
- if ((p = sc->async) != NULL)
- psignal(p, SIGIO);
- mutex_exit(proc_lock);
- }
- midi_wakeup(&sc->wchan);
- selnotify(&sc->wsel, 0, 0); /* filter will spin if locked */
+ mutex_enter(proc_lock);
+ pid = sc->async;
+ if (pid != 0 && (p = proc_find(pid)) != NULL)
+ psignal(p, SIGIO);
+ mutex_exit(proc_lock);
}
-void
+static void
midi_in(void *addr, int data)
{
- struct midi_softc *sc = addr;
- struct midi_buffer *mb = &sc->inbuf;
- int i;
- int count;
+ struct midi_softc *sc;
+ struct midi_buffer *mb;
+ int i, count;
enum fst_ret got;
- int s; /* hw may have various spls so impose our own */
MIDI_BUF_DECLARE(idx);
MIDI_BUF_DECLARE(buf);
+ sc = addr;
+ mb = &sc->inbuf;
+
+ KASSERT(mutex_owned(sc->lock));
+
if (!sc->isopen)
return;
- if (!(sc->flags & FREAD))
+ if ((sc->flags & FREAD) == 0)
return; /* discard data if not reading */
sxp_again:
- do
+ do {
got = midi_fst(&sc->rcv, data, FST_CANON);
- while ( got == FST_HUH );
+ } while (got == FST_HUH);
- switch ( got ) {
+ switch (got) {
case FST_MORE:
case FST_ERR:
return;
@@ -735,11 +692,11 @@ sxp_again:
* a raw reader. (Really should do something intelligent with
* it then, though....)
*/
- if ( got == FST_RT && MIDI_ACK == sc->rcv.pos[0] ) {
- if ( !sc->rcv_expect_asense ) {
+ if (got == FST_RT && MIDI_ACK == sc->rcv.pos[0]) {
+ if (!sc->rcv_expect_asense) {
sc->rcv_expect_asense = 1;
callout_schedule(&sc->rcv_asense_co,
- MIDI_RCV_ASENSE_PERIOD);
+ MIDI_RCV_ASENSE_PERIOD);
}
sc->rcv_quiescent = 0;
sc->rcv_eof = 0;
@@ -757,19 +714,15 @@ sxp_again:
case FST_SYX:
case FST_SXP:
count = sc->rcv.end - sc->rcv.pos;
- MIDI_IN_LOCK(sc,s);
sc->rcv_quiescent = 0;
sc->rcv_eof = 0;
- if ( 0 == count ) {
- MIDI_IN_UNLOCK(sc,s);
+ if (0 == count)
break;
- }
MIDI_BUF_PRODUCER_INIT(mb,idx);
MIDI_BUF_PRODUCER_INIT(mb,buf);
if (count > buf_lim - buf_cur
|| 1 > idx_lim - idx_cur) {
sc->rcv.bytesDiscarded.ev_count += count;
- MIDI_IN_UNLOCK(sc,s);
DPRINTF(("midi_in: buffer full, discard data=0x%02x\n",
sc->rcv.pos[0]));
return;
@@ -782,28 +735,32 @@ sxp_again:
MIDI_BUF_WRAP(idx);
MIDI_BUF_PRODUCER_WBACK(mb,buf);
MIDI_BUF_PRODUCER_WBACK(mb,idx);
- MIDI_IN_UNLOCK(sc,s);
- softint_schedule(sc->sih_rd);
+ cv_broadcast(&sc->rchan);
+ selnotify(&sc->rsel, 0, NOTE_SUBMIT);
+ if (sc->async != 0)
+ softint_schedule(sc->sih);
break;
default: /* don't #ifdef this away, gcc will say FST_HUH not handled */
printf("midi_in: midi_fst returned %d?!\n", got);
}
- if ( FST_SXP == got )
+ if (FST_SXP == got)
goto sxp_again;
}
-void
+static void
midi_out(void *addr)
{
struct midi_softc *sc = addr;
+ KASSERT(mutex_owned(sc->lock));
+
if (!sc->isopen)
return;
DPRINTFN(8, ("midi_out: %p\n", sc));
midi_intr_out(sc);
}
-int
+static int
midiopen(dev_t dev, int flags, int ifmt, struct lwp *l)
{
struct midi_softc *sc;
@@ -813,16 +770,22 @@ midiopen(dev_t dev, int flags, int ifmt, struct lwp *l)
sc = device_lookup_private(&midi_cd, MIDIUNIT(dev));
if (sc == NULL)
return (ENXIO);
- if (sc->dying)
- return (EIO);
-
DPRINTFN(3,("midiopen %p\n", sc));
+ mutex_enter(sc->lock);
+ if (sc->dying) {
+ mutex_exit(sc->lock);
+ return (EIO);
+ }
hw = sc->hw_if;
- if (!hw)
+ if (hw == NULL) {
+ mutex_exit(sc->lock);
return ENXIO;
- if (sc->isopen)
+ }
+ if (sc->isopen) {
+ mutex_exit(sc->lock);
return EBUSY;
+ }
/* put both state machines into known states */
sc->rcv.state = MIDI_IN_START;
@@ -847,14 +810,8 @@ midiopen(dev_t dev, int flags, int ifmt, struct lwp *l)
sc->rcv_expect_asense = 0;
sc->rcv_quiescent = 0;
sc->rcv_eof = 0;
-
- error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
- if (error)
- return error;
sc->isopen++;
sc->flags = flags;
- sc->rchan = 0;
- sc->wchan = 0;
sc->pbus = 0;
sc->async = 0;
@@ -865,222 +822,225 @@ midiopen(dev_t dev, int flags, int ifmt, struct lwp *l)
}
#endif
+ error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
+ if (error) {
+ mutex_exit(sc->lock);
+ return error;
+ }
+
+ mutex_exit(sc->lock);
return 0;
}
-int
-midiclose(dev_t dev, int flags, int ifmt,
- struct lwp *l)
+static int
+midiclose(dev_t dev, int flags, int ifmt, struct lwp *l)
{
- struct midi_softc *sc =
- device_lookup_private(&midi_cd, MIDIUNIT(dev));
- const struct midi_hw_if *hw = sc->hw_if;
- int s, error;
+ struct midi_softc *sc;
+ const struct midi_hw_if *hw;
+
+ sc = device_lookup_private(&midi_cd, MIDIUNIT(dev));
+ hw = sc->hw_if;
DPRINTFN(3,("midiclose %p\n", sc));
+ mutex_enter(sc->lock);
/* midi_start_output(sc); anything buffered => pbus already set! */
- error = 0;
- MIDI_OUT_LOCK(sc,s);
while (sc->pbus) {
DPRINTFN(8,("midiclose sleep ...\n"));
- error =
- midi_sleep_timo(&sc->wchan, "mid_dr", 30*hz, &sc->out_lock);
+ cv_wait(&sc->wchan, sc->lock);
}
sc->isopen = 0;
- MIDI_OUT_UNLOCK(sc,s);
- callout_stop(&sc->xmt_asense_co); /* xxx fix this - sleep? */
- callout_stop(&sc->rcv_asense_co);
+ callout_halt(&sc->xmt_asense_co, sc->lock);
+ callout_halt(&sc->rcv_asense_co, sc->lock);
hw->close(sc->hw_hdl);
-#if NSEQUENCER > 0
sc->seqopen = 0;
sc->seq_md = 0;
-#endif
+ mutex_exit(sc->lock);
+
return 0;
}
-int
+static int
midiread(dev_t dev, struct uio *uio, int ioflag)
{
- struct midi_softc *sc =
- device_lookup_private(&midi_cd, MIDIUNIT(dev));
- struct midi_buffer *mb = &sc->inbuf;
- int error;
- int s;
+ struct midi_softc *sc;
+ struct midi_buffer *mb;
+ int appetite, error, first;
MIDI_BUF_DECLARE(idx);
MIDI_BUF_DECLARE(buf);
- int appetite;
- int first = 1;
+
+ sc = device_lookup_private(&midi_cd, MIDIUNIT(dev));
+ mb = &sc->inbuf;
+ first = 1;
DPRINTFN(6,("midiread: %p, count=%lu\n", sc,
- (unsigned long)uio->uio_resid));
+ (unsigned long)uio->uio_resid));
- if (sc->dying)
+ mutex_enter(sc->lock);
+ if (sc->dying) {
+ mutex_exit(sc->lock);
return EIO;
- if ( !(sc->props & MIDI_PROP_CAN_INPUT) )
- return ENXIO;
-
- MIDI_IN_LOCK(sc,s);
+ }
+ if ((sc->props & MIDI_PROP_CAN_INPUT) == 0) {
+ mutex_exit(sc->lock);
+ return ENXIO;
+ }
MIDI_BUF_CONSUMER_INIT(mb,idx);
MIDI_BUF_CONSUMER_INIT(mb,buf);
- MIDI_IN_UNLOCK(sc,s);
-
error = 0;
- for ( ;; ) {
+ for (;;) {
/*
* If the used portion of idx wraps around the end, just take
* the first part on this iteration, and we'll get the rest on
* the next.
*/
- if ( idx_lim > idx_end )
+ if (idx_lim > idx_end)
idx_lim = idx_end;
/*
* Count bytes through the last complete message that will
* fit in the requested read.
*/
for (appetite = uio->uio_resid; idx_cur < idx_lim; ++idx_cur) {
- if ( appetite < MB_IDX_LEN(*idx_cur) )
+ if (appetite < MB_IDX_LEN(*idx_cur))
break;
appetite -= MB_IDX_LEN(*idx_cur);
}
appetite = uio->uio_resid - appetite;
+
/*
* Only if the read is too small to hold even the first
* complete message will we return a partial one (updating idx
* to reflect the remaining length of the message).
*/
- if ( appetite == 0 && idx_cur < idx_lim ) {
- if ( !first )
- goto unlocked_exit; /* idx_cur not advanced */
+ if (appetite == 0 && idx_cur < idx_lim) {
+ if (!first)
+ break;
appetite = uio->uio_resid;
*idx_cur = PACK_MB_IDX(MB_IDX_CAT(*idx_cur),
- MB_IDX_LEN(*idx_cur) - appetite);
+ MB_IDX_LEN(*idx_cur) - appetite);
}
KASSERT(buf_cur + appetite <= buf_lim);
/* move the bytes */
- if ( appetite > 0 ) {
+ if (appetite > 0) {
first = 0; /* we know we won't return empty-handed */
/* do two uiomoves if data wrap around end of buf */
- if ( buf_cur + appetite > buf_end ) {
+ if (buf_cur + appetite > buf_end) {
DPRINTFN(8,
("midiread: uiomove cc=%td (prewrap)\n",
buf_end - buf_cur));
- error = uiomove(buf_cur, buf_end-buf_cur, uio);
- if ( error )
- goto unlocked_exit;
+ mutex_exit(sc->lock);
+ error = uiomove(buf_cur, buf_end - buf_cur, uio);
+ mutex_enter(sc->lock);
+ if (error)
+ break;
appetite -= buf_end - buf_cur;
buf_cur = mb->buf;
}
DPRINTFN(8, ("midiread: uiomove cc=%d\n", appetite));
+ mutex_exit(sc->lock);
error = uiomove(buf_cur, appetite, uio);
- if ( error )
- goto unlocked_exit;
+ mutex_enter(sc->lock);
+ if (error)
+ break;
buf_cur += appetite;
}
MIDI_BUF_WRAP(idx);
MIDI_BUF_WRAP(buf);
-
- MIDI_IN_LOCK(sc,s);
MIDI_BUF_CONSUMER_WBACK(mb,idx);
MIDI_BUF_CONSUMER_WBACK(mb,buf);
- if ( 0 == uio->uio_resid ) /* if read satisfied, we're done */
+ if (0 == uio->uio_resid) /* if read satisfied, we're done */
break;
MIDI_BUF_CONSUMER_REFRESH(mb,idx);
- if ( idx_cur == idx_lim ) { /* need to wait for data? */
- if ( !first || sc->rcv_eof ) /* never block reader if */
+ if (idx_cur == idx_lim) { /* need to wait for data? */
+ if (!first || sc->rcv_eof) /* never block reader if */
break; /* any data already in hand */
if (ioflag & IO_NDELAY) {
error = EWOULDBLOCK;
break;
}
- error = midi_sleep(&sc->rchan, "mid rd", &sc->in_lock);
- if ( error )
+ error = cv_wait_sig(&sc->rchan, sc->lock);
+ if (error)
break;
MIDI_BUF_CONSUMER_REFRESH(mb,idx); /* what'd we get? */
}
MIDI_BUF_CONSUMER_REFRESH(mb,buf);
- MIDI_IN_UNLOCK(sc,s);
- if ( sc->dying )
- return EIO;
+ if (sc->dying) {
+ error = EIO;
+ break;
+ }
}
- MIDI_IN_UNLOCK(sc,s);
+ mutex_exit(sc->lock);
-unlocked_exit:
return error;
}
-void
+static void
midi_rcv_asense(void *arg)
{
- struct midi_softc *sc = arg;
- int s;
-
- if ( sc->dying || !sc->isopen )
- return;
+ struct midi_softc *sc;
+
+ sc = arg;
- if ( sc->rcv_quiescent ) {
- MIDI_IN_LOCK(sc,s);
+ mutex_enter(sc->lock);
+ if (sc->dying || !sc->isopen) {
+ mutex_exit(sc->lock);
+ return;
+ }
+ if (sc->rcv_quiescent) {
sc->rcv_eof = 1;
sc->rcv_quiescent = 0;
sc->rcv_expect_asense = 0;
- MIDI_IN_UNLOCK(sc,s);
- softint_schedule(sc->sih_rd);
+ cv_broadcast(&sc->rchan);
+ selnotify(&sc->rsel, 0, NOTE_SUBMIT);
+ if (sc->async)
+ softint_schedule(sc->sih);
+ mutex_exit(sc->lock);
return;
- }
-
+ }
sc->rcv_quiescent = 1;
callout_schedule(&sc->rcv_asense_co, MIDI_RCV_ASENSE_PERIOD);
+ mutex_exit(sc->lock);
}
-void
+static void
midi_xmt_asense(void *arg)
{
- struct midi_softc *sc = arg;
- int s;
- int error;
- int armed;
-
- if ( sc->dying || !sc->isopen )
- return;
+ struct midi_softc *sc;
+ int error, armed;
- MIDI_OUT_LOCK(sc,s);
- if ( sc->pbus || sc->dying || !sc->isopen ) {
- MIDI_OUT_UNLOCK(sc,s);
+ sc = arg;
+
+ mutex_enter(sc->lock);
+ if (sc->pbus || sc->dying || !sc->isopen) {
+ mutex_exit(sc->lock);
return;
}
sc->pbus = 1;
- DPRINTFN(8,("midi_xmt_asense: %p\n", sc));
-
- if ( sc->props & MIDI_PROP_OUT_INTR ) {
+ if (sc->props & MIDI_PROP_OUT_INTR) {
error = sc->hw_if->output(sc->hw_hdl, MIDI_ACK);
armed = (error == 0);
- } else { /* polled output, do with interrupts unmasked */
- MIDI_OUT_UNLOCK(sc,s);
- /* running from softclock, so top half won't sneak in here */
+ } else {
error = sc->hw_if->output(sc->hw_hdl, MIDI_ACK);
- MIDI_OUT_LOCK(sc,s);
armed = 0;
}
-
- if ( !armed ) {
+ if (!armed) {
sc->pbus = 0;
callout_schedule(&sc->xmt_asense_co, MIDI_XMT_ASENSE_PERIOD);
}
-
- MIDI_OUT_UNLOCK(sc,s);
+ mutex_exit(sc->lock);
}
/*
* The way this function was hacked up to plug into poll_out and intr_out
* after they were written won't win it any beauty contests, but it'll work
- * (code in haste, refactor at leisure). This may be called with the lock
- * (by intr_out) or without the lock (by poll_out) so it only does what could
- * be safe either way.
+ * (code in haste, refactor at leisure).
*/
-int midi_msg_out(struct midi_softc *sc,
- u_char **idx, u_char **idxl, u_char **buf, u_char **bufl) {
+static int
+midi_msg_out(struct midi_softc *sc, u_char **idx, u_char **idxl, u_char **buf,
+ u_char **bufl)
+{
MIDI_BUF_DECLARE(idx);
MIDI_BUF_DECLARE(buf);
MIDI_BUF_EXTENT_INIT(&sc->outbuf,idx);
@@ -1090,7 +1050,9 @@ int midi_msg_out(struct midi_softc *sc,
u_char contig[3];
u_char *cp;
u_char *ep;
-
+
+ KASSERT(mutex_owned(sc->lock));
+
idx_cur = *idx;
idx_lim = *idxl;
buf_cur = *buf;
@@ -1098,32 +1060,29 @@ int midi_msg_out(struct midi_softc *sc,
length = MB_IDX_LEN(*idx_cur);
- for ( cp = contig, ep = cp + length; cp < ep; ) {
+ for ( cp = contig, ep = cp + length; cp < ep;) {
*cp++ = *buf_cur++;
MIDI_BUF_WRAP(buf);
}
cp = contig;
- switch ( MB_IDX_CAT(*idx_cur) ) {
+ switch ( MB_IDX_CAT(*idx_cur)) {
case FST_CHV: /* chnmsg to be compressed (for device that wants it) */
++ cp;
-- length;
/* FALLTHROUGH */
case FST_CHN:
error = sc->hw_if_ext->channel(sc->hw_hdl,
- MIDI_GET_STATUS(contig[0]),
- MIDI_GET_CHAN(contig[0]),
- cp, length);
+ MIDI_GET_STATUS(contig[0]), MIDI_GET_CHAN(contig[0]),
+ cp, length);
break;
case FST_COM:
error = sc->hw_if_ext->common(sc->hw_hdl,
- MIDI_GET_STATUS(contig[0]),
- cp, length);
+ MIDI_GET_STATUS(contig[0]), cp, length);
break;
case FST_SYX:
case FST_SXP:
- error = sc->hw_if_ext->sysex(sc->hw_hdl,
- cp, length);
+ error = sc->hw_if_ext->sysex(sc->hw_hdl, cp, length);
break;
case FST_RT:
error = sc->hw_if->output(sc->hw_hdl, *cp);
@@ -1132,7 +1091,7 @@ int midi_msg_out(struct midi_softc *sc,
error = EIO;
}
- if ( !error ) {
+ if (!error) {
++ idx_cur;
MIDI_BUF_WRAP(idx);
*idx = idx_cur;
@@ -1172,74 +1131,69 @@ int midi_msg_out(struct midi_softc *sc,
* may really have tx interrupt capability and want only implementation; that
* ought to happen.
*/
-int
+static int
midi_poll_out(struct midi_softc *sc)
{
struct midi_buffer *mb = &sc->outbuf;
int error;
int msglen;
- int s;
MIDI_BUF_DECLARE(idx);
MIDI_BUF_DECLARE(buf);
- error = 0;
+ KASSERT(mutex_owned(sc->lock));
- MIDI_OUT_LOCK(sc,s);
+ error = 0;
MIDI_BUF_CONSUMER_INIT(mb,idx);
MIDI_BUF_CONSUMER_INIT(mb,buf);
- MIDI_OUT_UNLOCK(sc,s);
- for ( ;; ) {
- while ( idx_cur != idx_lim ) {
- if ( sc->hw_if_ext ) {
+ for (;;) {
+ while (idx_cur != idx_lim) {
+ if (sc->hw_if_ext) {
error = midi_msg_out(sc, &idx_cur, &idx_lim,
- &buf_cur, &buf_lim);
- if ( error )
- goto ioerror;
+ &buf_cur, &buf_lim);
+ if (error != 0) {
+ break;
+ }
continue;
}
/* or, lacking hw_if_ext ... */
msglen = MB_IDX_LEN(*idx_cur);
DPRINTFN(7,("midi_poll_out: %p <- %#02x\n",
- sc->hw_hdl, *buf_cur));
+ sc->hw_hdl, *buf_cur));
error = sc->hw_if->output(sc->hw_hdl, *buf_cur);
- if ( error )
- goto ioerror;
- ++ buf_cur;
+ if (error) {
+ break;
+ }
+ buf_cur++;
MIDI_BUF_WRAP(buf);
- -- msglen;
- if ( msglen )
+ msglen--;
+ if (msglen) {
*idx_cur = PACK_MB_IDX(MB_IDX_CAT(*idx_cur),
- msglen);
- else {
- ++ idx_cur;
+ msglen);
+ } else {
+ idx_cur++;
MIDI_BUF_WRAP(idx);
}
}
+ if (error != 0) {
+ break;
+ }
KASSERT(buf_cur == buf_lim);
- MIDI_OUT_LOCK(sc,s);
MIDI_BUF_CONSUMER_WBACK(mb,idx);
MIDI_BUF_CONSUMER_WBACK(mb,buf);
MIDI_BUF_CONSUMER_REFRESH(mb,idx); /* any more to transmit? */
MIDI_BUF_CONSUMER_REFRESH(mb,buf);
- if ( idx_lim == idx_cur )
- break; /* still holding lock */
- MIDI_OUT_UNLOCK(sc,s);
+ if (idx_lim == idx_cur)
+ break;
}
- goto disarm; /* lock held */
-ioerror:
-#if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
- aprint_error_dev(sc->dev, "midi_poll_output error %d\n", error);
-#endif
- MIDI_OUT_LOCK(sc,s);
- MIDI_BUF_CONSUMER_WBACK(mb,idx);
- MIDI_BUF_CONSUMER_WBACK(mb,buf);
-
-disarm:
+ if (error != 0) {
+ DPRINTF(("midi_poll_output error %d\n", error));
+ MIDI_BUF_CONSUMER_WBACK(mb,idx);
+ MIDI_BUF_CONSUMER_WBACK(mb,buf);
+ }
sc->pbus = 0;
callout_schedule(&sc->xmt_asense_co, MIDI_XMT_ASENSE_PERIOD);
- MIDI_OUT_UNLOCK(sc,s);
return error;
}
@@ -1251,74 +1205,76 @@ disarm:
* interrupt will be forthcoming, and if it returns EINPROGRESS it wants
* another byte right away.
*/
-int
+static int
midi_intr_out(struct midi_softc *sc)
{
- struct midi_buffer *mb = &sc->outbuf;
- int error;
- int msglen;
- int s;
+ struct midi_buffer *mb;
+ int error, msglen;
MIDI_BUF_DECLARE(idx);
MIDI_BUF_DECLARE(buf);
int armed = 0;
+ KASSERT(mutex_owned(sc->lock));
+
error = 0;
+ mb = &sc->outbuf;
- MIDI_OUT_LOCK(sc,s);
MIDI_BUF_CONSUMER_INIT(mb,idx);
MIDI_BUF_CONSUMER_INIT(mb,buf);
- while ( idx_cur != idx_lim ) {
- if ( sc->hw_if_ext ) {
+ while (idx_cur != idx_lim) {
+ if (sc->hw_if_ext) {
error = midi_msg_out(sc, &idx_cur, &idx_lim,
- &buf_cur, &buf_lim);
- if ( !error ) /* no EINPROGRESS from extended hw_if */
+ &buf_cur, &buf_lim);
+ if (!error ) /* no EINPROGRESS from extended hw_if */
armed = 1;
break;
}
/* or, lacking hw_if_ext ... */
msglen = MB_IDX_LEN(*idx_cur);
error = sc->hw_if->output(sc->hw_hdl, *buf_cur);
- if ( error && error != EINPROGRESS )
+ if (error && error != EINPROGRESS)
break;
++ buf_cur;
MIDI_BUF_WRAP(buf);
-- msglen;
- if ( msglen )
+ if (msglen)
*idx_cur = PACK_MB_IDX(MB_IDX_CAT(*idx_cur),msglen);
else {
++ idx_cur;
MIDI_BUF_WRAP(idx);
}
- if ( !error ) {
+ if (!error) {
armed = 1;
break;
}
}
MIDI_BUF_CONSUMER_WBACK(mb,idx);
MIDI_BUF_CONSUMER_WBACK(mb,buf);
- if ( !armed ) {
+ if (!armed) {
sc->pbus = 0;
callout_schedule(&sc->xmt_asense_co, MIDI_XMT_ASENSE_PERIOD);
}
- MIDI_OUT_UNLOCK(sc,s);
- softint_schedule(sc->sih_wr);
-
-#if defined(AUDIO_DEBUG) || defined(DIAGNOSTIC)
- if ( error )
- aprint_error_dev(sc->dev, "midi_intr_output error %d\n",
- error);
-#endif
+ cv_broadcast(&sc->wchan);
+ selnotify(&sc->wsel, 0, NOTE_SUBMIT);
+ if (sc->async) {
+ softint_schedule(sc->sih);
+ }
+ if (error) {
+ DPRINTF(("midi_intr_output error %d\n", error));
+ }
return error;
}
-int
+static int
midi_start_output(struct midi_softc *sc)
{
+
+ KASSERT(mutex_owned(sc->lock));
+
if (sc->dying)
return EIO;
-
- if ( sc->props & MIDI_PROP_OUT_INTR )
+ if (sc->props & MIDI_PROP_OUT_INTR)
return midi_intr_out(sc);
return midi_poll_out(sc);
}
@@ -1326,15 +1282,18 @@ midi_start_output(struct midi_softc *sc)
static int
real_writebytes(struct midi_softc *sc, u_char *ibuf, int cc)
{
- u_char *iend = ibuf + cc;
- struct midi_buffer *mb = &sc->outbuf;
- int arming = 0;
- int count;
- int s;
- int got;
+ u_char *iend;
+ struct midi_buffer *mb;
+ int arming, count, got;
enum fst_form form;
MIDI_BUF_DECLARE(idx);
MIDI_BUF_DECLARE(buf);
+
+ KASSERT(mutex_owned(sc->lock));
+
+ iend = ibuf + cc;
+ mb = &sc->outbuf;
+ arming = 0;
/*
* If the hardware uses the extended hw_if, pass it canonicalized
@@ -1343,25 +1302,23 @@ real_writebytes(struct midi_softc *sc, u_char *ibuf, int cc)
* if it does not, send it compressed messages (using COMPR form as
* there is no need to preserve the status for the bottom half).
*/
- if ( NULL == sc->hw_if_ext )
+ if (NULL == sc->hw_if_ext)
form = FST_COMPR;
- else if ( sc->hw_if_ext->compress )
+ else if (sc->hw_if_ext->compress)
form = FST_VCOMP;
else
form = FST_CANON;
- MIDI_OUT_LOCK(sc,s);
MIDI_BUF_PRODUCER_INIT(mb,idx);
MIDI_BUF_PRODUCER_INIT(mb,buf);
- MIDI_OUT_UNLOCK(sc,s);
if (sc->dying)
return EIO;
- while ( ibuf < iend ) {
+ while (ibuf < iend) {
got = midi_fst(&sc->xmt, *ibuf, form);
++ ibuf;
- switch ( got ) {
+ switch ( got) {
case FST_MORE:
continue;
case FST_ERR:
@@ -1380,7 +1337,7 @@ real_writebytes(struct midi_softc *sc, u_char *ibuf, int cc)
#endif
}
count = sc->xmt.end - sc->xmt.pos;
- if ( 0 == count ) /* can happen with stray 0xf7; see midi_fst */
+ if (0 == count ) /* can happen with stray 0xf7; see midi_fst */
continue;
/*
* return EWOULDBLOCK if the data passed will not fit in
@@ -1388,25 +1345,22 @@ real_writebytes(struct midi_softc *sc, u_char *ibuf, int cc)
* If got==FST_SXP we lose the new status byte, but we're losing
* anyway, so c'est la vie.
*/
- if ( idx_cur == idx_lim || count > buf_lim - buf_cur ) {
- MIDI_OUT_LOCK(sc,s);
+ if (idx_cur == idx_lim || count > buf_lim - buf_cur) {
MIDI_BUF_PRODUCER_REFRESH(mb,idx); /* get the most */
MIDI_BUF_PRODUCER_REFRESH(mb,buf); /* current facts */
- MIDI_OUT_UNLOCK(sc,s);
- if ( idx_cur == idx_lim || count > buf_lim - buf_cur )
+ if (idx_cur == idx_lim || count > buf_lim - buf_cur)
return EWOULDBLOCK; /* caller's problem */
}
*idx_cur++ = PACK_MB_IDX(got,count);
MIDI_BUF_WRAP(idx);
- while ( count ) {
+ while (count) {
*buf_cur++ = *(sc->xmt.pos)++;
MIDI_BUF_WRAP(buf);
-- count;
}
- if ( FST_SXP == got )
+ if (FST_SXP == got)
-- ibuf; /* again with same status byte */
}
- MIDI_OUT_LOCK(sc,s);
MIDI_BUF_PRODUCER_WBACK(mb,buf);
MIDI_BUF_PRODUCER_WBACK(mb,idx);
/*
@@ -1417,24 +1371,21 @@ real_writebytes(struct midi_softc *sc, u_char *ibuf, int cc)
* the critical section (pbus==1 will stop anyone else doing the same).
*/
MIDI_BUF_CONSUMER_INIT(mb,idx); /* check what consumer's got to read */
- if ( !sc->pbus && idx_cur < idx_lim ) {
+ if (!sc->pbus && idx_cur < idx_lim) {
sc->pbus = 1;
callout_stop(&sc->xmt_asense_co);
arming = 1;
}
- MIDI_OUT_UNLOCK(sc,s);
return arming ? midi_start_output(sc) : 0;
}
-int
+static int
midiwrite(dev_t dev, struct uio *uio, int ioflag)
{
- struct midi_softc *sc =
- device_lookup_private(&midi_cd, MIDIUNIT(dev));
- struct midi_buffer *mb = &sc->outbuf;
+ struct midi_softc *sc;
+ struct midi_buffer *mb;
int error;
u_char inp[256];
- int s;
MIDI_BUF_DECLARE(idx);
MIDI_BUF_DECLARE(buf);
size_t idxspace;
@@ -1442,53 +1393,58 @@ midiwrite(dev_t dev, struct uio *uio, int ioflag)
size_t xfrcount;
int pollout = 0;
- DPRINTFN(6, ("midiwrite: %p, unit=%d, count=%lu\n", sc, (int)minor(dev),
- (unsigned long)uio->uio_resid));
+ sc = device_lookup_private(&midi_cd, MIDIUNIT(dev));
- if (sc->dying)
- return EIO;
+ DPRINTFN(6,("midiwrite: %p, unit=%d, count=%lu\n", sc, (int)minor(dev),
+ (unsigned long)uio->uio_resid));
+ mutex_enter(sc->lock);
+ if (sc->dying) {
+ mutex_exit(sc->lock);
+ return EIO;
+ }
+ mb = &sc->outbuf;
error = 0;
while (uio->uio_resid > 0 && !error) {
-
/*
* block if necessary for the minimum buffer space to guarantee
* we can write something.
*/
- MIDI_OUT_LOCK(sc,s);
MIDI_BUF_PRODUCER_INIT(mb,idx); /* init can't go above loop; */
MIDI_BUF_PRODUCER_INIT(mb,buf); /* real_writebytes moves cur */
- for ( ;; ) {
+ for (;;) {
idxspace = MIDI_BUF_PRODUCER_REFRESH(mb,idx) - idx_cur;
bufspace = MIDI_BUF_PRODUCER_REFRESH(mb,buf) - buf_cur;
- if ( idxspace >= 1 && bufspace >= 3 && !pollout )
+ if (idxspace >= 1 && bufspace >= 3 && !pollout)
break;
DPRINTFN(8,("midi_write: sleep idx=%zd buf=%zd\n",
idxspace, bufspace));
if (ioflag & IO_NDELAY) {
- error = EWOULDBLOCK;
/*
* If some amount has already been transferred,
* the common syscall code will automagically
* convert this to success with a short count.
*/
- goto locked_exit;
+ mutex_exit(sc->lock);
+ return EWOULDBLOCK;
}
- if ( pollout ) {
- preempt(); /* see midi_poll_output */
+ if (pollout) {
+ mutex_exit(sc->lock);
+ yield(); /* see midi_poll_output */
+ mutex_enter(sc->lock);
pollout = 0;
} else
- error = midi_sleep(&sc->wchan, "mid wr",
- &sc->out_lock);
- if (error)
+ error = cv_wait_sig(&sc->wchan, sc->lock);
+ if (error) {
/*
* Similarly, the common code will handle
* EINTR and ERESTART properly here, changing to
* a short count if something transferred.
*/
- goto locked_exit;
+ mutex_exit(sc->lock);
+ return error;
+ }
}
- MIDI_OUT_UNLOCK(sc,s);
/*
* The number of bytes we can safely extract from the uio
@@ -1501,14 +1457,16 @@ midiwrite(dev_t dev, struct uio *uio, int ioflag)
* the transfer to the min of idxspace and (bufspace-1)>>1.
*/
xfrcount = (bufspace - 1) >> 1;
- if ( xfrcount > idxspace )
+ if (xfrcount > idxspace)
xfrcount = idxspace;
- if ( xfrcount > sizeof inp )
+ if (xfrcount > sizeof inp)
xfrcount = sizeof inp;
- if ( xfrcount > uio->uio_resid )
+ if (xfrcount > uio->uio_resid)
xfrcount = uio->uio_resid;
+ mutex_exit(sc->lock);
error = uiomove(inp, xfrcount, uio);
+ mutex_enter(sc->lock);
#ifdef MIDI_DEBUG
if (error)
printf("midi_write:(1) uiomove failed %d; "
@@ -1525,22 +1483,19 @@ midiwrite(dev_t dev, struct uio *uio, int ioflag)
*/
error = real_writebytes(sc, inp, xfrcount);
KASSERT(error != EWOULDBLOCK);
-
- if ( error )
+ if (error)
break;
+
/*
* If this is a polling device and we just sent a buffer, let's
* not send another without giving some other process a chance.
*/
- if ( ! (sc->props & MIDI_PROP_OUT_INTR) )
+ if ((sc->props & MIDI_PROP_OUT_INTR) == 0)
pollout = 1;
DPRINTFN(8,("midiwrite: uio_resid now %zu, props=%d\n",
- uio->uio_resid, sc->props));
+ uio->uio_resid, sc->props));
}
- return error;
-
-locked_exit:
- MIDI_OUT_UNLOCK(sc,s);
+ mutex_exit(sc->lock);
return error;
}
@@ -1553,31 +1508,37 @@ midi_writebytes(int unit, u_char *bf, int cc)
{
struct midi_softc *sc =
device_lookup_private(&midi_cd, unit);
+ int error;
DPRINTFN(7, ("midi_writebytes: %p, unit=%d, cc=%d %#02x %#02x %#02x\n",
sc, unit, cc, bf[0], bf[1], bf[2]));
- return real_writebytes(sc, bf, cc);
+
+ mutex_enter(sc->lock);
+ error = real_writebytes(sc, bf, cc);
+ mutex_exit(sc->lock);
+
+ return error;
}
-int
+static int
midiioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
{
- struct midi_softc *sc =
- device_lookup_private(&midi_cd, MIDIUNIT(dev));
- const struct midi_hw_if *hw = sc->hw_if;
+ struct midi_softc *sc;
+ const struct midi_hw_if *hw;
int error;
- int s;
MIDI_BUF_DECLARE(buf);
- DPRINTFN(5,("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
-
+ sc = device_lookup_private(&midi_cd, MIDIUNIT(dev));;
if (sc->dying)
return EIO;
-
+ hw = sc->hw_if;
error = 0;
+
+ DPRINTFN(5,("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
+
switch (cmd) {
case FIONBIO:
- /* All handled in the upper FS layer. */
+ /* All handled in the upper layer. */
break;
case FIONREAD:
@@ -1593,20 +1554,26 @@ midiioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
* read of m < n, fewer than m bytes may be read to ensure the
* read ends at a message boundary.
*/
- MIDI_IN_LOCK(sc,s);
+ mutex_enter(sc->lock);
MIDI_BUF_CONSUMER_INIT(&sc->inbuf,buf);
- MIDI_IN_UNLOCK(sc,s);
*(int *)addr = buf_lim - buf_cur;
+ mutex_exit(sc->lock);
break;
case FIOASYNC:
+ mutex_enter(proc_lock);
if (*(int *)addr) {
- if (sc->async)
- return EBUSY;
- sc->async = l->l_proc;
- DPRINTFN(5,("midi_ioctl: FIOASYNC %p\n", l->l_proc));
- } else
+ if (sc->async) {
+ error = EBUSY;
+ } else {
+ sc->async = curproc->p_pid;
+ }
+ DPRINTFN(5,("midi_ioctl: FIOASYNC %d\n",
+ curproc->p_pid));
+ } else {
sc->async = 0;
+ }
+ mutex_exit(proc_lock);
break;
#if 0
@@ -1625,54 +1592,53 @@ midiioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
#endif
default:
- if (hw->ioctl)
+ if (hw->ioctl != NULL) {
+ mutex_enter(sc->lock);
error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, l);
- else
+ mutex_exit(sc->lock);
+ } else {
error = EINVAL;
+ }
break;
}
return error;
}
-int
+static int
midipoll(dev_t dev, int events, struct lwp *l)
{
- struct midi_softc *sc =
- device_lookup_private(&midi_cd, MIDIUNIT(dev));
- int revents = 0;
- int s;
+ struct midi_softc *sc;
+ int revents;
MIDI_BUF_DECLARE(idx);
MIDI_BUF_DECLARE(buf);
+ sc = device_lookup_private(&midi_cd, MIDIUNIT(dev));
+ revents = 0;
+
DPRINTFN(6,("midipoll: %p events=0x%x\n", sc, events));
- if (sc->dying)
+ mutex_enter(sc->lock);
+ if (sc->dying) {
+ mutex_exit(sc->lock);
return POLLHUP;
-
- s = splaudio();
-
- if ((sc->flags&FREAD) && (events & (POLLIN | POLLRDNORM))) {
- simple_lock(&sc->in_lock);
- MIDI_BUF_CONSUMER_INIT(&sc->inbuf,idx);
+ }
+ if ((events & (POLLIN | POLLRDNORM)) != 0) {
+ MIDI_BUF_CONSUMER_INIT(&sc->inbuf, idx);
if (idx_cur < idx_lim)
revents |= events & (POLLIN | POLLRDNORM);
else
selrecord(l, &sc->rsel);
- simple_unlock(&sc->in_lock);
}
-
- if ((sc->flags&FWRITE) && (events & (POLLOUT | POLLWRNORM))) {
- simple_lock(&sc->out_lock);
- MIDI_BUF_PRODUCER_INIT(&sc->outbuf,idx);
- MIDI_BUF_PRODUCER_INIT(&sc->outbuf,buf);
- if ( idx_lim - idx_cur >= 1 && buf_lim - buf_cur >= 3 )
+ if ((events & (POLLOUT | POLLWRNORM)) != 0) {
+ MIDI_BUF_PRODUCER_INIT(&sc->outbuf, idx);
+ MIDI_BUF_PRODUCER_INIT(&sc->outbuf, buf);
+ if (idx_lim - idx_cur >= 1 && buf_lim - buf_cur >= 3)
revents |= events & (POLLOUT | POLLWRNORM);
else
selrecord(l, &sc->wsel);
- simple_unlock(&sc->out_lock);
}
+ mutex_exit(sc->lock);
- splx(s);
return revents;
}
@@ -1680,26 +1646,24 @@ static void
filt_midirdetach(struct knote *kn)
{
struct midi_softc *sc = kn->kn_hook;
- int s;
- s = splaudio();
+ mutex_enter(sc->lock);
SLIST_REMOVE(&sc->rsel.sel_klist, kn, knote, kn_selnext);
- splx(s);
+ mutex_exit(sc->lock);
}
static int
filt_midiread(struct knote *kn, long hint)
{
struct midi_softc *sc = kn->kn_hook;
- int s;
MIDI_BUF_DECLARE(buf);
- /* XXXLUKEM (thorpej): please make sure this is correct. */
-
- MIDI_IN_LOCK(sc,s);
+ if (hint != NOTE_SUBMIT)
+ mutex_enter(sc->lock);
MIDI_BUF_CONSUMER_INIT(&sc->inbuf,buf);
kn->kn_data = buf_lim - buf_cur;
- MIDI_IN_UNLOCK(sc,s);
+ if (hint != NOTE_SUBMIT)
+ mutex_exit(sc->lock);
return (kn->kn_data > 0);
}
@@ -1710,30 +1674,28 @@ static void
filt_midiwdetach(struct knote *kn)
{
struct midi_softc *sc = kn->kn_hook;
- int s;
- s = splaudio();
+ mutex_enter(sc->lock);
SLIST_REMOVE(&sc->wsel.sel_klist, kn, knote, kn_selnext);
- splx(s);
+ mutex_exit(sc->lock);
}
static int
filt_midiwrite(struct knote *kn, long hint)
{
struct midi_softc *sc = kn->kn_hook;
- int s;
MIDI_BUF_DECLARE(idx);
MIDI_BUF_DECLARE(buf);
- /* XXXLUKEM (thorpej): please make sure this is correct. */
-
- MIDI_OUT_LOCK(sc,s);
+ if (hint != NOTE_SUBMIT)
+ mutex_enter(sc->lock);
MIDI_BUF_PRODUCER_INIT(&sc->outbuf,idx);
MIDI_BUF_PRODUCER_INIT(&sc->outbuf,buf);
kn->kn_data = ((buf_lim - buf_cur)-1)>>1;
- if ( kn->kn_data > idx_lim - idx_cur )
+ if (kn->kn_data > idx_lim - idx_cur)
kn->kn_data = idx_lim - idx_cur;
- MIDI_OUT_UNLOCK(sc,s);
+ if (hint != NOTE_SUBMIT)
+ mutex_exit(sc->lock);
return (kn->kn_data > 0);
}
@@ -1746,7 +1708,6 @@ midikqfilter(dev_t dev, struct knote *kn)
struct midi_softc *sc =
device_lookup_private(&midi_cd, MIDIUNIT(dev));
struct klist *klist;
- int s;
switch (kn->kn_filter) {
case EVFILT_READ:
@@ -1765,9 +1726,9 @@ midikqfilter(dev_t dev, struct knote *kn)
kn->kn_hook = sc;
- s = splaudio();
+ mutex_enter(sc->lock);
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
- splx(s);
+ mutex_exit(sc->lock);
return (0);
}
@@ -1780,15 +1741,18 @@ midi_getinfo(dev_t dev, struct midi_info *mi)
sc = device_lookup_private(&midi_cd, MIDIUNIT(dev));
if (sc == NULL)
return;
- if (sc->dying)
- return;
-
+ mutex_enter(sc->lock);
sc->hw_if->getinfo(sc->hw_hdl, mi);
+ mutex_exit(sc->lock);
}
#elif NMIDIBUS > 0 /* but NMIDI == 0 */
-void midi_register_hw_if_ext(struct midi_hw_if_ext *exthw) { /* stub */
+void
+midi_register_hw_if_ext(struct midi_hw_if_ext *exthw)
+{
+
+ /* nothing */
}
#endif /* NMIDI > 0 */
@@ -1802,12 +1766,11 @@ midi_attach_mi(const struct midi_hw_if *mhwp, void *hdlp, device_t dev)
{
struct audio_attach_args arg;
-#ifdef DIAGNOSTIC
if (mhwp == NULL) {
- aprint_error("midi_attach_mi: NULL\n");
+ panic("midi_attach_mi: NULL\n");
return (0);
}
-#endif
+
arg.type = AUDIODEV_TYPE_MIDI;
arg.hwif = mhwp;
arg.hdl = hdlp;
diff --git a/sys/dev/midi_if.h b/sys/dev/midi_if.h
index 35af9dbcbf7..245a82f2792 100644
--- a/sys/dev/midi_if.h
+++ b/sys/dev/midi_if.h
@@ -1,4 +1,4 @@
-/* $NetBSD: midi_if.h,v 1.22 2009/04/07 17:55:55 dyoung Exp $ */
+/* $NetBSD: midi_if.h,v 1.23 2011/11/23 23:07:31 jmcneill Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -32,6 +32,8 @@
#ifndef _SYS_DEV_MIDI_IF_H_
#define _SYS_DEV_MIDI_IF_H_
+#include <sys/mutex.h>
+
struct midi_info {
const char *name; /* Name of MIDI hardware */
int props;
@@ -51,6 +53,7 @@ struct midi_hw_if {
int (*output)(void *, int); /* output a byte */
void (*getinfo)(void *, struct midi_info *);
int (*ioctl)(void *, u_long, void *, int, struct lwp *);
+ void (*get_locks)(void *, kmutex_t **, kmutex_t **);
};
/*
diff --git a/sys/dev/midictl.c b/sys/dev/midictl.c
index 282fd7791b6..c29c33173bb 100644
--- a/sys/dev/midictl.c
+++ b/sys/dev/midictl.c
@@ -1,11 +1,11 @@
-/* $NetBSD: midictl.c,v 1.6 2008/06/24 10:55:48 gmcgarry Exp $ */
+/* $NetBSD: midictl.c,v 1.7 2011/11/23 23:07:31 jmcneill Exp $ */
/*-
- * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * Copyright (c) 2006, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Chapman Flack.
+ * by Chapman Flack, and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,34 +29,18 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: midictl.c,v 1.6 2008/06/24 10:55:48 gmcgarry Exp $");
+__KERNEL_RCSID(0, "$NetBSD: midictl.c,v 1.7 2011/11/23 23:07:31 jmcneill Exp $");
/*
* See midictl.h for an overview of the purpose and use of this module.
*/
-#if defined(_KERNEL)
-#define _MIDICTL_ASSERT(x) KASSERT(x)
-#define _MIDICTL_MALLOC(s,t) malloc((s), (t), M_WAITOK)
-#define _MIDICTL_ZMALLOC(s,t) malloc((s), (t), M_WAITOK|M_ZERO)
-#define _MIDICTL_IMZMALLOC(s,t) malloc((s), (t), M_NOWAIT|M_ZERO)
-#define _MIDICTL_PANIC(...) panic(__VA_ARGS__)
-#define _MIDICTL_FREE(s,t) free((s), (t))
#include <sys/systm.h>
#include <sys/types.h>
-#else
-#include <assert.h>
-#include <err.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#define _MIDICTL_ASSERT(x) assert(x)
-#define _MIDICTL_MALLOC(s,t) malloc((s))
-#define _MIDICTL_ZMALLOC(s,t) calloc(1,(s))
-#define _MIDICTL_IMZMALLOC(s,t) calloc(1,(s))
-#define _MIDICTL_PANIC(...) errx(1,__VA_ARGS__)
-#define _MIDICTL_FREE(s,t) free((s))
-#endif
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/kmem.h>
#include "midictl.h"
@@ -101,8 +85,6 @@ static uint_fast16_t read14(midictl *mc, uint_fast8_t chan, class c,
static class classify(uint_fast16_t *key, _Bool *islsb);
static midictl_notify notify_no_one;
-static midictl_store *store_init(void);
-static void store_done(midictl_store *s);
static _Bool store_locate(midictl_store *s, class c,
uint_fast8_t chan, uint_fast16_t key);
/*
@@ -123,57 +105,116 @@ static void store_update(midictl_store *s, class c,
#define C7_SET 0x80 /* a 7-bit ctl has been set */
#define C1_SET 2 /* a 1-bit ctl has been set */
-#if defined(_MIDICTL_MAIN)
-#define XS(s) [MIDICTL_##s]=#s
-char const * const evt_strings[] = {
- XS(CTLR), XS(RPN), XS(NRPN), XS(RESET), XS(NOTES_OFF),
- XS(SOUND_OFF), XS(LOCAL), XS(MODE)
+/*
+ * I M P L E M E N T A T I O N O F T H E S T O R E :
+ *
+ * MIDI defines a metric plethora of possible controllers, registered
+ * parameters, and nonregistered parameters: a bit more than 32k possible words
+ * to store. The saving grace is that only a handful are likely to appear in
+ * typical MIDI data, and only a handful are likely implemented by or
+ * interesting to a typical client. So the store implementation needs to be
+ * suited to a largish but quite sparse data set.
+ *
+ * A double-hashed, open address table is used here. Each slot is a uint64
+ * that contains the match key (control class|channel|ctl-or-PN-number) as
+ * well as the values for two or more channels. CTL14s, RPNs, and NRPNs can
+ * be packed two channels to the slot; CTL7s, six channels; and CTL1s get all
+ * 16 channels into one slot. The channel value used in the key is the lowest
+ * channel stored in the slot. Open addressing is appropriate here because the
+ * link fields in a chained approach would be at least 100% overhead, and also,
+ * we don't delete (MIDICTL_RESET is the only event that logically deletes
+ * things, and at the moment it does not remove anything from the table, but
+ * zeroes the stored value). If wanted, the deletion algorithm for open
+ * addressing could be used, with shrinking/rehashing when the load factor
+ * drops below 3/8 (1/2 is the current threshold for expansion), and the
+ * rehashing would relieve the fills-with-DELETED problem in most cases. But
+ * for now the table never shrinks while the device is open.
+ */
+
+struct midictl_store {
+ uint64_t *table;
+ uint64_t key;
+ uint32_t idx;
+ uint32_t lgcapacity;
+ uint32_t used;
+ kcondvar_t cv;
+ kmutex_t *lock;
+ bool destroy;
};
-#undef XS
-void
-dbgnotify(void *cookie, midictl_evt e, uint_fast8_t chan, uint_fast16_t key)
-{
- printf("NFY %p %s chan %u #%u\n", cookie, evt_strings[e], chan, key);
-}
+#define INITIALLGCAPACITY 6 /* initial capacity 1<<6 */
+#define IS_USED 1<<15
+#define IS_CTL7 1<<14
-midictl mc = {
- .accept_any_ctl_rpn = 0,
- .accept_any_nrpn = 0,
- .base_channel = 16,
- .cookie = NULL,
- .notify = dbgnotify
+#define CTL1SHIFT(chan) (23+((chan)<<1))
+#define CTL7SHIFT(chan) (16+((chan)<<3))
+#define CTLESHIFT(chan) (23+((chan)<<4))
+
+#define NEED_REHASH(s) ((s)->used * 2 >= 1 << (s)->lgcapacity)
+
+static uint_fast8_t const packing[] = {
+ [CTL1 ] = 16, /* 16 * 2 bits ==> 32 bits, all chns in one bucket */
+ [CTL7 ] = 6, /* 6 * 8 bits ==> 48 bits, 6 chns in one bucket */
+ [CTL14] = 2, /* 2 *16 bits ==> 32 bits, 2 chns in one bucket */
+ [RPN ] = 2,
+ [NRPN ] = 2
};
-int
-main(int argc, char **argv)
-{
- int cnt, a, b, c;
-
- midictl_open(&mc);
- do {
- cnt = scanf("%i %i %i", &a, &b, &c);
- if ( 3 == cnt ) {
- midictl_change(&mc, a, (uint8_t[]){b,c});
- }
- } while ( EOF != cnt );
- midictl_close(&mc);
- return 0;
-}
-#endif /* defined(_MIDICTL_MAIN) */
+static uint32_t store_idx(uint32_t lgcapacity,
+ uint64_t *table,
+ uint64_t key, uint64_t mask);
+static void store_rehash(midictl_store *s);
+static void store_thread(void *);
-void
+int
midictl_open(midictl *mc)
{
- if ( NULL == mc->notify )
+ midictl_store *s;
+ int error;
+
+ if (mc->lock == NULL)
+ panic("midictl_open: no lock");
+ if (NULL == mc->notify)
mc->notify = notify_no_one;
- mc->store = store_init();
+ s = kmem_zalloc(sizeof(*s), KM_SLEEP);
+ if (s == NULL) {
+ return ENOMEM;
+ }
+ s->lgcapacity = INITIALLGCAPACITY;
+ s->table = kmem_zalloc(sizeof(*s->table)<<s->lgcapacity, KM_SLEEP);
+ if (s->table == NULL) {
+ kmem_free(s->table, sizeof(*s->table)<<s->lgcapacity);
+ kmem_free(s, sizeof(*s));
+ return ENOMEM;
+ }
+ s->lock = mc->lock;
+ cv_init(&s->cv, "midictlv");
+ error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, store_thread,
+ s, NULL, "midictlt");
+ if (error != 0) {
+ printf("midictl: cannot create kthread, error = %d\n", error);
+ cv_destroy(&s->cv);
+ kmem_free(s->table, sizeof(*s->table)<<s->lgcapacity);
+ kmem_free(s, sizeof(*s));
+ return error;
+ }
+ mc->store = s;
+ return 0;
}
void
midictl_close(midictl *mc)
{
- store_done(mc->store);
+ midictl_store *s;
+ kmutex_t *lock;
+
+ s = mc->store;
+ lock = s->lock;
+
+ mutex_enter(lock);
+ s->destroy = true;
+ cv_broadcast(&s->cv);
+ mutex_exit(lock);
}
void
@@ -182,6 +223,9 @@ midictl_change(midictl *mc, uint_fast8_t chan, uint8_t *ctlval)
class c;
uint_fast16_t key, val;
_Bool islsb, present;
+
+ KASSERT(mutex_owned(mc->lock));
+ KASSERT(!mc->store->destroy);
switch ( ctlval[0] ) {
/*
@@ -307,6 +351,9 @@ midictl_read(midictl *mc, uint_fast8_t chan, uint_fast8_t ctlr,
uint_fast16_t key, val;
class c;
_Bool islsb, present;
+
+ KASSERT(mutex_owned(mc->lock));
+ KASSERT(!mc->store->destroy);
key = ctlr;
c = classify(&key, &islsb);
@@ -328,7 +375,7 @@ midictl_read(midictl *mc, uint_fast8_t chan, uint_fast8_t ctlr,
}
return val & 0x7f;
case CTL14:
- _MIDICTL_ASSERT(!islsb);
+ KASSERT(!islsb);
return read14(mc, chan, c, key, dflt);
case RPN:
case NRPN:
@@ -341,6 +388,10 @@ uint_fast16_t
midictl_rpn_read(midictl *mc, uint_fast8_t chan, uint_fast16_t ctlr,
uint_fast16_t dflt)
{
+
+ KASSERT(mutex_owned(mc->lock));
+ KASSERT(!mc->store->destroy);
+
return read14(mc, chan, RPN, ctlr, dflt);
}
@@ -348,6 +399,10 @@ uint_fast16_t
midictl_nrpn_read(midictl *mc, uint_fast8_t chan, uint_fast16_t ctlr,
uint_fast16_t dflt)
{
+
+ KASSERT(mutex_owned(mc->lock));
+ KASSERT(!mc->store->destroy);
+
return read14(mc, chan, NRPN, ctlr, dflt);
}
@@ -357,6 +412,8 @@ reset_all_controllers(midictl *mc, uint_fast8_t chan)
uint_fast16_t ctlr, key;
class c;
_Bool islsb, present;
+
+ KASSERT(mutex_owned(mc->lock));
for ( ctlr = 0 ; ; ++ ctlr ) {
switch ( ctlr ) {
@@ -401,6 +458,8 @@ enter14(midictl *mc, uint_fast8_t chan, class c, uint_fast16_t key,
uint16_t stval;
_Bool present;
+ KASSERT(mutex_owned(mc->lock));
+
present = store_locate(mc->store, c, chan, key);
stval = (present) ? store_extract(mc->store, c, chan, key) : 0;
if ( !( stval & (C14MSET|C14LSET) ) ) {
@@ -423,7 +482,9 @@ read14(midictl *mc, uint_fast8_t chan, class c, uint_fast16_t key,
{
uint16_t val;
_Bool present;
-
+
+ KASSERT(mutex_owned(mc->lock));
+
present = store_locate(mc->store, c, chan, key);
if ( !present )
goto neitherset;
@@ -479,90 +540,38 @@ notify_no_one(void *cookie, midictl_evt evt,
#undef C7_SET
#undef C1_SET
-/*
- * I M P L E M E N T A T I O N O F T H E S T O R E :
- *
- * MIDI defines a metric plethora of possible controllers, registered
- * parameters, and nonregistered parameters: a bit more than 32k possible words
- * to store. The saving grace is that only a handful are likely to appear in
- * typical MIDI data, and only a handful are likely implemented by or
- * interesting to a typical client. So the store implementation needs to be
- * suited to a largish but quite sparse data set.
- *
- * A double-hashed, open address table is used here. Each slot is a uint64
- * that contains the match key (control class|channel|ctl-or-PN-number) as
- * well as the values for two or more channels. CTL14s, RPNs, and NRPNs can
- * be packed two channels to the slot; CTL7s, six channels; and CTL1s get all
- * 16 channels into one slot. The channel value used in the key is the lowest
- * channel stored in the slot. Open addressing is appropriate here because the
- * link fields in a chained approach would be at least 100% overhead, and also,
- * we don't delete (MIDICTL_RESET is the only event that logically deletes
- * things, and at the moment it does not remove anything from the table, but
- * zeroes the stored value). If wanted, the deletion algorithm for open
- * addressing could be used, with shrinking/rehashing when the load factor
- * drops below 3/8 (3/4 is the current threshold for expansion), and the
- * rehashing would relieve the fills-with-DELETED problem in most cases. But
- * for now the table never shrinks while the device is open.
- */
-
-#include <sys/malloc.h>
-
-#define INITIALLGCAPACITY 6 /* initial capacity 1<<6 */
-#define IS_USED 1<<15
-#define IS_CTL7 1<<14
-
-#define CTL1SHIFT(chan) (23+((chan)<<1))
-#define CTL7SHIFT(chan) (16+((chan)<<3))
-#define CTLESHIFT(chan) (23+((chan)<<4))
-
-static uint_fast8_t const packing[] = {
- [CTL1 ] = 16, /* 16 * 2 bits ==> 32 bits, all chns in one bucket */
- [CTL7 ] = 6, /* 6 * 8 bits ==> 48 bits, 6 chns in one bucket */
- [CTL14] = 2, /* 2 *16 bits ==> 32 bits, 2 chns in one bucket */
- [RPN ] = 2,
- [NRPN ] = 2
-};
-
-struct midictl_store {
- uint64_t *table;
- uint64_t key;
- uint32_t idx;
- uint32_t lgcapacity;
- uint32_t used;
-};
-
-static uint32_t store_idx(uint32_t lgcapacity,
- uint64_t *table,
- uint64_t key, uint64_t mask);
-static void store_rehash(midictl_store *s);
-
-static midictl_store *
-store_init(void)
+static void
+store_thread(void *arg)
{
midictl_store *s;
-
- s = _MIDICTL_MALLOC(sizeof *s, M_DEVBUF);
- s->used = 0;
- s->lgcapacity = INITIALLGCAPACITY;
- s->table = _MIDICTL_ZMALLOC(sizeof *s->table<<s->lgcapacity, M_DEVBUF);
- return s;
-}
-static void
-store_done(midictl_store *s)
-{
- _MIDICTL_FREE(s->table, M_DEVBUF);
- _MIDICTL_FREE(s, M_DEVBUF);
+ s = arg;
+
+ mutex_enter(s->lock);
+ for (;;) {
+ if (s->destroy) {
+ mutex_exit(s->lock);
+ cv_destroy(&s->cv);
+ kmem_free(s->table, sizeof(*s->table)<<s->lgcapacity);
+ kmem_free(s, sizeof(*s));
+ kthread_exit(0);
+ } else if (NEED_REHASH(s)) {
+ store_rehash(s);
+ } else {
+ cv_wait(&s->cv, s->lock);
+ }
+ }
}
static _Bool
store_locate(midictl_store *s, class c, uint_fast8_t chan, uint_fast16_t key)
{
uint64_t mask;
+
+ KASSERT(mutex_owned(s->lock));
if ( s->used >= 1 << s->lgcapacity )
- _MIDICTL_PANIC("%s: repeated attempts to expand table failed, "
- "plumb ran out of space", __func__);
+ panic("%s: repeated attempts to expand table failed", __func__);
chan = packing[c] * (chan/packing[c]);
@@ -586,6 +595,9 @@ static uint16_t
store_extract(midictl_store *s, class c, uint_fast8_t chan,
uint_fast16_t key)
{
+
+ KASSERT(mutex_owned(s->lock));
+
chan %= packing[c];
switch ( c ) {
case CTL1:
@@ -605,6 +617,8 @@ store_update(midictl_store *s, class c, uint_fast8_t chan,
uint_fast16_t key, uint16_t value)
{
uint64_t orig;
+
+ KASSERT(mutex_owned(s->lock));
orig = s->table[s->idx];
if ( !(orig & IS_USED) ) {
@@ -632,8 +646,8 @@ store_update(midictl_store *s, class c, uint_fast8_t chan,
}
s->table[s->idx] = orig;
- if ( s->used * 4 >= 3 << s->lgcapacity )
- store_rehash(s);
+ if (NEED_REHASH(s))
+ cv_broadcast(&s->cv);
}
static uint32_t
@@ -666,99 +680,53 @@ store_idx(uint32_t lgcapacity, uint64_t *table,
static void
store_rehash(midictl_store *s)
{
- uint64_t *newtbl, mask;
- uint32_t newlgcap, oidx, nidx;
-
- newlgcap = 1 + s->lgcapacity;
- newtbl = _MIDICTL_IMZMALLOC(sizeof *newtbl << newlgcap, M_DEVBUF);
-
+ uint64_t *newtbl, *oldtbl, mask;
+ uint32_t oldlgcap, newlgcap, oidx, nidx;
+
+ KASSERT(mutex_owned(s->lock));
+
+ oldlgcap = s->lgcapacity;
+ newlgcap = oldlgcap + s->lgcapacity;
+
+ mutex_exit(s->lock);
+ newtbl = kmem_zalloc(sizeof(*newtbl) << newlgcap, KM_SLEEP);
+ mutex_enter(s->lock);
+
+ if (newtbl == NULL) {
+ kpause("midictls", false, hz, s->lock);
+ return;
+ }
/*
- * Because IMZMALLOC can't sleep, it might have returned NULL.
- * We rehash when there is some capacity left in the table, so
- * just leave it alone; we'll get another chance on the next insertion.
- * Nothing to panic about unless the load factor really hits 1.
+ * If s->lgcapacity is changed from what we saved int oldlgcap
+ * then someone else has already done this for us.
+ * XXXMRG but only function changes s->lgcapacity from its
+ * initial value, and it is called singled threaded from the
+ * main store_thread(), so this code seems dead to me.
*/
- if ( NULL == newtbl )
+ if (oldlgcap != s->lgcapacity) {
+ KASSERT(FALSE);
+ mutex_exit(s->lock);
+ kmem_free(newtbl, sizeof(*newtbl) << newlgcap);
+ mutex_enter(s->lock);
return;
-
- for ( oidx = 1<<s->lgcapacity ; oidx --> 0 ; ) {
- if ( !(s->table[oidx] & IS_USED) )
+ }
+
+ for (oidx = 1 << s->lgcapacity ; oidx-- > 0 ; ) {
+ if (!(s->table[oidx] & IS_USED))
continue;
- if ( s->table[oidx] & IS_CTL7 )
+ if (s->table[oidx] & IS_CTL7)
mask = 0xffff;
else
mask = 0x3fffff;
- nidx = store_idx(newlgcap, newtbl, s->table[oidx]&mask, mask);
+ nidx = store_idx(newlgcap, newtbl,
+ s->table[oidx] & mask, mask);
newtbl[nidx] = s->table[oidx];
}
-
- _MIDICTL_FREE(s->table, M_DEVBUF);
+ oldtbl = s->table;
s->table = newtbl;
s->lgcapacity = newlgcap;
-}
-
-#if defined(_MIDICTL_MAIN)
-void
-dumpstore(void)
-{
- uint64_t val;
- uint32_t i, remain;
- midictl_store *s;
- char const *lbl;
- uint_fast16_t key;
- uint_fast8_t chan;
- class c;
-
- s = mc.store;
-
- printf("store capacity %u, used %u\n", 1<<s->lgcapacity, s->used);
- remain = s->used;
-
- for ( i = 1<<s->lgcapacity; i --> 0; ) {
- if ( !(s->table[i] & IS_USED) )
- continue;
- -- remain;
- if ( s->table[i] & IS_CTL7 ) {
- c = CTL7;
- chan = 0xf & (s->table[i]>>7);
- key = 0x7f & s->table[i];
- } else {
- c = 0x7 & (s->table[i]>>20);
- chan = 0xf & (s->table[i]>>16);
- key = 0x3fff & s->table[i];
- }
- switch ( c ) {
- case CTL1:
- lbl = "CTL1";
- val = s->table[i] >> CTL1SHIFT(0);
- break;
- case CTL7:
- lbl = "CTL7";
- val = s->table[i] >> CTL7SHIFT(0);
- break;
- case CTL14:
- lbl = "CTL14";
- val = s->table[i] >> CTLESHIFT(0);
- break;
- case RPN:
- lbl = "RPN";
- val = s->table[i] >> CTLESHIFT(0);
- break;
- case NRPN:
- lbl = "NRPN";
- val = s->table[i] >> CTLESHIFT(0);
- break;
- default:
- lbl = "???";
- chan = 0;
- key = 0;
- val = s->table[i];
- }
- printf("[%7u] %5s chans %x-%x key %5u: %"PRIx64"\n",
- i, lbl, chan, chan+packing[c]-1, key, val);
- }
- if ( 0 != remain )
- printf("remain == %u ??\n", remain);
+ mutex_exit(s->lock);
+ kmem_free(oldtbl, sizeof(*oldtbl) << oldlgcap);
+ mutex_enter(s->lock);
}
-#endif
diff --git a/sys/dev/midictl.h b/sys/dev/midictl.h
index f2ee5dd6eb3..95943047679 100644
--- a/sys/dev/midictl.h
+++ b/sys/dev/midictl.h
@@ -1,11 +1,11 @@
-/* $NetBSD: midictl.h,v 1.3 2008/04/28 20:23:47 martin Exp $ */
+/* $NetBSD: midictl.h,v 1.4 2011/11/23 23:07:31 jmcneill Exp $ */
/*-
- * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * Copyright (c) 2006, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Chapman Flack.
+ * by Chapman Flack and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -157,9 +157,10 @@ typedef struct {
uint16_t rpn;
uint16_t nrpn;
midictl_store *store;
+ kmutex_t *lock;
} midictl;
-extern void
+extern int
midictl_open(midictl *);
extern void
diff --git a/sys/dev/midisyn.c b/sys/dev/midisyn.c
index 562bf40318f..fdc05728a6f 100644
--- a/sys/dev/midisyn.c
+++ b/sys/dev/midisyn.c
@@ -1,11 +1,11 @@
-/* $NetBSD: midisyn.c,v 1.22 2008/04/28 20:23:47 martin Exp $ */
+/* $NetBSD: midisyn.c,v 1.23 2011/11/23 23:07:31 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson (augustss@NetBSD.org).
+ * by Lennart Augustsson (augustss@NetBSD.org), and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: midisyn.c,v 1.22 2008/04/28 20:23:47 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: midisyn.c,v 1.23 2011/11/23 23:07:31 jmcneill Exp $");
#include <sys/param.h>
#include <sys/ioctl.h>
@@ -38,7 +38,7 @@ __KERNEL_RCSID(0, "$NetBSD: midisyn.c,v 1.22 2008/04/28 20:23:47 martin Exp $");
#include <sys/vnode.h>
#include <sys/select.h>
#include <sys/proc.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/systm.h>
#include <sys/syslog.h>
#include <sys/kernel.h>
@@ -60,9 +60,9 @@ int midisyndebug = 0;
#define DPRINTFN(n,x)
#endif
-int midisyn_findvoice(midisyn *, int, int);
-void midisyn_freevoice(midisyn *, int);
-uint_fast16_t midisyn_allocvoice(midisyn *, uint_fast8_t, uint_fast8_t);
+static int midisyn_findvoice(midisyn *, int, int);
+static void midisyn_freevoice(midisyn *, int);
+static uint_fast16_t midisyn_allocvoice(midisyn *, uint_fast8_t, uint_fast8_t);
static void midisyn_attackv_vel(midisyn *, uint_fast16_t, midipitch_t,
int16_t, uint_fast8_t);
@@ -75,13 +75,14 @@ static void midisyn_chan_releasev(midisyn *, uint_fast8_t, uint_fast8_t);
static void midisyn_upd_level(midisyn *, uint_fast8_t);
static void midisyn_upd_pitch(midisyn *, uint_fast8_t);
-int midisyn_open(void *, int,
- void (*iintr)(void *, int),
- void (*ointr)(void *), void *arg);
-void midisyn_close(void *);
-int midisyn_sysrt(void *, int);
-void midisyn_getinfo(void *, struct midi_info *);
-int midisyn_ioctl(void *, u_long, void *, int, struct lwp *);
+static int midisyn_open(void *, int,
+ void (*iintr)(void *, int),
+ void (*ointr)(void *), void *arg);
+static void midisyn_close(void *);
+static int midisyn_sysrt(void *, int);
+static void midisyn_getinfo(void *, struct midi_info *);
+static int midisyn_ioctl(void *, u_long, void *, int, struct lwp *);
+static void midisyn_get_locks(void *, kmutex_t **, kmutex_t **);
const struct midi_hw_if midisyn_hw_if = {
midisyn_open,
@@ -89,11 +90,12 @@ const struct midi_hw_if midisyn_hw_if = {
midisyn_sysrt,
midisyn_getinfo,
midisyn_ioctl,
+ midisyn_get_locks,
};
-int midisyn_channelmsg(void *, int, int, u_char *, int);
-int midisyn_commonmsg(void *, int, u_char *, int);
-int midisyn_sysex(void *, u_char *, int);
+static int midisyn_channelmsg(void *, int, int, u_char *, int);
+static int midisyn_commonmsg(void *, int, u_char *, int);
+static int midisyn_sysex(void *, u_char *, int);
struct midi_hw_if_ext midisyn_hw_if_ext = {
.channel = midisyn_channelmsg,
@@ -123,20 +125,31 @@ struct channelstate { /* dyamically allocated in open() on account of size */
#define PEND_ALL (PEND_LEVEL|PEND_PITCH)
};
-int
+static int
midisyn_open(void *addr, int flags, void (*iintr)(void *, int),
void (*ointr)(void *), void *arg)
{
midisyn *ms = addr;
- int rslt;
+ int rslt, error;
uint_fast8_t chan;
+ if (ms->lock == NULL) {
+ panic("midisyn_open: no lock");
+ }
+
+ KASSERT(mutex_owned(ms->lock));
DPRINTF(("midisyn_open: ms=%p ms->mets=%p\n", ms, ms->mets));
-
- midictl_open(&ms->ctl);
-
- ms->chnstate = malloc(MIDI_MAX_CHANS*sizeof *(ms->chnstate),
- M_DEVBUF, M_WAITOK); /* init'd by RESET below */
+
+ mutex_exit(ms->lock);
+ ms->ctl.lock = ms->lock;
+ error = midictl_open(&ms->ctl);
+ if (error != 0) {
+ mutex_enter(ms->lock);
+ return error;
+ }
+ ms->chnstate = kmem_alloc(MIDI_MAX_CHANS * sizeof(*ms->chnstate),
+ KM_SLEEP); /* init'd by RESET below */
+ mutex_enter(ms->lock);
rslt = 0;
if (ms->mets->open)
@@ -152,13 +165,14 @@ midisyn_open(void *addr, int flags, void (*iintr)(void *, int),
return rslt;
}
-void
+static void
midisyn_close(void *addr)
{
midisyn *ms = addr;
struct midisyn_methods *fs;
int chan;
+ KASSERT(mutex_owned(ms->lock));
DPRINTF(("midisyn_close: ms=%p ms->mets=%p\n", ms, ms->mets));
fs = ms->mets;
@@ -168,16 +182,19 @@ midisyn_close(void *addr)
if (fs->close)
fs->close(ms);
- free(ms->chnstate, M_DEVBUF);
-
+ mutex_exit(ms->lock);
midictl_close(&ms->ctl);
+ kmem_free(ms->chnstate, MIDI_MAX_CHANS * sizeof(*ms->chnstate));
+ mutex_enter(ms->lock);
}
-void
+static void
midisyn_getinfo(void *addr, struct midi_info *mi)
{
midisyn *ms = addr;
+ KASSERT(mutex_owned(ms->lock));
+
mi->name = ms->name;
/*
* I was going to add a property here to suppress midi(4)'s warning
@@ -195,23 +212,36 @@ midisyn_getinfo(void *addr, struct midi_info *mi)
midi_register_hw_if_ext(&midisyn_hw_if_ext);
}
-int
+static void
+midisyn_get_locks(void *addr, kmutex_t **intr, kmutex_t **proc)
+{
+ midisyn *ms = addr;
+
+ *intr = ms->lock;
+ *proc = NULL;
+}
+
+static int
midisyn_ioctl(void *maddr, u_long cmd, void *addr, int flag, struct lwp *l)
{
midisyn *ms = maddr;
+ KASSERT(mutex_owned(ms->lock));
+
if (ms->mets->ioctl)
return (ms->mets->ioctl(ms, cmd, addr, flag, l));
else
return (EINVAL);
}
-int
+static int
midisyn_findvoice(midisyn *ms, int chan, int note)
{
u_int cn;
int v;
+ KASSERT(mutex_owned(ms->lock));
+
cn = MS_CHANNOTE(chan, note);
for (v = 0; v < ms->nvoice; v++)
if (ms->voices[v].chan_note == cn && ms->voices[v].inuse)
@@ -222,14 +252,19 @@ midisyn_findvoice(midisyn *ms, int chan, int note)
void
midisyn_attach(struct midi_softc *sc, midisyn *ms)
{
+
+ if (ms->lock == NULL) {
+ panic("midisyn_attach: no lock");
+ }
+
/*
* XXX there should be a way for this function to indicate failure
* (other than panic) if some preconditions aren't met, for example
* if some nonoptional methods are missing.
*/
if (ms->mets->allocv == 0) {
- ms->voices = malloc(ms->nvoice * sizeof (struct voice),
- M_DEVBUF, M_WAITOK|M_ZERO);
+ ms->voices = kmem_zalloc(ms->nvoice * sizeof(struct voice),
+ KM_SLEEP);
ms->seqno = 1;
ms->mets->allocv = midisyn_allocvoice;
}
@@ -248,20 +283,25 @@ midisyn_attach(struct midi_softc *sc, midisyn *ms)
DPRINTF(("midisyn_attach: ms=%p\n", sc->hw_hdl));
}
-void
+static void
midisyn_freevoice(midisyn *ms, int voice)
{
+
+ KASSERT(mutex_owned(ms->lock));
+
if (ms->mets->allocv != midisyn_allocvoice)
return;
ms->voices[voice].inuse = 0;
}
-uint_fast16_t
+static uint_fast16_t
midisyn_allocvoice(midisyn *ms, uint_fast8_t chan, uint_fast8_t note)
{
int bestv, v;
u_int bestseq, s;
+ KASSERT(mutex_owned(ms->lock));
+
/* Find a free voice, or if no free voice is found the oldest. */
bestv = 0;
bestseq = ms->voices[0].seqno + (ms->voices[0].inuse ? 0x40000000 : 0);
@@ -294,23 +334,29 @@ static void
midisyn_attackv_vel(midisyn *ms, uint_fast16_t voice, midipitch_t mp,
int16_t level_cB, uint_fast8_t vel)
{
+
+ KASSERT(mutex_owned(ms->lock));
+
ms->voices[voice].velcB = midisyn_vol2cB((uint_fast16_t)vel << 7);
ms->mets->attackv(ms, voice, mp, level_cB + ms->voices[voice].velcB);
}
-int
+static int
midisyn_sysrt(void *addr, int b)
{
+
return 0;
}
-int midisyn_channelmsg(void *addr, int status, int chan, u_char *buf,
- int len)
+static int
+midisyn_channelmsg(void *addr, int status, int chan, u_char *buf, int len)
{
midisyn *ms = addr;
int voice = 0; /* initialize to keep gcc quiet */
struct midisyn_methods *fs;
+ KASSERT(mutex_owned(ms->lock));
+
DPRINTF(("midisyn_channelmsg: ms=%p status=%#02x chan=%d\n",
ms, status, chan));
fs = ms->mets;
@@ -393,14 +439,17 @@ int midisyn_channelmsg(void *addr, int status, int chan, u_char *buf,
return 0;
}
-int midisyn_commonmsg(void *addr, int status,
- u_char *buf, int len)
+static int
+midisyn_commonmsg(void *addr, int status, u_char *buf, int len)
{
+
return 0;
}
-int midisyn_sysex(void *addr, u_char *buf, int len)
+static int
+midisyn_sysex(void *addr, u_char *buf, int len)
{
+
/*
* unimplemented by existing drivers. it is surely more sensible
* to do some parsing of well-defined sysex messages here, either
@@ -419,6 +468,9 @@ midisyn_notify(void *cookie, midictl_evt evt,
int drvhandled;
ms = (struct midisyn *)cookie;
+
+ KASSERT(mutex_owned(ms->lock));
+
drvhandled = 0;
if ( ms->mets->ctlnotice )
drvhandled = ms->mets->ctlnotice(ms, evt, chan, key);
@@ -542,6 +594,7 @@ midisyn_notify(void *cookie, midictl_evt evt,
static midipitch_t
midisyn_clamp_pitch(midipitch_t mp)
{
+
if ( mp <= 0 )
return 0;
if ( mp >= MIDIPITCH_MAX )
@@ -553,6 +606,8 @@ static int16_t
midisyn_adj_level(midisyn *ms, uint_fast8_t chan)
{
int32_t level;
+
+ KASSERT(mutex_owned(ms->lock));
level = ms->chnstate[chan].volume + ms->chnstate[chan].expression;
if ( level <= INT16_MIN )
@@ -564,6 +619,9 @@ static midipitch_t
midisyn_adj_pitch(midisyn *ms, uint_fast8_t chan)
{
struct channelstate *s = ms->chnstate + chan;
+
+ KASSERT(mutex_owned(ms->lock));
+
return s->bend + s->tuning_fine +s->tuning_coarse;
}
@@ -583,6 +641,9 @@ midisyn_adj_pitch(midisyn *ms, uint_fast8_t chan)
static void
midisyn_chan_releasev(midisyn *ms, uint_fast8_t chan, uint_fast8_t vel)
{
+
+ KASSERT(mutex_owned(ms->lock));
+
VOICECHAN_FOREACH_BEGIN(ms,vp,chan)
ms->mets->releasev(ms, vp - ms->voices, vel);
midisyn_freevoice(ms, vp - ms->voices);
@@ -594,6 +655,9 @@ midisyn_upd_level(midisyn *ms, uint_fast8_t chan)
{
int32_t level;
int16_t chan_level;
+
+ KASSERT(mutex_owned(ms->lock));
+
if ( NULL == ms->mets->relevelv )
return;
@@ -613,6 +677,8 @@ static void
midisyn_upd_pitch(midisyn *ms, uint_fast8_t chan)
{
midipitch_t chan_adj;
+
+ KASSERT(mutex_owned(ms->lock));
if ( NULL == ms->mets->repitchv )
return;
diff --git a/sys/dev/midisynvar.h b/sys/dev/midisynvar.h
index 5967984ec9b..d16a0e4a670 100644
--- a/sys/dev/midisynvar.h
+++ b/sys/dev/midisynvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: midisynvar.h,v 1.12 2008/04/28 20:23:47 martin Exp $ */
+/* $NetBSD: midisynvar.h,v 1.13 2011/11/23 23:07:31 jmcneill Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -164,6 +164,7 @@ struct midisyn {
int nvoice;
int flags;
void *data;
+ kmutex_t *lock;
/* Set up by midisyn but available to synth driver for reading ctls */
/*
diff --git a/sys/dev/midivar.h b/sys/dev/midivar.h
index d23ca9d66a3..bf26d0fbde8 100644
--- a/sys/dev/midivar.h
+++ b/sys/dev/midivar.h
@@ -1,7 +1,7 @@
-/* $NetBSD: midivar.h,v 1.17 2008/04/28 20:23:47 martin Exp $ */
+/* $NetBSD: midivar.h,v 1.18 2011/11/23 23:07:31 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -35,12 +35,11 @@
#define MIDI_BUFSIZE 1024
-#include "sequencer.h"
-
#include <sys/callout.h>
#include <sys/cdefs.h>
#include <sys/device.h>
-#include <sys/simplelock.h>
+#include <sys/condvar.h>
+#include <sys/mutex.h>
/*
* In both xmt and rcv direction, the midi_fst runs at the time data are
@@ -191,40 +190,17 @@ struct midi_softc {
struct midi_buffer outbuf;
struct midi_buffer inbuf;
int props;
- int rchan, wchan;
- struct simplelock out_lock; /* overkill or no? */
- struct simplelock in_lock;
-
-#define MIDI_OUT_LOCK(sc,s) \
- do { \
- (s) = splaudio(); \
- simple_lock(&(sc)->out_lock); \
- } while (/*CONSTCOND*/0)
-#define MIDI_OUT_UNLOCK(sc,s) \
- do { \
- simple_unlock(&(sc)->out_lock); \
- splx((s)); \
- } while (/*CONSTCOND*/0)
-#define MIDI_IN_LOCK(sc,s) \
- do { \
- (s) = splaudio(); \
- simple_lock(&(sc)->in_lock); \
- } while (/*CONSTCOND*/0)
-#define MIDI_IN_UNLOCK(sc,s) \
- do { \
- simple_unlock(&(sc)->in_lock); \
- splx((s)); \
- } while (/*CONSTCOND*/0)
-
+ kcondvar_t rchan;
+ kcondvar_t wchan;
+ kmutex_t *lock;
int pbus;
int rcv_expect_asense;
int rcv_quiescent;
int rcv_eof;
struct selinfo wsel; /* write selector */
struct selinfo rsel; /* read selector */
- struct proc *async; /* process who wants audio SIGIO */
- void *sih_rd;
- void *sih_wr;
+ pid_t async; /* process who wants audio SIGIO */
+ void *sih;
struct callout xmt_asense_co;
struct callout rcv_asense_co;
@@ -263,11 +239,9 @@ struct midi_softc {
#define MIDI_CAT_STATUS2 2
#define MIDI_CAT_COMMON 3
-#if NSEQUENCER > 0
/* Synthesizer emulation stuff */
int seqopen;
struct midi_dev *seq_md; /* structure that links us with the seq. */
-#endif
};
#define MIDIUNIT(d) ((d) & 0xff)
diff --git a/sys/dev/mulaw.c b/sys/dev/mulaw.c
index 6ad90901890..19e7f3c1344 100644
--- a/sys/dev/mulaw.c
+++ b/sys/dev/mulaw.c
@@ -1,4 +1,4 @@
-/* $NetBSD: mulaw.c,v 1.27 2008/03/04 18:23:44 cube Exp $ */
+/* $NetBSD: mulaw.c,v 1.28 2011/11/23 23:07:31 jmcneill Exp $ */
/*
* Copyright (c) 1991-1993 Regents of the University of California.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mulaw.c,v 1.27 2008/03/04 18:23:44 cube Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mulaw.c,v 1.28 2011/11/23 23:07:31 jmcneill Exp $");
#include <sys/types.h>
#include <sys/systm.h>
@@ -261,7 +261,7 @@ static const uint8_t lintoalaw[256] = {
#define DEFINE_FILTER(name) \
static int \
-name##_fetch_to(stream_fetcher_t *, audio_stream_t *, int); \
+name##_fetch_to(struct audio_softc *, stream_fetcher_t *, audio_stream_t *, int); \
stream_filter_t * \
name(struct audio_softc *sc, const audio_params_t *from, \
const audio_params_t *to) \
@@ -270,7 +270,8 @@ name(struct audio_softc *sc, const audio_params_t *from, \
return auconv_nocontext_filter_factory(name##_fetch_to); \
} \
static int \
-name##_fetch_to(stream_fetcher_t *self, audio_stream_t *dst, int max_used)
+name##_fetch_to(struct audio_softc *sc, stream_fetcher_t *self, \
+ audio_stream_t *dst, int max_used)
DEFINE_FILTER(mulaw_to_linear8)
{
@@ -278,7 +279,7 @@ DEFINE_FILTER(mulaw_to_linear8)
int m, err;
this = (stream_filter_t *)self;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
return err;
m = dst->end - dst->start;
m = min(m, max_used);
@@ -301,7 +302,7 @@ DEFINE_FILTER(mulaw_to_linear16)
this = (stream_filter_t *)self;
max_used = (max_used + 1) & ~1; /* round up to even */
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used / 2)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used / 2)))
return err;
m = (dst->end - dst->start) & ~1;
m = min(m, max_used);
@@ -340,7 +341,7 @@ DEFINE_FILTER(linear16_to_mulaw)
int m, err;
this = (stream_filter_t *)self;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used * 2)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used * 2)))
return err;
m = dst->end - dst->start;
m = min(m, max_used);
@@ -375,7 +376,7 @@ DEFINE_FILTER(linear8_to_mulaw)
int m, err;
this = (stream_filter_t *)self;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
return err;
m = dst->end - dst->start;
m = min(m, max_used);
@@ -397,7 +398,7 @@ DEFINE_FILTER(alaw_to_linear8)
int m, err;
this = (stream_filter_t *)self;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
return err;
m = dst->end - dst->start;
m = min(m, max_used);
@@ -420,7 +421,7 @@ DEFINE_FILTER(alaw_to_linear16)
this = (stream_filter_t *)self;
max_used = (max_used + 1) & ~1; /* round up to even */
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used / 2)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used / 2)))
return err;
m = (dst->end - dst->start) & ~1;
m = min(m, max_used);
@@ -459,7 +460,7 @@ DEFINE_FILTER(linear8_to_alaw)
int m, err;
this = (stream_filter_t *)self;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
return err;
m = dst->end - dst->start;
m = min(m, max_used);
@@ -481,7 +482,7 @@ DEFINE_FILTER(linear16_to_alaw)
int m, err;
this = (stream_filter_t *)self;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used * 2)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used * 2)))
return err;
m = dst->end - dst->start;
m = min(m, max_used);
diff --git a/sys/dev/ofisa/joy_ofisa.c b/sys/dev/ofisa/joy_ofisa.c
index 165846026a5..377426dfe6b 100644
--- a/sys/dev/ofisa/joy_ofisa.c
+++ b/sys/dev/ofisa/joy_ofisa.c
@@ -1,7 +1,7 @@
-/* $NetBSD: joy_ofisa.c,v 1.14 2008/04/28 20:23:54 martin Exp $ */
+/* $NetBSD: joy_ofisa.c,v 1.15 2011/11/23 23:07:33 jmcneill Exp $ */
/*-
- * Copyright (c) 1996, 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996, 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: joy_ofisa.c,v 1.14 2008/04/28 20:23:54 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: joy_ofisa.c,v 1.15 2011/11/23 23:07:33 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -47,10 +47,15 @@ __KERNEL_RCSID(0, "$NetBSD: joy_ofisa.c,v 1.14 2008/04/28 20:23:54 martin Exp $"
#define JOY_NPORTS 1 /* XXX should be in a header file */
+struct joy_ofisa_softc {
+ struct joy_softc sc_joy;
+ kmutex_t sc_lock;
+};
+
static int joy_ofisa_match(device_t, cfdata_t, void *);
static void joy_ofisa_attach(device_t, device_t, void *);
-CFATTACH_DECL_NEW(joy_ofisa, sizeof(struct joy_softc),
+CFATTACH_DECL_NEW(joy_ofisa, sizeof(struct joy_ofisa_softc),
joy_ofisa_match, joy_ofisa_attach, NULL, NULL);
static int
@@ -71,7 +76,8 @@ joy_ofisa_match(device_t parent, cfdata_t match, void *aux)
static void
joy_ofisa_attach(device_t parent, device_t self, void *aux)
{
- struct joy_softc *sc = device_private(self);
+ struct joy_ofisa_softc *osc = device_private(self);
+ struct joy_softc *sc = &osc->sc_joy;
struct ofisa_attach_args *aa = aux;
struct ofisa_reg_desc reg;
char *model = NULL;
@@ -119,5 +125,8 @@ joy_ofisa_attach(device_t parent, device_t self, void *aux)
aprint_normal(": %s", model);
aprint_normal("\n");
+ mutex_init(&osc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ sc->sc_lock = &osc->sc_lock;
+
joyattach(sc);
}
diff --git a/sys/dev/pad/pad.c b/sys/dev/pad/pad.c
index 22c296c1388..72446497a09 100644
--- a/sys/dev/pad/pad.c
+++ b/sys/dev/pad/pad.c
@@ -1,4 +1,4 @@
-/* $NetBSD: pad.c,v 1.16 2010/09/03 19:19:48 jmcneill Exp $ */
+/* $NetBSD: pad.c,v 1.17 2011/11/23 23:07:33 jmcneill Exp $ */
/*-
* Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.16 2010/09/03 19:19:48 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.17 2011/11/23 23:07:33 jmcneill Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -42,6 +42,7 @@ __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.16 2010/09/03 19:19:48 jmcneill Exp $");
#include <sys/audioio.h>
#include <sys/vnode.h>
#include <sys/module.h>
+#include <sys/atomic.h>
#include <dev/audio_if.h>
#include <dev/audiovar.h>
@@ -88,6 +89,7 @@ static int pad_get_port(void *, mixer_ctrl_t *);
static int pad_query_devinfo(void *, mixer_devinfo_t *);
static int pad_get_props(void *);
static int pad_round_blocksize(void *, int, int, const audio_params_t *);
+static void pad_get_locks(void *, kmutex_t **, kmutex_t **);
static const struct audio_hw_if pad_hw_if = {
.query_encoding = pad_query_encoding,
@@ -102,6 +104,7 @@ static const struct audio_hw_if pad_hw_if = {
.query_devinfo = pad_query_devinfo,
.get_props = pad_get_props,
.round_blocksize = pad_round_blocksize,
+ .get_locks = pad_get_locks,
};
#define PAD_NFORMATS 1
@@ -130,7 +133,7 @@ const struct cdevsw pad_cdevsw = {
.d_poll = nopoll,
.d_mmap = nommap,
.d_kqfilter = nokqfilter,
- .d_flag = D_OTHER,
+ .d_flag = D_OTHER | D_MPSAFE,
};
CFATTACH_DECL2_NEW(pad, sizeof(pad_softc_t), pad_match, pad_attach, pad_detach,
@@ -153,7 +156,7 @@ padattach(int n)
}
for (i = 0; i < n; i++) {
- cf = kmem_alloc(sizeof(struct cfdata), KM_NOSLEEP);
+ cf = kmem_alloc(sizeof(struct cfdata), KM_SLEEP);
if (cf == NULL) {
aprint_error("%s: couldn't allocate cfdata\n",
pad_cd.cd_name);
@@ -178,6 +181,8 @@ pad_add_block(pad_softc_t *sc, uint8_t *blk, int blksize)
if (sc->sc_open == 0)
return EIO;
+ KASSERT(mutex_owned(&sc->sc_lock));
+
if (sc->sc_buflen + blksize > PAD_BUFSIZE)
return ENOBUFS;
@@ -203,6 +208,7 @@ pad_get_block(pad_softc_t *sc, pad_block_t *pb, int blksize)
{
int l;
+ KASSERT(mutex_owned(&sc->sc_lock));
KASSERT(pb != NULL);
if (sc->sc_buflen < blksize)
@@ -225,6 +231,7 @@ pad_get_block(pad_softc_t *sc, pad_block_t *pb, int blksize)
static int
pad_match(device_t parent, cfdata_t data, void *opaque)
{
+
return 1;
}
@@ -252,7 +259,8 @@ pad_attach(device_t parent, device_t self, void *opaque)
}
cv_init(&sc->sc_condvar, device_xname(self));
- mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_SCHED);
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE);
sc->sc_swvol = 255;
sc->sc_buflen = 0;
@@ -280,7 +288,8 @@ pad_detach(device_t self, int flags)
pmf_device_deregister(self);
- mutex_destroy(&sc->sc_mutex);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
cv_destroy(&sc->sc_condvar);
auconv_delete_encodings(sc->sc_encodings);
@@ -297,8 +306,7 @@ pad_open(dev_t dev, int flags, int fmt, struct lwp *l)
if (sc == NULL)
return ENXIO;
- if (sc->sc_open++) {
- sc->sc_open--;
+ if (atomic_swap_uint(&sc->sc_open, 1) != 0) {
return EBUSY;
}
@@ -315,7 +323,7 @@ pad_close(dev_t dev, int flags, int fmt, struct lwp *l)
return ENXIO;
KASSERT(sc->sc_open > 0);
- sc->sc_open--;
+ sc->sc_open = 0;
return 0;
}
@@ -335,42 +343,43 @@ pad_read(dev_t dev, struct uio *uio, int flags)
err = 0;
+ mutex_enter(&sc->sc_lock);
intr = sc->sc_intr;
intrarg = sc->sc_intrarg;
while (uio->uio_resid > 0 && !err) {
err = pad_get_block(sc, &pb, min(uio->uio_resid, PAD_BLKSIZE));
- if (!err)
+ if (!err) {
+ mutex_exit(&sc->sc_lock);
err = uiomove(pb.pb_ptr, pb.pb_len, uio);
- else {
- if (intr) {
- (*intr)(intrarg);
- intr = sc->sc_intr;
- intrarg = sc->sc_intrarg;
- err = 0;
- continue;
- }
+ mutex_enter(&sc->sc_lock);
+ continue;
+ }
- mutex_enter(&sc->sc_mutex);
- err = cv_timedwait_sig(&sc->sc_condvar, &sc->sc_mutex,
- hz/100);
- if (err != 0 && err != EWOULDBLOCK) {
- mutex_exit(&sc->sc_mutex);
- if (err != ERESTART)
- aprint_error_dev(sc->sc_dev,
- "cv_timedwait_sig returned %d\n",
- err);
- return EINTR;
- }
+ if (intr) {
+ mutex_enter(&sc->sc_intr_lock);
+ (*intr)(intrarg);
+ mutex_exit(&sc->sc_intr_lock);
intr = sc->sc_intr;
intrarg = sc->sc_intrarg;
- mutex_exit(&sc->sc_mutex);
err = 0;
+ continue;
+ }
+ err = cv_wait_sig(&sc->sc_condvar, &sc->sc_lock);
+ if (err != 0) {
+ mutex_exit(&sc->sc_lock);
+ return err;
}
+ intr = sc->sc_intr;
+ intrarg = sc->sc_intrarg;
}
- if (intr)
+ if (intr) {
+ mutex_enter(&sc->sc_intr_lock);
(*intr)(intrarg);
+ mutex_exit(&sc->sc_intr_lock);
+ }
+ mutex_exit(&sc->sc_lock);
return err;
}
@@ -382,6 +391,8 @@ pad_query_encoding(void *opaque, struct audio_encoding *ae)
sc = (pad_softc_t *)opaque;
+ KASSERT(mutex_owned(&sc->sc_lock));
+
return auconv_query_encoding(sc->sc_encodings, ae);
}
@@ -394,6 +405,8 @@ pad_set_params(void *opaque, int setmode, int usemode,
sc = (pad_softc_t *)opaque;
+ KASSERT(mutex_owned(&sc->sc_lock));
+
if (auconv_set_converter(pad_formats, PAD_NFORMATS, AUMODE_PLAY,
play, true, pfil) < 0)
return EINVAL;
@@ -428,7 +441,7 @@ pad_start_output(void *opaque, void *block, int blksize,
sc = (pad_softc_t *)opaque;
- mutex_enter(&sc->sc_mutex);
+ KASSERT(mutex_owned(&sc->sc_lock));
sc->sc_intr = intr;
sc->sc_intrarg = intrarg;
@@ -436,9 +449,7 @@ pad_start_output(void *opaque, void *block, int blksize,
err = pad_add_block(sc, block, blksize);
- cv_signal(&sc->sc_condvar);
-
- mutex_exit(&sc->sc_mutex);
+ cv_broadcast(&sc->sc_condvar);
return err;
}
@@ -447,7 +458,13 @@ static int
pad_start_input(void *opaque, void *block, int blksize,
void (*intr)(void *), void *intrarg)
{
- return EINVAL;
+ pad_softc_t *sc;
+
+ sc = (pad_softc_t *)opaque;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+
+ return EOPNOTSUPP;
}
static int
@@ -456,6 +473,9 @@ pad_halt_output(void *opaque)
pad_softc_t *sc;
sc = (pad_softc_t *)opaque;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+
sc->sc_intr = NULL;
sc->sc_intrarg = NULL;
sc->sc_buflen = 0;
@@ -467,6 +487,12 @@ pad_halt_output(void *opaque)
static int
pad_halt_input(void *opaque)
{
+ pad_softc_t *sc;
+
+ sc = (pad_softc_t *)opaque;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+
return 0;
}
@@ -487,6 +513,8 @@ pad_set_port(void *opaque, mixer_ctrl_t *mc)
sc = (pad_softc_t *)opaque;
+ KASSERT(mutex_owned(&sc->sc_lock));
+
switch (mc->dev) {
case PAD_OUTPUT_MASTER_VOLUME:
case PAD_INPUT_DAC_VOLUME:
@@ -504,6 +532,8 @@ pad_get_port(void *opaque, mixer_ctrl_t *mc)
sc = (pad_softc_t *)opaque;
+ KASSERT(mutex_owned(&sc->sc_lock));
+
switch (mc->dev) {
case PAD_OUTPUT_MASTER_VOLUME:
case PAD_INPUT_DAC_VOLUME:
@@ -521,6 +551,8 @@ pad_query_devinfo(void *opaque, mixer_devinfo_t *di)
sc = (pad_softc_t *)opaque;
+ KASSERT(mutex_owned(&sc->sc_lock));
+
switch (di->index) {
case PAD_OUTPUT_CLASS:
di->mixer_class = PAD_OUTPUT_CLASS;
@@ -558,6 +590,12 @@ pad_query_devinfo(void *opaque, mixer_devinfo_t *di)
static int
pad_get_props(void *opaque)
{
+ pad_softc_t *sc;
+
+ sc = (pad_softc_t *)opaque;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+
return 0;
}
@@ -565,9 +603,25 @@ static int
pad_round_blocksize(void *opaque, int blksize, int mode,
const audio_params_t *p)
{
+ pad_softc_t *sc;
+
+ sc = (pad_softc_t *)opaque;
+ KASSERT(mutex_owned(&sc->sc_lock));
+
return PAD_BLKSIZE;
}
+static void
+pad_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread)
+{
+ pad_softc_t *sc;
+
+ sc = (pad_softc_t *)opaque;
+
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
#ifdef _MODULE
MODULE(MODULE_CLASS_DRIVER, pad, NULL);
diff --git a/sys/dev/pad/padvar.h b/sys/dev/pad/padvar.h
index 1e71d8498d4..81f9d9fee73 100644
--- a/sys/dev/pad/padvar.h
+++ b/sys/dev/pad/padvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: padvar.h,v 1.3 2008/09/04 10:42:55 christos Exp $ */
+/* $NetBSD: padvar.h,v 1.4 2011/11/23 23:07:33 jmcneill Exp $ */
/*-
* Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
@@ -32,13 +32,14 @@
typedef struct pad_softc {
device_t sc_dev;
- int sc_open;
+ u_int sc_open;
struct audio_encoding_set *sc_encodings;
void (*sc_intr)(void *);
void *sc_intrarg;
kcondvar_t sc_condvar;
- kmutex_t sc_mutex;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
struct audio_softc *sc_audiodev;
int sc_blksize;
diff --git a/sys/dev/pad/padvol.c b/sys/dev/pad/padvol.c
index 21d23923901..f55836718b6 100644
--- a/sys/dev/pad/padvol.c
+++ b/sys/dev/pad/padvol.c
@@ -1,4 +1,4 @@
-/* $NetBSD: padvol.c,v 1.5 2011/02/28 16:56:39 riz Exp $ */
+/* $NetBSD: padvol.c,v 1.6 2011/11/23 23:07:33 jmcneill Exp $ */
/*-
* Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: padvol.c,v 1.5 2011/02/28 16:56:39 riz Exp $");
+__KERNEL_RCSID(0, "$NetBSD: padvol.c,v 1.6 2011/11/23 23:07:33 jmcneill Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -57,7 +57,8 @@ pad_filter_dtor(stream_filter_t *this)
static stream_filter_t *
pad_filter_factory(struct audio_softc *sc,
- int (*fetch_to)(stream_fetcher_t *, audio_stream_t *, int))
+ int (*fetch_to)(struct audio_softc *, stream_fetcher_t *,
+ audio_stream_t *, int))
{
pad_filter_t *this;
@@ -84,7 +85,7 @@ PAD_DEFINE_FILTER(pad_vol_slinear16_le)
this = &pf->base;
max_used = (max_used + 1) & ~1;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
+ if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used)))
return err;
m = (dst->end - dst->start) & ~1;
m = min(m, max_used);
@@ -110,7 +111,7 @@ PAD_DEFINE_FILTER(pad_vol_slinear16_be)
this = &pf->base;
max_used = (max_used + 1) & ~1;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used)))
+ if ((err = this->prev->fetch_to(asc, this->prev, this->src, max_used)))
return err;
m = (dst->end - dst->start) & ~1;
m = min(m, max_used);
diff --git a/sys/dev/pad/padvol.h b/sys/dev/pad/padvol.h
index 41c236acdf8..6e317c263fa 100644
--- a/sys/dev/pad/padvol.h
+++ b/sys/dev/pad/padvol.h
@@ -1,4 +1,4 @@
-/* $NetBSD: padvol.h,v 1.2 2008/05/09 03:44:51 jmcneill Exp $ */
+/* $NetBSD: padvol.h,v 1.3 2011/11/23 23:07:33 jmcneill Exp $ */
/*-
* Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
@@ -36,17 +36,18 @@ stream_filter_t * pad_vol_slinear16_be(struct audio_softc *,
#define PAD_DEFINE_FILTER(name) \
static int \
- name##_fetch_to(stream_fetcher_t *, audio_stream_t *, int); \
+ name##_fetch_to(struct audio_softc *, stream_fetcher_t *, \
+ audio_stream_t *, int); \
stream_filter_t * name(struct audio_softc *, \
const audio_params_t *, const audio_params_t *); \
stream_filter_t * \
- name(struct audio_softc *sc, const audio_params_t *from, \
+ name(struct audio_softc *asc, const audio_params_t *from, \
const audio_params_t *to) \
{ \
- return pad_filter_factory(sc, name##_fetch_to); \
+ return pad_filter_factory(asc, name##_fetch_to); \
} \
static int \
- name##_fetch_to(stream_fetcher_t *self, audio_stream_t *dst, \
- int max_used)
+ name##_fetch_to(struct audio_softc *asc, stream_fetcher_t *self, \
+ audio_stream_t *dst, int max_used)
#endif /* !_SYS_DEV_PAD_PADVOL_H */
diff --git a/sys/dev/pci/auacer.c b/sys/dev/pci/auacer.c
index 18d02d613a7..125daacd3cd 100644
--- a/sys/dev/pci/auacer.c
+++ b/sys/dev/pci/auacer.c
@@ -1,7 +1,7 @@
-/* $NetBSD: auacer.c,v 1.28 2010/11/13 13:52:05 uebayasi Exp $ */
+/* $NetBSD: auacer.c,v 1.29 2011/11/23 23:07:33 jmcneill Exp $ */
/*-
- * Copyright (c) 2004 The NetBSD Foundation, Inc.
+ * Copyright (c) 2004, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -44,12 +44,12 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: auacer.c,v 1.28 2010/11/13 13:52:05 uebayasi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: auacer.c,v 1.29 2011/11/23 23:07:33 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
#include <sys/fcntl.h>
#include <sys/proc.h>
@@ -98,6 +98,8 @@ struct auacer_chan {
struct auacer_softc {
struct device sc_dev;
void *sc_ih;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
audio_device_t sc_audev;
@@ -163,8 +165,8 @@ static int auacer_getdev(void *, struct audio_device *);
static int auacer_set_port(void *, mixer_ctrl_t *);
static int auacer_get_port(void *, mixer_ctrl_t *);
static int auacer_query_devinfo(void *, mixer_devinfo_t *);
-static void *auacer_allocm(void *, int, size_t, struct malloc_type *, int);
-static void auacer_freem(void *, void *, struct malloc_type *);
+static void *auacer_allocm(void *, int, size_t);
+static void auacer_freem(void *, void *, size_t);
static size_t auacer_round_buffersize(void *, int, size_t);
static paddr_t auacer_mappage(void *, void *, off_t, int);
static int auacer_get_props(void *);
@@ -180,6 +182,7 @@ static int auacer_alloc_cdata(struct auacer_softc *);
static int auacer_allocmem(struct auacer_softc *, size_t, size_t,
struct auacer_dma *);
static int auacer_freemem(struct auacer_softc *, struct auacer_dma *);
+static void auacer_get_locks(void *, kmutex_t **, kmutex_t **);
static bool auacer_resume(device_t, const pmf_qual_t *);
static int auacer_set_rate(struct auacer_softc *, int, u_int);
@@ -214,7 +217,7 @@ static struct audio_hw_if auacer_hw_if = {
auacer_trigger_output,
auacer_trigger_input,
NULL, /* dev_ioctl */
- NULL, /* powerstate */
+ auacer_get_locks,
};
#define AUACER_FORMATS_4CH 1
@@ -272,6 +275,9 @@ auacer_attach(device_t parent, device_t self, void *aux)
sc->sc_dmamap_flags = BUS_DMA_COHERENT; /* XXX remove */
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
/* enable bus mastering */
v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
@@ -280,16 +286,20 @@ auacer_attach(device_t parent, device_t self, void *aux)
/* Map and establish the interrupt. */
if (pci_intr_map(pa, &ih)) {
aprint_error_dev(&sc->sc_dev, "can't map interrupt\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
intrstr = pci_intr_string(pa->pa_pc, ih);
- sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO,
+ sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_SCHED,
auacer_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(&sc->sc_dev, "can't establish interrupt");
if (intrstr != NULL)
aprint_error(" at %s", intrstr);
aprint_error("\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
aprint_normal_dev(&sc->sc_dev, "interrupting at %s\n", intrstr);
@@ -314,11 +324,15 @@ auacer_attach(device_t parent, device_t self, void *aux)
sc->host_if.write = auacer_write_codec;
sc->host_if.reset = auacer_reset_codec;
- if (ac97_attach(&sc->host_if, self) != 0)
+ if (ac97_attach(&sc->host_if, self, &sc->sc_lock) != 0) {
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
+ }
/* setup audio_format */
memcpy(sc->sc_formats, auacer_formats, sizeof(auacer_formats));
+ mutex_enter(&sc->sc_lock);
if (!AC97_IS_4CH(sc->codec_if))
AUFMT_INVALIDATE(&sc->sc_formats[AUACER_FORMATS_4CH]);
if (!AC97_IS_6CH(sc->codec_if))
@@ -329,15 +343,22 @@ auacer_attach(device_t parent, device_t self, void *aux)
sc->sc_formats[i].frequency[0] = 48000;
}
}
+ mutex_exit(&sc->sc_lock);
if (0 != auconv_create_encodings(sc->sc_formats, AUACER_NFORMATS,
&sc->sc_encodings)) {
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
- audio_attach_mi(&auacer_hw_if, sc, &sc->sc_dev);
-
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
auacer_reset(sc);
+ mutex_spin_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
+
+ audio_attach_mi(&auacer_hw_if, sc, &sc->sc_dev);
if (!pmf_device_register(self, NULL, auacer_resume))
aprint_error_dev(self, "couldn't establish power handler\n");
@@ -671,8 +692,7 @@ auacer_query_devinfo(void *v, mixer_devinfo_t *dp)
}
static void *
-auacer_allocm(void *v, int direction, size_t size,
- struct malloc_type *pool, int flags)
+auacer_allocm(void *v, int direction, size_t size)
{
struct auacer_softc *sc;
struct auacer_dma *p;
@@ -681,13 +701,13 @@ auacer_allocm(void *v, int direction, size_t size,
if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX))
return NULL;
- p = malloc(sizeof(*p), pool, flags | M_ZERO);
+ p = kmem_zalloc(sizeof(*p), KM_SLEEP);
if (p == NULL)
return NULL;
sc = v;
error = auacer_allocmem(sc, size, 0, p);
if (error) {
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return NULL;
}
@@ -698,7 +718,7 @@ auacer_allocm(void *v, int direction, size_t size,
}
static void
-auacer_freem(void *v, void *ptr, struct malloc_type *pool)
+auacer_freem(void *v, void *ptr, size_t size)
{
struct auacer_softc *sc;
struct auacer_dma *p, **pp;
@@ -708,7 +728,7 @@ auacer_freem(void *v, void *ptr, struct malloc_type *pool)
if (KERNADDR(p) == ptr) {
auacer_freemem(sc, p);
*pp = p->next;
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return;
}
}
@@ -760,6 +780,16 @@ auacer_get_props(void *v)
}
static void
+auacer_get_locks(void *v, kmutex_t **intr, kmutex_t **proc)
+{
+ struct auacer_softc *sc;
+
+ sc = v;
+ *intr = &sc->sc_intr_lock;
+ *proc = &sc->sc_lock;
+}
+
+static void
auacer_add_entry(struct auacer_chan *chan)
{
struct auacer_dmalist *q;
@@ -827,14 +857,18 @@ auacer_intr(void *v)
int ret, intrs;
sc = v;
- intrs = READ4(sc, ALI_INTERRUPTSR);
- DPRINTF(ALI_DEBUG_INTR, ("auacer_intr: intrs=0x%x\n", intrs));
+ DPRINTF(ALI_DEBUG_INTR, ("auacer_intr: intrs=0x%x\n",
+ READ4(sc, ALI_INTERRUPTSR)));
+
+ mutex_spin_enter(&sc->sc_intr_lock);
+ intrs = READ4(sc, ALI_INTERRUPTSR);
ret = 0;
if (intrs & ALI_INT_PCMOUT) {
auacer_upd_chan(sc, &sc->sc_pcmo);
ret++;
}
+ mutex_spin_exit(&sc->sc_intr_lock);
return ret != 0;
}
@@ -917,22 +951,22 @@ auacer_allocmem(struct auacer_softc *sc, size_t size, size_t align,
p->size = size;
error = bus_dmamem_alloc(sc->dmat, p->size, align, 0,
p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
- &p->nsegs, BUS_DMA_NOWAIT);
+ &p->nsegs, BUS_DMA_WAITOK);
if (error)
return error;
error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size,
- &p->addr, BUS_DMA_NOWAIT|sc->sc_dmamap_flags);
+ &p->addr, BUS_DMA_WAITOK|sc->sc_dmamap_flags);
if (error)
goto free;
error = bus_dmamap_create(sc->dmat, p->size, 1, p->size,
- 0, BUS_DMA_NOWAIT, &p->map);
+ 0, BUS_DMA_WAITOK, &p->map);
if (error)
goto unmap;
error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL,
- BUS_DMA_NOWAIT);
+ BUS_DMA_WAITOK);
if (error)
goto destroy;
return (0);
@@ -1018,9 +1052,13 @@ auacer_resume(device_t dv, const pmf_qual_t *qual)
{
struct auacer_softc *sc = device_private(dv);
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
auacer_reset_codec(sc);
+ mutex_spin_exit(&sc->sc_intr_lock);
delay(1000);
sc->codec_if->vtbl->restore_ports(sc->codec_if);
+ mutex_exit(&sc->sc_lock);
return true;
}
diff --git a/sys/dev/pci/auich.c b/sys/dev/pci/auich.c
index 911960f631f..ba002822d51 100644
--- a/sys/dev/pci/auich.c
+++ b/sys/dev/pci/auich.c
@@ -1,7 +1,7 @@
-/* $NetBSD: auich.c,v 1.138 2010/11/13 13:52:05 uebayasi Exp $ */
+/* $NetBSD: auich.c,v 1.139 2011/11/23 23:07:34 jmcneill Exp $ */
/*-
- * Copyright (c) 2000, 2004, 2005 The NetBSD Foundation, Inc.
+ * Copyright (c) 2000, 2004, 2005, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -111,28 +111,27 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: auich.c,v 1.138 2010/11/13 13:52:05 uebayasi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: auich.c,v 1.139 2011/11/23 23:07:34 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
#include <sys/fcntl.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
+#include <sys/audioio.h>
+#include <sys/bus.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/auichreg.h>
-#include <sys/audioio.h>
#include <dev/audio_if.h>
#include <dev/mulaw.h>
#include <dev/auconv.h>
-#include <sys/bus.h>
-
#include <dev/ic/ac97reg.h>
#include <dev/ic/ac97var.h>
@@ -162,6 +161,8 @@ struct auich_cdata {
struct auich_softc {
device_t sc_dev;
void *sc_ih;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
device_t sc_audiodev;
audio_device_t sc_audev;
@@ -180,6 +181,7 @@ struct auich_softc {
struct ac97_host_if host_if;
int sc_codecnum;
int sc_codectype;
+ int sc_fixedrate;
enum ac97_host_flags sc_codecflags;
bool sc_spdif;
@@ -266,8 +268,8 @@ static int auich_getdev(void *, struct audio_device *);
static int auich_set_port(void *, mixer_ctrl_t *);
static int auich_get_port(void *, mixer_ctrl_t *);
static int auich_query_devinfo(void *, mixer_devinfo_t *);
-static void *auich_allocm(void *, int, size_t, struct malloc_type *, int);
-static void auich_freem(void *, void *, struct malloc_type *);
+static void *auich_allocm(void *, int, size_t);
+static void auich_freem(void *, void *, size_t);
static size_t auich_round_buffersize(void *, int, size_t);
static paddr_t auich_mappage(void *, void *, off_t, int);
static int auich_get_props(void *);
@@ -277,7 +279,7 @@ static int auich_trigger_output(void *, void *, void *, int,
void (*)(void *), void *, const audio_params_t *);
static int auich_trigger_input(void *, void *, void *, int,
void (*)(void *), void *, const audio_params_t *);
-static int auich_powerstate(void *, int);
+static void auich_get_locks(void *, kmutex_t **, kmutex_t **);
static int auich_alloc_cdata(struct auich_softc *);
@@ -327,7 +329,7 @@ static const struct audio_hw_if auich_hw_if = {
auich_trigger_output,
auich_trigger_input,
NULL, /* dev_ioctl */
- auich_powerstate,
+ auich_get_locks,
};
#define AUICH_FORMATS_1CH 0
@@ -523,13 +525,16 @@ map_done:
pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
v | PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_BACKTOBACK_ENABLE);
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
/* Map and establish the interrupt. */
if (pci_intr_map(pa, &sc->intrh)) {
aprint_error_dev(self, "can't map interrupt\n");
return;
}
intrstr = pci_intr_string(pa->pa_pc, sc->intrh);
- sc->sc_ih = pci_intr_establish(pa->pa_pc, sc->intrh, IPL_AUDIO,
+ sc->sc_ih = pci_intr_establish(pa->pa_pc, sc->intrh, IPL_SCHED,
auich_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(self, "can't establish interrupt");
@@ -607,9 +612,13 @@ map_done:
break;
}
- if (ac97_attach_type(&sc->host_if, self, sc->sc_codectype) != 0)
+ if (ac97_attach_type(&sc->host_if, self, sc->sc_codectype,
+ &sc->sc_lock) != 0)
return;
+
+ mutex_enter(&sc->sc_lock);
sc->codec_if->vtbl->unlock(sc->codec_if);
+ sc->sc_fixedrate = AC97_IS_FIXED_RATE(sc->codec_if);
/* setup audio_format */
if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) {
@@ -624,6 +633,7 @@ map_done:
sc->sc_audio_formats[i].frequency[0] = 48000;
}
}
+ mutex_exit(&sc->sc_lock);
if (0 != auconv_create_encodings(sc->sc_audio_formats, AUICH_AUDIO_NFORMATS,
&sc->sc_encodings))
return;
@@ -631,6 +641,7 @@ map_done:
&sc->sc_spdif_encodings))
return;
} else {
+ mutex_exit(&sc->sc_lock);
memcpy(sc->sc_modem_formats, auich_modem_formats, sizeof(auich_modem_formats));
if (0 != auconv_create_encodings(sc->sc_modem_formats, AUICH_MODEM_NFORMATS,
&sc->sc_encodings))
@@ -644,8 +655,7 @@ map_done:
config_interrupts(self, auich_finish_attach);
/* sysctl setup */
- if (AC97_IS_FIXED_RATE(sc->codec_if) &&
- sc->sc_codectype == AC97_CODEC_TYPE_AUDIO)
+ if (sc->sc_fixedrate && sc->sc_codectype == AC97_CODEC_TYPE_AUDIO)
return;
err = sysctl_createv(&sc->sc_log, 0, NULL, NULL, 0,
@@ -660,7 +670,7 @@ map_done:
goto sysctl_err;
node_mib = node->sysctl_num;
- if (!AC97_IS_FIXED_RATE(sc->codec_if)) {
+ if (!sc->sc_fixedrate) {
/* passing the sc address instead of &sc->sc_ac97_clock */
err = sysctl_createv(&sc->sc_log, 0, NULL, &node_ac97clock,
CTLFLAG_READWRITE,
@@ -702,6 +712,8 @@ auich_detach(device_t self, int flags)
/* sysctl */
sysctl_teardown(&sc->sc_log);
+ mutex_enter(&sc->sc_lock);
+
/* audio_encoding_set */
auconv_delete_encodings(sc->sc_encodings);
auconv_delete_encodings(sc->sc_spdif_encodings);
@@ -710,6 +722,10 @@ auich_detach(device_t self, int flags)
if (sc->codec_if != NULL)
sc->codec_if->vtbl->detach(sc->codec_if);
+ mutex_exit(&sc->sc_lock);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
+
/* PCI */
if (sc->sc_ih != NULL)
pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
@@ -738,7 +754,9 @@ auich_sysctl_verify(SYSCTLFN_ARGS)
if (tmp < 48000 || tmp > 96000)
return EINVAL;
+ mutex_enter(&sc->sc_lock);
sc->sc_ac97_clock = tmp;
+ mutex_exit(&sc->sc_lock);
}
return 0;
@@ -749,8 +767,10 @@ auich_finish_attach(device_t self)
{
struct auich_softc *sc = device_private(self);
+ mutex_enter(&sc->sc_lock);
if (!AC97_IS_FIXED_RATE(sc->codec_if))
auich_calibrate(sc);
+ mutex_exit(&sc->sc_lock);
sc->sc_audiodev = audio_attach_mi(&auich_hw_if, sc, sc->sc_dev);
@@ -900,7 +920,9 @@ auich_open(void *addr, int flags)
struct auich_softc *sc;
sc = (struct auich_softc *)addr;
+ mutex_spin_exit(&sc->sc_intr_lock);
sc->codec_if->vtbl->lock(sc->codec_if);
+ mutex_spin_enter(&sc->sc_intr_lock);
return 0;
}
@@ -910,7 +932,9 @@ auich_close(void *addr)
struct auich_softc *sc;
sc = (struct auich_softc *)addr;
+ mutex_spin_exit(&sc->sc_intr_lock);
sc->codec_if->vtbl->unlock(sc->codec_if);
+ mutex_spin_enter(&sc->sc_intr_lock);
}
static int
@@ -1118,8 +1142,7 @@ auich_query_devinfo(void *v, mixer_devinfo_t *dp)
}
static void *
-auich_allocm(void *v, int direction, size_t size,
- struct malloc_type *pool, int flags)
+auich_allocm(void *v, int direction, size_t size)
{
struct auich_softc *sc;
struct auich_dma *p;
@@ -1128,14 +1151,14 @@ auich_allocm(void *v, int direction, size_t size,
if (size > (ICH_DMALIST_MAX * ICH_DMASEG_MAX))
return NULL;
- p = malloc(sizeof(*p), pool, flags|M_ZERO);
+ p = kmem_alloc(sizeof(*p), KM_SLEEP);
if (p == NULL)
return NULL;
sc = v;
error = auich_allocmem(sc, size, 0, p);
if (error) {
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return NULL;
}
@@ -1146,7 +1169,7 @@ auich_allocm(void *v, int direction, size_t size,
}
static void
-auich_freem(void *v, void *ptr, struct malloc_type *pool)
+auich_freem(void *v, void *ptr, size_t size)
{
struct auich_softc *sc;
struct auich_dma *p, **pp;
@@ -1156,7 +1179,7 @@ auich_freem(void *v, void *ptr, struct malloc_type *pool)
if (KERNADDR(p) == ptr) {
auich_freemem(sc, p);
*pp = p->next;
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return;
}
}
@@ -1222,6 +1245,8 @@ auich_intr(void *v)
if (!device_has_power(sc->sc_dev))
return (0);
+ mutex_spin_enter(&sc->sc_intr_lock);
+
ret = 0;
#ifdef DIAGNOSTIC
csts = pci_conf_read(sc->sc_pc, sc->sc_pt, PCI_COMMAND_STATUS_REG);
@@ -1320,6 +1345,8 @@ auich_intr(void *v)
}
#endif
+ mutex_spin_exit(&sc->sc_intr_lock);
+
return ret;
}
@@ -1454,12 +1481,6 @@ auich_trigger_input(void *v, void *start, void *end, int blksize,
}
static int
-auich_powerstate(void *v, int state)
-{
- return 0;
-}
-
-static int
auich_allocmem(struct auich_softc *sc, size_t size, size_t align,
struct auich_dma *p)
{
@@ -1468,22 +1489,22 @@ auich_allocmem(struct auich_softc *sc, size_t size, size_t align,
p->size = size;
error = bus_dmamem_alloc(sc->dmat, p->size, align, 0,
p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
- &p->nsegs, BUS_DMA_NOWAIT);
+ &p->nsegs, BUS_DMA_WAITOK);
if (error)
return error;
error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size,
- &p->addr, BUS_DMA_NOWAIT|sc->sc_dmamap_flags);
+ &p->addr, BUS_DMA_WAITOK|sc->sc_dmamap_flags);
if (error)
goto free;
error = bus_dmamap_create(sc->dmat, p->size, 1, p->size,
- 0, BUS_DMA_NOWAIT, &p->map);
+ 0, BUS_DMA_WAITOK, &p->map);
if (error)
goto unmap;
error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL,
- BUS_DMA_NOWAIT);
+ BUS_DMA_WAITOK);
if (error)
goto destroy;
return 0;
@@ -1572,6 +1593,9 @@ auich_resume(device_t dv, const pmf_qual_t *qual)
struct auich_softc *sc = device_private(dv);
pcireg_t v;
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
+
if (sc->sc_iose) {
v = pci_conf_read(sc->sc_pc, sc->sc_pt, ICH_CFG);
pci_conf_write(sc->sc_pc, sc->sc_pt, ICH_CFG,
@@ -1579,8 +1603,10 @@ auich_resume(device_t dv, const pmf_qual_t *qual)
}
auich_reset_codec(sc);
+ mutex_spin_exit(&sc->sc_intr_lock);
DELAY(1000);
(sc->codec_if->vtbl->restore_ports)(sc->codec_if);
+ mutex_exit(&sc->sc_lock);
return true;
}
@@ -1614,7 +1640,7 @@ auich_calibrate(struct auich_softc *sc)
/* Setup a buffer */
bytes = 64000;
- temp_buffer = auich_allocm(sc, AUMODE_RECORD, bytes, M_DEVBUF, M_WAITOK);
+ temp_buffer = auich_allocm(sc, AUMODE_RECORD, bytes);
for (p = sc->sc_dmas; p && KERNADDR(p) != temp_buffer; p = p->next)
continue;
@@ -1645,6 +1671,7 @@ auich_calibrate(struct auich_softc *sc)
(0 - 1) & ICH_LVI_MASK);
/* start */
+ kpreempt_disable();
microtime(&t1);
bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CTRL, ICH_RPBM);
@@ -1661,6 +1688,7 @@ auich_calibrate(struct auich_softc *sc)
/* stop */
bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CTRL, 0);
+ kpreempt_enable();
/* reset */
DELAY(100);
@@ -1669,7 +1697,7 @@ auich_calibrate(struct auich_softc *sc)
/* turn time delta into us */
wait_us = ((t2.tv_sec - t1.tv_sec) * 1000000) + t2.tv_usec - t1.tv_usec;
- auich_freem(sc, temp_buffer, M_DEVBUF);
+ auich_freem(sc, temp_buffer, bytes);
if (nciv == ociv) {
printf("%s: ac97 link rate calibration timed out after %"
@@ -1702,3 +1730,13 @@ auich_clear_cas(struct auich_softc *sc)
return;
}
+
+static void
+auich_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct auich_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
diff --git a/sys/dev/pci/auixp.c b/sys/dev/pci/auixp.c
index 132cf8fe2c7..d7f875ea55a 100644
--- a/sys/dev/pci/auixp.c
+++ b/sys/dev/pci/auixp.c
@@ -1,4 +1,4 @@
-/* $NetBSD: auixp.c,v 1.34 2010/02/24 22:37:59 dyoung Exp $ */
+/* $NetBSD: auixp.c,v 1.35 2011/11/23 23:07:34 jmcneill Exp $ */
/*
* Copyright (c) 2004, 2005 Reinoud Zandijk <reinoud@netbsd.org>
@@ -50,33 +50,32 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: auixp.c,v 1.34 2010/02/24 22:37:59 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: auixp.c,v 1.35 2011/11/23 23:07:34 jmcneill Exp $");
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/null.h>
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
#include <sys/conf.h>
#include <sys/exec.h>
#include <sys/select.h>
#include <sys/audioio.h>
#include <sys/queue.h>
-
#include <sys/bus.h>
#include <sys/intr.h>
-#include <dev/pci/pcidevs.h>
-#include <dev/pci/pcivar.h>
-
#include <dev/audio_if.h>
#include <dev/mulaw.h>
#include <dev/auconv.h>
+
#include <dev/ic/ac97var.h>
#include <dev/ic/ac97reg.h>
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcivar.h>
#include <dev/pci/auixpreg.h>
#include <dev/pci/auixpvar.h>
@@ -153,8 +152,8 @@ static int auixp_halt_input(void *);
static int auixp_set_port(void *, mixer_ctrl_t *);
static int auixp_get_port(void *, mixer_ctrl_t *);
static int auixp_query_devinfo(void *, mixer_devinfo_t *);
-static void * auixp_malloc(void *, int, size_t, struct malloc_type *, int);
-static void auixp_free(void *, void *, struct malloc_type *);
+static void * auixp_malloc(void *, int, size_t);
+static void auixp_free(void *, void *, size_t);
static int auixp_getdev(void *, struct audio_device *);
static size_t auixp_round_buffersize(void *, int, size_t);
static int auixp_get_props(void *);
@@ -193,6 +192,7 @@ static void auixp_program_dma_chain(struct auixp_softc *,
struct auixp_dma *);
static void auixp_dma_update(struct auixp_softc *, struct auixp_dma *);
static void auixp_update_busbusy(struct auixp_softc *);
+static void auixp_get_locks(void *, kmutex_t **, kmutex_t **);
static bool auixp_resume(device_t, const pmf_qual_t *);
@@ -234,7 +234,7 @@ static const struct audio_hw_if auixp_hw_if = {
auixp_trigger_output,
auixp_trigger_input,
NULL, /* dev_ioctl */
- NULL, /* powerstate */
+ auixp_get_locks,
};
@@ -459,8 +459,7 @@ auixp_round_blocksize(void *hdl, int bs, int mode,
* kernel virtual address we return here as a reference to the mapping.
*/
static void *
-auixp_malloc(void *hdl, int direction, size_t size,
- struct malloc_type *type, int flags)
+auixp_malloc(void *hdl, int direction, size_t size)
{
struct auixp_codec *co;
struct auixp_softc *sc;
@@ -470,14 +469,14 @@ auixp_malloc(void *hdl, int direction, size_t size,
co = (struct auixp_codec *) hdl;
sc = co->sc;
/* get us a auixp_dma structure */
- dma = malloc(sizeof(*dma), type, flags);
+ dma = kmem_alloc(sizeof(*dma), KM_SLEEP);
if (!dma)
return NULL;
/* get us a dma buffer itself */
error = auixp_allocmem(sc, size, 16, dma);
if (error) {
- free(dma, type);
+ kmem_free(dma, sizeof(*dma));
aprint_error_dev(&sc->sc_dev, "auixp_malloc: not enough memory\n");
return NULL;
@@ -498,7 +497,7 @@ auixp_malloc(void *hdl, int direction, size_t size,
* recording
*/
static void
-auixp_free(void *hdl, void *addr, struct malloc_type *type)
+auixp_free(void *hdl, void *addr, size_t size)
{
struct auixp_codec *co;
struct auixp_softc *sc;
@@ -511,7 +510,7 @@ auixp_free(void *hdl, void *addr, struct malloc_type *type)
SLIST_REMOVE(&sc->sc_dma_list, dma, auixp_dma,
dma_chain);
auixp_freemem(sc, dma);
- free(dma, type);
+ kmem_free(dma, sizeof(*dma));
return;
}
}
@@ -644,7 +643,7 @@ auixp_allocate_dma_chain(struct auixp_softc *sc, struct auixp_dma **dmap)
/* allocate keeper of dma area */
*dmap = NULL;
- dma = malloc(sizeof(struct auixp_dma), M_DEVBUF, M_NOWAIT | M_ZERO);
+ dma = kmem_zalloc(sizeof(struct auixp_dma), KM_SLEEP);
if (!dma)
return ENOMEM;
@@ -653,7 +652,7 @@ auixp_allocate_dma_chain(struct auixp_softc *sc, struct auixp_dma **dmap)
16, dma);
if (error) {
aprint_error_dev(&sc->sc_dev, "can't malloc dma descriptor chain\n");
- free(dma, M_DEVBUF);
+ kmem_free(dma, sizeof(*dma));
return ENOMEM;
}
@@ -909,14 +908,18 @@ auixp_intr(void *softc)
int ret;
sc = softc;
+ mutex_spin_enter(&sc->sc_intr_lock);
+
iot = sc->sc_iot;
ioh = sc->sc_ioh;
ret = 0;
/* get status from the interrupt status register */
status = bus_space_read_4(iot, ioh, ATI_REG_ISR);
- if (status == 0)
+ if (status == 0) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
+ }
DPRINTF(("%s: (status = %x)\n", device_xname(&sc->sc_dev), status));
@@ -957,6 +960,7 @@ auixp_intr(void *softc)
/* acknowledge interrupt sources */
bus_space_write_4(iot, ioh, ATI_REG_ISR, status);
+ mutex_spin_exit(&sc->sc_intr_lock);
return ret;
}
@@ -974,7 +978,7 @@ auixp_allocmem(struct auixp_softc *sc, size_t size,
/* allocate DMA safe memory but in just one segment for now :( */
error = bus_dmamem_alloc(sc->sc_dmat, dma->size, align, 0,
dma->segs, sizeof(dma->segs) / sizeof(dma->segs[0]), &dma->nsegs,
- BUS_DMA_NOWAIT);
+ BUS_DMA_WAITOK);
if (error)
return error;
@@ -983,13 +987,13 @@ auixp_allocmem(struct auixp_softc *sc, size_t size,
* coherent with the CPU.
*/
error = bus_dmamem_map(sc->sc_dmat, dma->segs, dma->nsegs, dma->size,
- &dma->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
+ &dma->addr, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
if (error)
goto free;
/* allocate associated dma handle and initialize it. */
error = bus_dmamap_create(sc->sc_dmat, dma->size, 1, dma->size, 0,
- BUS_DMA_NOWAIT, &dma->map);
+ BUS_DMA_WAITOK, &dma->map);
if (error)
goto unmap;
@@ -998,7 +1002,7 @@ auixp_allocmem(struct auixp_softc *sc, size_t size,
* need to be wired.
*/
error = bus_dmamap_load(sc->sc_dmat, dma->map, dma->addr, dma->size, NULL,
- BUS_DMA_NOWAIT);
+ BUS_DMA_WAITOK);
if (error)
goto destroy;
@@ -1164,8 +1168,11 @@ auixp_attach(device_t parent, device_t self, void *aux)
/* where are we connected at ? */
intrstr = pci_intr_string(pc, ih);
- /* establish interrupt routine hookup at IPL_AUDIO level */
- sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, auixp_intr, self);
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
+ /* establish interrupt routine hookup at IPL_SCHED level */
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_SCHED, auixp_intr, self);
if (sc->sc_ih == NULL) {
aprint_error_dev(&sc->sc_dev, "can't establish interrupt");
if (intrstr != NULL)
@@ -1225,10 +1232,12 @@ auixp_post_config(device_t self)
/* copy formats and invalidate entries not suitable for codec0 */
memcpy(sc->sc_formats, auixp_formats, sizeof(auixp_formats));
+ mutex_enter(&sc->sc_lock);
sc->has_4ch = AC97_IS_4CH(codec->codec_if);
sc->has_6ch = AC97_IS_6CH(codec->codec_if);
sc->is_fixed = AC97_IS_FIXED_RATE(codec->codec_if);
sc->has_spdif = AC97_HAS_SPDIF(codec->codec_if);
+ mutex_exit(&sc->sc_lock);
for (i = 0; i < AUIXP_NFORMATS; i++) {
if (sc->is_fixed) {
@@ -1262,14 +1271,6 @@ auixp_post_config(device_t self)
return;
}
- /* attach audio devices for all detected codecs */
- /* XXX wise? look at other multiple-codec able chipsets XXX */
- for (codec_nr = 0; codec_nr < ATI_IXP_CODECS; codec_nr++) {
- codec = &sc->sc_codec[codec_nr];
- if (codec->present)
- audio_attach_mi(&auixp_hw_if, codec, &sc->sc_dev);
- }
-
if (sc->has_spdif) {
aprint_normal_dev(&sc->sc_dev, "codec spdif support detected but disabled "
"for now\n");
@@ -1290,11 +1291,18 @@ auixp_post_config(device_t self)
sc->sc_input_dma->dma_enable_bit = ATI_REG_CMD_IN_DMA_EN |
ATI_REG_CMD_RECEIVE_EN;
+ /* attach audio devices for all detected codecs */
+ /* XXX wise? look at other multiple-codec able chipsets XXX */
+ for (codec_nr = 0; codec_nr < ATI_IXP_CODECS; codec_nr++) {
+ codec = &sc->sc_codec[codec_nr];
+ if (codec->present)
+ audio_attach_mi(&auixp_hw_if, codec, &sc->sc_dev);
+ }
+
/* done! now enable all interrupts we can service */
auixp_enable_interrupts(sc);
}
-
static void
auixp_enable_interrupts(struct auixp_softc *sc)
{
@@ -1304,6 +1312,9 @@ auixp_enable_interrupts(struct auixp_softc *sc)
iot = sc->sc_iot;
ioh = sc->sc_ioh;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
+
/* clear all pending */
bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff);
@@ -1320,6 +1331,8 @@ auixp_enable_interrupts(struct auixp_softc *sc)
#endif
bus_space_write_4(iot, ioh, ATI_REG_IER, value);
+
+ mutex_spin_exit(&sc->sc_intr_lock);
}
@@ -1331,11 +1344,16 @@ auixp_disable_interrupts(struct auixp_softc *sc)
iot = sc->sc_iot;
ioh = sc->sc_ioh;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
+
/* disable all interrupt sources */
bus_space_write_4(iot, ioh, ATI_REG_IER, 0);
/* clear all pending */
bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff);
+
+ mutex_spin_exit(&sc->sc_intr_lock);
}
@@ -1355,13 +1373,15 @@ auixp_detach(device_t self, int flags)
/* tear down .... */
config_detach(&sc->sc_dev, flags); /* XXX OK? XXX */
+ pmf_device_deregister(self);
if (sc->sc_ih != NULL)
pci_intr_disestablish(sc->sc_pct, sc->sc_ih);
if (sc->sc_ios)
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
- pmf_device_deregister(self);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return 0;
}
@@ -1570,21 +1590,24 @@ auixp_autodetect_codecs(struct auixp_softc *sc)
if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC0_NOT_READY)) {
/* codec 0 present */
DPRINTF(("auixp : YAY! codec 0 present!\n"));
- if (ac97_attach(&sc->sc_codec[0].host_if, &sc->sc_dev) == 0)
+ if (ac97_attach(&sc->sc_codec[0].host_if, &sc->sc_dev,
+ &sc->sc_lock) == 0)
sc->sc_num_codecs++;
}
if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC1_NOT_READY)) {
/* codec 1 present */
DPRINTF(("auixp : YAY! codec 1 present!\n"));
- if (ac97_attach(&sc->sc_codec[1].host_if, &sc->sc_dev) == 0)
+ if (ac97_attach(&sc->sc_codec[1].host_if, &sc->sc_dev,
+ &sc->sc_lock) == 0)
sc->sc_num_codecs++;
}
if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC2_NOT_READY)) {
/* codec 2 present */
DPRINTF(("auixp : YAY! codec 2 present!\n"));
- if (ac97_attach(&sc->sc_codec[2].host_if, &sc->sc_dev) == 0)
+ if (ac97_attach(&sc->sc_codec[2].host_if, &sc->sc_dev,
+ &sc->sc_lock) == 0)
sc->sc_num_codecs++;
}
@@ -1757,9 +1780,11 @@ auixp_resume(device_t dv, const pmf_qual_t *qual)
{
struct auixp_softc *sc = device_private(dv);
+ mutex_enter(&sc->sc_lock);
auixp_reset_codec(sc);
delay(1000);
(sc->sc_codec[0].codec_if->vtbl->restore_ports)(sc->sc_codec[0].codec_if);
+ mutex_exit(&sc->sc_lock);
return true;
}
@@ -1784,3 +1809,13 @@ auixp_dumpreg(void)
printf("\n");
}
#endif
+
+static void
+auixp_get_locks(void *addr, kmutex_t **intr, kmutex_t **proc)
+{
+ struct auixp_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *proc = &sc->sc_lock;
+}
diff --git a/sys/dev/pci/auixpvar.h b/sys/dev/pci/auixpvar.h
index 8ab76770088..845d2ce87ae 100644
--- a/sys/dev/pci/auixpvar.h
+++ b/sys/dev/pci/auixpvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: auixpvar.h,v 1.6 2007/12/09 20:28:06 jmcneill Exp $*/
+/* $NetBSD: auixpvar.h,v 1.7 2011/11/23 23:07:34 jmcneill Exp $*/
/*
* Copyright (c) 2004, 2005 Reinoud Zandijk <reinoud@netbsd.org>
@@ -97,6 +97,8 @@ struct auixp_codec {
struct auixp_softc {
struct device sc_dev;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
/* card id */
int type;
diff --git a/sys/dev/pci/autri.c b/sys/dev/pci/autri.c
index 5a3043c9beb..962131d06a2 100644
--- a/sys/dev/pci/autri.c
+++ b/sys/dev/pci/autri.c
@@ -1,4 +1,4 @@
-/* $NetBSD: autri.c,v 1.46 2010/02/24 22:37:59 dyoung Exp $ */
+/* $NetBSD: autri.c,v 1.47 2011/11/23 23:07:34 jmcneill Exp $ */
/*
* Copyright (c) 2001 SOMEYA Yoshihiko and KUROSAWA Takahiro.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: autri.c,v 1.46 2010/02/24 22:37:59 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: autri.c,v 1.47 2011/11/23 23:07:34 jmcneill Exp $");
#include "midi.h"
@@ -43,26 +43,25 @@ __KERNEL_RCSID(0, "$NetBSD: autri.c,v 1.46 2010/02/24 22:37:59 dyoung Exp $");
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/fcntl.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
#include <sys/proc.h>
-
-#include <dev/pci/pcidevs.h>
-#include <dev/pci/pcireg.h>
-#include <dev/pci/pcivar.h>
-
#include <sys/audioio.h>
+#include <sys/bus.h>
+#include <sys/intr.h>
+
#include <dev/audio_if.h>
#include <dev/midi_if.h>
#include <dev/mulaw.h>
#include <dev/auconv.h>
+
#include <dev/ic/ac97reg.h>
#include <dev/ic/ac97var.h>
#include <dev/ic/mpuvar.h>
-#include <sys/bus.h>
-#include <sys/intr.h>
-
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
#include <dev/pci/autrireg.h>
#include <dev/pci/autrivar.h>
@@ -128,12 +127,13 @@ static int autri_halt_input(void *);
static int autri_getdev(void *, struct audio_device *);
static int autri_mixer_set_port(void *, mixer_ctrl_t *);
static int autri_mixer_get_port(void *, mixer_ctrl_t *);
-static void* autri_malloc(void *, int, size_t, struct malloc_type *, int);
-static void autri_free(void *, void *, struct malloc_type *);
+static void* autri_malloc(void *, int, size_t);
+static void autri_free(void *, void *, size_t);
static size_t autri_round_buffersize(void *, int, size_t);
static paddr_t autri_mappage(void *, void *, off_t, int);
static int autri_get_props(void *);
static int autri_query_devinfo(void *, mixer_devinfo_t *);
+static void autri_get_locks(void *, kmutex_t **, kmutex_t **);
static const struct audio_hw_if autri_hw_if = {
autri_open,
@@ -163,7 +163,7 @@ static const struct audio_hw_if autri_hw_if = {
autri_trigger_output,
autri_trigger_input,
NULL, /* dev_ioctl */
- NULL, /* powerstate */
+ autri_get_locks,
};
#if NMIDI > 0
@@ -179,6 +179,7 @@ static const struct midi_hw_if autri_midi_hw_if = {
autri_midi_output,
autri_midi_getinfo,
NULL, /* ioctl */
+ autri_get_locks,
};
#endif
@@ -542,13 +543,16 @@ autri_attach(device_t parent, device_t self, void *aux)
return;
}
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
/* map and establish the interrupt */
if (pci_intr_map(pa, &ih)) {
aprint_error_dev(&sc->sc_dev, "couldn't map interrupt\n");
return;
}
intrstr = pci_intr_string(pc, ih);
- sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, autri_intr, sc);
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_SCHED, autri_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(&sc->sc_dev, "couldn't establish interrupt");
if (intrstr != NULL)
@@ -582,7 +586,8 @@ autri_attach(device_t parent, device_t self, void *aux)
codec->host_if.write = autri_write_codec;
codec->host_if.flags = autri_flags_codec;
- if ((r = ac97_attach(&codec->host_if, self)) != 0) {
+ r = ac97_attach(&codec->host_if, self, &sc->sc_lock);
+ if (r != 0) {
aprint_error_dev(&sc->sc_dev, "can't attach codec (error 0x%X)\n", r);
return;
}
@@ -605,8 +610,12 @@ autri_resume(device_t dv, const pmf_qual_t *qual)
{
struct autri_softc *sc = device_private(dv);
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
autri_init(sc);
+ mutex_spin_exit(&sc->sc_intr_lock);
(sc->sc_codec.codec_if->vtbl->restore_ports)(sc->sc_codec.codec_if);
+ mutex_exit(&sc->sc_lock);
return true;
}
@@ -772,9 +781,13 @@ autri_intr(void *p)
u_int32_t cso,eso;
*/
sc = p;
+ mutex_spin_enter(&sc->sc_intr_lock);
+
intsrc = TREAD4(sc, AUTRI_MISCINT);
- if ((intsrc & (ADDRESS_IRQ | MPU401_IRQ)) == 0)
+ if ((intsrc & (ADDRESS_IRQ | MPU401_IRQ)) == 0) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
+ }
if (intsrc & ADDRESS_IRQ) {
@@ -831,6 +844,7 @@ autri_intr(void *p)
autri_reg_set_4(sc,AUTRI_MISCINT,
ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW);
+ mutex_spin_exit(&sc->sc_intr_lock);
return 1;
}
@@ -847,22 +861,22 @@ autri_allocmem(struct autri_softc *sc, size_t size, size_t align,
p->size = size;
error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
- &p->nsegs, BUS_DMA_NOWAIT);
+ &p->nsegs, BUS_DMA_WAITOK);
if (error)
return error;
error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
- &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
+ &p->addr, BUS_DMA_WAITOK|BUS_DMA_COHERENT);
if (error)
goto free;
error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
- 0, BUS_DMA_NOWAIT, &p->map);
+ 0, BUS_DMA_WAITOK, &p->map);
if (error)
goto unmap;
error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL,
- BUS_DMA_NOWAIT);
+ BUS_DMA_WAITOK);
if (error)
goto destroy;
return (0);
@@ -1073,14 +1087,13 @@ autri_query_devinfo(void *addr, mixer_devinfo_t *dip)
}
static void *
-autri_malloc(void *addr, int direction, size_t size,
- struct malloc_type *pool, int flags)
+autri_malloc(void *addr, int direction, size_t size)
{
struct autri_softc *sc;
struct autri_dma *p;
int error;
- p = malloc(sizeof(*p), pool, flags);
+ p = kmem_alloc(sizeof(*p), KM_SLEEP);
if (!p)
return NULL;
sc = addr;
@@ -1089,7 +1102,7 @@ autri_malloc(void *addr, int direction, size_t size,
#endif
error = autri_allocmem(sc, size, 0x10000, p);
if (error) {
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return NULL;
}
@@ -1099,7 +1112,7 @@ autri_malloc(void *addr, int direction, size_t size,
}
static void
-autri_free(void *addr, void *ptr, struct malloc_type *pool)
+autri_free(void *addr, void *ptr, size_t size)
{
struct autri_softc *sc;
struct autri_dma **pp, *p;
@@ -1109,7 +1122,7 @@ autri_free(void *addr, void *ptr, struct malloc_type *pool)
if (KERNADDR(p) == ptr) {
autri_freemem(sc, p);
*pp = p->next;
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return;
}
}
@@ -1378,6 +1391,17 @@ autri_trigger_input(void *addr, void *start, void *end, int blksize,
return 0;
}
+
+static void
+autri_get_locks(void *addr, kmutex_t **intr, kmutex_t **proc)
+{
+ struct autri_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *proc = &sc->sc_lock;
+}
+
#if 0
static int
autri_halt(struct autri_softc *sc)
@@ -1473,7 +1497,7 @@ autri_midi_close(void *addr)
DPRINTF(("autri_midi_close()\n"));
sc = addr;
- tsleep(sc, PWAIT, "autri", hz/10); /* give uart a chance to drain */
+ kpause("autri", FALSE, hz/10, &sc->sc_lock); /* give uart a chance to drain */
sc->sc_iintr = NULL;
sc->sc_ointr = NULL;
diff --git a/sys/dev/pci/autrivar.h b/sys/dev/pci/autrivar.h
index 3ea4da811c1..7fa31badb16 100644
--- a/sys/dev/pci/autrivar.h
+++ b/sys/dev/pci/autrivar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: autrivar.h,v 1.4 2007/12/09 20:28:06 jmcneill Exp $ */
+/* $NetBSD: autrivar.h,v 1.5 2011/11/23 23:07:34 jmcneill Exp $ */
/*
* Copyright (c) 2001 SOMEYA Yoshihiko and KUROSAWA Takahiro.
@@ -69,6 +69,8 @@ struct autri_chstatus {
struct autri_softc {
struct device sc_dev; /* base device */
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
pci_chipset_tag_t sc_pc;
pcitag_t sc_pt;
pcireg_t sc_devid;
diff --git a/sys/dev/pci/auvia.c b/sys/dev/pci/auvia.c
index c146b8e2c29..3f709c72f23 100644
--- a/sys/dev/pci/auvia.c
+++ b/sys/dev/pci/auvia.c
@@ -1,11 +1,11 @@
-/* $NetBSD: auvia.c,v 1.73 2010/11/13 13:52:05 uebayasi Exp $ */
+/* $NetBSD: auvia.c,v 1.74 2011/11/23 23:07:34 jmcneill Exp $ */
/*-
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * Copyright (c) 2000, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Tyler C. Sarna
+ * by Tyler C. Sarna.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -40,11 +40,11 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: auvia.c,v 1.73 2010/11/13 13:52:05 uebayasi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: auvia.c,v 1.74 2011/11/23 23:07:34 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
#include <sys/audioio.h>
@@ -60,6 +60,8 @@ __KERNEL_RCSID(0, "$NetBSD: auvia.c,v 1.73 2010/11/13 13:52:05 uebayasi Exp $");
#include <dev/pci/auviavar.h>
+#define AUVIA_MINBLKSZ 512
+
struct auvia_dma {
struct auvia_dma *next;
void *addr;
@@ -97,8 +99,8 @@ static int auvia_getdev(void *, struct audio_device *);
static int auvia_set_port(void *, mixer_ctrl_t *);
static int auvia_get_port(void *, mixer_ctrl_t *);
static int auvia_query_devinfo(void *, mixer_devinfo_t *);
-static void * auvia_malloc(void *, int, size_t, struct malloc_type *, int);
-static void auvia_free(void *, void *, struct malloc_type *);
+static void * auvia_malloc(void *, int, size_t);
+static void auvia_free(void *, void *, size_t);
static size_t auvia_round_buffersize(void *, int, size_t);
static paddr_t auvia_mappage(void *, void *, off_t, int);
static int auvia_get_props(void *);
@@ -111,9 +113,13 @@ static int auvia_trigger_output(void *, void *, void *, int,
static int auvia_trigger_input(void *, void *, void *, int,
void (*)(void *), void *,
const audio_params_t *);
+static void auvia_get_locks(void *, kmutex_t **, kmutex_t **);
static bool auvia_resume(device_t, const pmf_qual_t *);
-static int auvia_intr(void *);
+static int auvia_intr(void *);
+static void * auvia_malloc_dmamem(void *, int, size_t);
+static int auvia_malloc_channel(struct auvia_softc *, struct auvia_softc_chan *,
+ size_t);
static int auvia_attach_codec(void *, struct ac97_codec_if *);
static int auvia_write_codec(void *, uint8_t, uint16_t);
static int auvia_read_codec(void *, uint8_t, uint16_t *);
@@ -231,7 +237,7 @@ static const struct audio_hw_if auvia_hw_if = {
auvia_trigger_output,
auvia_trigger_input,
NULL, /* dev_ioctl */
- NULL, /* powerstate */
+ auvia_get_locks,
};
#define AUVIA_FORMATS_4CH_16 2
@@ -297,21 +303,32 @@ auvia_detach(device_t self, int flags)
if ((rc = config_detach_children(self, flags)) != 0)
return rc;
-
pmf_device_deregister(self);
+ mutex_enter(&sc->sc_lock);
auconv_delete_encodings(sc->sc_encodings);
auconv_delete_encodings(sc->sc_spdif_encodings);
-
if (sc->codec_if != NULL)
sc->codec_if->vtbl->detach(sc->codec_if);
+ mutex_exit(&sc->sc_lock);
/* XXX restore compatibility? */
-
if (sc->sc_ih != NULL)
pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
+ if (sc->sc_play.sc_dma_ops != NULL) {
+ auvia_free(sc, sc->sc_play.sc_dma_ops,
+ sc->sc_play.sc_dma_op_count *
+ sizeof(struct auvia_dma_op));
+ }
+ if (sc->sc_record.sc_dma_ops != NULL) {
+ auvia_free(sc, sc->sc_record.sc_dma_ops,
+ sc->sc_play.sc_dma_op_count *
+ sizeof(struct auvia_dma_op));
+ }
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return 0;
}
@@ -408,13 +425,18 @@ auvia_attach(device_t parent, device_t self, void *aux)
}
intrstr = pci_intr_string(pc, ih);
- sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, auvia_intr, sc);
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_SCHED, auvia_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(sc->sc_dev, "couldn't establish interrupt");
if (intrstr != NULL)
aprint_error(" at %s", intrstr);
aprint_error("\n");
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
@@ -440,15 +462,18 @@ auvia_attach(device_t parent, device_t self, void *aux)
sc->host_if.reset = auvia_reset_codec;
sc->host_if.spdif_event = auvia_spdif_event;
- if ((r = ac97_attach(&sc->host_if, self)) != 0) {
+ if ((r = ac97_attach(&sc->host_if, self, &sc->sc_lock)) != 0) {
aprint_error_dev(sc->sc_dev, "can't attach codec (error 0x%X)\n", r);
pci_intr_disestablish(pc, sc->sc_ih);
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
/* setup audio_format */
memcpy(sc->sc_formats, auvia_formats, sizeof(auvia_formats));
+ mutex_enter(&sc->sc_lock);
if (sc->sc_play.sc_base != VIA8233_MP_BASE || !AC97_IS_4CH(sc->codec_if)) {
AUFMT_INVALIDATE(&sc->sc_formats[AUVIA_FORMATS_4CH_8]);
AUFMT_INVALIDATE(&sc->sc_formats[AUVIA_FORMATS_4CH_16]);
@@ -463,20 +488,29 @@ auvia_attach(device_t parent, device_t self, void *aux)
sc->sc_formats[r].frequency[0] = 48000;
}
}
+ mutex_exit(&sc->sc_lock);
if (0 != auconv_create_encodings(sc->sc_formats, AUVIA_NFORMATS,
&sc->sc_encodings)) {
+ mutex_enter(&sc->sc_lock);
sc->codec_if->vtbl->detach(sc->codec_if);
+ mutex_exit(&sc->sc_lock);
pci_intr_disestablish(pc, sc->sc_ih);
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
aprint_error_dev(sc->sc_dev, "can't create encodings\n");
return;
}
if (0 != auconv_create_encodings(auvia_spdif_formats,
AUVIA_SPDIF_NFORMATS, &sc->sc_spdif_encodings)) {
+ mutex_enter(&sc->sc_lock);
sc->codec_if->vtbl->detach(sc->codec_if);
+ mutex_exit(&sc->sc_lock);
pci_intr_disestablish(pc, sc->sc_ih);
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
aprint_error_dev(sc->sc_dev, "can't create spdif encodings\n");
return;
}
@@ -485,7 +519,9 @@ auvia_attach(device_t parent, device_t self, void *aux)
aprint_error_dev(self, "couldn't establish power handler\n");
audio_attach_mi(&auvia_hw_if, sc, sc->sc_dev);
+ mutex_enter(&sc->sc_lock);
sc->codec_if->vtbl->unlock(sc->codec_if);
+ mutex_exit(&sc->sc_lock);
return;
}
@@ -615,7 +651,9 @@ auvia_open(void *addr, int flags)
struct auvia_softc *sc;
sc = (struct auvia_softc *)addr;
+ mutex_spin_exit(&sc->sc_intr_lock);
sc->codec_if->vtbl->lock(sc->codec_if);
+ mutex_spin_enter(&sc->sc_intr_lock);
return 0;
}
@@ -625,7 +663,9 @@ auvia_close(void *addr)
struct auvia_softc *sc;
sc = (struct auvia_softc *)addr;
+ mutex_spin_exit(&sc->sc_intr_lock);
sc->codec_if->vtbl->unlock(sc->codec_if);
+ mutex_spin_enter(&sc->sc_intr_lock);
}
static int
@@ -751,11 +791,13 @@ auvia_round_blocksize(void *addr, int blk,
struct auvia_softc *sc;
sc = addr;
+
/* XXX VT823x might have the limitation of dma_ops size */
if (sc->sc_flags & AUVIA_FLAGS_VT8233 && blk < 288)
blk = 288;
- return (blk & -32);
+ /* Avoid too many dma_ops. */
+ return min((blk & -32), AUVIA_MINBLKSZ);
}
static int
@@ -832,42 +874,83 @@ auvia_query_devinfo(void *addr, mixer_devinfo_t *dip)
return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip);
}
+static int
+auvia_malloc_channel(struct auvia_softc *sc, struct auvia_softc_chan *ch,
+ size_t size)
+{
+ struct auvia_dma *dp;
+ int segs;
+
+ /* if old list is large enough, nothing to do */
+ segs = (size + AUVIA_MINBLKSZ - 1) / AUVIA_MINBLKSZ;
+ if (segs <= ch->sc_dma_op_count) {
+ return 0;
+ }
+
+ if (ch->sc_dma_ops) {
+ auvia_free(sc, ch->sc_dma_ops,
+ ch->sc_dma_op_count * sizeof(*dp));
+ }
+
+ ch->sc_dma_ops = auvia_malloc_dmamem(sc, 0,
+ sizeof(struct auvia_dma_op) * segs);
+
+ if (ch->sc_dma_ops == NULL) {
+ aprint_error_dev(sc->sc_dev, "couldn't build dmaops\n");
+ return ENOMEM;
+ }
+
+ for (dp = sc->sc_dmas;
+ dp && dp->addr != (void *)(ch->sc_dma_ops);
+ dp = dp->next)
+ continue;
+
+ if (!dp)
+ panic("%s: build_dma_ops: where'd my memory go??? "
+ "address (%p)\n", device_xname(sc->sc_dev),
+ ch->sc_dma_ops);
+
+ ch->sc_dma_op_count = segs;
+ ch->sc_dma_ops_dma = dp;
+
+ return 0;
+}
+
static void *
-auvia_malloc(void *addr, int direction, size_t size,
- struct malloc_type * pool, int flags)
+auvia_malloc_dmamem(void *addr, int direction, size_t size)
{
struct auvia_softc *sc;
struct auvia_dma *p;
int error;
int rseg;
- p = malloc(sizeof(*p), pool, flags);
- if (!p)
- return 0;
+ p = kmem_alloc(sizeof(*p), KM_SLEEP);
+ if (p == NULL)
+ return NULL;
sc = addr;
p->size = size;
if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &p->seg,
- 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
+ 1, &rseg, BUS_DMA_WAITOK)) != 0) {
aprint_error_dev(sc->sc_dev, "unable to allocate DMA, error = %d\n", error);
goto fail_alloc;
}
if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
- BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
+ BUS_DMA_WAITOK | BUS_DMA_COHERENT)) != 0) {
aprint_error_dev(sc->sc_dev, "unable to map DMA, error = %d\n",
error);
goto fail_map;
}
if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
- BUS_DMA_NOWAIT, &p->map)) != 0) {
+ BUS_DMA_WAITOK, &p->map)) != 0) {
aprint_error_dev(sc->sc_dev, "unable to create DMA map, error = %d\n",
error);
goto fail_create;
}
if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
- BUS_DMA_NOWAIT)) != 0) {
+ BUS_DMA_WAITOK)) != 0) {
aprint_error_dev(sc->sc_dev, "unable to load DMA map, error = %d\n",
error);
goto fail_load;
@@ -878,7 +961,6 @@ auvia_malloc(void *addr, int direction, size_t size,
return p->addr;
-
fail_load:
bus_dmamap_destroy(sc->sc_dmat, p->map);
fail_create:
@@ -886,12 +968,35 @@ fail_create:
fail_map:
bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
fail_alloc:
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return NULL;
}
+static void *
+auvia_malloc(void *addr, int direction, size_t size)
+{
+ struct auvia_softc *sc;
+ void *p;
+
+ sc = addr;
+
+ p = auvia_malloc_dmamem(addr, direction, size);
+ if (p == NULL) {
+ return NULL;
+ }
+ if (auvia_malloc_channel(sc, &sc->sc_play, size) != 0) {
+ auvia_free(addr, p, size);
+ return NULL;
+ }
+ if (auvia_malloc_channel(sc, &sc->sc_record, size) != 0) {
+ auvia_free(addr, p, size);
+ return NULL;
+ }
+ return p;
+}
+
static void
-auvia_free(void *addr, void *ptr, struct malloc_type *pool)
+auvia_free(void *addr, void *ptr, size_t size)
{
struct auvia_softc *sc;
struct auvia_dma **pp, *p;
@@ -905,7 +1010,7 @@ auvia_free(void *addr, void *ptr, struct malloc_type *pool)
bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
*pp = p->next;
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return;
}
@@ -956,6 +1061,16 @@ auvia_get_props(void *addr)
return props;
}
+static void
+auvia_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct auvia_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
static int
auvia_build_dma_ops(struct auvia_softc *sc, struct auvia_softc_chan *ch,
struct auvia_dma *p, void *start, void *end, int blksize)
@@ -964,42 +1079,11 @@ auvia_build_dma_ops(struct auvia_softc *sc, struct auvia_softc_chan *ch,
struct auvia_dma *dp;
bus_addr_t s;
size_t l;
- int segs;
-
- s = p->map->dm_segs[0].ds_addr;
- l = ((char *)end - (char *)start);
- segs = (l + blksize - 1) / blksize;
-
- if (segs > (ch->sc_dma_op_count)) {
- /* if old list was too small, free it */
- if (ch->sc_dma_ops) {
- auvia_free(sc, ch->sc_dma_ops, M_DEVBUF);
- }
-
- ch->sc_dma_ops = auvia_malloc(sc, 0,
- sizeof(struct auvia_dma_op) * segs, M_DEVBUF, M_WAITOK);
-
- if (ch->sc_dma_ops == NULL) {
- aprint_error_dev(sc->sc_dev, "couldn't build dmaops\n");
- return 1;
- }
-
- for (dp = sc->sc_dmas;
- dp && dp->addr != (void *)(ch->sc_dma_ops);
- dp = dp->next)
- continue;
-
- if (!dp)
- panic("%s: build_dma_ops: where'd my memory go??? "
- "address (%p)\n", device_xname(sc->sc_dev),
- ch->sc_dma_ops);
-
- ch->sc_dma_op_count = segs;
- ch->sc_dma_ops_dma = dp;
- }
dp = ch->sc_dma_ops_dma;
op = ch->sc_dma_ops;
+ s = p->map->dm_segs[0].ds_addr;
+ l = ((char *)end - (char *)start);
while (l) {
op->ptr = htole32(s);
@@ -1112,8 +1196,9 @@ auvia_intr(void *arg)
sc = arg;
rval = 0;
-
ch = &sc->sc_record;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
r = CH_READ1(sc, ch, AUVIA_RP_STAT);
if (r & AUVIA_RPSTAT_INTR) {
if (sc->sc_record.sc_intr)
@@ -1134,6 +1219,7 @@ auvia_intr(void *arg)
CH_WRITE1(sc, ch, AUVIA_RP_STAT, AUVIA_RPSTAT_INTR);
rval = 1;
}
+ mutex_spin_exit(&sc->sc_intr_lock);
return rval;
}
@@ -1143,9 +1229,13 @@ auvia_resume(device_t dv, const pmf_qual_t *qual)
{
struct auvia_softc *sc = device_private(dv);
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
auvia_reset_codec(sc);
DELAY(1000);
+ mutex_spin_exit(&sc->sc_intr_lock);
(sc->codec_if->vtbl->restore_ports)(sc->codec_if);
+ mutex_exit(&sc->sc_lock);
return true;
}
diff --git a/sys/dev/pci/auviavar.h b/sys/dev/pci/auviavar.h
index 9ef5a336b4b..f98a00c21bc 100644
--- a/sys/dev/pci/auviavar.h
+++ b/sys/dev/pci/auviavar.h
@@ -1,7 +1,7 @@
-/* $NetBSD: auviavar.h,v 1.15 2009/05/06 18:25:28 cegger Exp $ */
+/* $NetBSD: auviavar.h,v 1.16 2011/11/23 23:07:34 jmcneill Exp $ */
/*-
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * Copyright (c) 2000, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -46,6 +46,8 @@ struct auvia_softc_chan {
struct auvia_softc {
device_t sc_dev;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
char sc_revision[8];
u_int sc_flags;
diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c
index 59a94c00043..c8e664b8dbb 100644
--- a/sys/dev/pci/azalia.c
+++ b/sys/dev/pci/azalia.c
@@ -1,7 +1,7 @@
-/* $NetBSD: azalia.c,v 1.77 2011/08/29 14:47:07 jmcneill Exp $ */
+/* $NetBSD: azalia.c,v 1.78 2011/11/23 23:07:34 jmcneill Exp $ */
/*-
- * Copyright (c) 2005 The NetBSD Foundation, Inc.
+ * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -41,19 +41,20 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: azalia.c,v 1.77 2011/08/29 14:47:07 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: azalia.c,v 1.78 2011/11/23 23:07:34 jmcneill Exp $");
#include <sys/param.h>
#include <sys/device.h>
#include <sys/fcntl.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/systm.h>
#include <sys/module.h>
+
#include <dev/audio_if.h>
#include <dev/auconv.h>
+
#include <dev/pci/pcidevs.h>
#include <dev/pci/pcivar.h>
-
#include <dev/pci/azalia.h>
/* ----------------------------------------------------------------
@@ -110,6 +111,8 @@ typedef struct {
typedef struct azalia_t {
device_t dev;
device_t audiodev;
+ kmutex_t lock;
+ kmutex_t intr_lock;
pci_chipset_tag_t pc;
pcitag_t tag;
@@ -212,14 +215,15 @@ static int azalia_getdev(void *, struct audio_device *);
static int azalia_set_port(void *, mixer_ctrl_t *);
static int azalia_get_port(void *, mixer_ctrl_t *);
static int azalia_query_devinfo(void *, mixer_devinfo_t *);
-static void *azalia_allocm(void *, int, size_t, struct malloc_type *, int);
-static void azalia_freem(void *, void *, struct malloc_type *);
+static void *azalia_allocm(void *, int, size_t);
+static void azalia_freem(void *, void *, size_t);
static size_t azalia_round_buffersize(void *, int, size_t);
static int azalia_get_props(void *);
static int azalia_trigger_output(void *, void *, void *, int,
void (*)(void *), void *, const audio_params_t *);
static int azalia_trigger_input(void *, void *, void *, int,
void (*)(void *), void *, const audio_params_t *);
+static void azalia_get_locks(void *, kmutex_t **, kmutex_t **);
static int azalia_params2fmt(const audio_params_t *, uint16_t *);
@@ -256,7 +260,7 @@ static const struct audio_hw_if azalia_hw_if = {
azalia_trigger_output,
azalia_trigger_input,
NULL, /* dev_ioctl */
- NULL, /* powerstate */
+ azalia_get_locks,
};
static const char *pin_colors[16] = {
@@ -325,15 +329,21 @@ azalia_pci_attach(device_t parent, device_t self, void *aux)
aprint_error_dev(self, "can't map interrupt\n");
return;
}
+
+ mutex_init(&sc->lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
sc->pc = pa->pa_pc;
sc->tag = pa->pa_tag;
intrrupt_str = pci_intr_string(pa->pa_pc, ih);
- sc->ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, azalia_intr, sc);
+ sc->ih = pci_intr_establish(pa->pa_pc, ih, IPL_SCHED, azalia_intr, sc);
if (sc->ih == NULL) {
aprint_error_dev(self, "can't establish interrupt");
if (intrrupt_str != NULL)
aprint_error(" at %s", intrrupt_str);
aprint_error("\n");
+ mutex_destroy(&sc->lock);
+ mutex_destroy(&sc->intr_lock);
return;
}
aprint_normal_dev(self, "interrupting at %s\n", intrrupt_str);
@@ -356,6 +366,8 @@ azalia_pci_attach(device_t parent, device_t self, void *aux)
if (azalia_attach(sc)) {
aprint_error_dev(self, "initialization failure\n");
azalia_pci_detach(self, 0);
+ mutex_destroy(&sc->lock);
+ mutex_destroy(&sc->intr_lock);
return;
}
sc->subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
@@ -383,12 +395,15 @@ azalia_pci_detach(device_t self, int flags)
if (az->audiodev != NULL)
config_detach(az->audiodev, flags);
+ mutex_enter(&az->lock);
+
#if notyet
DPRINTF(("%s: halt streams\n", __func__));
azalia_stream_halt(&az->rstream);
azalia_stream_halt(&az->pstream);
#endif
+
DPRINTF(("%s: delete streams\n", __func__));
azalia_stream_delete(&az->rstream, az);
azalia_stream_delete(&az->pstream, az);
@@ -403,6 +418,10 @@ azalia_pci_detach(device_t self, int flags)
azalia_delete_corb(az);
azalia_delete_rirb(az);
+ mutex_exit(&az->lock);
+ mutex_destroy(&az->lock);
+ mutex_destroy(&az->intr_lock);
+
DPRINTF(("%s: delete PCI resources\n", __func__));
if (az->ih != NULL) {
pci_intr_disestablish(az->pc, az->ih);
@@ -419,13 +438,13 @@ static bool
azalia_pci_resume(device_t dv, const pmf_qual_t *qual)
{
azalia_t *az = device_private(dv);
- int s;
- s = splaudio();
+ mutex_enter(&az->lock);
+ mutex_spin_enter(&az->intr_lock);
azalia_attach(az);
- splx(s);
-
azalia_attach_intr(az->dev);
+ mutex_spin_exit(&az->intr_lock);
+ mutex_exit(&az->lock);
return true;
}
@@ -443,8 +462,13 @@ azalia_intr(void *v)
if (!device_has_power(az->dev))
return 0;
- if ((intsts = AZ_READ_4(az, INTSTS)) == 0)
+ mutex_spin_enter(&az->intr_lock);
+
+ intsts = AZ_READ_4(az, INTSTS);
+ if (intsts == 0) {
+ mutex_spin_exit(&az->intr_lock);
return 0;
+ }
ret = azalia_stream_intr(&az->pstream, intsts) +
azalia_stream_intr(&az->rstream, intsts);
@@ -461,6 +485,7 @@ azalia_intr(void *v)
ret++;
}
+ mutex_spin_exit(&az->intr_lock);
return ret;
}
@@ -766,8 +791,8 @@ azalia_init_rirb(azalia_t *az, int reinit)
az->unsolq_wp = 0;
az->unsolq_kick = FALSE;
if (reinit == 0) {
- az->unsolq = malloc(sizeof(rirb_entry_t) * UNSOLQ_SIZE,
- M_DEVBUF, M_ZERO | M_NOWAIT);
+ az->unsolq = kmem_zalloc(sizeof(rirb_entry_t) * UNSOLQ_SIZE,
+ KM_SLEEP);
} else {
memset(az->unsolq, 0, sizeof(rirb_entry_t) * UNSOLQ_SIZE);
}
@@ -805,7 +830,7 @@ azalia_delete_rirb(azalia_t *az)
uint8_t rirbctl;
if (az->unsolq != NULL) {
- free(az->unsolq, M_DEVBUF);
+ kmem_free(az->unsolq, UNSOLQ_SIZE);
az->unsolq = NULL;
}
if (az->rirb_dma.addr == NULL)
@@ -961,21 +986,21 @@ azalia_alloc_dmamem(azalia_t *az, size_t size, size_t align, azalia_dma_t *d)
d->size = size;
err = bus_dmamem_alloc(az->dmat, size, align, 0, d->segments, 1,
- &nsegs, BUS_DMA_NOWAIT);
+ &nsegs, BUS_DMA_WAITOK);
if (err)
return err;
if (nsegs != 1)
goto free;
err = bus_dmamem_map(az->dmat, d->segments, 1, size,
- &d->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_NOCACHE);
+ &d->addr, BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_NOCACHE);
if (err)
goto free;
err = bus_dmamap_create(az->dmat, size, 1, size, 0,
- BUS_DMA_NOWAIT, &d->map);
+ BUS_DMA_WAITOK, &d->map);
if (err)
goto unmap;
err = bus_dmamap_load(az->dmat, d->map, d->addr, size,
- NULL, BUS_DMA_NOWAIT);
+ NULL, BUS_DMA_WAITOK);
if (err)
goto destroy;
@@ -1113,8 +1138,8 @@ azalia_codec_init(codec_t *this, int reinit, uint32_t subid)
}
this->wend = this->wstart + COP_NSUBNODES(result);
if (!reinit) {
- this->w = malloc(sizeof(widget_t) * this->wend, M_DEVBUF,
- M_ZERO | M_NOWAIT);
+ this->w = kmem_zalloc(sizeof(widget_t) * this->wend,
+ KM_SLEEP);
if (this->w == NULL) {
aprint_error("%s: out of memory\n",
device_xname(this->dev));
@@ -1272,13 +1297,13 @@ azalia_codec_delete(codec_t *this)
if (this->mixer_delete != NULL)
this->mixer_delete(this);
if (this->formats != NULL) {
- free(this->formats, M_DEVBUF);
+ kmem_free(this->formats, this->szformats);
this->formats = NULL;
}
auconv_delete_encodings(this->encodings);
this->encodings = NULL;
if (this->extra != NULL) {
- free(this->extra, M_DEVBUF);
+ kmem_free(this->extra, this->szextra);
this->extra = NULL;
}
return 0;
@@ -1349,10 +1374,10 @@ azalia_codec_construct_format(codec_t *this, int newdac, int newadc)
}
if (this->formats != NULL)
- free(this->formats, M_DEVBUF);
+ kmem_free(this->formats, this->szformats);
this->nformats = 0;
- this->formats = malloc(sizeof(struct audio_format) * variation,
- M_DEVBUF, M_ZERO | M_NOWAIT);
+ this->szformats = sizeof(struct audio_format) * variation;
+ this->formats = kmem_zalloc(this->szformats, KM_SLEEP);
if (this->formats == NULL) {
aprint_error("%s: out of memory in %s\n",
device_xname(this->dev), __func__);
@@ -1506,15 +1531,11 @@ azalia_codec_comresp(const codec_t *codec, nid_t nid, uint32_t control,
uint32_t param, uint32_t* result)
{
azalia_t *az = device_private(codec->dev);
- int err, s;
+ int err;
- s = splaudio();
err = azalia_set_command(az, codec->address, nid, control, param);
- if (err)
- goto EXIT;
- err = azalia_get_response(az, result);
-EXIT:
- splx(s);
+ if (err == 0)
+ err = azalia_get_response(az, result);
return err;
}
@@ -1583,20 +1604,22 @@ azalia_codec_disconnect_stream(codec_t *this, int dir)
uint32_t v;
int i;
nid_t nid;
-
+
if (dir == AUMODE_RECORD)
group = &this->adcs.groups[this->adcs.cur];
else
group = &this->dacs.groups[this->dacs.cur];
for (i = 0; i < group->nconv; i++) {
nid = group->conv[i];
- this->comresp(this, nid, CORB_SET_CONVERTER_STREAM_CHANNEL,
- 0, NULL); /* stream#0 */
+ this->comresp(this, nid,
+ CORB_SET_CONVERTER_STREAM_CHANNEL, 0, NULL);/* stream#0 */
if (this->w[nid].widgetcap & COP_AWCAP_DIGITAL) {
/* disable S/PDIF */
- this->comresp(this, nid, CORB_GET_DIGITAL_CONTROL, 0, &v);
+ this->comresp(this, nid,
+ CORB_GET_DIGITAL_CONTROL, 0, &v);
v = (v & ~CORB_DCC_DIGEN) & 0xff;
- this->comresp(this, nid, CORB_SET_DIGITAL_CONTROL_L, v, NULL);
+ this->comresp(this, nid,
+ CORB_SET_DIGITAL_CONTROL_L, v, NULL);
}
}
return 0;
@@ -1870,8 +1893,7 @@ azalia_widget_init_connection(widget_t *this, const codec_t *codec,
if (length == 0)
return 0;
this->nconnections = length;
- this->connections = malloc(sizeof(nid_t) * (length + 3),
- M_DEVBUF, M_NOWAIT);
+ this->connections = kmem_alloc(sizeof(nid_t) * (length + 3), KM_SLEEP);
if (this->connections == NULL) {
aprint_error("%s: out of memory\n", device_xname(codec->dev));
return ENOMEM;
@@ -2245,8 +2267,7 @@ azalia_query_devinfo(void *v, mixer_devinfo_t *mdev)
}
static void *
-azalia_allocm(void *v, int dir, size_t size, struct malloc_type *pool,
- int flags)
+azalia_allocm(void *v, int dir, size_t size)
{
azalia_t *az;
stream_t *stream;
@@ -2261,7 +2282,7 @@ azalia_allocm(void *v, int dir, size_t size, struct malloc_type *pool,
}
static void
-azalia_freem(void *v, void *addr, struct malloc_type *pool)
+azalia_freem(void *v, void *addr, size_t size)
{
azalia_t *az;
stream_t *stream;
@@ -2408,6 +2429,16 @@ azalia_params2fmt(const audio_params_t *param, uint16_t *fmt)
MODULE(MODULE_CLASS_DRIVER, azalia, "pci");
+static void
+azalia_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ azalia_t *az;
+
+ az = addr;
+ *intr = &az->intr_lock;
+ *thread = &az->lock;
+}
+
#ifdef _MODULE
#include "ioconf.c"
#endif
diff --git a/sys/dev/pci/azalia.h b/sys/dev/pci/azalia.h
index 36d280c3a58..f8dbe158dca 100644
--- a/sys/dev/pci/azalia.h
+++ b/sys/dev/pci/azalia.h
@@ -1,7 +1,7 @@
-/* $NetBSD: azalia.h,v 1.20 2008/08/14 23:43:27 jmcneill Exp $ */
+/* $NetBSD: azalia.h,v 1.21 2011/11/23 23:07:35 jmcneill Exp $ */
/*-
- * Copyright (c) 2005 The NetBSD Foundation, Inc.
+ * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -578,13 +578,16 @@ typedef struct codec_t {
int running;
int nmixers, maxmixers;
+ size_t szmixers;
mixer_item_t *mixers;
struct audio_format *formats;
int nformats;
+ size_t szformats;
struct audio_encoding_set *encodings;
uint32_t *extra;
+ size_t szextra;
} codec_t;
diff --git a/sys/dev/pci/azalia_codec.c b/sys/dev/pci/azalia_codec.c
index 87af818ac97..e69dd671b85 100644
--- a/sys/dev/pci/azalia_codec.c
+++ b/sys/dev/pci/azalia_codec.c
@@ -1,7 +1,7 @@
-/* $NetBSD: azalia_codec.c,v 1.78 2010/05/03 04:36:43 dholland Exp $ */
+/* $NetBSD: azalia_codec.c,v 1.79 2011/11/23 23:07:35 jmcneill Exp $ */
/*-
- * Copyright (c) 2005 The NetBSD Foundation, Inc.
+ * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,13 +30,14 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: azalia_codec.c,v 1.78 2010/05/03 04:36:43 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: azalia_codec.c,v 1.79 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/param.h>
#include <sys/device.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/null.h>
#include <sys/systm.h>
+
#include <dev/pci/azalia.h>
#ifdef MAX_VOLUME_255
@@ -363,8 +364,8 @@ azalia_codec_init_vtbl(codec_t *this)
break;
}
if (extra_size > 0) {
- this->extra = malloc(sizeof(uint32_t) * extra_size,
- M_DEVBUF, M_ZERO | M_NOWAIT);
+ this->szextra = sizeof(uint32_t) * extra_size;
+ this->extra = kmem_zalloc(this->szextra, KM_SLEEP);
if (this->extra == NULL) {
aprint_error_dev(this->dev, "Not enough memory\n");
return ENOMEM;
@@ -564,8 +565,8 @@ generic_mixer_init(codec_t *this)
this->maxmixers = 10;
this->nmixers = 0;
- this->mixers = malloc(sizeof(mixer_item_t) * this->maxmixers,
- M_DEVBUF, M_ZERO | M_NOWAIT);
+ this->szmixers = sizeof(mixer_item_t) * this->maxmixers;
+ this->mixers = kmem_zalloc(this->szmixers, KM_SLEEP);
if (this->mixers == NULL) {
aprint_error_dev(this->dev, "out of memory in %s\n", __func__);
return ENOMEM;
@@ -1078,6 +1079,7 @@ static int
generic_mixer_ensure_capacity(codec_t *this, size_t newsize)
{
size_t newmax;
+ size_t newsz;
void *newbuf;
if (this->maxmixers >= newsize)
@@ -1085,16 +1087,16 @@ generic_mixer_ensure_capacity(codec_t *this, size_t newsize)
newmax = this->maxmixers + 10;
if (newmax < newsize)
newmax = newsize;
- newbuf = realloc(this->mixers, sizeof(mixer_item_t) * newmax, M_DEVBUF,
- M_ZERO | M_NOWAIT);
+ newsz = sizeof(mixer_item_t) * newmax;
+ newbuf = kmem_zalloc(newsz, KM_SLEEP);
if (newbuf == NULL) {
aprint_error_dev(this->dev, "out of memory in %s\n", __func__);
return ENOMEM;
}
+ memcpy(newbuf, this->mixers, this->szmixers);
+ kmem_free(this->mixers, this->szmixers);
this->mixers = newbuf;
- /* realloc(9) doesn't clear expanded area even if M_ZERO. */
- memset(&this->mixers[this->maxmixers], 0,
- sizeof(mixer_item_t) * (newmax - this->maxmixers));
+ this->szmixers = newsize;
this->maxmixers = newmax;
return 0;
}
@@ -1456,7 +1458,7 @@ generic_mixer_delete(codec_t *this)
{
if (this->mixers == NULL)
return 0;
- free(this->mixers, M_DEVBUF);
+ kmem_free(this->mixers, this->szmixers);
this->mixers = NULL;
return 0;
}
@@ -2255,8 +2257,8 @@ alc260_mixer_init(codec_t *this)
this->nmixers = __arraycount(alc260_mixer_items);
mi = alc260_mixer_items;
}
- this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
- M_DEVBUF, M_NOWAIT);
+ this->szmixers = sizeof(mixer_item_t) * this->nmixers;
+ this->mixers = kmem_alloc(this->szmixers, KM_SLEEP);
if (this->mixers == NULL) {
aprint_error_dev(this->dev, "out of memory in %s\n", __func__);
return ENOMEM;
@@ -2646,7 +2648,8 @@ alc880_mixer_init(codec_t *this)
mixer_ctrl_t mc;
this->nmixers = __arraycount(alc880_mixer_items);
- this->mixers = malloc(sizeof(alc880_mixer_items), M_DEVBUF, M_NOWAIT);
+ this->szmixers = sizeof(alc880_mixer_items);
+ this->mixers = kmem_alloc(this->szmixers, KM_SLEEP);
if (this->mixers == NULL) {
aprint_error_dev(this->dev, "out of memory in %s\n", __func__);
return ENOMEM;
@@ -2811,7 +2814,8 @@ alc882_mixer_init(codec_t *this)
mixer_ctrl_t mc;
this->nmixers = __arraycount(alc882_mixer_items);
- this->mixers = malloc(sizeof(alc882_mixer_items), M_DEVBUF, M_NOWAIT);
+ this->szmixers = sizeof(alc882_mixer_items);
+ this->mixers = kmem_alloc(this->szmixers, KM_SLEEP);
if (this->mixers == NULL) {
aprint_error_dev(this->dev, "out of memory in %s\n", __func__);
return ENOMEM;
@@ -3079,7 +3083,8 @@ alc883_mixer_init(codec_t *this)
mixer_ctrl_t mc;
this->nmixers = __arraycount(alc883_mixer_items);
- this->mixers = malloc(sizeof(alc883_mixer_items), M_DEVBUF, M_NOWAIT);
+ this->szmixers = sizeof(alc883_mixer_items);
+ this->mixers = kmem_alloc(this->szmixers, KM_SLEEP);
if (this->mixers == NULL) {
aprint_error_dev(this->dev, "out of memory in %s\n", __func__);
return ENOMEM;
@@ -3403,7 +3408,8 @@ ad1981hd_mixer_init(codec_t *this)
mixer_ctrl_t mc;
this->nmixers = __arraycount(ad1981hd_mixer_items);
- this->mixers = malloc(sizeof(ad1981hd_mixer_items), M_DEVBUF, M_NOWAIT);
+ this->szmixers = sizeof(ad1981hd_mixer_items);
+ this->mixers = kmem_alloc(this->szmixers, KM_SLEEP);
if (this->mixers == NULL) {
aprint_error_dev(this->dev, "out of memory in %s\n", __func__);
return ENOMEM;
@@ -3516,7 +3522,8 @@ ad1983_mixer_init(codec_t *this)
mixer_ctrl_t mc;
this->nmixers = __arraycount(ad1983_mixer_items);
- this->mixers = malloc(sizeof(ad1983_mixer_items), M_DEVBUF, M_NOWAIT);
+ this->szmixers = sizeof(ad1983_mixer_items);
+ this->mixers = kmem_alloc(this->szmixers, KM_SLEEP);
if (this->mixers == NULL) {
aprint_error_dev(this->dev, "out of memory in %s\n", __func__);
return ENOMEM;
@@ -3932,7 +3939,8 @@ ad1986a_mixer_init(codec_t *this)
mixer_ctrl_t mc;
this->nmixers = __arraycount(ad1986a_mixer_items);
- this->mixers = malloc(sizeof(ad1986a_mixer_items), M_DEVBUF, M_NOWAIT);
+ this->szmixers = sizeof(ad1986a_mixer_items);
+ this->mixers = kmem_alloc(this->szmixers, KM_SLEEP);
if (this->mixers == NULL) {
aprint_error_dev(this->dev, "out of memory in %s\n", __func__);
return ENOMEM;
@@ -4050,7 +4058,8 @@ cmi9880_mixer_init(codec_t *this)
mixer_ctrl_t mc;
this->nmixers = __arraycount(cmi9880_mixer_items);
- this->mixers = malloc(sizeof(cmi9880_mixer_items), M_DEVBUF, M_NOWAIT);
+ this->szmixers = sizeof(cmi9880_mixer_items);
+ this->mixers = kmem_alloc(this->szmixers, KM_SLEEP);
if (this->mixers == NULL) {
aprint_error_dev(this->dev, "out of memory in %s\n", __func__);
return ENOMEM;
@@ -4210,7 +4219,8 @@ stac9200_mixer_init(codec_t *this)
uint32_t value;
this->nmixers = __arraycount(stac9200_mixer_items);
- this->mixers = malloc(sizeof(stac9200_mixer_items), M_DEVBUF, M_NOWAIT);
+ this->szmixers = sizeof(stac9200_mixer_items);
+ this->mixers = kmem_alloc(this->szmixers, KM_SLEEP);
if (this->mixers == NULL) {
aprint_error_dev(this->dev, "out of memory in %s\n", __func__);
return ENOMEM;
diff --git a/sys/dev/pci/cmpci.c b/sys/dev/pci/cmpci.c
index f38b90ba95d..bde3b992b13 100644
--- a/sys/dev/pci/cmpci.c
+++ b/sys/dev/pci/cmpci.c
@@ -1,7 +1,7 @@
-/* $NetBSD: cmpci.c,v 1.42 2009/11/26 15:17:08 njoly Exp $ */
+/* $NetBSD: cmpci.c,v 1.43 2011/11/23 23:07:35 jmcneill Exp $ */
/*
- * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
+ * Copyright (c) 2000, 2001, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -43,7 +43,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cmpci.c,v 1.42 2009/11/26 15:17:08 njoly Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cmpci.c,v 1.43 2011/11/23 23:07:35 jmcneill Exp $");
#if defined(AUDIO_DEBUG) || defined(DEBUG)
#define DPRINTF(x) if (cmpcidebug) printf x
@@ -57,7 +57,7 @@ int cmpcidebug = 0;
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
#include <sys/proc.h>
@@ -119,10 +119,8 @@ static int cmpci_intr(void *);
/*
* DMA stuffs
*/
-static int cmpci_alloc_dmamem(struct cmpci_softc *, size_t,
- struct malloc_type *, int, void **);
-static int cmpci_free_dmamem(struct cmpci_softc *, void *,
- struct malloc_type *);
+static int cmpci_alloc_dmamem(struct cmpci_softc *, size_t, void **);
+static int cmpci_free_dmamem(struct cmpci_softc *, void *, size_t);
static struct cmpci_dmanode * cmpci_find_dmamem(struct cmpci_softc *,
void *);
@@ -140,8 +138,8 @@ static int cmpci_getdev(void *, struct audio_device *);
static int cmpci_set_port(void *, mixer_ctrl_t *);
static int cmpci_get_port(void *, mixer_ctrl_t *);
static int cmpci_query_devinfo(void *, mixer_devinfo_t *);
-static void *cmpci_allocm(void *, int, size_t, struct malloc_type *, int);
-static void cmpci_freem(void *, void *, struct malloc_type *);
+static void *cmpci_allocm(void *, int, size_t);
+static void cmpci_freem(void *, void *, size_t);
static size_t cmpci_round_buffersize(void *, int, size_t);
static paddr_t cmpci_mappage(void *, void *, off_t, int);
static int cmpci_get_props(void *);
@@ -149,6 +147,7 @@ static int cmpci_trigger_output(void *, void *, void *, int,
void (*)(void *), void *, const audio_params_t *);
static int cmpci_trigger_input(void *, void *, void *, int,
void (*)(void *), void *, const audio_params_t *);
+static void cmpci_get_locks(void *, kmutex_t **, kmutex_t **);
static const struct audio_hw_if cmpci_hw_if = {
NULL, /* open */
@@ -178,7 +177,7 @@ static const struct audio_hw_if cmpci_hw_if = {
cmpci_trigger_output, /* trigger_output */
cmpci_trigger_input, /* trigger_input */
NULL, /* dev_ioctl */
- NULL, /* powerstate */
+ cmpci_get_locks, /* get_locks */
};
#define CMPCI_NFORMATS 4
@@ -414,18 +413,24 @@ cmpci_attach(device_t parent, device_t self, void *aux)
return;
}
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
/* interrupt */
if (pci_intr_map(pa, &ih)) {
aprint_error_dev(&sc->sc_dev, "failed to map interrupt\n");
return;
}
strintr = pci_intr_string(pa->pa_pc, ih);
- sc->sc_ih=pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, cmpci_intr, sc);
+ sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_SCHED, cmpci_intr,
+ sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(&sc->sc_dev, "failed to establish interrupt");
if (strintr != NULL)
aprint_error(" at %s", strintr);
aprint_error("\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
aprint_normal_dev(&sc->sc_dev, "interrupting at %s\n", strintr);
@@ -526,11 +531,15 @@ cmpci_intr(void *handle)
#endif
uint32_t intrstat;
+ mutex_spin_enter(&sc->sc_intr_lock);
+
intrstat = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
CMPCI_REG_INTR_STATUS);
- if (!(intrstat & CMPCI_REG_ANY_INTR))
+ if (!(intrstat & CMPCI_REG_ANY_INTR)) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
+ }
delay(10);
@@ -564,6 +573,7 @@ cmpci_intr(void *handle)
mpu_intr(sc_mpu);
#endif
+ mutex_spin_exit(&sc->sc_intr_lock);
return 1;
}
@@ -719,10 +729,8 @@ static int
cmpci_halt_output(void *handle)
{
struct cmpci_softc *sc;
- int s;
sc = handle;
- s = splaudio();
sc->sc_play.intr = NULL;
cmpci_reg_clear_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE);
cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE);
@@ -730,7 +738,6 @@ cmpci_halt_output(void *handle)
cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET);
delay(10);
cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET);
- splx(s);
return 0;
}
@@ -739,10 +746,8 @@ static int
cmpci_halt_input(void *handle)
{
struct cmpci_softc *sc;
- int s;
sc = handle;
- s = splaudio();
sc->sc_rec.intr = NULL;
cmpci_reg_clear_4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE);
cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE);
@@ -750,7 +755,6 @@ cmpci_halt_input(void *handle)
cmpci_reg_set_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_RESET);
delay(10);
cmpci_reg_clear_4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_RESET);
- splx(s);
return 0;
}
@@ -1008,40 +1012,38 @@ cmpci_query_devinfo(void *handle, mixer_devinfo_t *dip)
}
static int
-cmpci_alloc_dmamem(struct cmpci_softc *sc, size_t size, struct malloc_type *type,
- int flags, void **r_addr)
+cmpci_alloc_dmamem(struct cmpci_softc *sc, size_t size, void **r_addr)
{
int error;
struct cmpci_dmanode *n;
- int w;
error = 0;
- n = malloc(sizeof(struct cmpci_dmanode), type, flags);
+ n = kmem_alloc(sizeof(struct cmpci_dmanode), KM_SLEEP);
if (n == NULL) {
error = ENOMEM;
goto quit;
}
- w = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
#define CMPCI_DMABUF_ALIGN 0x4
#define CMPCI_DMABUF_BOUNDARY 0x0
n->cd_tag = sc->sc_dmat;
n->cd_size = size;
error = bus_dmamem_alloc(n->cd_tag, n->cd_size,
CMPCI_DMABUF_ALIGN, CMPCI_DMABUF_BOUNDARY, n->cd_segs,
- sizeof(n->cd_segs)/sizeof(n->cd_segs[0]), &n->cd_nsegs, w);
+ sizeof(n->cd_segs)/sizeof(n->cd_segs[0]), &n->cd_nsegs,
+ BUS_DMA_WAITOK);
if (error)
goto mfree;
error = bus_dmamem_map(n->cd_tag, n->cd_segs, n->cd_nsegs, n->cd_size,
- &n->cd_addr, w | BUS_DMA_COHERENT);
+ &n->cd_addr, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
if (error)
goto dmafree;
error = bus_dmamap_create(n->cd_tag, n->cd_size, 1, n->cd_size, 0,
- w, &n->cd_map);
+ BUS_DMA_WAITOK, &n->cd_map);
if (error)
goto unmap;
error = bus_dmamap_load(n->cd_tag, n->cd_map, n->cd_addr, n->cd_size,
- NULL, w);
+ NULL, BUS_DMA_WAITOK);
if (error)
goto destroy;
@@ -1058,13 +1060,13 @@ cmpci_alloc_dmamem(struct cmpci_softc *sc, size_t size, struct malloc_type *type
bus_dmamem_free(n->cd_tag,
n->cd_segs, sizeof(n->cd_segs)/sizeof(n->cd_segs[0]));
mfree:
- free(n, type);
+ kmem_free(n, sizeof(*n));
quit:
return error;
}
static int
-cmpci_free_dmamem(struct cmpci_softc *sc, void *addr, struct malloc_type *type)
+cmpci_free_dmamem(struct cmpci_softc *sc, void *addr, size_t size)
{
struct cmpci_dmanode **nnp;
@@ -1076,7 +1078,7 @@ cmpci_free_dmamem(struct cmpci_softc *sc, void *addr, struct malloc_type *type)
bus_dmamem_unmap(n->cd_tag, n->cd_addr, n->cd_size);
bus_dmamem_free(n->cd_tag, n->cd_segs,
sizeof(n->cd_segs)/sizeof(n->cd_segs[0]));
- free(n, type);
+ kmem_free(n, sizeof(*n));
return 0;
}
}
@@ -1108,23 +1110,22 @@ cmpci_print_dmamem(struct cmpci_dmanode *p)
#endif /* DEBUG */
static void *
-cmpci_allocm(void *handle, int direction, size_t size,
- struct malloc_type *type, int flags)
+cmpci_allocm(void *handle, int direction, size_t size)
{
void *addr;
addr = NULL; /* XXX gcc */
- if (cmpci_alloc_dmamem(handle, size, type, flags, &addr))
+ if (cmpci_alloc_dmamem(handle, size, &addr))
return NULL;
return addr;
}
static void
-cmpci_freem(void *handle, void *addr, struct malloc_type *type)
+cmpci_freem(void *handle, void *addr, size_t size)
{
- cmpci_free_dmamem(handle, addr, type);
+ cmpci_free_dmamem(handle, addr, size);
}
#define MAXVAL 256
@@ -1744,4 +1745,14 @@ cmpci_trigger_input(void *handle, void *start, void *end, int blksize,
return 0;
}
+static void
+cmpci_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct cmpci_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
/* end of file */
diff --git a/sys/dev/pci/cmpcivar.h b/sys/dev/pci/cmpcivar.h
index 4c3233477f2..b989957dea3 100644
--- a/sys/dev/pci/cmpcivar.h
+++ b/sys/dev/pci/cmpcivar.h
@@ -1,7 +1,7 @@
-/* $NetBSD: cmpcivar.h,v 1.10 2007/03/04 06:02:17 christos Exp $ */
+/* $NetBSD: cmpcivar.h,v 1.11 2011/11/23 23:07:35 jmcneill Exp $ */
/*
- * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
+ * Copyright (c) 2000, 2001, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -174,6 +174,8 @@ typedef struct cmpci_dmanode *cmpci_dmapool_t;
*/
struct cmpci_softc {
struct device sc_dev;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
/* model/rev */
uint32_t sc_id;
diff --git a/sys/dev/pci/cs4280.c b/sys/dev/pci/cs4280.c
index c06cca180f5..cbd49ad4ad5 100644
--- a/sys/dev/pci/cs4280.c
+++ b/sys/dev/pci/cs4280.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cs4280.c,v 1.61 2011/04/04 20:37:56 dyoung Exp $ */
+/* $NetBSD: cs4280.c,v 1.62 2011/11/23 23:07:35 jmcneill Exp $ */
/*
* Copyright (c) 1999, 2000 Tatoku Ogaito. All rights reserved.
@@ -52,7 +52,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cs4280.c,v 1.61 2011/04/04 20:37:56 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cs4280.c,v 1.62 2011/11/23 23:07:35 jmcneill Exp $");
#include "midi.h"
@@ -64,14 +64,10 @@ __KERNEL_RCSID(0, "$NetBSD: cs4280.c,v 1.61 2011/04/04 20:37:56 dyoung Exp $");
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/systm.h>
-
-#include <dev/pci/pcidevs.h>
-#include <dev/pci/pcivar.h>
-#include <dev/pci/cs4280reg.h>
-#include <dev/pci/cs4280_image.h>
-#include <dev/pci/cs428xreg.h>
-
#include <sys/audioio.h>
+#include <sys/bus.h>
+#include <sys/bswap.h>
+
#include <dev/audio_if.h>
#include <dev/midi_if.h>
#include <dev/mulaw.h>
@@ -80,11 +76,13 @@ __KERNEL_RCSID(0, "$NetBSD: cs4280.c,v 1.61 2011/04/04 20:37:56 dyoung Exp $");
#include <dev/ic/ac97reg.h>
#include <dev/ic/ac97var.h>
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/cs4280reg.h>
+#include <dev/pci/cs4280_image.h>
+#include <dev/pci/cs428xreg.h>
#include <dev/pci/cs428x.h>
-#include <sys/bus.h>
-#include <sys/bswap.h>
-
#define BA1READ4(sc, r) bus_space_read_4((sc)->ba1t, (sc)->ba1h, (r))
#define BA1WRITE4(sc, r, x) bus_space_write_4((sc)->ba1t, (sc)->ba1h, (r), (x))
@@ -187,7 +185,7 @@ static const struct audio_hw_if cs4280_hw_if = {
cs4280_trigger_output,
cs4280_trigger_input,
NULL,
- NULL,
+ cs428x_get_locks,
};
#if NMIDI > 0
@@ -204,6 +202,7 @@ static const struct midi_hw_if cs4280_midi_hw_if = {
cs4280_midi_output,
cs4280_midi_getinfo,
0,
+ cs428x_get_locks,
};
#endif
@@ -326,20 +325,28 @@ cs4280_attach(device_t parent, device_t self, void *aux)
}
intrstr = pci_intr_string(pc, sc->intrh);
- sc->sc_ih = pci_intr_establish(sc->sc_pc, sc->intrh, IPL_AUDIO,
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
+ sc->sc_ih = pci_intr_establish(sc->sc_pc, sc->intrh, IPL_SCHED,
cs4280_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(&sc->sc_dev, "couldn't establish interrupt");
if (intrstr != NULL)
aprint_error(" at %s", intrstr);
aprint_error("\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
aprint_normal_dev(&sc->sc_dev, "interrupting at %s\n", intrstr);
/* Initialization */
- if(cs4280_init(sc, 1) != 0)
+ if(cs4280_init(sc, 1) != 0) {
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
+ }
sc->type = TYPE_CS4280;
sc->halt_input = cs4280_halt_input;
@@ -361,7 +368,7 @@ cs4280_attach(device_t parent, device_t self, void *aux)
sc->host_if.reset = NULL;
#endif
sc->host_if.flags = cs4280_flags_codec;
- if (ac97_attach(&sc->host_if, self) != 0) {
+ if (ac97_attach(&sc->host_if, self, &sc->sc_lock) != 0) {
aprint_error_dev(&sc->sc_dev, "ac97_attach failed\n");
return;
}
@@ -409,13 +416,18 @@ cs4280_intr(void *p)
sc = p;
handled = 0;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
+
/* grab interrupt register then clear it */
intr = BA0READ4(sc, CS4280_HISR);
BA0WRITE4(sc, CS4280_HICR, HICR_CHGM | HICR_IEV);
/* not for us ? */
- if ((intr & HISR_INTENA) == 0)
+ if ((intr & HISR_INTENA) == 0) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
+ }
/* Playback Interrupt */
if (intr & HISR_PINT) {
@@ -553,6 +565,7 @@ cs4280_intr(void *p)
}
#endif
+ mutex_spin_exit(&sc->sc_intr_lock);
return handled;
}
@@ -923,6 +936,9 @@ cs4280_suspend(device_t dv, const pmf_qual_t *qual)
{
struct cs428x_softc *sc = device_private(dv);
+ mutex_exit(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
+
if (sc->sc_prun) {
sc->sc_suspend_state.cs4280.pctl = BA1READ4(sc, CS4280_PCTL);
sc->sc_suspend_state.cs4280.pfie = BA1READ4(sc, CS4280_PFIE);
@@ -950,6 +966,9 @@ cs4280_suspend(device_t dv, const pmf_qual_t *qual)
BA1WRITE4(sc, CS4280_PCTL, sc->sc_suspend_state.cs4280.pctl & ~PCTL_MASK);
BA1WRITE4(sc, CS4280_CCTL, BA1READ4(sc, CS4280_CCTL) & ~CCTL_MASK);
+ mutex_spin_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
+
return true;
}
@@ -958,12 +977,12 @@ cs4280_resume(device_t dv, const pmf_qual_t *qual)
{
struct cs428x_softc *sc = device_private(dv);
+ mutex_exit(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
cs4280_init(sc, 0);
#if 0
cs4280_reset_codec(sc);
#endif
- /* restore ac97 registers */
- (*sc->codec_if->vtbl->restore_ports)(sc->codec_if);
/* restore DMA related status */
if(sc->sc_prun) {
@@ -990,6 +1009,13 @@ cs4280_resume(device_t dv, const pmf_qual_t *qual)
BA1WRITE4(sc, CS4280_CCTL, sc->sc_suspend_state.cs4280.cctl);
}
+ mutex_spin_exit(&sc->sc_intr_lock);
+
+ /* restore ac97 registers */
+ (*sc->codec_if->vtbl->restore_ports)(sc->codec_if);
+
+ mutex_exit(&sc->sc_lock);
+
return true;
}
@@ -1060,7 +1086,8 @@ cs4280_reset_codec(void *addr)
}
#endif
-static enum ac97_host_flags cs4280_flags_codec(void *addr)
+static enum ac97_host_flags
+cs4280_flags_codec(void *addr)
{
struct cs428x_softc *sc;
@@ -1630,7 +1657,8 @@ cs4280_midi_close(void *addr)
DPRINTF(("midi_close\n"));
sc = addr;
- tsleep(sc, PWAIT, "cs0clm", hz/10); /* give uart a chance to drain */
+ /* give uart a chance to drain */
+ kpause("cs0clm", false, hz/10, &sc->sc_intr_lock);
mem = BA0READ4(sc, CS4280_MIDCR);
mem &= ~MIDCR_MASK;
BA0WRITE4(sc, CS4280_MIDCR, mem);
diff --git a/sys/dev/pci/cs4281.c b/sys/dev/pci/cs4281.c
index c35d879955e..9e247c39389 100644
--- a/sys/dev/pci/cs4281.c
+++ b/sys/dev/pci/cs4281.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cs4281.c,v 1.44 2010/02/24 22:37:59 dyoung Exp $ */
+/* $NetBSD: cs4281.c,v 1.45 2011/11/23 23:07:35 jmcneill Exp $ */
/*
* Copyright (c) 2000 Tatoku Ogaito. All rights reserved.
@@ -43,7 +43,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cs4281.c,v 1.44 2010/02/24 22:37:59 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cs4281.c,v 1.45 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -137,7 +137,7 @@ static const struct audio_hw_if cs4281_hw_if = {
cs4281_trigger_output,
cs4281_trigger_input,
NULL,
- NULL,
+ cs428x_get_locks,
};
#if NMIDI > 0 && 0
@@ -154,6 +154,7 @@ static const struct midi_hw_if cs4281_midi_hw_if = {
cs4281_midi_output,
cs4281_midi_getinfo,
0,
+ cs428x_get_locks,
};
#endif
@@ -248,13 +249,18 @@ cs4281_attach(device_t parent, device_t self, void *aux)
}
intrstr = pci_intr_string(pc, sc->intrh);
- sc->sc_ih = pci_intr_establish(sc->sc_pc, sc->intrh, IPL_AUDIO,
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
+ sc->sc_ih = pci_intr_establish(sc->sc_pc, sc->intrh, IPL_SCHED,
cs4281_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(&sc->sc_dev, "couldn't establish interrupt");
if (intrstr != NULL)
aprint_error(" at %s", intrstr);
aprint_error("\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
aprint_normal_dev(&sc->sc_dev, "interrupting at %s\n", intrstr);
@@ -262,8 +268,11 @@ cs4281_attach(device_t parent, device_t self, void *aux)
/*
* Sound System start-up
*/
- if (cs4281_init(sc, 1) != 0)
+ if (cs4281_init(sc, 1) != 0) {
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
+ }
sc->type = TYPE_CS4281;
sc->halt_input = cs4281_halt_input;
@@ -279,8 +288,10 @@ cs4281_attach(device_t parent, device_t self, void *aux)
sc->host_if.read = cs428x_read_codec;
sc->host_if.write = cs428x_write_codec;
sc->host_if.reset = cs4281_reset_codec;
- if (ac97_attach(&sc->host_if, self) != 0) {
+ if (ac97_attach(&sc->host_if, self, &sc->sc_lock) != 0) {
aprint_error_dev(&sc->sc_dev, "ac97_attach failed\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
audio_attach_mi(&cs4281_hw_if, sc, &sc->sc_dev);
@@ -306,6 +317,8 @@ cs4281_intr(void *p)
hdsr0 = 0;
hdsr1 = 0;
+ mutex_spin_enter(&sc->sc_intr_lock);
+
/* grab interrupt register */
intr = BA0READ4(sc, CS4281_HISR);
@@ -314,6 +327,7 @@ cs4281_intr(void *p)
if ((intr & HISR_INTENA) == 0) {
/* clear the interrupt register */
BA0WRITE4(sc, CS4281_HICR, HICR_CHGM | HICR_IEV);
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
}
@@ -372,6 +386,8 @@ cs4281_intr(void *p)
}
DPRINTF(("\n"));
+ mutex_spin_exit(&sc->sc_intr_lock);
+
return handled;
}
@@ -721,6 +737,9 @@ cs4281_suspend(device_t dv, const pmf_qual_t *qual)
{
struct cs428x_softc *sc = device_private(dv);
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_exit(&sc->sc_intr_lock);
+
/* save current playback status */
if (sc->sc_prun) {
sc->sc_suspend_state.cs4281.dcr0 = BA0READ4(sc, CS4281_DCR0);
@@ -740,6 +759,9 @@ cs4281_suspend(device_t dv, const pmf_qual_t *qual)
BA0WRITE4(sc, CS4281_DCR0, BA0READ4(sc, CS4281_DCR0) | DCRn_MSK);
BA0WRITE4(sc, CS4281_DCR1, BA0READ4(sc, CS4281_DCR1) | DCRn_MSK);
+ mutex_spin_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
+
return true;
}
@@ -748,11 +770,16 @@ cs4281_resume(device_t dv, const pmf_qual_t *qual)
{
struct cs428x_softc *sc = device_private(dv);
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
+
cs4281_init(sc, 0);
cs4281_reset_codec(sc);
/* restore ac97 registers */
+ mutex_spin_exit(&sc->sc_intr_lock);
(*sc->codec_if->vtbl->restore_ports)(sc->codec_if);
+ mutex_spin_enter(&sc->sc_intr_lock);
/* restore DMA related status */
if (sc->sc_prun) {
@@ -773,6 +800,9 @@ cs4281_resume(device_t dv, const pmf_qual_t *qual)
if (sc->sc_prun || sc->sc_rrun)
BA0WRITE4(sc, CS4281_HICR, HICR_IEV | HICR_CHGM);
+ mutex_spin_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
+
return true;
}
diff --git a/sys/dev/pci/cs428x.c b/sys/dev/pci/cs428x.c
index 7c6aed9ac3f..b181f109ecf 100644
--- a/sys/dev/pci/cs428x.c
+++ b/sys/dev/pci/cs428x.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cs428x.c,v 1.15 2008/04/10 19:13:36 cegger Exp $ */
+/* $NetBSD: cs428x.c,v 1.16 2011/11/23 23:07:35 jmcneill Exp $ */
/*
* Copyright (c) 2000 Tatoku Ogaito. All rights reserved.
@@ -33,18 +33,16 @@
/* Common functions for CS4280 and CS4281 */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cs428x.c,v 1.15 2008/04/10 19:13:36 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cs428x.c,v 1.16 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
-
-#include <dev/pci/pcidevs.h>
-#include <dev/pci/pcivar.h>
-
#include <sys/audioio.h>
+#include <sys/bus.h>
+
#include <dev/audio_if.h>
#include <dev/midi_if.h>
#include <dev/mulaw.h>
@@ -53,8 +51,8 @@ __KERNEL_RCSID(0, "$NetBSD: cs428x.c,v 1.15 2008/04/10 19:13:36 cegger Exp $");
#include <dev/ic/ac97reg.h>
#include <dev/ic/ac97var.h>
-#include <sys/bus.h>
-
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcivar.h>
#include <dev/pci/cs428xreg.h>
#include <dev/pci/cs428x.h>
@@ -113,8 +111,7 @@ cs428x_query_devinfo(void *addr, mixer_devinfo_t *dip)
}
void *
-cs428x_malloc(void *addr, int direction, size_t size,
- struct malloc_type *pool, int flags)
+cs428x_malloc(void *addr, int direction, size_t size)
{
struct cs428x_softc *sc;
struct cs428x_dma *p;
@@ -122,14 +119,14 @@ cs428x_malloc(void *addr, int direction, size_t size,
sc = addr;
- p = malloc(sizeof(*p), pool, flags);
+ p = kmem_alloc(sizeof(*p), KM_SLEEP);
if (p == NULL)
return 0;
- error = cs428x_allocmem(sc, size, pool, flags, p);
+ error = cs428x_allocmem(sc, size, p);
if (error) {
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return 0;
}
@@ -139,7 +136,7 @@ cs428x_malloc(void *addr, int direction, size_t size,
}
void
-cs428x_free(void *addr, void *ptr, struct malloc_type *pool)
+cs428x_free(void *addr, void *ptr, size_t size)
{
struct cs428x_softc *sc;
struct cs428x_dma **pp, *p;
@@ -151,9 +148,9 @@ cs428x_free(void *addr, void *ptr, struct malloc_type *pool)
bus_dmamap_destroy(sc->sc_dmatag, p->map);
bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
- free(p->dum, pool);
+ kmem_free(p->dum, p->size);
*pp = p->next;
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return;
}
}
@@ -293,9 +290,7 @@ cs428x_write_codec(void *addr, uint8_t ac97_addr, uint16_t ac97_data)
/* Internal functions */
int
-cs428x_allocmem(struct cs428x_softc *sc,
- size_t size, struct malloc_type *pool, int flags,
- struct cs428x_dma *p)
+cs428x_allocmem(struct cs428x_softc *sc, size_t size, struct cs428x_dma *p)
{
int error;
size_t align;
@@ -303,13 +298,13 @@ cs428x_allocmem(struct cs428x_softc *sc,
align = sc->dma_align;
p->size = sc->dma_size;
/* allocate memory for upper audio driver */
- p->dum = malloc(size, pool, flags);
+ p->dum = kmem_alloc(size, KM_SLEEP);
if (p->dum == NULL)
return 1;
error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
- &p->nsegs, BUS_DMA_NOWAIT);
+ &p->nsegs, BUS_DMA_WAITOK);
if (error) {
aprint_error_dev(&sc->sc_dev, "unable to allocate DMA. error=%d\n",
error);
@@ -317,7 +312,7 @@ cs428x_allocmem(struct cs428x_softc *sc,
}
error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
- &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
+ &p->addr, BUS_DMA_WAITOK|BUS_DMA_COHERENT);
if (error) {
aprint_error_dev(&sc->sc_dev, "unable to map DMA, error=%d\n",
error);
@@ -325,7 +320,7 @@ cs428x_allocmem(struct cs428x_softc *sc,
}
error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
- 0, BUS_DMA_NOWAIT, &p->map);
+ 0, BUS_DMA_WAITOK, &p->map);
if (error) {
aprint_error_dev(&sc->sc_dev, "unable to create DMA map, error=%d\n",
error);
@@ -333,7 +328,7 @@ cs428x_allocmem(struct cs428x_softc *sc,
}
error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL,
- BUS_DMA_NOWAIT);
+ BUS_DMA_WAITOK);
if (error) {
aprint_error_dev(&sc->sc_dev, "unable to load DMA map, error=%d\n",
error);
@@ -348,7 +343,7 @@ cs428x_allocmem(struct cs428x_softc *sc,
free:
bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
allfree:
- free(p->dum, pool);
+ kmem_free(p->dum, size);
return error;
}
@@ -369,3 +364,13 @@ cs428x_src_wait(struct cs428x_softc *sc)
}
return 0;
}
+
+void
+cs428x_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct cs428x_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
diff --git a/sys/dev/pci/cs428x.h b/sys/dev/pci/cs428x.h
index 97cffe2a79b..a9fec33afbe 100644
--- a/sys/dev/pci/cs428x.h
+++ b/sys/dev/pci/cs428x.h
@@ -1,4 +1,4 @@
-/* $NetBSD: cs428x.h,v 1.14 2007/12/09 20:28:07 jmcneill Exp $ */
+/* $NetBSD: cs428x.h,v 1.15 2011/11/23 23:07:35 jmcneill Exp $ */
/*
* Copyright (c) 2000 Tatoku Ogaito. All rights reserved.
@@ -73,6 +73,8 @@ enum cs428x_flags {
*/
struct cs428x_softc {
struct device sc_dev;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
pci_chipset_tag_t sc_pc;
pcitag_t sc_pt;
@@ -179,14 +181,14 @@ int cs428x_write_codec(void *, u_int8_t, u_int16_t);
int cs428x_mixer_set_port(void *, mixer_ctrl_t *);
int cs428x_mixer_get_port(void *, mixer_ctrl_t *);
int cs428x_query_devinfo(void *, mixer_devinfo_t *);
-void *cs428x_malloc(void *, int, size_t, struct malloc_type *, int);
+void *cs428x_malloc(void *, int, size_t);
size_t cs428x_round_buffersize(void *, int, size_t);
-void cs428x_free(void *, void *, struct malloc_type *);
+void cs428x_free(void *, void *, size_t);
paddr_t cs428x_mappage(void *, void *, off_t, int);
+void cs428x_get_locks(void *, kmutex_t **, kmutex_t **);
/* internal functions */
-int cs428x_allocmem(struct cs428x_softc *, size_t, struct malloc_type *,
- int, struct cs428x_dma *);
+int cs428x_allocmem(struct cs428x_softc *, size_t, struct cs428x_dma *);
int cs428x_src_wait(struct cs428x_softc *);
diff --git a/sys/dev/pci/eap.c b/sys/dev/pci/eap.c
index ca9b9b69af1..e7016595d7c 100644
--- a/sys/dev/pci/eap.c
+++ b/sys/dev/pci/eap.c
@@ -1,13 +1,13 @@
-/* $NetBSD: eap.c,v 1.92 2008/04/28 20:23:54 martin Exp $ */
+/* $NetBSD: eap.c,v 1.93 2011/11/23 23:07:35 jmcneill Exp $ */
/* $OpenBSD: eap.c,v 1.6 1999/10/05 19:24:42 csapuntz Exp $ */
/*
- * Copyright (c) 1998, 1999, 2002 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 1999, 2002, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson <augustss@NetBSD.org>, Charles M. Hannum, and
- * Antti Kantee <pooka@NetBSD.org>.
+ * by Lennart Augustsson <augustss@NetBSD.org>, Charles M. Hannum,
+ * Antti Kantee <pooka@NetBSD.org>, and Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -51,7 +51,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: eap.c,v 1.92 2008/04/28 20:23:54 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: eap.c,v 1.93 2011/11/23 23:07:35 jmcneill Exp $");
#include "midi.h"
#include "joy_eap.h"
@@ -60,24 +60,21 @@ __KERNEL_RCSID(0, "$NetBSD: eap.c,v 1.92 2008/04/28 20:23:54 martin Exp $");
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/fcntl.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/select.h>
-
-#include <dev/pci/pcidevs.h>
-#include <dev/pci/pcivar.h>
-
+#include <sys/mutex.h>
+#include <sys/bus.h>
#include <sys/audioio.h>
+
#include <dev/audio_if.h>
#include <dev/midi_if.h>
#include <dev/audiovar.h>
#include <dev/mulaw.h>
#include <dev/auconv.h>
-#include <dev/ic/ac97var.h>
-
-#include <sys/bus.h>
+#include <dev/pci/pcidevs.h>
#include <dev/pci/eapreg.h>
#include <dev/pci/eapvar.h>
@@ -98,78 +95,6 @@ static void eap_attach(device_t, device_t, void *);
static int eap_detach(device_t, int);
static int eap_intr(void *);
-struct eap_dma {
- bus_dmamap_t map;
- void *addr;
- bus_dma_segment_t segs[1];
- int nsegs;
- size_t size;
- struct eap_dma *next;
-};
-
-#define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
-#define KERNADDR(p) ((void *)((p)->addr))
-
-/*
- * The card has two DACs. Using them is a bit twisted: we use DAC2
- * as default and DAC1 as the optional secondary DAC.
- */
-#define EAP_DAC1 1
-#define EAP_DAC2 0
-#define EAP_I1 EAP_DAC2
-#define EAP_I2 EAP_DAC1
-struct eap_instance {
- device_t parent;
- int index;
-
- void (*ei_pintr)(void *); /* DMA completion intr handler */
- void *ei_parg; /* arg for ei_intr() */
- device_t ei_audiodev; /* audio device, for detach */
-#ifdef DIAGNOSTIC
- char ei_prun;
-#endif
-};
-
-struct eap_softc {
- device_t sc_dev; /* base device */
- void *sc_ih; /* interrupt vectoring */
- bus_space_tag_t iot;
- bus_space_handle_t ioh;
- bus_size_t iosz;
- bus_dma_tag_t sc_dmatag; /* DMA tag */
-
- struct eap_dma *sc_dmas;
-
- void (*sc_rintr)(void *); /* DMA completion intr handler */
- void *sc_rarg; /* arg for sc_intr() */
-#ifdef DIAGNOSTIC
- char sc_rrun;
-#endif
-
-#if NMIDI > 0
- void (*sc_iintr)(void *, int); /* midi input ready handler */
- void (*sc_ointr)(void *); /* midi output ready handler */
- void *sc_arg;
- device_t sc_mididev;
-#endif
-#if NJOY_EAP > 0
- device_t sc_gameport;
-#endif
-
- u_short sc_port[AK_NPORTS]; /* mirror of the hardware setting */
- u_int sc_record_source; /* recording source mask */
- u_int sc_input_source; /* input source mask */
- u_int sc_mic_preamp;
- char sc_1371; /* Using ES1371/AC97 codec */
-
- struct ac97_codec_if *codec_if;
- struct ac97_host_if host_if;
-
- struct eap_instance sc_ei[2];
-
- pci_chipset_tag_t sc_pc; /* For detach */
-};
-
static int eap_allocmem(struct eap_softc *, size_t, size_t,
struct eap_dma *);
static int eap_freemem(struct eap_softc *, struct eap_dma *);
@@ -205,8 +130,8 @@ static int eap1370_mixer_get_port(void *, mixer_ctrl_t *);
static int eap1371_mixer_set_port(void *, mixer_ctrl_t *);
static int eap1371_mixer_get_port(void *, mixer_ctrl_t *);
static int eap1370_query_devinfo(void *, mixer_devinfo_t *);
-static void *eap_malloc(void *, int, size_t, struct malloc_type *, int);
-static void eap_free(void *, void *, struct malloc_type *);
+static void *eap_malloc(void *, int, size_t);
+static void eap_free(void *, void *, size_t);
static size_t eap_round_buffersize(void *, int, size_t);
static paddr_t eap_mappage(void *, void *, off_t, int);
static int eap_get_props(void *);
@@ -222,6 +147,8 @@ static int eap1371_attach_codec(void *, struct ac97_codec_if *);
static int eap1371_read_codec(void *, uint8_t, uint16_t *);
static int eap1371_write_codec(void *, uint8_t, uint16_t );
static int eap1371_reset_codec(void *);
+static void eap_get_locks(void *, kmutex_t **, kmutex_t **);
+
#if NMIDI > 0
static void eap_midi_close(void *);
static void eap_midi_getinfo(void *, struct midi_info *);
@@ -259,7 +186,7 @@ static const struct audio_hw_if eap1370_hw_if = {
eap_trigger_output,
eap_trigger_input,
NULL,
- NULL,
+ eap_get_locks,
};
static const struct audio_hw_if eap1371_hw_if = {
@@ -290,7 +217,7 @@ static const struct audio_hw_if eap1371_hw_if = {
eap_trigger_output,
eap_trigger_input,
NULL,
- NULL,
+ eap_get_locks,
};
#if NMIDI > 0
@@ -300,6 +227,7 @@ static const struct midi_hw_if eap_midi_hw_if = {
eap_midi_output,
eap_midi_getinfo,
0, /* ioctl */
+ eap_get_locks,
};
#endif
@@ -372,7 +300,7 @@ eap1370_write_codec(struct eap_softc *sc, int a, int d)
static inline void
eap1371_ready_codec(struct eap_softc *sc, uint8_t a, uint32_t wd)
{
- int to, s;
+ int to;
uint32_t src, t;
for (to = 0; to < EAP_WRITE_TIMEOUT; to++) {
@@ -384,7 +312,7 @@ eap1371_ready_codec(struct eap_softc *sc, uint8_t a, uint32_t wd)
aprint_error_dev(sc->sc_dev,
"eap1371_ready_codec timeout 1\n");
- s = splaudio();
+ mutex_spin_enter(&sc->sc_intr_lock);
src = eap1371_src_wait(sc) & E1371_SRC_CTLMASK;
EWRITE4(sc, E1371_SRC, src | E1371_SRC_STATE_OK);
@@ -413,7 +341,7 @@ eap1371_ready_codec(struct eap_softc *sc, uint8_t a, uint32_t wd)
eap1371_src_wait(sc);
EWRITE4(sc, E1371_SRC, src);
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
}
static int
@@ -518,7 +446,6 @@ eap1371_set_adc_rate(struct eap_softc *sc, int rate)
{
int freq, n, truncm;
int out;
- int s;
/* Whatever, it works, so I'll leave it :) */
@@ -541,7 +468,7 @@ eap1371_set_adc_rate(struct eap_softc *sc, int rate)
out = ESRC_SMF | ESRC_SET_TRUNC((119 - truncm) / 2);
}
out |= ESRC_SET_N(n);
- s = splaudio();
+ mutex_spin_enter(&sc->sc_intr_lock);
eap1371_src_write(sc, ESRC_ADC+ESRC_TRUNC_N, out);
out = eap1371_src_read(sc, ESRC_ADC+ESRC_IREGS) & 0xff;
@@ -550,7 +477,7 @@ eap1371_set_adc_rate(struct eap_softc *sc, int rate)
eap1371_src_write(sc, ESRC_ADC+ESRC_VFF, freq & 0x7fff);
eap1371_src_write(sc, ESRC_ADC_VOLL, ESRC_SET_ADC_VOL(n));
eap1371_src_write(sc, ESRC_ADC_VOLR, ESRC_SET_ADC_VOL(n));
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
}
static void
@@ -559,7 +486,6 @@ eap1371_set_dac_rate(struct eap_instance *ei, int rate)
struct eap_softc *sc;
int dac;
int freq, r;
- int s;
DPRINTFN(2, ("eap1371_set_dac_date: set rate for %d\n", ei->index));
sc = device_private(ei->parent);
@@ -573,7 +499,7 @@ eap1371_set_dac_rate(struct eap_instance *ei, int rate)
rate = 4000;
freq = ((rate << 15) + 1500) / 3000;
- s = splaudio();
+ mutex_spin_enter(&sc->sc_intr_lock);
eap1371_src_wait(sc);
r = EREAD4(sc, E1371_SRC) & (E1371_SRC_DISABLE |
E1371_SRC_DISP2 | E1371_SRC_DISP1 | E1371_SRC_DISREC);
@@ -586,7 +512,7 @@ eap1371_set_dac_rate(struct eap_instance *ei, int rate)
E1371_SRC_DISP2 | E1371_SRC_DISP1 | E1371_SRC_DISREC);
r &= ~(ei->index == EAP_DAC1 ? E1371_SRC_DISP1 : E1371_SRC_DISP2);
EWRITE4(sc, E1371_SRC, r);
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
}
static void
@@ -615,6 +541,9 @@ eap_attach(device_t parent, device_t self, void *aux)
revstr = "";
aprint_naive(": Audio controller\n");
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
/* Stash this away for detach */
sc->sc_pc = pc;
@@ -671,7 +600,7 @@ eap_attach(device_t parent, device_t self, void *aux)
return;
}
intrstr = pci_intr_string(pc, ih);
- sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, eap_intr, sc);
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_SCHED, eap_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(sc->sc_dev, "couldn't establish interrupt");
if (intrstr != NULL)
@@ -777,7 +706,7 @@ eap_attach(device_t parent, device_t self, void *aux)
sc->host_if.write = eap1371_write_codec;
sc->host_if.reset = eap1371_reset_codec;
- if (ac97_attach(&sc->host_if, self) == 0) {
+ if (ac97_attach(&sc->host_if, self, &sc->sc_lock) == 0) {
/* Interrupt enable */
EWRITE4(sc, EAP_SIC, EAP_P2_INTR_EN | EAP_R1_INTR_EN);
} else
@@ -849,6 +778,8 @@ eap_detach(device_t self, int flags)
bus_space_unmap(sc->iot, sc->ioh, sc->iosz);
pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return 0;
}
@@ -868,16 +799,15 @@ eap1371_reset_codec(void *sc_)
{
struct eap_softc *sc;
uint32_t icsc;
- int s;
sc = sc_;
- s = splaudio();
+ mutex_spin_enter(&sc->sc_intr_lock);
icsc = EREAD4(sc, EAP_ICSC);
EWRITE4(sc, EAP_ICSC, icsc | E1371_SYNC_RES);
delay(20);
EWRITE4(sc, EAP_ICSC, icsc & ~E1371_SYNC_RES);
delay(1);
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
}
@@ -889,9 +819,12 @@ eap_intr(void *p)
uint32_t intr, sic;
sc = p;
+ mutex_spin_enter(&sc->sc_intr_lock);
intr = EREAD4(sc, EAP_ICSS);
- if (!(intr & EAP_INTR))
+ if (!(intr & EAP_INTR)) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
+ }
sic = EREAD4(sc, EAP_SIC);
DPRINTFN(5, ("eap_intr: ICSS=0x%08x, SIC=0x%08x\n", intr, sic));
if (intr & EAP_I_ADC) {
@@ -957,6 +890,7 @@ eap_intr(void *p)
eap_uart_txrdy(sc);
}
#endif
+ mutex_spin_exit(&sc->sc_intr_lock);
return 1;
}
@@ -968,22 +902,22 @@ eap_allocmem(struct eap_softc *sc, size_t size, size_t align, struct eap_dma *p)
p->size = size;
error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
- &p->nsegs, BUS_DMA_NOWAIT);
+ &p->nsegs, BUS_DMA_WAITOK);
if (error)
return error;
error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
- &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
+ &p->addr, BUS_DMA_WAITOK|BUS_DMA_COHERENT);
if (error)
goto free;
error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
- 0, BUS_DMA_NOWAIT, &p->map);
+ 0, BUS_DMA_WAITOK, &p->map);
if (error)
goto unmap;
error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL,
- BUS_DMA_NOWAIT);
+ BUS_DMA_WAITOK);
if (error)
goto destroy;
return (0);
@@ -1786,22 +1720,21 @@ eap1370_query_devinfo(void *addr, mixer_devinfo_t *dip)
}
static void *
-eap_malloc(void *addr, int direction, size_t size,
- struct malloc_type *pool, int flags)
+eap_malloc(void *addr, int direction, size_t size)
{
struct eap_instance *ei;
struct eap_softc *sc;
struct eap_dma *p;
int error;
- p = malloc(sizeof(*p), pool, flags);
+ p = kmem_alloc(sizeof(*p), KM_SLEEP);
if (!p)
return NULL;
ei = addr;
sc = device_private(ei->parent);
error = eap_allocmem(sc, size, 16, p);
if (error) {
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return NULL;
}
p->next = sc->sc_dmas;
@@ -1810,7 +1743,7 @@ eap_malloc(void *addr, int direction, size_t size,
}
static void
-eap_free(void *addr, void *ptr, struct malloc_type *pool)
+eap_free(void *addr, void *ptr, size_t size)
{
struct eap_instance *ei;
struct eap_softc *sc;
@@ -1822,7 +1755,7 @@ eap_free(void *addr, void *ptr, struct malloc_type *pool)
if (KERNADDR(p) == ptr) {
eap_freemem(sc, p);
*pp = p->next;
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return;
}
}
@@ -1850,6 +1783,7 @@ eap_mappage(void *addr, void *mem, off_t off, int prot)
continue;
if (!p)
return -1;
+
return bus_dmamem_mmap(sc->sc_dmatag, p->segs, p->nsegs,
off, prot, BUS_DMA_WAITOK);
}
@@ -1862,6 +1796,18 @@ eap_get_props(void *addr)
AUDIO_PROP_FULLDUPLEX;
}
+static void
+eap_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct eap_instance *ei;
+ struct eap_softc *sc;
+
+ ei = addr;
+ sc = device_private(ei->parent);
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
#if NMIDI > 0
static int
eap_midi_open(void *addr, int flags,
@@ -1894,7 +1840,8 @@ eap_midi_close(void *addr)
struct eap_softc *sc;
sc = addr;
- tsleep(sc, PWAIT, "eapclm", hz/10); /* give uart a chance to drain */
+ /* give uart a chance to drain */
+ (void)kpause("eapclm", false, hz/10, &sc->sc_intr_lock);
EWRITE1(sc, EAP_UART_CONTROL, 0);
EWRITE4(sc, EAP_ICSC, EREAD4(sc, EAP_ICSC) & ~EAP_UART_EN);
diff --git a/sys/dev/pci/eapvar.h b/sys/dev/pci/eapvar.h
index c45c05d8b39..37b12f174c0 100644
--- a/sys/dev/pci/eapvar.h
+++ b/sys/dev/pci/eapvar.h
@@ -1,9 +1,88 @@
-/* $NetBSD: eapvar.h,v 1.3 2009/05/06 10:34:32 cegger Exp $ */
+/* $NetBSD: eapvar.h,v 1.4 2011/11/23 23:07:35 jmcneill Exp $ */
+
+#include <dev/pci/pcivar.h>
+
+#include <dev/ic/ac97var.h>
struct eap_gameport_args {
bus_space_tag_t gpa_iot;
bus_space_handle_t gpa_ioh;
};
+struct eap_dma {
+ bus_dmamap_t map;
+ void *addr;
+ bus_dma_segment_t segs[1];
+ int nsegs;
+ size_t size;
+ struct eap_dma *next;
+};
+
+#define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
+#define KERNADDR(p) ((void *)((p)->addr))
+
+/*
+ * The card has two DACs. Using them is a bit twisted: we use DAC2
+ * as default and DAC1 as the optional secondary DAC.
+ */
+#define EAP_DAC1 1
+#define EAP_DAC2 0
+#define EAP_I1 EAP_DAC2
+#define EAP_I2 EAP_DAC1
+struct eap_instance {
+ device_t parent;
+ int index;
+
+ void (*ei_pintr)(void *); /* DMA completion intr handler */
+ void *ei_parg; /* arg for ei_intr() */
+ device_t ei_audiodev; /* audio device, for detach */
+#ifdef DIAGNOSTIC
+ char ei_prun;
+#endif
+};
+
+struct eap_softc {
+ device_t sc_dev; /* base device */
+ void *sc_ih; /* interrupt vectoring */
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ bus_size_t iosz;
+ bus_dma_tag_t sc_dmatag; /* DMA tag */
+ kmutex_t sc_intr_lock;
+ kmutex_t sc_lock;
+
+ struct eap_dma *sc_dmas;
+
+ void (*sc_rintr)(void *); /* DMA completion intr handler */
+ void *sc_rarg; /* arg for sc_intr() */
+#ifdef DIAGNOSTIC
+ char sc_rrun;
+#endif
+
+#if NMIDI > 0
+ void (*sc_iintr)(void *, int); /* midi input ready handler */
+ void (*sc_ointr)(void *); /* midi output ready handler */
+ void *sc_arg;
+ device_t sc_mididev;
+#endif
+#if NJOY_EAP > 0
+ device_t sc_gameport;
+#endif
+
+ u_short sc_port[AK_NPORTS]; /* mirror of the hardware setting */
+ u_int sc_record_source; /* recording source mask */
+ u_int sc_input_source; /* input source mask */
+ u_int sc_mic_preamp;
+ char sc_1371; /* Using ES1371/AC97 codec */
+
+ struct ac97_codec_if *codec_if;
+ struct ac97_host_if host_if;
+
+ struct eap_instance sc_ei[2];
+
+ pci_chipset_tag_t sc_pc; /* For detach */
+};
+
+
device_t eap_joy_attach(device_t, struct eap_gameport_args *);
int eap_joy_detach(device_t, struct eap_gameport_args *);
diff --git a/sys/dev/pci/emuxki.c b/sys/dev/pci/emuxki.c
index 7c67772a3ed..78da57f43ca 100644
--- a/sys/dev/pci/emuxki.c
+++ b/sys/dev/pci/emuxki.c
@@ -1,11 +1,11 @@
-/* $NetBSD: emuxki.c,v 1.59 2009/11/26 15:17:09 njoly Exp $ */
+/* $NetBSD: emuxki.c,v 1.60 2011/11/23 23:07:35 jmcneill Exp $ */
/*-
- * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * Copyright (c) 2001, 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Yannick Montulet.
+ * by Yannick Montulet, and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -49,25 +49,29 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: emuxki.c,v 1.59 2009/11/26 15:17:09 njoly Exp $");
+__KERNEL_RCSID(0, "$NetBSD: emuxki.c,v 1.60 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/param.h>
#include <sys/device.h>
#include <sys/errno.h>
-#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/audioio.h>
#include <sys/select.h>
-#include <dev/pci/pcireg.h>
-#include <dev/pci/pcivar.h>
-#include <dev/pci/pcidevs.h>
+#include <sys/mutex.h>
+#include <sys/kmem.h>
+#include <sys/malloc.h>
+
#include <dev/audio_if.h>
#include <dev/audiovar.h>
#include <dev/auconv.h>
#include <dev/mulaw.h>
+
#include <dev/ic/ac97reg.h>
#include <dev/ic/ac97var.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
#include <dev/pci/emuxkireg.h>
#include <dev/pci/emuxkivar.h>
@@ -78,18 +82,16 @@ static int emuxki_detach(device_t, int);
/* DMA mem mgmt */
static struct dmamem *dmamem_alloc(bus_dma_tag_t, size_t, bus_size_t,
- int, struct malloc_type *, int);
-static void dmamem_free(struct dmamem *, struct malloc_type *);
+ int);
+static void dmamem_free(struct dmamem *);
/* Emu10k1 init & shutdown */
static int emuxki_init(struct emuxki_softc *);
static void emuxki_shutdown(struct emuxki_softc *);
/* Emu10k1 mem mgmt */
-static void *emuxki_pmem_alloc(struct emuxki_softc *, size_t,
- struct malloc_type *,int);
-static void *emuxki_rmem_alloc(struct emuxki_softc *, size_t,
- struct malloc_type *,int);
+static void *emuxki_pmem_alloc(struct emuxki_softc *, size_t);
+static void *emuxki_rmem_alloc(struct emuxki_softc *, size_t);
/*
* Emu10k1 channels funcs : There is no direct access to channels, everything
@@ -101,8 +103,9 @@ static void *emuxki_rmem_alloc(struct emuxki_softc *, size_t,
static struct emuxki_voice *emuxki_voice_new(struct emuxki_softc *,
uint8_t);
static void emuxki_voice_delete(struct emuxki_voice *);
-static int emuxki_voice_set_audioparms(struct emuxki_voice *, uint8_t,
- uint8_t, uint32_t);
+static int emuxki_voice_set_audioparms(struct emuxki_softc *,
+ struct emuxki_voice *, uint8_t,
+ uint8_t, uint32_t);
/* emuxki_voice_set_fxparms will come later, it'll need channel distinction */
static int emuxki_voice_set_bufparms(struct emuxki_voice *,
void *, uint32_t, uint16_t);
@@ -150,11 +153,12 @@ static int emuxki_set_port(void *, mixer_ctrl_t *);
static int emuxki_get_port(void *, mixer_ctrl_t *);
static int emuxki_query_devinfo(void *, mixer_devinfo_t *);
-static void *emuxki_allocm(void *, int, size_t, struct malloc_type *, int);
-static void emuxki_freem(void *, void *, struct malloc_type *);
+static void *emuxki_allocm(void *, int, size_t);
+static void emuxki_freem(void *, void *, size_t);
static paddr_t emuxki_mappage(void *, void *, off_t, int);
static int emuxki_get_props(void *);
+static void emuxki_get_locks(void *, kmutex_t **, kmutex_t **);
/* Interrupt handler */
static int emuxki_intr(void *);
@@ -200,7 +204,7 @@ static const struct audio_hw_if emuxki_hw_if = {
emuxki_trigger_output,
emuxki_trigger_input,
NULL, /* dev_ioctl */
- NULL, /* powerstate */
+ emuxki_get_locks,
};
#if 0
@@ -235,22 +239,20 @@ static const struct audio_format emuxki_formats[EMUXKI_NFORMATS] = {
*/
static void
-dmamem_delete(struct dmamem *mem, struct malloc_type *type)
+dmamem_delete(struct dmamem *mem)
{
- free(mem->segs, type);
- free(mem, type);
+ kmem_free(mem->segs, mem->nsegs * sizeof(*(mem->segs)));
+ kmem_free(mem, sizeof(*mem));
}
static struct dmamem *
-dmamem_alloc(bus_dma_tag_t dmat, size_t size, bus_size_t align,
- int nsegs, struct malloc_type *type, int flags)
+dmamem_alloc(bus_dma_tag_t dmat, size_t size, bus_size_t align, int nsegs)
{
struct dmamem *mem;
- int bus_dma_flags;
/* Allocate memory for structure */
- if ((mem = malloc(sizeof(*mem), type, flags)) == NULL)
+ if ((mem = kmem_alloc(sizeof(*mem), KM_SLEEP)) == NULL)
return NULL;
mem->dmat = dmat;
mem->size = size;
@@ -258,41 +260,40 @@ dmamem_alloc(bus_dma_tag_t dmat, size_t size, bus_size_t align,
mem->nsegs = nsegs;
mem->bound = 0;
- mem->segs = malloc(mem->nsegs * sizeof(*(mem->segs)), type, flags);
+ mem->segs = kmem_alloc(mem->nsegs * sizeof(*(mem->segs)), KM_SLEEP);
if (mem->segs == NULL) {
- free(mem, type);
+ kmem_free(mem, sizeof(*mem));
return NULL;
}
- bus_dma_flags = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
if (bus_dmamem_alloc(dmat, mem->size, mem->align, mem->bound,
mem->segs, mem->nsegs, &(mem->rsegs),
- bus_dma_flags)) {
- dmamem_delete(mem, type);
+ BUS_DMA_WAITOK)) {
+ dmamem_delete(mem);
return NULL;
}
if (bus_dmamem_map(dmat, mem->segs, mem->nsegs, mem->size,
- &(mem->kaddr), bus_dma_flags | BUS_DMA_COHERENT)) {
+ &(mem->kaddr), BUS_DMA_WAITOK | BUS_DMA_COHERENT)) {
bus_dmamem_free(dmat, mem->segs, mem->nsegs);
- dmamem_delete(mem, type);
+ dmamem_delete(mem);
return NULL;
}
if (bus_dmamap_create(dmat, mem->size, mem->nsegs, mem->size,
- mem->bound, bus_dma_flags, &(mem->map))) {
+ mem->bound, BUS_DMA_WAITOK, &(mem->map))) {
bus_dmamem_unmap(dmat, mem->kaddr, mem->size);
bus_dmamem_free(dmat, mem->segs, mem->nsegs);
- dmamem_delete(mem, type);
+ dmamem_delete(mem);
return NULL;
}
if (bus_dmamap_load(dmat, mem->map, mem->kaddr,
- mem->size, NULL, bus_dma_flags)) {
+ mem->size, NULL, BUS_DMA_WAITOK)) {
bus_dmamap_destroy(dmat, mem->map);
bus_dmamem_unmap(dmat, mem->kaddr, mem->size);
bus_dmamem_free(dmat, mem->segs, mem->nsegs);
- dmamem_delete(mem, type);
+ dmamem_delete(mem);
return NULL;
}
@@ -300,14 +301,14 @@ dmamem_alloc(bus_dma_tag_t dmat, size_t size, bus_size_t align,
}
static void
-dmamem_free(struct dmamem *mem, struct malloc_type *type)
+dmamem_free(struct dmamem *mem)
{
bus_dmamap_unload(mem->dmat, mem->map);
bus_dmamap_destroy(mem->dmat, mem->map);
bus_dmamem_unmap(mem->dmat, mem->kaddr, mem->size);
bus_dmamem_free(mem->dmat, mem->segs, mem->nsegs);
- dmamem_delete(mem, type);
+ dmamem_delete(mem);
}
@@ -376,7 +377,7 @@ emuxki_ac97_init(struct emuxki_softc *sc)
sc->hostif.write = emuxki_ac97_write;
sc->hostif.reset = emuxki_ac97_reset;
sc->hostif.flags = emuxki_ac97_flags;
- return ac97_attach(&sc->hostif, sc->sc_dev);
+ return ac97_attach(&sc->hostif, sc->sc_dev, &sc->sc_lock);
}
static int
@@ -412,6 +413,11 @@ emuxki_attach(device_t parent, device_t self, void *aux)
pa = aux;
aprint_naive(": Audio controller\n");
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+ mutex_init(&sc->sc_index_lock, MUTEX_DEFAULT, IPL_SCHED);
+ mutex_init(&sc->sc_ac97_index_lock, MUTEX_DEFAULT, IPL_SCHED);
+
if (pci_mapreg_map(pa, EMU_PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
&(sc->sc_iot), &(sc->sc_ioh), &(sc->sc_iob),
&(sc->sc_ios))) {
@@ -434,7 +440,7 @@ emuxki_attach(device_t parent, device_t self, void *aux)
}
intrstr = pci_intr_string(pa->pa_pc, ih);
- sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, emuxki_intr,
+ sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_SCHED, emuxki_intr,
sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(self, "couldn't establish interrupt");
@@ -473,10 +479,12 @@ emuxki_attach(device_t parent, device_t self, void *aux)
return;
}
#if 0
+ mutex_enter(&sc->lock);
sc->rsourcectl.dev =
sc->codecif->vtbl->get_portnum_by_name(sc->codec_if, AudioCrecord,
AudioNsource, NULL);
sc->rsourcectl.cp = AUDIO_MIXER_ENUM;
+ mutex_exit(&sc->lock);
#endif
}
@@ -496,10 +504,17 @@ emuxki_detach(device_t self, int flags)
EMU_HCFG_MUTEBUTTONENABLE);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_INTE, 0);
+ mutex_enter(&sc->sc_lock);
emuxki_shutdown(sc);
+ mutex_exit(&sc->sc_lock);
emuxki_pci_shutdown(sc);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
+ mutex_destroy(&sc->sc_index_lock);
+ mutex_destroy(&sc->sc_ac97_index_lock);
+
return 0;
}
@@ -573,7 +588,6 @@ emuxki_read(struct emuxki_softc *sc, uint16_t chano, uint32_t reg)
{
uint32_t ptr, mask;
uint8_t size, offset;
- int s;
mask = 0xffffffff;
offset = 0;
@@ -587,11 +601,11 @@ emuxki_read(struct emuxki_softc *sc, uint16_t chano, uint32_t reg)
mask = ((1 << size) - 1) << offset;
}
- s = splaudio();
+ mutex_spin_enter(&sc->sc_index_lock);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_PTR, ptr);
ptr = (bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_DATA) & mask)
>> offset;
- splx(s);
+ mutex_spin_exit(&sc->sc_index_lock);
return ptr;
}
@@ -602,7 +616,6 @@ emuxki_write(struct emuxki_softc *sc, uint16_t chano,
{
uint32_t ptr, mask;
uint8_t size, offset;
- int s;
ptr = ((((u_int32_t) reg) << 16) &
(sc->sc_type & EMUXKI_AUDIGY ?
@@ -616,10 +629,10 @@ emuxki_write(struct emuxki_softc *sc, uint16_t chano,
(emuxki_read(sc, chano, reg & 0xffff) & ~mask);
}
- s = splaudio();
+ mutex_spin_enter(&sc->sc_index_lock);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_PTR, ptr);
bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_DATA, data);
- splx(s);
+ mutex_spin_exit(&sc->sc_index_lock);
}
/* Microcode should this go in /sys/dev/microcode ? */
@@ -842,14 +855,13 @@ emuxki_init(struct emuxki_softc *sc)
/* Here is our Page Table */
if ((sc->ptb = dmamem_alloc(sc->sc_dmat,
EMU_MAXPTE * sizeof(u_int32_t),
- EMU_DMA_ALIGN, EMU_DMAMEM_NSEG,
- M_DEVBUF, M_WAITOK)) == NULL)
+ EMU_DMA_ALIGN, EMU_DMAMEM_NSEG)) == NULL)
return ENOMEM;
/* This is necessary unless you like Metallic noise... */
if ((sc->silentpage = dmamem_alloc(sc->sc_dmat, EMU_PTESIZE,
- EMU_DMA_ALIGN, EMU_DMAMEM_NSEG, M_DEVBUF, M_WAITOK))==NULL){
- dmamem_free(sc->ptb, M_DEVBUF);
+ EMU_DMA_ALIGN, EMU_DMAMEM_NSEG))==NULL){
+ dmamem_free(sc->ptb);
return ENOMEM;
}
@@ -944,43 +956,41 @@ emuxki_shutdown(struct emuxki_softc *sc)
emuxki_write(sc, 0, EMU_DBG, 0x8000); /* necessary ? */
- dmamem_free(sc->silentpage, M_DEVBUF);
- dmamem_free(sc->ptb, M_DEVBUF);
+ dmamem_free(sc->silentpage);
+ dmamem_free(sc->ptb);
}
/* Emu10k1 Memory management */
static struct emuxki_mem *
-emuxki_mem_new(struct emuxki_softc *sc, int ptbidx,
- size_t size, struct malloc_type *type, int flags)
+emuxki_mem_new(struct emuxki_softc *sc, int ptbidx, size_t size)
{
struct emuxki_mem *mem;
- if ((mem = malloc(sizeof(*mem), type, flags)) == NULL)
+ if ((mem = kmem_alloc(sizeof(*mem), KM_SLEEP)) == NULL)
return NULL;
mem->ptbidx = ptbidx;
if ((mem->dmamem = dmamem_alloc(sc->sc_dmat, size, EMU_DMA_ALIGN,
- EMU_DMAMEM_NSEG, type, flags)) == NULL) {
- free(mem, type);
+ EMU_DMAMEM_NSEG)) == NULL) {
+ kmem_free(mem, sizeof(*mem));
return NULL;
}
return mem;
}
static void
-emuxki_mem_delete(struct emuxki_mem *mem, struct malloc_type *type)
+emuxki_mem_delete(struct emuxki_mem *mem, size_t size)
{
- dmamem_free(mem->dmamem, type);
- free(mem, type);
+ dmamem_free(mem->dmamem);
+ kmem_free(mem, sizeof(*mem));
}
static void *
-emuxki_pmem_alloc(struct emuxki_softc *sc, size_t size,
- struct malloc_type *type, int flags)
+emuxki_pmem_alloc(struct emuxki_softc *sc, size_t size)
{
- int i, j, s;
+ int i, j;
size_t numblocks;
struct emuxki_mem *mem;
uint32_t *ptb, silentpage;
@@ -991,48 +1001,48 @@ emuxki_pmem_alloc(struct emuxki_softc *sc, size_t size,
if (size % EMU_PTESIZE)
numblocks++;
- for (i = 0; i < EMU_MAXPTE; i++)
+ for (i = 0; i < EMU_MAXPTE; i++) {
+ mutex_spin_enter(&sc->sc_intr_lock);
if ((le32toh(ptb[i]) & EMU_CHAN_MAP_PTE_MASK) == silentpage) {
/* We look for a free PTE */
- s = splaudio();
for (j = 0; j < numblocks; j++)
if ((le32toh(ptb[i + j])
& EMU_CHAN_MAP_PTE_MASK) != silentpage)
break;
if (j == numblocks) {
+ mutex_spin_exit(&sc->sc_intr_lock);
if ((mem = emuxki_mem_new(sc, i,
- size, type, flags)) == NULL) {
- splx(s);
+ size)) == NULL) {
return NULL;
}
+ mutex_spin_enter(&sc->sc_intr_lock);
for (j = 0; j < numblocks; j++)
ptb[i + j] =
htole32((((DMAADDR(mem->dmamem) +
j * EMU_PTESIZE)) << 1) | (i + j));
LIST_INSERT_HEAD(&(sc->mem), mem, next);
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
return (KERNADDR(mem->dmamem));
} else
i += j;
- splx(s);
}
+ mutex_spin_exit(&sc->sc_intr_lock);
+ }
return NULL;
}
static void *
-emuxki_rmem_alloc(struct emuxki_softc *sc, size_t size,
- struct malloc_type *type, int flags)
+emuxki_rmem_alloc(struct emuxki_softc *sc, size_t size)
{
struct emuxki_mem *mem;
- int s;
- mem = emuxki_mem_new(sc, EMU_RMEM, size, type, flags);
+ mem = emuxki_mem_new(sc, EMU_RMEM, size);
if (mem == NULL)
return NULL;
- s = splaudio();
+ mutex_spin_enter(&sc->sc_intr_lock);
LIST_INSERT_HEAD(&(sc->mem), mem, next);
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
return KERNADDR(mem->dmamem);
}
@@ -1230,7 +1240,6 @@ emuxki_channel_commit_parms(struct emuxki_channel *chan)
struct emuxki_softc *sc;
uint32_t start, mapval;
uint8_t chano;
- int s;
voice = chan->voice;
sc = voice->sc;
@@ -1239,7 +1248,7 @@ emuxki_channel_commit_parms(struct emuxki_channel *chan)
(voice->stereo ? 28 : 30) * (voice->b16 + 1);
mapval = DMAADDR(sc->silentpage) << 1 | EMU_CHAN_MAP_PTI_MASK;
- s = splaudio();
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
emuxki_write(sc, chano, EMU_CHAN_CPF_STEREO, voice->stereo);
emuxki_channel_commit_fx(chan);
@@ -1284,7 +1293,6 @@ emuxki_channel_commit_parms(struct emuxki_channel *chan)
emuxki_write(sc, chano, EMU_CHAN_PEFE,
(chan->pitch.envelope_amount << 8) |
chan->filter.envelope_amount);
- splx(s);
}
static void
@@ -1294,7 +1302,6 @@ emuxki_channel_start(struct emuxki_channel *chan)
struct emuxki_softc *sc;
u_int8_t cache_sample, cache_invalid_size, chano;
u_int32_t sample;
- int s;
voice = chan->voice;
sc = voice->sc;
@@ -1303,7 +1310,7 @@ emuxki_channel_start(struct emuxki_channel *chan)
sample = voice->b16 ? 0x00000000 : 0x80808080;
cache_invalid_size = (voice->stereo ? 28 : 30) * (voice->b16 + 1);
- s = splaudio();
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
while (cache_sample--) {
emuxki_write(sc, chano, EMU_CHAN_CD0 + cache_sample,
sample);
@@ -1333,27 +1340,23 @@ emuxki_channel_start(struct emuxki_channel *chan)
emuxki_write(sc, chano, EMU_CHAN_CPF_PITCH,
chan->pitch.current);
emuxki_write(sc, chano, EMU_CHAN_IP, chan->pitch.initial);
-
- splx(s);
}
static void
emuxki_channel_stop(struct emuxki_channel *chan)
{
struct emuxki_softc *sc;
- int s;
u_int8_t chano;
sc = chan->voice->sc;
chano = chan->num;
- s = splaudio();
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
emuxki_write(sc, chano, EMU_CHAN_PTRX_PITCHTARGET, 0);
emuxki_write(sc, chano, EMU_CHAN_CPF_PITCH, 0);
emuxki_write(sc, chano, EMU_CHAN_IFATN_ATTENUATION, 0xff);
emuxki_write(sc, chano, EMU_CHAN_VTFT_VOLUMETARGET, 0);
emuxki_write(sc, chano, EMU_CHAN_CVCF_CURRVOL, 0);
emuxki_write(sc, chano, EMU_CHAN_IP, 0);
- splx(s);
}
/*
@@ -1368,7 +1371,6 @@ static int
emuxki_voice_channel_create(struct emuxki_voice *voice)
{
struct emuxki_channel **channel;
- int s;
uint8_t i, stereo;
channel = voice->sc->channel;
@@ -1377,14 +1379,12 @@ emuxki_voice_channel_create(struct emuxki_voice *voice)
if ((stereo && (channel[i + 1] != NULL)) ||
(channel[i] != NULL)) /* Looking for free channels */
continue;
- s = splaudio();
+
if (stereo) {
voice->dataloc.chan[1] =
emuxki_channel_new(voice, i + 1);
- if (voice->dataloc.chan[1] == NULL) {
- splx(s);
+ if (voice->dataloc.chan[1] == NULL)
return ENOMEM;
- }
}
voice->dataloc.chan[0] = emuxki_channel_new(voice, i);
if (voice->dataloc.chan[0] == NULL) {
@@ -1392,10 +1392,8 @@ emuxki_voice_channel_create(struct emuxki_voice *voice)
emuxki_channel_delete(voice->dataloc.chan[1]);
voice->dataloc.chan[1] = NULL;
}
- splx(s);
return ENOMEM;
}
- splx(s);
return 0;
}
return EAGAIN;
@@ -1478,19 +1476,23 @@ static struct emuxki_voice *
emuxki_voice_new(struct emuxki_softc *sc, uint8_t use)
{
struct emuxki_voice *voice;
- int s;
- s = splaudio();
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
voice = sc->lvoice;
sc->lvoice = NULL;
- splx(s);
if (!voice) {
- if (!(voice = malloc(sizeof(*voice), M_DEVBUF, M_WAITOK)))
+ mutex_exit(&sc->sc_intr_lock);
+ voice = kmem_alloc(sizeof(*voice), KM_SLEEP);
+ mutex_enter(&sc->sc_intr_lock);
+ if (!voice)
return NULL;
- } else if (voice->use != use)
+ } else if (voice->use != use) {
+ mutex_exit(&sc->sc_intr_lock);
emuxki_voice_dataloc_destroy(voice);
- else
+ mutex_enter(&sc->sc_intr_lock);
+ } else
goto skip_initialize;
voice->sc = sc;
@@ -1511,9 +1513,7 @@ emuxki_voice_new(struct emuxki_softc *sc, uint8_t use)
voice->use = use;
skip_initialize:
- s = splaudio();
LIST_INSERT_HEAD((&sc->voices), voice, next);
- splx(s);
return voice;
}
@@ -1523,26 +1523,26 @@ emuxki_voice_delete(struct emuxki_voice *voice)
{
struct emuxki_softc *sc;
struct emuxki_voice *lvoice;
- int s;
sc = voice->sc;
if (voice->state & EMU_VOICE_STATE_STARTED)
emuxki_voice_halt(voice);
- s = splaudio();
LIST_REMOVE(voice, next);
lvoice = sc->lvoice;
sc->lvoice = voice;
- splx(s);
if (lvoice) {
+ mutex_exit(&sc->sc_lock);
emuxki_voice_dataloc_destroy(lvoice);
- free(lvoice, M_DEVBUF);
+ kmem_free(lvoice, sizeof(*lvoice));
+ mutex_enter(&sc->sc_lock);
}
}
static int
-emuxki_voice_set_stereo(struct emuxki_voice *voice, uint8_t stereo)
+emuxki_voice_set_stereo(struct emuxki_softc *sc,
+ struct emuxki_voice *voice, uint8_t stereo)
{
int error;
emuxki_recsrc_t source;
@@ -1551,11 +1551,14 @@ emuxki_voice_set_stereo(struct emuxki_voice *voice, uint8_t stereo)
source = 0; /* XXX: gcc */
if (! (voice->use & EMU_VOICE_USE_PLAY))
source = voice->dataloc.source;
+ mutex_exit(&sc->sc_lock);
emuxki_voice_dataloc_destroy(voice);
if (! (voice->use & EMU_VOICE_USE_PLAY))
voice->dataloc.source = source;
voice->stereo = stereo;
- if ((error = emuxki_voice_dataloc_create(voice)))
+ error = emuxki_voice_dataloc_create(voice);
+ mutex_enter(&sc->sc_lock);
+ if (error)
return error;
if (voice->use & EMU_VOICE_USE_PLAY) {
fxsend.a.dest = 0x0;
@@ -1610,8 +1613,8 @@ emuxki_voice_set_srate(struct emuxki_voice *voice, uint32_t srate)
}
static int
-emuxki_voice_set_audioparms(struct emuxki_voice *voice, uint8_t stereo,
- uint8_t b16, uint32_t srate)
+emuxki_voice_set_audioparms(struct emuxki_softc *sc,
+ struct emuxki_voice *voice, uint8_t stereo, uint8_t b16, uint32_t srate)
{
int error;
@@ -1626,7 +1629,7 @@ emuxki_voice_set_audioparms(struct emuxki_voice *voice, uint8_t stereo,
#endif
error = 0;
if (voice->stereo != stereo) {
- if ((error = emuxki_voice_set_stereo(voice, stereo)))
+ if ((error = emuxki_voice_set_stereo(sc, voice, stereo)))
return error;
}
voice->b16 = b16;
@@ -1765,11 +1768,10 @@ emuxki_resched_timer(struct emuxki_softc *sc)
struct emuxki_voice *voice;
uint16_t timerate;
uint8_t active;
- int s;
timerate = 1024;
active = 0;
- s = splaudio();
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
LIST_FOREACH(voice, &sc->voices, next) {
if ((voice->state & EMU_VOICE_STATE_STARTED) == 0)
continue;
@@ -1792,7 +1794,6 @@ emuxki_resched_timer(struct emuxki_softc *sc)
EMU_INTE_INTERTIMERENB);
sc->timerstate |= EMU_TIMER_STATE_ENABLED;
}
- splx(s);
}
static int
@@ -1898,12 +1899,10 @@ emuxki_voice_start(struct emuxki_voice *voice,
case EMU_RECSRC_FX:
case EMU_RECSRC_MIC:
/* DMA completion interrupt is useless; use timer */
- int s;
- s = splaudio();
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
val = emu_rd(sc, INTE, 4);
val |= emuxki_recsrc_intrmasks[voice->dataloc.source];
emu_wr(sc, INTE, val, 4);
- splx(s);
break;
default:
break;
@@ -1947,12 +1946,10 @@ emuxki_voice_halt(struct emuxki_voice *voice)
emuxki_recsrc_szreg[voice->dataloc.source],
EMU_RECBS_BUFSIZE_NONE);
#if 0
- int s;
- s = splaudio();
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
val = emu_rd(sc, INTE, 4);
val &= ~emuxki_recsrc_intrmasks[voice->dataloc.source];
emu_wr(sc, INTE, val, 4);
- splx(s);
#endif
break;
default:
@@ -1976,6 +1973,9 @@ emuxki_intr(void *arg)
sc = arg;
claim = 0;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
+
while ((ipr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_IPR))) {
if (ipr & EMU_IPR_INTERVALTIMER) {
LIST_FOREACH(voice, &sc->voices, next) {
@@ -2010,6 +2010,8 @@ emuxki_intr(void *arg)
claim = 1;
}
+ mutex_spin_exit(&sc->sc_intr_lock);
+
return claim;
}
@@ -2150,8 +2152,8 @@ emuxki_query_encoding(void *addr, struct audio_encoding *fp)
}
static int
-emuxki_set_vparms(struct emuxki_voice *voice, const audio_params_t *p,
- stream_filter_list_t *fil)
+emuxki_set_vparms(struct emuxki_softc *sc, struct emuxki_voice *voice,
+ const audio_params_t *p, stream_filter_list_t *fil)
{
int mode, i;
@@ -2163,8 +2165,8 @@ emuxki_set_vparms(struct emuxki_voice *voice, const audio_params_t *p,
return EINVAL;
if (fil->req_size > 0)
p = &fil->filters[0].param;
- return emuxki_voice_set_audioparms
- (voice, p->channels == 2, p->precision == 16, p->sample_rate);
+ return emuxki_voice_set_audioparms(sc, voice, p->channels == 2,
+ p->precision == 16, p->sample_rate);
}
static int
@@ -2198,7 +2200,7 @@ emuxki_set_params(void *addr, int setmode, int usemode, audio_params_t *play,
}
/* No multiple voice support for now */
- if ((error = emuxki_set_vparms(v, p, fil)))
+ if ((error = emuxki_set_vparms(sc, v, p, fil)))
return error;
}
@@ -2274,23 +2276,22 @@ emuxki_query_devinfo(void *addr, mixer_devinfo_t *minfo)
}
static void *
-emuxki_allocm(void *addr, int direction, size_t size,
- struct malloc_type *type, int flags)
+emuxki_allocm(void *addr, int direction, size_t size)
{
if (direction == AUMODE_PLAY)
- return emuxki_pmem_alloc(addr, size, type, flags);
+ return emuxki_pmem_alloc(addr, size);
else
- return emuxki_rmem_alloc(addr, size, type, flags);
+ return emuxki_rmem_alloc(addr, size);
}
static void
-emuxki_freem(void *addr, void *ptr, struct malloc_type *type)
+emuxki_freem(void *addr, void *ptr, size_t size)
{
struct emuxki_softc *sc;
struct emuxki_mem *mem;
uint32_t *ptb, silentpage;
size_t numblocks;
- int i, s;
+ int i;
sc = addr;
ptb = KERNADDR(sc->ptb);
@@ -2299,7 +2300,7 @@ emuxki_freem(void *addr, void *ptr, struct malloc_type *type)
if (KERNADDR(mem->dmamem) != ptr)
continue;
- s = splaudio();
+ mutex_spin_enter(&sc->sc_intr_lock);
if (mem->ptbidx != EMU_RMEM) {
numblocks = DMASIZE(mem->dmamem) / EMU_PTESIZE;
if (DMASIZE(mem->dmamem) % EMU_PTESIZE)
@@ -2309,9 +2310,9 @@ emuxki_freem(void *addr, void *ptr, struct malloc_type *type)
htole32(silentpage | (mem->ptbidx + i));
}
LIST_REMOVE(mem, next);
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
- emuxki_mem_delete(mem, type);
+ emuxki_mem_delete(mem, size);
break;
}
}
@@ -2388,6 +2389,8 @@ emuxki_mappage(void *addr, void *ptr, off_t off, int prot)
struct emuxki_mem *mem;
sc = addr;
+
+ mutex_exit(&sc->sc_lock);
LIST_FOREACH(mem, &sc->mem, next) {
if (KERNADDR(mem->dmamem) == ptr) {
struct dmamem *dm = mem->dmamem;
@@ -2396,6 +2399,7 @@ emuxki_mappage(void *addr, void *ptr, off_t off, int prot)
off, prot, BUS_DMA_WAITOK);
}
}
+ mutex_enter(&sc->sc_lock);
return -1;
}
@@ -2420,7 +2424,7 @@ emuxki_trigger_output(void *addr, void *start, void *end, int blksize,
voice = sc->pvoice;
if (voice == NULL)
return ENXIO;
- if ((error = emuxki_voice_set_audioparms(voice, params->channels == 2,
+ if ((error = emuxki_voice_set_audioparms(sc, voice, params->channels == 2,
params->precision == 16, params->sample_rate)))
return error;
if ((error = emuxki_voice_set_bufparms(voice, start,
@@ -2445,8 +2449,9 @@ emuxki_trigger_input(void *addr, void *start, void *end, int blksize,
voice = sc->rvoice;
if (voice == NULL)
return ENXIO;
- if ((error = emuxki_voice_set_audioparms(voice, params->channels == 2,
- params->precision == 16, params->sample_rate)))
+ if ((error = emuxki_voice_set_audioparms(sc, voice,
+ params->channels == 2, params->precision == 16,
+ params->sample_rate)))
return error;
if ((error = emuxki_voice_set_bufparms(voice, start,
(char *)end - (char *)start, blksize)))
@@ -2474,13 +2479,12 @@ static int
emuxki_ac97_read(void *arg, uint8_t reg, uint16_t *val)
{
struct emuxki_softc *sc;
- int s;
sc = arg;
- s = splaudio();
+ mutex_spin_enter(&sc->sc_ac97_index_lock);
bus_space_write_1(sc->sc_iot, sc->sc_ioh, EMU_AC97ADDR, reg);
*val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, EMU_AC97DATA);
- splx(s);
+ mutex_spin_exit(&sc->sc_ac97_index_lock);
return 0;
}
@@ -2489,13 +2493,12 @@ static int
emuxki_ac97_write(void *arg, uint8_t reg, uint16_t val)
{
struct emuxki_softc *sc;
- int s;
sc = arg;
- s = splaudio();
+ mutex_spin_enter(&sc->sc_ac97_index_lock);
bus_space_write_1(sc->sc_iot, sc->sc_ioh, EMU_AC97ADDR, reg);
bus_space_write_2(sc->sc_iot, sc->sc_ioh, EMU_AC97DATA, val);
- splx(s);
+ mutex_spin_exit(&sc->sc_ac97_index_lock);
return 0;
}
@@ -2513,3 +2516,13 @@ emuxki_ac97_flags(void *arg)
return AC97_HOST_SWAPPED_CHANNELS;
}
+
+static void
+emuxki_get_locks(void *arg, kmutex_t **intr, kmutex_t **proc)
+{
+ struct emuxki_softc *sc;
+
+ sc = arg;
+ *intr = &sc->sc_intr_lock;
+ *proc = &sc->sc_lock;
+}
diff --git a/sys/dev/pci/emuxkivar.h b/sys/dev/pci/emuxkivar.h
index 29f96f4b8a4..182cc1d6620 100644
--- a/sys/dev/pci/emuxkivar.h
+++ b/sys/dev/pci/emuxkivar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: emuxkivar.h,v 1.12 2009/06/09 11:01:18 tsutsui Exp $ */
+/* $NetBSD: emuxkivar.h,v 1.13 2011/11/23 23:07:35 jmcneill Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -233,6 +233,10 @@ struct emuxki_softc {
pci_chipset_tag_t sc_pc; /* PCI tag */
bus_dma_tag_t sc_dmat;
void *sc_ih; /* interrupt handler */
+ kmutex_t sc_intr_lock;
+ kmutex_t sc_lock;
+ kmutex_t sc_index_lock;
+ kmutex_t sc_ac97_index_lock;
/* EMU10K1 device structures */
LIST_HEAD(, emuxki_mem) mem;
diff --git a/sys/dev/pci/esa.c b/sys/dev/pci/esa.c
index 0bb5533b505..2c2f291ed63 100644
--- a/sys/dev/pci/esa.c
+++ b/sys/dev/pci/esa.c
@@ -1,4 +1,4 @@
-/* $NetBSD: esa.c,v 1.54 2010/02/24 22:38:00 dyoung Exp $ */
+/* $NetBSD: esa.c,v 1.55 2011/11/23 23:07:35 jmcneill Exp $ */
/*
* Copyright (c) 2001-2008 Jared D. McNeill <jmcneill@invisible.ca>
@@ -39,32 +39,31 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: esa.c,v 1.54 2010/02/24 22:38:00 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: esa.c,v 1.55 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/null.h>
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
#include <sys/conf.h>
#include <sys/exec.h>
#include <sys/select.h>
#include <sys/audioio.h>
-
#include <sys/bus.h>
#include <sys/intr.h>
-#include <dev/pci/pcidevs.h>
-#include <dev/pci/pcivar.h>
-
#include <dev/audio_if.h>
#include <dev/mulaw.h>
#include <dev/auconv.h>
+
#include <dev/ic/ac97var.h>
#include <dev/ic/ac97reg.h>
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcivar.h>
#include <dev/pci/esareg.h>
#include <dev/pci/esadsp.h>
#include <dev/pci/esavar.h>
@@ -117,9 +116,8 @@ static int esa_halt_input(void *);
static int esa_set_port(void *, mixer_ctrl_t *);
static int esa_get_port(void *, mixer_ctrl_t *);
static int esa_query_devinfo(void *, mixer_devinfo_t *);
-static void * esa_malloc(void *, int, size_t, struct malloc_type *,
- int);
-static void esa_free(void *, void *, struct malloc_type *);
+static void * esa_malloc(void *, int, size_t);
+static void esa_free(void *, void *, size_t);
static int esa_getdev(void *, struct audio_device *);
static size_t esa_round_buffersize(void *, int, size_t);
static int esa_get_props(void *);
@@ -129,6 +127,7 @@ static int esa_trigger_output(void *, void *, void *, int,
static int esa_trigger_input(void *, void *, void *, int,
void (*)(void *), void *,
const audio_params_t *);
+static void esa_get_locks(void *, kmutex_t **, kmutex_t **);
static int esa_intr(void *);
static int esa_allocmem(struct esa_softc *, size_t, size_t,
@@ -224,7 +223,7 @@ static const struct audio_hw_if esa_hw_if = {
esa_trigger_output,
esa_trigger_input,
NULL, /* dev_ioctl */
- NULL, /* powerstate */
+ esa_get_locks,
};
CFATTACH_DECL2_NEW(esa, sizeof(struct esa_softc), esa_match, esa_attach,
@@ -456,22 +455,21 @@ esa_halt_input(void *hdl)
}
static void *
-esa_malloc(void *hdl, int direction, size_t size,
- struct malloc_type *type, int flags)
+esa_malloc(void *hdl, int direction, size_t size)
{
struct esa_voice *vc;
struct esa_softc *sc;
struct esa_dma *p;
int error;
- p = malloc(sizeof(*p), type, flags);
+ p = kmem_alloc(sizeof(*p), KM_SLEEP);
if (p == NULL)
return NULL;
vc = hdl;
sc = device_private(vc->parent);
error = esa_allocmem(sc, size, 16, p);
if (error) {
- free(p, type);
+ kmem_free(p, sizeof(*p));
aprint_error_dev(sc->sc_dev,
"%s: not enough memory\n", __func__);
return 0;
@@ -483,7 +481,7 @@ esa_malloc(void *hdl, int direction, size_t size,
}
static void
-esa_free(void *hdl, void *addr, struct malloc_type *type)
+esa_free(void *hdl, void *addr, size_t size)
{
struct esa_voice *vc;
struct esa_softc *sc;
@@ -496,7 +494,7 @@ esa_free(void *hdl, void *addr, struct malloc_type *type)
if (KERNADDR(p) == addr) {
esa_freemem(sc, p);
*pp = p->next;
- free(p, type);
+ kmem_free(p, sizeof(*p));
return;
}
}
@@ -837,12 +835,16 @@ esa_intr(void *hdl)
int i;
sc = hdl;
+ mutex_spin_enter(&sc->sc_intr_lock);
+
iot = sc->sc_iot;
ioh = sc->sc_ioh;
status = bus_space_read_1(iot, ioh, ESA_HOST_INT_STATUS);
- if (status == 0xff)
+ if (status == 0xff) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
+ }
/* ack the interrupt */
bus_space_write_1(iot, ioh, ESA_HOST_INT_STATUS, status);
@@ -874,8 +876,10 @@ esa_intr(void *hdl)
(bus_space_read_1(iot, ioh,
ESA_ASSP_CONTROL_B) & ESA_STOP_ASSP_CLOCK) != 0 ||
(bus_space_read_1(iot, ioh,
- ESA_ASSP_HOST_INT_STATUS) & ESA_DSP2HOST_REQ_TIMER) == 0)
+ ESA_ASSP_HOST_INT_STATUS) & ESA_DSP2HOST_REQ_TIMER) == 0) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return 1;
+ }
bus_space_write_1(iot, ioh, ESA_ASSP_HOST_INT_STATUS,
ESA_DSP2HOST_REQ_TIMER);
@@ -914,6 +918,7 @@ esa_intr(void *hdl)
}
}
+ mutex_spin_exit(&sc->sc_intr_lock);
return 1;
}
@@ -926,22 +931,22 @@ esa_allocmem(struct esa_softc *sc, size_t size, size_t align,
p->size = size;
error = bus_dmamem_alloc(sc->sc_dmat, p->size, align, 0,
p->segs, sizeof(p->segs) / sizeof(p->segs[0]),
- &p->nsegs, BUS_DMA_NOWAIT);
+ &p->nsegs, BUS_DMA_WAITOK);
if (error)
return error;
error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, p->size,
- &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
+ &p->addr, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
if (error)
goto free;
error = bus_dmamap_create(sc->sc_dmat, p->size, 1, p->size, 0,
- BUS_DMA_NOWAIT, &p->map);
+ BUS_DMA_WAITOK, &p->map);
if (error)
goto unmap;
error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size, NULL,
- BUS_DMA_NOWAIT);
+ BUS_DMA_WAITOK);
if (error)
goto destroy;
@@ -1004,9 +1009,7 @@ esa_attach(device_t parent, device_t self, void *aux)
const char *intrstr;
uint32_t data;
char devinfo[256];
- int revision, len;
- int i;
- int error;
+ int revision, i, error;
sc = device_private(self);
pa = (struct pci_attach_args *)aux;
@@ -1045,18 +1048,25 @@ esa_attach(device_t parent, device_t self, void *aux)
sc->sc_pct = pc;
sc->sc_dmat = pa->pa_dmat;
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
/* Map and establish an interrupt */
if (pci_intr_map(pa, &ih)) {
aprint_error_dev(sc->sc_dev, "can't map interrupt\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
intrstr = pci_intr_string(pc, ih);
- sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, esa_intr, sc);
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_SCHED, esa_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(sc->sc_dev, "can't establish interrupt");
if (intrstr != NULL)
aprint_error(" at %s", intrstr);
aprint_error("\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
@@ -1065,6 +1075,8 @@ esa_attach(device_t parent, device_t self, void *aux)
if ((error = pci_activate(pa->pa_pc, pa->pa_tag, self,
pci_activate_null)) && error != EOPNOTSUPP) {
aprint_error_dev(sc->sc_dev, "cannot activate %d\n", error);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
@@ -1072,16 +1084,20 @@ esa_attach(device_t parent, device_t self, void *aux)
if (esa_init(sc) == -1) {
aprint_error_dev(sc->sc_dev,
"esa_attach: unable to initialize the card\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
/* create suspend save area */
- len = sizeof(uint16_t) * (ESA_REV_B_CODE_MEMORY_LENGTH
+ sc->savememsz = sizeof(uint16_t) * (ESA_REV_B_CODE_MEMORY_LENGTH
+ ESA_REV_B_DATA_MEMORY_LENGTH + 1);
- sc->savemem = (uint16_t *)malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
+ sc->savemem = (uint16_t *)kmem_zalloc(sc->savememsz, KM_SLEEP);
if (sc->savemem == NULL) {
aprint_error_dev(sc->sc_dev,
"unable to allocate suspend buffer\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
@@ -1102,18 +1118,6 @@ esa_attach(device_t parent, device_t self, void *aux)
else
sc->codec_flags = AC97_HOST_SWAPPED_CHANNELS;
-
- /* Attach AC97 host interface */
- sc->host_if.arg = sc;
- sc->host_if.attach = esa_attach_codec;
- sc->host_if.read = esa_read_codec;
- sc->host_if.write = esa_write_codec;
- sc->host_if.reset = esa_reset_codec;
- sc->host_if.flags = esa_flags_codec;
-
- if (ac97_attach(&sc->host_if, self) != 0)
- return;
-
/* initialize list management structures */
sc->mixer_list.mem_addr = ESA_KDATA_MIXER_XFER0;
sc->mixer_list.max = ESA_MAX_VIRTUAL_MIXER_CHANNELS;
@@ -1131,6 +1135,22 @@ esa_attach(device_t parent, device_t self, void *aux)
sc->dma_list.indexmap[i] = -1;
sc->adc1_list.indexmap[i] = -1;
}
+
+ /* Attach AC97 host interface */
+ sc->host_if.arg = sc;
+ sc->host_if.attach = esa_attach_codec;
+ sc->host_if.read = esa_read_codec;
+ sc->host_if.write = esa_write_codec;
+ sc->host_if.reset = esa_reset_codec;
+ sc->host_if.flags = esa_flags_codec;
+
+ if (ac97_attach(&sc->host_if, self, &sc->sc_lock) != 0) {
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
+ return;
+ }
+
+ /* Attach audio interface. */
for (i = 0; i < ESA_NUM_VOICES; i++) {
sc->voice[i].parent = sc->sc_dev;
sc->voice[i].index = i;
@@ -1176,7 +1196,9 @@ esa_detach(device_t self, int flags)
if (sc->sc_ios)
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
- free(sc->savemem, M_DEVBUF);
+ kmem_free(sc->savemem, sc->savememsz);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return 0;
}
@@ -1337,6 +1359,8 @@ esa_init(struct esa_softc *sc)
(ESA_MINISRC_IN_BUFFER_SIZE & ~1) +
(ESA_MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255) & ~255;
+ mutex_spin_enter(&sc->sc_intr_lock);
+
/* Disable legacy emulation */
data = pci_conf_read(pc, tag, PCI_LEGACY_AUDIO_CTRL);
data |= DISABLE_LEGACY;
@@ -1409,6 +1433,8 @@ esa_init(struct esa_softc *sc)
bus_space_write_1(iot, ioh, ESA_DSP_PORT_CONTROL_REG_B,
reset_state | ESA_REGB_ENABLE_RESET);
+ mutex_spin_exit(&sc->sc_intr_lock);
+
return 0;
}
@@ -1661,6 +1687,9 @@ esa_suspend(device_t dv, const pmf_qual_t *qual)
index = 0;
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
+
bus_space_write_2(iot, ioh, ESA_HOST_INT_CTRL, 0);
bus_space_write_1(iot, ioh, ESA_ASSP_CONTROL_C, 0);
@@ -1676,6 +1705,9 @@ esa_suspend(device_t dv, const pmf_qual_t *qual)
sc->savemem[index++] = esa_read_assp(sc,
ESA_MEMTYPE_INTERNAL_DATA, i);
+ mutex_spin_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
+
return true;
}
@@ -1693,6 +1725,9 @@ esa_resume(device_t dv, const pmf_qual_t *qual)
delay(10000);
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
+
data = pci_conf_read(sc->sc_pct, sc->sc_tag, PCI_LEGACY_AUDIO_CTRL);
pci_conf_write(sc->sc_pct, sc->sc_tag, PCI_LEGACY_AUDIO_CTRL,
data | DISABLE_LEGACY);
@@ -1723,10 +1758,15 @@ esa_resume(device_t dv, const pmf_qual_t *qual)
esa_enable_interrupts(sc);
esa_amp_enable(sc);
+ mutex_spin_exit(&sc->sc_intr_lock);
+
/* Finally, power up AC97 codec */
delay(1000);
+
sc->codec_if->vtbl->restore_ports(sc->codec_if);
+ mutex_exit(&sc->sc_lock);
+
return true;
}
@@ -1765,3 +1805,13 @@ esa_mappage(void *addr, void *mem, off_t off, int prot)
return bus_dmamem_mmap(sc->sc_dmat, p->segs, p->nsegs,
off, prot, BUS_DMA_WAITOK);
}
+
+static void
+esa_get_locks(void *addr, kmutex_t **intr, kmutex_t **proc)
+{
+ struct esa_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *proc = &sc->sc_lock;
+}
diff --git a/sys/dev/pci/esavar.h b/sys/dev/pci/esavar.h
index 11b5df32187..889bf16e2aa 100644
--- a/sys/dev/pci/esavar.h
+++ b/sys/dev/pci/esavar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: esavar.h,v 1.10 2008/03/27 14:13:34 jmcneill Exp $ */
+/* $NetBSD: esavar.h,v 1.11 2011/11/23 23:07:35 jmcneill Exp $ */
/*
* Copyright (c) 2001, 2002 Jared D. McNeill <jmcneill@invisible.ca>
@@ -102,6 +102,8 @@ struct esa_softc
bus_space_handle_t sc_ioh;
bus_addr_t sc_iob;
bus_size_t sc_ios;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
pcitag_t sc_tag;
pci_chipset_tag_t sc_pct;
@@ -133,4 +135,5 @@ struct esa_softc
int delay1, delay2;
uint16_t *savemem;
+ size_t savememsz;
};
diff --git a/sys/dev/pci/esm.c b/sys/dev/pci/esm.c
index f1729b2cf99..67c656ceb61 100644
--- a/sys/dev/pci/esm.c
+++ b/sys/dev/pci/esm.c
@@ -1,4 +1,4 @@
-/* $NetBSD: esm.c,v 1.53 2010/02/24 22:38:00 dyoung Exp $ */
+/* $NetBSD: esm.c,v 1.54 2011/11/23 23:07:35 jmcneill Exp $ */
/*-
* Copyright (c) 2002, 2003 Matt Fredette
@@ -66,26 +66,25 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: esm.c,v 1.53 2010/02/24 22:38:00 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: esm.c,v 1.54 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
-
#include <sys/bus.h>
-
#include <sys/audioio.h>
+
#include <dev/audio_if.h>
#include <dev/mulaw.h>
#include <dev/auconv.h>
+
#include <dev/ic/ac97var.h>
#include <dev/ic/ac97reg.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/pcivar.h>
-
#include <dev/pci/esmreg.h>
#include <dev/pci/esmvar.h>
@@ -190,7 +189,7 @@ const struct audio_hw_if esm_hw_if = {
esm_trigger_output,
esm_trigger_input,
NULL,
- NULL,
+ esm_get_locks,
};
struct audio_device esm_device = {
@@ -1320,15 +1319,13 @@ esm_query_devinfo(void *sc, mixer_devinfo_t *dip)
}
void *
-esm_malloc(void *sc, int direction, size_t size,
- struct malloc_type *pool, int flags)
+esm_malloc(void *sc, int direction, size_t size)
{
struct esm_softc *ess;
int off;
DPRINTF(ESM_DEBUG_DMA,
- ("esm_malloc(%p, %d, 0x%lx, %p, 0x%x)",
- sc, direction, (unsigned long int)size, pool, flags));
+ ("esm_malloc(%p, %d, 0x%zd)", sc, direction, size));
ess = sc;
/*
* Each buffer can only be allocated once.
@@ -1352,13 +1349,11 @@ esm_malloc(void *sc, int direction, size_t size,
}
void
-esm_free(void *sc, void *ptr, struct malloc_type *pool)
+esm_free(void *sc, void *ptr, size_t size)
{
struct esm_softc *ess;
- DPRINTF(ESM_DEBUG_DMA,
- ("esm_free(%p, %p, %p)\n",
- sc, ptr, pool));
+ DPRINTF(ESM_DEBUG_DMA, ("esm_free(%p, %p, %zd)\n", sc, ptr, size));
ess = sc;
if ((char *)ptr == (char *)ess->sc_dma.addr + MAESTRO_PLAYBUF_OFF)
ess->rings_alloced &= ~AUMODE_PLAY;
@@ -1421,9 +1416,13 @@ esm_intr(void *sc)
ess = sc;
ret = 0;
+
+ mutex_spin_enter(&ess->sc_intr_lock);
status = bus_space_read_1(ess->st, ess->sh, PORT_HOSTINT_STAT);
- if (!status)
+ if (!status) {
+ mutex_spin_exit(&ess->sc_intr_lock);
return 0;
+ }
/* Acknowledge all. */
bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1);
@@ -1499,6 +1498,7 @@ esm_intr(void *sc)
}
ret++;
}
+ mutex_spin_exit(&ess->sc_intr_lock);
return ret;
}
@@ -1529,22 +1529,22 @@ esm_allocmem(struct esm_softc *sc, size_t size, size_t align,
p->size = size;
error = bus_dmamem_alloc(sc->dmat, p->size, align, 0,
p->segs, __arraycount(p->segs),
- &p->nsegs, BUS_DMA_NOWAIT);
+ &p->nsegs, BUS_DMA_WAITOK);
if (error)
return error;
error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size,
- &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
+ &p->addr, BUS_DMA_WAITOK|BUS_DMA_COHERENT);
if (error)
goto free;
error = bus_dmamap_create(sc->dmat, p->size, 1, p->size,
- 0, BUS_DMA_NOWAIT, &p->map);
+ 0, BUS_DMA_WAITOK, &p->map);
if (error)
goto unmap;
error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL,
- BUS_DMA_NOWAIT);
+ BUS_DMA_WAITOK);
if (error)
goto destroy;
@@ -1612,6 +1612,9 @@ esm_attach(device_t parent, device_t self, void *aux)
revision = PCI_REVISION(pa->pa_class);
aprint_normal(": %s (rev. 0x%02x)\n", devinfo, revision);
+ mutex_init(&ess->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&ess->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
/* Enable the device. */
csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
@@ -1621,6 +1624,8 @@ esm_attach(device_t parent, device_t self, void *aux)
if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
&ess->st, &ess->sh, NULL, &ess->sz)) {
aprint_error_dev(ess->sc_dev, "can't map i/o space\n");
+ mutex_destroy(&ess->sc_lock);
+ mutex_destroy(&ess->sc_intr_lock);
return;
}
@@ -1640,15 +1645,19 @@ esm_attach(device_t parent, device_t self, void *aux)
/* Map and establish the interrupt. */
if (pci_intr_map(pa, &ih)) {
aprint_error_dev(ess->sc_dev, "can't map interrupt\n");
+ mutex_destroy(&ess->sc_lock);
+ mutex_destroy(&ess->sc_intr_lock);
return;
}
intrstr = pci_intr_string(pc, ih);
- ess->ih = pci_intr_establish(pc, ih, IPL_AUDIO, esm_intr, self);
+ ess->ih = pci_intr_establish(pc, ih, IPL_SCHED, esm_intr, self);
if (ess->ih == NULL) {
aprint_error_dev(ess->sc_dev, "can't establish interrupt");
if (intrstr != NULL)
aprint_error(" at %s", intrstr);
aprint_error("\n");
+ mutex_destroy(&ess->sc_lock);
+ mutex_destroy(&ess->sc_intr_lock);
return;
}
aprint_normal_dev(ess->sc_dev, "interrupting at %s\n",
@@ -1663,6 +1672,8 @@ esm_attach(device_t parent, device_t self, void *aux)
pci_activate_null)) && error != EOPNOTSUPP) {
aprint_error_dev(ess->sc_dev, "cannot activate %d\n",
error);
+ mutex_destroy(&ess->sc_lock);
+ mutex_destroy(&ess->sc_intr_lock);
return;
}
delay(100000);
@@ -1686,6 +1697,8 @@ esm_attach(device_t parent, device_t self, void *aux)
esm_read_codec(ess, 0, &codec_data);
if (codec_data == 0x80) {
aprint_error_dev(ess->sc_dev, "PT101 codec detected!\n");
+ mutex_destroy(&ess->sc_lock);
+ mutex_destroy(&ess->sc_intr_lock);
return;
}
@@ -1708,13 +1721,18 @@ esm_attach(device_t parent, device_t self, void *aux)
ess->host_if.reset = esm_reset_codec;
ess->host_if.flags = esm_flags_codec;
- if (ac97_attach(&ess->host_if, self) != 0)
+ if (ac97_attach(&ess->host_if, self, &ess->sc_lock) != 0) {
+ mutex_destroy(&ess->sc_lock);
+ mutex_destroy(&ess->sc_intr_lock);
return;
+ }
/* allocate our DMA region */
if (esm_allocmem(ess, MAESTRO_DMA_SZ, MAESTRO_DMA_ALIGN,
&ess->sc_dma)) {
aprint_error_dev(ess->sc_dev, "couldn't allocate memory!\n");
+ mutex_destroy(&ess->sc_lock);
+ mutex_destroy(&ess->sc_intr_lock);
return;
}
ess->rings_alloced = 0;
@@ -1742,16 +1760,18 @@ esm_detach(device_t self, int flags)
int rc;
struct esm_softc *ess = device_private(self);
- pmf_device_deregister(self);
-
if ((rc = config_detach_children(self, flags)) != 0)
return rc;
+ pmf_device_deregister(self);
/* free our DMA region */
esm_freemem(ess, &ess->sc_dma);
- if (ess->codec_if != NULL)
+ if (ess->codec_if != NULL) {
+ mutex_enter(&ess->sc_lock);
ess->codec_if->vtbl->detach(ess->codec_if);
+ mutex_exit(&ess->sc_lock);
+ }
/* XXX Restore CONF_MAESTRO? */
/* XXX Restore legacy emulations? */
@@ -1761,6 +1781,8 @@ esm_detach(device_t self, int flags)
pci_intr_disestablish(ess->pc, ess->ih);
bus_space_unmap(ess->st, ess->sh, ess->sz);
+ mutex_destroy(&ess->sc_lock);
+ mutex_destroy(&ess->sc_intr_lock);
return 0;
}
@@ -1769,21 +1791,21 @@ static bool
esm_suspend(device_t dv, const pmf_qual_t *qual)
{
struct esm_softc *ess = device_private(dv);
- int x;
- x = splaudio();
+ mutex_enter(&ess->sc_lock);
+ mutex_spin_enter(&ess->sc_intr_lock);
wp_stoptimer(ess);
bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0);
-
esm_halt_output(ess);
esm_halt_input(ess);
- splx(x);
+ mutex_spin_exit(&ess->sc_intr_lock);
/* Power down everything except clock. */
esm_write_codec(ess, AC97_REG_POWER, 0xdf00);
delay(20);
bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0);
delay(1);
+ mutex_exit(&ess->sc_lock);
return true;
}
@@ -1792,18 +1814,21 @@ static bool
esm_resume(device_t dv, const pmf_qual_t *qual)
{
struct esm_softc *ess = device_private(dv);
- int x;
uint16_t pcmbar;
delay(100000);
+
+ mutex_enter(&ess->sc_lock);
+ mutex_spin_enter(&ess->sc_intr_lock);
esm_init(ess);
/* set DMA base address */
for (pcmbar = WAVCACHE_PCMBAR; pcmbar < WAVCACHE_PCMBAR + 4; pcmbar++)
wc_wrreg(ess, pcmbar,
DMAADDR(&ess->sc_dma) >> WAVCACHE_BASEADDR_SHIFT);
-
+ mutex_spin_exit(&ess->sc_intr_lock);
ess->codec_if->vtbl->restore_ports(ess->codec_if);
+ mutex_spin_enter(&ess->sc_intr_lock);
#if 0
if (mixer_reinit(dev)) {
printf("%s: unable to reinitialize the mixer\n",
@@ -1812,7 +1837,6 @@ esm_resume(device_t dv, const pmf_qual_t *qual)
}
#endif
- x = splaudio();
#if TODO
if (ess->pactive)
esm_start_output(ess);
@@ -1823,7 +1847,18 @@ esm_resume(device_t dv, const pmf_qual_t *qual)
set_timer(ess);
wp_starttimer(ess);
}
- splx(x);
+ mutex_spin_exit(&ess->sc_intr_lock);
+ mutex_exit(&ess->sc_lock);
return true;
}
+
+void
+esm_get_locks(void *addr, kmutex_t **intr, kmutex_t **proc)
+{
+ struct esm_softc *esm;
+
+ esm = addr;
+ *intr = &esm->sc_intr_lock;
+ *proc = &esm->sc_lock;
+}
diff --git a/sys/dev/pci/esmvar.h b/sys/dev/pci/esmvar.h
index ace50abbf50..f2219c76476 100644
--- a/sys/dev/pci/esmvar.h
+++ b/sys/dev/pci/esmvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: esmvar.h,v 1.17 2009/05/07 06:08:02 cegger Exp $ */
+/* $NetBSD: esmvar.h,v 1.18 2011/11/23 23:07:35 jmcneill Exp $ */
/*-
* Copyright (c) 2002, 2003 Matt Fredette
@@ -151,6 +151,8 @@ struct esm_chinfo {
struct esm_softc {
device_t sc_dev;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
bus_space_tag_t st;
bus_space_handle_t sh;
@@ -218,10 +220,11 @@ int esm_set_params(void *, int, int, audio_params_t *, audio_params_t *,
int esm_set_port(void *, mixer_ctrl_t *);
int esm_get_port(void *, mixer_ctrl_t *);
int esm_query_devinfo(void *, mixer_devinfo_t *);
-void *esm_malloc(void *, int, size_t, struct malloc_type *, int);
-void esm_free(void *, void *, struct malloc_type *);
+void *esm_malloc(void *, int, size_t);
+void esm_free(void *, void *, size_t);
size_t esm_round_buffersize(void *, int, size_t);
paddr_t esm_mappage(void *, void *, off_t, int);
int esm_get_props(void *);
+void esm_get_locks(void *, kmutex_t **, kmutex_t **);
enum esm_quirk_flags esm_get_quirks(pcireg_t);
diff --git a/sys/dev/pci/eso.c b/sys/dev/pci/eso.c
index 4a3b026c029..1fa8cb2b013 100644
--- a/sys/dev/pci/eso.c
+++ b/sys/dev/pci/eso.c
@@ -1,4 +1,33 @@
-/* $NetBSD: eso.c,v 1.57 2009/11/26 15:17:09 njoly Exp $ */
+/* $NetBSD: eso.c,v 1.58 2011/11/23 23:07:35 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software developed for The NetBSD Foundation
+ * by Andrew Doran.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
/*
* Copyright (c) 1999, 2000, 2004 Klaus J. Klein
@@ -33,14 +62,14 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: eso.c,v 1.57 2009/11/26 15:17:09 njoly Exp $");
+__KERNEL_RCSID(0, "$NetBSD: eso.c,v 1.58 2011/11/23 23:07:35 jmcneill Exp $");
#include "mpu.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
#include <sys/queue.h>
#include <sys/proc.h>
@@ -50,7 +79,6 @@ __KERNEL_RCSID(0, "$NetBSD: eso.c,v 1.57 2009/11/26 15:17:09 njoly Exp $");
#include <sys/audioio.h>
#include <dev/audio_if.h>
-#include <dev/midi_if.h>
#include <dev/mulaw.h>
#include <dev/auconv.h>
@@ -117,8 +145,8 @@ static int eso_getdev(void *, struct audio_device *);
static int eso_set_port(void *, mixer_ctrl_t *);
static int eso_get_port(void *, mixer_ctrl_t *);
static int eso_query_devinfo(void *, mixer_devinfo_t *);
-static void * eso_allocm(void *, int, size_t, struct malloc_type *, int);
-static void eso_freem(void *, void *, struct malloc_type *);
+static void * eso_allocm(void *, int, size_t);
+static void eso_freem(void *, void *, size_t);
static size_t eso_round_buffersize(void *, int, size_t);
static paddr_t eso_mappage(void *, void *, off_t, int);
static int eso_get_props(void *);
@@ -126,6 +154,7 @@ static int eso_trigger_output(void *, void *, void *, int,
void (*)(void *), void *, const audio_params_t *);
static int eso_trigger_input(void *, void *, void *, int,
void (*)(void *), void *, const audio_params_t *);
+static void eso_get_locks(void *, kmutex_t **, kmutex_t **);
static const struct audio_hw_if eso_hw_if = {
NULL, /* open */
@@ -155,7 +184,7 @@ static const struct audio_hw_if eso_hw_if = {
eso_trigger_output,
eso_trigger_input,
NULL, /* dev_ioctl */
- NULL, /* powerstate */
+ eso_get_locks,
};
static const char * const eso_rev2model[] = {
@@ -204,7 +233,7 @@ static void eso_write_ctlreg(struct eso_softc *, uint8_t, uint8_t);
static void eso_write_mixreg(struct eso_softc *, uint8_t, uint8_t);
/* DMA memory allocation */
static int eso_allocmem(struct eso_softc *, size_t, size_t, size_t,
- int, int, struct eso_dma *);
+ int, struct eso_dma *);
static void eso_freemem(struct eso_dma *);
static struct eso_dma * eso_kva2dma(const struct eso_softc *, const void *);
@@ -239,7 +268,6 @@ eso_attach(device_t parent, device_t self, void *aux)
aprint_naive(": Audio controller\n");
sc->sc_revision = PCI_REVISION(pa->pa_class);
-
aprint_normal(": ESS Solo-1 PCI AudioDrive ");
if (sc->sc_revision <
sizeof (eso_rev2model) / sizeof (eso_rev2model[0]))
@@ -352,18 +380,27 @@ eso_attach(device_t parent, device_t self, void *aux)
aprint_error_dev(&sc->sc_dev, "couldn't map interrupt\n");
return;
}
+
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
intrstring = pci_intr_string(pa->pa_pc, ih);
- sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, eso_intr, sc);
+ sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_SCHED, eso_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(&sc->sc_dev, "couldn't establish interrupt");
if (intrstring != NULL)
aprint_error(" at %s", intrstring);
aprint_error("\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
aprint_normal_dev(&sc->sc_dev, "interrupting at %s\n",
intrstring);
+ cv_init(&sc->sc_pcv, "esoho");
+ cv_init(&sc->sc_rcv, "esohi");
+
/*
* Set up the DDMA Control register; a suitable I/O region has been
* supposedly mapped in the VC base address register.
@@ -408,9 +445,11 @@ eso_attach(device_t parent, device_t self, void *aux)
sc->sc_mpudev = config_found(&sc->sc_dev, &aa, audioprint);
if (sc->sc_mpudev != NULL) {
/* Unmask the MPU irq. */
+ mutex_spin_enter(&sc->sc_intr_lock);
mvctl = eso_read_mixreg(sc, ESO_MIXREG_MVCTL);
mvctl |= ESO_MIXREG_MVCTL_MPUIRQM;
eso_write_mixreg(sc, ESO_MIXREG_MVCTL, mvctl);
+ mutex_spin_exit(&sc->sc_intr_lock);
}
aa.type = AUDIODEV_TYPE_AUX;
@@ -436,6 +475,7 @@ eso_defer(device_t self)
* forward way to implement it. Note that we skip over the first
* 1K region, which is typically occupied by an attached ISA bus.
*/
+ mutex_enter(&sc->sc_lock);
for (start = 0x0400; start < 0xffff; start += 0x0400) {
if (bus_space_alloc(sc->sc_iot,
start + sc->sc_vcsize, start + 0x0400 - 1,
@@ -443,15 +483,19 @@ eso_defer(device_t self)
&sc->sc_dmac_ioh) != 0)
continue;
+ mutex_spin_enter(&sc->sc_intr_lock);
pci_conf_write(pa->pa_pc, pa->pa_tag, ESO_PCI_DDMAC,
addr | ESO_PCI_DDMAC_DE);
+ mutex_spin_exit(&sc->sc_intr_lock);
sc->sc_dmac_iot = sc->sc_iot;
sc->sc_dmac_configured = 1;
aprint_normal("mapping Audio 1 DMA using I/O space at 0x%lx\n",
(unsigned long)addr);
+ mutex_exit(&sc->sc_lock);
return;
}
+ mutex_exit(&sc->sc_lock);
aprint_error("can't map Audio 1 DMA into I/O space\n");
}
@@ -532,26 +576,24 @@ eso_read_ctlreg(struct eso_softc *sc, uint8_t reg)
static void
eso_write_mixreg(struct eso_softc *sc, uint8_t reg, uint8_t val)
{
- int s;
+
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
/* DPRINTF(("mixreg 0x%02x = 0x%02x\n", reg, val)); */
- s = splaudio();
bus_space_write_1(sc->sc_sb_iot, sc->sc_sb_ioh, ESO_SB_MIXERADDR, reg);
bus_space_write_1(sc->sc_sb_iot, sc->sc_sb_ioh, ESO_SB_MIXERDATA, val);
- splx(s);
}
static uint8_t
eso_read_mixreg(struct eso_softc *sc, uint8_t reg)
{
- int s;
uint8_t val;
- s = splaudio();
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
bus_space_write_1(sc->sc_sb_iot, sc->sc_sb_ioh, ESO_SB_MIXERADDR, reg);
val = bus_space_read_1(sc->sc_sb_iot, sc->sc_sb_ioh, ESO_SB_MIXERDATA);
- splx(s);
return val;
}
@@ -565,12 +607,16 @@ eso_intr(void *hdl)
#endif
uint8_t irqctl;
+ mutex_spin_enter(&sc->sc_intr_lock);
+
irqctl = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ESO_IO_IRQCTL);
/* If it wasn't ours, that's all she wrote. */
if ((irqctl & (ESO_IO_IRQCTL_A1IRQ | ESO_IO_IRQCTL_A2IRQ |
- ESO_IO_IRQCTL_HVIRQ | ESO_IO_IRQCTL_MPUIRQ)) == 0)
+ ESO_IO_IRQCTL_HVIRQ | ESO_IO_IRQCTL_MPUIRQ)) == 0) {
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
+ }
if (irqctl & ESO_IO_IRQCTL_A1IRQ) {
/* Clear interrupt. */
@@ -580,7 +626,7 @@ eso_intr(void *hdl)
if (sc->sc_rintr)
sc->sc_rintr(sc->sc_rarg);
else
- wakeup(&sc->sc_rintr);
+ cv_broadcast(&sc->sc_rcv);
}
if (irqctl & ESO_IO_IRQCTL_A2IRQ) {
@@ -593,7 +639,7 @@ eso_intr(void *hdl)
if (sc->sc_pintr)
sc->sc_pintr(sc->sc_parg);
else
- wakeup(&sc->sc_pintr);
+ cv_broadcast(&sc->sc_pcv);
}
if (irqctl & ESO_IO_IRQCTL_HVIRQ) {
@@ -614,6 +660,7 @@ eso_intr(void *hdl)
mpu_intr(sc_mpu);
#endif
+ mutex_spin_exit(&sc->sc_intr_lock);
return 1;
}
@@ -623,6 +670,8 @@ eso_reset(struct eso_softc *sc)
{
int i;
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
bus_space_write_1(sc->sc_sb_iot, sc->sc_sb_ioh, ESO_SB_RESET,
ESO_SB_RESET_SW | ESO_SB_RESET_FIFO);
/* `Delay' suggested in the data sheet. */
@@ -765,6 +814,8 @@ eso_set_params(void *hdl, int setmode, int usemode,
mode, p, FALSE, fil);
if (i < 0)
return EINVAL;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
if (mode == AUMODE_RECORD) {
/* Audio 1 */
DPRINTF(("A1 srg 0x%02x fdiv 0x%02x\n", srg, fltdiv));
@@ -776,6 +827,7 @@ eso_set_params(void *hdl, int setmode, int usemode,
eso_write_mixreg(sc, ESO_MIXREG_A2SRG, srg);
eso_write_mixreg(sc, ESO_MIXREG_A2FLTDIV, fltdiv);
}
+ mutex_spin_exit(&sc->sc_intr_lock);
#undef ABS
}
@@ -795,7 +847,7 @@ static int
eso_halt_output(void *hdl)
{
struct eso_softc *sc;
- int error, s;
+ int error;
sc = hdl;
DPRINTF(("%s: halt_output\n", device_xname(&sc->sc_dev)));
@@ -811,15 +863,19 @@ eso_halt_output(void *hdl)
* state with the least hair. (Besides, that item needs to be
* rephrased for trigger_*()-based DMA environments.)
*/
- s = splaudio();
eso_write_mixreg(sc, ESO_MIXREG_A2C1,
ESO_MIXREG_A2C1_FIFOENB | ESO_MIXREG_A2C1_DMAENB);
bus_space_write_1(sc->sc_iot, sc->sc_ioh, ESO_IO_A2DMAM,
ESO_IO_A2DMAM_DMAENB);
sc->sc_pintr = NULL;
- error = tsleep(&sc->sc_pintr, PCATCH | PWAIT, "esoho", sc->sc_pdrain);
- splx(s);
+ mutex_exit(&sc->sc_lock);
+ error = cv_timedwait_sig(&sc->sc_pcv, &sc->sc_intr_lock, sc->sc_pdrain);
+ if (!mutex_tryenter(&sc->sc_lock)) {
+ mutex_spin_exit(&sc->sc_intr_lock);
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
+ }
/* Shut down DMA completely. */
eso_write_mixreg(sc, ESO_MIXREG_A2C1, 0);
@@ -832,13 +888,12 @@ static int
eso_halt_input(void *hdl)
{
struct eso_softc *sc;
- int error, s;
+ int error;
sc = hdl;
DPRINTF(("%s: halt_input\n", device_xname(&sc->sc_dev)));
/* Just like eso_halt_output(), but for Audio 1. */
- s = splaudio();
eso_write_ctlreg(sc, ESO_CTLREG_A1C2,
ESO_CTLREG_A1C2_READ | ESO_CTLREG_A1C2_ADC |
ESO_CTLREG_A1C2_DMAENB);
@@ -846,8 +901,13 @@ eso_halt_input(void *hdl)
DMA37MD_WRITE | DMA37MD_DEMAND);
sc->sc_rintr = NULL;
- error = tsleep(&sc->sc_rintr, PCATCH | PWAIT, "esohi", sc->sc_rdrain);
- splx(s);
+ mutex_exit(&sc->sc_lock);
+ error = cv_timedwait_sig(&sc->sc_rcv, &sc->sc_intr_lock, sc->sc_rdrain);
+ if (!mutex_tryenter(&sc->sc_lock)) {
+ mutex_spin_exit(&sc->sc_intr_lock);
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
+ }
/* Shut down DMA completely. */
eso_write_ctlreg(sc, ESO_CTLREG_A1C2,
@@ -883,8 +943,13 @@ eso_set_port(void *hdl, mixer_ctrl_t *cp)
struct eso_softc *sc;
unsigned int lgain, rgain;
uint8_t tmp;
+ int error;
sc = hdl;
+ error = 0;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
+
switch (cp->dev) {
case ESO_DAC_PLAY_VOL:
case ESO_MIC_PLAY_VOL:
@@ -899,8 +964,10 @@ eso_set_port(void *hdl, mixer_ctrl_t *cp)
case ESO_SYNTH_REC_VOL:
case ESO_CD_REC_VOL:
case ESO_AUXB_REC_VOL:
- if (cp->type != AUDIO_MIXER_VALUE)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_VALUE) {
+ error = EINVAL;
+ break;
+ }
/*
* Stereo-capable mixer ports: if we get a single-channel
@@ -919,17 +986,22 @@ eso_set_port(void *hdl, mixer_ctrl_t *cp)
cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]);
break;
default:
- return EINVAL;
+ error = EINVAL;
+ break;
}
- sc->sc_gain[cp->dev][ESO_LEFT] = lgain;
- sc->sc_gain[cp->dev][ESO_RIGHT] = rgain;
- eso_set_gain(sc, cp->dev);
+ if (!error) {
+ sc->sc_gain[cp->dev][ESO_LEFT] = lgain;
+ sc->sc_gain[cp->dev][ESO_RIGHT] = rgain;
+ eso_set_gain(sc, cp->dev);
+ }
break;
case ESO_MASTER_VOL:
- if (cp->type != AUDIO_MIXER_VALUE)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_VALUE) {
+ error = EINVAL;
+ break;
+ }
/* Like above, but a precision of 6 bits. */
switch (cp->un.value.num_channels) {
@@ -944,18 +1016,23 @@ eso_set_port(void *hdl, mixer_ctrl_t *cp)
cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]);
break;
default:
- return EINVAL;
+ error = EINVAL;
+ break;
}
- sc->sc_gain[cp->dev][ESO_LEFT] = lgain;
- sc->sc_gain[cp->dev][ESO_RIGHT] = rgain;
- eso_set_gain(sc, cp->dev);
+ if (!error) {
+ sc->sc_gain[cp->dev][ESO_LEFT] = lgain;
+ sc->sc_gain[cp->dev][ESO_RIGHT] = rgain;
+ eso_set_gain(sc, cp->dev);
+ }
break;
case ESO_SPATIALIZER:
if (cp->type != AUDIO_MIXER_VALUE ||
- cp->un.value.num_channels != 1)
- return EINVAL;
+ cp->un.value.num_channels != 1) {
+ error = EINVAL;
+ break;
+ }
sc->sc_gain[cp->dev][ESO_LEFT] =
sc->sc_gain[cp->dev][ESO_RIGHT] =
@@ -967,8 +1044,10 @@ eso_set_port(void *hdl, mixer_ctrl_t *cp)
case ESO_MONO_PLAY_VOL:
case ESO_MONO_REC_VOL:
if (cp->type != AUDIO_MIXER_VALUE ||
- cp->un.value.num_channels != 1)
- return EINVAL;
+ cp->un.value.num_channels != 1) {
+ error = EINVAL;
+ break;
+ }
sc->sc_gain[cp->dev][ESO_LEFT] =
sc->sc_gain[cp->dev][ESO_RIGHT] =
@@ -979,8 +1058,10 @@ eso_set_port(void *hdl, mixer_ctrl_t *cp)
case ESO_PCSPEAKER_VOL:
if (cp->type != AUDIO_MIXER_VALUE ||
- cp->un.value.num_channels != 1)
- return EINVAL;
+ cp->un.value.num_channels != 1) {
+ error = EINVAL;
+ break;
+ }
sc->sc_gain[cp->dev][ESO_LEFT] =
sc->sc_gain[cp->dev][ESO_RIGHT] =
@@ -990,8 +1071,10 @@ eso_set_port(void *hdl, mixer_ctrl_t *cp)
break;
case ESO_SPATIALIZER_ENABLE:
- if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_ENUM) {
+ error = EINVAL;
+ break;
+ }
sc->sc_spatializer = (cp->un.ord != 0);
@@ -1005,8 +1088,10 @@ eso_set_port(void *hdl, mixer_ctrl_t *cp)
break;
case ESO_MASTER_MUTE:
- if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_ENUM) {
+ error = EINVAL;
+ break;
+ }
sc->sc_mvmute = (cp->un.ord != 0);
@@ -1028,20 +1113,28 @@ eso_set_port(void *hdl, mixer_ctrl_t *cp)
break;
case ESO_MONOOUT_SOURCE:
- if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_ENUM) {
+ error = EINVAL;
+ break;
+ }
- return eso_set_monooutsrc(sc, cp->un.ord);
+ error = eso_set_monooutsrc(sc, cp->un.ord);
+ break;
case ESO_MONOIN_BYPASS:
- if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_ENUM) {
+ error = EINVAL;
+ break;
+ }
- return (eso_set_monoinbypass(sc, cp->un.ord));
+ error = (eso_set_monoinbypass(sc, cp->un.ord));
+ break;
case ESO_RECORD_MONITOR:
- if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_ENUM) {
+ error = EINVAL;
+ break;
+ }
sc->sc_recmon = (cp->un.ord != 0);
@@ -1054,30 +1147,43 @@ eso_set_port(void *hdl, mixer_ctrl_t *cp)
break;
case ESO_RECORD_SOURCE:
- if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_ENUM) {
+ error = EINVAL;
+ break;
+ }
- return eso_set_recsrc(sc, cp->un.ord);
+ error = eso_set_recsrc(sc, cp->un.ord);
+ break;
case ESO_MIC_PREAMP:
- if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_ENUM) {
+ error = EINVAL;
+ break;
+ }
- return eso_set_preamp(sc, cp->un.ord);
+ error = eso_set_preamp(sc, cp->un.ord);
+ break;
default:
- return EINVAL;
+ error = EINVAL;
+ break;
}
- return 0;
+ mutex_spin_exit(&sc->sc_intr_lock);
+ return error;
}
static int
eso_get_port(void *hdl, mixer_ctrl_t *cp)
{
struct eso_softc *sc;
+ int error;
sc = hdl;
+ error = 0;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
+
switch (cp->dev) {
case ESO_MASTER_VOL:
/* Reload from mixer after hardware volume control use. */
@@ -1114,7 +1220,8 @@ eso_get_port(void *hdl, mixer_ctrl_t *cp)
sc->sc_gain[cp->dev][ESO_RIGHT];
break;
default:
- return EINVAL;
+ error = EINVAL;
+ break;
}
break;
@@ -1122,8 +1229,10 @@ eso_get_port(void *hdl, mixer_ctrl_t *cp)
case ESO_PCSPEAKER_VOL:
case ESO_MONO_REC_VOL:
case ESO_SPATIALIZER:
- if (cp->un.value.num_channels != 1)
- return EINVAL;
+ if (cp->un.value.num_channels != 1) {
+ error = EINVAL;
+ break;
+ }
cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
sc->sc_gain[cp->dev][ESO_LEFT];
break;
@@ -1160,9 +1269,11 @@ eso_get_port(void *hdl, mixer_ctrl_t *cp)
break;
default:
- return EINVAL;
+ error = EINVAL;
+ break;
}
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
}
@@ -1456,31 +1567,30 @@ eso_query_devinfo(void *hdl, mixer_devinfo_t *dip)
static int
eso_allocmem(struct eso_softc *sc, size_t size, size_t align,
- size_t boundary, int flags, int direction, struct eso_dma *ed)
+ size_t boundary, int direction, struct eso_dma *ed)
{
- int error, wait;
+ int error;
- wait = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
ed->ed_size = size;
error = bus_dmamem_alloc(ed->ed_dmat, ed->ed_size, align, boundary,
ed->ed_segs, sizeof (ed->ed_segs) / sizeof (ed->ed_segs[0]),
- &ed->ed_nsegs, wait);
+ &ed->ed_nsegs, BUS_DMA_WAITOK);
if (error)
goto out;
error = bus_dmamem_map(ed->ed_dmat, ed->ed_segs, ed->ed_nsegs,
- ed->ed_size, &ed->ed_kva, wait | BUS_DMA_COHERENT);
+ ed->ed_size, &ed->ed_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
if (error)
goto free;
error = bus_dmamap_create(ed->ed_dmat, ed->ed_size, 1, ed->ed_size, 0,
- wait, &ed->ed_map);
+ BUS_DMA_WAITOK, &ed->ed_map);
if (error)
goto unmap;
error = bus_dmamap_load(ed->ed_dmat, ed->ed_map, ed->ed_kva,
- ed->ed_size, NULL, wait |
+ ed->ed_size, NULL, BUS_DMA_WAITOK |
(direction == AUMODE_RECORD) ? BUS_DMA_READ : BUS_DMA_WRITE);
if (error)
goto destroy;
@@ -1522,8 +1632,7 @@ eso_kva2dma(const struct eso_softc *sc, const void *kva)
}
static void *
-eso_allocm(void *hdl, int direction, size_t size, struct malloc_type *type,
- int flags)
+eso_allocm(void *hdl, int direction, size_t size)
{
struct eso_softc *sc;
struct eso_dma *ed;
@@ -1531,7 +1640,7 @@ eso_allocm(void *hdl, int direction, size_t size, struct malloc_type *type,
int error;
sc = hdl;
- if ((ed = malloc(sizeof (*ed), type, flags)) == NULL)
+ if ((ed = kmem_alloc(sizeof (*ed), KM_SLEEP)) == NULL)
return NULL;
/*
@@ -1567,9 +1676,9 @@ eso_allocm(void *hdl, int direction, size_t size, struct malloc_type *type,
#endif
ed->ed_dmat = sc->sc_dmat;
- error = eso_allocmem(sc, size, 32, boundary, flags, direction, ed);
+ error = eso_allocmem(sc, size, 32, boundary, direction, ed);
if (error) {
- free(ed, type);
+ kmem_free(ed, sizeof(*ed));
return NULL;
}
SLIST_INSERT_HEAD(&sc->sc_dmas, ed, ed_slist);
@@ -1578,7 +1687,7 @@ eso_allocm(void *hdl, int direction, size_t size, struct malloc_type *type,
}
static void
-eso_freem(void *hdl, void *addr, struct malloc_type *type)
+eso_freem(void *hdl, void *addr, size_t size)
{
struct eso_softc *sc;
struct eso_dma *p;
@@ -1588,7 +1697,7 @@ eso_freem(void *hdl, void *addr, struct malloc_type *type)
SLIST_REMOVE(&sc->sc_dmas, p, eso_dma, ed_slist);
eso_freemem(p);
- free(p, type);
+ kmem_free(p, sizeof(*p));
}
static size_t
@@ -1803,6 +1912,17 @@ eso_trigger_input(void *hdl, void *start, void *end, int blksize,
return 0;
}
+
+static void
+eso_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct eso_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
/*
* Mixer utility functions.
*/
@@ -1812,6 +1932,8 @@ eso_set_recsrc(struct eso_softc *sc, unsigned int recsrc)
mixer_devinfo_t di;
int i;
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
di.index = ESO_RECORD_SOURCE;
if (eso_query_devinfo(sc, &di) != 0)
panic("eso_set_recsrc: eso_query_devinfo failed");
@@ -1834,6 +1956,8 @@ eso_set_monooutsrc(struct eso_softc *sc, unsigned int monooutsrc)
int i;
uint8_t mpm;
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
di.index = ESO_MONOOUT_SOURCE;
if (eso_query_devinfo(sc, &di) != 0)
panic("eso_set_monooutsrc: eso_query_devinfo failed");
@@ -1859,6 +1983,8 @@ eso_set_monoinbypass(struct eso_softc *sc, unsigned int monoinbypass)
int i;
uint8_t mpm;
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
di.index = ESO_MONOIN_BYPASS;
if (eso_query_devinfo(sc, &di) != 0)
panic("eso_set_monoinbypass: eso_query_devinfo failed");
@@ -1884,6 +2010,8 @@ eso_set_preamp(struct eso_softc *sc, unsigned int preamp)
int i;
uint8_t mpm;
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
di.index = ESO_MIC_PREAMP;
if (eso_query_devinfo(sc, &di) != 0)
panic("eso_set_preamp: eso_query_devinfo failed");
@@ -1911,6 +2039,8 @@ eso_reload_master_vol(struct eso_softc *sc)
{
uint8_t mv;
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
mv = eso_read_mixreg(sc, ESO_MIXREG_LMVM);
sc->sc_gain[ESO_MASTER_VOL][ESO_LEFT] =
(mv & ~ESO_MIXREG_LMVM_MUTE) << 2;
@@ -1926,6 +2056,8 @@ eso_set_gain(struct eso_softc *sc, unsigned int port)
{
uint8_t mixreg, tmp;
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
switch (port) {
case ESO_DAC_PLAY_VOL:
mixreg = ESO_MIXREG_PVR_A2;
diff --git a/sys/dev/pci/esovar.h b/sys/dev/pci/esovar.h
index 6c714761538..1719339e6f8 100644
--- a/sys/dev/pci/esovar.h
+++ b/sys/dev/pci/esovar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: esovar.h,v 1.9 2009/05/06 10:34:32 cegger Exp $ */
+/* $NetBSD: esovar.h,v 1.10 2011/11/23 23:07:35 jmcneill Exp $ */
/*
* Copyright (c) 1999, 2000, 2004 Klaus J. Klein
@@ -86,6 +86,9 @@
*/
struct eso_softc {
struct device sc_dev;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
+
pci_intr_handle_t * sc_ih;
unsigned int sc_revision; /* PCI Revision ID */
@@ -124,6 +127,8 @@ struct eso_softc {
void * sc_parg;
void (*sc_rintr)(void *);
void * sc_rarg;
+ kcondvar_t sc_pcv;
+ kcondvar_t sc_rcv;
/* Auto-initialize DMA transfer block drain timeouts, in ticks */
int sc_pdrain;
diff --git a/sys/dev/pci/fms.c b/sys/dev/pci/fms.c
index d2f2dcc0e32..114e9c2ce0c 100644
--- a/sys/dev/pci/fms.c
+++ b/sys/dev/pci/fms.c
@@ -1,7 +1,7 @@
-/* $NetBSD: fms.c,v 1.38 2010/11/13 13:52:05 uebayasi Exp $ */
+/* $NetBSD: fms.c,v 1.39 2011/11/23 23:07:35 jmcneill Exp $ */
/*-
- * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -34,14 +34,14 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fms.c,v 1.38 2010/11/13 13:52:05 uebayasi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fms.c,v 1.39 2011/11/23 23:07:35 jmcneill Exp $");
#include "mpu.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
#include <sys/audioio.h>
@@ -86,8 +86,8 @@ static int fms_getdev(void *, struct audio_device *);
static int fms_set_port(void *, mixer_ctrl_t *);
static int fms_get_port(void *, mixer_ctrl_t *);
static int fms_query_devinfo(void *, mixer_devinfo_t *);
-static void *fms_malloc(void *, int, size_t, struct malloc_type *, int);
-static void fms_free(void *, void *, struct malloc_type *);
+static void *fms_malloc(void *, int, size_t);
+static void fms_free(void *, void *, size_t);
static size_t fms_round_buffersize(void *, int, size_t);
static paddr_t fms_mappage(void *, void *, off_t, int);
static int fms_get_props(void *);
@@ -97,6 +97,7 @@ static int fms_trigger_output(void *, void *, void *, int,
static int fms_trigger_input(void *, void *, void *, int,
void (*)(void *), void *,
const audio_params_t *);
+static void fms_get_locks(void *, kmutex_t **, kmutex_t **);
CFATTACH_DECL(fms, sizeof (struct fms_softc),
fms_match, fms_attach, NULL, NULL);
@@ -136,7 +137,7 @@ static const struct audio_hw_if fms_hw_if = {
fms_trigger_output,
fms_trigger_input,
NULL,
- NULL,
+ fms_get_locks,
};
static int fms_attach_codec(void *, struct ac97_codec_if *);
@@ -240,18 +241,35 @@ fms_attach(device_t parent, device_t self, void *aux)
aprint_naive(": Audio controller\n");
aprint_normal(": Forte Media FM-801\n");
+ if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
+ &sc->sc_ioh, &sc->sc_ioaddr, &sc->sc_iosize)) {
+ aprint_error_dev(&sc->sc_dev, "can't map i/o space\n");
+ return;
+ }
+ if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x30, 2,
+ &sc->sc_mpu_ioh))
+ panic("fms_attach: can't get mpu subregion handle");
+ if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x68, 4,
+ &sc->sc_opl_ioh))
+ panic("fms_attach: can't get opl subregion handle");
+
if (pci_intr_map(pa, &ih)) {
aprint_error_dev(&sc->sc_dev, "couldn't map interrupt\n");
return;
}
intrstr = pci_intr_string(pc, ih);
- sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, fms_intr, sc);
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_SCHED, fms_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(&sc->sc_dev, "couldn't establish interrupt");
if (intrstr != NULL)
aprint_error(" at %s", intrstr);
aprint_error("\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
@@ -259,20 +277,6 @@ fms_attach(device_t parent, device_t self, void *aux)
aprint_normal_dev(&sc->sc_dev, "interrupting at %s\n", intrstr);
- if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
- &sc->sc_ioh, &sc->sc_ioaddr, &sc->sc_iosize)) {
- aprint_error_dev(&sc->sc_dev, "can't map i/o space\n");
- return;
- }
-
- if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x30, 2,
- &sc->sc_mpu_ioh))
- panic("fms_attach: can't get mpu subregion handle");
-
- if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x68, 4,
- &sc->sc_opl_ioh))
- panic("fms_attach: can't get opl subregion handle");
-
/* Disable legacy audio (SBPro compatibility) */
pci_conf_write(pc, pt, 0x40, 0);
@@ -304,8 +308,11 @@ fms_attach(device_t parent, device_t self, void *aux)
sc->host_if.write = fms_write_codec;
sc->host_if.reset = fms_reset_codec;
- if (ac97_attach(&sc->host_if, self) != 0)
+ if (ac97_attach(&sc->host_if, self, &sc->sc_lock) != 0) {
+ mutex_destroy(&sc->sc_intr_lock);
+ mutex_destroy(&sc->sc_lock);
return;
+ }
audio_attach_mi(&fms_hw_if, sc, &sc->sc_dev);
@@ -415,6 +422,8 @@ fms_intr(void *arg)
#endif
uint16_t istat;
+ mutex_spin_enter(&sc->sc_intr_lock);
+
istat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS);
if (istat & FM_INTSTATUS_PLAY) {
@@ -455,6 +464,8 @@ fms_intr(void *arg)
bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS,
istat & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC));
+ mutex_spin_exit(&sc->sc_intr_lock);
+
return 1;
}
@@ -664,8 +675,7 @@ fms_get_port(void *addr, mixer_ctrl_t *cp)
}
static void *
-fms_malloc(void *addr, int direction, size_t size,
- struct malloc_type *pool, int flags)
+fms_malloc(void *addr, int direction, size_t size)
{
struct fms_softc *sc;
struct fms_dma *p;
@@ -673,33 +683,33 @@ fms_malloc(void *addr, int direction, size_t size,
int rseg;
sc = addr;
- p = malloc(sizeof(*p), pool, flags);
+ p = kmem_alloc(sizeof(*p), KM_SLEEP);
if (p == NULL)
return NULL;
p->size = size;
if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &p->seg,
- 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
+ 1, &rseg, BUS_DMA_WAITOK)) != 0) {
aprint_error_dev(&sc->sc_dev, "unable to allocate DMA, error = %d\n", error);
goto fail_alloc;
}
if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
- BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
+ BUS_DMA_WAITOK | BUS_DMA_COHERENT)) != 0) {
aprint_error_dev(&sc->sc_dev, "unable to map DMA, error = %d\n",
error);
goto fail_map;
}
if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
- BUS_DMA_NOWAIT, &p->map)) != 0) {
+ BUS_DMA_WAITOK, &p->map)) != 0) {
aprint_error_dev(&sc->sc_dev, "unable to create DMA map, error = %d\n",
error);
goto fail_create;
}
if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
- BUS_DMA_NOWAIT)) != 0) {
+ BUS_DMA_WAITOK)) != 0) {
aprint_error_dev(&sc->sc_dev, "unable to load DMA map, error = %d\n",
error);
goto fail_load;
@@ -718,12 +728,12 @@ fail_create:
fail_map:
bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
fail_alloc:
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return NULL;
}
static void
-fms_free(void *addr, void *ptr, struct malloc_type *pool)
+fms_free(void *addr, void *ptr, size_t size)
{
struct fms_softc *sc;
struct fms_dma **pp, *p;
@@ -737,7 +747,7 @@ fms_free(void *addr, void *ptr, struct malloc_type *pool)
bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
*pp = p->next;
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return;
}
@@ -852,3 +862,13 @@ fms_trigger_input(void *addr, void *start, void *end, int blksize,
FM_REC_START | FM_REC_STOPNOW | sc->sc_rec_reg);
return 0;
}
+
+static void
+fms_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct fms_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
diff --git a/sys/dev/pci/fmsvar.h b/sys/dev/pci/fmsvar.h
index c009ca50031..e487ac3c6cf 100644
--- a/sys/dev/pci/fmsvar.h
+++ b/sys/dev/pci/fmsvar.h
@@ -1,7 +1,7 @@
-/* $NetBSD: fmsvar.h,v 1.5 2009/05/06 10:34:32 cegger Exp $ */
+/* $NetBSD: fmsvar.h,v 1.6 2011/11/23 23:07:35 jmcneill Exp $ */
/*-
- * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -36,6 +36,8 @@
struct fms_softc {
struct device sc_dev;
void *sc_ih;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
diff --git a/sys/dev/pci/gcscaudio.c b/sys/dev/pci/gcscaudio.c
index d61fd19c66b..aad1a558bee 100644
--- a/sys/dev/pci/gcscaudio.c
+++ b/sys/dev/pci/gcscaudio.c
@@ -1,4 +1,4 @@
-/* $NetBSD: gcscaudio.c,v 1.7 2011/06/09 14:46:33 joerg Exp $ */
+/* $NetBSD: gcscaudio.c,v 1.8 2011/11/23 23:07:35 jmcneill Exp $ */
/*-
* Copyright (c) 2008 SHIMIZU Ryo <ryo@nerv.org>
@@ -27,11 +27,11 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gcscaudio.c,v 1.7 2011/06/09 14:46:33 joerg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gcscaudio.c,v 1.8 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
#include <sys/queue.h>
@@ -85,6 +85,8 @@ struct gcscaudio_softc_ch {
struct gcscaudio_softc {
struct device sc_dev;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
pci_chipset_tag_t sc_pc;
pcitag_t sc_pt;
void *sc_ih;
@@ -138,8 +140,8 @@ static int gcscaudio_getdev(void *, struct audio_device *);
static int gcscaudio_set_port(void *, mixer_ctrl_t *);
static int gcscaudio_get_port(void *, mixer_ctrl_t *);
static int gcscaudio_query_devinfo(void *, mixer_devinfo_t *);
-static void *gcscaudio_malloc(void *, int, size_t, struct malloc_type *, int);
-static void gcscaudio_free(void *, void *, struct malloc_type *);
+static void *gcscaudio_malloc(void *, int, size_t);
+static void gcscaudio_free(void *, void *, size_t);
static size_t gcscaudio_round_buffersize(void *, int, size_t);
static paddr_t gcscaudio_mappage(void *, void *, off_t, int);
static int gcscaudio_get_props(void *);
@@ -149,6 +151,7 @@ static int gcscaudio_trigger_output(void *, void *, void *, int,
static int gcscaudio_trigger_input(void *, void *, void *, int,
void (*)(void *), void *,
const audio_params_t *);
+static void gcscaudio_get_locks(void *, kmutex_t **, kmutex_t **);
static bool gcscaudio_resume(device_t, const pmf_qual_t *);
static int gcscaudio_intr(void *);
@@ -168,7 +171,7 @@ static int gcscaudio_set_params_ch(struct gcscaudio_softc *,
audio_params_t *, stream_filter_list_t *);
static int gcscaudio_allocate_dma(struct gcscaudio_softc *, size_t, void **,
bus_dma_segment_t *, int, int *,
- int, bus_dmamap_t *);
+ bus_dmamap_t *);
CFATTACH_DECL(gcscaudio, sizeof (struct gcscaudio_softc),
@@ -209,7 +212,7 @@ static const struct audio_hw_if gcscaudio_hw_if = {
.trigger_output = gcscaudio_trigger_output,
.trigger_input = gcscaudio_trigger_input,
.dev_ioctl = NULL,
- .powerstate = NULL
+ .get_locks = gcscaudio_get_locks,
};
static const struct audio_format gcscaudio_formats_2ch = {
@@ -271,6 +274,8 @@ gcscaudio_attach(device_t parent, device_t self, void *aux)
sc->sc_dmat = pa->pa_dmat;
LIST_INIT(&sc->sc_dmalist);
sc->sc_mch_split_buf = NULL;
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
aprint_normal(": AMD Geode CS5536 Audio\n");
@@ -286,7 +291,7 @@ gcscaudio_attach(device_t parent, device_t self, void *aux)
}
intrstr = pci_intr_string(sc->sc_pc, ih);
- sc->sc_ih = pci_intr_establish(sc->sc_pc, ih, IPL_AUDIO,
+ sc->sc_ih = pci_intr_establish(sc->sc_pc, ih, IPL_SCHED,
gcscaudio_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(&sc->sc_dev, "couldn't establish interrupt");
@@ -301,7 +306,7 @@ gcscaudio_attach(device_t parent, device_t self, void *aux)
if (gcscaudio_allocate_dma(sc, sizeof(*sc->sc_prd.p_prdtables),
(void **)&(sc->sc_prd.p_prdtables), sc->sc_prd.p_prdsegs, 1,
- &(sc->sc_prd.p_prdnseg), M_WAITOK, &(sc->sc_prd.p_prdmap)) != 0)
+ &(sc->sc_prd.p_prdnseg), &(sc->sc_prd.p_prdmap)) != 0)
goto attach_failure_intr;
sc->host_if.arg = sc;
@@ -311,7 +316,7 @@ gcscaudio_attach(device_t parent, device_t self, void *aux)
sc->host_if.reset = gcscaudio_reset_codec;
sc->host_if.spdif_event = gcscaudio_spdif_event_codec;
- if ((rc = ac97_attach(&sc->host_if, self)) != 0) {
+ if ((rc = ac97_attach(&sc->host_if, self, &sc->sc_lock)) != 0) {
aprint_error_dev(&sc->sc_dev,
"can't attach codec (error=%d)\n", rc);
goto attach_failure_intr;
@@ -607,7 +612,7 @@ gcscaudio_halt_output(void *arg)
/* channel splitter */
sc->sc_mch_splitter = NULL;
if (sc->sc_mch_split_buf)
- gcscaudio_free(sc, sc->sc_mch_split_buf, M_DEVBUF);
+ gcscaudio_free(sc, sc->sc_mch_split_buf, sc->sc_mch_split_size);
sc->sc_mch_split_buf = NULL;
return 0;
@@ -660,8 +665,7 @@ gcscaudio_query_devinfo(void *addr, mixer_devinfo_t *dip)
}
static void *
-gcscaudio_malloc(void *arg, int direction, size_t size,
- struct malloc_type *pool, int flags)
+gcscaudio_malloc(void *arg, int direction, size_t size)
{
struct gcscaudio_softc *sc;
struct gcscaudio_dma *p;
@@ -669,17 +673,15 @@ gcscaudio_malloc(void *arg, int direction, size_t size,
sc = (struct gcscaudio_softc *)arg;
- p = malloc(sizeof(*p), pool, flags);
+ p = kmem_alloc(sizeof(*p), KM_SLEEP);
if (p == NULL)
return NULL;
p->size = size;
error = gcscaudio_allocate_dma(sc, size, &p->addr,
- p->segs, sizeof(p->segs)/sizeof(p->segs[0]), &p->nseg,
- BUS_DMA_NOWAIT, &p->map);
-
+ p->segs, sizeof(p->segs)/sizeof(p->segs[0]), &p->nseg, &p->map);
if (error) {
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return NULL;
}
@@ -688,7 +690,7 @@ gcscaudio_malloc(void *arg, int direction, size_t size,
}
static void
-gcscaudio_free(void *arg, void *ptr, struct malloc_type *pool)
+gcscaudio_free(void *arg, void *ptr, size_t size)
{
struct gcscaudio_softc *sc;
struct gcscaudio_dma *p;
@@ -703,7 +705,7 @@ gcscaudio_free(void *arg, void *ptr, struct malloc_type *pool)
bus_dmamem_free(sc->sc_dmat, p->segs, p->nseg);
LIST_REMOVE(p, list);
- free(p, pool);
+ kmem_free(p, sizeof(*p));
break;
}
}
@@ -1041,10 +1043,11 @@ gcscaudio_trigger_output(void *addr, void *start, void *end, int blksize,
* BM7: none
*/
if (sc->sc_mch_split_buf)
- gcscaudio_free(sc, sc->sc_mch_split_buf, M_DEVBUF);
+ gcscaudio_free(sc, sc->sc_mch_split_buf,
+ sc->sc_mch_split_size);
if ((sc->sc_mch_split_buf = gcscaudio_malloc(sc, AUMODE_PLAY,
- size, M_DEVBUF, M_WAITOK)) == NULL)
+ size)) == NULL)
return ENOMEM;
/*
@@ -1096,10 +1099,11 @@ gcscaudio_trigger_output(void *addr, void *start, void *end, int blksize,
*
*/
if (sc->sc_mch_split_buf)
- gcscaudio_free(sc, sc->sc_mch_split_buf, M_DEVBUF);
+ gcscaudio_free(sc, sc->sc_mch_split_buf,
+ sc->sc_mch_split_size);
if ((sc->sc_mch_split_buf = gcscaudio_malloc(sc, AUMODE_PLAY,
- size, M_DEVBUF, M_WAITOK)) == NULL)
+ size)) == NULL)
return ENOMEM;
/*
@@ -1184,6 +1188,17 @@ gcscaudio_trigger_input(void *addr, void *start, void *end, int blksize,
return 0;
}
+static void
+gcscaudio_get_locks(void *arg, kmutex_t **intr, kmutex_t **thread)
+{
+ struct gcscaudio_softc *sc;
+
+ sc = (struct gcscaudio_softc *)arg;
+
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
static int
gcscaudio_intr(void *arg)
{
@@ -1194,9 +1209,12 @@ gcscaudio_intr(void *arg)
nintr = 0;
sc = (struct gcscaudio_softc *)arg;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
+
intr = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ACC_IRQ_STATUS);
if (intr == 0)
- return 0;
+ goto done;
/* Front output */
if (intr & ACC_IRQ_STATUS_BM0_IRQ_STS) {
@@ -1273,6 +1291,9 @@ gcscaudio_intr(void *arg)
aprint_normal_dev(&sc->sc_dev, "Audio Bus Master 5 IRQ Status\n");
#endif
+done:
+ mutex_spin_exit(&sc->sc_intr_lock);
+
return nintr ? 1 : 0;
}
@@ -1291,19 +1312,19 @@ gcscaudio_resume(device_t dv, const pmf_qual_t *qual)
static int
gcscaudio_allocate_dma(struct gcscaudio_softc *sc, size_t size, void **addrp,
bus_dma_segment_t *seglist, int nseg, int *rsegp,
- int flags, bus_dmamap_t *mapp)
+ bus_dmamap_t *mapp)
{
int error;
if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, seglist,
- nseg, rsegp, flags)) != 0) {
+ nseg, rsegp, BUS_DMA_WAITOK)) != 0) {
aprint_error_dev(&sc->sc_dev,
"unable to allocate DMA buffer, error=%d\n", error);
goto fail_alloc;
}
if ((error = bus_dmamem_map(sc->sc_dmat, seglist, nseg, size, addrp,
- BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
+ BUS_DMA_WAITOK | BUS_DMA_COHERENT)) != 0) {
aprint_error_dev(&sc->sc_dev,
"unable to map DMA buffer, error=%d\n",
error);
@@ -1311,14 +1332,14 @@ gcscaudio_allocate_dma(struct gcscaudio_softc *sc, size_t size, void **addrp,
}
if ((error = bus_dmamap_create(sc->sc_dmat, size, nseg, size, 0,
- BUS_DMA_NOWAIT, mapp)) != 0) {
+ BUS_DMA_WAITOK, mapp)) != 0) {
aprint_error_dev(&sc->sc_dev,
"unable to create DMA map, error=%d\n", error);
goto fail_create;
}
if ((error = bus_dmamap_load(sc->sc_dmat, *mapp, *addrp, size, NULL,
- BUS_DMA_NOWAIT)) != 0) {
+ BUS_DMA_WAITOK)) != 0) {
aprint_error_dev(&sc->sc_dev,
"unable to load DMA map, error=%d\n", error);
goto fail_load;
diff --git a/sys/dev/pci/hdaudio/hdafg.c b/sys/dev/pci/hdaudio/hdafg.c
index c2cd0dd1186..6d21a99fb30 100644
--- a/sys/dev/pci/hdaudio/hdafg.c
+++ b/sys/dev/pci/hdaudio/hdafg.c
@@ -1,4 +1,4 @@
-/* $NetBSD: hdafg.c,v 1.10 2011/10/25 00:00:13 jmcneill Exp $ */
+/* $NetBSD: hdafg.c,v 1.11 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (c) 2009 Precedence Technologies Ltd <support@precedence.co.uk>
@@ -60,7 +60,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hdafg.c,v 1.10 2011/10/25 00:00:13 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hdafg.c,v 1.11 2011/11/23 23:07:36 jmcneill Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -285,6 +285,8 @@ struct hdaudio_audiodev {
struct hdafg_softc {
device_t sc_dev;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
struct hdaudio_softc *sc_host;
struct hdaudio_codec *sc_codec;
struct hdaudio_function_group *sc_fg;
@@ -361,8 +363,8 @@ static int hdafg_halt_input(void *);
static int hdafg_set_port(void *, mixer_ctrl_t *);
static int hdafg_get_port(void *, mixer_ctrl_t *);
static int hdafg_query_devinfo(void *, mixer_devinfo_t *);
-static void * hdafg_allocm(void *, int, size_t, struct malloc_type *, int);
-static void hdafg_freem(void *, void *, struct malloc_type *);
+static void * hdafg_allocm(void *, int, size_t);
+static void hdafg_freem(void *, void *, size_t);
static int hdafg_getdev(void *, struct audio_device *);
static size_t hdafg_round_buffersize(void *, int, size_t);
static paddr_t hdafg_mappage(void *, void *, off_t, int);
@@ -373,6 +375,7 @@ static int hdafg_trigger_output(void *, void *, void *, int,
static int hdafg_trigger_input(void *, void *, void *, int,
void (*)(void *), void *,
const audio_params_t *);
+static void hdafg_get_locks(void *, kmutex_t **, kmutex_t **);
static const struct audio_hw_if hdafg_hw_if = {
.query_encoding = hdafg_query_encoding,
@@ -392,6 +395,7 @@ static const struct audio_hw_if hdafg_hw_if = {
.get_props = hdafg_get_props,
.trigger_output = hdafg_trigger_output,
.trigger_input = hdafg_trigger_input,
+ .get_locks = hdafg_get_locks,
};
static int
@@ -3162,15 +3166,16 @@ hdafg_stream_intr(struct hdaudio_stream *st)
hda_write1(ad->ad_sc->sc_host, HDAUDIO_SD_STS(st->st_shift),
HDAUDIO_STS_DESE | HDAUDIO_STS_FIFOE | HDAUDIO_STS_BCIS);
- //if (sts & HDAUDIO_STS_BCIS) {
- if (st == ad->ad_playback && ad->ad_playbackintr) {
- ad->ad_playbackintr(ad->ad_playbackintrarg);
- handled = 1;
- } else if (st == ad->ad_capture && ad->ad_captureintr) {
- ad->ad_captureintr(ad->ad_captureintrarg);
- handled = 1;
- }
- //}
+ mutex_spin_enter(&ad->ad_sc->sc_intr_lock);
+ /* XXX test (sts & HDAUDIO_STS_BCIS)? */
+ if (st == ad->ad_playback && ad->ad_playbackintr) {
+ ad->ad_playbackintr(ad->ad_playbackintrarg);
+ handled = 1;
+ } else if (st == ad->ad_capture && ad->ad_captureintr) {
+ ad->ad_captureintr(ad->ad_captureintrarg);
+ handled = 1;
+ }
+ mutex_spin_exit(&ad->ad_sc->sc_intr_lock);
return handled;
}
@@ -3545,6 +3550,9 @@ hdafg_attach(device_t parent, device_t self, void *opaque)
sc->sc_dev = self;
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
callout_init(&sc->sc_jack_callout, 0);
callout_setfunc(&sc->sc_jack_callout,
hdafg_hp_switch_handler, sc);
@@ -3713,6 +3721,9 @@ hdafg_detach(device_t self, int flags)
if (mx)
kmem_free(mx, sc->sc_nmixers * sizeof(*mx));
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
+
pmf_device_deregister(self);
return 0;
@@ -4032,8 +4043,7 @@ hdafg_query_devinfo(void *opaque, mixer_devinfo_t *di)
}
static void *
-hdafg_allocm(void *opaque, int direction, size_t size,
- struct malloc_type *type, int flags)
+hdafg_allocm(void *opaque, int direction, size_t size)
{
struct hdaudio_audiodev *ad = opaque;
struct hdaudio_stream *st;
@@ -4056,7 +4066,7 @@ hdafg_allocm(void *opaque, int direction, size_t size,
}
static void
-hdafg_freem(void *opaque, void *addr, struct malloc_type *type)
+hdafg_freem(void *opaque, void *addr, size_t size)
{
struct hdaudio_audiodev *ad = opaque;
struct hdaudio_stream *st;
@@ -4167,6 +4177,15 @@ hdafg_trigger_input(void *opaque, void *start, void *end, int blksize,
return 0;
}
+static void
+hdafg_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread)
+{
+ struct hdaudio_audiodev *ad = opaque;
+
+ *intr = &ad->ad_sc->sc_intr_lock;
+ *thread = &ad->ad_sc->sc_lock;
+}
+
static int
hdafg_unsol(device_t self, uint8_t tag)
{
diff --git a/sys/dev/pci/hdaudio/hdaudio.c b/sys/dev/pci/hdaudio/hdaudio.c
index eda9772a4ed..8bb0c75f934 100644
--- a/sys/dev/pci/hdaudio/hdaudio.c
+++ b/sys/dev/pci/hdaudio/hdaudio.c
@@ -1,4 +1,4 @@
-/* $NetBSD: hdaudio.c,v 1.16 2011/11/04 15:32:34 jakllsch Exp $ */
+/* $NetBSD: hdaudio.c,v 1.17 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (c) 2009 Precedence Technologies Ltd <support@precedence.co.uk>
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hdaudio.c,v 1.16 2011/11/04 15:32:34 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hdaudio.c,v 1.17 2011/11/23 23:07:36 jmcneill Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -778,8 +778,8 @@ hdaudio_attach(device_t dev, struct hdaudio_softc *sc)
KASSERT(sc->sc_memvalid == true);
sc->sc_dev = dev;
- mutex_init(&sc->sc_corb_mtx, MUTEX_DEFAULT, IPL_AUDIO);
- mutex_init(&sc->sc_stream_mtx, MUTEX_DEFAULT, IPL_AUDIO);
+ mutex_init(&sc->sc_corb_mtx, MUTEX_DEFAULT, IPL_SCHED);
+ mutex_init(&sc->sc_stream_mtx, MUTEX_DEFAULT, IPL_SCHED);
hdaudio_init(sc);
diff --git a/sys/dev/pci/hdaudio/hdaudio_pci.c b/sys/dev/pci/hdaudio/hdaudio_pci.c
index 59884f9d55e..5d22bfdc566 100644
--- a/sys/dev/pci/hdaudio/hdaudio_pci.c
+++ b/sys/dev/pci/hdaudio/hdaudio_pci.c
@@ -1,4 +1,4 @@
-/* $NetBSD: hdaudio_pci.c,v 1.8 2011/02/12 15:15:34 jmcneill Exp $ */
+/* $NetBSD: hdaudio_pci.c,v 1.9 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (c) 2009 Precedence Technologies Ltd <support@precedence.co.uk>
@@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hdaudio_pci.c,v 1.8 2011/02/12 15:15:34 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hdaudio_pci.c,v 1.9 2011/11/23 23:07:36 jmcneill Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -141,7 +141,7 @@ hdaudio_pci_attach(device_t parent, device_t self, void *opaque)
return;
}
intrstr = pci_intr_string(pa->pa_pc, ih);
- sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO,
+ sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_SCHED,
hdaudio_pci_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(self, "couldn't establish interrupt");
diff --git a/sys/dev/pci/joy_eap.c b/sys/dev/pci/joy_eap.c
index e6dfb3d1dee..83bc32718c5 100644
--- a/sys/dev/pci/joy_eap.c
+++ b/sys/dev/pci/joy_eap.c
@@ -1,18 +1,20 @@
-/* $NetBSD: joy_eap.c,v 1.12 2009/05/07 07:56:03 cegger Exp $ */
+/* $NetBSD: joy_eap.c,v 1.13 2011/11/23 23:07:35 jmcneill Exp $ */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: joy_eap.c,v 1.12 2009/05/07 07:56:03 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: joy_eap.c,v 1.13 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/audioio.h>
-#include <dev/audio_if.h>
#include <sys/bus.h>
+#include <dev/audio_if.h>
+
#include <dev/pci/eapreg.h>
#include <dev/pci/eapvar.h>
+
#include <dev/ic/joyvar.h>
struct joy_eap_aa {
@@ -98,6 +100,7 @@ static void
joy_eap_attach(device_t parent, device_t self, void *aux)
{
struct joy_softc *sc = device_private(self);
+ struct eap_softc *esc = device_private(parent);
struct joy_eap_aa *eaa = aux;
aprint_normal("\n");
@@ -105,6 +108,7 @@ joy_eap_attach(device_t parent, device_t self, void *aux)
sc->sc_iot = eaa->aa_iot;
sc->sc_ioh = eaa->aa_ioh;
sc->sc_dev = self;
+ sc->sc_lock = &esc->sc_lock;
joyattach(sc);
}
diff --git a/sys/dev/pci/joy_eso.c b/sys/dev/pci/joy_eso.c
index f4c61178878..cbb745e5a51 100644
--- a/sys/dev/pci/joy_eso.c
+++ b/sys/dev/pci/joy_eso.c
@@ -1,7 +1,7 @@
-/* $NetBSD: joy_eso.c,v 1.14 2008/04/28 20:23:55 martin Exp $ */
+/* $NetBSD: joy_eso.c,v 1.15 2011/11/23 23:07:35 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: joy_eso.c,v 1.14 2008/04/28 20:23:55 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: joy_eso.c,v 1.15 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -75,6 +75,7 @@ joy_eso_attach(device_t parent, device_t self, void *aux)
sc->sc_ioh = esc->sc_game_ioh;
sc->sc_iot = esc->sc_game_iot;
sc->sc_dev = self;
+ sc->sc_lock = &esc->sc_lock;
joyattach(sc);
}
diff --git a/sys/dev/pci/joy_pci.c b/sys/dev/pci/joy_pci.c
index 80ba4791203..d1c5d259458 100644
--- a/sys/dev/pci/joy_pci.c
+++ b/sys/dev/pci/joy_pci.c
@@ -1,7 +1,7 @@
-/* $NetBSD: joy_pci.c,v 1.17 2008/04/28 20:23:55 martin Exp $ */
+/* $NetBSD: joy_pci.c,v 1.18 2011/11/23 23:07:35 jmcneill Exp $ */
/*-
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * Copyright (c) 2000, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: joy_pci.c,v 1.17 2008/04/28 20:23:55 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: joy_pci.c,v 1.18 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -45,6 +45,11 @@ __KERNEL_RCSID(0, "$NetBSD: joy_pci.c,v 1.17 2008/04/28 20:23:55 martin Exp $");
#include <dev/ic/joyvar.h>
+struct joy_pci_softc {
+ struct joy_softc sc_joy;
+ kmutex_t sc_lock;
+};
+
static int bar_is_io(pci_chipset_tag_t pc, pcitag_t tag, int reg);
static int
@@ -70,26 +75,21 @@ static int
bar_is_io(pci_chipset_tag_t pc, pcitag_t tag, int reg)
{
pcireg_t address, mask;
- int s;
- /*
- * The splhigh() is not realy necessary at autoconfig time,
- * but maybe useful if used in lkm context later.
- */
- s = splhigh();
address = pci_conf_read(pc, tag, reg);
pci_conf_write(pc, tag, reg, 0xffffffff);
mask = pci_conf_read(pc, tag, reg);
pci_conf_write(pc, tag, reg, address);
- splx(s);
- return (PCI_MAPREG_TYPE(address) == PCI_MAPREG_TYPE_IO && PCI_MAPREG_IO_SIZE(mask) > 0);
+ return (PCI_MAPREG_TYPE(address) == PCI_MAPREG_TYPE_IO &&
+ PCI_MAPREG_IO_SIZE(mask) > 0);
}
static void
joy_pci_attach(device_t parent, device_t self, void *aux)
{
struct joy_softc *sc = device_private(self);
+ struct joy_pci_softc *psc = device_private(self);
struct pci_attach_args *pa = aux;
char devinfo[256];
bus_size_t mapsize;
@@ -115,16 +115,19 @@ joy_pci_attach(device_t parent, device_t self, void *aux)
}
if (mapsize != 2) {
- if (!bus_space_subregion(sc->sc_iot, sc->sc_ioh, 1, 1, &sc->sc_ioh) < 0) {
+ if (!bus_space_subregion(sc->sc_iot, sc->sc_ioh, 1, 1,
+ &sc->sc_ioh) < 0) {
aprint_error_dev(self, "error mapping subregion\n");
return;
}
}
+ mutex_init(&psc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
sc->sc_dev = self;
+ sc->sc_lock = &psc->sc_lock;
joyattach(sc);
}
-CFATTACH_DECL_NEW(joy_pci, sizeof(struct joy_softc),
+CFATTACH_DECL_NEW(joy_pci, sizeof(struct joy_pci_softc),
joy_pci_match, joy_pci_attach, NULL, NULL);
diff --git a/sys/dev/pci/mpu_cmpci.c b/sys/dev/pci/mpu_cmpci.c
index de29f459348..b9e03cb8c86 100644
--- a/sys/dev/pci/mpu_cmpci.c
+++ b/sys/dev/pci/mpu_cmpci.c
@@ -1,7 +1,7 @@
-/* $NetBSD: mpu_cmpci.c,v 1.15 2008/04/28 20:23:55 martin Exp $ */
+/* $NetBSD: mpu_cmpci.c,v 1.16 2011/11/23 23:07:35 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mpu_cmpci.c,v 1.15 2008/04/28 20:23:55 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mpu_cmpci.c,v 1.16 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -79,6 +79,7 @@ mpu_cmpci_attach(device_t parent, device_t self, void *aux)
sc->ioh = ysc->sc_mpu_ioh;
sc->model = "CMPCI MPU-401 MIDI UART";
sc->sc_dev = self;
+ sc->lock = &ysc->sc_intr_lock;
mpu_attach(sc);
}
diff --git a/sys/dev/pci/mpu_eso.c b/sys/dev/pci/mpu_eso.c
index ee3d0671a7b..4f118a56096 100644
--- a/sys/dev/pci/mpu_eso.c
+++ b/sys/dev/pci/mpu_eso.c
@@ -1,7 +1,7 @@
-/* $NetBSD: mpu_eso.c,v 1.16 2008/04/28 20:23:55 martin Exp $ */
+/* $NetBSD: mpu_eso.c,v 1.17 2011/11/23 23:07:35 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mpu_eso.c,v 1.16 2008/04/28 20:23:55 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mpu_eso.c,v 1.17 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -80,6 +80,7 @@ mpu_eso_attach(device_t parent, device_t self, void *aux)
sc->iot = esc->sc_mpu_iot;
sc->model = "ESO MPU-401 MIDI UART";
sc->sc_dev = self;
+ sc->lock = &esc->sc_intr_lock;
mpu_attach(sc);
}
diff --git a/sys/dev/pci/mpu_fms.c b/sys/dev/pci/mpu_fms.c
index c9dd8ab8831..2375c190968 100644
--- a/sys/dev/pci/mpu_fms.c
+++ b/sys/dev/pci/mpu_fms.c
@@ -1,7 +1,7 @@
-/* $NetBSD: mpu_fms.c,v 1.16 2008/04/28 20:23:55 martin Exp $ */
+/* $NetBSD: mpu_fms.c,v 1.17 2011/11/23 23:07:35 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mpu_fms.c,v 1.16 2008/04/28 20:23:55 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mpu_fms.c,v 1.17 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -81,6 +81,7 @@ mpu_fms_attach(device_t parent, device_t self, void *aux)
sc->iot = ssc->sc_iot;
sc->model = "FM801 MPU-401 MIDI UART";
sc->sc_dev = self;
+ sc->lock = &ssc->sc_intr_lock;
mpu_attach(sc);
}
diff --git a/sys/dev/pci/mpu_yds.c b/sys/dev/pci/mpu_yds.c
index 30ccc2f58ac..0e9bbb15999 100644
--- a/sys/dev/pci/mpu_yds.c
+++ b/sys/dev/pci/mpu_yds.c
@@ -1,7 +1,7 @@
-/* $NetBSD: mpu_yds.c,v 1.15 2008/04/28 20:23:55 martin Exp $ */
+/* $NetBSD: mpu_yds.c,v 1.16 2011/11/23 23:07:35 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mpu_yds.c,v 1.15 2008/04/28 20:23:55 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mpu_yds.c,v 1.16 2011/11/23 23:07:35 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -84,6 +84,7 @@ mpu_yds_attach(device_t parent, device_t self, void *aux)
#ifndef AUDIO_NO_POWER_CTL
sc->powerctl = 0;
#endif
+ sc->lock = &ysc->sc_intr_lock;
sc->sc_dev = self;
mpu_attach(sc);
diff --git a/sys/dev/pci/neo.c b/sys/dev/pci/neo.c
index 10acbcfd5af..688f3a0b0ce 100644
--- a/sys/dev/pci/neo.c
+++ b/sys/dev/pci/neo.c
@@ -1,4 +1,4 @@
-/* $NetBSD: neo.c,v 1.45 2010/02/24 22:38:01 dyoung Exp $ */
+/* $NetBSD: neo.c,v 1.46 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
@@ -32,29 +32,26 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: neo.c,v 1.45 2010/02/24 22:38:01 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: neo.c,v 1.46 2011/11/23 23:07:36 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
-
#include <sys/bus.h>
-
-#include <dev/pci/pcidevs.h>
-#include <dev/pci/pcivar.h>
-
-#include <dev/pci/neoreg.h>
-#include <dev/pci/neo-coeff.h>
-
#include <sys/audioio.h>
+
#include <dev/audio_if.h>
#include <dev/mulaw.h>
#include <dev/auconv.h>
#include <dev/ic/ac97var.h>
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/neoreg.h>
+#include <dev/pci/neo-coeff.h>
/* -------------------------------------------------------------------- */
/*
@@ -120,6 +117,8 @@ __KERNEL_RCSID(0, "$NetBSD: neo.c,v 1.45 2010/02/24 22:38:01 dyoung Exp $");
/* device private data */
struct neo_softc {
struct device dev;
+ kmutex_t lock;
+ kmutex_t intr_lock;
bus_space_tag_t bufiot;
bus_space_handle_t bufioh;
@@ -200,11 +199,12 @@ static int neo_write_codec(void *, uint8_t, uint16_t);
static int neo_reset_codec(void *);
static enum ac97_host_flags neo_flags_codec(void *);
static int neo_query_devinfo(void *, mixer_devinfo_t *);
-static void * neo_malloc(void *, int, size_t, struct malloc_type *, int);
-static void neo_free(void *, void *, struct malloc_type *);
+static void * neo_malloc(void *, int, size_t);
+static void neo_free(void *, void *, size_t);
static size_t neo_round_buffersize(void *, int, size_t);
static paddr_t neo_mappage(void *, void *, off_t, int);
static int neo_get_props(void *);
+static void neo_get_locks(void *, kmutex_t **, kmutex_t **);
CFATTACH_DECL(neo, sizeof(struct neo_softc),
neo_match, neo_attach, NULL, NULL);
@@ -270,7 +270,7 @@ static const struct audio_hw_if neo_hw_if = {
neo_trigger_output,
neo_trigger_input,
NULL,
- NULL,
+ neo_get_locks,
};
/* -------------------------------------------------------------------- */
@@ -365,6 +365,8 @@ neo_intr(void *p)
int rv;
sc = (struct neo_softc *)p;
+ mutex_spin_enter(&sc->intr_lock);
+
rv = 0;
status = (sc->irsz == 2) ?
nm_rd_2(sc, NM_INT_REG) :
@@ -420,6 +422,7 @@ neo_intr(void *p)
rv = 1;
}
+ mutex_spin_exit(&sc->intr_lock);
return rv;
}
@@ -553,8 +556,12 @@ neo_resume(device_t dv, const pmf_qual_t *qual)
{
struct neo_softc *sc = device_private(dv);
+ mutex_enter(&sc->lock);
+ mutex_spin_enter(&sc->intr_lock);
nm_init(sc);
- sc->codec_if->vtbl->restore_ports(sc->codec_if);
+ mutex_spin_exit(&sc->intr_lock);
+ sc->codec_if->vtbl->restore_ports(sc->codec_if);
+ mutex_exit(&sc->lock);
return true;
}
@@ -568,6 +575,7 @@ neo_attach(device_t parent, device_t self, void *aux)
char const *intrstr;
pci_intr_handle_t ih;
pcireg_t csr;
+ int error;
sc = device_private(self);
pa = (struct pci_attach_args *)aux;
@@ -597,20 +605,31 @@ neo_attach(device_t parent, device_t self, void *aux)
return;
}
+ mutex_init(&sc->lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
intrstr = pci_intr_string(pc, ih);
- sc->ih = pci_intr_establish(pc, ih, IPL_AUDIO, neo_intr, sc);
+ sc->ih = pci_intr_establish(pc, ih, IPL_SCHED, neo_intr, sc);
if (sc->ih == NULL) {
aprint_error_dev(&sc->dev, "couldn't establish interrupt");
if (intrstr != NULL)
aprint_error(" at %s", intrstr);
aprint_error("\n");
+ mutex_destroy(&sc->lock);
+ mutex_destroy(&sc->intr_lock);
return;
}
aprint_normal_dev(&sc->dev, "interrupting at %s\n", intrstr);
- if (nm_init(sc) != 0)
+ mutex_spin_enter(&sc->intr_lock);
+ error = nm_init(sc);
+ mutex_spin_exit(&sc->intr_lock);
+ if (error != 0) {
+ mutex_destroy(&sc->lock);
+ mutex_destroy(&sc->intr_lock);
return;
+ }
/* Enable the device. */
csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
@@ -618,15 +637,17 @@ neo_attach(device_t parent, device_t self, void *aux)
csr | PCI_COMMAND_MASTER_ENABLE);
sc->host_if.arg = sc;
-
sc->host_if.attach = neo_attach_codec;
sc->host_if.read = neo_read_codec;
sc->host_if.write = neo_write_codec;
sc->host_if.reset = neo_reset_codec;
sc->host_if.flags = neo_flags_codec;
- if (ac97_attach(&sc->host_if, self) != 0)
+ if (ac97_attach(&sc->host_if, self, &sc->lock) != 0) {
+ mutex_destroy(&sc->lock);
+ mutex_destroy(&sc->intr_lock);
return;
+ }
if (!pmf_device_register(self, NULL, neo_resume))
aprint_error_dev(self, "couldn't establish power handler\n");
@@ -942,8 +963,7 @@ neo_query_devinfo(void *addr, mixer_devinfo_t *dip)
}
static void *
-neo_malloc(void *addr, int direction, size_t size,
- struct malloc_type *pool, int flags)
+neo_malloc(void *addr, int direction, size_t size)
{
struct neo_softc *sc;
void *rv;
@@ -970,7 +990,7 @@ neo_malloc(void *addr, int direction, size_t size,
}
static void
-neo_free(void *addr, void *ptr, struct malloc_type *pool)
+neo_free(void *addr, void *ptr, size_t size)
{
struct neo_softc *sc;
vaddr_t v;
@@ -986,8 +1006,7 @@ neo_free(void *addr, void *ptr, struct malloc_type *pool)
}
static size_t
-neo_round_buffersize(void *addr, int direction,
- size_t size)
+neo_round_buffersize(void *addr, int direction, size_t size)
{
return NM_BUFFSIZE;
@@ -1020,3 +1039,13 @@ neo_get_props(void *addr)
return AUDIO_PROP_INDEPENDENT | AUDIO_PROP_MMAP |
AUDIO_PROP_FULLDUPLEX;
}
+
+static void
+neo_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct neo_softc *sc;
+
+ sc = addr;
+ *intr = &sc->intr_lock;
+ *thread = &sc->lock;
+}
diff --git a/sys/dev/pci/opl_eso.c b/sys/dev/pci/opl_eso.c
index 3e60f890c56..85ca4ced1fd 100644
--- a/sys/dev/pci/opl_eso.c
+++ b/sys/dev/pci/opl_eso.c
@@ -1,4 +1,4 @@
-/* $NetBSD: opl_eso.c,v 1.16 2008/04/28 20:23:55 martin Exp $ */
+/* $NetBSD: opl_eso.c,v 1.17 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: opl_eso.c,v 1.16 2008/04/28 20:23:55 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: opl_eso.c,v 1.17 2011/11/23 23:07:36 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -76,6 +76,7 @@ opl_eso_attach(device_t parent, device_t self, void *aux)
sc->ioh = esc->sc_sb_ioh;
sc->iot = esc->sc_sb_iot;
sc->offs = 0;
+ sc->lock = &esc->sc_intr_lock;
strcpy(sc->syn.name, "ESO ");
/*sc->spkrctl = 0;
sc->spkrarg = 0;*/
diff --git a/sys/dev/pci/sv.c b/sys/dev/pci/sv.c
index 8cf9d4f9e0a..657a39708b3 100644
--- a/sys/dev/pci/sv.c
+++ b/sys/dev/pci/sv.c
@@ -1,8 +1,8 @@
-/* $NetBSD: sv.c,v 1.44 2009/11/26 15:17:10 njoly Exp $ */
+/* $NetBSD: sv.c,v 1.45 2011/11/23 23:07:36 jmcneill Exp $ */
/* $OpenBSD: sv.c,v 1.2 1998/07/13 01:50:15 csapuntz Exp $ */
/*
- * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -67,12 +67,12 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sv.c,v 1.44 2009/11/26 15:17:10 njoly Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sv.c,v 1.45 2011/11/23 23:07:36 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
#include <dev/pci/pcireg.h>
@@ -159,11 +159,12 @@ static int sv_getdev(void *, struct audio_device *);
static int sv_mixer_set_port(void *, mixer_ctrl_t *);
static int sv_mixer_get_port(void *, mixer_ctrl_t *);
static int sv_query_devinfo(void *, mixer_devinfo_t *);
-static void * sv_malloc(void *, int, size_t, struct malloc_type *, int);
-static void sv_free(void *, void *, struct malloc_type *);
+static void * sv_malloc(void *, int, size_t);
+static void sv_free(void *, void *, size_t);
static size_t sv_round_buffersize(void *, int, size_t);
static paddr_t sv_mappage(void *, void *, off_t, int);
static int sv_get_props(void *);
+static void sv_get_locks(void *, kmutex_t **, kmutex_t **);
#ifdef AUDIO_DEBUG
void sv_dumpregs(struct sv_softc *sc);
@@ -197,7 +198,7 @@ static const struct audio_hw_if sv_hw_if = {
sv_trigger_output,
sv_trigger_input,
NULL,
- NULL,
+ sv_get_locks,
};
#define SV_NFORMATS 4
@@ -235,12 +236,9 @@ static uint8_t
sv_read_indirect(struct sv_softc *sc, uint8_t reg)
{
uint8_t val;
- int s;
- s = splaudio();
sv_write(sc, SV_CODEC_IADDR, reg & SV_IADDR_MASK);
val = sv_read(sc, SV_CODEC_IDATA);
- splx(s);
return val;
}
@@ -248,16 +246,13 @@ static void
sv_write_indirect(struct sv_softc *sc, uint8_t reg, uint8_t val)
{
uint8_t iaddr;
- int s;
iaddr = reg & SV_IADDR_MASK;
- s = splaudio();
if (reg == SV_DMA_DATA_FORMAT)
iaddr |= SV_IADDR_MCE;
sv_write(sc, SV_CODEC_IADDR, iaddr);
sv_write(sc, SV_CODEC_IDATA, val);
- splx(s);
}
static int
@@ -425,26 +420,24 @@ sv_attach(device_t parent, device_t self, void *aux)
DPRINTF(("sv_attach: control=0x%x\n", sv_read(sc, SV_CODEC_CONTROL)));
- /* Enable DMA interrupts */
- reg = sv_read(sc, SV_CODEC_INTMASK);
- reg &= ~(SV_INTMASK_DMAA | SV_INTMASK_DMAC);
- reg |= SV_INTMASK_UD | SV_INTMASK_SINT | SV_INTMASK_MIDI;
- sv_write(sc, SV_CODEC_INTMASK, reg);
-
- sv_read(sc, SV_CODEC_STATUS);
-
/* Map and establish the interrupt. */
if (pci_intr_map(pa, &ih)) {
aprint_error_dev(&sc->sc_dev, "couldn't map interrupt\n");
return;
}
+
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
intrstr = pci_intr_string(pc, ih);
- sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, sv_intr, sc);
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_SCHED, sv_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(&sc->sc_dev, "couldn't establish interrupt");
if (intrstr != NULL)
aprint_error(" at %s", intrstr);
aprint_error("\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
printf("%s: interrupting at %s\n", device_xname(&sc->sc_dev), intrstr);
@@ -456,6 +449,13 @@ sv_attach(device_t parent, device_t self, void *aux)
printf(", wavetable ROM present");
printf("\n");
+ /* Enable DMA interrupts */
+ reg = sv_read(sc, SV_CODEC_INTMASK);
+ reg &= ~(SV_INTMASK_DMAA | SV_INTMASK_DMAC);
+ reg |= SV_INTMASK_UD | SV_INTMASK_SINT | SV_INTMASK_MIDI;
+ sv_write(sc, SV_CODEC_INTMASK, reg);
+ sv_read(sc, SV_CODEC_STATUS);
+
sv_init_mixer(sc);
audio_attach_mi(&sv_hw_if, sc, &sc->sc_dev);
@@ -500,12 +500,12 @@ sv_intr(void *p)
uint8_t intr;
sc = p;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
+
intr = sv_read(sc, SV_CODEC_STATUS);
DPRINTFN(5,("sv_intr: intr=0x%x\n", intr));
- if (!(intr & (SV_INTSTATUS_DMAA | SV_INTSTATUS_DMAC)))
- return 0;
-
if (intr & SV_INTSTATUS_DMAA) {
if (sc->sc_pintr)
sc->sc_pintr(sc->sc_parg);
@@ -516,7 +516,9 @@ sv_intr(void *p)
sc->sc_rintr(sc->sc_rarg);
}
- return 1;
+ mutex_spin_exit(&sc->sc_intr_lock);
+
+ return (intr & (SV_INTSTATUS_DMAA | SV_INTSTATUS_DMAC)) != 0;
}
static int
@@ -527,22 +529,22 @@ sv_allocmem(struct sv_softc *sc, size_t size, size_t align,
p->size = size;
error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
- p->segs, ARRAY_SIZE(p->segs), &p->nsegs, BUS_DMA_NOWAIT);
+ p->segs, ARRAY_SIZE(p->segs), &p->nsegs, BUS_DMA_WAITOK);
if (error)
return error;
error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
- &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
+ &p->addr, BUS_DMA_WAITOK|BUS_DMA_COHERENT);
if (error)
goto free;
error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
- 0, BUS_DMA_NOWAIT, &p->map);
+ 0, BUS_DMA_WAITOK, &p->map);
if (error)
goto unmap;
error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL,
- BUS_DMA_NOWAIT | (direction == AUMODE_RECORD) ? BUS_DMA_READ : BUS_DMA_WRITE);
+ BUS_DMA_WAITOK | (direction == AUMODE_RECORD) ? BUS_DMA_READ : BUS_DMA_WRITE);
if (error)
goto destroy;
DPRINTF(("sv_allocmem: pa=%lx va=%lx pba=%lx\n",
@@ -694,8 +696,10 @@ sv_set_params(void *addr, int setmode, int usemode, audio_params_t *play,
if (val > 65535)
val = 65535;
+ mutex_spin_enter(&sc->sc_intr_lock);
sv_write_indirect(sc, SV_PCM_SAMPLE_RATE_0, val & 0xff);
sv_write_indirect(sc, SV_PCM_SAMPLE_RATE_1, val >> 8);
+ mutex_spin_exit(&sc->sc_intr_lock);
#define F_REF 24576000
@@ -754,9 +758,11 @@ sv_set_params(void *addr, int setmode, int usemode, audio_params_t *play,
best_n -= 2;
best_m -= 2;
+ mutex_spin_enter(&sc->sc_intr_lock);
sv_write_indirect(sc, SV_ADC_PLL_M, best_m);
sv_write_indirect(sc, SV_ADC_PLL_N,
best_n | (a << SV_PLL_R_SHIFT));
+ mutex_spin_exit(&sc->sc_intr_lock);
}
return 0;
@@ -1102,6 +1108,7 @@ sv_mixer_set_port(void *addr, mixer_ctrl_t *cp)
if (cp->type != AUDIO_MIXER_ENUM)
return EINVAL;
+ mutex_spin_enter(&sc->sc_intr_lock);
reg = sv_read_indirect(sc, ports[idx].l_port);
if (cp->un.ord)
reg |= SV_MUTE_BIT;
@@ -1117,6 +1124,7 @@ sv_mixer_set_port(void *addr, mixer_ctrl_t *cp)
reg &= ~SV_MUTE_BIT;
sv_write_indirect(sc, ports[idx].r_port, reg);
}
+ mutex_spin_exit(&sc->sc_intr_lock);
} else {
int lval, rval;
@@ -1140,7 +1148,7 @@ sv_mixer_set_port(void *addr, mixer_ctrl_t *cp)
rval = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
}
-
+ mutex_spin_enter(&sc->sc_intr_lock);
reg = sv_read_indirect(sc, ports[idx].l_port);
reg &= ~(ports[idx].mask);
lval = (AUDIO_MAX_GAIN - lval) * ports[idx].mask /
@@ -1160,6 +1168,7 @@ sv_mixer_set_port(void *addr, mixer_ctrl_t *cp)
}
sv_read_indirect(sc, ports[idx].l_port);
+ mutex_spin_exit(&sc->sc_intr_lock);
}
return 0;
@@ -1179,6 +1188,7 @@ sv_mixer_set_port(void *addr, mixer_ctrl_t *cp)
return EINVAL;
found:
+ mutex_spin_enter(&sc->sc_intr_lock);
reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
reg &= ~SV_REC_SOURCE_MASK;
reg |= (((cp->un.ord) << SV_REC_SOURCE_SHIFT) & SV_REC_SOURCE_MASK);
@@ -1188,6 +1198,7 @@ sv_mixer_set_port(void *addr, mixer_ctrl_t *cp)
reg &= ~SV_REC_SOURCE_MASK;
reg |= (((cp->un.ord) << SV_REC_SOURCE_SHIFT) & SV_REC_SOURCE_MASK);
sv_write_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL, reg);
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
case SV_RECORD_GAIN:
@@ -1203,6 +1214,7 @@ sv_mixer_set_port(void *addr, mixer_ctrl_t *cp)
val = (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]
* SV_REC_GAIN_MASK) / AUDIO_MAX_GAIN;
+ mutex_spin_enter(&sc->sc_intr_lock);
reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
reg &= ~SV_REC_GAIN_MASK;
reg |= val;
@@ -1212,6 +1224,7 @@ sv_mixer_set_port(void *addr, mixer_ctrl_t *cp)
reg &= ~SV_REC_GAIN_MASK;
reg |= val;
sv_write_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL, reg);
+ mutex_spin_exit(&sc->sc_intr_lock);
}
return (0);
@@ -1219,6 +1232,7 @@ sv_mixer_set_port(void *addr, mixer_ctrl_t *cp)
if (cp->type != AUDIO_MIXER_ENUM)
return EINVAL;
+ mutex_spin_enter(&sc->sc_intr_lock);
reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
if (cp->un.ord) {
reg |= SV_MIC_BOOST_BIT;
@@ -1227,12 +1241,14 @@ sv_mixer_set_port(void *addr, mixer_ctrl_t *cp)
}
sv_write_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL, reg);
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
case SV_SRS_MODE:
if (cp->type != AUDIO_MIXER_ENUM)
return EINVAL;
+ mutex_spin_enter(&sc->sc_intr_lock);
reg = sv_read_indirect(sc, SV_SRS_SPACE_CONTROL);
if (cp->un.ord) {
reg &= ~SV_SRS_SPACE_ONOFF;
@@ -1241,6 +1257,7 @@ sv_mixer_set_port(void *addr, mixer_ctrl_t *cp)
}
sv_write_indirect(sc, SV_SRS_SPACE_CONTROL, reg);
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
}
@@ -1251,10 +1268,14 @@ static int
sv_mixer_get_port(void *addr, mixer_ctrl_t *cp)
{
struct sv_softc *sc;
- int val;
+ int val, error;
uint8_t reg;
sc = addr;
+ error = 0;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
+
if (cp->dev >= SV_FIRST_MIXER &&
cp->dev <= SV_LAST_MIXER) {
int off = cp->dev - SV_FIRST_MIXER;
@@ -1266,83 +1287,101 @@ sv_mixer_get_port(void *addr, mixer_ctrl_t *cp)
idx = off / 2;
if (mute) {
if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
-
- reg = sv_read_indirect(sc, ports[idx].l_port);
- cp->un.ord = ((reg & SV_MUTE_BIT) ? 1 : 0);
+ error = EINVAL;
+ else {
+ reg = sv_read_indirect(sc, ports[idx].l_port);
+ cp->un.ord = ((reg & SV_MUTE_BIT) ? 1 : 0);
+ }
} else {
- if (cp->type != AUDIO_MIXER_VALUE)
- return EINVAL;
-
- if (cp->un.value.num_channels != 1 &&
- cp->un.value.num_channels != 2)
- return EINVAL;
-
- if ((ports[idx].r_port == 0 &&
+ if (cp->type != AUDIO_MIXER_VALUE ||
+ (cp->un.value.num_channels != 1 &&
+ cp->un.value.num_channels != 2) ||
+ ((ports[idx].r_port == 0 &&
cp->un.value.num_channels != 1) ||
(ports[idx].r_port != 0 &&
- cp->un.value.num_channels != 2))
- return EINVAL;
-
- reg = sv_read_indirect(sc, ports[idx].l_port);
- reg &= ports[idx].mask;
-
- val = AUDIO_MAX_GAIN - ((reg * AUDIO_MAX_GAIN) / ports[idx].mask);
-
- if (ports[idx].r_port != 0) {
- cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = val;
-
- reg = sv_read_indirect(sc, ports[idx].r_port);
+ cp->un.value.num_channels != 2)))
+ error = EINVAL;
+ else {
+ reg = sv_read_indirect(sc, ports[idx].l_port);
reg &= ports[idx].mask;
- val = AUDIO_MAX_GAIN - ((reg * AUDIO_MAX_GAIN)
- / ports[idx].mask);
- cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = val;
- } else
- cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = val;
+ val = AUDIO_MAX_GAIN -
+ ((reg * AUDIO_MAX_GAIN) / ports[idx].mask);
+
+ if (ports[idx].r_port != 0) {
+ cp->un.value.level
+ [AUDIO_MIXER_LEVEL_LEFT] = val;
+
+ reg = sv_read_indirect(sc,
+ ports[idx].r_port);
+ reg &= ports[idx].mask;
+
+ val = AUDIO_MAX_GAIN -
+ ((reg * AUDIO_MAX_GAIN)
+ / ports[idx].mask);
+ cp->un.value.level
+ [AUDIO_MIXER_LEVEL_RIGHT] = val;
+ } else
+ cp->un.value.level
+ [AUDIO_MIXER_LEVEL_MONO] = val;
+ }
}
- return 0;
+ return error;
}
switch (cp->dev) {
case SV_RECORD_SOURCE:
- if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_ENUM) {
+ error = EINVAL;
+ break;
+ }
reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
cp->un.ord = ((reg & SV_REC_SOURCE_MASK) >> SV_REC_SOURCE_SHIFT);
- return 0;
+ break;
case SV_RECORD_GAIN:
- if (cp->type != AUDIO_MIXER_VALUE)
- return EINVAL;
- if (cp->un.value.num_channels != 1)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_VALUE) {
+ error = EINVAL;
+ break;
+ }
+ if (cp->un.value.num_channels != 1) {
+ error = EINVAL;
+ break;
+ }
reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL) & SV_REC_GAIN_MASK;
cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
(((unsigned int)reg) * AUDIO_MAX_GAIN) / SV_REC_GAIN_MASK;
- return 0;
+ break;
case SV_MIC_BOOST:
- if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_ENUM) {
+ error = EINVAL;
+ break;
+ }
reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
cp->un.ord = ((reg & SV_MIC_BOOST_BIT) ? 1 : 0);
- return 0;
+ break;
case SV_SRS_MODE:
- if (cp->type != AUDIO_MIXER_ENUM)
- return EINVAL;
+ if (cp->type != AUDIO_MIXER_ENUM) {
+ error = EINVAL;
+ break;
+ }
reg = sv_read_indirect(sc, SV_SRS_SPACE_CONTROL);
cp->un.ord = ((reg & SV_SRS_SPACE_ONOFF) ? 0 : 1);
- return 0;
+ break;
+ default:
+ error = EINVAL;
+ break;
}
- return EINVAL;
+ mutex_spin_exit(&sc->sc_intr_lock);
+ return error;
}
static void
@@ -1369,20 +1408,19 @@ sv_init_mixer(struct sv_softc *sc)
}
static void *
-sv_malloc(void *addr, int direction, size_t size,
- struct malloc_type *pool, int flags)
+sv_malloc(void *addr, int direction, size_t size)
{
struct sv_softc *sc;
struct sv_dma *p;
int error;
sc = addr;
- p = malloc(sizeof(*p), pool, flags);
+ p = kmem_alloc(sizeof(*p), KM_SLEEP);
if (p == NULL)
return NULL;
error = sv_allocmem(sc, size, 16, direction, p);
if (error) {
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return 0;
}
p->next = sc->sc_dmas;
@@ -1391,7 +1429,7 @@ sv_malloc(void *addr, int direction, size_t size,
}
static void
-sv_free(void *addr, void *ptr, struct malloc_type *pool)
+sv_free(void *addr, void *ptr, size_t size)
{
struct sv_softc *sc;
struct sv_dma **pp, *p;
@@ -1401,7 +1439,7 @@ sv_free(void *addr, void *ptr, struct malloc_type *pool)
if (KERNADDR(p) == ptr) {
sv_freemem(sc, p);
*pp = p->next;
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return;
}
}
@@ -1436,3 +1474,13 @@ sv_get_props(void *addr)
{
return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
}
+
+static void
+sv_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct sv_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
diff --git a/sys/dev/pci/svvar.h b/sys/dev/pci/svvar.h
index 3176d8d3631..de76a7bfe7f 100644
--- a/sys/dev/pci/svvar.h
+++ b/sys/dev/pci/svvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: svvar.h,v 1.6 2005/12/11 12:22:50 christos Exp $ */
+/* $NetBSD: svvar.h,v 1.7 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (c) 1998 Constantine Paul Sapuntzakis
@@ -33,6 +33,8 @@
struct sv_softc {
struct device sc_dev; /* base device */
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
void *sc_ih; /* interrupt vectoring */
bus_space_tag_t sc_iot;
diff --git a/sys/dev/pci/yds.c b/sys/dev/pci/yds.c
index 7aa32c96bf0..fa6075c3b86 100644
--- a/sys/dev/pci/yds.c
+++ b/sys/dev/pci/yds.c
@@ -1,4 +1,4 @@
-/* $NetBSD: yds.c,v 1.50 2010/07/26 22:33:24 jym Exp $ */
+/* $NetBSD: yds.c,v 1.51 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (c) 2000, 2001 Kazuki Sakamoto and Minoura Makoto.
@@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: yds.c,v 1.50 2010/07/26 22:33:24 jym Exp $");
+__KERNEL_RCSID(0, "$NetBSD: yds.c,v 1.51 2011/11/23 23:07:36 jmcneill Exp $");
#include "mpu.h"
@@ -47,7 +47,7 @@ __KERNEL_RCSID(0, "$NetBSD: yds.c,v 1.50 2010/07/26 22:33:24 jym Exp $");
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/fcntl.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/device.h>
#include <sys/proc.h>
@@ -167,12 +167,13 @@ static int yds_halt_input(void *);
static int yds_getdev(void *, struct audio_device *);
static int yds_mixer_set_port(void *, mixer_ctrl_t *);
static int yds_mixer_get_port(void *, mixer_ctrl_t *);
-static void *yds_malloc(void *, int, size_t, struct malloc_type *, int);
-static void yds_free(void *, void *, struct malloc_type *);
+static void *yds_malloc(void *, int, size_t);
+static void yds_free(void *, void *, size_t);
static size_t yds_round_buffersize(void *, int, size_t);
static paddr_t yds_mappage(void *, void *, off_t, int);
static int yds_get_props(void *);
static int yds_query_devinfo(void *, mixer_devinfo_t *);
+static void yds_get_locks(void *, kmutex_t **, kmutex_t **);
static int yds_attach_codec(void *, struct ac97_codec_if *);
static int yds_read_codec(void *, uint8_t, uint16_t *);
@@ -229,7 +230,7 @@ static const struct audio_hw_if yds_hw_if = {
yds_trigger_output,
yds_trigger_input,
NULL,
- NULL, /* powerstate */
+ yds_get_locks,
};
static const struct audio_device yds_device = {
@@ -442,7 +443,6 @@ yds_allocate_slots(struct yds_softc *sc)
i = yds_allocmem(sc, memsize, 16, p);
if (i) {
aprint_error_dev(sc->sc_dev, "couldn't alloc/map DSP DMA buffer, reason %d\n", i);
- free(p, M_DEVBUF);
return 1;
}
}
@@ -683,10 +683,14 @@ yds_suspend(device_t dv, const pmf_qual_t *qual)
pci_chipset_tag_t pc = sc->sc_pc;
pcitag_t tag = sc->sc_pcitag;
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
sc->sc_dsctrl = pci_conf_read(pc, tag, YDS_PCI_DSCTRL);
sc->sc_legacy = pci_conf_read(pc, tag, YDS_PCI_LEGACY);
sc->sc_ba[0] = pci_conf_read(pc, tag, YDS_PCI_FM_BA);
sc->sc_ba[1] = pci_conf_read(pc, tag, YDS_PCI_MPU_BA);
+ mutex_spin_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
return true;
}
@@ -700,6 +704,8 @@ yds_resume(device_t dv, const pmf_qual_t *qual)
pcireg_t reg;
/* Disable legacy mode */
+ mutex_enter(&sc->sc_lock);
+ mutex_spin_enter(&sc->sc_intr_lock);
reg = pci_conf_read(pc, tag, YDS_PCI_LEGACY);
pci_conf_write(pc, tag, YDS_PCI_LEGACY, reg & YDS_PCI_LEGACY_LAD);
@@ -711,11 +717,15 @@ yds_resume(device_t dv, const pmf_qual_t *qual)
reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
if (yds_init(sc)) {
aprint_error_dev(dv, "reinitialize failed\n");
+ mutex_spin_exit(&sc->sc_intr_lock);
+ mutex_exit(&sc->sc_lock);
return false;
}
pci_conf_write(pc, tag, YDS_PCI_DSCTRL, sc->sc_dsctrl);
+ mutex_spin_exit(&sc->sc_intr_lock);
sc->sc_codec[0].codec_if->vtbl->restore_ports(sc->sc_codec[0].codec_if);
+ mutex_exit(&sc->sc_lock);
return true;
}
@@ -755,13 +765,19 @@ yds_attach(device_t parent, device_t self, void *aux)
aprint_error_dev(self, "couldn't map interrupt\n");
return;
}
+
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SCHED);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
intrstr = pci_intr_string(pc, ih);
- sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, yds_intr, sc);
+ sc->sc_ih = pci_intr_establish(pc, ih, IPL_SCHED, yds_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(self, "couldn't establish interrupt");
if (intrstr != NULL)
aprint_error(" at %s", intrstr);
aprint_error("\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
aprint_normal_dev(self, "interrupting at %s\n", intrstr);
@@ -800,6 +816,8 @@ yds_attach(device_t parent, device_t self, void *aux)
/* Initialize the device */
if (yds_init(sc)) {
aprint_error_dev(self, "initialize failed\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
@@ -819,6 +837,8 @@ yds_attach(device_t parent, device_t self, void *aux)
}
if (to == AC97_TIMEOUT) {
aprint_error_dev(self, "no AC97 available\n");
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
@@ -893,15 +913,21 @@ detected:
codec->host_if.write = yds_write_codec;
codec->host_if.reset = yds_reset_codec;
- if ((r = ac97_attach(&codec->host_if, self)) != 0) {
+ r = ac97_attach(&codec->host_if, self, &sc->sc_lock);
+ if (r != 0) {
aprint_error_dev(self, "can't attach codec (error 0x%X)\n", r);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
}
}
if (0 != auconv_create_encodings(yds_formats, YDS_NFORMATS,
- &sc->sc_encodings))
+ &sc->sc_encodings)) {
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
return;
+ }
audio_attach_mi(&yds_hw_if, sc, self);
@@ -1015,6 +1041,8 @@ yds_intr(void *p)
#endif
u_int status;
+ mutex_spin_enter(&sc->sc_intr_lock);
+
status = YREAD4(sc, YDS_STATUS);
DPRINTFN(1, ("yds_intr: status=%08x\n", status));
if ((status & (YDS_STAT_INT|YDS_STAT_TINT)) == 0) {
@@ -1022,6 +1050,7 @@ yds_intr(void *p)
if (sc_mpu)
return mpu_intr(sc_mpu);
#endif
+ mutex_spin_exit(&sc->sc_intr_lock);
return 0;
}
@@ -1122,6 +1151,7 @@ yds_intr(void *p)
}
}
+ mutex_spin_exit(&sc->sc_intr_lock);
return 1;
}
@@ -1133,22 +1163,22 @@ yds_allocmem(struct yds_softc *sc, size_t size, size_t align, struct yds_dma *p)
p->size = size;
error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
- &p->nsegs, BUS_DMA_NOWAIT);
+ &p->nsegs, BUS_DMA_WAITOK);
if (error)
return error;
error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
- &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
+ &p->addr, BUS_DMA_WAITOK|BUS_DMA_COHERENT);
if (error)
goto free;
error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
- 0, BUS_DMA_NOWAIT, &p->map);
+ 0, BUS_DMA_WAITOK, &p->map);
if (error)
goto unmap;
error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL,
- BUS_DMA_NOWAIT);
+ BUS_DMA_WAITOK);
if (error)
goto destroy;
return 0;
@@ -1192,9 +1222,6 @@ yds_open(void *addr, int flags)
return 0;
}
-/*
- * Close function is called at splaudio().
- */
static void
yds_close(void *addr)
{
@@ -1628,20 +1655,19 @@ yds_query_devinfo(void *addr, mixer_devinfo_t *dip)
}
static void *
-yds_malloc(void *addr, int direction, size_t size,
- struct malloc_type *pool, int flags)
+yds_malloc(void *addr, int direction, size_t size)
{
struct yds_softc *sc;
struct yds_dma *p;
int error;
- p = malloc(sizeof(*p), pool, flags);
+ p = kmem_alloc(sizeof(*p), KM_SLEEP);
if (p == NULL)
return NULL;
sc = addr;
error = yds_allocmem(sc, size, 16, p);
if (error) {
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return NULL;
}
p->next = sc->sc_dmas;
@@ -1650,7 +1676,7 @@ yds_malloc(void *addr, int direction, size_t size,
}
static void
-yds_free(void *addr, void *ptr, struct malloc_type *pool)
+yds_free(void *addr, void *ptr, size_t size)
{
struct yds_softc *sc;
struct yds_dma **pp, *p;
@@ -1660,7 +1686,7 @@ yds_free(void *addr, void *ptr, struct malloc_type *pool)
if (KERNADDR(p) == ptr) {
yds_freemem(sc, p);
*pp = p->next;
- free(p, pool);
+ kmem_free(p, sizeof(*p));
return;
}
}
@@ -1712,3 +1738,13 @@ yds_get_props(void *addr)
return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
AUDIO_PROP_FULLDUPLEX;
}
+
+static void
+yds_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct yds_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
diff --git a/sys/dev/pci/ydsvar.h b/sys/dev/pci/ydsvar.h
index 02cb036776b..d41c4b1c83c 100644
--- a/sys/dev/pci/ydsvar.h
+++ b/sys/dev/pci/ydsvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: ydsvar.h,v 1.10 2008/07/09 15:42:37 joerg Exp $ */
+/* $NetBSD: ydsvar.h,v 1.11 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (c) 2000, 2001 Kazuki Sakamoto and Minoura Makoto.
@@ -55,6 +55,8 @@ struct yds_codec_softc {
struct yds_softc {
device_t sc_dev;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
pci_chipset_tag_t sc_pc;
pcitag_t sc_pcitag;
pcireg_t sc_id;
diff --git a/sys/dev/sbus/cs4231_sbus.c b/sys/dev/sbus/cs4231_sbus.c
index e20f75a42e7..20d0e2abc73 100644
--- a/sys/dev/sbus/cs4231_sbus.c
+++ b/sys/dev/sbus/cs4231_sbus.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cs4231_sbus.c,v 1.48 2011/06/02 00:23:28 christos Exp $ */
+/* $NetBSD: cs4231_sbus.c,v 1.49 2011/11/23 23:07:36 jmcneill Exp $ */
/*-
* Copyright (c) 1998, 1999, 2002, 2007 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cs4231_sbus.c,v 1.48 2011/06/02 00:23:28 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cs4231_sbus.c,v 1.49 2011/11/23 23:07:36 jmcneill Exp $");
#include "audio.h"
#if NAUDIO > 0
@@ -124,7 +124,7 @@ const struct audio_hw_if audiocs_sbus_hw_if = {
cs4231_sbus_trigger_output,
cs4231_sbus_trigger_input,
NULL, /* dev_ioctl */
- NULL, /* powerstate */
+ ad1848_get_locks,
};
@@ -160,9 +160,9 @@ cs4231_sbus_attach(device_t parent, device_t self, void *aux)
sbsc->sc_bt = sc->sc_bustag = sa->sa_bustag;
sc->sc_dmatag = sa->sa_dmatag;
- sbsc->sc_pint = sparc_softintr_establish(IPL_VM,
+ sbsc->sc_pint = sparc_softintr_establish(IPL_SCHED,
(void *)cs4231_sbus_pint, sc);
- sbsc->sc_rint = sparc_softintr_establish(IPL_VM,
+ sbsc->sc_rint = sparc_softintr_establish(IPL_SCHED,
(void *)cs4231_sbus_rint, sc);
/*
@@ -187,6 +187,7 @@ cs4231_sbus_attach(device_t parent, device_t self, void *aux)
cs4231_common_attach(sc, self, bh);
printf("\n");
+ ad1848_init_locks(&sc->sc_ad1848, IPL_SCHED);
/* Establish interrupt channel */
if (sa->sa_nintr)
bus_intr_establish(sa->sa_bustag,
@@ -515,6 +516,8 @@ cs4231_sbus_intr(void *arg)
if ((csr & APC_INTR_MASK) == 0) /* any interrupt pedning? */
return 0;
+ mutex_spin_enter(&sc->sc_ad1848.sc_intr_lock);
+
/* write back DMA status to clear interrupt */
bus_space_write_4(sbsc->sc_bt, sbsc->sc_bh, APC_DMA_CSR, csr);
++sc->sc_intrcnt.ev_count;
@@ -595,6 +598,8 @@ cs4231_sbus_intr(void *arg)
/* evcnt? */
}
+ mutex_spin_exit(&sc->sc_ad1848.sc_intr_lock);
+
return 1;
}
@@ -604,11 +609,11 @@ cs4231_sbus_pint(void *cookie)
struct cs4231_softc *sc = cookie;
struct cs_transfer *t;
- KERNEL_LOCK(1, NULL);
+ mutex_spin_enter(&sc->sc_ad1848.sc_intr_lock);
t = &sc->sc_playback;
if (t->t_intr != NULL)
(*t->t_intr)(t->t_arg);
- KERNEL_UNLOCK_ONE(NULL);
+ mutex_spin_exit(&sc->sc_ad1848.sc_intr_lock);
return 0;
}
@@ -618,11 +623,11 @@ cs4231_sbus_rint(void *cookie)
struct cs4231_softc *sc = cookie;
struct cs_transfer *t;
- KERNEL_LOCK(1, NULL);
+ mutex_spin_enter(&sc->sc_ad1848.sc_intr_lock);
t = &sc->sc_capture;
if (t->t_intr != NULL)
(*t->t_intr)(t->t_arg);
- KERNEL_UNLOCK_ONE(NULL);
+ mutex_spin_exit(&sc->sc_ad1848.sc_intr_lock);
return 0;
}
diff --git a/sys/dev/sbus/dbri.c b/sys/dev/sbus/dbri.c
index 2023c2303b5..8509a22fc27 100644
--- a/sys/dev/sbus/dbri.c
+++ b/sys/dev/sbus/dbri.c
@@ -1,4 +1,4 @@
-/* $NetBSD: dbri.c,v 1.33 2011/03/09 05:40:11 macallan Exp $ */
+/* $NetBSD: dbri.c,v 1.34 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
@@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dbri.c,v 1.33 2011/03/09 05:40:11 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dbri.c,v 1.34 2011/11/23 23:07:36 jmcneill Exp $");
#include "audio.h"
#if NAUDIO > 0
@@ -43,11 +43,11 @@ __KERNEL_RCSID(0, "$NetBSD: dbri.c,v 1.33 2011/03/09 05:40:11 macallan Exp $");
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/device.h>
-#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/intr.h>
+#include <sys/kmem.h>
#include <dev/sbus/sbusvar.h>
#include <sparc/sparc/auxreg.h>
@@ -156,9 +156,10 @@ static int dbri_trigger_output(void *, void *, void *, int,
void (*)(void *), void *, const struct audio_params *);
static int dbri_trigger_input(void *, void *, void *, int,
void (*)(void *), void *, const struct audio_params *);
+static void dbri_get_locks(void *, kmutex_t **, kmutex_t **);
-static void *dbri_malloc(void *, int, size_t, struct malloc_type *, int);
-static void dbri_free(void *, void *, struct malloc_type *);
+static void *dbri_malloc(void *, int, size_t);
+static void dbri_free(void *, void *, size_t);
static paddr_t dbri_mappage(void *, void *, off_t, int);
static void dbri_set_power(struct dbri_softc *, int);
static void dbri_bring_up(struct dbri_softc *);
@@ -175,32 +176,25 @@ struct audio_device dbri_device = {
};
struct audio_hw_if dbri_hw_if = {
- dbri_open,
- dbri_close,
- NULL, /* drain */
- dbri_query_encoding,
- dbri_set_params,
- dbri_round_blocksize,
- NULL, /* commit_settings */
- NULL, /* init_output */
- NULL, /* init_input */
- NULL, /* start_output */
- NULL, /* start_input */
- dbri_halt_output,
- dbri_halt_input,
- NULL, /* speaker_ctl */
- dbri_getdev,
- NULL, /* setfd */
- dbri_set_port,
- dbri_get_port,
- dbri_query_devinfo,
- dbri_malloc,
- dbri_free,
- dbri_round_buffersize,
- dbri_mappage,
- dbri_get_props,
- dbri_trigger_output,
- dbri_trigger_input
+ .open = dbri_open,
+ .close = dbri_close,
+ .query_encoding = dbri_query_encoding,
+ .set_params = dbri_set_params,
+ .round_blocksize = dbri_round_blocksize,
+ .halt_output = dbri_halt_output,
+ .halt_input = dbri_halt_input,
+ .getdev = dbri_getdev,
+ .set_port = dbri_set_port,
+ .get_port = dbri_get_port,
+ .query_devinfo = dbri_query_devinfo,
+ .allocm = dbri_malloc,
+ .freem = dbri_free,
+ .round_buffersize = dbri_round_buffersize,
+ .mappage = dbri_mappage,
+ .get_props = dbri_get_props,
+ .trigger_output = dbri_trigger_output,
+ .trigger_input = dbri_trigger_input,
+ .get_locks = dbri_get_locks,
};
CFATTACH_DECL_NEW(dbri, sizeof(struct dbri_softc),
@@ -370,6 +364,9 @@ dbri_attach_sbus(device_t parent, device_t self, void *aux)
sc->sc_dmabase = sc->sc_dmamap->dm_segs[0].ds_addr;
sc->sc_bufsiz = size;
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+
bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_SCHED, dbri_intr,
sc);
@@ -475,6 +472,8 @@ dbri_intr(void *hdl)
bus_space_handle_t ioh = sc->sc_ioh;
int x;
+ mutex_spin_enter(&sc->sc_intr_lock);
+
/* clear interrupt */
x = bus_space_read_4(iot, ioh, DBRI_REG1);
if (x & (DBRI_MRR | DBRI_MLE | DBRI_LBG | DBRI_MBE)) {
@@ -509,6 +508,8 @@ dbri_intr(void *hdl)
dbri_process_interrupt_buffer(sc);
+ mutex_spin_exit(&sc->sc_intr_lock);
+
return (1);
}
@@ -601,9 +602,8 @@ dbri_command_send(struct dbri_softc *sc, volatile uint32_t *cmd)
bus_space_handle_t ioh = sc->sc_ioh;
bus_space_tag_t iot = sc->sc_iot;
int maxloops = 1000000;
- int x;
- x = splsched();
+ mutex_spin_enter(&sc->sc_intr_lock);
sc->sc_locked--;
@@ -641,7 +641,7 @@ dbri_command_send(struct dbri_softc *sc, volatile uint32_t *cmd)
}
}
- splx(x);
+ mutex_spin_exit(&sc->sc_intr_lock);
return;
}
@@ -1269,7 +1269,7 @@ setup_ring_xmit(struct dbri_softc *sc, int pipe, int which, int num, int blksz,
void (*callback)(void *), void *callback_args)
{
volatile uint32_t *cmd;
- int x, i;
+ int i;
int td;
int td_first, td_last;
bus_addr_t dmabuf, dmabase;
@@ -1319,7 +1319,7 @@ setup_ring_xmit(struct dbri_softc *sc, int pipe, int which, int num, int blksz,
dd->callback = callback;
dd->callback_args = callback_args;
- x = splsched();
+ mutex_spin_enter(&sc->sc_intr_lock);
/* the pipe shouldn't be active */
if (pipe_active(sc, pipe)) {
@@ -1355,7 +1355,7 @@ setup_ring_xmit(struct dbri_softc *sc, int pipe, int which, int num, int blksz,
DPRINTF("%s: starting DMA\n", __func__);
}
- splx(x);
+ mutex_spin_exit(&sc->sc_intr_lock);
return;
}
@@ -1365,7 +1365,7 @@ setup_ring_recv(struct dbri_softc *sc, int pipe, int which, int num, int blksz,
void (*callback)(void *), void *callback_args)
{
volatile uint32_t *cmd;
- int x, i;
+ int i;
int td_first, td_last;
bus_addr_t dmabuf, dmabase;
struct dbri_desc *dd = &sc->sc_desc[which];
@@ -1410,7 +1410,7 @@ setup_ring_recv(struct dbri_softc *sc, int pipe, int which, int num, int blksz,
dd->callback = callback;
dd->callback_args = callback_args;
- x = splsched();
+ mutex_spin_enter(&sc->sc_intr_lock);
/* the pipe shouldn't be active */
if (pipe_active(sc, pipe)) {
@@ -1446,7 +1446,7 @@ setup_ring_recv(struct dbri_softc *sc, int pipe, int which, int num, int blksz,
DPRINTF("%s: starting DMA\n", __func__);
}
- splx(x);
+ mutex_spin_exit(&sc->sc_intr_lock);
return;
}
@@ -2049,6 +2049,14 @@ dbri_trigger_input(void *hdl, void *start, void *end, int blksize,
return 0;
}
+static void
+dbri_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread)
+{
+ struct dbri_softc *sc = opaque;
+
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
static uint32_t
reverse_bytes(uint32_t b, int len)
@@ -2075,7 +2083,7 @@ reverse_bytes(uint32_t b, int len)
}
static void *
-dbri_malloc(void *v, int dir, size_t s, struct malloc_type *mt, int flags)
+dbri_malloc(void *v, int dir, size_t s)
{
struct dbri_softc *sc = v;
struct dbri_desc *dd = &sc->sc_desc[sc->sc_desc_used];
@@ -2116,7 +2124,7 @@ dbri_malloc(void *v, int dir, size_t s, struct malloc_type *mt, int flags)
}
static void
-dbri_free(void *v, void *p, struct malloc_type *mt)
+dbri_free(void *v, void *p, size_t size)
{
struct dbri_softc *sc = v;
struct dbri_desc *dd;
@@ -2206,10 +2214,9 @@ dbri_resume(device_t self, const pmf_qual_t *qual)
aprint_verbose("resume: %d\n", sc->sc_refcount);
if (sc->sc_playing) {
volatile uint32_t *cmd;
- int s;
dbri_bring_up(sc);
- s = splsched();
+ mutex_spin_enter(&sc->sc_intr_lock);
cmd = dbri_command_lock(sc);
*(cmd++) = DBRI_CMD(DBRI_COMMAND_SDP,
0, sc->sc_pipe[4].sdp |
@@ -2218,7 +2225,7 @@ dbri_resume(device_t self, const pmf_qual_t *qual)
*(cmd++) = sc->sc_dmabase +
dbri_dma_off(xmit, 0);
dbri_command_send(sc, cmd);
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
}
return true;
}
diff --git a/sys/dev/sbus/dbrivar.h b/sys/dev/sbus/dbrivar.h
index f8786016873..0e3bf153b0e 100644
--- a/sys/dev/sbus/dbrivar.h
+++ b/sys/dev/sbus/dbrivar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: dbrivar.h,v 1.12 2011/01/11 00:49:50 macallan Exp $ */
+/* $NetBSD: dbrivar.h,v 1.13 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
@@ -166,6 +166,9 @@ struct dbri_softc {
struct audio_params sc_params;
struct dbri_dma *sc_dma;
+
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
};
#define dbri_dma_off(member, elem) \
diff --git a/sys/dev/sequencer.c b/sys/dev/sequencer.c
index 0e55325b2d5..53c72591147 100644
--- a/sys/dev/sequencer.c
+++ b/sys/dev/sequencer.c
@@ -1,11 +1,11 @@
-/* $NetBSD: sequencer.c,v 1.52 2009/03/18 10:22:39 cegger Exp $ */
+/* $NetBSD: sequencer.c,v 1.53 2011/11/23 23:07:31 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson (augustss@NetBSD.org).
+ * by Lennart Augustsson (augustss@NetBSD.org) and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,8 +29,33 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+/*
+ * Locking:
+ *
+ * o sc_lock: provides atomic access to all data structures. Taken from
+ * both process and soft interrupt context.
+ *
+ * o sc_dvlock: serializes operations on /dev/sequencer. Taken from
+ * process context. Dropped while waiting for data in sequencerread()
+ * to allow concurrent reads/writes while no data available.
+ *
+ * o sc_isopen: we allow only one concurrent open, only to prevent user
+ * and/or application error.
+ *
+ * o MIDI softc locks. These can be spinlocks and there can be many of
+ * them, because we can open many MIDI devices. We take these only in two
+ * places: when enabling redirection from the MIDI device and when
+ * disabling it (open/close). midiseq_in() is called by the MIDI driver
+ * with its own lock held when passing data into this module. To avoid
+ * lock order and context problems, we package the received message as a
+ * sequencer_pcqitem_t and put onto a producer-consumer queue. A soft
+ * interrupt is scheduled to dequeue and decode the message later where we
+ * can safely acquire the sequencer device's sc_lock. PCQ is lockless for
+ * multiple producer, single consumer settings like this one.
+ */
+
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sequencer.c,v 1.52 2009/03/18 10:22:39 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sequencer.c,v 1.53 2011/11/23 23:07:31 jmcneill Exp $");
#include "sequencer.h"
@@ -40,7 +65,7 @@ __KERNEL_RCSID(0, "$NetBSD: sequencer.c,v 1.52 2009/03/18 10:22:39 cegger Exp $"
#include <sys/vnode.h>
#include <sys/select.h>
#include <sys/poll.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/syslog.h>
@@ -51,6 +76,10 @@ __KERNEL_RCSID(0, "$NetBSD: sequencer.c,v 1.52 2009/03/18 10:22:39 cegger Exp $"
#include <sys/midiio.h>
#include <sys/device.h>
#include <sys/intr.h>
+#include <sys/atomic.h>
+#include <sys/pcq.h>
+#include <sys/vnode.h>
+#include <sys/kauth.h>
#include <dev/midi_if.h>
#include <dev/midivar.h>
@@ -83,6 +112,11 @@ int sequencerdebug = 0;
#define RECALC_USPERDIV(t) \
((t)->usperdiv = 60*1000000L/((t)->tempo_beatpermin*(t)->timebase_divperbeat))
+typedef union sequencer_pcqitem {
+ void *qi_ptr;
+ char qi_msg[4];
+} sequencer_pcqitem_t;
+
struct sequencer_softc seqdevs[NSEQUENCER];
void sequencerattach(int);
@@ -100,9 +134,6 @@ static int seq_drain(struct sequencer_softc *);
static void seq_startoutput(struct sequencer_softc *);
static void seq_timeout(void *);
static int seq_to_new(seq_event_t *, struct uio *);
-static int seq_sleep_timo(int *, const char *, int);
-static int seq_sleep(int *, const char *);
-static void seq_wakeup(int *);
static void seq_softintr(void *);
struct midi_softc;
@@ -131,7 +162,7 @@ static dev_type_kqfilter(sequencerkqfilter);
const struct cdevsw sequencer_cdevsw = {
sequenceropen, sequencerclose, sequencerread, sequencerwrite,
sequencerioctl, nostop, notty, sequencerpoll, nommap,
- sequencerkqfilter, D_OTHER,
+ sequencerkqfilter, D_OTHER | D_MPSAFE
};
void
@@ -141,9 +172,59 @@ sequencerattach(int n)
for (n = 0; n < NSEQUENCER; n++) {
sc = &seqdevs[n];
- callout_init(&sc->sc_callout, 0);
- sc->sih = softint_establish(SOFTINT_SERIAL, seq_softintr, sc);
+ callout_init(&sc->sc_callout, CALLOUT_MPSAFE);
+ sc->sih = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE,
+ seq_softintr, sc);
+ mutex_init(&sc->lock, MUTEX_DEFAULT, IPL_NONE);
+ cv_init(&sc->rchan, "midiseqr");
+ cv_init(&sc->wchan, "midiseqw");
+ cv_init(&sc->lchan, "midiseql");
+ sc->pcq = pcq_create(SEQ_MAXQ, KM_SLEEP);
+ if (sc->pcq == NULL) {
+ panic("sequencerattach");
+ }
+ }
+}
+
+/*
+ * Release reference to device acquired with sequencer_enter().
+ */
+static void
+sequencer_exit(struct sequencer_softc *sc)
+{
+
+ sc->dvlock--;
+ cv_broadcast(&sc->lchan);
+ mutex_exit(&sc->lock);
+}
+
+/*
+ * Look up sequencer device and acquire locks for device access.
+ */
+static int
+sequencer_enter(dev_t dev, struct sequencer_softc **scp)
+{
+ struct sequencer_softc *sc;
+ int unit;
+
+ /* First, find the device and take sc_lock. */
+ unit = SEQUENCERUNIT(dev);
+ if (unit >= NSEQUENCER)
+ return (ENXIO);
+ sc = &seqdevs[unit];
+ if (sc == NULL)
+ return ENXIO;
+ mutex_enter(&sc->lock);
+ while (sc->dvlock) {
+ cv_wait(&sc->lchan, &sc->lock);
}
+ sc->dvlock++;
+ if (sc->dying) {
+ sequencer_exit(sc);
+ return EIO;
+ }
+ *scp = sc;
+ return 0;
}
static int
@@ -152,41 +233,31 @@ sequenceropen(dev_t dev, int flags, int ifmt, struct lwp *l)
int unit = SEQUENCERUNIT(dev);
struct sequencer_softc *sc;
struct midi_dev *md;
- int nmidi;
+ struct midi_softc *msc;
+ int error;
DPRINTF(("sequenceropen\n"));
- if (unit >= NSEQUENCER)
- return (ENXIO);
- sc = &seqdevs[unit];
- if (sc->isopen)
+ if ((error = sequencer_enter(dev, &sc)) != 0)
+ return error;
+ KASSERT(sc == &seqdevs[unit]);
+ if (sc->isopen != 0) {
+ sequencer_exit(sc);
return EBUSY;
+ }
+
if (SEQ_IS_OLD(unit))
sc->mode = SEQ_OLD;
else
sc->mode = SEQ_NEW;
sc->isopen++;
sc->flags = flags & (FREAD|FWRITE);
- sc->rchan = 0;
- sc->wchan = 0;
sc->pbus = 0;
sc->async = 0;
sc->input_stamp = ~0;
sc->nmidi = 0;
- nmidi = midi_unit_count();
-
- sc->devs = malloc(nmidi * sizeof(struct midi_dev *),
- M_DEVBUF, M_WAITOK);
- for (unit = 0; unit < nmidi; unit++) {
- md = midiseq_open(unit, flags);
- if (md) {
- sc->devs[sc->nmidi++] = md;
- md->seq = sc;
- md->doingsysex = 0;
- }
- }
-
+ sc->ndevs = midi_unit_count();
sc->timer.timebase_divperbeat = 100;
sc->timer.tempo_beatpermin = 60;
RECALC_USPERDIV(&sc->timer);
@@ -197,45 +268,36 @@ sequenceropen(dev_t dev, int flags, int ifmt, struct lwp *l)
SEQ_QINIT(&sc->outq);
sc->lowat = SEQ_MAXQ / 2;
- seq_reset(sc);
-
- DPRINTF(("sequenceropen: mode=%d, nmidi=%d\n", sc->mode, sc->nmidi));
- return 0;
-}
+ if (sc->ndevs > 0) {
+ mutex_exit(&sc->lock);
+ sc->devs = kmem_alloc(sc->ndevs * sizeof(struct midi_dev *),
+ KM_SLEEP);
+ for (unit = 0; unit < sc->ndevs; unit++) {
+ md = midiseq_open(unit, flags);
+ if (md) {
+ sc->devs[sc->nmidi++] = md;
+ md->seq = sc;
+ md->doingsysex = 0;
+ }
+ }
+ mutex_enter(&sc->lock);
+ } else {
+ sc->devs = NULL;
+ }
-static int
-seq_sleep_timo(int *chan, const char *label, int timo)
-{
- int st;
-
- if (!label)
- label = "seq";
-
- DPRINTFN(5, ("seq_sleep_timo: %p %s %d\n", chan, label, timo));
- *chan = 1;
- st = tsleep(chan, PWAIT | PCATCH, label, timo);
- *chan = 0;
-#ifdef MIDI_DEBUG
- if (st != 0)
- printf("seq_sleep: %d\n", st);
-#endif
- return st;
-}
+ /* Only now redirect input from MIDI devices. */
+ for (unit = 0; unit < sc->nmidi; unit++) {
+ msc = sc->devs[unit]->msc;
+ mutex_enter(msc->lock);
+ msc->seqopen = 1;
+ mutex_exit(msc->lock);
+ }
-static int
-seq_sleep(int *chan, const char *label)
-{
- return seq_sleep_timo(chan, label, 0);
-}
+ seq_reset(sc);
+ sequencer_exit(sc);
-static void
-seq_wakeup(int *chan)
-{
- if (*chan) {
- DPRINTFN(5, ("seq_wakeup: %p\n", chan));
- wakeup(chan);
- *chan = 0;
- }
+ DPRINTF(("%s: mode=%d, nmidi=%d\n", __func__, sc->mode, sc->nmidi));
+ return 0;
}
static int
@@ -243,11 +305,13 @@ seq_drain(struct sequencer_softc *sc)
{
int error;
+ KASSERT(mutex_owned(&sc->lock));
+
DPRINTFN(3, ("seq_drain: %p, len=%d\n", sc, SEQ_QLEN(&sc->outq)));
seq_startoutput(sc);
error = 0;
- while(!SEQ_QEMPTY(&sc->outq) && !error)
- error = seq_sleep_timo(&sc->wchan, "seq_dr", 60*hz);
+ while (!SEQ_QEMPTY(&sc->outq) && !error)
+ error = cv_timedwait_sig(&sc->wchan, &sc->lock, 60*hz);
return (error);
}
@@ -255,22 +319,31 @@ static void
seq_timeout(void *addr)
{
struct sequencer_softc *sc = addr;
- struct proc *p;
+ proc_t *p;
+ pid_t pid;
DPRINTFN(4, ("seq_timeout: %p\n", sc));
+
+ mutex_enter(&sc->lock);
+ if (sc->timeout == 0) {
+ mutex_spin_exit(&sc->lock);
+ return;
+ }
sc->timeout = 0;
seq_startoutput(sc);
- if (SEQ_QLEN(&sc->outq) < sc->lowat) {
- seq_wakeup(&sc->wchan);
- selnotify(&sc->wsel, 0, 0);
- if (sc->async != NULL) {
- mutex_enter(proc_lock);
- if ((p = sc->async) != NULL)
- psignal(p, SIGIO);
- mutex_exit(proc_lock);
- }
+ if (SEQ_QLEN(&sc->outq) >= sc->lowat) {
+ mutex_exit(&sc->lock);
+ return;
}
-
+ cv_broadcast(&sc->wchan);
+ selnotify(&sc->wsel, 0, NOTE_SUBMIT);
+ if ((pid = sc->async) != 0) {
+ mutex_enter(proc_lock);
+ if ((p = proc_find(pid)) != NULL)
+ psignal(p, SIGIO);
+ mutex_exit(proc_lock);
+ }
+ mutex_exit(&sc->lock);
}
static void
@@ -279,195 +352,286 @@ seq_startoutput(struct sequencer_softc *sc)
struct sequencer_queue *q = &sc->outq;
seq_event_t cmd;
+ KASSERT(mutex_owned(&sc->lock));
+
if (sc->timeout)
return;
DPRINTFN(4, ("seq_startoutput: %p, len=%d\n", sc, SEQ_QLEN(q)));
- while(!SEQ_QEMPTY(q) && !sc->timeout) {
+ while (!SEQ_QEMPTY(q) && !sc->timeout) {
SEQ_QGET(q, cmd);
seq_do_command(sc, &cmd);
}
}
static int
-sequencerclose(dev_t dev, int flags, int ifmt,
- struct lwp *l)
+sequencerclose(dev_t dev, int flags, int ifmt, struct lwp *l)
{
- struct sequencer_softc *sc = &seqdevs[SEQUENCERUNIT(dev)];
- int n, s;
+ struct sequencer_softc *sc;
+ struct midi_softc *msc;
+ int unit, error;
- DPRINTF(("sequencerclose: %p\n", sc));
+ DPRINTF(("sequencerclose: %"PRIx64"\n", dev));
+ if ((error = sequencer_enter(dev, &sc)) != 0)
+ return error;
seq_drain(sc);
- s = splaudio();
if (sc->timeout) {
- callout_stop(&sc->sc_callout);
+ callout_halt(&sc->sc_callout, &sc->lock);
sc->timeout = 0;
}
- splx(s);
+ /* Bin input from MIDI devices. */
+ for (unit = 0; unit < sc->nmidi; unit++) {
+ msc = sc->devs[unit]->msc;
+ mutex_enter(msc->lock);
+ msc->seqopen = 0;
+ mutex_exit(msc->lock);
+ }
+ mutex_exit(&sc->lock);
+
+ for (unit = 0; unit < sc->nmidi; unit++)
+ if (sc->devs[unit] != NULL)
+ midiseq_close(sc->devs[unit]);
+ if (sc->devs != NULL) {
+ KASSERT(sc->ndevs > 0);
+ kmem_free(sc->devs, sc->ndevs * sizeof(struct midi_dev *));
+ sc->devs = NULL;
+ }
- for (n = 0; n < sc->nmidi; n++)
- midiseq_close(sc->devs[n]);
- free(sc->devs, M_DEVBUF);
+ mutex_enter(&sc->lock);
sc->isopen = 0;
- return (0);
-}
+ sequencer_exit(sc);
-static void
-seq_softintr(void *cookie)
-{
- struct sequencer_softc *sc = cookie;
- struct proc *p;
+ DPRINTF(("sequencerclose: %"PRIx64" done\n", dev));
- seq_wakeup(&sc->rchan);
- selnotify(&sc->rsel, 0, 0);
- if (sc->async != NULL) {
- mutex_enter(proc_lock);
- if ((p = sc->async) != NULL)
- psignal(p, SIGIO);
- mutex_exit(proc_lock);
- }
+ return (0);
}
static int
seq_input_event(struct sequencer_softc *sc, seq_event_t *cmd)
{
- struct sequencer_queue *q = &sc->inq;
-
- DPRINTFN(2, ("seq_input_event: %02x %02x %02x %02x %02x %02x %02x %02x\n",
- cmd->tag,
- cmd->unknown.byte[0], cmd->unknown.byte[1],
- cmd->unknown.byte[2], cmd->unknown.byte[3],
- cmd->unknown.byte[4], cmd->unknown.byte[5],
- cmd->unknown.byte[6]));
+ struct sequencer_queue *q;
+
+ KASSERT(mutex_owned(&sc->lock));
+
+ DPRINTFN(2, ("seq_input_event: %02x %02x %02x %02x %02x "
+ "%02x %02x %02x\n", cmd->tag,
+ cmd->unknown.byte[0], cmd->unknown.byte[1],
+ cmd->unknown.byte[2], cmd->unknown.byte[3],
+ cmd->unknown.byte[4], cmd->unknown.byte[5],
+ cmd->unknown.byte[6]));
+ q = &sc->inq;
if (SEQ_QFULL(q))
return (ENOMEM);
SEQ_QPUT(q, *cmd);
- softint_schedule(sc->sih);
+ cv_broadcast(&sc->rchan);
+ selnotify(&sc->rsel, 0, NOTE_SUBMIT);
+ if (sc->async != 0) {
+ proc_t *p;
+
+ mutex_enter(proc_lock);
+ if ((p = proc_find(sc->async)) != NULL)
+ psignal(p, SIGIO);
+ mutex_exit(proc_lock);
+ }
return 0;
}
-void
-seq_event_intr(void *addr, seq_event_t *iev)
+static void
+seq_softintr(void *addr)
{
- struct sequencer_softc *sc = addr;
- u_long t;
+ struct sequencer_softc *sc;
struct timeval now;
- int s;
+ seq_event_t ev;
+ int status, chan, unit;
+ sequencer_pcqitem_t qi;
+ u_long t;
+
+ sc = addr;
+
+ mutex_enter(&sc->lock);
+ qi.qi_ptr = pcq_get(sc->pcq);
+ if (qi.qi_ptr == NULL) {
+ mutex_exit(&sc->lock);
+ return;
+ }
+ KASSERT((qi.qi_msg[3] & 0x80) != 0);
+ unit = qi.qi_msg[3] & ~0x80;
+ status = MIDI_GET_STATUS(qi.qi_msg[0]);
+ chan = MIDI_GET_CHAN(qi.qi_msg[0]);
+ switch (status) {
+ case MIDI_NOTEON: /* midi(4) always canonicalizes hidden note-off */
+ ev = SEQ_MK_CHN(NOTEON, .device=unit, .channel=chan,
+ .key=qi.qi_msg[1], .velocity=qi.qi_msg[2]);
+ break;
+ case MIDI_NOTEOFF:
+ ev = SEQ_MK_CHN(NOTEOFF, .device=unit, .channel=chan,
+ .key=qi.qi_msg[1], .velocity=qi.qi_msg[2]);
+ break;
+ case MIDI_KEY_PRESSURE:
+ ev = SEQ_MK_CHN(KEY_PRESSURE, .device=unit, .channel=chan,
+ .key=qi.qi_msg[1], .pressure=qi.qi_msg[2]);
+ break;
+ case MIDI_CTL_CHANGE: /* XXX not correct for MSB */
+ ev = SEQ_MK_CHN(CTL_CHANGE, .device=unit, .channel=chan,
+ .controller=qi.qi_msg[1], .value=qi.qi_msg[2]);
+ break;
+ case MIDI_PGM_CHANGE:
+ ev = SEQ_MK_CHN(PGM_CHANGE, .device=unit, .channel=chan,
+ .program=qi.qi_msg[1]);
+ break;
+ case MIDI_CHN_PRESSURE:
+ ev = SEQ_MK_CHN(CHN_PRESSURE, .device=unit, .channel=chan,
+ .pressure=qi.qi_msg[1]);
+ break;
+ case MIDI_PITCH_BEND:
+ ev = SEQ_MK_CHN(PITCH_BEND, .device=unit, .channel=chan,
+ .value=(qi.qi_msg[1] & 0x7f) | ((qi.qi_msg[2] & 0x7f) << 7));
+ break;
+ default: /* this is now the point where MIDI_ACKs disappear */
+ mutex_exit(&sc->lock);
+ return;
+ }
microtime(&now);
- s = splsoftclock();
if (!sc->timer.running)
now = sc->timer.stoptime;
SUBTIMEVAL(&now, &sc->timer.reftime);
t = now.tv_sec * 1000000 + now.tv_usec;
t /= sc->timer.usperdiv;
t += sc->timer.divs_lastchange;
- splx(s);
if (t != sc->input_stamp) {
seq_input_event(sc, &SEQ_MK_TIMING(WAIT_ABS, .divisions=t));
sc->input_stamp = t; /* XXX wha hoppen if timer is reset? */
}
- seq_input_event(sc, iev);
+ seq_input_event(sc, &ev);
+ mutex_exit(&sc->lock);
}
static int
sequencerread(dev_t dev, struct uio *uio, int ioflag)
{
- struct sequencer_softc *sc = &seqdevs[SEQUENCERUNIT(dev)];
- struct sequencer_queue *q = &sc->inq;
+ struct sequencer_softc *sc;
+ struct sequencer_queue *q;
seq_event_t ev;
- int error, s;
+ int error;
- DPRINTFN(20, ("sequencerread: %p, count=%d, ioflag=%x\n",
- sc, (int) uio->uio_resid, ioflag));
+ DPRINTFN(20, ("sequencerread: %"PRIx64", count=%d, ioflag=%x\n",
+ dev, (int)uio->uio_resid, ioflag));
+
+ if ((error = sequencer_enter(dev, &sc)) != 0)
+ return error;
+ q = &sc->inq;
if (sc->mode == SEQ_OLD) {
+ sequencer_exit(sc);
DPRINTFN(-1,("sequencerread: old read\n"));
- return (EINVAL); /* XXX unimplemented */
+ return EINVAL; /* XXX unimplemented */
}
-
- error = 0;
while (SEQ_QEMPTY(q)) {
- if (ioflag & IO_NDELAY)
- return EWOULDBLOCK;
- else {
- error = seq_sleep(&sc->rchan, "seq rd");
- if (error)
- return error;
+ if (ioflag & IO_NDELAY) {
+ error = EWOULDBLOCK;
+ break;
+ }
+ /* Drop lock to allow concurrent read/write. */
+ KASSERT(sc->dvlock != 0);
+ sc->dvlock--;
+ error = cv_wait_sig(&sc->rchan, &sc->lock);
+ while (sc->dvlock != 0) {
+ cv_wait(&sc->lchan, &sc->lock);
+ }
+ sc->dvlock++;
+ if (error) {
+ break;
}
}
- s = splaudio();
- while (uio->uio_resid >= sizeof ev && !error && !SEQ_QEMPTY(q)) {
+ while (uio->uio_resid >= sizeof(ev) && !error && !SEQ_QEMPTY(q)) {
SEQ_QGET(q, ev);
- error = uiomove(&ev, sizeof ev, uio);
+ mutex_exit(&sc->lock);
+ error = uiomove(&ev, sizeof(ev), uio);
+ mutex_enter(&sc->lock);
}
- splx(s);
+ sequencer_exit(sc);
return error;
}
static int
sequencerwrite(dev_t dev, struct uio *uio, int ioflag)
{
- struct sequencer_softc *sc = &seqdevs[SEQUENCERUNIT(dev)];
- struct sequencer_queue *q = &sc->outq;
+ struct sequencer_softc *sc;
+ struct sequencer_queue *q;
int error;
seq_event_t cmdbuf;
int size;
- DPRINTFN(2, ("sequencerwrite: %p, count=%d\n", sc, (int) uio->uio_resid));
+ DPRINTFN(2, ("sequencerwrite: %"PRIx64", count=%d\n", dev,
+ (int)uio->uio_resid));
+
+ if ((error = sequencer_enter(dev, &sc)) != 0)
+ return error;
+ q = &sc->outq;
- error = 0;
size = sc->mode == SEQ_NEW ? sizeof cmdbuf : SEQOLD_CMDSIZE;
- while (uio->uio_resid >= size) {
+ while (uio->uio_resid >= size && error == 0) {
+ mutex_exit(&sc->lock);
error = uiomove(&cmdbuf, size, uio);
- if (error)
- break;
- if (sc->mode == SEQ_OLD)
- if (seq_to_new(&cmdbuf, uio))
+ if (error == 0) {
+ if (sc->mode == SEQ_OLD && seq_to_new(&cmdbuf, uio)) {
+ mutex_enter(&sc->lock);
continue;
- if (cmdbuf.tag == SEQ_FULLSIZE) {
- /* We do it like OSS does, asynchronously */
- error = seq_do_fullsize(sc, &cmdbuf, uio);
- if (error)
- break;
- continue;
+ }
+ if (cmdbuf.tag == SEQ_FULLSIZE) {
+ /* We do it like OSS does, asynchronously */
+ error = seq_do_fullsize(sc, &cmdbuf, uio);
+ if (error == 0) {
+ mutex_enter(&sc->lock);
+ continue;
+ }
+ }
+ }
+ mutex_enter(&sc->lock);
+ if (error != 0) {
+ break;
}
while (SEQ_QFULL(q)) {
seq_startoutput(sc);
if (SEQ_QFULL(q)) {
- if (ioflag & IO_NDELAY)
- return EWOULDBLOCK;
- error = seq_sleep(&sc->wchan, "seq_wr");
- if (error)
- return error;
+ if (ioflag & IO_NDELAY) {
+ error = EWOULDBLOCK;
+ break;
+ }
+ error = cv_wait_sig(&sc->wchan, &sc->lock);
+ if (error) {
+ break;
+ }
}
}
- SEQ_QPUT(q, cmdbuf);
+ if (error == 0) {
+ SEQ_QPUT(q, cmdbuf);
+ }
}
- seq_startoutput(sc);
-
-#ifdef SEQUENCER_DEBUG
- if (error)
+ if (error == 0) {
+ seq_startoutput(sc);
+ } else {
DPRINTFN(2, ("sequencerwrite: error=%d\n", error));
-#endif
+ }
+ sequencer_exit(sc);
return error;
}
static int
-sequencerioctl(dev_t dev, u_long cmd, void *addr, int flag,
- struct lwp *l)
+sequencerioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
{
- struct sequencer_softc *sc = &seqdevs[SEQUENCERUNIT(dev)];
+ struct sequencer_softc *sc;
struct synth_info *si;
struct midi_dev *md;
- int devno;
- int error;
- int s;
- int t;
+ int devno, error, t;
+ struct timeval now;
+ u_long tx;
- DPRINTFN(2, ("sequencerioctl: %p cmd=0x%08lx\n", sc, cmd));
+ DPRINTFN(2, ("sequencerioctl: %"PRIx64" cmd=0x%08lx\n", dev, cmd));
- error = 0;
+ if ((error = sequencer_enter(dev, &sc)) != 0)
+ return error;
switch (cmd) {
case FIONBIO:
/* All handled in the upper FS layer. */
@@ -475,12 +639,14 @@ sequencerioctl(dev_t dev, u_long cmd, void *addr, int flag,
case FIOASYNC:
if (*(int *)addr) {
- if (sc->async)
+ if (sc->async != 0)
return EBUSY;
- sc->async = l->l_proc;
- DPRINTF(("sequencer_ioctl: FIOASYNC %p\n", l));
- } else
+ sc->async = curproc->p_pid;
+ DPRINTF(("sequencer_ioctl: FIOASYNC %d\n",
+ sc->async));
+ } else {
sc->async = 0;
+ }
break;
case SEQUENCER_RESET:
@@ -493,17 +659,17 @@ sequencerioctl(dev_t dev, u_long cmd, void *addr, int flag,
break;
case SEQUENCER_SYNC:
- if (sc->flags == FREAD)
- return 0;
- seq_drain(sc);
- error = 0;
+ if (sc->flags != FREAD)
+ seq_drain(sc);
break;
case SEQUENCER_INFO:
si = (struct synth_info*)addr;
devno = si->device;
- if (devno < 0 || devno >= sc->nmidi)
- return EINVAL;
+ if (devno < 0 || devno >= sc->nmidi) {
+ error = EINVAL;
+ break;
+ }
md = sc->devs[devno];
strncpy(si->name, md->name, sizeof si->name);
si->synth_type = SYNTH_TYPE_MIDI;
@@ -523,13 +689,15 @@ sequencerioctl(dev_t dev, u_long cmd, void *addr, int flag,
case SEQUENCER_OUTOFBAND:
DPRINTFN(3, ("sequencer_ioctl: OOB=%02x %02x %02x %02x %02x %02x %02x %02x\n",
- *(u_char *)addr, *((u_char *)addr+1),
- *((u_char *)addr+2), *((u_char *)addr+3),
- *((u_char *)addr+4), *((u_char *)addr+5),
- *((u_char *)addr+6), *((u_char *)addr+7)));
- if ( !(sc->flags & FWRITE ) )
- return EBADF;
- error = seq_do_command(sc, (seq_event_t *)addr);
+ *(u_char *)addr, *((u_char *)addr+1),
+ *((u_char *)addr+2), *((u_char *)addr+3),
+ *((u_char *)addr+4), *((u_char *)addr+5),
+ *((u_char *)addr+6), *((u_char *)addr+7)));
+ if ((sc->flags & FWRITE) == 0) {
+ error = EBADF;
+ } else {
+ error = seq_do_command(sc, (seq_event_t *)addr);
+ }
break;
case SEQUENCER_TMR_TIMEBASE:
@@ -539,39 +707,29 @@ sequencerioctl(dev_t dev, u_long cmd, void *addr, int flag,
if (t > 10000)
t = 10000;
*(int *)addr = t;
- s = splsoftclock();
sc->timer.timebase_divperbeat = t;
sc->timer.divs_lastchange = sc->timer.divs_lastevent;
microtime(&sc->timer.reftime);
RECALC_USPERDIV(&sc->timer);
- splx(s);
break;
case SEQUENCER_TMR_START:
- s = splsoftclock();
error = seq_do_timing(sc, &SEQ_MK_TIMING(START));
- splx(s);
break;
case SEQUENCER_TMR_STOP:
- s = splsoftclock();
error = seq_do_timing(sc, &SEQ_MK_TIMING(STOP));
- splx(s);
break;
case SEQUENCER_TMR_CONTINUE:
- s = splsoftclock();
error = seq_do_timing(sc, &SEQ_MK_TIMING(CONTINUE));
- splx(s);
break;
case SEQUENCER_TMR_TEMPO:
- s = splsoftclock();
error = seq_do_timing(sc,
&SEQ_MK_TIMING(TEMPO, .bpm=*(int *)addr));
- splx(s);
- if (!error)
- *(int *)addr = sc->timer.tempo_beatpermin;
+ if (error == 0)
+ *(int *)addr = sc->timer.tempo_beatpermin;
break;
case SEQUENCER_TMR_SOURCE:
@@ -592,32 +750,26 @@ sequencerioctl(dev_t dev, u_long cmd, void *addr, int flag,
break;
case SEQUENCER_CTRLRATE:
- s = splsoftclock();
*(int *)addr = (sc->timer.tempo_beatpermin
- *sc->timer.timebase_divperbeat + 30) / 60;
- splx(s);
+ *sc->timer.timebase_divperbeat + 30) / 60;
break;
case SEQUENCER_GETTIME:
- {
- struct timeval now;
- u_long tx;
microtime(&now);
- s = splsoftclock();
SUBTIMEVAL(&now, &sc->timer.reftime);
tx = now.tv_sec * 1000000 + now.tv_usec;
tx /= sc->timer.usperdiv;
tx += sc->timer.divs_lastchange;
- splx(s);
*(int *)addr = tx;
break;
- }
default:
DPRINTFN(-1,("sequencer_ioctl: unimpl %08lx\n", cmd));
error = EINVAL;
break;
}
+ sequencer_exit(sc);
+
return error;
}
@@ -629,6 +781,7 @@ sequencerpoll(dev_t dev, int events, struct lwp *l)
DPRINTF(("sequencerpoll: %p events=0x%x\n", sc, events));
+ mutex_enter(&sc->lock);
if (events & (POLLIN | POLLRDNORM))
if ((sc->flags&FREAD) && !SEQ_QEMPTY(&sc->inq))
revents |= events & (POLLIN | POLLRDNORM);
@@ -644,6 +797,7 @@ sequencerpoll(dev_t dev, int events, struct lwp *l)
if ((sc->flags&FWRITE) && (events & (POLLOUT | POLLWRNORM)))
selrecord(l, &sc->wsel);
}
+ mutex_exit(&sc->lock);
return revents;
}
@@ -652,24 +806,31 @@ static void
filt_sequencerrdetach(struct knote *kn)
{
struct sequencer_softc *sc = kn->kn_hook;
- int s;
- s = splaudio();
+ mutex_enter(&sc->lock);
SLIST_REMOVE(&sc->rsel.sel_klist, kn, knote, kn_selnext);
- splx(s);
+ mutex_exit(&sc->lock);
}
static int
filt_sequencerread(struct knote *kn, long hint)
{
struct sequencer_softc *sc = kn->kn_hook;
+ int rv;
- /* XXXLUKEM (thorpej): make sure this is correct */
-
- if (SEQ_QEMPTY(&sc->inq))
- return (0);
- kn->kn_data = sizeof(seq_event_rec);
- return (1);
+ if (hint != NOTE_SUBMIT) {
+ mutex_enter(&sc->lock);
+ }
+ if (SEQ_QEMPTY(&sc->inq)) {
+ rv = 0;
+ } else {
+ kn->kn_data = sizeof(seq_event_rec);
+ rv = 1;
+ }
+ if (hint != NOTE_SUBMIT) {
+ mutex_exit(&sc->lock);
+ }
+ return rv;
}
static const struct filterops sequencerread_filtops =
@@ -679,24 +840,31 @@ static void
filt_sequencerwdetach(struct knote *kn)
{
struct sequencer_softc *sc = kn->kn_hook;
- int s;
- s = splaudio();
+ mutex_enter(&sc->lock);
SLIST_REMOVE(&sc->wsel.sel_klist, kn, knote, kn_selnext);
- splx(s);
+ mutex_exit(&sc->lock);
}
static int
filt_sequencerwrite(struct knote *kn, long hint)
{
struct sequencer_softc *sc = kn->kn_hook;
+ int rv;
- /* XXXLUKEM (thorpej): make sure this is correct */
-
- if (SEQ_QLEN(&sc->outq) >= sc->lowat)
- return (0);
- kn->kn_data = sizeof(seq_event_rec);
- return (1);
+ if (hint != NOTE_SUBMIT) {
+ mutex_enter(&sc->lock);
+ }
+ if (SEQ_QLEN(&sc->outq) >= sc->lowat) {
+ rv = 0;
+ } else {
+ kn->kn_data = sizeof(seq_event_rec);
+ rv = 1;
+ }
+ if (hint != NOTE_SUBMIT) {
+ mutex_exit(&sc->lock);
+ }
+ return rv;
}
static const struct filterops sequencerwrite_filtops =
@@ -707,7 +875,6 @@ sequencerkqfilter(dev_t dev, struct knote *kn)
{
struct sequencer_softc *sc = &seqdevs[SEQUENCERUNIT(dev)];
struct klist *klist;
- int s;
switch (kn->kn_filter) {
case EVFILT_READ:
@@ -726,9 +893,9 @@ sequencerkqfilter(dev_t dev, struct knote *kn)
kn->kn_hook = sc;
- s = splaudio();
+ mutex_enter(&sc->lock);
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
- splx(s);
+ mutex_exit(&sc->lock);
return (0);
}
@@ -739,6 +906,8 @@ seq_reset(struct sequencer_softc *sc)
int i, chn;
struct midi_dev *md;
+ KASSERT(mutex_owned(&sc->lock));
+
if ( !(sc->flags & FWRITE) )
return;
for (i = 0; i < sc->nmidi; i++) {
@@ -760,6 +929,8 @@ seq_do_command(struct sequencer_softc *sc, seq_event_t *b)
{
int dev;
+ KASSERT(mutex_owned(&sc->lock));
+
DPRINTFN(4, ("seq_do_command: %p cmd=0x%02x\n", sc, b->timing.op));
switch(b->tag) {
@@ -792,6 +963,8 @@ seq_do_chnvoice(struct sequencer_softc *sc, seq_event_t *b)
int error;
struct midi_dev *md;
+ KASSERT(mutex_owned(&sc->lock));
+
dev = b->voice.device;
if (dev < 0 || dev >= sc->nmidi ||
b->voice.channel > 15 ||
@@ -825,6 +998,8 @@ seq_do_chncommon(struct sequencer_softc *sc, seq_event_t *b)
int error;
struct midi_dev *md;
+ KASSERT(mutex_owned(&sc->lock));
+
dev = b->common.device;
if (dev < 0 || dev >= sc->nmidi ||
b->common.channel > 15)
@@ -858,6 +1033,9 @@ seq_do_chncommon(struct sequencer_softc *sc, seq_event_t *b)
static int
seq_do_local(struct sequencer_softc *sc, seq_event_t *b)
{
+
+ KASSERT(mutex_owned(&sc->lock));
+
return (EINVAL);
}
@@ -868,6 +1046,8 @@ seq_do_sysex(struct sequencer_softc *sc, seq_event_t *b)
struct midi_dev *md;
uint8_t *bf = b->sysex.buffer;
+ KASSERT(mutex_owned(&sc->lock));
+
dev = b->sysex.device;
if (dev < 0 || dev >= sc->nmidi)
return (ENXIO);
@@ -895,6 +1075,8 @@ seq_timer_waitabs(struct sequencer_softc *sc, uint32_t divs)
struct syn_timer *t;
int ticks;
+ KASSERT(mutex_owned(&sc->lock));
+
t = &sc->timer;
t->divs_lastevent = divs;
divs -= t->divs_lastchange;
@@ -932,11 +1114,13 @@ seq_do_timing(struct sequencer_softc *sc, seq_event_t *b)
struct timeval when;
int error;
+ KASSERT(mutex_owned(&sc->lock));
+
error = 0;
switch(b->timing.op) {
case TMR_WAIT_REL:
seq_timer_waitabs(sc,
- b->t_WAIT_REL.divisions + t->divs_lastevent);
+ b->t_WAIT_REL.divisions + t->divs_lastevent);
break;
case TMR_WAIT_ABS:
seq_timer_waitabs(sc, b->t_WAIT_ABS.divisions);
@@ -1115,48 +1299,20 @@ seq_to_new(seq_event_t *ev, struct uio *uio)
void
midiseq_in(struct midi_dev *md, u_char *msg, int len)
{
- int unit = md->unit;
- seq_event_t ev;
- int status, chan;
+ struct sequencer_softc *sc;
+ sequencer_pcqitem_t qi;
DPRINTFN(2, ("midiseq_in: %p %02x %02x %02x\n",
md, msg[0], msg[1], msg[2]));
- status = MIDI_GET_STATUS(msg[0]);
- chan = MIDI_GET_CHAN(msg[0]);
- switch (status) {
- case MIDI_NOTEON: /* midi(4) always canonicalizes hidden note-off */
- ev = SEQ_MK_CHN(NOTEON, .device=unit, .channel=chan,
- .key=msg[1], .velocity=msg[2]);
- break;
- case MIDI_NOTEOFF:
- ev = SEQ_MK_CHN(NOTEOFF, .device=unit, .channel=chan,
- .key=msg[1], .velocity=msg[2]);
- break;
- case MIDI_KEY_PRESSURE:
- ev = SEQ_MK_CHN(KEY_PRESSURE, .device=unit, .channel=chan,
- .key=msg[1], .pressure=msg[2]);
- break;
- case MIDI_CTL_CHANGE: /* XXX not correct for MSB */
- ev = SEQ_MK_CHN(CTL_CHANGE, .device=unit, .channel=chan,
- .controller=msg[1], .value=msg[2]);
- break;
- case MIDI_PGM_CHANGE:
- ev = SEQ_MK_CHN(PGM_CHANGE, .device=unit, .channel=chan,
- .program=msg[1]);
- break;
- case MIDI_CHN_PRESSURE:
- ev = SEQ_MK_CHN(CHN_PRESSURE, .device=unit, .channel=chan,
- .pressure=msg[1]);
- break;
- case MIDI_PITCH_BEND:
- ev = SEQ_MK_CHN(PITCH_BEND, .device=unit, .channel=chan,
- .value=(msg[1] & 0x7f) | ((msg[2] & 0x7f) << 7));
- break;
- default: /* this is now the point where MIDI_ACKs disappear */
- return;
- }
- seq_event_intr(md->seq, &ev);
+ sc = md->seq;
+
+ qi.qi_msg[0] = msg[0];
+ qi.qi_msg[1] = msg[1];
+ qi.qi_msg[2] = msg[2];
+ qi.qi_msg[3] = md->unit | 0x80; /* ensure non-zero value of qi_ptr */
+ pcq_put(sc->pcq, qi.qi_ptr);
+ softint_schedule(sc->sih);
}
static struct midi_dev *
@@ -1169,31 +1325,45 @@ midiseq_open(int unit, int flags)
struct midi_info mi;
int major;
dev_t dev;
+ vnode_t *vp;
major = devsw_name2chr("midi", NULL, 0);
dev = makedev(major, unit);
- midi_getinfo(dev, &mi);
- if ( !(mi.props & MIDI_PROP_CAN_INPUT) )
- flags &= ~FREAD;
- if ( 0 == ( flags & ( FREAD | FWRITE ) ) )
- return 0;
DPRINTFN(2, ("midiseq_open: %d %d\n", unit, flags));
- error = cdev_open(dev, flags, 0, 0);
+
+ error = cdevvp(dev, &vp);
if (error)
- return (0);
+ return NULL;
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ error = VOP_OPEN(vp, flags, kauth_cred_get());
+ VOP_UNLOCK(vp);
+ if (error) {
+ vrele(vp);
+ return NULL;
+ }
+
+ /* Only after we have acquired reference via VOP_OPEN(). */
+ midi_getinfo(dev, &mi);
+ if ((mi.props & MIDI_PROP_CAN_INPUT) == 0)
+ flags &= ~FREAD;
+ if ((flags & (FREAD|FWRITE)) == 0) {
+ vrele(vp);
+ return NULL;
+ }
+
sc = device_lookup_private(&midi_cd, unit);
- sc->seqopen = 1;
- md = malloc(sizeof *md, M_DEVBUF, M_WAITOK|M_ZERO);
- sc->seq_md = md;
+ md = kmem_zalloc(sizeof(*md), KM_SLEEP);
md->msc = sc;
md->unit = unit;
md->name = mi.name;
md->subtype = 0;
md->nr_voices = 128; /* XXX */
md->instr_bank_size = 128; /* XXX */
+ md->vp = vp;
if (mi.props & MIDI_PROP_CAN_INPUT)
md->capabilities |= SYNTH_CAP_INPUT;
+ sc->seq_md = md;
return (md);
}
@@ -1207,8 +1377,8 @@ midiseq_close(struct midi_dev *md)
dev = makedev(major, md->unit);
DPRINTFN(2, ("midiseq_close: %d\n", md->unit));
- cdev_close(dev, 0, 0, 0);
- free(md, M_DEVBUF);
+ (void)vn_close(md->vp, 0, kauth_cred_get());
+ kmem_free(md, sizeof(*md));
}
static void
@@ -1297,6 +1467,7 @@ static int
midiseq_loadpatch(struct midi_dev *md,
struct sysex_info *sysex, struct uio *uio)
{
+ struct sequencer_softc *sc;
u_char c, bf[128];
int i, cc, error;
@@ -1317,7 +1488,10 @@ midiseq_loadpatch(struct midi_dev *md,
return error;
if (c != MIDI_SYSEX_START) /* must start like this */
return EINVAL;
+ sc = md->seq;
+ mutex_enter(&sc->lock);
error = midiseq_out(md, &c, 1, 0);
+ mutex_exit(&sc->lock);
if (error)
return error;
--sysex->len;
@@ -1335,7 +1509,9 @@ midiseq_loadpatch(struct midi_dev *md,
* function will not block us (though in this case we have
* a process and could in principle block).
*/
+ mutex_enter(&sc->lock);
error = midiseq_out(md, bf, i, 0);
+ mutex_exit(&sc->lock);
if (error)
break;
sysex->len -= i;
@@ -1348,7 +1524,10 @@ midiseq_loadpatch(struct midi_dev *md,
*/
uio->uio_resid = 0;
c = MIDI_SYSEX_END;
- return midiseq_out(md, &c, 1, 0);
+ mutex_enter(&sc->lock);
+ error = midiseq_out(md, &c, 1, 0);
+ mutex_exit(&sc->lock);
+ return error;
}
#include "midi.h"
@@ -1358,7 +1537,7 @@ static dev_type_close(midiclose);
const struct cdevsw midi_cdevsw = {
midiopen, midiclose, noread, nowrite, noioctl,
- nostop, notty, nopoll, nommap, nokqfilter, D_OTHER
+ nostop, notty, nopoll, nommap, nokqfilter, D_OTHER | D_MPSAFE
};
/*
diff --git a/sys/dev/sequencervar.h b/sys/dev/sequencervar.h
index 5e933e7fbb9..89cf5712f18 100644
--- a/sys/dev/sequencervar.h
+++ b/sys/dev/sequencervar.h
@@ -1,7 +1,7 @@
-/* $NetBSD: sequencervar.h,v 1.13 2008/04/28 20:23:47 martin Exp $ */
+/* $NetBSD: sequencervar.h,v 1.14 2011/11/23 23:07:31 jmcneill Exp $ */
/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,6 +30,7 @@
*/
#include <sys/callout.h>
+#include <sys/vnode.h>
struct midi_softc;
@@ -69,25 +70,33 @@ struct midi_dev {
struct sequencer_softc *seq;
struct midi_softc *msc;
char doingsysex; /* doing a SEQ_SYSEX */
+ vnode_t *vp;
};
struct sequencer_softc {
struct device dev;
struct device *sc_dev; /* Hardware device struct */
- struct callout sc_callout;
- int isopen; /* Open indicator */
+ callout_t sc_callout;
+ kmutex_t lock;
+ kcondvar_t wchan;
+ kcondvar_t rchan;
+ kcondvar_t lchan;
+ int dvlock;
+ int dying;
+ u_int isopen; /* Open indicator */
int flags; /* Open flags */
int mode;
#define SEQ_OLD 0
#define SEQ_NEW 1
- int rchan, wchan;
int pbus;
- struct selinfo wsel; /* write selector */
- struct selinfo rsel; /* read selector */
- struct proc *async; /* process who wants audio SIGIO */
+ struct selinfo wsel; /* write selector */
+ struct selinfo rsel; /* read selector */
+ pid_t async; /* process who wants audio SIGIO */
void *sih;
+ pcq_t *pcq;
int nmidi; /* number of MIDI devices */
+ int ndevs;
struct midi_dev **devs;
struct syn_timer timer;
diff --git a/sys/dev/tc/bba.c b/sys/dev/tc/bba.c
index 71894df84ec..7d99142bd07 100644
--- a/sys/dev/tc/bba.c
+++ b/sys/dev/tc/bba.c
@@ -1,4 +1,4 @@
-/* $NetBSD: bba.c,v 1.38 2011/06/04 01:27:57 tsutsui Exp $ */
+/* $NetBSD: bba.c,v 1.39 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -29,13 +29,13 @@
/* maxine/alpha baseboard audio (bba) */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bba.c,v 1.38 2011/06/04 01:27:57 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bba.c,v 1.39 2011/11/23 23:07:36 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/bus.h>
#include <machine/autoconf.h>
@@ -111,10 +111,10 @@ static void bba_onclose(struct am7930_softc *);
static stream_filter_factory_t bba_output_conv;
static stream_filter_factory_t bba_input_conv;
-static int bba_output_conv_fetch_to(stream_fetcher_t *, audio_stream_t *,
- int);
-static int bba_input_conv_fetch_to(stream_fetcher_t *, audio_stream_t *,
- int);
+static int bba_output_conv_fetch_to(struct audio_softc *, stream_fetcher_t *,
+ audio_stream_t *, int);
+static int bba_input_conv_fetch_to(struct audio_softc *, stream_fetcher_t *,
+ audio_stream_t *, int);
struct am7930_glue bba_glue = {
bba_codec_iread,
@@ -136,8 +136,8 @@ static int bba_round_blocksize(void *, int, int, const audio_params_t *);
static int bba_halt_output(void *);
static int bba_halt_input(void *);
static int bba_getdev(void *, struct audio_device *);
-static void *bba_allocm(void *, int, size_t, struct malloc_type *, int);
-static void bba_freem(void *, void *, struct malloc_type *);
+static void *bba_allocm(void *, int, size_t);
+static void bba_freem(void *, void *, size_t);
static size_t bba_round_buffersize(void *, int, size_t);
static int bba_get_props(void *);
static paddr_t bba_mappage(void *, void *, off_t, int);
@@ -147,6 +147,8 @@ static int bba_trigger_output(void *, void *, void *, int,
static int bba_trigger_input(void *, void *, void *, int,
void (*)(void *), void *,
const audio_params_t *);
+static void bba_get_locks(void *opaque, kmutex_t **intr,
+ kmutex_t **thread);
static const struct audio_hw_if sa_hw_if = {
am7930_open,
@@ -176,6 +178,7 @@ static const struct audio_hw_if sa_hw_if = {
bba_trigger_output, /* md */
bba_trigger_input, /* md */
0,
+ bba_get_locks,
};
static struct audio_device bba_device = {
@@ -288,8 +291,7 @@ bba_reset(struct bba_softc *sc, int reset)
static void *
-bba_allocm(void *addr, int direction, size_t size,
- struct malloc_type *pool, int flags)
+bba_allocm(void *addr, int direction, size_t size)
{
struct am7930_softc *asc;
struct bba_softc *sc;
@@ -297,30 +299,28 @@ bba_allocm(void *addr, int direction, size_t size,
int rseg;
void *kva;
struct bba_mem *m;
- int w;
int state;
DPRINTF(("bba_allocm: size = %zu\n", size));
asc = addr;
sc = addr;
state = 0;
- w = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
if (bus_dmamem_alloc(sc->sc_dmat, size, BBA_DMABUF_ALIGN,
- BBA_DMABUF_BOUNDARY, &seg, 1, &rseg, w)) {
+ BBA_DMABUF_BOUNDARY, &seg, 1, &rseg, BUS_DMA_WAITOK)) {
aprint_error_dev(asc->sc_dev, "can't allocate DMA buffer\n");
goto bad;
}
state |= 1;
if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
- &kva, w | BUS_DMA_COHERENT)) {
+ &kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT)) {
aprint_error_dev(asc->sc_dev, "can't map DMA buffer\n");
goto bad;
}
state |= 2;
- m = malloc(sizeof(struct bba_mem), pool, flags);
+ m = kmem_alloc(sizeof(struct bba_mem), KM_SLEEP);
if (m == NULL)
goto bad;
m->addr = seg.ds_addr;
@@ -341,7 +341,7 @@ bad:
static void
-bba_freem(void *addr, void *ptr, struct malloc_type *pool)
+bba_freem(void *addr, void *ptr, size_t size)
{
struct bba_softc *sc;
struct bba_mem **mp, *m;
@@ -364,7 +364,7 @@ bba_freem(void *addr, void *ptr, struct malloc_type *pool)
seg.ds_addr = m->addr;
seg.ds_len = m->size;
bus_dmamem_free(sc->sc_dmat, &seg, 1);
- free(m, pool);
+ kmem_free(m, sizeof(struct bba_mem));
}
@@ -573,16 +573,26 @@ bad:
return 1;
}
+static void
+bba_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread)
+{
+ struct bba_softc *bsc = opaque;
+ struct am7930_softc *sc = &bsc->sc_am7930;
+
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
static int
bba_intr(void *addr)
{
struct bba_softc *sc;
struct bba_dma_state *d;
tc_addr_t nphys;
- int s, mask;
+ int mask;
sc = addr;
- s = splaudio();
+ mutex_enter(&sc->sc_am7930.sc_intr_lock);
mask = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR);
@@ -605,7 +615,7 @@ bba_intr(void *addr)
(*d->intr)(d->intr_arg);
}
- splx(s);
+ mutex_exit(&sc->sc_am7930.sc_intr_lock);
return 0;
}
@@ -649,14 +659,14 @@ bba_input_conv(struct audio_softc *sc, const audio_params_t *from,
}
static int
-bba_input_conv_fetch_to(stream_fetcher_t *self, audio_stream_t *dst,
- int max_used)
+bba_input_conv_fetch_to(struct audio_softc *sc, stream_fetcher_t *self,
+ audio_stream_t *dst, int max_used)
{
stream_filter_t *this;
int m, err;
this = (stream_filter_t *)self;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used * 4)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used * 4)))
return err;
m = dst->end - dst->start;
m = min(m, max_used);
@@ -674,15 +684,15 @@ bba_output_conv(struct audio_softc *sc, const audio_params_t *from,
}
static int
-bba_output_conv_fetch_to(stream_fetcher_t *self, audio_stream_t *dst,
- int max_used)
+bba_output_conv_fetch_to(struct audio_softc *sc, stream_fetcher_t *self,
+ audio_stream_t *dst, int max_used)
{
stream_filter_t *this;
int m, err;
this = (stream_filter_t *)self;
max_used = (max_used + 3) & ~3;
- if ((err = this->prev->fetch_to(this->prev, this->src, max_used / 4)))
+ if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used / 4)))
return err;
m = (dst->end - dst->start) & ~3;
m = min(m, max_used);
diff --git a/sys/dev/usb/uaudio.c b/sys/dev/usb/uaudio.c
index 0df73fbb2b2..f4897c195b1 100644
--- a/sys/dev/usb/uaudio.c
+++ b/sys/dev/usb/uaudio.c
@@ -1,4 +1,4 @@
-/* $NetBSD: uaudio.c,v 1.120 2010/12/28 20:11:18 jakllsch Exp $ */
+/* $NetBSD: uaudio.c,v 1.121 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.120 2010/12/28 20:11:18 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.121 2011/11/23 23:07:36 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -155,8 +155,18 @@ struct chan {
struct uaudio_softc *sc; /* our softc */
};
+/*
+ * XXX Locking notes:
+ *
+ * The MI USB audio subsystem is not MP-SAFE. Our strategy here
+ * is to ensure we have the kernel lock held when calling into
+ * usbd, and, generally, to have dropped the sc_intr_lock during
+ * these sections as well since the usb code will sleep.
+ */
struct uaudio_softc {
device_t sc_dev; /* base device */
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
usbd_device_handle sc_udev; /* USB device */
int sc_ac_iface; /* Audio Control interface */
usbd_interface_handle sc_ac_ifaceh;
@@ -322,6 +332,7 @@ Static int uaudio_mixer_set_port(void *, mixer_ctrl_t *);
Static int uaudio_mixer_get_port(void *, mixer_ctrl_t *);
Static int uaudio_query_devinfo(void *, mixer_devinfo_t *);
Static int uaudio_get_props(void *);
+Static void uaudio_get_locks(void *, kmutex_t **, kmutex_t **);
Static const struct audio_hw_if uaudio_hw_if = {
uaudio_open,
@@ -351,7 +362,7 @@ Static const struct audio_hw_if uaudio_hw_if = {
uaudio_trigger_output,
uaudio_trigger_input,
NULL,
- NULL,
+ uaudio_get_locks,
};
int uaudio_match(device_t, cfdata_t, void *);
@@ -393,6 +404,8 @@ uaudio_attach(device_t parent, device_t self, void *aux)
sc->sc_dev = self;
sc->sc_udev = uaa->device;
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB);
strlcpy(sc->sc_adev.name, "USB audio", sizeof(sc->sc_adev.name));
strlcpy(sc->sc_adev.version, "", sizeof(sc->sc_adev.version));
@@ -519,6 +532,10 @@ uaudio_detach(device_t self, int flags)
if (sc->sc_formats != NULL)
free(sc->sc_formats, M_USBDEV);
auconv_delete_encodings(sc->sc_encodings);
+
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
+
return rv;
}
@@ -2173,10 +2190,12 @@ uaudio_close(void *addr)
Static int
uaudio_drain(void *addr)
{
- struct uaudio_softc *sc;
+ struct uaudio_softc *sc = addr;
- sc = addr;
- usbd_delay_ms(sc->sc_udev, UAUDIO_NCHANBUFS * UAUDIO_NFRAMES);
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
+ kpause("uaudiodr", false,
+ mstohz(UAUDIO_NCHANBUFS * UAUDIO_NFRAMES), &sc->sc_intr_lock);
return 0;
}
@@ -2184,32 +2203,42 @@ uaudio_drain(void *addr)
Static int
uaudio_halt_out_dma(void *addr)
{
- struct uaudio_softc *sc;
+ struct uaudio_softc *sc = addr;
DPRINTF(("uaudio_halt_out_dma: enter\n"));
- sc = addr;
+
+ KERNEL_LOCK(1, curlwp);
+ mutex_spin_exit(&sc->sc_intr_lock);
if (sc->sc_playchan.pipe != NULL) {
uaudio_chan_close(sc, &sc->sc_playchan);
sc->sc_playchan.pipe = NULL;
uaudio_chan_free_buffers(sc, &sc->sc_playchan);
sc->sc_playchan.intr = NULL;
}
+ mutex_spin_enter(&sc->sc_intr_lock);
+ KERNEL_UNLOCK_ONE(curlwp);
+
return 0;
}
Static int
uaudio_halt_in_dma(void *addr)
{
- struct uaudio_softc *sc;
+ struct uaudio_softc *sc = addr;
DPRINTF(("uaudio_halt_in_dma: enter\n"));
- sc = addr;
+
+ KERNEL_LOCK(1, curlwp);
+ mutex_spin_exit(&sc->sc_intr_lock);
if (sc->sc_recchan.pipe != NULL) {
uaudio_chan_close(sc, &sc->sc_recchan);
sc->sc_recchan.pipe = NULL;
uaudio_chan_free_buffers(sc, &sc->sc_recchan);
sc->sc_recchan.intr = NULL;
}
+ mutex_spin_enter(&sc->sc_intr_lock);
+ KERNEL_UNLOCK_ONE(curlwp);
+
return 0;
}
@@ -2283,6 +2312,16 @@ uaudio_get_props(void *addr)
}
+Static void
+uaudio_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct uaudio_softc *sc;
+
+ sc = addr;
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
Static int
uaudio_get(struct uaudio_softc *sc, int which, int type, int wValue,
int wIndex, int len)
@@ -2412,8 +2451,10 @@ uaudio_ctl_get(struct uaudio_softc *sc, int which, struct mixerctl *mc,
int val;
DPRINTFN(5,("uaudio_ctl_get: which=%d chan=%d\n", which, chan));
+ KERNEL_LOCK(1, curlwp);
val = uaudio_get(sc, which, UT_READ_CLASS_INTERFACE, mc->wValue[chan],
mc->wIndex, MIX_SIZE(mc->type));
+ KERNEL_UNLOCK_ONE(curlwp);
return uaudio_value2bsd(mc, val);
}
@@ -2422,8 +2463,10 @@ uaudio_ctl_set(struct uaudio_softc *sc, int which, struct mixerctl *mc,
int chan, int val)
{
val = uaudio_bsd2value(mc, val);
+ KERNEL_LOCK(1, curlwp);
uaudio_set(sc, which, UT_WRITE_CLASS_INTERFACE, mc->wValue[chan],
mc->wIndex, MIX_SIZE(mc->type), val);
+ KERNEL_UNLOCK_ONE(curlwp);
}
Static int
@@ -2535,11 +2578,18 @@ uaudio_trigger_input(void *addr, void *start, void *end, int blksize,
"fraction=0.%03d\n", ch->sample_size, ch->bytes_per_frame,
ch->fraction));
+ KERNEL_LOCK(1, curlwp);
+ mutex_spin_exit(&sc->sc_intr_lock);
err = uaudio_chan_alloc_buffers(sc, ch);
- if (err)
+ if (err) {
+ mutex_spin_enter(&sc->sc_intr_lock);
+ KERNEL_UNLOCK_ONE(curlwp);
return EIO;
+ }
err = uaudio_chan_open(sc, ch);
+ mutex_spin_enter(&sc->sc_intr_lock);
+ KERNEL_UNLOCK_ONE(curlwp);
if (err) {
uaudio_chan_free_buffers(sc, ch);
return EIO;
@@ -2548,10 +2598,12 @@ uaudio_trigger_input(void *addr, void *start, void *end, int blksize,
ch->intr = intr;
ch->arg = arg;
+ KERNEL_LOCK(1, curlwp);
s = splusb();
for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX -1 shouldn't be needed */
uaudio_chan_rtransfer(ch);
splx(s);
+ KERNEL_UNLOCK_ONE(curlwp);
return 0;
}
@@ -2578,11 +2630,18 @@ uaudio_trigger_output(void *addr, void *start, void *end, int blksize,
"fraction=0.%03d\n", ch->sample_size, ch->bytes_per_frame,
ch->fraction));
+ KERNEL_LOCK(1, curlwp);
+ mutex_spin_exit(&sc->sc_intr_lock);
err = uaudio_chan_alloc_buffers(sc, ch);
- if (err)
+ if (err) {
+ mutex_spin_enter(&sc->sc_intr_lock);
+ KERNEL_UNLOCK_ONE(curlwp);
return EIO;
+ }
err = uaudio_chan_open(sc, ch);
+ mutex_spin_enter(&sc->sc_intr_lock);
+ KERNEL_UNLOCK_ONE(curlwp);
if (err) {
uaudio_chan_free_buffers(sc, ch);
return EIO;
@@ -2591,10 +2650,12 @@ uaudio_trigger_output(void *addr, void *start, void *end, int blksize,
ch->intr = intr;
ch->arg = arg;
+ KERNEL_LOCK(1, curlwp);
s = splusb();
for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX */
uaudio_chan_ptransfer(ch);
splx(s);
+ KERNEL_UNLOCK_ONE(curlwp);
return 0;
}
@@ -2779,7 +2840,6 @@ uaudio_chan_pintr(usbd_xfer_handle xfer, usbd_private_handle priv,
struct chanbuf *cb;
struct chan *ch;
uint32_t count;
- int s;
cb = priv;
ch = cb->chan;
@@ -2798,7 +2858,7 @@ uaudio_chan_pintr(usbd_xfer_handle xfer, usbd_private_handle priv,
#endif
ch->transferred += cb->size;
- s = splaudio();
+ mutex_spin_enter(&ch->sc->sc_intr_lock);
/* Call back to upper layer */
while (ch->transferred >= ch->blksize) {
ch->transferred -= ch->blksize;
@@ -2806,7 +2866,7 @@ uaudio_chan_pintr(usbd_xfer_handle xfer, usbd_private_handle priv,
ch->intr, ch->arg));
ch->intr(ch->arg);
}
- splx(s);
+ mutex_spin_exit(&ch->sc->sc_intr_lock);
/* start next transfer */
uaudio_chan_ptransfer(ch);
@@ -2865,7 +2925,7 @@ uaudio_chan_rintr(usbd_xfer_handle xfer, usbd_private_handle priv,
struct chanbuf *cb;
struct chan *ch;
uint32_t count;
- int s, i, n, frsize;
+ int i, n, frsize;
cb = priv;
ch = cb->chan;
@@ -2905,14 +2965,14 @@ uaudio_chan_rintr(usbd_xfer_handle xfer, usbd_private_handle priv,
/* Call back to upper layer */
ch->transferred += count;
- s = splaudio();
+ mutex_spin_enter(&ch->sc->sc_intr_lock);
while (ch->transferred >= ch->blksize) {
ch->transferred -= ch->blksize;
DPRINTFN(5,("uaudio_chan_rintr: call %p(%p)\n",
ch->intr, ch->arg));
ch->intr(ch->arg);
}
- splx(s);
+ mutex_spin_exit(&ch->sc->sc_intr_lock);
/* start next transfer */
uaudio_chan_rtransfer(ch);
@@ -3045,6 +3105,7 @@ Static usbd_status
uaudio_set_speed(struct uaudio_softc *sc, int endpt, u_int speed)
{
usb_device_request_t req;
+ usbd_status err;
uint8_t data[3];
DPRINTFN(5,("uaudio_set_speed: endpt=%d speed=%u\n", endpt, speed));
@@ -3057,7 +3118,11 @@ uaudio_set_speed(struct uaudio_softc *sc, int endpt, u_int speed)
data[1] = speed >> 8;
data[2] = speed >> 16;
- return usbd_do_request(sc->sc_udev, &req, data);
+ KERNEL_LOCK(1, curlwp);
+ err = usbd_do_request(sc->sc_udev, &req, data);
+ KERNEL_UNLOCK_ONE(curlwp);
+
+ return err;
}
#ifdef _MODULE
diff --git a/sys/dev/usb/umidi.c b/sys/dev/usb/umidi.c
index 81369b277af..9cd4405d09f 100644
--- a/sys/dev/usb/umidi.c
+++ b/sys/dev/usb/umidi.c
@@ -1,4 +1,4 @@
-/* $NetBSD: umidi.c,v 1.44 2011/10/07 19:41:03 jakllsch Exp $ */
+/* $NetBSD: umidi.c,v 1.45 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: umidi.c,v 1.44 2011/10/07 19:41:03 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: umidi.c,v 1.45 2011/11/23 23:07:36 jmcneill Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -79,6 +79,7 @@ static int umidi_commonmsg(void *, int, u_char *, int);
static int umidi_sysex(void *, u_char *, int);
static int umidi_rtmsg(void *, int);
static void umidi_getinfo(void *, struct midi_info *);
+static void umidi_get_locks(void *, kmutex_t **, kmutex_t **);
static usbd_status alloc_pipe(struct umidi_endpoint *);
static void free_pipe(struct umidi_endpoint *);
@@ -127,11 +128,11 @@ static void out_solicit(void *); /* struct umidi_endpoint* for softintr */
const struct midi_hw_if umidi_hw_if = {
- umidi_open,
- umidi_close,
- umidi_rtmsg,
- umidi_getinfo,
- 0, /* ioctl */
+ .open = umidi_open,
+ .close = umidi_close,
+ .output = umidi_rtmsg,
+ .getinfo = umidi_getinfo,
+ .get_locks = umidi_get_locks,
};
struct midi_hw_if_ext umidi_hw_if_ext = {
@@ -200,6 +201,8 @@ umidi_attach(device_t parent, device_t self, void *aux)
aprint_normal_dev(self, "");
umidi_print_quirk(sc->sc_quirk);
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB);
err = alloc_all_endpoints(sc);
if (err!=USBD_NORMAL_COMPLETION) {
@@ -297,6 +300,9 @@ umidi_detach(device_t self, int flags)
usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
sc->sc_dev);
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
+
return 0;
}
@@ -436,6 +442,15 @@ umidi_getinfo(void *addr, struct midi_info *mi)
midi_register_hw_if_ext(mm? &umidi_hw_if_mm : &umidi_hw_if_ext);
}
+static void
+umidi_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
+{
+ struct umidi_mididev *mididev = addr;
+ struct umidi_softc *sc = mididev->sc;
+
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
/*
* each endpoint stuffs
@@ -1547,6 +1562,7 @@ in_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
{
int cn, len, i;
struct umidi_endpoint *ep = (struct umidi_endpoint *)priv;
+ struct umidi_softc *sc = ep->sc;
struct umidi_jack *jack;
unsigned char *packet;
umidi_packet_bufp slot;
@@ -1557,6 +1573,7 @@ in_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
if (ep->sc->sc_dying || !ep->num_open)
return;
+ mutex_enter(&sc->sc_intr_lock);
usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
if ( 0 == count % UMIDI_PACKET_SIZE ) {
DPRINTFN(200,("%s: input endpoint %p transfer length %u\n",
@@ -1588,6 +1605,7 @@ in_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
(unsigned)data[0],
(unsigned)data[1],
(unsigned)data[2]));
+ mutex_exit(&sc->sc_intr_lock);
return;
}
@@ -1610,6 +1628,7 @@ in_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
}
(void)start_input_transfer(ep);
+ mutex_exit(&sc->sc_intr_lock);
}
static void
@@ -1623,6 +1642,7 @@ out_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
if (sc->sc_dying)
return;
+ mutex_enter(&sc->sc_intr_lock);
#ifdef UMIDI_DEBUG
if ( umididebug >= 200 )
microtime(&umidi_tv);
@@ -1657,6 +1677,7 @@ out_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
ep->soliciting = 1;
out_solicit(ep);
}
+ mutex_exit(&sc->sc_intr_lock);
}
/*
diff --git a/sys/dev/usb/umidivar.h b/sys/dev/usb/umidivar.h
index abc3c12962f..2a1243744f5 100644
--- a/sys/dev/usb/umidivar.h
+++ b/sys/dev/usb/umidivar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: umidivar.h,v 1.14 2010/11/03 22:34:24 dyoung Exp $ */
+/* $NetBSD: umidivar.h,v 1.15 2011/11/23 23:07:36 jmcneill Exp $ */
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -119,4 +119,7 @@ struct umidi_softc {
struct umidi_endpoint *sc_in_ep;
struct umidi_endpoint *sc_endpoints;
int cblnums_global;
+
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
};