[alsa-devel] [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora

GNUtoo GNUtoo at no-log.org
Tue Jan 12 18:48:59 CET 2010

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.



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;

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;
xfer = count > frame->size ? frame->size : count;
if (copy_from_user(frame->data, buf, xfer)) {
rc = -EFAULT;
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;
spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
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->playback_substream = substream;
	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
		runtime->hw = msm_pcm_capture_hardware;
		prtd->capture_substream = substream;

	ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
	if (ret < 0) goto out;

	/* Ensure that buffer size is a multiple of period size */
	ret = snd_pcm_hw_constraint_integer(runtime,
	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;

	return ret;

More information about the Alsa-devel mailing list