diff options
-rw-r--r-- | share/man/man4/audio.4 | 106 | ||||
-rw-r--r-- | sys/dev/audio.c | 149 | ||||
-rw-r--r-- | sys/kern/kern_pledge.c | 6 | ||||
-rw-r--r-- | sys/sys/audioio.h | 26 |
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 |