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: