Re: Driver design question

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

 



At Thu, 19 Oct 2006 18:12:30 -0400,
Lee Revell wrote:
> 
> On Wed, 2006-10-04 at 11:17 +0200, Takashi Iwai wrote:
> > At Tue, 03 Oct 2006 11:35:22 -0400,
> > Lee Revell wrote:
> > > 
> > > On Fri, 2006-09-29 at 22:03 -0400, Lee Revell wrote:
> > > > pcm-indirect.h:
> > > > 
> > > >  90  */
> > > >  91 static inline snd_pcm_uframes_t
> > > >  92 snd_pcm_indirect_playback_pointer(snd_pcm_substream_t *substream,
> > > >  93                                   snd_pcm_indirect_t *rec,
> > > > unsigned int ptr)
> > > >  94 {
> > > > 
> > > > [ ... ]
> > > > 
> > > > 103         if (substream->ops->ack)
> > > > 104                 substream->ops->ack(substream);
> > > > 
> > > > But, this cannot work with our hardware, if the ack callback always
> > > > transfers 0x2000 words from the hardware, because the pointer callback
> > > > is invoked many times per period.
> > > 
> > > If the ack callback is called many times per period, but our hardware
> > > only supports writing in chunks of 0x2000 words, how can we copy to the
> > > hardware from the ack callback as you recommend without using an
> > > intermediate buffer?
> > 
> > I thought you don't have to write 0x2000 words at once but in a loop?
> > Look at dream_playback_copy().  It has bytes argument.  That specifies
> > the size to copy.  Setting snd_pcm_indirect.hw_buffer_size = 0x4000
> > should restrict the max size to be written to 0x2000 words.
> > 
> 
> Is there any way to force the upper layers to only ever transfer 0x2000
> words - no more, no less?  I think the hardware gets unhappy if they are
> not all transferred quickly.

It's easy to fix this.  An untested patch is below.

> Anyway, I still can't make it work with the PCM indirect API.  The best
> I've managed to produce is choppy sound that seems to underrun every
> period.  Do you see what could be wrong with my code?

You should give a fixed period size (0x2000), i.e. set both
period_bytes_min and period_bytes_max = 0x4000 (and periods_min = 2) in
snd_pcm_hardware.  In this way, the ack is called at least at each
time 0x2000 words are processed.

BTW, what does dream_get_mpu_data_poll_status_byte() do?
Does it check whether you can another push 0x2000 words?

If so, you should check this before claling
snd_pcm_indirect_playback_transfer() in dream_work_transfer().

static void dream_work_transfer(void *data)
{
	struct snd_card_dream *dream = data;
	snd_pcm_substream_t *substream = dream->playback_substream;
	struct snd_card_dream_pcm *dpcm = substream->runtime->private_data;
	if (!substream)
		return;

	if (dpcm->running &&
	    dream_get_mpu_data_poll_status_byte(dream, 
		&dream->midi2, MPU401_IT_MASK, MPU401_IT_VALUE, 100) < 0)
                return;

	snd_pcm_indirect_playback_transfer(substream,
		&dream->playback_rec, dream_playback_copy);
}

Possibly, the block transfer patch might be not needed if you add this
check.

Also, to avoid the restriction of period_size, you'll need the
implementation of asynchronous background transfer, e.g. by polling at
each timer interrupt (suppose the polling is atomic and fast) then 
scheduling the transfer work immediately if the space is available.

static void snd_card_dream_pcm_timer_function(unsigned long data)
{
	...

        dream->playback_size += size;
        if (dream->playback_size >= runtime->period_size) {
                dream->playback_size %= runtime->period_size;
                snd_pcm_period_elapsed(dpcm->substream);
        } else if (dpcm->running) {
		if (!dream_get_mpu_data_poll_status_byte(dream, 
			 &dream->midi2, MPU401_IT_MASK, MPU401_IT_VALUE, 100)) 
			/* async transfer */
			schedule_work(&dream->playback_work);
	}

        dpcm->timer.expires = 1 + jiffies;
        add_timer(&dpcm->timer);
}

The polling isn't necessary at each timer interrupt, but can be each
0x2000 words, instead, though.


Takashi


diff -r d7fe584f7395 include/pcm-indirect.h
--- a/include/pcm-indirect.h	Thu Oct 19 20:35:56 2006 +0200
+++ b/include/pcm-indirect.h	Fri Oct 20 12:27:41 2006 +0200
@@ -27,6 +27,7 @@ struct snd_pcm_indirect {
 struct snd_pcm_indirect {
 	unsigned int hw_buffer_size;	/* Byte size of hardware buffer */
 	unsigned int hw_queue_size;	/* Max queue size of hw buffer (0 = buffer size) */
+	unsigned int hw_xfer_block;	/* transfer alignment (0 = unaligned) */
 	unsigned int hw_data;	/* Offset to next dst (or src) in hw ring buffer */
 	unsigned int hw_io;	/* Ring buffer hw pointer */
 	int hw_ready;		/* Bytes ready for play (or captured) in hw ring buffer */
@@ -72,6 +73,11 @@ snd_pcm_indirect_playback_transfer(struc
 			bytes = sw_to_end;
 		if (! bytes)
 			break;
+		if (rec->hw_xfer_block) {
+			if (bytes < rec->hw_xfer_block)
+				break;
+			bytes = rec->hw_xfer_block;
+		}
 		copy(substream, rec, bytes);
 		rec->hw_data += bytes;
 		if (rec->hw_data == rec->hw_buffer_size)
@@ -137,6 +143,11 @@ snd_pcm_indirect_capture_transfer(struct
 			bytes = sw_to_end;
 		if (! bytes)
 			break;
+		if (rec->hw_xfer_block) {
+			if (bytes < rec->hw_xfer_block)
+				break;
+			bytes = rec->hw_xfer_block;
+		}
 		copy(substream, rec, bytes);
 		rec->hw_data += bytes;
 		if ((int)rec->hw_data == rec->hw_buffer_size)

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/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