[alsa-devel] Ends up with write error

Ning Zhang ning.zhang06 at gmail.com
Wed Feb 20 09:30:54 CET 2008


Hi all,
I am writing a ALSA driver for my ARM 926 platform. The ARM communicates
with the DSP by accessing a 128-byte shared memory. I don't use IRQ
mechanism.(In fact, I am not sure the platform has this mechanism)
Here is some code slices:

static struct snd_pcm_hardware snd_arch_playback_hw = {

   .info = (SNDRV_PCM_INFO_MMAP |

            SNDRV_PCM_INFO_INTERLEAVED |

            SNDRV_PCM_INFO_BLOCK_TRANSFER),

   .formats = SNDRV_PCM_FMTBIT_S16_LE,

   .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\

             SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\

             SNDRV_PCM_RATE_48000),

   .rate_min = 8000,

   .rate_max = 48000,

   .channels_min = 2,

   .channels_max = 2,

   .buffer_bytes_max = 128,

   .period_bytes_min = 2,

   .period_bytes_max = 128,

   .periods_min = 1,

   .periods_max = 64,

};



static snd_pcm_uframes_t snd_arch_pcm_pointer(struct snd_pcm_substream

                                                *substream)

{    …

   /*

    * get the current hardware pointer

    */

   current_ptr = arch_fw_read_dsp_reg(chip, AFE_RWADDR) & AFE_RD_ADDR;


return bytes_to_frames(runtime, current_ptr);

}

static int snd_arch_pcm_playback_copy(struct snd_pcm_substream *substream,

                                        int channel,

                                        snd_pcm_uframes_t pos,

                                        void __user *src,

                                        snd_pcm_uframes_t count)

{  ……



   count = frames_to_bytes(runtime, count);

   pos = frames_to_bytes(runtime, pos);

   chip->bufpos = pos;

               ….

   spin_lock(chip->reg_lock);

   if ( count > 0 && count <= MAX_BUF_SIZE ) {

           if ( copy_from_user(chip->bufptr, src, count) ) {

                    snd_printk(KERN_ERR "can not copy user data!\n");

                    return -EFAULT;

           }

           if ( arch_fill_rx_buf(chip,

                                        (signed short*)(chip->bufptr),
count) < 0 ) {

                    snd_printk(KERN_ERR "fill rx buffer failed!\n");

                    return -1;

           }

             ……………

   }
           spin_unlock(chip->reg_lock);

   return 0;

}

The problem is my driver can make sounds, but ends up a write error.  After
much debugging, I think there might be some problem in the
interworking  between
middle-level driver and the device driver.

           I found the runtime->control->avail_min=32,  and the
runtime->buffer_size and runtime->period_size are both 32. So at first
middle-level driver call snd_pcm_lib_write1 transfers 32 frames(128 bytes)
to the device driver's copy callback function and trigger function.  Then
when middle-level driver wants to transfer another 32 frames, it calls the
pointer callback function and gets the position, because at this time the
whole bytes has not been processed completely, so the pointer function's
return value must less than 32, and the avail must less than
runtime->control_->avail_min, and goes to this flow and ends up a write
error.

_______________________________________________________________________________

if (((avail < runtime->control->avail_min && size > avail) ||

                     (size >= runtime->xfer_align && avail <
runtime->xfer_align))) {

                            ……………...

                          long tout;

                          init_waitqueue_entry(&wait, current);

                          add_wait_queue(&runtime->sleep, &wait);

                          while (1) {

                                   if (signal_pending(current)) {

                                            state = SIGNALED;

                                            break;

                                   }

                                   set_current_state(TASK_INTERRUPTIBLE);

                                   snd_pcm_stream_unlock_irq(substream);

                                   tout = schedule_timeout(10 * HZ);

                                   snd_pcm_stream_lock_irq(substream);

                                   if (tout == 0) {

                                            if (runtime->status->state !=
SNDRV_PCM_STATE_PREPARED &&

                                                runtime->status->state !=
SNDRV_PCM_STATE_PAUSED) {

                                                     state =
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;

                                                     break;

                                            }

                                   }

                                   switch (runtime->status->state) {

                                                                     …………..

                                   :

                                            state = ERROR;

                                            goto _end_loop;



                                   default:

                                            break;

                                   }

                                   avail = snd_pcm_playback_avail(runtime);

                                   if (avail >= runtime->control->avail_min)
{

                                            state = READY;

                                            break;

                                   }

                          }

                         _end_loop:

                          remove_wait_queue(&runtime->sleep, &wait);



                          switch (state) {

                          …….

                          case EXPIRED:

                                   snd_printd("playback write error (DMA or
IRQ trouble?)\n");

                                   err = -EIO;

                                   goto _end_unlock;

                          ………

                          }

                  }

This code is a  part of  snd_pcm_lib_write1() in sound/core/pcm_lib.c

 I think that I misunderstood the mechanism of middle-level driver. Could
you please correct me?

What should the pointer callback function return?  What's it  for?

How comes the runtime->control->avail_min?

Because I don't use the IRQ, so should I use the snd_pcm_period_elapsed
function? And where?

ALSA Version is 1.0.14rc1 and I use alsa-lib-1.0.15.

Can someone comment on this and give me some hints to solve this
problem?  Thanks
in advance.

 BRs,

David


More information about the Alsa-devel mailing list