Messages in this thread | | | Date | Mon, 24 Apr 2006 19:57:15 +0200 | From | Takashi Iwai <> | Subject | Re: [linuxsh-dev] Re: [Alsa-devel] [PATCH] Add Dreamcast AICA driver to alsa-driver |
| |
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 majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |