Subject: kern/3356: Linus audio emulation is incomplete
To: None <gnats-bugs@gnats.netbsd.org>
From: Lennart Augustsson <augustss@cs.chalmers.se>
List: netbsd-bugs
Date: 03/18/1997 23:35:45
>Number:         3356
>Category:       kern
>Synopsis:       Linus audio emulation is incomplete
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Mar 18 14:50:01 1997
>Last-Modified:
>Originator:     Lennart Augustsson
>Organization:
Department of Computing Science, Chalmers University
>Release:        NetBSD-current 970318
>Environment:
System: NetBSD calvin.cs.chalmers.se 1.2D NetBSD 1.2D (CALVIN) #129: Tue Mar 18 23:19:29 MET 1997 augustss@calvin.cs.chalmers.se:/usr/src/sys/arch/i386/compile/CALVIN i386


>Description:
	The Linux audio emulation lacks one crucial ioctl for
	raplayer (the Real Audio player) to work.  It is a simple one
	that sets the number of channels.  (Linux provides two
	different calls for this operation; we had the other one.)
>How-To-Repeat:
	Try raplayer.
>Fix:
	The patch below fixes that problem and prepares for adding
	mixer ioctl which are completely lacking.  I plan to send a
	PR with those later when I've integrated them properly.

	After applying these patches raplayer works, but it sounds
	pretty bad.  This is because netbsd handles writes to the
	audio device differently than other OSes.  A write which
	is not a multiple of the blocksize is padded with silence.
	In my mind this is a very non-intuitive and silly behaviour.
	I'll send another PR with a fix ASAP.

diff -c -r /usr/src/sys/compat/linux/old/linux_audio.c /usr/src/sys/compat/linux/linux_audio.c
*** /usr/src/sys/compat/linux/old/linux_audio.c	Fri Oct 18 13:19:54 1996
--- /usr/src/sys/compat/linux/linux_audio.c	Tue Mar 18 23:18:08 1997
***************
*** 88,93 ****
--- 88,109 ----
  		if (error)
  			return error;
  		break;
+ 	case LINUX_SOUND_PCM_WRITE_CHANNELS:
+ 		AUDIO_INITINFO(&tmpinfo);
+ 		error = copyin(SCARG(uap, data), &idat, sizeof idat);
+ 		if (error)
+ 			return error;
+ 		tmpinfo.play.channels =
+ 		tmpinfo.record.channels = 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.channels;
+ 		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)
***************
*** 165,168 ****
--- 181,217 ----
  	}
  
  	return 0;
+ }
+ 
+ int
+ linux_ioctl_mixer(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;
+ {	       
+ #if 0
+ /* use this with mixer emulation */
+ 	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;
+ #endif
+         return EINVAL;
  }
diff -c -r /usr/src/sys/compat/linux/old/linux_audio.h /usr/src/sys/compat/linux/linux_audio.h
*** /usr/src/sys/compat/linux/old/linux_audio.h	Fri Mar  8 13:25:29 1996
--- /usr/src/sys/compat/linux/linux_audio.h	Tue Mar 18 22:32:47 1997
***************
*** 17,22 ****
--- 17,23 ----
  #define	LINUX_SNDCTL_DSP_STEREO		_LINUX_IOWR('P', 3, int)
  #define	LINUX_SNDCTL_DSP_GETBLKSIZE	_LINUX_IOWR('P', 4, int)
  #define	LINUX_SNDCTL_DSP_SETFMT		_LINUX_IOWR('P', 5, int)
+ #define	LINUX_SOUND_PCM_WRITE_CHANNELS	_LINUX_IOWR('P', 6, int)
  #define	LINUX_SNDCTL_DSP_POST		_LINUX_IO('P', 8)
  #define	LINUX_SNDCTL_DSP_SETFRAGMENT	_LINUX_IOWR('P', 10, int)
  #define	LINUX_SNDCTL_DSP_GETFMTS	_LINUX_IOR('P', 11, int)
diff -c -r /usr/src/sys/compat/linux/old/linux_ioctl.c /usr/src/sys/compat/linux/linux_ioctl.c
*** /usr/src/sys/compat/linux/old/linux_ioctl.c	Fri Apr  5 14:35:22 1996
--- /usr/src/sys/compat/linux/linux_ioctl.c	Tue Mar 18 22:32:47 1997
***************
*** 68,73 ****
--- 68,75 ----
  	} */ *uap = v;
  
  	switch (LINUX_IOCGROUP(SCARG(uap, com))) {
+ 	case 'M':
+ 		return linux_ioctl_mixer(p, uap, retval);
  	case 'P':
  		return linux_ioctl_audio(p, uap, retval);
  	case 'T':
diff -c -r /usr/src/sys/compat/linux/old/linux_ioctl.h /usr/src/sys/compat/linux/linux_ioctl.h
*** /usr/src/sys/compat/linux/old/linux_ioctl.h	Fri Apr  5 14:35:23 1996
--- /usr/src/sys/compat/linux/linux_ioctl.h	Tue Mar 18 22:32:47 1997
***************
*** 37,42 ****
--- 37,44 ----
  struct linux_sys_ioctl_args;
  int linux_ioctl_audio __P((struct proc *, struct linux_sys_ioctl_args *,
      register_t *));
+ int linux_ioctl_mixer __P((struct proc *, struct linux_sys_ioctl_args *,
+     register_t *));
  int linux_machdepioctl __P((struct proc *, void *, register_t *));
  int linux_ioctl_termios __P((struct proc *, struct linux_sys_ioctl_args *,
      register_t *));
>Audit-Trail:
>Unformatted: