Home | History | Annotate | Line # | Download | only in ossaudio
ossaudio.c revision 1.11
      1  1.11  augustss /*	$NetBSD: ossaudio.c,v 1.11 1997/05/19 23:05:14 augustss Exp $	*/
      2   1.1   mycroft #include <sys/param.h>
      3   1.1   mycroft #include <sys/proc.h>
      4   1.1   mycroft #include <sys/systm.h>
      5   1.1   mycroft #include <sys/file.h>
      6   1.6  augustss #include <sys/vnode.h>
      7   1.1   mycroft #include <sys/filedesc.h>
      8   1.1   mycroft #include <sys/ioctl.h>
      9   1.1   mycroft #include <sys/mount.h>
     10   1.1   mycroft #include <sys/audioio.h>
     11   1.1   mycroft 
     12   1.1   mycroft #include <sys/syscallargs.h>
     13   1.1   mycroft 
     14   1.6  augustss #include <compat/ossaudio/ossaudio.h>
     15   1.6  augustss #include <compat/ossaudio/ossaudiovar.h>
     16   1.6  augustss 
     17   1.6  augustss static struct audiodevinfo *getdevinfo __P((struct file *, struct proc *));
     18   1.1   mycroft 
     19   1.1   mycroft int
     20   1.6  augustss oss_ioctl_audio(p, uap, retval)
     21   1.1   mycroft 	register struct proc *p;
     22   1.6  augustss 	register struct oss_sys_ioctl_args /* {
     23   1.1   mycroft 		syscallarg(int) fd;
     24   1.1   mycroft 		syscallarg(u_long) com;
     25   1.1   mycroft 		syscallarg(caddr_t) data;
     26   1.1   mycroft 	} */ *uap;
     27   1.1   mycroft 	register_t *retval;
     28   1.1   mycroft {
     29   1.1   mycroft 	register struct file *fp;
     30   1.1   mycroft 	register struct filedesc *fdp;
     31   1.1   mycroft 	u_long com;
     32   1.1   mycroft 	struct audio_info tmpinfo;
     33   1.1   mycroft 	int idat;
     34   1.1   mycroft 	int error;
     35   1.6  augustss 	int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *));
     36   1.1   mycroft 
     37   1.1   mycroft 	fdp = p->p_fd;
     38   1.1   mycroft 	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
     39   1.1   mycroft 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
     40   1.1   mycroft 		return (EBADF);
     41   1.1   mycroft 
     42   1.1   mycroft 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
     43   1.1   mycroft 		return (EBADF);
     44   1.1   mycroft 
     45   1.6  augustss 	ioctlf = fp->f_ops->fo_ioctl;
     46   1.6  augustss 
     47   1.1   mycroft 	com = SCARG(uap, com);
     48   1.1   mycroft 	retval[0] = 0;
     49   1.1   mycroft 
     50   1.1   mycroft 	switch (com) {
     51   1.6  augustss 	case OSS_SNDCTL_DSP_RESET:
     52   1.6  augustss 		error = ioctlf(fp, AUDIO_FLUSH, (caddr_t)0, p);
     53   1.1   mycroft 		if (error)
     54   1.1   mycroft 			return error;
     55   1.1   mycroft 		break;
     56   1.6  augustss 	case OSS_SNDCTL_DSP_SYNC:
     57   1.6  augustss 	case OSS_SNDCTL_DSP_POST:
     58   1.6  augustss 		error = ioctlf(fp, AUDIO_DRAIN, (caddr_t)0, p);
     59   1.1   mycroft 		if (error)
     60   1.1   mycroft 			return error;
     61   1.1   mycroft 		break;
     62   1.6  augustss 	case OSS_SNDCTL_DSP_SPEED:
     63   1.1   mycroft 		AUDIO_INITINFO(&tmpinfo);
     64   1.1   mycroft 		error = copyin(SCARG(uap, data), &idat, sizeof idat);
     65   1.1   mycroft 		if (error)
     66   1.1   mycroft 			return error;
     67   1.1   mycroft 		tmpinfo.play.sample_rate =
     68   1.1   mycroft 		tmpinfo.record.sample_rate = idat;
     69   1.6  augustss 		(void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
     70   1.6  augustss 		/* fall into ... */
     71   1.6  augustss 	case OSS_SOUND_PCM_READ_RATE:
     72   1.6  augustss 		error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
     73   1.1   mycroft 		if (error)
     74   1.1   mycroft 			return error;
     75   1.1   mycroft 		idat = tmpinfo.play.sample_rate;
     76   1.1   mycroft 		error = copyout(&idat, SCARG(uap, data), sizeof idat);
     77   1.1   mycroft 		if (error)
     78   1.1   mycroft 			return error;
     79   1.1   mycroft 		break;
     80   1.6  augustss 	case OSS_SNDCTL_DSP_STEREO:
     81   1.1   mycroft 		AUDIO_INITINFO(&tmpinfo);
     82   1.1   mycroft 		error = copyin(SCARG(uap, data), &idat, sizeof idat);
     83   1.1   mycroft 		if (error)
     84   1.1   mycroft 			return error;
     85   1.1   mycroft 		tmpinfo.play.channels =
     86   1.1   mycroft 		tmpinfo.record.channels = idat ? 2 : 1;
     87   1.6  augustss 		(void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
     88   1.6  augustss 		error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
     89   1.1   mycroft 		if (error)
     90   1.1   mycroft 			return error;
     91   1.1   mycroft 		idat = tmpinfo.play.channels - 1;
     92   1.1   mycroft 		error = copyout(&idat, SCARG(uap, data), sizeof idat);
     93   1.1   mycroft 		if (error)
     94   1.1   mycroft 			return error;
     95   1.1   mycroft 		break;
     96   1.6  augustss 	case OSS_SNDCTL_DSP_GETBLKSIZE:
     97   1.6  augustss 		error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
     98   1.1   mycroft 		if (error)
     99   1.1   mycroft 			return error;
    100   1.1   mycroft 		idat = tmpinfo.blocksize;
    101   1.1   mycroft 		error = copyout(&idat, SCARG(uap, data), sizeof idat);
    102   1.1   mycroft 		if (error)
    103   1.1   mycroft 			return error;
    104   1.1   mycroft 		break;
    105   1.6  augustss 	case OSS_SNDCTL_DSP_SETFMT:
    106   1.1   mycroft 		AUDIO_INITINFO(&tmpinfo);
    107   1.1   mycroft 		error = copyin(SCARG(uap, data), &idat, sizeof idat);
    108   1.1   mycroft 		if (error)
    109   1.1   mycroft 			return error;
    110   1.1   mycroft 		switch (idat) {
    111   1.6  augustss 		case OSS_AFMT_MU_LAW:
    112   1.1   mycroft 			tmpinfo.play.precision =
    113   1.1   mycroft 			tmpinfo.record.precision = 8;
    114   1.1   mycroft 			tmpinfo.play.encoding =
    115   1.1   mycroft 			tmpinfo.record.encoding = AUDIO_ENCODING_ULAW;
    116   1.1   mycroft 			break;
    117   1.6  augustss 		case OSS_AFMT_A_LAW:
    118   1.1   mycroft 			tmpinfo.play.precision =
    119   1.1   mycroft 			tmpinfo.record.precision = 8;
    120   1.1   mycroft 			tmpinfo.play.encoding =
    121   1.1   mycroft 			tmpinfo.record.encoding = AUDIO_ENCODING_ALAW;
    122   1.1   mycroft 			break;
    123   1.6  augustss 		case OSS_AFMT_U8:
    124   1.1   mycroft 			tmpinfo.play.precision =
    125   1.1   mycroft 			tmpinfo.record.precision = 8;
    126   1.1   mycroft 			tmpinfo.play.encoding =
    127   1.8  augustss 			tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR;
    128   1.8  augustss 			break;
    129   1.8  augustss 		case OSS_AFMT_S8:
    130   1.8  augustss 			tmpinfo.play.precision =
    131   1.8  augustss 			tmpinfo.record.precision = 8;
    132   1.8  augustss 			tmpinfo.play.encoding =
    133   1.1   mycroft 			tmpinfo.record.encoding = AUDIO_ENCODING_LINEAR;
    134   1.1   mycroft 			break;
    135   1.6  augustss 		case OSS_AFMT_S16_LE:
    136   1.1   mycroft 			tmpinfo.play.precision =
    137   1.1   mycroft 			tmpinfo.record.precision = 16;
    138   1.1   mycroft 			tmpinfo.play.encoding =
    139   1.8  augustss 			tmpinfo.record.encoding = AUDIO_ENCODING_LINEAR_LE;
    140   1.8  augustss 			break;
    141   1.8  augustss 		case OSS_AFMT_S16_BE:
    142   1.8  augustss 			tmpinfo.play.precision =
    143   1.8  augustss 			tmpinfo.record.precision = 16;
    144   1.8  augustss 			tmpinfo.play.encoding =
    145   1.8  augustss 			tmpinfo.record.encoding = AUDIO_ENCODING_LINEAR_BE;
    146   1.8  augustss 			break;
    147   1.8  augustss 		case OSS_AFMT_U16_LE:
    148   1.8  augustss 			tmpinfo.play.precision =
    149   1.8  augustss 			tmpinfo.record.precision = 16;
    150   1.8  augustss 			tmpinfo.play.encoding =
    151   1.8  augustss 			tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE;
    152   1.8  augustss 			break;
    153   1.8  augustss 		case OSS_AFMT_U16_BE:
    154   1.8  augustss 			tmpinfo.play.precision =
    155   1.8  augustss 			tmpinfo.record.precision = 16;
    156   1.8  augustss 			tmpinfo.play.encoding =
    157   1.8  augustss 			tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE;
    158   1.1   mycroft 			break;
    159   1.1   mycroft 		default:
    160   1.1   mycroft 			return EINVAL;
    161   1.1   mycroft 		}
    162   1.6  augustss 		(void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
    163   1.6  augustss 		/* fall into ... */
    164   1.6  augustss 	case OSS_SOUND_PCM_READ_BITS:
    165   1.6  augustss 		error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
    166   1.1   mycroft 		if (error)
    167   1.1   mycroft 			return error;
    168   1.5   mycroft 		switch (tmpinfo.play.encoding) {
    169   1.5   mycroft 		case AUDIO_ENCODING_ULAW:
    170   1.6  augustss 			idat = OSS_AFMT_MU_LAW;
    171   1.5   mycroft 			break;
    172   1.5   mycroft 		case AUDIO_ENCODING_ALAW:
    173   1.6  augustss 			idat = OSS_AFMT_A_LAW;
    174   1.5   mycroft 			break;
    175   1.8  augustss 		case AUDIO_ENCODING_LINEAR_LE:
    176   1.8  augustss 			if (tmpinfo.play.precision == 16)
    177   1.8  augustss 				idat = OSS_AFMT_S16_LE;
    178   1.8  augustss 			else
    179   1.8  augustss 				idat = OSS_AFMT_S8;
    180   1.8  augustss 			break;
    181   1.8  augustss 		case AUDIO_ENCODING_LINEAR_BE:
    182   1.8  augustss 			if (tmpinfo.play.precision == 16)
    183   1.8  augustss 				idat = OSS_AFMT_S16_BE;
    184   1.8  augustss 			else
    185   1.8  augustss 				idat = OSS_AFMT_S8;
    186   1.8  augustss 			break;
    187   1.8  augustss 		case AUDIO_ENCODING_ULINEAR_LE:
    188   1.8  augustss 			if (tmpinfo.play.precision == 16)
    189   1.8  augustss 				idat = OSS_AFMT_U16_LE;
    190   1.8  augustss 			else
    191   1.8  augustss 				idat = OSS_AFMT_U8;
    192   1.8  augustss 			break;
    193   1.8  augustss 		case AUDIO_ENCODING_ULINEAR_BE:
    194   1.8  augustss 			if (tmpinfo.play.precision == 16)
    195   1.8  augustss 				idat = OSS_AFMT_U16_BE;
    196   1.8  augustss 			else
    197   1.8  augustss 				idat = OSS_AFMT_U8;
    198   1.5   mycroft 			break;
    199   1.5   mycroft 		case AUDIO_ENCODING_ADPCM:
    200   1.6  augustss 			idat = OSS_AFMT_IMA_ADPCM;
    201   1.5   mycroft 			break;
    202   1.5   mycroft 		}
    203   1.5   mycroft 		error = copyout(&idat, SCARG(uap, data), sizeof idat);
    204   1.5   mycroft 		if (error)
    205   1.5   mycroft 			return error;
    206   1.1   mycroft 		break;
    207   1.6  augustss 	case OSS_SNDCTL_DSP_CHANNELS:
    208   1.6  augustss 		AUDIO_INITINFO(&tmpinfo);
    209   1.6  augustss 		error = copyin(SCARG(uap, data), &idat, sizeof idat);
    210   1.6  augustss 		if (error)
    211   1.6  augustss 			return error;
    212   1.6  augustss 		tmpinfo.play.channels =
    213   1.6  augustss 		tmpinfo.record.channels = idat;
    214   1.6  augustss 		(void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
    215   1.6  augustss 		/* fall into ... */
    216   1.6  augustss 	case OSS_SOUND_PCM_READ_CHANNELS:
    217   1.6  augustss 		error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
    218   1.6  augustss 		if (error)
    219   1.6  augustss 			return error;
    220   1.6  augustss 		idat = tmpinfo.play.channels;
    221   1.6  augustss 		error = copyout(&idat, SCARG(uap, data), sizeof idat);
    222   1.6  augustss 		if (error)
    223   1.6  augustss 			return error;
    224   1.6  augustss 		break;
    225   1.6  augustss 	case OSS_SOUND_PCM_WRITE_FILTER:
    226   1.6  augustss 	case OSS_SOUND_PCM_READ_FILTER:
    227   1.6  augustss 		return EINVAL; /* XXX unimplemented */
    228   1.6  augustss 	case OSS_SNDCTL_DSP_SUBDIVIDE:
    229   1.9  augustss 		error = copyin(SCARG(uap, data), &idat, sizeof idat);
    230   1.9  augustss 		if (error)
    231   1.9  augustss 			return error;
    232   1.9  augustss 		error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
    233   1.9  augustss 		if (error)
    234   1.9  augustss 			return error;
    235   1.9  augustss 		if (idat == 0)
    236   1.9  augustss 			idat = tmpinfo.buffersize / tmpinfo.blocksize;
    237   1.9  augustss 		idat = (tmpinfo.buffersize / idat) & -4;
    238   1.9  augustss 		AUDIO_INITINFO(&tmpinfo);
    239   1.9  augustss 		tmpinfo.blocksize = idat;
    240   1.9  augustss 		error = ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
    241   1.9  augustss 		if (error)
    242   1.9  augustss 			return error;
    243   1.9  augustss 		idat = tmpinfo.buffersize / tmpinfo.blocksize;
    244   1.9  augustss 		error = copyout(&idat, SCARG(uap, data), sizeof idat);
    245   1.9  augustss 		if (error)
    246   1.9  augustss 			return error;
    247   1.9  augustss 		break;
    248   1.6  augustss 	case OSS_SNDCTL_DSP_SETFRAGMENT:
    249   1.1   mycroft 		AUDIO_INITINFO(&tmpinfo);
    250   1.1   mycroft 		error = copyin(SCARG(uap, data), &idat, sizeof idat);
    251   1.1   mycroft 		if (error)
    252   1.1   mycroft 			return error;
    253   1.1   mycroft 		if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17)
    254   1.1   mycroft 			return EINVAL;
    255   1.1   mycroft 		tmpinfo.blocksize = 1 << (idat & 0xffff);
    256   1.1   mycroft 		tmpinfo.hiwat = (idat >> 16) & 0xffff;
    257   1.6  augustss 		(void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
    258   1.6  augustss 		error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
    259   1.1   mycroft 		if (error)
    260   1.1   mycroft 			return error;
    261   1.1   mycroft 		idat = tmpinfo.blocksize;
    262   1.1   mycroft 		error = copyout(&idat, SCARG(uap, data), sizeof idat);
    263   1.1   mycroft 		if (error)
    264   1.1   mycroft 			return error;
    265   1.1   mycroft 		break;
    266   1.6  augustss 	case OSS_SNDCTL_DSP_GETFMTS:
    267   1.6  augustss 		idat = OSS_AFMT_MU_LAW | OSS_AFMT_U8 | OSS_AFMT_S16_LE;
    268   1.6  augustss 		error = copyout(&idat, SCARG(uap, data), sizeof idat);
    269   1.6  augustss 		if (error)
    270   1.6  augustss 			return error;
    271   1.6  augustss 		break;
    272   1.6  augustss 	case OSS_SNDCTL_DSP_GETOSPACE:
    273   1.6  augustss 	case OSS_SNDCTL_DSP_GETISPACE:
    274   1.6  augustss 	case OSS_SNDCTL_DSP_NONBLOCK:
    275   1.6  augustss 		return EINVAL; /* XXX unimplemented */
    276   1.6  augustss 	case OSS_SNDCTL_DSP_GETCAPS:
    277   1.6  augustss 		idat = 0; /* XXX full duplex info should be set */
    278   1.1   mycroft 		error = copyout(&idat, SCARG(uap, data), sizeof idat);
    279   1.1   mycroft 		if (error)
    280   1.1   mycroft 			return error;
    281   1.1   mycroft 		break;
    282   1.6  augustss 	case OSS_SNDCTL_DSP_GETTRIGGER:
    283   1.6  augustss 	case OSS_SNDCTL_DSP_SETTRIGGER:
    284   1.6  augustss 	case OSS_SNDCTL_DSP_GETIPTR:
    285   1.6  augustss 	case OSS_SNDCTL_DSP_GETOPTR:
    286   1.6  augustss 	case OSS_SNDCTL_DSP_MAPINBUF:
    287   1.6  augustss 	case OSS_SNDCTL_DSP_MAPOUTBUF:
    288   1.6  augustss 	case OSS_SNDCTL_DSP_SETSYNCRO:
    289   1.6  augustss 	case OSS_SNDCTL_DSP_SETDUPLEX:
    290   1.6  augustss 	case OSS_SNDCTL_DSP_PROFILE:
    291   1.6  augustss 		return EINVAL; /* XXX unimplemented */
    292   1.1   mycroft 	default:
    293   1.1   mycroft 		return EINVAL;
    294   1.1   mycroft 	}
    295   1.1   mycroft 
    296   1.1   mycroft 	return 0;
    297   1.3   mycroft }
    298   1.3   mycroft 
    299   1.6  augustss /* If the NetBSD mixer device should have more than 32 devices
    300   1.6  augustss  * some will not be available to Linux */
    301   1.6  augustss #define NETBSD_MAXDEVS 32
    302   1.6  augustss struct audiodevinfo {
    303   1.6  augustss 	int done;
    304   1.6  augustss 	dev_t dev;
    305   1.7  augustss 	int16_t devmap[OSS_SOUND_MIXER_NRDEVICES],
    306   1.7  augustss 	        rdevmap[NETBSD_MAXDEVS];
    307   1.6  augustss         u_long devmask, recmask, stereomask;
    308   1.6  augustss 	u_long caps, source;
    309   1.6  augustss };
    310   1.6  augustss 
    311   1.6  augustss /*
    312   1.6  augustss  * Collect the audio device information to allow faster
    313   1.6  augustss  * emulation of the Linux mixer ioctls.  Cache the information
    314   1.6  augustss  * to eliminate the overhead of repeating all the ioctls needed
    315   1.6  augustss  * to collect the information.
    316   1.6  augustss  */
    317   1.6  augustss static struct audiodevinfo *
    318   1.6  augustss getdevinfo(fp, p)
    319   1.6  augustss 	struct file *fp;
    320   1.6  augustss 	struct proc *p;
    321   1.6  augustss {
    322   1.6  augustss 	mixer_devinfo_t mi;
    323   1.6  augustss 	int i;
    324   1.6  augustss 	static struct {
    325   1.6  augustss 		char *name;
    326   1.6  augustss 		int code;
    327   1.6  augustss 	} *dp, devs[] = {
    328   1.6  augustss 		{ AudioNmicrophone,	OSS_SOUND_MIXER_MIC },
    329   1.6  augustss 		{ AudioNline,		OSS_SOUND_MIXER_LINE },
    330   1.6  augustss 		{ AudioNcd,		OSS_SOUND_MIXER_CD },
    331   1.6  augustss 		{ AudioNdac,		OSS_SOUND_MIXER_PCM },
    332   1.6  augustss 		{ AudioNrecord,		OSS_SOUND_MIXER_IMIX },
    333   1.6  augustss 		{ AudioNvolume,		OSS_SOUND_MIXER_VOLUME },
    334   1.6  augustss 		{ AudioNtreble,		OSS_SOUND_MIXER_TREBLE },
    335   1.6  augustss 		{ AudioNbass,		OSS_SOUND_MIXER_BASS },
    336   1.6  augustss 		{ AudioNspeaker,	OSS_SOUND_MIXER_SPEAKER },
    337   1.6  augustss /*		{ AudioNheadphone,	?? },*/
    338   1.6  augustss 		{ AudioNoutput,		OSS_SOUND_MIXER_OGAIN },
    339   1.6  augustss 		{ AudioNinput,		OSS_SOUND_MIXER_IGAIN },
    340  1.10  augustss 		{ AudioNmaster,		OSS_SOUND_MIXER_SPEAKER },
    341   1.6  augustss /*		{ AudioNstereo,		?? },*/
    342   1.6  augustss /*		{ AudioNmono,		?? },*/
    343   1.6  augustss 		{ AudioNfmsynth,	OSS_SOUND_MIXER_SYNTH },
    344   1.6  augustss /*		{ AudioNwave,		OSS_SOUND_MIXER_PCM },*/
    345  1.10  augustss 		{ AudioNmidi,		OSS_SOUND_MIXER_SYNTH },
    346   1.6  augustss /*		{ AudioNmixerout,	?? },*/
    347   1.6  augustss 		{ 0, -1 }
    348   1.6  augustss 	};
    349   1.6  augustss 	int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *)) =
    350   1.6  augustss 	    fp->f_ops->fo_ioctl;
    351   1.6  augustss 	struct vnode *vp;
    352   1.6  augustss 	struct vattr va;
    353   1.6  augustss 	static struct audiodevinfo devcache = { 0 };
    354   1.6  augustss 	struct audiodevinfo *di = &devcache;
    355   1.6  augustss 
    356   1.6  augustss 	/* Figure out what device it is so we can check if the
    357   1.6  augustss 	 * cached data is valid.
    358   1.6  augustss 	 */
    359   1.6  augustss 	vp = (struct vnode *)fp->f_data;
    360   1.6  augustss 	if (vp->v_type != VCHR)
    361   1.6  augustss 		return 0;
    362   1.6  augustss 	if (VOP_GETATTR(vp, &va, p->p_ucred, p))
    363   1.6  augustss 		return 0;
    364   1.6  augustss 	if (di->done && di->dev == va.va_rdev)
    365   1.6  augustss 		return di;
    366   1.6  augustss 
    367   1.6  augustss 	di->done = 1;
    368   1.6  augustss 	di->dev = va.va_rdev;
    369   1.6  augustss 	di->devmask = 0;
    370   1.6  augustss 	di->recmask = 0;
    371   1.6  augustss 	di->stereomask = 0;
    372   1.6  augustss 	di->source = -1;
    373   1.6  augustss 	di->caps = 0;
    374   1.6  augustss 	for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++)
    375   1.6  augustss 		di->devmap[i] = -1;
    376   1.6  augustss 	for(i = 0; i < NETBSD_MAXDEVS; i++)
    377   1.6  augustss 		di->rdevmap[i] = -1;
    378   1.6  augustss 	for(i = 0; i < NETBSD_MAXDEVS; i++) {
    379   1.6  augustss 		mi.index = i;
    380   1.6  augustss 		if (ioctlf(fp, AUDIO_MIXER_DEVINFO, (caddr_t)&mi, p) < 0)
    381   1.6  augustss 			break;
    382   1.6  augustss 		switch(mi.type) {
    383   1.6  augustss 		case AUDIO_MIXER_VALUE:
    384   1.6  augustss 			for(dp = devs; dp->name; dp++)
    385   1.6  augustss 		    		if (strcmp(dp->name, mi.label.name) == 0)
    386   1.6  augustss 					break;
    387   1.6  augustss 			if (dp->code >= 0) {
    388   1.6  augustss 				di->devmap[dp->code] = i;
    389   1.6  augustss 				di->rdevmap[i] = dp->code;
    390   1.6  augustss 				di->devmask |= 1 << dp->code;
    391   1.6  augustss 				if (mi.un.v.num_channels == 2)
    392   1.6  augustss 					di->stereomask |= 1 << dp->code;
    393   1.6  augustss 			}
    394   1.6  augustss 			break;
    395   1.6  augustss 		case AUDIO_MIXER_ENUM:
    396   1.6  augustss 			if (strcmp(mi.label.name, AudioNsource) == 0) {
    397   1.6  augustss 				int j;
    398   1.6  augustss 				di->source = i;
    399  1.10  augustss 				for(j = 0; j < mi.un.e.num_mem; j++)
    400   1.6  augustss 					di->recmask |= 1 << di->rdevmap[mi.un.e.member[j].ord];
    401   1.6  augustss 				di->caps = OSS_SOUND_CAP_EXCL_INPUT;
    402   1.6  augustss 			}
    403   1.6  augustss 			break;
    404   1.6  augustss 		case AUDIO_MIXER_SET:
    405   1.6  augustss 			if (strcmp(mi.label.name, AudioNsource) == 0) {
    406   1.6  augustss 				int j;
    407   1.6  augustss 				di->source = i;
    408   1.6  augustss 				for(j = 0; j < mi.un.s.num_mem; j++) {
    409   1.6  augustss 					int k, mask = mi.un.s.member[j].mask;
    410   1.6  augustss 					if (mask) {
    411  1.10  augustss 						for(k = 0; !(mask & 1); mask >>= 1, k++)
    412   1.6  augustss 							;
    413   1.6  augustss 						di->recmask |= 1 << di->rdevmap[k];
    414   1.6  augustss 					}
    415   1.6  augustss 				}
    416   1.6  augustss 			}
    417   1.6  augustss 			break;
    418   1.6  augustss 		}
    419   1.6  augustss 	}
    420   1.6  augustss 	return di;
    421   1.6  augustss }
    422   1.6  augustss 
    423   1.6  augustss int
    424   1.6  augustss oss_ioctl_mixer(p, uap, retval)
    425   1.6  augustss 	register struct proc *p;
    426   1.6  augustss 	register struct oss_sys_ioctl_args /* {
    427   1.6  augustss 		syscallarg(int) fd;
    428   1.6  augustss 		syscallarg(u_long) com;
    429   1.6  augustss 		syscallarg(caddr_t) data;
    430   1.6  augustss 	} */ *uap;
    431   1.6  augustss 	register_t *retval;
    432   1.6  augustss {
    433   1.6  augustss 	struct file *fp;
    434   1.6  augustss 	struct filedesc *fdp;
    435   1.6  augustss 	u_long com;
    436   1.6  augustss 	struct audiodevinfo *di;
    437   1.6  augustss 	mixer_ctrl_t mc;
    438   1.6  augustss 	int idat;
    439   1.6  augustss 	int i;
    440   1.6  augustss 	int error;
    441   1.6  augustss 	int l, r, n;
    442   1.6  augustss 	int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *));
    443   1.6  augustss 
    444   1.6  augustss 	fdp = p->p_fd;
    445   1.6  augustss 	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
    446   1.6  augustss 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
    447   1.6  augustss 		return (EBADF);
    448   1.6  augustss 
    449   1.6  augustss 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
    450   1.6  augustss 		return (EBADF);
    451   1.6  augustss 
    452   1.6  augustss 	com = SCARG(uap, com);
    453   1.6  augustss 	retval[0] = 0;
    454   1.6  augustss 
    455   1.6  augustss 	di = getdevinfo(fp, p);
    456   1.6  augustss 	if (di == 0)
    457   1.6  augustss 		return EINVAL;
    458   1.6  augustss 
    459   1.6  augustss 	ioctlf = fp->f_ops->fo_ioctl;
    460   1.6  augustss 	switch (com) {
    461   1.6  augustss 	case OSS_SOUND_MIXER_READ_RECSRC:
    462   1.6  augustss 		if (di->source == -1)
    463   1.6  augustss 			return EINVAL;
    464   1.6  augustss 		mc.dev = di->source;
    465   1.6  augustss 		if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) {
    466   1.6  augustss 			mc.type = AUDIO_MIXER_ENUM;
    467   1.6  augustss 			error = ioctlf(fp, AUDIO_MIXER_READ, (caddr_t)&mc, p);
    468   1.6  augustss 			if (error)
    469   1.6  augustss 				return error;
    470   1.6  augustss 			idat = 1 << di->rdevmap[mc.un.ord];
    471   1.6  augustss 		} else {
    472   1.6  augustss 			int k;
    473   1.6  augustss 			unsigned int mask;
    474   1.6  augustss 			mc.type = AUDIO_MIXER_SET;
    475   1.6  augustss 			error = ioctlf(fp, AUDIO_MIXER_READ, (caddr_t)&mc, p);
    476   1.6  augustss 			if (error)
    477   1.6  augustss 				return error;
    478   1.6  augustss 			idat = 0;
    479   1.6  augustss 			for(mask = mc.un.mask, k = 0; mask; mask >>= 1, k++)
    480  1.10  augustss 				if (mask & 1)
    481  1.10  augustss 					idat |= 1 << di->rdevmap[k];
    482   1.6  augustss 		}
    483   1.6  augustss 		break;
    484   1.6  augustss 	case OSS_SOUND_MIXER_READ_DEVMASK:
    485   1.6  augustss 		idat = di->devmask;
    486   1.6  augustss 		break;
    487   1.6  augustss 	case OSS_SOUND_MIXER_READ_RECMASK:
    488   1.6  augustss 		idat = di->recmask;
    489   1.6  augustss 		break;
    490   1.6  augustss 	case OSS_SOUND_MIXER_READ_STEREODEVS:
    491   1.6  augustss 		idat = di->stereomask;
    492   1.6  augustss 		break;
    493   1.6  augustss 	case OSS_SOUND_MIXER_READ_CAPS:
    494   1.6  augustss 		idat = di->caps;
    495   1.6  augustss 		break;
    496   1.6  augustss 	case OSS_SOUND_MIXER_WRITE_RECSRC:
    497   1.6  augustss 		if (di->source == -1)
    498   1.6  augustss 			return EINVAL;
    499   1.6  augustss 		mc.dev = di->source;
    500   1.6  augustss 		error = copyin(SCARG(uap, data), &idat, sizeof idat);
    501   1.6  augustss 		if (error)
    502   1.6  augustss 			return error;
    503   1.7  augustss 		if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) {
    504   1.7  augustss 			mc.type = AUDIO_MIXER_ENUM;
    505   1.7  augustss 			for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++)
    506   1.7  augustss 				if (idat & (1 << i))
    507   1.7  augustss 					break;
    508   1.7  augustss 			if (i >= OSS_SOUND_MIXER_NRDEVICES ||
    509   1.7  augustss 			    di->devmap[i] == -1)
    510   1.7  augustss 				return EINVAL;
    511   1.7  augustss 			mc.un.ord = di->devmap[i];
    512   1.7  augustss 		} else {
    513   1.7  augustss 			mc.type = AUDIO_MIXER_SET;
    514  1.11  augustss 			mc.un.mask = 0;
    515  1.10  augustss 			for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) {
    516   1.7  augustss 				if (idat & (1 << i)) {
    517   1.7  augustss 					if (di->devmap[i] == -1)
    518   1.7  augustss 						return EINVAL;
    519   1.7  augustss 					mc.un.mask |= 1 << di->devmap[i];
    520   1.7  augustss 				}
    521  1.10  augustss 			}
    522   1.7  augustss 		}
    523   1.7  augustss 		return ioctlf(fp, AUDIO_MIXER_WRITE, (caddr_t)&mc, p);
    524   1.6  augustss 	default:
    525   1.6  augustss 		if (OSS_MIXER_READ(OSS_SOUND_MIXER_FIRST) <= com &&
    526   1.6  augustss 		    com < OSS_MIXER_READ(OSS_SOUND_MIXER_NRDEVICES)) {
    527   1.6  augustss 			n = OSS_GET_DEV(com);
    528   1.7  augustss 			if (di->devmap[n] == -1)
    529   1.7  augustss 				return EINVAL;
    530   1.6  augustss 			mc.dev = di->devmap[n];
    531   1.6  augustss 			mc.type = AUDIO_MIXER_VALUE;
    532   1.6  augustss 		    doread:
    533   1.6  augustss 			mc.un.value.num_channels = di->stereomask & (1<<n) ? 2 : 1;
    534   1.6  augustss 			error = ioctlf(fp, AUDIO_MIXER_READ, (caddr_t)&mc, p);
    535   1.6  augustss 			if (error)
    536   1.6  augustss 				return error;
    537   1.6  augustss 			if (mc.type != AUDIO_MIXER_VALUE)
    538   1.6  augustss 				return EINVAL;
    539   1.6  augustss 			if (mc.un.value.num_channels != 2) {
    540   1.6  augustss 				l = r = mc.un.value.level[AUDIO_MIXER_LEVEL_MONO];
    541   1.6  augustss 			} else {
    542   1.6  augustss 				l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    543   1.6  augustss 				r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    544   1.6  augustss 			}
    545   1.6  augustss 			l = l * 100 / 255;
    546   1.6  augustss 			r = r * 100 / 255;
    547   1.6  augustss 			idat = l | (r << 8);
    548   1.6  augustss 			break;
    549   1.6  augustss 		} else if (OSS_MIXER_WRITE(OSS_SOUND_MIXER_FIRST) <= com &&
    550   1.6  augustss 			   com < OSS_MIXER_WRITE(OSS_SOUND_MIXER_NRDEVICES)) {
    551   1.6  augustss 			n = OSS_GET_DEV(com);
    552   1.7  augustss 			if (di->devmap[n] == -1)
    553   1.7  augustss 				return EINVAL;
    554   1.6  augustss 			error = copyin(SCARG(uap, data), &idat, sizeof idat);
    555   1.6  augustss 			if (error)
    556   1.6  augustss 				return error;
    557   1.6  augustss 			l = (idat & 0xff) * 255 / 100;
    558   1.6  augustss 			r = (idat >> 8) * 255 / 100;
    559   1.6  augustss 			mc.dev = di->devmap[n];
    560   1.6  augustss 			mc.type = AUDIO_MIXER_VALUE;
    561   1.6  augustss 			if (di->stereomask & (1<<n)) {
    562   1.6  augustss 				mc.un.value.num_channels = 2;
    563   1.6  augustss 				mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
    564   1.6  augustss 				mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
    565   1.6  augustss 			} else {
    566   1.6  augustss 				mc.un.value.num_channels = 1;
    567   1.6  augustss 				mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] = (l+r)/2;
    568   1.6  augustss 			}
    569   1.6  augustss 			error = ioctlf(fp, AUDIO_MIXER_WRITE, (caddr_t)&mc, p);
    570   1.6  augustss 			if (error)
    571   1.6  augustss 				return error;
    572   1.6  augustss 			goto doread;
    573   1.6  augustss 		} else
    574   1.6  augustss 			return EINVAL;
    575   1.6  augustss 	}
    576   1.6  augustss 	return copyout(&idat, SCARG(uap, data), sizeof idat);
    577   1.6  augustss }
    578   1.6  augustss 
    579   1.6  augustss /* XXX hook for sequencer emulation */
    580   1.3   mycroft int
    581   1.6  augustss oss_ioctl_sequencer(p, uap, retval)
    582   1.3   mycroft 	register struct proc *p;
    583   1.6  augustss 	register struct oss_sys_ioctl_args /* {
    584   1.3   mycroft 		syscallarg(int) fd;
    585   1.3   mycroft 		syscallarg(u_long) com;
    586   1.3   mycroft 		syscallarg(caddr_t) data;
    587   1.3   mycroft 	} */ *uap;
    588   1.3   mycroft 	register_t *retval;
    589   1.3   mycroft {
    590   1.3   mycroft 	register struct file *fp;
    591   1.3   mycroft 	register struct filedesc *fdp;
    592   1.6  augustss #if 0
    593   1.3   mycroft 	u_long com;
    594   1.3   mycroft 	int idat;
    595   1.3   mycroft 	int error;
    596   1.3   mycroft #endif
    597   1.3   mycroft 
    598   1.3   mycroft 	fdp = p->p_fd;
    599   1.3   mycroft 	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
    600   1.3   mycroft 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
    601   1.3   mycroft 		return (EBADF);
    602   1.3   mycroft 
    603   1.3   mycroft 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
    604   1.3   mycroft 		return (EBADF);
    605   1.3   mycroft 
    606   1.6  augustss #if 0
    607   1.3   mycroft 	com = SCARG(uap, com);
    608   1.6  augustss #endif
    609   1.3   mycroft 	retval[0] = 0;
    610   1.3   mycroft 
    611   1.6  augustss 	return EINVAL;
    612   1.1   mycroft }
    613