Ends up with write error

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi all,I am writing a ALSA driver for my ARM 926 platform. The ARM communicateswith the DSP by accessing a 128-byte shared memory. I don't use IRQmechanism.(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.  Aftermuch debugging, I think there might be some problem in theinterworking  betweenmiddle-level driver and the device driver.
           I found the runtime->control->avail_min=32,  and theruntime->buffer_size and runtime->period_size are both 32. So at firstmiddle-level driver call snd_pcm_lib_write1 transfers 32 frames(128 bytes)to the device driver's copy callback function and trigger function.  Thenwhen middle-level driver wants to transfer another 32 frames, it calls thepointer callback function and gets the position, because at this time thewhole bytes has not been processed completely, so the pointer function'sreturn value must less than 32, and the avail must less thanruntime->control_->avail_min, and goes to this flow and ends up a writeerror.
_______________________________________________________________________________
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 orIRQ 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. Couldyou 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_elapsedfunction? 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 thisproblem?  Thanksin advance.
 BRs,
David_______________________________________________Alsa-devel mailing listAlsa-devel@xxxxxxxxxxxxxxxxxxxx://mailman.alsa-project.org/mailman/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux