Module Name: src
Committed By: nat
Date: Fri Feb 10 19:31:42 UTC 2017
Modified Files:
src/share/man/man4: audio.4
src/sys/dev: audio.c audiobell.c audiovar.h
src/sys/sys: audioio.h file.h
src/usr.bin/audio/ctl: audioctl.1 ctl.c
Log Message:
Audio now uses fdclone, there is no longer a limitation of one audio
instance per process. Virtual channels are placed in a queue, so there is
no longer a compile time limit of VAUDIOCHANS.
A new sysctl has been added to control multiple user access.
Mixer labels on virtual channels are now prefixed by vchan.
audiobell.c and audioctl have been updated to reflect these changes.
Use of fdclone was posted to tech-kern@ and improvements made.
Multiuser access control changes and the use of a queue were suggessted by
pgoyette@
To generate a diff of this commit:
cvs rdiff -u -r1.73 -r1.74 src/share/man/man4/audio.4
cvs rdiff -u -r1.301 -r1.302 src/sys/dev/audio.c
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/audiobell.c
cvs rdiff -u -r1.49 -r1.50 src/sys/dev/audiovar.h
cvs rdiff -u -r1.35 -r1.36 src/sys/sys/audioio.h
cvs rdiff -u -r1.80 -r1.81 src/sys/sys/file.h
cvs rdiff -u -r1.20 -r1.21 src/usr.bin/audio/ctl/audioctl.1
cvs rdiff -u -r1.41 -r1.42 src/usr.bin/audio/ctl/ctl.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/share/man/man4/audio.4
diff -u src/share/man/man4/audio.4:1.73 src/share/man/man4/audio.4:1.74
--- src/share/man/man4/audio.4:1.73 Mon Dec 12 11:49:27 2016
+++ src/share/man/man4/audio.4 Fri Feb 10 19:31:42 2017
@@ -1,4 +1,4 @@
-.\" $NetBSD: audio.4,v 1.73 2016/12/12 11:49:27 nat Exp $
+.\" $NetBSD: audio.4,v 1.74 2017/02/10 19:31:42 nat Exp $
.\"
.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -99,11 +99,8 @@ and
are identical.
.Sh VIRTUAL CHANNELS
Any process may open a sampling device at a given time.
-There is a constraint of
-.Em one
-device per process and file descriptors may
-.Em not
-be shared between processes.
+Any number of devices per process and file descriptors may be shared between
+processes.
.Pp
Virtual channels are converted to a common format, signed linear encoding,
frequency channels and precision.
@@ -116,6 +113,7 @@ variables.
.It hw.driverN.frequency
.It hw.driverN.channels
.It hw.driverN.saturate
+.It hw.driverN.multiuser
.El
.Pp
Where
@@ -141,14 +139,28 @@ If set to false the channels are
.Em divided
evenly in volume with respect to the master volume.
.Pp
+An additional
+.Xr sysctl 8
+variable determines if multiple users are allowed to access the sampling
+device, hw.driverN.multiuser.
+.Pp
+By default it is set to false.
+This means that the sampling device may be only used by
+.Em one
+user at a time.
+Other users (except root) attempting to open the sampling device will be
+denied.
+.Pp
+If set to true, all users may access the sampling device at any time.
+.Pp
Each virtual channel has a corresponding mixer:
.Bl -tag -width -compact
-.It outputs.dacN Output volume
-.It inputs.micN Recording volume
+.It vchan.dacN Output volume
+.It vchan.micN Recording volume
.El
.Pp
Where N is the virtual channel number.
-e.g ouputs.dac0 controlling playback volume and outputs.mic0 controlling
+e.g vchan.dac0 controlling playback volume and vchan.mic0 controlling
recording volume for the first virtual channel.
.Pp
On a half-duplex device, writes while recording is in progress will be
@@ -233,17 +245,8 @@ The following
commands are supported on the sample devices:
.Pp
.Bl -tag -width indent
-.It Dv AUDIO_SETPROC (struct audio_pid)
-This command will select the audio device opened by pid.
-.Bd -literal
-struct audio_pid {
- pid_t pid;
- lwpid_t lwpid;
-};
-.Ed
-.Pp
-Currently the lpwid value is
-.Em ignored .
+.It Dv AUDIO_SETPROC (int)
+This command will select the audio channel for subsequent ioctl calls.
.It Dv AUDIO_FLUSH
This command stops all playback and recording, clears all queued
buffers, resets error counters, and restarts recording and playback as
Index: src/sys/dev/audio.c
diff -u src/sys/dev/audio.c:1.301 src/sys/dev/audio.c:1.302
--- src/sys/dev/audio.c:1.301 Tue Feb 7 02:05:26 2017
+++ src/sys/dev/audio.c Fri Feb 10 19:31:42 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: audio.c,v 1.301 2017/02/07 02:05:26 nat Exp $ */
+/* $NetBSD: audio.c,v 1.302 2017/02/10 19:31:42 nat Exp $ */
/*-
* Copyright (c) 2016 Nathanial Sloss <[email protected]>
@@ -148,7 +148,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.301 2017/02/07 02:05:26 nat Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.302 2017/02/10 19:31:42 nat Exp $");
#include "audio.h"
#if NAUDIO > 0
@@ -157,12 +157,17 @@ __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
#include <sys/vnode.h>
#include <sys/select.h>
#include <sys/poll.h>
+#include <sys/kauth.h>
#include <sys/kmem.h>
#include <sys/malloc.h>
#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
@@ -203,88 +208,103 @@ int audio_idle_timeout = 30;
int audio_blk_ms = AUDIO_BLK_MS;
-int audiosetinfo(struct audio_softc *, struct audio_info *, bool, int);
-int audiogetinfo(struct audio_softc *, struct audio_info *, int, int);
-
-int audio_open(dev_t, struct audio_softc *, int, int, struct lwp *);
-int audio_close(struct audio_softc *, int, int, struct lwp *, int);
-int audio_read(struct audio_softc *, struct uio *, int);
-int audio_write(struct audio_softc *, struct uio *, int);
+int audiosetinfo(struct audio_softc *, struct audio_info *, bool,
+ struct virtual_channel *);
+int audiogetinfo(struct audio_softc *, struct audio_info *, int,
+ struct virtual_channel *);
+
+int audio_open(dev_t, struct audio_softc *, int, int, struct lwp *,
+ struct file **);
+int audio_close(struct audio_softc *, int, struct audio_chan *);
+int audio_read(struct audio_softc *, struct uio *, int,
+ struct virtual_channel *);
+int audio_write(struct audio_softc *, struct uio *, int,
+ struct virtual_channel *);
int audio_ioctl(dev_t, struct audio_softc *, u_long, void *, int,
- struct lwp *);
-int audio_poll(struct audio_softc *, int, struct lwp *);
-int audio_kqfilter(struct audio_softc *, struct knote *);
-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 *);
+ struct lwp *, struct audio_chan *);
+int audio_poll(struct audio_softc *, int, struct lwp *,
+ struct virtual_channel *);
+int audio_kqfilter(struct audio_chan *, struct knote *);
+paddr_t audiommap(dev_t, off_t, int, struct virtual_channel *);
+paddr_t audio_mmap(struct audio_softc *, off_t, int, struct virtual_channel *);
+int audio_fop_mmap(struct file *, off_t *, size_t, int, int *, int *,
+ struct uvm_object **, int *);
+
+int mixer_open(dev_t, struct audio_softc *, int, int, struct lwp *,
+ struct file **);
+int mixer_close(struct audio_softc *, int, struct audio_chan *);
int mixer_ioctl(struct audio_softc *, u_long, void *, int, struct lwp *);
static void mixer_remove(struct audio_softc *);
static void mixer_signal(struct audio_softc *);
+static void grow_mixer_states(struct audio_softc *, int);
+static void shrink_mixer_states(struct audio_softc *, int);
-void audio_init_record(struct audio_softc *, int);
-void audio_init_play(struct audio_softc *, int);
-int audiostartr(struct audio_softc *, int);
-int audiostartp(struct audio_softc *, int);
+void audio_init_record(struct audio_softc *, struct virtual_channel *);
+void audio_init_play(struct audio_softc *, struct virtual_channel *);
+int audiostartr(struct audio_softc *, struct virtual_channel *);
+int audiostartp(struct audio_softc *, struct virtual_channel *);
void audio_rint(void *);
void audio_pint(void *);
void audio_mix(void *);
void audio_upmix(void *);
void audio_play_thread(void *);
void audio_rec_thread(void *);
-void recswvol_func(struct audio_softc *, struct audio_ringbuffer *, int,
- size_t);
-void recswvol_func8(struct audio_softc *, struct audio_ringbuffer *, int,
- size_t);
-void recswvol_func16(struct audio_softc *, struct audio_ringbuffer *, int,
- size_t);
-void recswvol_func32(struct audio_softc *, struct audio_ringbuffer *, int,
- size_t);
+void recswvol_func(struct audio_softc *, struct audio_ringbuffer *,
+ size_t, struct virtual_channel *);
+void recswvol_func8(struct audio_softc *, struct audio_ringbuffer *,
+ size_t, struct virtual_channel *);
+void recswvol_func16(struct audio_softc *, struct audio_ringbuffer *,
+ size_t, struct virtual_channel *);
+void recswvol_func32(struct audio_softc *, struct audio_ringbuffer *,
+ size_t, struct virtual_channel *);
void saturate_func(struct audio_softc *);
void saturate_func8(struct audio_softc *);
void saturate_func16(struct audio_softc *);
void saturate_func32(struct audio_softc *);
-void mix_func(struct audio_softc *, struct audio_ringbuffer *, int);
-void mix_func8(struct audio_softc *, struct audio_ringbuffer *, int);
-void mix_func16(struct audio_softc *, struct audio_ringbuffer *, int);
-void mix_func32(struct audio_softc *, struct audio_ringbuffer *, int);
+void mix_func(struct audio_softc *, struct audio_ringbuffer *,
+ struct virtual_channel *);
+void mix_func8(struct audio_softc *, struct audio_ringbuffer *,
+ struct virtual_channel *);
+void mix_func16(struct audio_softc *, struct audio_ringbuffer *,
+ struct virtual_channel *);
+void mix_func32(struct audio_softc *, struct audio_ringbuffer *,
+ struct virtual_channel *);
void mix_write(void *);
void mix_read(void *);
int audio_check_params(struct audio_params *);
-void audio_calc_blksize(struct audio_softc *, int, int);
+void audio_calc_blksize(struct audio_softc *, int, struct virtual_channel *);
void audio_fill_silence(struct audio_params *, uint8_t *, int);
int audio_silence_copyout(struct audio_softc *, int, struct uio *);
void audio_init_ringbuffer(struct audio_softc *,
struct audio_ringbuffer *, int);
-int audio_initbufs(struct audio_softc *, int);
-void audio_calcwater(struct audio_softc *, int);
-int audio_drain(struct audio_softc *, int);
-void audio_clear(struct audio_softc *, int);
-void audio_clear_intr_unlocked(struct audio_softc *sc, int);
+int audio_initbufs(struct audio_softc *, struct virtual_channel *);
+void audio_calcwater(struct audio_softc *, struct virtual_channel *);
+int audio_drain(struct audio_softc *, struct audio_chan *);
+void audio_clear(struct audio_softc *, struct virtual_channel *);
+void audio_clear_intr_unlocked(struct audio_softc *sc,
+ struct virtual_channel *);
static inline void
audio_pint_silence(struct audio_softc *, struct audio_ringbuffer *,
- uint8_t *, int, int);
+ uint8_t *, int, struct virtual_channel *);
int audio_alloc_ring(struct audio_softc *, struct audio_ringbuffer *, int,
size_t);
void audio_free_ring(struct audio_softc *, struct audio_ringbuffer *);
static int audio_setup_pfilters(struct audio_softc *, const audio_params_t *,
- stream_filter_list_t *, int);
+ stream_filter_list_t *, struct virtual_channel *);
static int audio_setup_rfilters(struct audio_softc *, const audio_params_t *,
- stream_filter_list_t *, int);
+ stream_filter_list_t *, struct virtual_channel *);
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
- (stream_filter_list_t *, stream_filter_factory_t,
- const audio_params_t *);
-static void stream_filter_list_prepend
- (stream_filter_list_t *, stream_filter_factory_t,
- const audio_params_t *);
-static void stream_filter_list_set
- (stream_filter_list_t *, int, stream_filter_factory_t,
- const audio_params_t *);
-int audio_set_defaults(struct audio_softc *, u_int, int);
+static void stream_filter_list_append(stream_filter_list_t *,
+ stream_filter_factory_t, const audio_params_t *);
+static void stream_filter_list_prepend(stream_filter_list_t *,
+ stream_filter_factory_t, const audio_params_t *);
+static void stream_filter_list_set(stream_filter_list_t *, int,
+ stream_filter_factory_t, const audio_params_t *);
+int audio_set_defaults(struct audio_softc *, u_int,
+ struct virtual_channel *);
static int audio_sysctl_frequency(SYSCTLFN_PROTO);
static int audio_sysctl_precision(SYSCTLFN_PROTO);
static int audio_sysctl_channels(SYSCTLFN_PROTO);
@@ -321,8 +341,14 @@ static int audio_enter(dev_t, krw_t, str
static void audio_exit(struct audio_softc *);
static int audio_waitio(struct audio_softc *, kcondvar_t *);
-#define AUDIO_OUTPUT_CLASS 0
-#define AUDIO_INPUT_CLASS 1
+int audioclose(struct file *);
+int audioread(struct file *, off_t *, struct uio *, kauth_cred_t, int);
+int audiowrite(struct file *, off_t *, struct uio *, kauth_cred_t, int);
+int audioioctl(struct file *, u_long, void *);
+int audiopoll(struct file *, int);
+int audiofcntl(struct file *, u_int, void *);
+int audiokqfilter(struct file *, struct knote *);
+int audiostat(struct file *, struct stat *);
struct portname {
const char *name;
@@ -355,13 +381,14 @@ static int
audio_set_port(struct audio_softc *, mixer_ctrl_t *);
static int
audio_query_devinfo(struct audio_softc *, mixer_devinfo_t *);
-static int audio_set_params
- (struct audio_softc *, int, int, audio_params_t *, audio_params_t *,
- stream_filter_list_t *, stream_filter_list_t *, int);
+static int audio_set_params (struct audio_softc *, int, int,
+ audio_params_t *, audio_params_t *,
+ stream_filter_list_t *, stream_filter_list_t *,
+ struct virtual_channel *);
static int
audio_query_encoding(struct audio_softc *, struct audio_encoding *);
static int audio_set_vchan_defaults
- (struct audio_softc *, u_int, const struct audio_format *, int);
+ (struct audio_softc *, u_int, const struct audio_format *);
static int vchan_autoconfig(struct audio_softc *);
int au_get_lr_value(struct audio_softc *, mixer_ctrl_t *, int *, int *);
int au_set_lr_value(struct audio_softc *, mixer_ctrl_t *, int, int);
@@ -380,28 +407,36 @@ static int uio_fetcher_fetch_to(struct a
static int null_fetcher_fetch_to(struct audio_softc *, stream_fetcher_t *,
audio_stream_t *, int);
+int audiobellopen(dev_t, int, int, struct lwp *, struct file **);
+
dev_type_open(audioopen);
-dev_type_close(audioclose);
-dev_type_read(audioread);
-dev_type_write(audiowrite);
-dev_type_ioctl(audioioctl);
-dev_type_poll(audiopoll);
-dev_type_mmap(audiommap);
-dev_type_kqfilter(audiokqfilter);
const struct cdevsw audio_cdevsw = {
.d_open = audioopen,
- .d_close = audioclose,
- .d_read = audioread,
- .d_write = audiowrite,
- .d_ioctl = audioioctl,
+ .d_close = noclose,
+ .d_read = noread,
+ .d_write = nowrite,
+ .d_ioctl = noioctl,
.d_stop = nostop,
.d_tty = notty,
- .d_poll = audiopoll,
- .d_mmap = audiommap,
- .d_kqfilter = audiokqfilter,
+ .d_poll = nopoll,
+ .d_mmap = nommap,
+ .d_kqfilter = nokqfilter,
.d_discard = nodiscard,
- .d_flag = D_MCLOSE | D_MPSAFE
+ .d_flag = D_OTHER | D_MPSAFE
+};
+
+const struct fileops audio_fileops = {
+ .fo_read = audioread,
+ .fo_write = audiowrite,
+ .fo_ioctl = audioioctl,
+ .fo_fcntl = audiofcntl,
+ .fo_stat = audiostat,
+ .fo_poll = audiopoll,
+ .fo_close = audioclose,
+ .fo_mmap = audio_fop_mmap,
+ .fo_kqfilter = audiokqfilter,
+ .fo_restart = fnullop_restart
};
/* The default audio mode: 8 kHz mono mu-law */
@@ -441,6 +476,7 @@ audioattach(device_t parent, device_t se
struct audio_softc *sc;
struct audio_attach_args *sa;
struct virtual_channel *vc;
+ struct audio_chan *chan;
const struct audio_hw_if *hwp;
const struct sysctlnode *node;
void *hdlp;
@@ -487,10 +523,11 @@ audioattach(device_t parent, device_t se
sc->sc_trigger_started = false;
sc->sc_rec_started = false;
sc->sc_dying = false;
- sc->sc_vchan[0] = kmem_zalloc(sizeof(struct virtual_channel), KM_SLEEP);
- vc = sc->sc_vchan[0];
- memset(sc->sc_audiopid, -1, sizeof(sc->sc_audiopid));
- memset(sc->sc_despid, -1, sizeof(sc->sc_despid));
+ chan = kmem_zalloc(sizeof(struct audio_chan), KM_SLEEP);
+ vc = kmem_zalloc(sizeof(struct virtual_channel), KM_SLEEP);
+ chan->vc = vc;
+ SIMPLEQ_INIT(&sc->sc_audiochan);
+ SIMPLEQ_INSERT_HEAD(&sc->sc_audiochan, chan, entries);
vc->sc_open = 0;
vc->sc_mode = 0;
vc->sc_npfilters = 0;
@@ -575,13 +612,16 @@ audioattach(device_t parent, device_t se
if (error)
goto bad_play;
- error = audio_alloc_ring(sc, &sc->sc_vchan[0]->sc_mpr,
+ error = audio_alloc_ring(sc, &vc->sc_mpr,
AUMODE_PLAY, AU_RING_SIZE);
bad_play:
if (error) {
if (sc->sc_pr.s.start != NULL)
audio_free_ring(sc, &sc->sc_pr);
sc->hw_if = NULL;
+ if (vc->sc_mpr.s.start != 0)
+ audio_free_ring(sc, &vc->sc_mpr);
+ sc->hw_if = NULL;
aprint_error_dev(sc->sc_dev, "could not allocate play "
"buffer\n");
return;
@@ -593,16 +633,16 @@ bad_play:
if (error)
goto bad_rec;
- error = audio_alloc_ring(sc, &sc->sc_vchan[0]->sc_mrr,
+ error = audio_alloc_ring(sc, &vc->sc_mrr,
AUMODE_RECORD, AU_RING_SIZE);
bad_rec:
if (error) {
- if (sc->sc_vchan[0]->sc_mrr.s.start != NULL)
- audio_free_ring(sc, &sc->sc_vchan[0]->sc_mrr);
+ if (vc->sc_mrr.s.start != NULL)
+ audio_free_ring(sc, &vc->sc_mrr);
if (sc->sc_pr.s.start != NULL)
audio_free_ring(sc, &sc->sc_pr);
- if (sc->sc_vchan[0]->sc_mpr.s.start != 0)
- audio_free_ring(sc, &sc->sc_vchan[0]->sc_mpr);
+ if (vc->sc_mpr.s.start != 0)
+ audio_free_ring(sc, &vc->sc_mpr);
sc->hw_if = NULL;
aprint_error_dev(sc->sc_dev, "could not allocate record"
" buffer\n");
@@ -612,6 +652,7 @@ bad_rec:
sc->sc_lastgain = 128;
sc->sc_saturate = true;
+ sc->sc_multiuser = false;
mutex_exit(sc->sc_lock);
error = vchan_autoconfig(sc);
@@ -620,8 +661,8 @@ bad_rec:
"failed\n", __func__);
}
- sc->sc_pr.blksize = sc->sc_vchan[0]->sc_mpr.blksize;
- sc->sc_rr.blksize = sc->sc_vchan[0]->sc_mrr.blksize;
+ sc->sc_pr.blksize = vc->sc_mpr.blksize;
+ sc->sc_rr.blksize = vc->sc_mrr.blksize;
sc->sc_sih_rd = softint_establish(SOFTINT_SERIAL | SOFTINT_MPSAFE,
audio_softintr_rd, sc);
sc->sc_sih_wr = softint_establish(SOFTINT_SERIAL | SOFTINT_MPSAFE,
@@ -672,10 +713,11 @@ bad_rec:
mutex_exit(sc->sc_lock);
/* Allocate save area. Ensure non-zero allocation. */
- sc->sc_nmixer_states = mi.index;
sc->sc_static_nmixer_states = mi.index;
+ sc->sc_static_nmixer_states++;
+ sc->sc_nmixer_states = sc->sc_static_nmixer_states;
sc->sc_mixer_state = kmem_zalloc(sizeof(mixer_ctrl_t) *
- (sc->sc_nmixer_states + (VAUDIOCHANS + 1) * 2), KM_SLEEP);
+ (sc->sc_nmixer_states + 1), KM_SLEEP);
/*
* This is where we assign each control in the "audio" model, to the
@@ -811,6 +853,15 @@ bad_rec:
&sc->sc_saturate, 0,
CTL_HW, node->sysctl_num,
CTL_CREATE, CTL_EOL);
+
+ sysctl_createv(&sc->sc_log, 0, NULL, NULL,
+ CTLFLAG_READWRITE,
+ CTLTYPE_BOOL, "multiuser",
+ SYSCTL_DESCR("allow multiple user acess"),
+ NULL, 0,
+ &sc->sc_multiuser, 0,
+ CTL_HW, node->sysctl_num,
+ CTL_CREATE, CTL_EOL);
}
selinit(&sc->sc_rsel);
@@ -869,7 +920,8 @@ int
audiodetach(device_t self, int flags)
{
struct audio_softc *sc;
- int maj, mn, i, n, rc;
+ struct audio_chan *chan;
+ int maj, mn, i, rc;
sc = device_private(self);
DPRINTF(("audio_detach: sc=%p flags=%d\n", sc, flags));
@@ -927,32 +979,38 @@ audiodetach(device_t self, int flags)
pmf_device_deregister(self);
/* free resources */
- for (n = 0; n < VAUDIOCHANS; n++) {
- if (n != 0 && sc->sc_audiopid[n].pid == -1)
+ SIMPLEQ_FOREACH(chan, &sc->sc_audiochan, entries) {
+ if (chan == NULL)
+ break;
+
+ if (chan->chan == MIXER_INUSE)
continue;
- audio_free_ring(sc, &sc->sc_vchan[n]->sc_mpr);
- audio_free_ring(sc, &sc->sc_vchan[n]->sc_mrr);
+ audio_free_ring(sc, &chan->vc->sc_mpr);
+ audio_free_ring(sc, &chan->vc->sc_mrr);
}
audio_free_ring(sc, &sc->sc_pr);
audio_free_ring(sc, &sc->sc_rr);
- for (n = 0; n < VAUDIOCHANS; n++) {
- if (n != 0 && sc->sc_audiopid[n].pid == -1)
+ SIMPLEQ_FOREACH(chan, &sc->sc_audiochan, entries) {
+ if (chan == NULL)
+ break;
+
+ if (chan->chan == MIXER_INUSE)
continue;
- for (i = 0; i < sc->sc_vchan[n]->sc_npfilters; i++) {
- sc->sc_vchan[n]->sc_pfilters[i]->dtor
- (sc->sc_vchan[n]->sc_pfilters[i]);
- sc->sc_vchan[n]->sc_pfilters[i] = NULL;
- audio_stream_dtor(&sc->sc_vchan[n]->sc_pstreams[i]);
- }
- sc->sc_vchan[n]->sc_npfilters = 0;
-
- for (i = 0; i < sc->sc_vchan[n]->sc_nrfilters; i++) {
- sc->sc_vchan[n]->sc_rfilters[i]->dtor
- (sc->sc_vchan[n]->sc_rfilters[i]);
- sc->sc_vchan[n]->sc_rfilters[i] = NULL;
- audio_stream_dtor(&sc->sc_vchan[n]->sc_rstreams[i]);
+ for (i = 0; i < chan->vc->sc_npfilters; i++) {
+ chan->vc->sc_pfilters[i]->dtor
+ (chan->vc->sc_pfilters[i]);
+ chan->vc->sc_pfilters[i] = NULL;
+ audio_stream_dtor(&chan->vc->sc_pstreams[i]);
+ }
+ chan->vc->sc_npfilters = 0;
+
+ for (i = 0; i < chan->vc->sc_nrfilters; i++) {
+ chan->vc->sc_rfilters[i]->dtor
+ (chan->vc->sc_rfilters[i]);
+ chan->vc->sc_rfilters[i] = NULL;
+ audio_stream_dtor(&chan->vc->sc_rstreams[i]);
}
- sc->sc_vchan[n]->sc_nrfilters = 0;
+ chan->vc->sc_nrfilters = 0;
}
auconv_delete_encodings(sc->sc_encodings);
@@ -966,7 +1024,12 @@ audiodetach(device_t self, int flags)
sc->sc_sih_wr = NULL;
}
- kmem_free(sc->sc_vchan[0], sizeof(struct virtual_channel));
+ chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
+ kmem_free(chan->vc, sizeof(struct virtual_channel));
+ SIMPLEQ_REMOVE(&sc->sc_audiochan, chan, audio_chan, entries);
+ kmem_free(chan, sizeof(struct audio_chan));
+ kmem_free(sc->sc_mixer_state, sizeof(mixer_ctrl_t) *
+ (sc->sc_nmixer_states + 1));
#ifdef AUDIO_PM_IDLE
callout_destroy(&sc->sc_idle_counter);
@@ -1094,29 +1157,26 @@ void audio_print_params(const char *, st
void
audio_printsc(struct audio_softc *sc)
{
- int n;
-
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (sc->sc_audiopid[n].pid == curproc->p_pid)
- break;
- }
-
- if (n == VAUDIOCHANS)
+ struct audio_chan *chan;
+
+ chan = SIMPLEQ_FIRST(sc->sc_audiochan);
+
+ if (chan == NULL)
return;
printf("hwhandle %p hw_if %p ", sc->hw_hdl, sc->hw_if);
- printf("open 0x%x mode 0x%x\n", sc->sc_vchan[n]->sc_open,
- sc->sc_vchan[n]->sc_mode);
+ printf("open 0x%x mode 0x%x\n", chan->vc->sc_open,
+ chan->vc->sc_mode);
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_vchan[n]->sc_mrr.s),
- audio_stream_get_used(&sc->sc_vchan[n]->sc_mpr.s));
- printf("rbus 0x%x pbus 0x%x ", sc->sc_vchan[n]->sc_rbus,
- sc->sc_vchan[n]->sc_pbus);
- printf("blksize %d", sc->sc_vchan[n]->sc_mpr.blksize);
- printf("hiwat %d lowat %d\n", sc->sc_vchan[n]->sc_mpr.usedhigh,
- sc->sc_vchan[n]->sc_mpr.usedlow);
+ audio_stream_get_used(&chan->vc->sc_mrr.s),
+ audio_stream_get_used(&chan->vc->sc_mpr.s));
+ printf("rbus 0x%x pbus 0x%x ", chan->vc->sc_rbus,
+ chan->vc->sc_pbus);
+ printf("blksize %d", chan->vc->sc_mpr.blksize);
+ printf("hiwat %d lowat %d\n", chan->vc->sc_mpr.usedhigh,
+ chan->vc->sc_mpr.usedlow);
}
void
@@ -1132,8 +1192,10 @@ audio_alloc_ring(struct audio_softc *sc,
int direction, size_t bufsize)
{
const struct audio_hw_if *hw;
+ struct audio_chan *chan;
void *hdl;
+ chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
hw = sc->hw_if;
hdl = sc->hw_hdl;
/*
@@ -1145,8 +1207,7 @@ audio_alloc_ring(struct audio_softc *sc,
if (hw->round_buffersize) {
bufsize = hw->round_buffersize(hdl, direction, bufsize);
}
- if (hw->allocm && (r == &sc->sc_vchan[0]->sc_mpr ||
- r == &sc->sc_vchan[0]->sc_mrr))
+ if (hw->allocm && (r == &chan->vc->sc_mpr || r == &chan->vc->sc_mrr))
r->s.start = hw->allocm(hdl, direction, bufsize);
else
r->s.start = kmem_zalloc(bufsize, KM_SLEEP);
@@ -1160,11 +1221,15 @@ audio_alloc_ring(struct audio_softc *sc,
void
audio_free_ring(struct audio_softc *sc, struct audio_ringbuffer *r)
{
+ struct audio_chan *chan;
+
if (r->s.start == NULL)
return;
- if (sc->hw_if->freem && (r == &sc->sc_vchan[0]->sc_mpr ||
- r == &sc->sc_vchan[0]->sc_mrr))
+ chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
+
+ if (sc->hw_if->freem && (r == &chan->vc->sc_mpr ||
+ r == &chan->vc->sc_mrr))
sc->hw_if->freem(sc->hw_hdl, r->s.start, r->s.bufsize);
else
kmem_free(r->s.start, r->s.bufsize);
@@ -1173,17 +1238,15 @@ audio_free_ring(struct audio_softc *sc,
static int
audio_setup_pfilters(struct audio_softc *sc, const audio_params_t *pp,
- stream_filter_list_t *pfilters, int m)
+ stream_filter_list_t *pfilters, struct virtual_channel *vc)
{
stream_filter_t *pf[AUDIO_MAX_FILTERS], *of[AUDIO_MAX_FILTERS];
audio_stream_t ps[AUDIO_MAX_FILTERS], os[AUDIO_MAX_FILTERS];
- struct virtual_channel *vc;
const audio_params_t *from_param;
audio_params_t *to_param;
int i, n, onfilters;
KASSERT(mutex_owned(sc->sc_lock));
- vc = sc->sc_vchan[m];
/* Construct new filters. */
memset(pf, 0, sizeof(pf));
@@ -1255,17 +1318,15 @@ audio_setup_pfilters(struct audio_softc
static int
audio_setup_rfilters(struct audio_softc *sc, const audio_params_t *rp,
- stream_filter_list_t *rfilters, int m)
+ stream_filter_list_t *rfilters, struct virtual_channel *vc)
{
stream_filter_t *rf[AUDIO_MAX_FILTERS], *of[AUDIO_MAX_FILTERS];
audio_stream_t rs[AUDIO_MAX_FILTERS], os[AUDIO_MAX_FILTERS];
- struct virtual_channel *vc;
const audio_params_t *to_param;
audio_params_t *from_param;
int i, onfilters;
KASSERT(mutex_owned(sc->sc_lock));
- vc = sc->sc_vchan[m];
/* Construct new filters. */
memset(rf, 0, sizeof(rf));
@@ -1470,9 +1531,32 @@ audio_waitio(struct audio_softc *sc, kco
}
int
+audiobellopen(dev_t dev, int flags, int ifmt, struct lwp *l,
+ struct file **fp)
+{
+ 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 AUDIO_DEVICE:
+ error = audio_open(dev, sc, flags, ifmt, l, fp);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ audio_exit(sc);
+
+ return error;
+}
+int
audioopen(dev_t dev, int flags, int ifmt, struct lwp *l)
{
struct audio_softc *sc;
+ struct file *fp;
int error;
if ((error = audio_enter(dev, RW_WRITER, &sc)) != 0)
@@ -1482,10 +1566,10 @@ audioopen(dev_t dev, int flags, int ifmt
case SOUND_DEVICE:
case AUDIO_DEVICE:
case AUDIOCTL_DEVICE:
- error = audio_open(dev, sc, flags, ifmt, l);
+ error = audio_open(dev, sc, flags, ifmt, l, &fp);
break;
case MIXER_DEVICE:
- error = mixer_open(dev, sc, flags, ifmt, l);
+ error = mixer_open(dev, sc, flags, ifmt, l, &fp);
break;
default:
error = ENXIO;
@@ -1497,52 +1581,65 @@ audioopen(dev_t dev, int flags, int ifmt
}
int
-audioclose(dev_t dev, int flags, int ifmt, struct lwp *l)
+audioclose(struct file *fp)
{
struct audio_softc *sc;
- int error, n;
+ struct audio_chan *chan;
+ int error;
+ dev_t dev;
+
+ chan = fp->f_audioctx;
+ if (chan == NULL) /* XXX:NS Why is this needed. */
+ return EIO;
+
+ dev = chan->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:
case AUDIOCTL_DEVICE:
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (sc->sc_audiopid[n].pid == curproc->p_pid)
- break;
- }
- if (n == VAUDIOCHANS) {
- error = EIO;
- break;
- }
- error = audio_close(sc, flags, ifmt, l, n);
+ error = audio_close(sc, fp->f_flag, chan);
break;
case MIXER_DEVICE:
- error = mixer_close(sc, flags, ifmt, l);
+ error = mixer_close(sc, fp->f_flag, chan);
break;
default:
error = ENXIO;
break;
}
+ if (error == 0) {
+ kmem_free(fp->f_audioctx, sizeof(struct audio_chan));
+ fp->f_audioctx = NULL;
+ }
+
audio_exit(sc);
return error;
}
int
-audioread(dev_t dev, struct uio *uio, int ioflag)
+audioread(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
+ int ioflag)
{
struct audio_softc *sc;
+ struct virtual_channel *vc;
int error;
+ dev_t dev;
+
+ dev = fp->f_audioctx->dev;
if ((error = audio_enter(dev, RW_READER, &sc)) != 0)
return error;
+
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
- error = audio_read(sc, uio, ioflag);
+ vc = fp->f_audioctx->vc;
+ error = audio_read(sc, uio, ioflag, vc);
break;
case AUDIOCTL_DEVICE:
case MIXER_DEVICE:
@@ -1558,17 +1655,24 @@ audioread(dev_t dev, struct uio *uio, in
}
int
-audiowrite(dev_t dev, struct uio *uio, int ioflag)
+audiowrite(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
+ int ioflag)
{
struct audio_softc *sc;
+ struct virtual_channel *vc;
int error;
+ dev_t dev;
+
+ dev = fp->f_audioctx->dev;
if ((error = audio_enter(dev, RW_READER, &sc)) != 0)
return error;
+
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
- error = audio_write(sc, uio, ioflag);
+ vc = fp->f_audioctx->vc;
+ error = audio_write(sc, uio, ioflag, vc);
break;
case AUDIOCTL_DEVICE:
case MIXER_DEVICE:
@@ -1584,11 +1688,17 @@ audiowrite(dev_t dev, struct uio *uio, i
}
int
-audioioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
+audioioctl(struct file *fp, u_long cmd, void *addr)
{
struct audio_softc *sc;
+ struct audio_chan *chan;
+ struct lwp *l = curlwp;
int error;
krw_t rw;
+ dev_t dev;
+
+ chan = fp->f_audioctx;
+ dev = chan->dev;
/* Figure out which lock type we need. */
switch (cmd) {
@@ -1605,18 +1715,21 @@ audioioctl(dev_t dev, u_long cmd, void *
if ((error = audio_enter(dev, rw, &sc)) != 0)
return error;
+ chan = fp->f_audioctx;
+
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
case AUDIOCTL_DEVICE:
device_active(sc->dev, DVA_SYSTEM);
if (IOCGROUP(cmd) == IOCGROUP(AUDIO_MIXER_READ))
- error = mixer_ioctl(sc, cmd, addr, flag, l);
+ error = mixer_ioctl(sc, cmd, addr, fp->f_flag, l);
else
- error = audio_ioctl(dev, sc, cmd, addr, flag, l);
+ error = audio_ioctl(dev, sc, cmd, addr, fp->f_flag, l,
+ chan);
break;
case MIXER_DEVICE:
- error = mixer_ioctl(sc, cmd, addr, flag, l);
+ error = mixer_ioctl(sc, cmd, addr, fp->f_flag, l);
break;
default:
error = ENXIO;
@@ -1628,10 +1741,35 @@ audioioctl(dev_t dev, u_long cmd, void *
}
int
-audiopoll(dev_t dev, int events, struct lwp *l)
+audiofcntl(struct file *fp, u_int cmd, void *data)
+{
+
+ return EOPNOTSUPP;
+}
+
+int
+audiostat(struct file *fp, struct stat *st)
+{
+ memset(st, 0, sizeof(*st));
+
+ st->st_dev = fp->f_audioctx->dev;
+
+ st->st_uid = kauth_cred_geteuid(fp->f_cred);
+ st->st_gid = kauth_cred_getegid(fp->f_cred);
+ st->st_mode = S_IFCHR;
+ return 0;
+}
+
+int
+audiopoll(struct file *fp, int events)
{
struct audio_softc *sc;
+ struct virtual_channel *vc;
+ struct lwp *l = curlwp;
int revents;
+ dev_t dev;
+
+ dev = fp->f_audioctx->dev;
/* Don't bother with device level lock here. */
sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
@@ -1642,10 +1780,12 @@ audiopoll(dev_t dev, int events, struct
mutex_exit(sc->sc_lock);
return EIO;
}
+
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
- revents = audio_poll(sc, events, l);
+ vc = fp->f_audioctx->vc;
+ revents = audio_poll(sc, events, l, vc);
break;
case AUDIOCTL_DEVICE:
case MIXER_DEVICE:
@@ -1661,10 +1801,15 @@ audiopoll(dev_t dev, int events, struct
}
int
-audiokqfilter(dev_t dev, struct knote *kn)
+audiokqfilter(struct file *fp, struct knote *kn)
{
struct audio_softc *sc;
int rv;
+ struct audio_chan *chan;
+ dev_t dev;
+
+ chan = fp->f_audioctx;
+ dev = chan->dev;
/* Don't bother with device level lock here. */
sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
@@ -1678,7 +1823,7 @@ audiokqfilter(dev_t dev, struct knote *k
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
- rv = audio_kqfilter(sc, kn);
+ rv = audio_kqfilter(chan, kn);
break;
case AUDIOCTL_DEVICE:
case MIXER_DEVICE:
@@ -1692,12 +1837,35 @@ audiokqfilter(dev_t dev, struct knote *k
return rv;
}
+/* XXX:NS mmap is disabled. */
+int
+audio_fop_mmap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp,
+ int *advicep, struct uvm_object **uobjp, int *maxprotp)
+{
+ struct audio_chan *chan;
+ struct virtual_channel *vc;
+ dev_t dev;
+
+ return -1;
+
+ chan = fp->f_audioctx;
+ dev = chan->dev;
+ vc = chan->vc;
+
+ *offp = audiommap(dev, *offp, prot, vc);
+ *maxprotp = prot;
+ *advicep = UVM_ADV_RANDOM;
+ return -1;
+}
+
paddr_t
-audiommap(dev_t dev, off_t off, int prot)
+audiommap(dev_t dev, off_t off, int prot, struct virtual_channel *vc)
{
struct audio_softc *sc;
paddr_t error;
+ return -1;
+
/*
* Acquire a reader lock. audio_mmap() will drop sc_lock
* in order to allow the device's mmap routine to sleep.
@@ -1707,10 +1875,11 @@ audiommap(dev_t dev, off_t off, int prot
if ((error = audio_enter(dev, RW_READER, &sc)) != 0)
return 1;
device_active(sc->dev, DVA_SYSTEM); /* XXXJDM */
+
switch (AUDIODEV(dev)) {
case SOUND_DEVICE:
case AUDIO_DEVICE:
- error = audio_mmap(sc, off, prot);
+ error = audio_mmap(sc, off, prot, vc);
break;
case AUDIOCTL_DEVICE:
case MIXER_DEVICE:
@@ -1765,20 +1934,24 @@ audio_init_ringbuffer(struct audio_softc
}
int
-audio_initbufs(struct audio_softc *sc, int n)
+audio_initbufs(struct audio_softc *sc, struct virtual_channel *vc)
{
const struct audio_hw_if *hw;
- struct virtual_channel *vc;
+ struct audio_chan *chan;
int error;
- DPRINTF(("audio_initbufs: mode=0x%x\n", sc->sc_vchan[n]->sc_mode));
- vc = sc->sc_vchan[0];
+ if (vc == NULL) {
+ chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
+ vc = chan->vc;
+ }
+
+ DPRINTF(("audio_initbufs: mode=0x%x\n", vc->sc_mode));
hw = sc->hw_if;
- if (audio_can_capture(sc) || (sc->sc_vchan[n]->sc_open & AUOPEN_READ)) {
- audio_init_ringbuffer(sc, &sc->sc_vchan[n]->sc_mrr,
+ if (audio_can_capture(sc) || (vc->sc_open & AUOPEN_READ)) {
+ audio_init_ringbuffer(sc, &vc->sc_mrr,
AUMODE_RECORD);
if (sc->sc_opens == 0 && hw->init_input &&
- (sc->sc_vchan[n]->sc_mode & AUMODE_RECORD)) {
+ (vc->sc_mode & AUMODE_RECORD)) {
error = hw->init_input(sc->hw_hdl, vc->sc_mrr.s.start,
vc->sc_mrr.s.end - vc->sc_mrr.s.start);
if (error)
@@ -1786,13 +1959,12 @@ audio_initbufs(struct audio_softc *sc, i
}
}
- if (audio_can_playback(sc) ||
- (sc->sc_vchan[n]->sc_open & AUOPEN_WRITE)) {
- audio_init_ringbuffer(sc, &sc->sc_vchan[n]->sc_mpr,
+ if (audio_can_playback(sc) || (vc->sc_open & AUOPEN_WRITE)) {
+ audio_init_ringbuffer(sc, &vc->sc_mpr,
AUMODE_PLAY);
- sc->sc_vchan[n]->sc_sil_count = 0;
+ vc->sc_sil_count = 0;
if (sc->sc_opens == 0 && hw->init_output &&
- (sc->sc_vchan[n]->sc_mode & AUMODE_PLAY)) {
+ (vc->sc_mode & AUMODE_PLAY)) {
error = hw->init_output(sc->hw_hdl, vc->sc_mpr.s.start,
vc->sc_mpr.s.end - vc->sc_mpr.s.start);
if (error)
@@ -1805,22 +1977,22 @@ audio_initbufs(struct audio_softc *sc, i
if (audio_can_playback(sc)) {
sc->sc_pnintr = 0;
sc->sc_pblktime = (u_long)(
- (double)sc->sc_vchan[n]->sc_mpr.blksize * 100000 /
- (double)(sc->sc_vchan[n]->sc_pparams.precision / NBBY *
- sc->sc_vchan[n].sc_pparams.channels *
- sc->sc_vchan[n].sc_pparams.sample_rate)) * 10;
+ (double)vc->sc_mpr.blksize * 100000 /
+ (double)(vc->sc_pparams.precision / NBBY *
+ vc->sc_pparams.channels *
+ vc->sc_pparams.sample_rate)) * 10;
DPRINTF(("audio: play blktime = %lu for %d\n",
- sc->sc_pblktime, sc->sc_vchan[n].sc_mpr.blksize));
+ sc->sc_pblktime, vc->sc_mpr.blksize));
}
if (audio_can_capture(sc)) {
sc->sc_rnintr = 0;
sc->sc_rblktime = (u_long)(
- (double)sc->sc_vchan[n]->sc_mrr.blksize * 100000 /
- (double)(sc->sc_vchan[n]->sc_rparams.precision / NBBY *
- sc->sc_vchan[n]->sc_rparams.channels *
- sc->sc_vchan[n]->sc_rparams.sample_rate)) * 10;
+ (double)vc->sc_mrr.blksize * 100000 /
+ (double)(vc->sc_rparams.precision / NBBY *
+ vc->sc_rparams.channels *
+ vc->sc_rparams.sample_rate)) * 10;
DPRINTF(("audio: record blktime = %lu for %d\n",
- sc->sc_rblktime, sc->sc_vchan[n]->sc_mrr.blksize));
+ sc->sc_rblktime, vc->sc_mrr.blksize));
}
#undef double
#endif
@@ -1829,10 +2001,8 @@ audio_initbufs(struct audio_softc *sc, i
}
void
-audio_calcwater(struct audio_softc *sc, int n)
+audio_calcwater(struct audio_softc *sc, struct virtual_channel *vc)
{
- struct virtual_channel *vc = sc->sc_vchan[n];
-
/* set high at 100% */
if (audio_can_playback(sc) && vc && vc->sc_pustream) {
vc->sc_mpr.usedhigh =
@@ -1856,38 +2026,30 @@ audio_calcwater(struct audio_softc *sc,
int
audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
- struct lwp *l)
+ struct lwp *l, struct file **nfp)
{
- int error, i, n;
+ struct file *fp;
+ int error, fd, i, n;
u_int mode;
const struct audio_hw_if *hw;
struct virtual_channel *vc;
+ struct audio_chan *chan;
KASSERT(mutex_owned(sc->sc_lock));
- if (sc->sc_ready == false || sc->sc_opens >= VAUDIOCHANS)
- return ENXIO;
-
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (sc->sc_audiopid[n].pid == curproc->p_pid)
- break;
- }
- if (n < VAUDIOCHANS)
- return ENXIO;
-
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (sc->sc_audiopid[n].pid == -1)
- break;
- }
- if (n == VAUDIOCHANS)
+ if (sc->sc_ready == false)
return ENXIO;
hw = sc->hw_if;
if (hw == NULL)
return ENXIO;
-
- sc->sc_vchan[n] = kmem_zalloc(sizeof(struct virtual_channel), KM_SLEEP);
- vc = sc->sc_vchan[n];
+ n = 0;
+ SIMPLEQ_FOREACH(chan, &sc->sc_audiochan, entries)
+ n++;
+
+ chan = kmem_zalloc(sizeof(struct audio_chan), KM_SLEEP);
+ vc = kmem_zalloc(sizeof(struct virtual_channel), KM_SLEEP);
+ chan->vc = vc;
vc->sc_open = 0;
vc->sc_mode = 0;
@@ -1912,6 +2074,7 @@ audio_open(dev_t dev, struct audio_softc
if (((flags & FREAD) && (vc->sc_open & AUOPEN_READ)) ||
((flags & FWRITE) && (vc->sc_open & AUOPEN_WRITE))) {
kmem_free(vc, sizeof(struct virtual_channel));
+ kmem_free(chan, sizeof(struct audio_chan));
return EBUSY;
}
@@ -1923,10 +2086,13 @@ audio_open(dev_t dev, struct audio_softc
}
if (error) {
kmem_free(vc, sizeof(struct virtual_channel));
+ kmem_free(chan, sizeof(struct audio_chan));
return error;
}
if (sc->sc_opens == 0) {
+ sc->sc_credentials = kauth_cred_get();
+ kauth_cred_hold(sc->sc_credentials);
if (hw->open != NULL) {
mutex_enter(sc->sc_intr_lock);
error = hw->open(sc->hw_hdl, flags);
@@ -1934,17 +2100,28 @@ audio_open(dev_t dev, struct audio_softc
if (error) {
kmem_free(vc,
sizeof(struct virtual_channel));
+ kmem_free(chan,
+ sizeof(struct audio_chan));
return error;
}
}
audio_init_ringbuffer(sc, &sc->sc_pr, AUMODE_PLAY);
audio_init_ringbuffer(sc, &sc->sc_rr, AUMODE_RECORD);
- audio_initbufs(sc, 0);
+ audio_initbufs(sc, NULL);
sc->schedule_wih = false;
sc->schedule_rih = false;
sc->sc_eof = 0;
vc->sc_rbus = false;
sc->sc_async_audio = 0;
+ } else if (sc->sc_multiuser == false) {
+ /* XXX:NS Should be handled correctly. */
+ /* Do we allow multi user access */
+ if (kauth_cred_geteuid(sc->sc_credentials) !=
+ kauth_cred_geteuid(kauth_cred_get()) &&
+ kauth_cred_geteuid(kauth_cred_get()) != 0) {
+ error = EPERM;
+ goto bad;
+ }
}
mutex_enter(sc->sc_intr_lock);
@@ -1963,18 +2140,18 @@ audio_open(dev_t dev, struct audio_softc
mode |= AUMODE_PLAY | AUMODE_PLAY_ALL;
}
- vc->sc_mrr.blksize = sc->sc_vchan[0]->sc_mrr.blksize;
- vc->sc_mpr.blksize = sc->sc_vchan[0]->sc_mpr.blksize;
+ vc->sc_mrr.blksize = sc->sc_rr.blksize;
+ vc->sc_mpr.blksize = sc->sc_pr.blksize;
/*
* Multiplex device: /dev/audio (MU-Law) and /dev/sound (linear)
* The /dev/audio is always (re)set to 8-bit MU-Law mono
* For the other devices, you get what they were last set to.
*/
- error = audio_set_defaults(sc, mode, n);
+ error = audio_set_defaults(sc, mode, vc);
if (!error && ISDEVSOUND(dev) && sc->sc_aivalid == true) {
sc->sc_ai.mode = mode;
- error = audiosetinfo(sc, &sc->sc_ai, true, n);
+ error = audiosetinfo(sc, &sc->sc_ai, true, vc);
}
if (error)
goto bad;
@@ -1992,7 +2169,11 @@ audio_open(dev_t dev, struct audio_softc
#endif
/* audio_close() decreases sc_mpr[n].usedlow, recalculate here */
- audio_calcwater(sc, n);
+ audio_calcwater(sc, vc);
+
+ error = fd_allocfile(&fp, &fd);
+ if (error)
+ return error;
DPRINTF(("audio_open: done sc_mode = 0x%x\n", vc->sc_mode));
@@ -2000,12 +2181,18 @@ audio_open(dev_t dev, struct audio_softc
if (flags & FREAD)
sc->sc_recopens++;
sc->sc_opens++;
- sc->sc_audiopid[n].pid = curproc->p_pid;
- sc->sc_despid[n].pid = curproc->p_pid;
- sc->sc_nmixer_states += 2;
+ chan->dev = dev;
+ chan->chan = n;
+ chan->deschan = n;
+ grow_mixer_states(sc, 2);
+ SIMPLEQ_INSERT_TAIL(&sc->sc_audiochan, chan, entries);
mutex_exit(sc->sc_intr_lock);
- return 0;
+ error = fd_clone(fp, fd, flags, &audio_fileops, chan);
+ KASSERT(error == EMOVEFD);
+
+ *nfp = fp;
+ return error;
bad:
for (i = 0; i < vc->sc_npfilters; i++) {
@@ -2026,7 +2213,8 @@ bad:
audio_free_ring(sc, &vc->sc_mpr);
audio_free_ring(sc, &vc->sc_mrr);
mutex_enter(sc->sc_lock);
- kmem_free(sc->sc_vchan[n], sizeof(struct virtual_channel));
+ kmem_free(vc, sizeof(struct virtual_channel));
+ kmem_free(chan, sizeof(struct audio_chan));
return error;
}
@@ -2034,13 +2222,11 @@ bad:
* Must be called from task context.
*/
void
-audio_init_record(struct audio_softc *sc, int n)
+audio_init_record(struct audio_softc *sc, struct virtual_channel *vc)
{
KASSERT(mutex_owned(sc->sc_lock));
-
- struct virtual_channel *vc = sc->sc_vchan[n];
-
+
if (sc->sc_opens != 0)
return;
@@ -2055,7 +2241,7 @@ audio_init_record(struct audio_softc *sc
* Must be called from task context.
*/
void
-audio_init_play(struct audio_softc *sc, int n)
+audio_init_play(struct audio_softc *sc, struct virtual_channel *vc)
{
KASSERT(mutex_owned(sc->sc_lock));
@@ -2064,37 +2250,42 @@ audio_init_play(struct audio_softc *sc,
return;
mutex_enter(sc->sc_intr_lock);
- sc->sc_vchan[n]->sc_wstamp = sc->sc_vchan[n]->sc_mpr.stamp;
+ vc->sc_wstamp = vc->sc_mpr.stamp;
if (sc->hw_if->speaker_ctl)
sc->hw_if->speaker_ctl(sc->hw_hdl, SPKR_ON);
mutex_exit(sc->sc_intr_lock);
}
int
-audio_drain(struct audio_softc *sc, int n)
+audio_drain(struct audio_softc *sc, struct audio_chan *chan)
{
struct audio_ringbuffer *cb;
+ struct virtual_channel *vc;
int error, drops;
int cc, i, used;
+ bool hw = false;
KASSERT(mutex_owned(sc->sc_lock));
KASSERT(mutex_owned(sc->sc_intr_lock));
error = 0;
+ vc = chan->vc;
DPRINTF(("audio_drain: enter busy=%d\n", sc->sc_vchan[n]->sc_pbus));
- cb = &sc->sc_vchan[n]->sc_mpr;
+ cb = &chan->vc->sc_mpr;
if (cb->mmapped)
return 0;
used = audio_stream_get_used(&cb->s);
- if (n == 0)
+ if (chan == SIMPLEQ_FIRST(&sc->sc_audiochan)) {
+ hw = true;
used += audio_stream_get_used(&sc->sc_pr.s);
- for (i = 0; i < sc->sc_vchan[n]->sc_npfilters; i++)
- used += audio_stream_get_used(&sc->sc_vchan[n]->sc_pstreams[i]);
- if (used <= 0 || (n == 0 && sc->hw_if->trigger_output == NULL))
+ }
+ for (i = 0; i < vc->sc_npfilters; i++)
+ used += audio_stream_get_used(&vc->sc_pstreams[i]);
+ if (used <= 0 || (hw == true && sc->hw_if->trigger_output == NULL))
return 0;
- if (n != 0 && !sc->sc_vchan[n]->sc_pbus) {
+ if (hw == false && !vc->sc_pbus) {
/* We've never started playing, probably because the
* block was too short. Pad it and start now.
*/
@@ -2103,11 +2294,12 @@ audio_drain(struct audio_softc *sc, int
cc = cb->blksize - (inp - cb->s.start) % cb->blksize;
audio_fill_silence(&cb->s.param, inp, cc);
cb->s.inp = audio_stream_add_inp(&cb->s, inp, cc);
- error = audiostartp(sc, n);
+ error = audiostartp(sc, vc);
if (error)
return error;
- } else if (n == 0) {
- used = cb->blksize * 2;
+ } else if (hw == true) {
+ used = cb->blksize - (sc->sc_pr.s.inp - sc->sc_pr.s.start)
+ % cb->blksize;
while (used > 0) {
cc = sc->sc_pr.s.end - sc->sc_pr.s.inp;
if (cc > used)
@@ -2131,15 +2323,13 @@ audio_drain(struct audio_softc *sc, int
cb->copying = false;
}
#endif
- sc->sc_vchan[n]->sc_draining = true;
+ vc->sc_draining = true;
- i = 0;
-drain_again:
drops = cb->drops;
error = 0;
while (cb->drops == drops && !error) {
DPRINTF(("audio_drain: n=%d, used=%d, drops=%ld\n", n,
- audio_stream_get_used(&sc->sc_vchan[n]->sc_mpr.s),
+ audio_stream_get_used(&vc->sc_mpr.s),
cb->drops));
mutex_exit(sc->sc_intr_lock);
error = audio_waitio(sc, &sc->sc_wchan);
@@ -2147,11 +2337,7 @@ drain_again:
if (sc->sc_dying)
error = EIO;
}
- i++;
- if (n == 0 && i < 2)
- goto drain_again;
-
- sc->sc_vchan[n]->sc_draining = false;
+ vc->sc_draining = false;
return error;
}
@@ -2161,8 +2347,7 @@ drain_again:
*/
/* ARGSUSED */
int
-audio_close(struct audio_softc *sc, int flags, int ifmt,
- struct lwp *l, int n)
+audio_close(struct audio_softc *sc, int flags, struct audio_chan *chan)
{
struct virtual_channel *vc;
const struct audio_hw_if *hw;
@@ -2170,10 +2355,10 @@ audio_close(struct audio_softc *sc, int
KASSERT(mutex_owned(sc->sc_lock));
- if (sc->sc_opens == 0 || n == 0)
+ if (sc->sc_opens == 0)
return ENXIO;
- vc = sc->sc_vchan[n];
+ vc = chan->vc;
hw = sc->hw_if;
if (hw == NULL)
@@ -2201,11 +2386,11 @@ audio_close(struct audio_softc *sc, int
*/
if ((flags & FWRITE) && vc->sc_pbus) {
if (!vc->sc_mpr.pause)
- audio_drain(sc, n);
+ audio_drain(sc, chan);
vc->sc_pbus = false;
}
if (sc->sc_opens == 1) {
- audio_drain(sc, 0);
+ audio_drain(sc, SIMPLEQ_FIRST(&sc->sc_audiochan));
if (hw->drain)
(void)hw->drain(sc->hw_hdl);
hw->halt_output(sc->hw_hdl);
@@ -2216,8 +2401,10 @@ audio_close(struct audio_softc *sc, int
if (sc->sc_opens == 1 && hw->close != NULL)
hw->close(sc->hw_hdl);
- if (sc->sc_opens == 1)
+ if (sc->sc_opens == 1) {
sc->sc_async_audio = 0;
+ kauth_cred_free(sc->sc_credentials);
+ }
vc->sc_open = 0;
vc->sc_mode = 0;
@@ -2239,40 +2426,31 @@ audio_close(struct audio_softc *sc, int
if (flags & FREAD)
sc->sc_recopens--;
sc->sc_opens--;
- sc->sc_nmixer_states -= 2;
- sc->sc_audiopid[n].pid = -1;
- sc->sc_despid[n].pid = -1;
+ shrink_mixer_states(sc, 2);
+ SIMPLEQ_REMOVE(&sc->sc_audiochan, chan, audio_chan, entries);
mutex_exit(sc->sc_intr_lock);
mutex_exit(sc->sc_lock);
audio_free_ring(sc, &vc->sc_mpr);
audio_free_ring(sc, &vc->sc_mrr);
mutex_enter(sc->sc_lock);
- kmem_free(sc->sc_vchan[n], sizeof(struct virtual_channel));
+ kmem_free(vc, sizeof(struct virtual_channel));
return 0;
}
int
-audio_read(struct audio_softc *sc, struct uio *uio, int ioflag)
+audio_read(struct audio_softc *sc, struct uio *uio, int ioflag,
+ struct virtual_channel *vc)
{
struct audio_ringbuffer *cb;
- struct virtual_channel *vc;
const uint8_t *outp;
uint8_t *inp;
- int error, used, cc, n, m;
+ int error, used, cc, n;
KASSERT(mutex_owned(sc->sc_lock));
- for (m = 1; m < VAUDIOCHANS; m++) {
- if (sc->sc_audiopid[m].pid == curproc->p_pid)
- break;
- }
- if (m == VAUDIOCHANS)
- return EINVAL;
-
if (sc->hw_if == NULL)
return ENXIO;
- vc = sc->sc_vchan[m];
cb = &vc->sc_mrr;
if (cb->mmapped)
@@ -2326,7 +2504,7 @@ audio_read(struct audio_softc *sc, struc
while (uio->uio_resid > 0 && !error) {
while ((used = audio_stream_get_used(vc->sc_rustream)) <= 0) {
if (!vc->sc_rbus && !vc->sc_mrr.pause)
- error = audiostartr(sc, m);
+ error = audiostartr(sc, vc);
mutex_exit(sc->sc_intr_lock);
if (error)
return error;
@@ -2370,11 +2548,9 @@ audio_read(struct audio_softc *sc, struc
}
void
-audio_clear(struct audio_softc *sc, int n)
+audio_clear(struct audio_softc *sc, struct virtual_channel *vc)
{
- struct virtual_channel *vc = sc->sc_vchan[n];
-
KASSERT(mutex_owned(sc->sc_intr_lock));
if (vc->sc_rbus) {
@@ -2394,28 +2570,29 @@ audio_clear(struct audio_softc *sc, int
}
void
-audio_clear_intr_unlocked(struct audio_softc *sc, int n)
+audio_clear_intr_unlocked(struct audio_softc *sc, struct virtual_channel *vc)
{
mutex_enter(sc->sc_intr_lock);
- audio_clear(sc, n);
+ audio_clear(sc, vc);
mutex_exit(sc->sc_intr_lock);
}
void
-audio_calc_blksize(struct audio_softc *sc, int mode, int n)
+audio_calc_blksize(struct audio_softc *sc, int mode,
+ struct virtual_channel *vc)
{
const audio_params_t *parm;
struct audio_ringbuffer *rb;
- if (sc->sc_vchan[n]->sc_blkset)
+ if (vc->sc_blkset)
return;
if (mode == AUMODE_PLAY) {
- rb = &sc->sc_vchan[n]->sc_mpr;
+ rb = &vc->sc_mpr;
parm = &rb->s.param;
} else {
- rb = &sc->sc_vchan[n]->sc_mrr;
+ rb = &vc->sc_mrr;
parm = &rb->s.param;
}
@@ -2493,12 +2670,14 @@ audio_fill_silence(struct audio_params *
int
audio_silence_copyout(struct audio_softc *sc, int n, struct uio *uio)
{
+ struct audio_chan *chan;
struct virtual_channel *vc;
uint8_t zerobuf[128];
int error;
int k;
- vc = sc->sc_vchan[0];
+ chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
+ vc = chan->vc;
audio_fill_silence(&vc->sc_rparams, zerobuf, sizeof zerobuf);
error = 0;
@@ -2583,30 +2762,22 @@ uio_fetcher_ctor(uio_fetcher_t *this, st
}
int
-audio_write(struct audio_softc *sc, struct uio *uio, int ioflag)
+audio_write(struct audio_softc *sc, struct uio *uio, int ioflag,
+ struct virtual_channel *vc)
{
uio_fetcher_t ufetcher;
audio_stream_t stream;
struct audio_ringbuffer *cb;
- struct virtual_channel *vc;
stream_fetcher_t *fetcher;
stream_filter_t *filter;
uint8_t *inp, *einp;
- int saveerror, error, n, m, cc, used;
+ int saveerror, error, m, cc, used;
KASSERT(mutex_owned(sc->sc_lock));
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (sc->sc_audiopid[n].pid == curproc->p_pid)
- break;
- }
- if (n == VAUDIOCHANS)
- return EINVAL;
-
if (sc->hw_if == NULL)
return ENXIO;
- vc = sc->sc_vchan[n];
cb = &vc->sc_mpr;
DPRINTFN(2,("audio_write: sc=%p count=%zu used=%d(hi=%d)\n",
@@ -2732,7 +2903,7 @@ audio_write(struct audio_softc *sc, stru
cb->copying = false;
if (!vc->sc_pbus && !cb->pause) {
saveerror = error;
- error = audiostartp(sc, n);
+ error = audiostartp(sc, vc);
if (saveerror != 0) {
/* Report the first error that occurred. */
error = saveerror;
@@ -2750,31 +2921,26 @@ audio_write(struct audio_softc *sc, stru
int
audio_ioctl(dev_t dev, struct audio_softc *sc, u_long cmd, void *addr, int flag,
- struct lwp *l)
+ struct lwp *l, struct audio_chan *chan)
{
const struct audio_hw_if *hw;
+ struct audio_chan *pchan;
struct virtual_channel *vc;
struct audio_offset *ao;
u_long stamp;
- int error, offs, fd, m, n;
+ int error, offs, fd;
bool rbus, pbus;
KASSERT(mutex_owned(sc->sc_lock));
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (sc->sc_audiopid[n].pid == curproc->p_pid)
+
+ SIMPLEQ_FOREACH(pchan, &sc->sc_audiochan, entries) {
+ if (pchan->chan == chan->deschan)
break;
}
- m = n;
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (sc->sc_despid[m].pid >= 0 && sc->sc_audiopid[n].pid ==
- sc->sc_despid[m].pid)
- break;
- }
-
- if (m >= VAUDIOCHANS || n >= VAUDIOCHANS)
+ if (pchan == NULL)
return ENXIO;
- vc = sc->sc_vchan[n];
+ vc = pchan->vc;
DPRINTF(("audio_ioctl(%lu,'%c',%lu)\n",
IOCPARM_LEN(cmd), (char)IOCGROUP(cmd), cmd&0xff));
@@ -2784,8 +2950,8 @@ audio_ioctl(dev_t dev, struct audio_soft
error = 0;
switch (cmd) {
case AUDIO_SETPROC:
- if ((struct audio_pid *)addr != NULL)
- sc->sc_despid[m] = *(struct audio_pid *)addr;
+ if ((int *)addr != NULL && *(int*)addr > 0)
+ chan->deschan = *(int*)addr;
break;
case FIONBIO:
/* All handled in the upper FS layer. */
@@ -2800,9 +2966,9 @@ audio_ioctl(dev_t dev, struct audio_soft
if (sc->sc_async_audio != 0)
error = EBUSY;
else
- sc->sc_async_audio = sc->sc_audiopid[n].pid;
- DPRINTF(("audio_ioctl: FIOASYNC pid %d\n",
- sc->sc_audiopid[n].pid));
+ sc->sc_async_audio = pchan->chan;
+ DPRINTF(("audio_ioctl: FIOASYNC chan %d\n",
+ sc->sc_audiochan[n].chan));
} else
sc->sc_async_audio = 0;
break;
@@ -2812,17 +2978,17 @@ audio_ioctl(dev_t dev, struct audio_soft
rbus = vc->sc_rbus;
pbus = vc->sc_pbus;
mutex_enter(sc->sc_intr_lock);
- audio_clear(sc, n);
- error = audio_initbufs(sc, n);
+ audio_clear(sc, vc);
+ error = audio_initbufs(sc, vc);
if (error) {
mutex_exit(sc->sc_intr_lock);
return error;
}
if ((vc->sc_mode & AUMODE_PLAY) && !vc->sc_pbus && pbus)
- error = audiostartp(sc, n);
+ error = audiostartp(sc, vc);
if (!error &&
(vc->sc_mode & AUMODE_RECORD) && !vc->sc_rbus && rbus)
- error = audiostartr(sc, n);
+ error = audiostartr(sc, vc);
mutex_exit(sc->sc_intr_lock);
break;
@@ -2886,27 +3052,27 @@ audio_ioctl(dev_t dev, struct audio_soft
case AUDIO_SETINFO:
DPRINTF(("AUDIO_SETINFO mode=0x%x\n", vc->sc_mode));
- error = audiosetinfo(sc, (struct audio_info *)addr, false, n);
+ error = audiosetinfo(sc, (struct audio_info *)addr, false, vc);
if (!error && ISDEVSOUND(dev)) {
- error = audiogetinfo(sc, &sc->sc_ai, 0, n);
+ error = audiogetinfo(sc, &sc->sc_ai, 0, vc);
sc->sc_aivalid = true;
}
break;
case AUDIO_GETINFO:
DPRINTF(("AUDIO_GETINFO\n"));
- error = audiogetinfo(sc, (struct audio_info *)addr, 0, n);
+ error = audiogetinfo(sc, (struct audio_info *)addr, 0, vc);
break;
case AUDIO_GETBUFINFO:
DPRINTF(("AUDIO_GETBUFINFO\n"));
- error = audiogetinfo(sc, (struct audio_info *)addr, 1, n);
+ error = audiogetinfo(sc, (struct audio_info *)addr, 1, vc);
break;
case AUDIO_DRAIN:
DPRINTF(("AUDIO_DRAIN\n"));
mutex_enter(sc->sc_intr_lock);
- error = audio_drain(sc, n);
+ error = audio_drain(sc, pchan);
if (!error && sc->sc_opens == 1 && hw->drain)
error = hw->drain(sc->hw_hdl);
mutex_exit(sc->sc_intr_lock);
@@ -2966,20 +3132,13 @@ audio_ioctl(dev_t dev, struct audio_soft
}
int
-audio_poll(struct audio_softc *sc, int events, struct lwp *l)
+audio_poll(struct audio_softc *sc, int events, struct lwp *l,
+ struct virtual_channel *vc)
{
- struct virtual_channel *vc;
int revents;
- int used, n;
+ int used;
KASSERT(mutex_owned(sc->sc_lock));
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (sc->sc_audiopid[n].pid == curproc->p_pid)
- break;
- }
- if (n == VAUDIOCHANS)
- return ENXIO;
- vc = sc->sc_vchan[n];
DPRINTF(("audio_poll: events=0x%x mode=%d\n", events, vc->sc_mode));
@@ -3028,8 +3187,16 @@ static void
filt_audiordetach(struct knote *kn)
{
struct audio_softc *sc;
+ struct audio_chan *chan;
+ dev_t dev;
+
+ chan = kn->kn_hook;
+ dev = chan->dev;
+ sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
+ if (sc == NULL)
+ return;
+
- sc = kn->kn_hook;
mutex_enter(sc->sc_intr_lock);
SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
mutex_exit(sc->sc_intr_lock);
@@ -3039,18 +3206,17 @@ static int
filt_audioread(struct knote *kn, long hint)
{
struct audio_softc *sc;
+ struct audio_chan *chan;
struct virtual_channel *vc;
- int n;
+ dev_t dev;
- sc = kn->kn_hook;
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (sc->sc_audiopid[n].pid == curproc->p_pid)
- break;
- }
- if (n == VAUDIOCHANS)
+ chan = kn->kn_hook;
+ dev = chan->dev;
+ sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
+ if (sc == NULL)
return ENXIO;
- vc = sc->sc_vchan[n];
+ vc = chan->vc;
mutex_enter(sc->sc_intr_lock);
if (!vc->sc_full_duplex && (vc->sc_mode & AUMODE_PLAY))
kn->kn_data = vc->sc_mpr.stamp - vc->sc_wstamp;
@@ -3069,8 +3235,15 @@ static void
filt_audiowdetach(struct knote *kn)
{
struct audio_softc *sc;
+ struct audio_chan *chan;
+ dev_t dev;
+
+ chan = kn->kn_hook;
+ dev = chan->dev;
+ sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
+ if (sc == NULL)
+ return;
- sc = kn->kn_hook;
mutex_enter(sc->sc_intr_lock);
SLIST_REMOVE(&sc->sc_wsel.sel_klist, kn, knote, kn_selnext);
mutex_exit(sc->sc_intr_lock);
@@ -3080,19 +3253,19 @@ static int
filt_audiowrite(struct knote *kn, long hint)
{
struct audio_softc *sc;
+ struct audio_chan *chan;
audio_stream_t *stream;
- int n;
+ dev_t dev;
- sc = kn->kn_hook;
- mutex_enter(sc->sc_intr_lock);
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (sc->sc_audiopid[n].pid == curproc->p_pid)
- break;
- }
- if (n == VAUDIOCHANS)
+ chan = kn->kn_hook;
+ dev = chan->dev;
+ sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
+ if (sc == NULL)
return ENXIO;
- stream = sc->sc_vchan[n]->sc_pustream;
+ mutex_enter(sc->sc_intr_lock);
+
+ stream = chan->vc->sc_pustream;
kn->kn_data = (stream->end - stream->start)
- audio_stream_get_used(stream);
mutex_exit(sc->sc_intr_lock);
@@ -3104,9 +3277,17 @@ static const struct filterops audiowrite
{ 1, NULL, filt_audiowdetach, filt_audiowrite };
int
-audio_kqfilter(struct audio_softc *sc, struct knote *kn)
+audio_kqfilter(struct audio_chan *chan, struct knote *kn)
{
+ struct audio_softc *sc;
struct klist *klist;
+ dev_t dev;
+
+ dev = chan->dev;
+
+ sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev));
+ if (sc == NULL)
+ return ENXIO;
switch (kn->kn_filter) {
case EVFILT_READ:
@@ -3123,7 +3304,7 @@ audio_kqfilter(struct audio_softc *sc, s
return EINVAL;
}
- kn->kn_hook = sc;
+ kn->kn_hook = chan;
mutex_enter(sc->sc_intr_lock);
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
@@ -3132,28 +3313,20 @@ audio_kqfilter(struct audio_softc *sc, s
return 0;
}
+/* XXX:NS mmap to be fixed. */
paddr_t
-audio_mmap(struct audio_softc *sc, off_t off, int prot)
+audio_mmap(struct audio_softc *sc, off_t off, int prot,
+ struct virtual_channel *vc)
{
struct audio_ringbuffer *cb;
- struct virtual_channel *vc;
paddr_t rv;
- int n;
KASSERT(mutex_owned(sc->sc_lock));
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (sc->sc_audiopid[n].pid == curproc->p_pid)
- break;
- }
- if (n == VAUDIOCHANS)
- return -1;
-
if (sc->hw_if == NULL)
return ENXIO;
DPRINTF(("audio_mmap: off=%lld, prot=%d\n", (long long)off, prot));
- vc = sc->sc_vchan[n];
if (!(audio_get_props(sc) & AUDIO_PROP_MMAP))
return -1;
#if 0
@@ -3171,13 +3344,13 @@ audio_mmap(struct audio_softc *sc, off_t
*/
if (prot == (VM_PROT_READ|VM_PROT_WRITE) ||
prot == VM_PROT_WRITE)
- cb = &sc->sc_vchan[n]->sc_mpr;
+ cb = &vc->sc_mpr;
else if (prot == VM_PROT_READ)
- cb = &sc->sc_vchan[n]->sc_mrr;
+ cb = &vc->sc_mrr;
else
return -1;
#else
- cb = &sc->sc_vchan[n]->sc_mpr;
+ cb = &vc->sc_mpr;
#endif
if ((u_int)off >= cb->s.bufsize)
@@ -3190,13 +3363,13 @@ audio_mmap(struct audio_softc *sc, off_t
mutex_enter(sc->sc_intr_lock);
vc->sc_pustream = &cb->s;
if (!vc->sc_pbus && !vc->sc_mpr.pause)
- (void)audiostartp(sc, n);
+ (void)audiostartp(sc, vc);
mutex_exit(sc->sc_intr_lock);
} else {
mutex_enter(sc->sc_intr_lock);
vc->sc_rustream = &cb->s;
if (!vc->sc_rbus && !sc->sc_rr.pause)
- (void)audiostartr(sc, n);
+ (void)audiostartr(sc, vc);
mutex_exit(sc->sc_intr_lock);
}
}
@@ -3207,14 +3380,12 @@ audio_mmap(struct audio_softc *sc, off_t
}
int
-audiostartr(struct audio_softc *sc, int n)
+audiostartr(struct audio_softc *sc, struct virtual_channel *vc)
{
- struct virtual_channel *vc;
KASSERT(mutex_owned(sc->sc_lock));
KASSERT(mutex_owned(sc->sc_intr_lock));
- vc = sc->sc_vchan[n];
DPRINTF(("audiostartr: start=%p used=%d(hi=%d) mmapped=%d\n",
vc->sc_mrr.s.start, audio_stream_get_used(&vc->sc_mrr.s),
vc->sc_mrr.usedhigh, vc->sc_mrr.mmapped));
@@ -3232,14 +3403,15 @@ audiostartr(struct audio_softc *sc, int
}
int
-audiostartp(struct audio_softc *sc, int n)
+audiostartp(struct audio_softc *sc, struct virtual_channel *vc)
{
- struct virtual_channel *vc = sc->sc_vchan[n];
+ struct audio_chan *chan;
int error, used;
KASSERT(mutex_owned(sc->sc_lock));
KASSERT(mutex_owned(sc->sc_intr_lock));
+ chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
error = 0;
used = audio_stream_get_used(&vc->sc_mpr.s);
DPRINTF(("audiostartp: start=%p used=%d(hi=%d blk=%d) mmapped=%d\n",
@@ -3260,7 +3432,7 @@ audiostartp(struct audio_softc *sc, int
audio_mix(sc);
mix_write(sc);
- vc = sc->sc_vchan[0];
+ vc = chan->vc;
vc->sc_mpr.s.outp =
audio_stream_add_outp(&vc->sc_mpr.s,
vc->sc_mpr.s.outp, vc->sc_mpr.blksize);
@@ -3289,9 +3461,8 @@ audiostartp(struct audio_softc *sc, int
*/
static inline void
audio_pint_silence(struct audio_softc *sc, struct audio_ringbuffer *cb,
- uint8_t *inp, int cc, int n)
+ uint8_t *inp, int cc, struct virtual_channel *vc)
{
- struct virtual_channel *vc = sc->sc_vchan[n];
uint8_t *s, *e, *p, *q;
KASSERT(mutex_owned(sc->sc_lock));
@@ -3377,28 +3548,26 @@ void
audio_pint(void *v)
{
struct audio_softc *sc;
+ struct audio_chan *chan;
struct virtual_channel *vc;
- int blksize, i, used;
+ int blksize;
sc = v;
- vc = sc->sc_vchan[0];
+ chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
+ vc = chan->vc;
blksize = vc->sc_mpr.blksize;
if (sc->sc_dying == true)
return;
- used = audio_stream_get_used(&vc->sc_mpr.s);
- for (i = 0; i < vc->sc_npfilters; i++)
- used += audio_stream_get_used(&vc->sc_pstreams[i]);
-
- if (audio_stream_get_used(&sc->sc_pr.s) <blksize)
- goto wake_mix;
-
- if (vc->sc_draining == true && used <= 0) {
+ if (vc->sc_draining == true) {
vc->sc_mpr.drops += blksize;
cv_broadcast(&sc->sc_wchan);
}
+ if (audio_stream_get_used(&sc->sc_pr.s) < blksize)
+ goto wake_mix;
+
vc->sc_mpr.s.outp = audio_stream_add_outp(&vc->sc_mpr.s,
vc->sc_mpr.s.outp, blksize);
@@ -3413,13 +3582,12 @@ audio_mix(void *v)
{
stream_fetcher_t null_fetcher;
struct audio_softc *sc;
+ struct audio_chan *chan;
struct virtual_channel *vc;
struct audio_ringbuffer *cb;
stream_fetcher_t *fetcher;
uint8_t *inp;
- int cc, used;
- int blksize;
- int n, i;
+ int cc, used, blksize;
sc = v;
@@ -3431,16 +3599,22 @@ audio_mix(void *v)
if (sc->sc_dying == true)
return;
- i = sc->sc_opens;
- blksize = sc->sc_vchan[0]->sc_mpr.blksize;
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (!sc->sc_opens || i <= 0)
+ blksize = sc->sc_pr.blksize;
+ SIMPLEQ_FOREACH(chan, &sc->sc_audiochan, entries) {
+ if (!sc->sc_opens)
break; /* ignore interrupt if not open */
- if (sc->sc_audiopid[n].pid == -1)
+ if (chan == NULL)
+ break;
+
+ if (chan == SIMPLEQ_FIRST(&sc->sc_audiochan))
+ continue;
+
+ if (chan->chan == MIXER_INUSE)
continue;
- i--;
- vc = sc->sc_vchan[n];
+
+ vc = chan->vc;
+
if (!vc->sc_open)
continue;
if (!vc->sc_pbus)
@@ -3455,7 +3629,7 @@ audio_mix(void *v)
if (cb->mmapped) {
DPRINTF(("audio_pint: mmapped outp=%p cc=%d inp=%p\n",
cb->s.outp, blksize, cb->s.inp));
- mix_func(sc, cb, n);
+ mix_func(sc, cb, vc);
continue;
}
@@ -3532,7 +3706,7 @@ audio_mix(void *v)
vc->sc_playdrop += cc;
}
- audio_pint_silence(sc, cb, inp, cc, n);
+ audio_pint_silence(sc, cb, inp, cc, vc);
cb->s.inp = audio_stream_add_inp(&cb->s, inp,
cc);
@@ -3540,14 +3714,14 @@ audio_mix(void *v)
used = audio_stream_get_used(&cb->s);
if (used + blksize < cb->s.end - cb->s.start) {
audio_pint_silence(sc, cb, cb->s.inp,
- blksize, n);
+ blksize, vc);
}
}
}
DPRINTFN(5, ("audio_pint: outp=%p cc=%d\n", cb->s.outp,
blksize));
- mix_func(sc, cb, n);
+ mix_func(sc, cb, vc);
cb->s.outp = audio_stream_add_outp(&cb->s, cb->s.outp, blksize);
DPRINTFN(2, ("audio_pint: mode=%d pause=%d used=%d lowat=%d\n",
@@ -3576,12 +3750,6 @@ audio_mix(void *v)
if (sc->schedule_rih == true)
softint_schedule(sc->sc_sih_rd);
kpreempt_enable();
-
- cc = sc->sc_vchan[0]->sc_mpr.blksize;
- if (sc->sc_writeme == false) {
- sc->sc_vchan[0]->sc_mpr.drops += cc;
- cv_broadcast(&sc->sc_wchan);
- }
}
/*
@@ -3613,28 +3781,30 @@ audio_upmix(void *v)
{
stream_fetcher_t null_fetcher;
struct audio_softc *sc;
+ struct audio_chan *chan;
struct audio_ringbuffer *cb;
stream_fetcher_t *last_fetcher;
struct virtual_channel *vc;
- int cc;
- int used;
- int blksize;
- int i;
- int n;
- int cc1;
+ int cc, used, blksize, cc1;
sc = v;
- i = sc->sc_opens;
- blksize = sc->sc_vchan[0]->sc_mrr.blksize;
+ blksize = sc->sc_rr.blksize;
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (!sc->sc_opens || i <= 0)
+ SIMPLEQ_FOREACH(chan, &sc->sc_audiochan, entries) {
+ if (!sc->sc_opens)
break; /* ignore interrupt if not open */
- if (sc->sc_audiopid[n].pid == -1)
+ if (chan == NULL)
+ break;
+
+ if (chan == SIMPLEQ_FIRST(&sc->sc_audiochan))
+ continue;
+
+ if (chan->chan == MIXER_INUSE)
continue;
- i--;
- vc = sc->sc_vchan[n];
+
+ vc = chan->vc;
+
if (!(vc->sc_open & AUOPEN_READ))
continue;
if (!vc->sc_rbus)
@@ -3661,7 +3831,7 @@ audio_upmix(void *v)
}
cc = blksize;
- recswvol_func(sc, cb, n, blksize);
+ recswvol_func(sc, cb, blksize, vc);
cb->s.inp = audio_stream_add_inp(&cb->s, cb->s.inp, blksize);
cb->stamp += blksize;
@@ -3815,14 +3985,20 @@ audio_check_params(struct audio_params *
static int
audio_set_vchan_defaults(struct audio_softc *sc, u_int mode,
- const struct audio_format *format, int n)
+ const struct audio_format *format)
{
- struct virtual_channel *vc = sc->sc_vchan[n];
+ struct audio_chan *chan;
+ struct virtual_channel *vc;
struct audio_info ai;
int error;
KASSERT(mutex_owned(sc->sc_lock));
+ chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
+ if (chan == NULL)
+ return EINVAL;
+ vc = chan->vc;
+
sc->sc_vchan_params.sample_rate = sc->sc_iffreq;
#if BYTE_ORDER == LITTLE_ENDIAN
sc->sc_vchan_params.encoding = AUDIO_ENCODING_SLINEAR_LE;
@@ -3861,15 +4037,18 @@ audio_set_vchan_defaults(struct audio_so
&sc->sc_encodings);
if (error == 0)
- error = audiosetinfo(sc, &ai, true, n);
+ error = audiosetinfo(sc, &ai, true, vc);
+
+ sc->sc_pr.blksize = vc->sc_mpr.blksize;
+ sc->sc_rr.blksize = vc->sc_mrr.blksize;
return error;
}
int
-audio_set_defaults(struct audio_softc *sc, u_int mode, int n)
+audio_set_defaults(struct audio_softc *sc, u_int mode,
+ struct virtual_channel *vc)
{
- struct virtual_channel *vc = sc->sc_vchan[n];
struct audio_info ai;
KASSERT(mutex_owned(sc->sc_lock));
@@ -3892,7 +4071,7 @@ audio_set_defaults(struct audio_softc *s
ai.play.pause = false;
ai.mode = mode;
- return audiosetinfo(sc, &ai, true, n);
+ return audiosetinfo(sc, &ai, true, vc);
}
int
@@ -4190,13 +4369,13 @@ au_get_port(struct audio_softc *sc, stru
}
int
-audiosetinfo(struct audio_softc *sc, struct audio_info *ai, bool reset, int n)
+audiosetinfo(struct audio_softc *sc, struct audio_info *ai, bool reset,
+ struct virtual_channel *vc)
{
stream_filter_list_t pfilters, rfilters;
audio_params_t pp, rp;
struct audio_prinfo *r, *p;
const struct audio_hw_if *hw;
- struct virtual_channel *vc;
audio_stream_t *oldpus, *oldrus;
int setmode;
int error;
@@ -4210,7 +4389,6 @@ audiosetinfo(struct audio_softc *sc, str
KASSERT(mutex_owned(sc->sc_lock));
- vc = sc->sc_vchan[n];
hw = sc->hw_if;
if (hw == NULL) /* HW has not attached */
return ENXIO;
@@ -4288,7 +4466,7 @@ audiosetinfo(struct audio_softc *sc, str
setmode = 0;
if (nr > 0) {
if (!cleared) {
- audio_clear_intr_unlocked(sc, n);
+ audio_clear_intr_unlocked(sc, vc);
cleared = true;
}
modechange = true;
@@ -4296,7 +4474,7 @@ audiosetinfo(struct audio_softc *sc, str
}
if (np > 0) {
if (!cleared) {
- audio_clear_intr_unlocked(sc, n);
+ audio_clear_intr_unlocked(sc, vc);
cleared = true;
}
modechange = true;
@@ -4305,7 +4483,7 @@ audiosetinfo(struct audio_softc *sc, str
if (SPECIFIED(ai->mode)) {
if (!cleared) {
- audio_clear_intr_unlocked(sc, n);
+ audio_clear_intr_unlocked(sc, vc);
cleared = true;
}
modechange = true;
@@ -4341,7 +4519,7 @@ audiosetinfo(struct audio_softc *sc, str
* no channels/sample_rate. */
error = audio_set_params(sc, setmode,
vc->sc_mode & (AUMODE_PLAY | AUMODE_RECORD), &pp, &rp,
- &pfilters, &rfilters, n);
+ &pfilters, &rfilters, vc);
if (error) {
DPRINTF(("%s: audio_set_params() failed with %d\n",
__func__, error));
@@ -4369,12 +4547,12 @@ audiosetinfo(struct audio_softc *sc, str
/* construct new filter chain */
if (setmode & AUMODE_PLAY) {
- error = audio_setup_pfilters(sc, &pp, &pfilters, n);
+ error = audio_setup_pfilters(sc, &pp, &pfilters, vc);
if (error)
goto cleanup;
}
if (setmode & AUMODE_RECORD) {
- error = audio_setup_rfilters(sc, &rp, &rfilters, n);
+ error = audio_setup_rfilters(sc, &rp, &rfilters, vc);
if (error)
goto cleanup;
}
@@ -4388,8 +4566,8 @@ audiosetinfo(struct audio_softc *sc, str
/* Play params can affect the record params, so recalculate blksize. */
if (nr > 0 || np > 0 || reset) {
vc->sc_blkset = false;
- audio_calc_blksize(sc, AUMODE_RECORD, n);
- audio_calc_blksize(sc, AUMODE_PLAY, n);
+ audio_calc_blksize(sc, AUMODE_RECORD, vc);
+ audio_calc_blksize(sc, AUMODE_PLAY, vc);
}
#ifdef AUDIO_DEBUG
if (audiodebug > 1 && nr > 0) {
@@ -4404,7 +4582,7 @@ audiosetinfo(struct audio_softc *sc, str
if (SPECIFIED(p->port)) {
if (!cleared) {
- audio_clear_intr_unlocked(sc, n);
+ audio_clear_intr_unlocked(sc, vc);
cleared = true;
}
error = au_set_port(sc, &sc->sc_outports, p->port);
@@ -4413,7 +4591,7 @@ audiosetinfo(struct audio_softc *sc, str
}
if (SPECIFIED(r->port)) {
if (!cleared) {
- audio_clear_intr_unlocked(sc, n);
+ audio_clear_intr_unlocked(sc, vc);
cleared = true;
}
error = au_set_port(sc, &sc->sc_inports, r->port);
@@ -4475,18 +4653,18 @@ audiosetinfo(struct audio_softc *sc, str
/* Block size specified explicitly. */
if (ai->blocksize == 0) {
if (!cleared) {
- audio_clear_intr_unlocked(sc, n);
+ audio_clear_intr_unlocked(sc, vc);
cleared = true;
}
vc->sc_blkset = false;
- audio_calc_blksize(sc, AUMODE_RECORD, n);
- audio_calc_blksize(sc, AUMODE_PLAY, n);
+ audio_calc_blksize(sc, AUMODE_RECORD, vc);
+ audio_calc_blksize(sc, AUMODE_PLAY, vc);
} else {
vc->sc_blkset = true;
/* check whether new blocksize changes actually */
if (hw->round_blocksize == NULL) {
if (!cleared) {
- audio_clear_intr_unlocked(sc, n);
+ audio_clear_intr_unlocked(sc, vc);
cleared = true;
}
vc->sc_mpr.blksize = ai->blocksize;
@@ -4499,12 +4677,11 @@ audiosetinfo(struct audio_softc *sc, str
ai->blocksize, AUMODE_RECORD,
&vc->sc_mrr.s.param);
if ((pblksize != vc->sc_mpr.blksize &&
- pblksize > sc->sc_vchan[0]->sc_mpr.blksize)
+ pblksize > sc->sc_pr.blksize)
|| (rblksize != vc->sc_mrr.blksize &&
- rblksize >
- sc->sc_vchan[0]->sc_mrr.blksize)) {
+ rblksize > sc->sc_rr.blksize)) {
if (!cleared) {
- audio_clear_intr_unlocked(sc, n);
+ audio_clear_intr_unlocked(sc, vc);
cleared = true;
}
vc->sc_mpr.blksize = pblksize;
@@ -4516,9 +4693,9 @@ audiosetinfo(struct audio_softc *sc, str
if (SPECIFIED(ai->mode)) {
if (vc->sc_mode & AUMODE_PLAY)
- audio_init_play(sc, n);
+ audio_init_play(sc, vc);
if (vc->sc_mode & AUMODE_RECORD)
- audio_init_record(sc, n);
+ audio_init_record(sc, vc);
}
if (hw->commit_settings && sc->sc_opens == 0) {
@@ -4536,20 +4713,20 @@ cleanup:
mutex_enter(sc->sc_intr_lock);
init_error = (pausechange == 1 && reset == 0) ? 0 :
- audio_initbufs(sc, n);
+ audio_initbufs(sc, vc);
if (init_error) goto err;
if (vc->sc_mpr.blksize != oldpblksize ||
vc->sc_mrr.blksize != oldrblksize ||
vc->sc_pustream != oldpus ||
vc->sc_rustream != oldrus)
- audio_calcwater(sc, n);
+ audio_calcwater(sc, vc);
if ((vc->sc_mode & AUMODE_PLAY) &&
pbus && !vc->sc_pbus)
- init_error = audiostartp(sc, n);
+ init_error = audiostartp(sc, vc);
if (!init_error &&
(vc->sc_mode & AUMODE_RECORD) &&
rbus && !vc->sc_rbus)
- init_error = audiostartr(sc, n);
+ init_error = audiostartr(sc, vc);
err:
mutex_exit(sc->sc_intr_lock);
if (init_error)
@@ -4584,17 +4761,15 @@ cleanup:
int
audiogetinfo(struct audio_softc *sc, struct audio_info *ai, int buf_only_mode,
- int n)
+ struct virtual_channel *vc)
{
struct audio_prinfo *r, *p;
const struct audio_hw_if *hw;
- struct virtual_channel *vc;
KASSERT(mutex_owned(sc->sc_lock));
r = &ai->record;
p = &ai->play;
- vc = sc->sc_vchan[n];
hw = sc->hw_if;
if (hw == NULL) /* HW has not attached */
return ENXIO;
@@ -4693,8 +4868,11 @@ audiogetinfo(struct audio_softc *sc, str
*/
int
mixer_open(dev_t dev, struct audio_softc *sc, int flags,
- int ifmt, struct lwp *l)
+ int ifmt, struct lwp *l, struct file **nfp)
{
+ struct file *fp;
+ struct audio_chan *chan;
+ int error, fd;
KASSERT(mutex_owned(sc->sc_lock));
@@ -4703,7 +4881,22 @@ mixer_open(dev_t dev, struct audio_softc
DPRINTF(("mixer_open: flags=0x%x sc=%p\n", flags, sc));
- return 0;
+ chan = kmem_zalloc(sizeof(struct audio_chan), KM_SLEEP);
+
+ error = fd_allocfile(&fp, &fd);
+ if (error)
+ return error;
+
+ chan->dev = dev;
+ chan->chan = MIXER_INUSE;
+
+ SIMPLEQ_INSERT_TAIL(&sc->sc_audiochan, chan, entries);
+
+ error = fd_clone(fp, fd, flags, &audio_fileops, chan);
+ KASSERT(error == EMOVEFD);
+
+ *nfp = fp;
+ return error;
}
/*
@@ -4750,7 +4943,7 @@ mixer_signal(struct audio_softc *sc)
*/
/* ARGSUSED */
int
-mixer_close(struct audio_softc *sc, int flags, int ifmt, struct lwp *l)
+mixer_close(struct audio_softc *sc, int flags, struct audio_chan *chan)
{
KASSERT(mutex_owned(sc->sc_lock));
@@ -4759,6 +4952,8 @@ mixer_close(struct audio_softc *sc, int
DPRINTF(("mixer_close: sc %p\n", sc));
mixer_remove(sc);
+ SIMPLEQ_REMOVE(&sc->sc_audiochan, chan, audio_chan, entries);
+
return 0;
}
@@ -4785,9 +4980,7 @@ mixer_ioctl(struct audio_softc *sc, u_lo
switch (cmd) {
case FIOASYNC:
if (*(int *)addr) {
- mutex_exit(sc->sc_lock);
ma = kmem_alloc(sizeof(struct mixer_asyncs), KM_SLEEP);
- mutex_enter(sc->sc_lock);
} else {
ma = NULL;
}
@@ -4837,9 +5030,9 @@ mixer_ioctl(struct audio_softc *sc, u_lo
break;
default:
- if (hw->dev_ioctl)
+ if (hw->dev_ioctl) {
error = hw->dev_ioctl(sc->hw_hdl, cmd, addr, flag, l);
- else
+ } else
error = EINVAL;
break;
}
@@ -4992,19 +5185,20 @@ static bool
audio_suspend(device_t dv, const pmf_qual_t *qual)
{
struct audio_softc *sc = device_private(dv);
+ struct audio_chan *chan;
const struct audio_hw_if *hwp = sc->hw_if;
struct virtual_channel *vc;
- int n;
bool pbus, rbus;
pbus = rbus = false;
mutex_enter(sc->sc_lock);
audio_mixer_capture(sc);
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (sc->sc_audiopid[n].pid == -1)
+ SIMPLEQ_FOREACH(chan, &sc->sc_audiochan, entries) {
+ if (chan == SIMPLEQ_FIRST(&sc->sc_audiochan) ||
+ chan->chan == MIXER_INUSE)
continue;
- vc = sc->sc_vchan[n];
+ vc = chan->vc;
if (vc->sc_pbus && !pbus)
pbus = true;
if (vc->sc_rbus && !rbus)
@@ -5028,29 +5222,30 @@ static bool
audio_resume(device_t dv, const pmf_qual_t *qual)
{
struct audio_softc *sc = device_private(dv);
+ struct audio_chan *chan;
struct virtual_channel *vc;
- int n;
mutex_enter(sc->sc_lock);
sc->sc_trigger_started = false;
sc->sc_rec_started = false;
audio_set_vchan_defaults(sc, AUMODE_PLAY | AUMODE_PLAY_ALL |
- AUMODE_RECORD, &sc->sc_format[0], 0);
+ AUMODE_RECORD, &sc->sc_format[0]);
audio_mixer_restore(sc);
- for (n = 1; n < VAUDIOCHANS; n++) {
- if (sc->sc_audiopid[n].pid == -1)
+ SIMPLEQ_FOREACH(chan, &sc->sc_audiochan, entries) {
+ if (chan == SIMPLEQ_FIRST(&sc->sc_audiochan) ||
+ chan->chan == MIXER_INUSE)
continue;
- vc = sc->sc_vchan[n];
+ vc = chan->vc;
if (vc->sc_lastinfovalid == true)
- audiosetinfo(sc, &vc->sc_lastinfo, true, n);
+ audiosetinfo(sc, &vc->sc_lastinfo, true, vc);
mutex_enter(sc->sc_intr_lock);
if (vc->sc_pbus == true && !vc->sc_mpr.pause)
- audiostartp(sc, n);
+ audiostartp(sc, vc);
if (vc->sc_rbus == true && !vc->sc_mrr.pause)
- audiostartr(sc, n);
+ audiostartr(sc, vc);
mutex_exit(sc->sc_intr_lock);
}
mutex_exit(sc->sc_lock);
@@ -5160,6 +5355,7 @@ void
mix_read(void *arg)
{
struct audio_softc *sc = arg;
+ struct audio_chan *chan;
struct virtual_channel *vc;
stream_filter_t *filter;
stream_fetcher_t *fetcher;
@@ -5167,7 +5363,8 @@ mix_read(void *arg)
int cc, cc1, blksize, error;
uint8_t *inp;
- vc = sc->sc_vchan[0];
+ chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
+ vc = chan->vc;
blksize = vc->sc_mrr.blksize;
cc = blksize;
@@ -5220,6 +5417,7 @@ void
mix_write(void *arg)
{
struct audio_softc *sc = arg;
+ struct audio_chan *chan;
struct virtual_channel *vc;
stream_filter_t *filter;
stream_fetcher_t *fetcher;
@@ -5227,7 +5425,8 @@ mix_write(void *arg)
int cc, cc1, cc2, blksize, error, used;
uint8_t *inp, *orig, *tocopy;
- vc = sc->sc_vchan[0];
+ chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
+ vc = chan->vc;
blksize = vc->sc_mpr.blksize;
cc = blksize;
error = 0;
@@ -5303,12 +5502,13 @@ mix_write(void *arg)
}
void
-mix_func8(struct audio_softc *sc, struct audio_ringbuffer *cb, int n)
+mix_func8(struct audio_softc *sc, struct audio_ringbuffer *cb,
+ struct virtual_channel *vc)
{
int blksize, cc, cc1, cc2, m, resid;
int8_t *orig, *tomix;
- blksize = sc->sc_vchan[0]->sc_mpr.blksize;
+ blksize = sc->sc_pr.blksize;
resid = blksize;
tomix = __UNCONST(cb->s.outp);
@@ -5325,8 +5525,8 @@ mix_func8(struct audio_softc *sc, struct
for (m = 0; m < cc; m++) {
orig[m] += (int8_t)((int32_t)(tomix[m] *
- ((sc->sc_vchan[n]->sc_swvol + 1) * 16)) /
- (sc->sc_opens * VAUDIOCHANS));
+ (vc->sc_swvol + 1)) / (sc->sc_opens *
+ 255));
}
if (&orig[m] >= (int8_t *)sc->sc_pr.s.end)
@@ -5339,12 +5539,13 @@ mix_func8(struct audio_softc *sc, struct
}
void
-mix_func16(struct audio_softc *sc, struct audio_ringbuffer *cb, int n)
+mix_func16(struct audio_softc *sc, struct audio_ringbuffer *cb,
+ struct virtual_channel *vc)
{
int blksize, cc, cc1, cc2, m, resid;
int16_t *orig, *tomix;
- blksize = sc->sc_vchan[0]->sc_mpr.blksize;
+ blksize = sc->sc_pr.blksize;
resid = blksize;
tomix = __UNCONST(cb->s.outp);
@@ -5361,8 +5562,8 @@ mix_func16(struct audio_softc *sc, struc
for (m = 0; m < cc / 2; m++) {
orig[m] += (int16_t)((int32_t)(tomix[m] *
- ((sc->sc_vchan[n]->sc_swvol + 1) * 16)) /
- (sc->sc_opens * VAUDIOCHANS));
+ (vc->sc_swvol + 1)) / (sc->sc_opens *
+ 255));
}
if (&orig[m] >= (int16_t *)sc->sc_pr.s.end)
@@ -5375,12 +5576,13 @@ mix_func16(struct audio_softc *sc, struc
}
void
-mix_func32(struct audio_softc *sc, struct audio_ringbuffer *cb, int n)
+mix_func32(struct audio_softc *sc, struct audio_ringbuffer *cb,
+ struct virtual_channel *vc)
{
int blksize, cc, cc1, cc2, m, resid;
int32_t *orig, *tomix;
- blksize = sc->sc_vchan[0]->sc_mpr.blksize;
+ blksize = sc->sc_pr.blksize;
resid = blksize;
tomix = __UNCONST(cb->s.outp);
@@ -5397,8 +5599,8 @@ mix_func32(struct audio_softc *sc, struc
for (m = 0; m < cc / 4; m++) {
orig[m] += (int32_t)((int32_t)(tomix[m] *
- ((sc->sc_vchan[n]->sc_swvol + 1) * 16)) /
- (sc->sc_opens * VAUDIOCHANS));
+ (vc->sc_swvol + 1)) / (sc->sc_opens *
+ 255));
}
if (&orig[m] >= (int32_t *)sc->sc_pr.s.end)
@@ -5411,18 +5613,19 @@ mix_func32(struct audio_softc *sc, struc
}
void
-mix_func(struct audio_softc *sc, struct audio_ringbuffer *cb, int n)
+mix_func(struct audio_softc *sc, struct audio_ringbuffer *cb,
+ struct virtual_channel *vc)
{
switch (sc->sc_precision) {
case 8:
- mix_func8(sc, cb, n);
+ mix_func8(sc, cb, vc);
break;
case 16:
- mix_func16(sc, cb, n);
+ mix_func16(sc, cb, vc);
break;
case 24:
case 32:
- mix_func32(sc, cb, n);
+ mix_func32(sc, cb, vc);
break;
default:
break;
@@ -5435,7 +5638,7 @@ saturate_func8(struct audio_softc *sc)
int blksize, m, i, resid;
int8_t *orig;
- blksize = sc->sc_vchan[0]->sc_mpr.blksize;
+ blksize = sc->sc_pr.blksize;
resid = blksize;
if (sc->sc_trigger_started == false)
resid *= 2;
@@ -5467,7 +5670,7 @@ saturate_func16(struct audio_softc *sc)
int blksize, m, i, resid;
int16_t *orig;
- blksize = sc->sc_vchan[0]->sc_mpr.blksize;
+ blksize = sc->sc_pr.blksize;
resid = blksize;
if (sc->sc_trigger_started == false)
resid *= 2;
@@ -5499,7 +5702,7 @@ saturate_func32(struct audio_softc *sc)
int blksize, m, i, resid;
int32_t *orig;
- blksize = sc->sc_vchan[0]->sc_mpr.blksize;
+ blksize = sc->sc_pr.blksize;
resid = blksize;
if (sc->sc_trigger_started == false)
resid *= 2;
@@ -5545,8 +5748,8 @@ saturate_func(struct audio_softc *sc)
}
void
-recswvol_func8(struct audio_softc *sc, struct audio_ringbuffer *cb, int n,
- size_t blksize)
+recswvol_func8(struct audio_softc *sc, struct audio_ringbuffer *cb,
+ size_t blksize, struct virtual_channel *vc)
{
int cc, cc1, m, resid;
int8_t *orig;
@@ -5562,7 +5765,7 @@ recswvol_func8(struct audio_softc *sc, s
for (m = 0; m < cc; m++) {
orig[m] = (int16_t)(orig[m] *
- (int16_t)(sc->sc_vchan[n]->sc_recswvol) / 256);
+ (int16_t)(vc->sc_recswvol) / 256);
}
orig = cb->s.start;
@@ -5571,8 +5774,8 @@ recswvol_func8(struct audio_softc *sc, s
}
void
-recswvol_func16(struct audio_softc *sc, struct audio_ringbuffer *cb, int n,
- size_t blksize)
+recswvol_func16(struct audio_softc *sc, struct audio_ringbuffer *cb,
+ size_t blksize, struct virtual_channel *vc)
{
int cc, cc1, m, resid;
int16_t *orig;
@@ -5588,7 +5791,7 @@ recswvol_func16(struct audio_softc *sc,
for (m = 0; m < cc / 2; m++) {
orig[m] = (int32_t)(orig[m] *
- (int32_t)(sc->sc_vchan[n]->sc_recswvol) / 256);
+ (int32_t)(vc->sc_recswvol) / 256);
}
orig = (uint16_t *)cb->s.start;
@@ -5597,8 +5800,8 @@ recswvol_func16(struct audio_softc *sc,
}
void
-recswvol_func32(struct audio_softc *sc, struct audio_ringbuffer *cb, int n,
- size_t blksize)
+recswvol_func32(struct audio_softc *sc, struct audio_ringbuffer *cb,
+ size_t blksize, struct virtual_channel *vc)
{
int cc, cc1, m, resid;
int32_t *orig;
@@ -5614,7 +5817,7 @@ recswvol_func32(struct audio_softc *sc,
for (m = 0; m < cc / 2; m++) {
orig[m] = (int64_t)(orig[m] *
- (int64_t)(sc->sc_vchan[n]->sc_recswvol) / 256);
+ (int64_t)(vc->sc_recswvol) / 256);
}
orig = (uint32_t *)cb->s.start;
@@ -5623,19 +5826,19 @@ recswvol_func32(struct audio_softc *sc,
}
void
-recswvol_func(struct audio_softc *sc, struct audio_ringbuffer *cb, int n,
- size_t blksize)
+recswvol_func(struct audio_softc *sc, struct audio_ringbuffer *cb,
+ size_t blksize, struct virtual_channel *vc)
{
switch (sc->sc_precision) {
case 8:
- recswvol_func8(sc, cb, n, blksize);
+ recswvol_func8(sc, cb, blksize, vc);
break;
case 16:
- recswvol_func16(sc, cb, n, blksize);
+ recswvol_func16(sc, cb, blksize, vc);
break;
case 24:
case 32:
- recswvol_func32(sc, cb, n, blksize);
+ recswvol_func32(sc, cb, blksize, vc);
break;
default:
break;
@@ -5645,14 +5848,20 @@ recswvol_func(struct audio_softc *sc, st
static uint8_t *
find_vchan_vol(struct audio_softc *sc, int d)
{
+ struct audio_chan *chan;
size_t j, n = (size_t)d / 2;
- for (size_t i = j = 0; i <= n; i++)
- if (sc->sc_audiopid[i].pid != -1)
- j++;
-
+ j = 0;
+ SIMPLEQ_FOREACH(chan, &sc->sc_audiochan, entries) {
+ if (chan == SIMPLEQ_FIRST(&sc->sc_audiochan) ||
+ chan->chan == MIXER_INUSE)
+ continue;
+ if (j == n)
+ break;
+ j++;
+ }
return (d & 1) == 0 ?
- &sc->sc_vchan[j]->sc_swvol : &sc->sc_vchan[j]->sc_recswvol;
+ &chan->vc->sc_swvol : &chan->vc->sc_recswvol;
}
static int
@@ -5662,6 +5871,8 @@ audio_set_port(struct audio_softc *sc, m
int d = mc->dev - sc->sc_static_nmixer_states;
+ if (d == -1)
+ return 0;
if (d < 0)
return sc->hw_if->set_port(sc->hw_hdl, mc);
@@ -5680,6 +5891,8 @@ audio_get_port(struct audio_softc *sc, m
int d = mc->dev - sc->sc_static_nmixer_states;
+ if (d == -1)
+ return 0;
if (d < 0)
return sc->hw_if->get_port(sc->hw_hdl, mc);
@@ -5697,10 +5910,15 @@ audio_query_devinfo(struct audio_softc *
KASSERT(mutex_owned(sc->sc_lock));
- if (di->index >= sc->sc_static_nmixer_states && di->index <
- sc->sc_nmixer_states) {
- if ((di->index - sc->sc_static_nmixer_states) % 2 == 0) {
- di->mixer_class = AUDIO_OUTPUT_CLASS;
+ if (di->index >= sc->sc_static_nmixer_states - 1 &&
+ di->index < sc->sc_nmixer_states) {
+ if (di->index == sc->sc_static_nmixer_states - 1) {
+ di->mixer_class = sc->sc_static_nmixer_states -1;
+ di->next = di->prev = AUDIO_MIXER_LAST;
+ strcpy(di->label.name, AudioCvirtchan);
+ di->type = AUDIO_MIXER_CLASS;
+ } else if ((di->index - sc->sc_static_nmixer_states) % 2 == 0) {
+ di->mixer_class = sc->sc_static_nmixer_states -1;
snprintf(mixLabel, sizeof(mixLabel), AudioNdac"%d",
(di->index - sc->sc_static_nmixer_states) / 2);
strcpy(di->label.name, mixLabel);
@@ -5709,10 +5927,10 @@ audio_query_devinfo(struct audio_softc *
di->un.v.num_channels = 1;
strcpy(di->un.v.units.name, AudioNvolume);
} else {
- di->mixer_class = AUDIO_INPUT_CLASS;
- snprintf(mixLabel, sizeof(mixLabel), AudioNmicrophone
- "%d", (di->index - sc->sc_static_nmixer_states) /
- 2);
+ di->mixer_class = sc->sc_static_nmixer_states -1;
+ snprintf(mixLabel, sizeof(mixLabel),
+ AudioNmicrophone "%d",
+ (di->index - sc->sc_static_nmixer_states) / 2);
strcpy(di->label.name, mixLabel);
di->type = AUDIO_MIXER_VALUE;
di->next = di->prev = AUDIO_MIXER_LAST;
@@ -5729,13 +5947,17 @@ audio_query_devinfo(struct audio_softc *
static int
audio_set_params(struct audio_softc *sc, int setmode, int usemode,
- audio_params_t *play, audio_params_t *rec,
- stream_filter_list_t *pfil, stream_filter_list_t *rfil, int n)
+ audio_params_t *play, audio_params_t *rec,
+ stream_filter_list_t *pfil, stream_filter_list_t *rfil,
+ struct virtual_channel *vc)
{
+ struct audio_chan *chan;
+
+ chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
int error = 0;
KASSERT(mutex_owned(sc->sc_lock));
- if (n == 0 && sc->hw_if->set_params != NULL) {
+ if (vc == chan->vc && sc->hw_if->set_params != NULL) {
sc->sc_ready = true;
if (sc->sc_precision == 8)
play->encoding = rec->encoding = AUDIO_ENCODING_SLINEAR;
@@ -5843,7 +6065,7 @@ audio_sysctl_frequency(SYSCTLFN_ARGS)
sc->sc_iffreq = t;
error = audio_set_vchan_defaults(sc, AUMODE_PLAY | AUMODE_PLAY_ALL
- | AUMODE_RECORD, &sc->sc_format[0], 0);
+ | AUMODE_RECORD, &sc->sc_format[0]);
if (error)
aprint_error_dev(sc->sc_dev, "Error setting frequency, "
"please check hardware capabilities\n");
@@ -5895,7 +6117,7 @@ audio_sysctl_precision(SYSCTLFN_ARGS)
sc->sc_format[0].encoding = AUDIO_ENCODING_SLINEAR_LE;
error = audio_set_vchan_defaults(sc, AUMODE_PLAY | AUMODE_PLAY_ALL
- | AUMODE_RECORD, &sc->sc_format[0], 0);
+ | AUMODE_RECORD, &sc->sc_format[0]);
if (error)
aprint_error_dev(sc->sc_dev, "Error setting precision, "
"please check hardware capabilities\n");
@@ -5936,7 +6158,7 @@ audio_sysctl_channels(SYSCTLFN_ARGS)
sc->sc_channels = t;
error = audio_set_vchan_defaults(sc, AUMODE_PLAY | AUMODE_PLAY_ALL
- | AUMODE_RECORD, &sc->sc_format[0], 0);
+ | AUMODE_RECORD, &sc->sc_format[0]);
if (error)
aprint_error_dev(sc->sc_dev, "Error setting channels, "
"please check hardware capabilities\n");
@@ -5948,10 +6170,12 @@ audio_sysctl_channels(SYSCTLFN_ARGS)
static int
vchan_autoconfig(struct audio_softc *sc)
{
+ struct audio_chan *chan;
struct virtual_channel *vc;
int error, i, j, k;
- vc = sc->sc_vchan[0];
+ chan = SIMPLEQ_FIRST(&sc->sc_audiochan);
+ vc = chan->vc;
error = 0;
mutex_enter(sc->sc_lock);
@@ -5964,7 +6188,7 @@ vchan_autoconfig(struct audio_softc *sc)
sc->sc_iffreq = auto_config_freq[k];
error = audio_set_vchan_defaults(sc,
AUMODE_PLAY | AUMODE_PLAY_ALL |
- AUMODE_RECORD, &sc->sc_format[0], 0);
+ AUMODE_RECORD, &sc->sc_format[0]);
if (vc->sc_npfilters > 0 &&
(vc->sc_mpr.s.param.
sample_rate != sc->sc_iffreq ||
@@ -5994,4 +6218,34 @@ vchan_autoconfig(struct audio_softc *sc)
return EINVAL;
}
+static void
+grow_mixer_states(struct audio_softc *sc, int count)
+{
+ mixer_ctrl_t *tmp_mixer_state;
+ size_t origlen = sizeof(mixer_ctrl_t) * (sc->sc_nmixer_states + 1);
+ size_t newlen = sizeof(mixer_ctrl_t) * count + origlen;
+
+ tmp_mixer_state = kmem_zalloc(newlen, KM_SLEEP);
+ memcpy(tmp_mixer_state, sc->sc_mixer_state, origlen);
+
+ sc->sc_nmixer_states += count;
+ kmem_free(sc->sc_mixer_state, origlen);
+ sc->sc_mixer_state = tmp_mixer_state;
+}
+
+static void
+shrink_mixer_states(struct audio_softc *sc, int count)
+{
+ mixer_ctrl_t *tmp_mixer_state;
+ size_t origlen = sizeof(mixer_ctrl_t) * (sc->sc_nmixer_states + 1);
+ size_t newlen = origlen - sizeof(mixer_ctrl_t) * count;
+
+ tmp_mixer_state = kmem_zalloc(newlen, KM_SLEEP);
+ memcpy(tmp_mixer_state, sc->sc_mixer_state, newlen);
+
+ sc->sc_nmixer_states -= count;
+ kmem_free(sc->sc_mixer_state, origlen);
+ sc->sc_mixer_state = tmp_mixer_state;
+}
+
#endif /* NAUDIO > 0 */
Index: src/sys/dev/audiobell.c
diff -u src/sys/dev/audiobell.c:1.12 src/sys/dev/audiobell.c:1.13
--- src/sys/dev/audiobell.c:1.12 Tue Dec 13 20:18:32 2016
+++ src/sys/dev/audiobell.c Fri Feb 10 19:31:42 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: audiobell.c,v 1.12 2016/12/13 20:18:32 christos Exp $ */
+/* $NetBSD: audiobell.c,v 1.13 2017/02/10 19:31:42 nat Exp $ */
/*
@@ -32,25 +32,29 @@
*/
#include <sys/types.h>
-__KERNEL_RCSID(0, "$NetBSD: audiobell.c,v 1.12 2016/12/13 20:18:32 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: audiobell.c,v 1.13 2017/02/10 19:31:42 nat Exp $");
#include <sys/audioio.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
+#include <sys/mutex.h>
#include <sys/null.h>
#include <sys/systm.h>
#include <sys/uio.h>
+#include <sys/unistd.h>
#include <dev/audio_if.h>
#include <dev/audiobellvar.h>
-extern dev_type_open(audioopen);
-extern dev_type_ioctl(audioioctl);
-extern dev_type_write(audiowrite);
-extern dev_type_close(audioclose);
+extern int audiobellopen(dev_t, int, int, struct lwp *, struct file **);
+extern int audioclose(struct file *);
+extern int audiowrite(struct file *, off_t *, struct uio *, kauth_cred_t, int);
+extern int audioioctl(struct file *, u_long, void *);
/* Convert a %age volume to an amount to add to u-law values */
/* XXX Probably highly inaccurate -- should be regenerated */
@@ -143,21 +147,32 @@ audiobell(void *v, u_int pitch, u_int pe
struct audio_info ai;
struct uio auio;
struct iovec aiov;
+ struct file *fp;
int size, len, offset;
+
+ fp = NULL;
dev_t audio = AUDIO_DEVICE | device_unit((device_t)v);
/* The audio system isn't built for polling. */
if (poll) return;
/* If not configured, we can't beep. */
- if (audioopen(audio, FWRITE, 0, NULL) != 0)
+ if (audiobellopen(audio, FWRITE, 0, NULL, &fp) != EMOVEFD || fp == NULL)
return;
+ mutex_enter(&fp->f_lock);
+ fp->f_count++;
+ mutex_exit(&fp->f_lock);
- if (audioioctl(audio, AUDIO_GETINFO, &ai, 0, NULL) != 0)
+ if (audioioctl(fp, AUDIO_GETINFO, &ai) != 0) {
+ audioclose(fp);
return;
+ }
buf = NULL;
+ if (ai.blocksize < 8192)
+ ai.blocksize = 8192;
+
len = period * 8;
size = min(len, ai.blocksize);
if (size == 0) goto out;
@@ -179,11 +194,12 @@ audiobell(void *v, u_int pitch, u_int pe
auio.uio_rw = UIO_WRITE;
UIO_SETUP_SYSSPACE(&auio);
- audiowrite(audio, &auio, 0);
+ audiowrite(fp, NULL, &auio, NULL, 0);
len -= size;
offset += size;
}
out:
if (buf != NULL) free(buf, M_TEMP);
- audioclose(audio, FWRITE, 0, NULL);
+ audioclose(fp);
+ closef(fp);
}
Index: src/sys/dev/audiovar.h
diff -u src/sys/dev/audiovar.h:1.49 src/sys/dev/audiovar.h:1.50
--- src/sys/dev/audiovar.h:1.49 Sun Jan 15 07:46:57 2017
+++ src/sys/dev/audiovar.h Fri Feb 10 19:31:42 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: audiovar.h,v 1.49 2017/01/15 07:46:57 isaki Exp $ */
+/* $NetBSD: audiovar.h,v 1.50 2017/02/10 19:31:42 nat Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -68,6 +68,7 @@
#include <sys/condvar.h>
#include <sys/proc.h>
+#include <sys/queue.h>
#include <dev/audio_if.h>
#include <dev/auconv.h>
@@ -103,9 +104,14 @@ struct audio_ringbuffer {
bool mmapped; /* device is mmap()-ed */
};
-#ifndef VAUDIOCHANS
-#define VAUDIOCHANS 4096
-#endif
+struct audio_chan {
+ dev_t dev;
+#define MIXER_INUSE -2
+ struct virtual_channel *vc;
+ int chan; /* virtual channel */
+ int deschan; /* desired channel for ioctls*/
+ SIMPLEQ_ENTRY(audio_chan) entries;
+};
struct virtual_channel {
u_char sc_open; /* multiple use device */
@@ -159,6 +165,7 @@ struct au_mixer_ports {
mixerout is selected, for dual case */
};
+SIMPLEQ_HEAD(chan_queue, audio_chan);
/*
* Software state, per audio device.
*/
@@ -167,10 +174,7 @@ struct audio_softc {
void *hw_hdl; /* Hardware driver handle */
const struct audio_hw_if *hw_if; /* Hardware interface */
device_t sc_dev; /* Hardware device struct */
- struct audio_pid
- sc_audiopid[VAUDIOCHANS]; /* audio caller */
- struct audio_pid
- sc_despid[VAUDIOCHANS]; /* process to work with ioctls */
+ struct chan_queue sc_audiochan; /* queue of open chans */
#define AUOPEN_READ 0x01
#define AUOPEN_WRITE 0x02
@@ -180,7 +184,6 @@ struct audio_softc {
pid_t sc_async_audio; /* process who wants audio SIGIO */
void *sc_sih_rd;
void *sc_sih_wr;
- struct virtual_channel *sc_vchan[VAUDIOCHANS];
struct mixer_asyncs {
struct mixer_asyncs *next;
pid_t pid;
@@ -215,7 +218,7 @@ struct audio_softc {
* play_thread
* sc_pr
* |
- * vchan[0]->sc_pustream
+ * vchan[0]->sc_pustream (First elemendt in sc_audiochan)
* |
* vchan[0]->sc_mpr
* |
@@ -287,6 +290,9 @@ struct audio_softc {
#define VAUDIO_NFORMATS 1
struct audio_format sc_format[VAUDIO_NFORMATS];
struct audio_params sc_vchan_params;
+
+ bool sc_multiuser;
+ kauth_cred_t sc_credentials; /* audio user's credentials */
};
#endif /* _SYS_DEV_AUDIOVAR_H_ */
Index: src/sys/sys/audioio.h
diff -u src/sys/sys/audioio.h:1.35 src/sys/sys/audioio.h:1.36
--- src/sys/sys/audioio.h:1.35 Thu Dec 8 10:28:44 2016
+++ src/sys/sys/audioio.h Fri Feb 10 19:31:42 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: audioio.h,v 1.35 2016/12/08 10:28:44 nat Exp $ */
+/* $NetBSD: audioio.h,v 1.36 2017/02/10 19:31:42 nat Exp $ */
/*
* Copyright (c) 1991-1993 Regents of the University of California.
@@ -143,11 +143,6 @@ typedef struct audio_encoding {
#define AUDIO_ENCODINGFLAG_EMULATED 1 /* software emulation mode */
} audio_encoding_t;
-struct audio_pid {
- pid_t pid; /* for audio device belonging to pid */
- lwpid_t lwpid; /* unused */
-};
-
/*
* Balance settings.
*/
@@ -162,6 +157,7 @@ struct audio_pid {
#define AUDIO_SPEAKER 0x01 /* built-in speaker */
#define AUDIO_HEADPHONE 0x02 /* headphone jack */
#define AUDIO_LINE_OUT 0x04 /* line out */
+#define VC_OUT 0x08 /* virt chan out */
/*
* Input ports
@@ -170,6 +166,7 @@ struct audio_pid {
#define AUDIO_LINE_IN 0x02 /* line in */
#define AUDIO_CD 0x04 /* on-board CD inputs */
#define AUDIO_INTERNAL_CD_IN AUDIO_CD /* internal CDROM */
+#define VC_IN 0x08 /* virt chan in */
/*
* Audio device operations
@@ -194,7 +191,7 @@ struct audio_pid {
#define AUDIO_PROP_PLAYBACK 0x10
#define AUDIO_PROP_CAPTURE 0x20
#define AUDIO_GETBUFINFO _IOR('A', 35, struct audio_info)
-#define AUDIO_SETPROC _IOW('A', 36, struct audio_pid)
+#define AUDIO_SETPROC _IOW('A', 36, int)
/*
* Mixer device
@@ -340,5 +337,6 @@ typedef struct mixer_ctrl {
#define AudioCmonitor "monitor"
#define AudioCequalization "equalization"
#define AudioCmodem "modem"
+#define AudioCvirtchan "vchan"
#endif /* !_SYS_AUDIOIO_H_ */
Index: src/sys/sys/file.h
diff -u src/sys/sys/file.h:1.80 src/sys/sys/file.h:1.81
--- src/sys/sys/file.h:1.80 Thu Jan 12 18:50:17 2017
+++ src/sys/sys/file.h Fri Feb 10 19:31:42 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: file.h,v 1.80 2017/01/12 18:50:17 christos Exp $ */
+/* $NetBSD: file.h,v 1.81 2017/02/10 19:31:42 nat Exp $ */
/*-
* Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -103,6 +103,7 @@ union file_data {
struct kqueue *fd_kq; // DTYPE_KQUEUE
void *fd_data; // DTYPE_MISC
struct rnd_ctx *fd_rndctx; // DTYPE_MISC (rnd)
+ struct audio_chan *fd_audioctx; // DTYPE_MISC (audio)
int fd_devunit; // DTYPE_MISC (tap)
struct bpf_d *fd_bpf; // DTYPE_MISC (bpf)
struct fcrypt *fd_fcrypt; // DTYPE_CRYPTO is not used
@@ -144,6 +145,7 @@ struct file {
#define f_ksem f_undata.fd_ks
#define f_rndctx f_undata.fd_rndctx
+#define f_audioctx f_undata.fd_audioctx
#define f_devunit f_undata.fd_devunit
#define f_bpf f_undata.fd_bpf
#define f_fcrypt f_undata.fd_fcrypt
Index: src/usr.bin/audio/ctl/audioctl.1
diff -u src/usr.bin/audio/ctl/audioctl.1:1.20 src/usr.bin/audio/ctl/audioctl.1:1.21
--- src/usr.bin/audio/ctl/audioctl.1:1.20 Thu Dec 8 10:28:44 2016
+++ src/usr.bin/audio/ctl/audioctl.1 Fri Feb 10 19:31:42 2017
@@ -1,4 +1,4 @@
-.\" $NetBSD: audioctl.1,v 1.20 2016/12/08 10:28:44 nat Exp $
+.\" $NetBSD: audioctl.1,v 1.21 2017/02/10 19:31:42 nat Exp $
.\"
.\" Copyright (c) 1997, 1999 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -35,17 +35,17 @@
.Sh SYNOPSIS
.Nm
.Op Fl d Ar device
-.Op Fl p Ar pid
+.Op Fl p Ar channel
.Op Fl n
.Fl a
.Nm
.Op Fl d Ar device
-.Op Fl p Ar pid
+.Op Fl p Ar channel
.Op Fl n
.Ar name ...
.Nm
.Op Fl d Ar device
-.Op Fl p Ar pid
+.Op Fl p Ar channel
.Op Fl n
.Fl w
.Ar name=value ...
@@ -72,8 +72,8 @@ flag can be used to give an alternative
.Pp
The
.Fl p
-flag can be used to give a virtual channel pid to control, the default is
-current process id.
+flag can be used to give a virtual channel to control, the default is a new
+channel.
.Pp
The
.Fl n
@@ -93,8 +93,7 @@ audio control device
audio I/O device (does not reset on open)
.El
.Sh EXAMPLES
-To set the playing sampling rate to 11025, for the channel opened by pid 3
-you can use
+To set the playing sampling rate to 11025, for the channel 3 you can use
.Dl audioctl -p 3 -w play.sample_rate=11025
To set all of the play parameters for CD-quality audio, you can use
.Dl audioctl -p 3 -w play=44100,2,16,slinear_le
Index: src/usr.bin/audio/ctl/ctl.c
diff -u src/usr.bin/audio/ctl/ctl.c:1.41 src/usr.bin/audio/ctl/ctl.c:1.42
--- src/usr.bin/audio/ctl/ctl.c:1.41 Thu Dec 8 10:28:44 2016
+++ src/usr.bin/audio/ctl/ctl.c Fri Feb 10 19:31:42 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ctl.c,v 1.41 2016/12/08 10:28:44 nat Exp $ */
+/* $NetBSD: ctl.c,v 1.42 2017/02/10 19:31:42 nat Exp $ */
/*
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: ctl.c,v 1.41 2016/12/08 10:28:44 nat Exp $");
+__RCSID("$NetBSD: ctl.c,v 1.42 2017/02/10 19:31:42 nat Exp $");
#endif
@@ -66,8 +66,7 @@ static char encbuf[1000];
static int properties, fullduplex, rerror;
-static struct audio_pid vchan_pid;
-
+int channel;
int verbose;
static struct field {
@@ -292,7 +291,7 @@ getinfo(int fd)
{
int pos, i;
- if (vchan_pid.pid >= 0 && ioctl(fd, AUDIO_SETPROC, &vchan_pid) < 0)
+ if (channel >= 0 && ioctl(fd, AUDIO_SETPROC, &channel) < 0)
err(1, "AUDIO_SETPROC");
if (ioctl(fd, AUDIO_GETDEV, &adev) < 0)
@@ -327,9 +326,11 @@ usage(void)
{
const char *prog = getprogname();
- fprintf(stderr, "Usage: %s [-d file] [-p] pid [-n] name ...\n", prog);
- fprintf(stderr, "Usage: %s [-d file] [-p] pid [-n] -w name=value ...\n", prog);
- fprintf(stderr, "Usage: %s [-d file] [-p] pid [-n] -a\n", prog);
+ fprintf(stderr, "Usage: %s [-d file] [-p] channel "
+ "[-n] name ...\n", prog);
+ fprintf(stderr, "Usage: %s [-d file] [-p] channel [-n] "
+ "-w name=value ...\n", prog);
+ fprintf(stderr, "Usage: %s [-d file] [-p] channel [-n] -a\n", prog);
exit(1);
}
@@ -342,7 +343,7 @@ main(int argc, char *argv[])
const char *file;
const char *sep = "=";
- vchan_pid.pid = -1;
+ channel = -1;
file = getenv("AUDIOCTLDEVICE");
if (file == NULL)
file = deffile;
@@ -359,7 +360,7 @@ main(int argc, char *argv[])
sep = 0;
break;
case 'p':
- vchan_pid.pid = atoi(optarg);
+ channel = atoi(optarg);
break;
case 'f': /* compatibility */
case 'd':
@@ -403,7 +404,8 @@ main(int argc, char *argv[])
getinfo(fd);
for (i = 0; fields[i].name; i++) {
if (fields[i].flags & SET) {
- printf("%s: -> ", fields[i].name);
+ printf("%s: -> ",
+ fields[i].name);
prfield(&fields[i], 0);
printf("\n");
}
@@ -415,9 +417,12 @@ main(int argc, char *argv[])
p = findfield(*argv);
if (p == 0) {
if (strchr(*argv, '='))
- warnx("field %s does not exist (use -w to set a variable)", *argv);
+ warnx("field %s does not exist "
+ "(use -w to set a "
+ "variable)", *argv);
else
- warnx("field %s does not exist", *argv);
+ warnx("field %s does not exist",
+ *argv);
} else {
prfield(p, sep);
printf("\n");
@@ -435,7 +440,7 @@ audioctl_write(int fd, int argc, char *a
{
struct field *p;
- if (vchan_pid.pid >= 0 && ioctl(fd, AUDIO_SETPROC, &vchan_pid) < 0)
+ if (channel >= 0 && ioctl(fd, AUDIO_SETPROC, &channel) < 0)
err(1, "AUDIO_SETPROC");
AUDIO_INITINFO(&info);
@@ -454,7 +459,8 @@ audioctl_write(int fd, int argc, char *a
else {
rdfield(p, q);
if (p->valp == &fullduplex)
- if (ioctl(fd, AUDIO_SETFD, &fullduplex) < 0)
+ if (ioctl(fd, AUDIO_SETFD,
+ &fullduplex) < 0)
err(1, "set failed");
}
}