diff options
author | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2016-03-16 06:46:40 +0000 |
---|---|---|
committer | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2016-03-16 06:46:40 +0000 |
commit | 6802204ffc24b73423fa8d97d3c8eb6e17e782bb (patch) | |
tree | 320f263b3bf32beba77b46f4d0a23c4c416ebbad /sys | |
parent | cb08d0ae7c091facf6183a96ecf5f06d48075c29 (diff) |
Expose new audio ioctls that do one thing only: start and stop DMA,
set and get parameters. This is much simpler.
ok semarie, armani, tweaks from jmc
Diffstat (limited to 'sys')
-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 |
3 files changed, 178 insertions, 3 deletions
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 |