From mboxrd@z Thu Jan 1 00:00:00 1970 From: Takashi Iwai Subject: Re: Help needed. (long) Date: Mon, 19 May 2003 18:34:42 +0200 Sender: alsa-devel-admin@lists.sourceforge.net Message-ID: References: <20030519024010.3367.h002.c012.wm@mail.icqmail.com.criticalpath.net> Mime-Version: 1.0 (generated by SEMI 1.14.4 - "Hosorogi") Content-Type: text/plain; charset=US-ASCII Return-path: In-Reply-To: <20030519024010.3367.h002.c012.wm@mail.icqmail.com.criticalpath.net> Errors-To: alsa-devel-admin@lists.sourceforge.net List-Help: List-Post: List-Subscribe: , List-Unsubscribe: , List-Archive: To: Eliot Blennerhassett Cc: alsa-devel@lists.sourceforge.net, eliot@blennerhassett.gen.nz List-Id: alsa-devel@alsa-project.org At Mon, 19 May 2003 02:40:08 -0700 (PDT), Eliot Blennerhassett wrote: > > Greetings, > > (Aside: I still can only post to this list via a web mailer, so apologies if the > formatting is messed up. Still looking for a way to find out what is wrong with > my POP mailer. > Also I'd like to attach a file, but I cant...) > > Whereas I have pressed the reset button for the Nth time, > Whereas I have little experience in driver writing, > Whereas I am going around in circles, > > Therefore, I have resolved to swallow my pride and subject my code to the > scrutiny of my superiors (in terms of ALSA driver knowledge at least...) > > If there is someone out there who can answer the following questions, and is > also interested and able in developing the driver further in exchange for an > AudioScience card (6114, 6122, or 5111)please let me know. > > 1) Am I understanding this correctly? > I see this kind of sequence: > prepare > copy > copy > copy > trigger(start) > > (driver calls period_elapsed) > pointer > copy > pointer > pointer > copy > pointer > pointer > pointer > trigger(stop) > > > The middle-layer expects that the pointer will be increasing (modulo the buffer > size). > It expects that it should have increased by (at least) the period every time > snd_pcm_period_elapsed is called. yes. in other words, snd_pcm_period_elapsed() is called after the period size or more size is consumed since the last call of snd_pcm_period_elapsed(). > When the middle-layer enters the draining state, the copy callback isn't called > any more. > What is supposed to happen to the pointer now, and how many more times is > period_elapsed expected to be called? the pointer should return the currently played buffer-position. (or, at least, the lastly-processed period-position if no accurate positioing is supported by the hardware.) copy callback is an alternative to copy_from/to_user(). thus, copy callback is independent on the state of DAC/ADC. the drain function waits for all pending periods on the buffer are processed. that is, you have to call period_elapsed() at most [pending buffer size / period size] times. > I ask because on our cards when data runs out, the 'pointer' stops moving. > When this happens, and I don't call period_elapsed, then aplay hangs for a while > before erroring out - "failed to exit drained state" it might depend on the implementation of pointer callback... let us see... > ========================== > > What I am basically trying to do is translate the following into the PCM > playback part of an ALSA driver. > > > wHE = HPI_OutStreamGetInfoEx( phSubSys, pOS->hOutStream, > &wState, &dwBufferSize, > &dwBytesToPlay, &dwSamplesPlayed, NULL); > > Data.dwpbData = (HW32)&dataBuffer; > > while((dwBytesToPlay<(dwBufferSize-BLOCK_SIZE))) > { > dwBytesRead=read_some_data(&dataBuffer); > Data.dwDataSize = dwBytesRead; > wHE = HPI_OutStreamWrite( phSubSys, pOS->hOutStream, &Data); > wHE = HPI_OutStreamGetInfo( phSubSys, pOS->hOutStream, > &wState, &dwBufferSize, &dwBytesToPlay); > > } > > > Notes: > wXxxx is 16 bit data, dwXxxx is 32 bit. > > wState: STOPPED, PLAYING, DRAINED=ran out of data. > dwBufferSize typically 500K to 1Mbyte > Data is a struct that contains a pointer to data buffer, size of data, and > format info. > > Our cards have no interrupts, and no DMA (...yet. The next one probably will) so > they must be polled. hmm, no interrupts at all? > Based on the dummy driver, I am using a timer to do the polling. > So far, it does play audio, but often crashes or locks the machine solid with a > kernel panic. perhaps the interrupt takes too long time? for a pseudo-DMA transfer, tasklet may be a better choice. > I need help with the subtleties, and any tips on how to debug this kind of > problem ;-) > > static void snd_card_asihpi_pcm_timer_function(unsigned long data) > { > snd_card_asihpi_pcm_t *dpcm = snd_magic_cast(snd_card_asihpi_pcm_t, (void > *)data, return); > snd_pcm_runtime_t *runtime = dpcm->substream->runtime; > > unsigned int pos; > int delta; > HW16 wState,err; > HW32 dwBufferSize; > HW32 dwDataToPlay; > HW32 dwSamplesPlayed; > > dpcm->timer.expires = 1 + jiffies; > add_timer(&dpcm->timer); > spin_lock_irq(&dpcm->lock); > > err= HPI_OutStreamGetInfoEx(phSubSys,dpcm->hStream, > &wState, > &dwBufferSize, > &dwDataToPlay, > &dwSamplesPlayed, > NULL); > HPI_HandleError( err ); > // if ((wState== HPI_STATE_DRAINED)) > // snd_pcm_stop(dpcm->substream, SNDRV_PCM_STATE_SETUP); > > pos = frames_to_bytes(runtime, dwSamplesPlayed); > pos %= dpcm->pcm_size; > delta = pos - dpcm->pcm_buf_pos; > dpcm->pcm_buf_pos = pos; > if (delta < 0) delta += dpcm->pcm_size; > > dpcm->pcm_irq_pos += delta; > > if (dpcm->pcm_irq_pos >= dpcm->pcm_count) { > dpcm->pcm_irq_pos %= dpcm->pcm_count; > snd_pcm_period_elapsed(dpcm->substream); > } > > spin_unlock_irq(&dpcm->lock); > } > > static snd_pcm_uframes_t snd_card_asihpi_playback_pointer(snd_pcm_substream_t * > substream) > { > snd_pcm_runtime_t *runtime = substream->runtime; > snd_card_asihpi_pcm_t *dpcm = snd_magic_cast(snd_card_asihpi_pcm_t, > runtime->private_data, return -ENXIO); > > snd_printd(KERN_INFO "playback pointer\n"); > > return bytes_to_frames(runtime, dpcm->pcm_buf_pos); > } > > > static int snd_card_asihpi_playback_copy( > snd_pcm_substream_t *substream, int channel, > snd_pcm_uframes_t pos, > void *src, > snd_pcm_uframes_t count) > { > snd_pcm_runtime_t *runtime = substream->runtime; > snd_card_asihpi_pcm_t *dpcm = snd_magic_cast(snd_card_asihpi_pcm_t, > runtime->private_data, return -ENXIO); > HW16 err; > unsigned int len; > > len = frames_to_bytes(runtime, count); > > if (copy_from_user(runtime->dma_area, src, len)) > return -EFAULT; > > dpcm->Data.dwDataSize = len; > dpcm->Data.dwpbData = (HW32)runtime->dma_area; > > err = HPI_OutStreamWrite(phSubSys,dpcm->hStream,&dpcm->Data); > return 0; > } > > > Is this an appropriate way to structure the driver? the code avoe looks ok for me. is the timer callback called after trigger(stop) is called, too? if it's called, the pointer callback must increase (as long as dwSamplesPlayed increases)... Takashi ------------------------------------------------------- This SF.net email is sponsored by: If flattening out C++ or Java code to make your application fit in a relational database is painful, don't do it! Check out ObjectStore. Now part of Progress Software. http://www.objectstore.net/sourceforge