Re: [linuxsh-dev] Re: [Alsa-devel] [PATCH] Add Dreamcast AICA driver to alsa-driver

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

 



At Mon, 24 Apr 2006 18:44:55 +0100,
Adrian McMenamin wrote:
> 
> > 
> > > +static int stereo_buffer_transfer(struct snd_pcm_substream
> > > +				  *substream, int buffer_size, int period)
> > > +{
> > 
> > I feel this transfer-and-wait could be done more efficiently using
> > workq than doing it in timer callback.  The trigger(start) and
> > aica_period_elapsed() calls queue_work() at each time.
> > 
> > The most work of spu_begin_dma() should be put in the workq, too.
> > 
> 
> heh. If you remember, a couple of months ago I had this in a kernel
> thread - ie much the same - and you or Lee said I should absolutely not
> use that mechanism :)

Well, a source code tell you better than hundreds words :)


> > You can write a single function for both mono and two-channel
> > streams.
> > 
> 
> How can I do that given the dma has to be serialised?

The second dma_xfer() can be in if (channels > 1) block (in addition
to different transfer bytes).  Something like below:

static int buffer_transfer(struct snd_pcm_substream*substream,
		int buffer_size, int period)
{
	int transferred;
	int dma_countout;
	struct snd_pcm_runtime *runtime;
	int period_offset;
	long dma_flags;

	period_offset = period;
	period_offset %= (AICA_PERIOD_NUMBER / runtime->channels);
	runtime = substream->runtime;
	/* transfer left and then right */
	dma_flags = claim_dma_lock();
	dma_countout = 0;
	dma_xfer(0,
		 runtime->dma_area + (AICA_PERIOD_SIZE * period_offset),
		 AICA_CHANNEL0_OFFSET +
		 (AICA_PERIOD_SIZE * period_offset), buffer_size / 2, 5);
	/* wait for completion */
	do {
		udelay(5);
		transferred = get_dma_residue(0);
		dma_countout++;
		if (dma_countout > 0x10000)
			break;	/* Approx 1/3 sec timeout in case of hardware failure */
	}
	while (transferred < buffer_size / 2);
	if (runtime->channels > 1) {
		dma_xfer(0,
			 AICA_BUFFER_SIZE / 2 + runtime->dma_area +
			 (AICA_PERIOD_SIZE * period_offset),
			 AICA_CHANNEL1_OFFSET +
			 (AICA_PERIOD_SIZE * period_offset), buffer_size / 2, 5);
		/* have to wait again */
		dma_countout = 0;
		do {
			udelay(5);
			transferred = get_dma_residue(0);
			dma_countout++;
			if (dma_countout > 0x10000)
				break;
		}
		while (transferred < buffer_size / 2);
	}
	release_dma_lock(dma_flags);
	return 0;
}


Takashi
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux