Hi all, There is no response so far, maybe I am not clear. So in sum, here are the questions: 1. In meddle-level driver, how comes the runtime->control->avail_min? I mean which function set the value, and according what to set the value? Does it have some relationship to the hardware configuration in the device driver( i.e snd_pcm_hardware )? 2. Should I use the snd_pcm_period_elapsed function even I don't use the interrupt mechanism? If yes, In which callback function should I call it(snd_pcm_period_elapsed)? 3,Can anybody do me a favor to explain the mechanism of the middle-level driver or give me some hints? Thanks in advance. BRs, David > > ------------------------------ > > Message: 7 > Date: Wed, 20 Feb 2008 16:30:54 +0800 > From: "Ning Zhang" <ning.zhang06@xxxxxxxxx> > Subject: Ends up with write error > To: alsa-devel <alsa-devel@xxxxxxxxxxxxxxxx> > Message-ID: > <48a1cba90802200030v65794b96j7c956406fdc0df9c@xxxxxxxxxxxxxx> > Content-Type: text/plain; charset=GB2312 > > 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 > > ------------------------------ > > _______________________________________________ > Alsa-devel mailing list > Alsa-devel@xxxxxxxxxxxxxxxx > http://mailman.alsa-project.org/mailman/listinfo/alsa-devel > > > End of Alsa-devel Digest, Vol 12, Issue 69 > ****************************************** > _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel