maestro3.c bug using SNDCTL_DSP_SYNC ioctl in 2.4.22

From: Neal H. Walfield
Date: Sat Nov 22 2003 - 18:37:32 EST


I recently acquired a Dell Latitude CPx 650 with a maestro3 chip.
With the 2.4.22 verion of the linux kernel (specifically 2.4.22-1-686
as distributed by Debian), I encountered some problems with the
SNDCTL_DSP_SYNC ioctl which is used, for example, by madplay [1]. On
startup, madplay calls the SNDCTL_DSP_SYNC ioctl. This causes no
problems until I interrupt madplay using control-C. If the next
operation is the SNDCTL ioctl (e.g. by starting madplay) then the
caller will hang waiting for the ioctl to return (this is easily seen
using strace). As far as I can tell, the driver hangs in
drain_dac()'s for loop waiting for s->dma_dac.count to drop to zero
which it never does. I can use control-C to interrupt it and madplay
will exit. Subsequent runs of madplay exhibit the same problem. On
the other hand, if I use another audio program such as gnome-vlc
(which strace indicates does not call the ioctl in question), it is
able to use the audio successfully. After exiting from gnome-vlc,
madplay will again work (however, hitting control-C and attempting to
start madplay again will cause it to exhibit the same hang). The
following work around allows me to use madplay successfully:

--- maestro3.c.orig Sat Aug 30 02:01:42 2003
+++ maestro3.c Sat Nov 22 15:52:16 2003
@@ -1291,7 +1291,7 @@ static int drain_dac(struct m3_state *s,
int count;
signed long tmo;

- if (s->dma_dac.mapped || !s->dma_dac.ready)
+ if (s->dma_dac.mapped || !s->dma_dac.ready || !(s->enable & DAC_RUNNING))
return 0;
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->dma_dac.wait, &wait);


If drain_dac ought to work even if the card is not enabled, then maybe
this patch is better:

--- maestro3.c.orig Sat Nov 22 15:52:16 2003
+++ maestro3.c Sat Nov 22 18:13:25 2003
@@ -1594,7 +1594,7 @@ static int m3_ioctl(struct inode *inode,
return put_user(SOUND_VERSION, (int *)arg);

case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
+ if ((file->f_mode & FMODE_WRITE) && !(s->enable & DAC_RUNNING))
return drain_dac(s, file->f_flags & O_NONBLOCK);
return 0;


I have no idea if either of these are correct fix. There may, for
instance, be unaccounted dma packets that need cleaning up; I haven't
looked that deeply into the code to be able to tell.

Thanks.


[1] http://www.underbit.com/products/mad/
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/