-/* $OpenBSD: ossaudio.c,v 1.17 2013/03/27 20:28:22 tedu Exp $ */
+/* $OpenBSD: ossaudio.c,v 1.18 2015/04/19 08:42:19 ratchov Exp $ */
/* $NetBSD: ossaudio.c,v 1.14 2001/05/10 01:53:48 augustss Exp $ */
/*-
static struct audiodevinfo *getdevinfo(int);
-static void setblocksize(int, struct audio_info *);
-
-static int audio_ioctl(int, unsigned long, void *);
static int mixer_ioctl(int, unsigned long, void *);
static int opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq);
static int enum_to_ord(struct audiodevinfo *di, int enm);
argp = va_arg(ap, void *);
va_end(ap);
if (IOCGROUP(com) == 'P')
- return audio_ioctl(fd, com, argp);
+ return ENOTTY;
else if (IOCGROUP(com) == 'M')
return mixer_ioctl(fd, com, argp);
else
return ioctl(fd, com, argp);
}
-static int
-audio_ioctl(int fd, unsigned long com, void *argp)
-{
-
- struct audio_info tmpinfo;
- struct audio_offset tmpoffs;
- struct audio_buf_info bufinfo;
- struct count_info cntinfo;
- struct audio_encoding tmpenc;
- struct audio_bufinfo tmpab;
- u_long ldat;
- u_int u;
- int idat, idata;
- int tempret, retval = 0, rerr = 0;
-
- switch (com) {
- case SNDCTL_DSP_RESET:
- retval = ioctl(fd, AUDIO_FLUSH, 0);
- rerr = errno;
- break;
- case SNDCTL_DSP_SYNC:
- retval = ioctl(fd, AUDIO_DRAIN, 0);
- rerr = errno;
- break;
- case SNDCTL_DSP_POST:
- /* This call is merely advisory, and may be a nop. */
- break;
- case SNDCTL_DSP_SPEED:
- AUDIO_INITINFO(&tmpinfo);
- tmpinfo.play.sample_rate =
- tmpinfo.record.sample_rate = INTARG;
- retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
- rerr = errno;
- /* FALLTHRU */
- case SOUND_PCM_READ_RATE:
- tempret = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
- if (retval >= 0) {
- retval = tempret;
- rerr = errno;
- }
- INTARG = tmpinfo.play.sample_rate;
- break;
- case SNDCTL_DSP_STEREO:
- AUDIO_INITINFO(&tmpinfo);
- tmpinfo.play.channels =
- tmpinfo.record.channels = INTARG ? 2 : 1;
- retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
- rerr = errno;
- tempret = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
- if (retval >= 0) {
- retval = tempret;
- rerr = errno;
- }
- INTARG = tmpinfo.play.channels - 1;
- break;
- case SNDCTL_DSP_GETBLKSIZE:
- retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
- rerr = errno;
- setblocksize(fd, &tmpinfo);
- INTARG = tmpinfo.blocksize;
- break;
- case SNDCTL_DSP_SETFMT:
- AUDIO_INITINFO(&tmpinfo);
- switch (INTARG) {
- case AFMT_MU_LAW:
- tmpinfo.play.precision =
- tmpinfo.record.precision = 8;
- tmpinfo.play.encoding =
- tmpinfo.record.encoding = AUDIO_ENCODING_ULAW;
- break;
- case AFMT_A_LAW:
- tmpinfo.play.precision =
- tmpinfo.record.precision = 8;
- tmpinfo.play.encoding =
- tmpinfo.record.encoding = AUDIO_ENCODING_ALAW;
- break;
- case AFMT_U8:
- tmpinfo.play.precision =
- tmpinfo.record.precision = 8;
- tmpinfo.play.encoding =
- tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR;
- break;
- case AFMT_S8:
- tmpinfo.play.precision =
- tmpinfo.record.precision = 8;
- tmpinfo.play.encoding =
- tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR;
- break;
- case AFMT_S16_LE:
- tmpinfo.play.precision =
- tmpinfo.record.precision = 16;
- tmpinfo.play.encoding =
- tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
- break;
- case AFMT_S16_BE:
- tmpinfo.play.precision =
- tmpinfo.record.precision = 16;
- tmpinfo.play.encoding =
- tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE;
- break;
- case AFMT_U16_LE:
- tmpinfo.play.precision =
- tmpinfo.record.precision = 16;
- tmpinfo.play.encoding =
- tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE;
- break;
- case AFMT_U16_BE:
- tmpinfo.play.precision =
- tmpinfo.record.precision = 16;
- tmpinfo.play.encoding =
- tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE;
- break;
- default:
- retval = -1;
- rerr = EINVAL;
- break;
- }
- if (retval == -1) {
- break;
- } else {
- retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
- rerr = errno;
- }
- /* FALLTHRU */
- case SOUND_PCM_READ_BITS:
- (void) ioctl(fd, AUDIO_GETINFO, &tmpinfo);
- switch (tmpinfo.play.encoding) {
- case AUDIO_ENCODING_ULAW:
- idat = AFMT_MU_LAW;
- break;
- case AUDIO_ENCODING_ALAW:
- idat = AFMT_A_LAW;
- break;
- case AUDIO_ENCODING_SLINEAR_LE:
- if (tmpinfo.play.precision == 16)
- idat = AFMT_S16_LE;
- else
- idat = AFMT_S8;
- break;
- case AUDIO_ENCODING_SLINEAR_BE:
- if (tmpinfo.play.precision == 16)
- idat = AFMT_S16_BE;
- else
- idat = AFMT_S8;
- break;
- case AUDIO_ENCODING_ULINEAR_LE:
- if (tmpinfo.play.precision == 16)
- idat = AFMT_U16_LE;
- else
- idat = AFMT_U8;
- break;
- case AUDIO_ENCODING_ULINEAR_BE:
- if (tmpinfo.play.precision == 16)
- idat = AFMT_U16_BE;
- else
- idat = AFMT_U8;
- break;
- case AUDIO_ENCODING_ADPCM:
- idat = AFMT_IMA_ADPCM;
- break;
- default:
- idat = AFMT_MU_LAW; /* XXX default encoding */
- break;
- }
- INTARG = idat;
- break;
- case SNDCTL_DSP_CHANNELS:
- AUDIO_INITINFO(&tmpinfo);
- tmpinfo.play.channels =
- tmpinfo.record.channels = INTARG;
- retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
- rerr = errno;
- /* FALLTHRU */
- case SOUND_PCM_READ_CHANNELS:
- tempret = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
- if (retval >= 0) {
- retval = tempret;
- rerr = errno;
- }
- INTARG = tmpinfo.play.channels;
- break;
- case SOUND_PCM_WRITE_FILTER:
- case SOUND_PCM_READ_FILTER:
- rerr = EINVAL;
- retval = -1; /* XXX unimplemented */
- break;
- case SNDCTL_DSP_SUBDIVIDE:
- retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
- if (retval < 0)
- return retval;
- setblocksize(fd, &tmpinfo);
- idat = INTARG;
- if (idat == 0)
- idat = tmpinfo.play.buffer_size / tmpinfo.blocksize;
- idat = (tmpinfo.play.buffer_size / idat) & -4;
- AUDIO_INITINFO(&tmpinfo);
- tmpinfo.blocksize = idat;
- retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
- if (retval < 0)
- return retval;
- INTARG = tmpinfo.play.buffer_size / tmpinfo.blocksize;
- break;
- case SNDCTL_DSP_SETFRAGMENT:
- AUDIO_INITINFO(&tmpinfo);
- idat = INTARG;
- if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17)
- return EINVAL;
- tmpinfo.blocksize = 1 << (idat & 0xffff);
- tmpinfo.hiwat = ((unsigned)idat >> 16) & 0x7fff;
- if (tmpinfo.hiwat == 0) /* 0 means set to max */
- tmpinfo.hiwat = 65536;
- retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
- rerr = errno;
- tempret = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
- if (retval >= 0) {
- retval = tempret;
- rerr = errno;
- }
- u = tmpinfo.blocksize;
- for(idat = 0; u > 1; idat++, u >>= 1)
- ;
- idat |= (tmpinfo.hiwat & 0x7fff) << 16;
- INTARG = idat;
- break;
- case SNDCTL_DSP_GETFMTS:
- for(idat = 0, tmpenc.index = 0;
- ioctl(fd, AUDIO_GETENC, &tmpenc) == 0;
- tmpenc.index++) {
- switch(tmpenc.encoding) {
- case AUDIO_ENCODING_ULAW:
- idat |= AFMT_MU_LAW;
- break;
- case AUDIO_ENCODING_ALAW:
- idat |= AFMT_A_LAW;
- break;
- case AUDIO_ENCODING_SLINEAR:
- idat |= AFMT_S8;
- break;
- case AUDIO_ENCODING_SLINEAR_LE:
- if (tmpenc.precision == 16)
- idat |= AFMT_S16_LE;
- else
- idat |= AFMT_S8;
- break;
- case AUDIO_ENCODING_SLINEAR_BE:
- if (tmpenc.precision == 16)
- idat |= AFMT_S16_BE;
- else
- idat |= AFMT_S8;
- break;
- case AUDIO_ENCODING_ULINEAR:
- idat |= AFMT_U8;
- break;
- case AUDIO_ENCODING_ULINEAR_LE:
- if (tmpenc.precision == 16)
- idat |= AFMT_U16_LE;
- else
- idat |= AFMT_U8;
- break;
- case AUDIO_ENCODING_ULINEAR_BE:
- if (tmpenc.precision == 16)
- idat |= AFMT_U16_BE;
- else
- idat |= AFMT_U8;
- break;
- case AUDIO_ENCODING_ADPCM:
- idat |= AFMT_IMA_ADPCM;
- break;
- default:
- break;
- }
- }
- INTARG = idat;
- break;
- case SNDCTL_DSP_GETOSPACE:
- retval = ioctl(fd, AUDIO_GETPRINFO, &tmpab);
- rerr = errno;
- bufinfo.fragsize = tmpab.blksize;
- bufinfo.fragstotal = tmpab.hiwat;
- bufinfo.bytes = tmpab.hiwat * tmpab.blksize - tmpab.seek;
- if (tmpab.blksize != 0)
- bufinfo.fragments = bufinfo.bytes / tmpab.blksize;
- else
- bufinfo.fragments = 0;
- *(struct audio_buf_info *)argp = bufinfo;
- break;
- case SNDCTL_DSP_GETISPACE:
- retval = ioctl(fd, AUDIO_GETRRINFO, &tmpab);
- rerr = errno;
- bufinfo.fragsize = tmpab.blksize;
- bufinfo.fragstotal = tmpab.hiwat;
- bufinfo.bytes = tmpab.seek;
- if (tmpab.blksize != 0 )
- bufinfo.fragments = bufinfo.bytes / tmpab.blksize;
- else
- bufinfo.fragments = 0;
- *(struct audio_buf_info *)argp = bufinfo;
- break;
- case SNDCTL_DSP_NONBLOCK:
- idat = 1;
- retval = ioctl(fd, FIONBIO, &idat);
- rerr = errno;
- break;
- case SNDCTL_DSP_GETCAPS:
- retval = ioctl(fd, AUDIO_GETPROPS, &idata);
- rerr = errno;
- idat = DSP_CAP_TRIGGER;
- if (idata & AUDIO_PROP_FULLDUPLEX)
- idat |= DSP_CAP_DUPLEX;
- if (idata & AUDIO_PROP_MMAP)
- idat |= DSP_CAP_MMAP;
- INTARG = idat;
- break;
- case SNDCTL_DSP_SETTRIGGER:
- idat = INTARG;
- AUDIO_INITINFO(&tmpinfo);
- if (idat & PCM_ENABLE_OUTPUT)
- tmpinfo.play.pause = 0;
- if (idat & PCM_ENABLE_INPUT)
- tmpinfo.record.pause = 0;
- retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
- rerr = errno;
- /* FALLTHRU */
- case SNDCTL_DSP_GETTRIGGER:
- tempret = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
- if (retval >= 0) {
- retval = tempret;
- rerr = errno;
- }
- idat = (tmpinfo.play.pause ? 0 : PCM_ENABLE_OUTPUT) |
- (tmpinfo.record.pause ? 0 : PCM_ENABLE_INPUT);
- INTARG = idat;
- break;
- case SNDCTL_DSP_GETIPTR:
- retval = ioctl(fd, AUDIO_GETIOFFS, &tmpoffs);
- rerr = errno;
- cntinfo.bytes = tmpoffs.samples;
- cntinfo.blocks = tmpoffs.deltablks;
- cntinfo.ptr = tmpoffs.offset;
- *(struct count_info *)argp = cntinfo;
- break;
- case SNDCTL_DSP_GETOPTR:
- retval = ioctl(fd, AUDIO_GETOOFFS, &tmpoffs);
- rerr = errno;
- cntinfo.bytes = tmpoffs.samples;
- cntinfo.blocks = tmpoffs.deltablks;
- cntinfo.ptr = tmpoffs.offset;
- *(struct count_info *)argp = cntinfo;
- break;
- case SNDCTL_DSP_SETDUPLEX:
- idat = 1;
- retval = ioctl(fd, AUDIO_SETFD, &idat);
- rerr = errno;
- break;
- case SNDCTL_DSP_GETODELAY:
- retval = ioctl(fd, AUDIO_WSEEK, &ldat);
- INTARG = (int)ldat;
- break;
- case SNDCTL_DSP_MAPINBUF:
- case SNDCTL_DSP_MAPOUTBUF:
- case SNDCTL_DSP_SETSYNCRO:
- case SNDCTL_DSP_PROFILE:
- rerr = EINVAL;
- retval = -1; /* XXX unimplemented */
- break;
- default:
- rerr = EINVAL;
- retval = -1;
- break;
- }
- errno = rerr;
- return retval;
-}
-
-
/* If the mixer device should have more than MAX_MIXER_DEVS devices
* some will not be available to Linux */
#define MAX_MIXER_DEVS 64
INTARG = idat;
return 0;
}
-
-/*
- * Check that the blocksize is a power of 2 as OSS wants.
- * If not, set it to be.
- */
-static void
-setblocksize(int fd, struct audio_info *info)
-{
- struct audio_info set;
- int s;
-
- if (info->blocksize & (info->blocksize-1)) {
- for(s = 32; s < info->blocksize; s <<= 1)
- ;
- AUDIO_INITINFO(&set);
- set.blocksize = s;
- ioctl(fd, AUDIO_SETINFO, &set);
- ioctl(fd, AUDIO_GETINFO, info);
- }
-}