summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/audio.4106
-rw-r--r--sys/dev/audio.c149
-rw-r--r--sys/kern/kern_pledge.c6
-rw-r--r--sys/sys/audioio.h26
4 files changed, 282 insertions, 5 deletions
diff --git a/share/man/man4/audio.4 b/share/man/man4/audio.4
index ae30267fc85..a1d68320cf7 100644
--- a/share/man/man4/audio.4
+++ b/share/man/man4/audio.4
@@ -1,4 +1,4 @@
-.\" $OpenBSD: audio.4,v 1.68 2015/07/28 20:45:02 ratchov Exp $
+.\" $OpenBSD: audio.4,v 1.69 2016/03/16 06:46:39 ratchov Exp $
.\" $NetBSD: audio.4,v 1.20 1998/05/28 17:27:15 augustss Exp $
.\"
.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
@@ -28,7 +28,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd $Mdocdate: July 28 2015 $
+.Dd $Mdocdate: March 16 2016 $
.Dt AUDIO 4
.Os
.Sh NAME
@@ -335,6 +335,108 @@ or unpause the particular direction.
In full-duplex the pause values for both directions must
be equal.
.Pp
+.It Dv AUDIO_SETPAR Fa "struct audio_swpar *"
+.It Dv AUDIO_GETPAR Fa "struct audio_swpar *"
+Set or get audio parameters as encoded in the
+.Vt audio_swpar
+structure.
+.Bd -literal
+struct audio_swpar {
+ unsigned int sig; /* if 1, encoding is signed */
+ unsigned int le; /* if 1, encoding is little-endian */
+ unsigned int bits; /* bits per sample */
+ unsigned int bps; /* bytes per sample */
+ unsigned int msb; /* if 1, bits are msb-aligned */
+ unsigned int rate; /* common play & rec sample rate */
+ unsigned int pchan; /* play channels */
+ unsigned int rchan; /* rec channels */
+ unsigned int nblks; /* number of blocks in play buffer */
+ unsigned int round; /* common frames per block */
+};
+.Ed
+.Pp
+When setting the device parameters with
+.Dv AUDIO_SETPAR ,
+the
+.Vt audio_swpar
+structure should first be initialized with
+.Pp
+.Bd -literal
+struct audio_swpar ap;
+
+AUDIO_INITPAR(&ap);
+.Ed
+.Pp
+and then only the values to be changed should be set.
+This ensures that the software will work with future versions
+of the driver.
+The driver will attempt to set the given parameters; if the
+device doesn't support them, it will choose other parameters.
+Then the software must call
+.Dv AUDIO_GETINFO
+to obtain the parameters in use.
+.Pp
+The parameters are as follows:
+.Bl -tag -width "round"
+.It Va bits
+Number of bits per sample: must be between 1 and 32.
+.It Va bps
+Bytes per sample; if specified, it must be large enough to hold all bits.
+By default it's set to the smallest power of two large enough to hold
+.Va bits .
+.It Va sig
+If set (i.e. non-zero) then the samples are signed,
+otherwise they are unsigned.
+.It Va le
+If set, then the byte order is little endian;
+if not it is big endian;
+it's meaningful only if
+.Va bps
+> 1.
+.It Va msb
+If set, then the
+.Va bits
+are aligned in the packet to the most significant bit
+(i.e. lower bits are padded),
+otherwise to the least significant bit
+(i.e. higher bits are padded).
+It's meaningful only if
+.Va bits
+<
+.Va bps
+* 8.
+.It Va rchan
+The number of recorded channels; meaningful only if the
+device is opened for reading.
+.It Va pchan
+The number of channels playing; meaningful only if
+the device is opened for writing.
+.It Va rate
+The sampling frequency in Hz.
+.It Va nblks
+The number of blocks in the play buffer.
+.It Va round
+The audio block size.
+.El
+.Pp
+.It Dv AUDIO_START
+Start playback and/or recording immediately.
+If the device is open for writing (playback), then
+the play buffer must be filled with the
+.Xr write 2
+syscall.
+The buffer size is obtained by multiplying
+the
+.Va nblks ,
+.Va round ,
+and
+.Va bps
+parameters obtained with
+.Dv AUDIO_GETPAR .
+.Pp
+.It Dv AUDIO_STOP
+Stop playback and recording immediately.
+.Pp
.It Dv AUDIO_GETPOS Fa "struct audio_pos *"
Fetch an atomic snapshot of device timing information in the
.Vt audio_pos
diff --git a/sys/dev/audio.c b/sys/dev/audio.c
index 1271bc77517..0db6c5d679b 100644
--- a/sys/dev/audio.c
+++ b/sys/dev/audio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: audio.c,v 1.144 2016/01/29 15:14:23 ratchov Exp $ */
+/* $OpenBSD: audio.c,v 1.145 2016/03/16 06:46:39 ratchov Exp $ */
/*
* Copyright (c) 2015 Alexandre Ratchov <alex@caoua.org>
*
@@ -1023,6 +1023,135 @@ audio_getinfo(struct audio_softc *sc, struct audio_info *ai)
}
int
+audio_ioc_start(struct audio_softc *sc)
+{
+ if (!sc->pause) {
+ DPRINTF("%s: can't start: already started\n", DEVNAME(sc));
+ return EBUSY;
+ }
+ if ((sc->mode & AUMODE_PLAY) && sc->play.used != sc->play.len) {
+ DPRINTF("%s: play buffer not ready\n", DEVNAME(sc));
+ return EBUSY;
+ }
+ if ((sc->mode & AUMODE_RECORD) && sc->rec.used != 0) {
+ DPRINTF("%s: record buffer not ready\n", DEVNAME(sc));
+ return EBUSY;
+ }
+ sc->pause = 0;
+ return audio_start(sc);
+}
+
+int
+audio_ioc_stop(struct audio_softc *sc)
+{
+ if (sc->pause) {
+ DPRINTF("%s: can't stop: not started\n", DEVNAME(sc));
+ return EBUSY;
+ }
+ sc->pause = 1;
+ if (sc->active)
+ return audio_stop(sc);
+ return 0;
+}
+
+int
+audio_ioc_getpar(struct audio_softc *sc, struct audio_swpar *p)
+{
+ p->rate = sc->rate;
+ p->sig = sc->sw_enc == AUDIO_ENCODING_SLINEAR_LE ||
+ sc->sw_enc == AUDIO_ENCODING_SLINEAR_BE;
+ p->le = sc->sw_enc == AUDIO_ENCODING_SLINEAR_LE ||
+ sc->sw_enc == AUDIO_ENCODING_ULINEAR_LE;
+ p->bits = sc->bits;
+ p->bps = sc->bps;
+ p->msb = sc->msb;
+ p->pchan = sc->pchan;
+ p->rchan = sc->rchan;
+ p->nblks = sc->nblks;
+ p->round = sc->round;
+ return 0;
+}
+
+int
+audio_ioc_setpar(struct audio_softc *sc, struct audio_swpar *p)
+{
+ int error, le, sig;
+
+ if (sc->active) {
+ DPRINTF("%s: can't change params during dma\n",
+ DEVNAME(sc));
+ return EBUSY;
+ }
+
+ /*
+ * copy desired parameters into the softc structure
+ */
+ if (p->sig != ~0U || p->le != ~0U || p->bits != ~0U) {
+ sig = 1;
+ le = (BYTE_ORDER == LITTLE_ENDIAN);
+ sc->bits = 16;
+ sc->bps = 2;
+ sc->msb = 1;
+ if (p->sig != ~0U)
+ sig = p->sig;
+ if (p->le != ~0U)
+ le = p->le;
+ if (p->bits != ~0U) {
+ sc->bits = p->bits;
+ sc->bps = sc->bits <= 8 ?
+ 1 : (sc->bits <= 16 ? 2 : 4);
+ if (p->bps != ~0U)
+ sc->bps = p->bps;
+ if (p->msb != ~0U)
+ sc->msb = p->msb ? 1 : 0;
+ }
+ sc->sw_enc = (sig) ?
+ (le ? AUDIO_ENCODING_SLINEAR_LE :
+ AUDIO_ENCODING_SLINEAR_BE) :
+ (le ? AUDIO_ENCODING_ULINEAR_LE :
+ AUDIO_ENCODING_ULINEAR_BE);
+ }
+ if (p->rate != ~0)
+ sc->rate = p->rate;
+ if (p->pchan != ~0)
+ sc->pchan = p->pchan;
+ if (p->rchan != ~0)
+ sc->rchan = p->rchan;
+ if (p->round != ~0)
+ sc->round = p->round;
+ if (p->nblks != ~0)
+ sc->nblks = p->nblks;
+
+ /*
+ * if the device is not opened for playback or recording don't
+ * touch the hardware yet (ex. if this is /dev/audioctlN)
+ */
+ if (sc->mode == 0)
+ return 0;
+
+ /*
+ * negociate parameters with the hardware
+ */
+ error = audio_setpar(sc);
+ if (error)
+ return error;
+ audio_clear(sc);
+ if ((sc->mode & AUMODE_PLAY) && sc->ops->init_output) {
+ error = sc->ops->init_output(sc->arg,
+ sc->play.data, sc->play.len);
+ if (error)
+ return error;
+ }
+ if ((sc->mode & AUMODE_RECORD) && sc->ops->init_input) {
+ error = sc->ops->init_input(sc->arg,
+ sc->rec.data, sc->rec.len);
+ if (error)
+ return error;
+ }
+ return 0;
+}
+
+int
audio_match(struct device *parent, void *match, void *aux)
{
struct audio_attach_args *sa = aux;
@@ -1587,6 +1716,16 @@ audio_ioctl(struct audio_softc *sc, unsigned long cmd, void *addr)
ap->rec_xrun = sc->rec.xrun;
mtx_leave(&audio_lock);
break;
+ case AUDIO_START:
+ return audio_ioc_start(sc);
+ case AUDIO_STOP:
+ return audio_ioc_stop(sc);
+ case AUDIO_SETPAR:
+ error = audio_ioc_setpar(sc, (struct audio_swpar *)addr);
+ break;
+ case AUDIO_GETPAR:
+ error = audio_ioc_getpar(sc, (struct audio_swpar *)addr);
+ break;
case AUDIO_SETINFO:
error = audio_setinfo(sc, (struct audio_info *)addr);
break;
@@ -1795,6 +1934,14 @@ audioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
error = EBUSY;
break;
}
+ if (cmd == AUDIO_SETPAR && sc->mode != 0) {
+ error = EBUSY;
+ break;
+ }
+ if (cmd == AUDIO_START || cmd == AUDIO_STOP) {
+ error = ENXIO;
+ break;
+ }
error = audio_ioctl(sc, cmd, addr);
break;
case AUDIO_DEV_MIXER:
diff --git a/sys/kern/kern_pledge.c b/sys/kern/kern_pledge.c
index 9d20c7f1784..1c711883fdf 100644
--- a/sys/kern/kern_pledge.c
+++ b/sys/kern/kern_pledge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_pledge.c,v 1.157 2016/03/15 15:10:09 semarie Exp $ */
+/* $OpenBSD: kern_pledge.c,v 1.158 2016/03/16 06:46:39 ratchov Exp $ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
@@ -1170,6 +1170,10 @@ pledge_ioctl(struct proc *p, long com, struct file *fp)
#if NAUDIO > 0
switch (com) {
case AUDIO_GETPOS:
+ case AUDIO_GETPAR:
+ case AUDIO_SETPAR:
+ case AUDIO_START:
+ case AUDIO_STOP:
case AUDIO_SETINFO:
case AUDIO_GETINFO:
case AUDIO_GETENC:
diff --git a/sys/sys/audioio.h b/sys/sys/audioio.h
index f93c1c45e56..0c5e850f073 100644
--- a/sys/sys/audioio.h
+++ b/sys/sys/audioio.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: audioio.h,v 1.23 2015/07/28 20:45:02 ratchov Exp $ */
+/* $OpenBSD: audioio.h,v 1.24 2016/03/16 06:46:39 ratchov Exp $ */
/* $NetBSD: audioio.h,v 1.24 1998/08/13 06:28:41 mrg Exp $ */
/*
@@ -38,6 +38,26 @@
#ifndef _SYS_AUDIOIO_H_
#define _SYS_AUDIOIO_H_
+#define AUDIO_INITPAR(p) \
+ (void)memset((void *)(p), 0xff, sizeof(struct audio_swpar))
+
+/*
+ * argument to AUDIO_SETPAR and AUDIO_GETPAR ioctls
+ */
+struct audio_swpar {
+ unsigned int sig; /* if 1, encoding is signed */
+ unsigned int le; /* if 1, encoding is little-endian */
+ unsigned int bits; /* bits per sample */
+ unsigned int bps; /* bytes per sample */
+ unsigned int msb; /* if 1, bits are msb-aligned */
+ unsigned int rate; /* common play & rec sample rate */
+ unsigned int pchan; /* play channels */
+ unsigned int rchan; /* rec channels */
+ unsigned int nblks; /* number of blocks in play buffer */
+ unsigned int round; /* common frames per block */
+ unsigned int _spare[6];
+};
+
/*
* Audio device
*/
@@ -149,6 +169,10 @@ typedef struct audio_encoding {
#define AUDIO_GETOOFFS _IOR('A', 33, struct audio_offset)
#define AUDIO_GETPROPS _IOR('A', 34, int)
#define AUDIO_GETPOS _IOR('A', 35, struct audio_pos)
+#define AUDIO_GETPAR _IOR('A', 36, struct audio_swpar)
+#define AUDIO_SETPAR _IOWR('A', 37, struct audio_swpar)
+#define AUDIO_START _IO('A', 38)
+#define AUDIO_STOP _IO('A', 39)
#define AUDIO_PROP_FULLDUPLEX 0x01
#define AUDIO_PROP_MMAP 0x02
#define AUDIO_PROP_INDEPENDENT 0x04