NetBSD/sys/compat/linux/linux_audio.c

168 lines
4.5 KiB
C

#include <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/audioio.h>
#include <sys/syscallargs.h>
#include <compat/linux/linux_types.h>
#include <compat/linux/linux_ioctl.h>
#include <compat/linux/linux_signal.h>
#include <compat/linux/linux_syscallargs.h>
#include <compat/linux/linux_audio.h>
int
linux_ioctl_audio(p, uap, retval)
register struct proc *p;
register struct linux_sys_ioctl_args /* {
syscallarg(int) fd;
syscallarg(u_long) com;
syscallarg(caddr_t) data;
} */ *uap;
register_t *retval;
{
register struct file *fp;
register struct filedesc *fdp;
u_long com;
struct audio_info tmpinfo;
int idat;
int error;
fdp = p->p_fd;
if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
(fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
return (EBADF);
if ((fp->f_flag & (FREAD | FWRITE)) == 0)
return (EBADF);
com = SCARG(uap, com);
retval[0] = 0;
switch (com) {
case LINUX_SNDCTL_DSP_RESET:
error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_FLUSH, (caddr_t)0, p);
if (error)
return error;
break;
case LINUX_SNDCTL_DSP_SYNC:
case LINUX_SNDCTL_DSP_POST:
error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_DRAIN, (caddr_t)0, p);
if (error)
return error;
break;
case LINUX_SNDCTL_DSP_SPEED:
AUDIO_INITINFO(&tmpinfo);
error = copyin(SCARG(uap, data), &idat, sizeof idat);
if (error)
return error;
tmpinfo.play.sample_rate =
tmpinfo.record.sample_rate = idat;
(void) (*fp->f_ops->fo_ioctl)(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
if (error)
return error;
idat = tmpinfo.play.sample_rate;
error = copyout(&idat, SCARG(uap, data), sizeof idat);
if (error)
return error;
break;
case LINUX_SNDCTL_DSP_STEREO:
AUDIO_INITINFO(&tmpinfo);
error = copyin(SCARG(uap, data), &idat, sizeof idat);
if (error)
return error;
tmpinfo.play.channels =
tmpinfo.record.channels = idat ? 2 : 1;
(void) (*fp->f_ops->fo_ioctl)(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
if (error)
return error;
idat = tmpinfo.play.channels - 1;
error = copyout(&idat, SCARG(uap, data), sizeof idat);
if (error)
return error;
break;
case LINUX_SNDCTL_DSP_GETBLKSIZE:
error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
if (error)
return error;
idat = tmpinfo.blocksize;
error = copyout(&idat, SCARG(uap, data), sizeof idat);
if (error)
return error;
break;
case LINUX_SNDCTL_DSP_SETFMT:
AUDIO_INITINFO(&tmpinfo);
error = copyin(SCARG(uap, data), &idat, sizeof idat);
if (error)
return error;
switch (idat) {
case LINUX_AFMT_MU_LAW:
tmpinfo.play.precision =
tmpinfo.record.precision = 8;
tmpinfo.play.encoding =
tmpinfo.record.encoding = AUDIO_ENCODING_ULAW;
break;
case LINUX_AFMT_A_LAW:
tmpinfo.play.precision =
tmpinfo.record.precision = 8;
tmpinfo.play.encoding =
tmpinfo.record.encoding = AUDIO_ENCODING_ALAW;
break;
case LINUX_AFMT_U8:
tmpinfo.play.precision =
tmpinfo.record.precision = 8;
tmpinfo.play.encoding =
tmpinfo.record.encoding = AUDIO_ENCODING_LINEAR;
break;
case LINUX_AFMT_S16_LE:
tmpinfo.play.precision =
tmpinfo.record.precision = 16;
tmpinfo.play.encoding =
tmpinfo.record.encoding = AUDIO_ENCODING_LINEAR;
break;
default:
return EINVAL;
}
(void) (*fp->f_ops->fo_ioctl)(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
if (error)
return error;
/*XXXX*/
break;
case LINUX_SNDCTL_DSP_SETFRAGMENT:
AUDIO_INITINFO(&tmpinfo);
error = copyin(SCARG(uap, data), &idat, sizeof idat);
if (error)
return error;
if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17)
return EINVAL;
tmpinfo.blocksize = 1 << (idat & 0xffff);
tmpinfo.hiwat = (idat >> 16) & 0xffff;
(void) (*fp->f_ops->fo_ioctl)(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
if (error)
return error;
idat = tmpinfo.blocksize;
error = copyout(&idat, SCARG(uap, data), sizeof idat);
if (error)
return error;
break;
case LINUX_SNDCTL_DSP_GETFMTS:
idat = LINUX_AFMT_MU_LAW | LINUX_AFMT_U8 | LINUX_AFMT_S16_LE;
error = copyout(&idat, SCARG(uap, data), sizeof idat);
if (error)
return error;
break;
default:
return EINVAL;
}
return 0;
}