示例#1
0
int
oss_ioctl_audio(struct lwp *l, const struct oss_sys_ioctl_args *uap, register_t *retval)
{
	/* {
		syscallarg(int) fd;
		syscallarg(u_long) com;
		syscallarg(void *) data;
	} */
	file_t *fp;
	u_long com;
	struct audio_info tmpinfo;
	struct audio_offset tmpoffs;
	struct oss_audio_buf_info bufinfo;
	struct oss_count_info cntinfo;
	struct audio_encoding tmpenc;
	u_int u;
	int idat, idata;
	int error = 0;
	int (*ioctlf)(file_t *, u_long, void *);

	if ((fp = fd_getfile(SCARG(uap, fd))) == NULL)
		return (EBADF);

	if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
		error = EBADF;
		goto out;
	}

	com = SCARG(uap, com);
	DPRINTF(("oss_ioctl_audio: com=%08lx\n", com));

	retval[0] = 0;

	ioctlf = fp->f_ops->fo_ioctl;
	switch (com) {
	case OSS_SNDCTL_DSP_RESET:
		error = ioctlf(fp, AUDIO_FLUSH, NULL);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_SYNC:
		error = ioctlf(fp, AUDIO_DRAIN, NULL);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_POST:
		/* This call is merely advisory, and may be a nop. */
		break;
	case OSS_SNDCTL_DSP_SPEED:
		AUDIO_INITINFO(&tmpinfo);
		error = copyin(SCARG(uap, data), &idat, sizeof idat);
		if (error)
			goto out;
		tmpinfo.play.sample_rate =
		tmpinfo.record.sample_rate = idat;
		error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
		DPRINTF(("oss_sys_ioctl: SNDCTL_DSP_SPEED %d = %d\n",
			 idat, error));
		if (error)
			goto out;
		/* fall into ... */
	case OSS_SOUND_PCM_READ_RATE:
		error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
		if (error)
			goto out;
		idat = tmpinfo.play.sample_rate;
		error = copyout(&idat, SCARG(uap, data), sizeof idat);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_STEREO:
		AUDIO_INITINFO(&tmpinfo);
		error = copyin(SCARG(uap, data), &idat, sizeof idat);
		if (error)
			goto out;
		tmpinfo.play.channels =
		tmpinfo.record.channels = idat ? 2 : 1;
		(void) ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
		error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
		if (error)
			goto out;
		idat = tmpinfo.play.channels - 1;
		error = copyout(&idat, SCARG(uap, data), sizeof idat);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_GETBLKSIZE:
		error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
		if (error)
			goto out;
		setblocksize(fp, &tmpinfo);
		idat = tmpinfo.blocksize;
		error = copyout(&idat, SCARG(uap, data), sizeof idat);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_SETFMT:
		AUDIO_INITINFO(&tmpinfo);
		error = copyin(SCARG(uap, data), &idat, sizeof idat);
		if (error)
			goto out;
		switch (idat) {
		case OSS_AFMT_MU_LAW:
			tmpinfo.play.precision =
			tmpinfo.record.precision = 8;
			tmpinfo.play.encoding =
			tmpinfo.record.encoding = AUDIO_ENCODING_ULAW;
			break;
		case OSS_AFMT_A_LAW:
			tmpinfo.play.precision =
			tmpinfo.record.precision = 8;
			tmpinfo.play.encoding =
			tmpinfo.record.encoding = AUDIO_ENCODING_ALAW;
			break;
		case OSS_AFMT_U8:
			tmpinfo.play.precision =
			tmpinfo.record.precision = 8;
			tmpinfo.play.encoding =
			tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR;
			break;
		case OSS_AFMT_S8:
			tmpinfo.play.precision =
			tmpinfo.record.precision = 8;
			tmpinfo.play.encoding =
			tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR;
			break;
		case OSS_AFMT_S16_LE:
			tmpinfo.play.precision =
			tmpinfo.record.precision = 16;
			tmpinfo.play.encoding =
			tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
			break;
		case OSS_AFMT_S16_BE:
			tmpinfo.play.precision =
			tmpinfo.record.precision = 16;
			tmpinfo.play.encoding =
			tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE;
			break;
		case OSS_AFMT_U16_LE:
			tmpinfo.play.precision =
			tmpinfo.record.precision = 16;
			tmpinfo.play.encoding =
			tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE;
			break;
		case OSS_AFMT_U16_BE:
			tmpinfo.play.precision =
			tmpinfo.record.precision = 16;
			tmpinfo.play.encoding =
			tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE;
			break;
		default:
			error = EINVAL;
			goto out;
		}
		(void) ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
		/* fall into ... */
	case OSS_SOUND_PCM_READ_BITS:
		error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
		if (error)
			goto out;
		switch (tmpinfo.play.encoding) {
		case AUDIO_ENCODING_ULAW:
			idat = OSS_AFMT_MU_LAW;
			break;
		case AUDIO_ENCODING_ALAW:
			idat = OSS_AFMT_A_LAW;
			break;
		case AUDIO_ENCODING_SLINEAR_LE:
			if (tmpinfo.play.precision == 16)
				idat = OSS_AFMT_S16_LE;
			else
				idat = OSS_AFMT_S8;
			break;
		case AUDIO_ENCODING_SLINEAR_BE:
			if (tmpinfo.play.precision == 16)
				idat = OSS_AFMT_S16_BE;
			else
				idat = OSS_AFMT_S8;
			break;
		case AUDIO_ENCODING_ULINEAR_LE:
			if (tmpinfo.play.precision == 16)
				idat = OSS_AFMT_U16_LE;
			else
				idat = OSS_AFMT_U8;
			break;
		case AUDIO_ENCODING_ULINEAR_BE:
			if (tmpinfo.play.precision == 16)
				idat = OSS_AFMT_U16_BE;
			else
				idat = OSS_AFMT_U8;
			break;
		case AUDIO_ENCODING_ADPCM:
			idat = OSS_AFMT_IMA_ADPCM;
			break;
		}
		error = copyout(&idat, SCARG(uap, data), sizeof idat);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_CHANNELS:
		AUDIO_INITINFO(&tmpinfo);
		error = copyin(SCARG(uap, data), &idat, sizeof idat);
		if (error)
			goto out;
		tmpinfo.play.channels =
		tmpinfo.record.channels = idat;
		(void) ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
		/* fall into ... */
	case OSS_SOUND_PCM_READ_CHANNELS:
		error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
		if (error)
			goto out;
		idat = tmpinfo.play.channels;
		error = copyout(&idat, SCARG(uap, data), sizeof idat);
		if (error)
			goto out;
		break;
	case OSS_SOUND_PCM_WRITE_FILTER:
	case OSS_SOUND_PCM_READ_FILTER:
		error = EINVAL; /* XXX unimplemented */
		goto out;
	case OSS_SNDCTL_DSP_SUBDIVIDE:
		error = copyin(SCARG(uap, data), &idat, sizeof idat);
		if (error)
			goto out;
		error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
		setblocksize(fp, &tmpinfo);
		if (error)
			goto out;
		if (idat == 0)
			idat = tmpinfo.play.buffer_size / tmpinfo.blocksize;
		idat = (tmpinfo.play.buffer_size / idat) & -4;
		AUDIO_INITINFO(&tmpinfo);
		tmpinfo.blocksize = idat;
		error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
		if (error)
			goto out;
		idat = tmpinfo.play.buffer_size / tmpinfo.blocksize;
		error = copyout(&idat, SCARG(uap, data), sizeof idat);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_SETFRAGMENT:
		AUDIO_INITINFO(&tmpinfo);
		error = copyin(SCARG(uap, data), &idat, sizeof idat);
		if (error)
			goto out;
		if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17) {
			error = EINVAL;
			goto out;
		}
		tmpinfo.blocksize = 1 << (idat & 0xffff);
		tmpinfo.hiwat = (idat >> 16) & 0x7fff;
		DPRINTF(("oss_audio: SETFRAGMENT blksize=%d, hiwat=%d\n",
			 tmpinfo.blocksize, tmpinfo.hiwat));
		if (tmpinfo.hiwat == 0)	/* 0 means set to max */
			tmpinfo.hiwat = 65536;
		(void) ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
		error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
		if (error)
			goto out;
		u = tmpinfo.blocksize;
		for(idat = 0; u > 1; idat++, u >>= 1)
			;
		idat |= (tmpinfo.hiwat & 0x7fff) << 16;
		error = copyout(&idat, SCARG(uap, data), sizeof idat);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_GETFMTS:
		for(idat = 0, tmpenc.index = 0;
		    ioctlf(fp, AUDIO_GETENC, &tmpenc) == 0;
		    tmpenc.index++) {
			switch(tmpenc.encoding) {
			case AUDIO_ENCODING_ULAW:
				idat |= OSS_AFMT_MU_LAW;
				break;
			case AUDIO_ENCODING_ALAW:
				idat |= OSS_AFMT_A_LAW;
				break;
			case AUDIO_ENCODING_SLINEAR:
				idat |= OSS_AFMT_S8;
				break;
			case AUDIO_ENCODING_SLINEAR_LE:
				if (tmpenc.precision == 16)
					idat |= OSS_AFMT_S16_LE;
				else
					idat |= OSS_AFMT_S8;
				break;
			case AUDIO_ENCODING_SLINEAR_BE:
				if (tmpenc.precision == 16)
					idat |= OSS_AFMT_S16_BE;
				else
					idat |= OSS_AFMT_S8;
				break;
			case AUDIO_ENCODING_ULINEAR:
				idat |= OSS_AFMT_U8;
				break;
			case AUDIO_ENCODING_ULINEAR_LE:
				if (tmpenc.precision == 16)
					idat |= OSS_AFMT_U16_LE;
				else
					idat |= OSS_AFMT_U8;
				break;
			case AUDIO_ENCODING_ULINEAR_BE:
				if (tmpenc.precision == 16)
					idat |= OSS_AFMT_U16_BE;
				else
					idat |= OSS_AFMT_U8;
				break;
			case AUDIO_ENCODING_ADPCM:
				idat |= OSS_AFMT_IMA_ADPCM;
				break;
			default:
				break;
			}
		}
		DPRINTF(("oss_sys_ioctl: SNDCTL_DSP_GETFMTS = %x\n", idat));
		error = copyout(&idat, SCARG(uap, data), sizeof idat);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_GETOSPACE:
		error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
		if (error)
			goto out;
		setblocksize(fp, &tmpinfo);
		bufinfo.fragsize = tmpinfo.blocksize;
		bufinfo.fragments = tmpinfo.hiwat -
		    (tmpinfo.play.seek + tmpinfo.blocksize - 1) /
		    tmpinfo.blocksize;
		bufinfo.fragstotal = tmpinfo.hiwat;
		bufinfo.bytes =
		    tmpinfo.hiwat * tmpinfo.blocksize - tmpinfo.play.seek;
		error = copyout(&bufinfo, SCARG(uap, data), sizeof bufinfo);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_GETISPACE:
		error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
		if (error)
			goto out;
		setblocksize(fp, &tmpinfo);
		bufinfo.fragsize = tmpinfo.blocksize;
		bufinfo.fragments = tmpinfo.hiwat -
		    (tmpinfo.record.seek + tmpinfo.blocksize - 1) /
		    tmpinfo.blocksize;
                bufinfo.fragstotal = tmpinfo.hiwat;
		bufinfo.bytes =
		    tmpinfo.hiwat * tmpinfo.blocksize - tmpinfo.record.seek;
		DPRINTF(("oss_sys_ioctl: SNDCTL_DSP_GETxSPACE = %d %d %d %d\n",
			 bufinfo.fragsize, bufinfo.fragments,
			 bufinfo.fragstotal, bufinfo.bytes));
		error = copyout(&bufinfo, SCARG(uap, data), sizeof bufinfo);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_NONBLOCK:
		idat = 1;
		error = ioctlf(fp, FIONBIO, &idat);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_GETCAPS:
		error = ioctlf(fp, AUDIO_GETPROPS, &idata);
		if (error)
			goto out;
		idat = OSS_DSP_CAP_TRIGGER; /* pretend we have trigger */
		if (idata & AUDIO_PROP_FULLDUPLEX)
			idat |= OSS_DSP_CAP_DUPLEX;
		if (idata & AUDIO_PROP_MMAP)
			idat |= OSS_DSP_CAP_MMAP;
		DPRINTF(("oss_sys_ioctl: SNDCTL_DSP_GETCAPS = %x\n", idat));
		error = copyout(&idat, SCARG(uap, data), sizeof idat);
		if (error)
			goto out;
		break;
#if 0
	case OSS_SNDCTL_DSP_GETTRIGGER:
		error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
		if (error)
			goto out;
		idat = (tmpinfo.play.pause ? 0 : OSS_PCM_ENABLE_OUTPUT) |
		       (tmpinfo.record.pause ? 0 : OSS_PCM_ENABLE_INPUT);
		error = copyout(&idat, SCARG(uap, data), sizeof idat);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_SETTRIGGER:
		(void) ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo, p);
		error = copyin(SCARG(uap, data), &idat, sizeof idat);
		if (error)
			goto out;
		tmpinfo.play.pause = (idat & OSS_PCM_ENABLE_OUTPUT) == 0;
		tmpinfo.record.pause = (idat & OSS_PCM_ENABLE_INPUT) == 0;
		(void) ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
		error = copyout(&idat, SCARG(uap, data), sizeof idat);
		if (error)
			goto out;
		break;
#else
	case OSS_SNDCTL_DSP_GETTRIGGER:
	case OSS_SNDCTL_DSP_SETTRIGGER:
		/* XXX Do nothing for now. */
		idat = OSS_PCM_ENABLE_OUTPUT;
		error = copyout(&idat, SCARG(uap, data), sizeof idat);
		goto out;
#endif
	case OSS_SNDCTL_DSP_GETIPTR:
		error = ioctlf(fp, AUDIO_GETIOFFS, &tmpoffs);
		if (error)
			goto out;
		cntinfo.bytes = tmpoffs.samples;
		cntinfo.blocks = tmpoffs.deltablks;
		cntinfo.ptr = tmpoffs.offset;
		error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_GETOPTR:
		error = ioctlf(fp, AUDIO_GETOOFFS, &tmpoffs);
		if (error)
			goto out;
		cntinfo.bytes = tmpoffs.samples;
		cntinfo.blocks = tmpoffs.deltablks;
		cntinfo.ptr = tmpoffs.offset;
		error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_SETDUPLEX:
		idat = 1;
		error = ioctlf(fp, AUDIO_SETFD, &idat);
		goto out;
	case OSS_SNDCTL_DSP_MAPINBUF:
	case OSS_SNDCTL_DSP_MAPOUTBUF:
	case OSS_SNDCTL_DSP_SETSYNCRO:
		error = EINVAL;
		goto out;
	case OSS_SNDCTL_DSP_GETODELAY:
		error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
		if (error)
			goto out;
		idat = tmpinfo.play.seek + tmpinfo.blocksize / 2;
		error = copyout(&idat, SCARG(uap, data), sizeof idat);
		if (error)
			goto out;
		break;
	case OSS_SNDCTL_DSP_PROFILE:
		/* This gives just a hint to the driver,
		 * implementing it as a NOP is ok
		 */
		break;
	default:
		error = EINVAL;
		goto out;
	}

 out:
 	fd_putfile(SCARG(uap, fd));
	return error;
}
示例#2
0
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;
}