[alsa-devel] Ends up with write error (Ning Zhang)
Ning Zhang
ning.zhang06 at gmail.com
Sun Feb 24 11:18:34 CET 2008
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 at gmail.com>
> Subject: [alsa-devel] Ends up with write error
> To: alsa-devel <alsa-devel at alsa-project.org>
> Message-ID:
> <48a1cba90802200030v65794b96j7c956406fdc0df9c at mail.gmail.com>
> 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 at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
>
> End of Alsa-devel Digest, Vol 12, Issue 69
> ******************************************
>
More information about the Alsa-devel
mailing list