1 #include <sys/param.h> 2 #include <sys/proc.h> 3 #include <sys/systm.h> 4 #include <sys/file.h> 5 #include <sys/filedesc.h> 6 #include <sys/ioctl.h> 7 #include <sys/mount.h> 8 #include <sys/audioio.h> 9 10 #include <sys/syscallargs.h> 11 12 #include <compat/linux/linux_types.h> 13 #include <compat/linux/linux_ioctl.h> 14 #include <compat/linux/linux_signal.h> 15 #include <compat/linux/linux_syscallargs.h> 16 #include <compat/linux/linux_audio.h> 17 18 int 19 linux_ioctl_audio(p, uap, retval) 20 register struct proc *p; 21 register struct linux_sys_ioctl_args /* { 22 syscallarg(int) fd; 23 syscallarg(u_long) com; 24 syscallarg(caddr_t) data; 25 } */ *uap; 26 register_t *retval; 27 { 28 register struct file *fp; 29 register struct filedesc *fdp; 30 u_long com; 31 struct audio_info tmpinfo; 32 int idat; 33 int error; 34 35 fdp = p->p_fd; 36 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 37 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 38 return (EBADF); 39 40 if ((fp->f_flag & (FREAD | FWRITE)) == 0) 41 return (EBADF); 42 43 com = SCARG(uap, com); 44 retval[0] = 0; 45 46 switch (com) { 47 case LINUX_SNDCTL_DSP_RESET: 48 error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_FLUSH, (caddr_t)0, p); 49 if (error) 50 return error; 51 break; 52 case LINUX_SNDCTL_DSP_SYNC: 53 case LINUX_SNDCTL_DSP_POST: 54 error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_DRAIN, (caddr_t)0, p); 55 if (error) 56 return error; 57 break; 58 case LINUX_SNDCTL_DSP_SPEED: 59 AUDIO_INITINFO(&tmpinfo); 60 error = copyin(SCARG(uap, data), &idat, sizeof idat); 61 if (error) 62 return error; 63 tmpinfo.play.sample_rate = 64 tmpinfo.record.sample_rate = idat; 65 (void) (*fp->f_ops->fo_ioctl)(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p); 66 error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 67 if (error) 68 return error; 69 idat = tmpinfo.play.sample_rate; 70 error = copyout(&idat, SCARG(uap, data), sizeof idat); 71 if (error) 72 return error; 73 break; 74 case LINUX_SNDCTL_DSP_STEREO: 75 AUDIO_INITINFO(&tmpinfo); 76 error = copyin(SCARG(uap, data), &idat, sizeof idat); 77 if (error) 78 return error; 79 tmpinfo.play.channels = 80 tmpinfo.record.channels = idat ? 2 : 1; 81 (void) (*fp->f_ops->fo_ioctl)(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p); 82 error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 83 if (error) 84 return error; 85 idat = tmpinfo.play.channels - 1; 86 error = copyout(&idat, SCARG(uap, data), sizeof idat); 87 if (error) 88 return error; 89 break; 90 case LINUX_SNDCTL_DSP_GETBLKSIZE: 91 error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 92 if (error) 93 return error; 94 idat = tmpinfo.blocksize; 95 error = copyout(&idat, SCARG(uap, data), sizeof idat); 96 if (error) 97 return error; 98 break; 99 case LINUX_SNDCTL_DSP_SETFMT: 100 AUDIO_INITINFO(&tmpinfo); 101 error = copyin(SCARG(uap, data), &idat, sizeof idat); 102 if (error) 103 return error; 104 switch (idat) { 105 case LINUX_AFMT_MU_LAW: 106 tmpinfo.play.precision = 107 tmpinfo.record.precision = 8; 108 tmpinfo.play.encoding = 109 tmpinfo.record.encoding = AUDIO_ENCODING_ULAW; 110 break; 111 case LINUX_AFMT_A_LAW: 112 tmpinfo.play.precision = 113 tmpinfo.record.precision = 8; 114 tmpinfo.play.encoding = 115 tmpinfo.record.encoding = AUDIO_ENCODING_ALAW; 116 break; 117 case LINUX_AFMT_U8: 118 tmpinfo.play.precision = 119 tmpinfo.record.precision = 8; 120 tmpinfo.play.encoding = 121 tmpinfo.record.encoding = AUDIO_ENCODING_LINEAR; 122 break; 123 case LINUX_AFMT_S16_LE: 124 tmpinfo.play.precision = 125 tmpinfo.record.precision = 16; 126 tmpinfo.play.encoding = 127 tmpinfo.record.encoding = AUDIO_ENCODING_LINEAR; 128 break; 129 default: 130 return EINVAL; 131 } 132 (void) (*fp->f_ops->fo_ioctl)(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p); 133 error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 134 if (error) 135 return error; 136 /*XXXX*/ 137 break; 138 case LINUX_SNDCTL_DSP_SETFRAGMENT: 139 AUDIO_INITINFO(&tmpinfo); 140 error = copyin(SCARG(uap, data), &idat, sizeof idat); 141 if (error) 142 return error; 143 if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17) 144 return EINVAL; 145 tmpinfo.blocksize = 1 << (idat & 0xffff); 146 tmpinfo.hiwat = (idat >> 16) & 0xffff; 147 (void) (*fp->f_ops->fo_ioctl)(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p); 148 error = (*fp->f_ops->fo_ioctl)(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 149 if (error) 150 return error; 151 idat = tmpinfo.blocksize; 152 error = copyout(&idat, SCARG(uap, data), sizeof idat); 153 if (error) 154 return error; 155 break; 156 case LINUX_SNDCTL_DSP_GETFMTS: 157 idat = LINUX_AFMT_MU_LAW | LINUX_AFMT_U8 | LINUX_AFMT_S16_LE; 158 error = copyout(&idat, SCARG(uap, data), sizeof idat); 159 if (error) 160 return error; 161 break; 162 default: 163 return EINVAL; 164 } 165 166 return 0; 167 } 168