Recently I looked again at the code. And I found this:
prtd->out[0].used = BUF_INVALID_LEN; prtd->out_head = 1; /* point to second buffer on startup */
in msm_pcm_open in msm7k-pcm.c
So here how it works: when the sound card is opened the fist buffer is assigned to BUF_INVALID_LEN and is skipped(prtd->out_head = 1).
Then at a point alsa_send_buffer (in msm-pcm.c) is called. But because mplayer uses a bigger buffer it goes this way: The first run goes fine: rc = wait_event_interruptible(the_locks.write_wait, (frame->used == 0) || (prtd->stopped)); is passed. Then in "xfer = count > frame->size ? frame->size : count;",the minimum between frame size and count is assigned to xfer. Then in copy_from_user(frame->data, buf, xfer) the audio frame is copied from userspace. Then xfer is assigned to frame->used Then "prtd->out_head ^= 1;" needs some little explanations: There are 2 buffers prtd->out[0] and prtd->out[1] And both out_head and out_tail can only be 0 or 1 So when prtd->out_head is 0,prtd->out_head ^= 1 changes to 1 into a 0 and vice versa.
Note that I recently changed things like frame = prtd->out + prtd->out_tail into that kind of things: frame = &prtd->out[prtd->out_tail] which makes it more Readable,and still works.
prtd->out is a struct buffer which is described in msm-pcm.h: struct msm_audio { struct buffer out[2]; ...
the struct buffer is also described in msm-pcm.h like this: struct buffer { void *data; unsigned size; unsigned used; unsigned addr; };
So...prtd->out_head was 1 because it was assigned to 1 in msm_pcm_open in msm7k-pcm.c Now it becomes 0
Then it does that: count -= xfer; which doesn't zero count it because mplayer used some big buffer size
Then it sends the data to the dsp...and doesn't exit the "while (count > 0) {" loop because count is not 0
And Finally it reaches that line a second time: "rc = wait_event_interruptible(the_locks.write_wait, (frame->used == 0) || (prtd->stopped));" But...frame->used was, and is still BUF_INVALID_LEN so it blocks.
By the way David Lanzendörfer fixed a lot of issues with kernel oops/panic with the OSS emulation...and merged the adsp and the alsa layer in one driver(that means that they are in a same directory and that the resource sharing issues is gone.)
I bet we are close to something working as mplayer can now work trough oss emulation or trough sdl(tough there are some buffer underrun problem sometimes with sdl and nearly all the time with oss) But we still have some work to do in order to clean the driver and fix the issues you described before re-submiting it.
Denis.
Appendix: ---------
here's the content of alsa_send_buffer: size_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf, size_t count, loff_t *pos) { unsigned long flag; const char __user *start = buf; struct buffer *frame; size_t xfer; int rc = 0;
mutex_lock(&the_locks.write_lock); while (count > 0) { frame = &prtd->out[prtd->out_head]; rc = wait_event_interruptible(the_locks.write_wait, (frame->used == 0) || (prtd->stopped)); if (rc < 0) break; if (prtd->stopped) { rc = -EBUSY; break; } xfer = count > frame->size ? frame->size : count; if (copy_from_user(frame->data, buf, xfer)) { rc = -EFAULT; break; } frame->used = xfer; prtd->out_head ^= 1; count -= xfer; buf += xfer;
spin_lock_irqsave(&the_locks.write_dsp_lock, flag); frame = &prtd->out[prtd->out_tail]; if (frame->used && prtd->out_needed) { audio_dsp_send_buffer(prtd, prtd->out_tail, frame->used); prtd->out_tail ^= 1; prtd->out_needed--; } spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag); } mutex_unlock(&the_locks.write_lock); if (buf > start) return buf - start; return rc;
And here's the content of msm_pcm_open:
static int msm_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct msm_audio *prtd; int ret = 0;
prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL); if (prtd == NULL) { ret = -ENOMEM; return ret; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { msm_vol_ctl.update = 1; /* Update Volume, with Cached value */ runtime->hw = msm_pcm_playback_hardware; prtd->dir = SNDRV_PCM_STREAM_PLAYBACK; prtd->playback_substream = substream; } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { runtime->hw = msm_pcm_capture_hardware; prtd->dir = SNDRV_PCM_STREAM_CAPTURE; prtd->capture_substream = substream; }
ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_sample_rates); if (ret < 0) goto out;
/* Ensure that buffer size is a multiple of period size */ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto out;
prtd->ops = &snd_msm_audio_ops; prtd->out[0].used = BUF_INVALID_LEN; prtd->out_head = 1; /* point to second buffer on startup */ runtime->private_data = prtd;
ret = alsa_adsp_configure(prtd); if (ret) goto out; copy_count = 0; return 0;
out: kfree(prtd); return ret; }