From 689c69120ea3c8db069e11a7065ceffee90d0460 Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Mon, 27 Dec 2010 21:17:35 +0100 Subject: ALSA: azt3328: improve snd_azf3328_codec_setdmaa() - add some WARN_ONCE - add multi-I/O helper (and use helper struct) - fix off-by-1 DMA length bug - better variable naming Signed-off-by: Andreas Mohr Signed-off-by: Takashi Iwai --- sound/pci/azt3328.c | 66 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 15 deletions(-) (limited to 'sound/pci/azt3328.c') diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 76ff5fdb4838..6117595fc075 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -175,6 +175,7 @@ #include #include +#include /* WARN_ONCE */ #include #include #include @@ -421,6 +422,21 @@ snd_azf3328_codec_outl(const struct snd_azf3328_codec_data *codec, outl(value, codec->io_base + reg); } +static inline void +snd_azf3328_codec_outl_multi(const struct snd_azf3328_codec_data *codec, + unsigned reg, const void *buffer, int count +) +{ + unsigned long addr = codec->io_base + reg; + if (count) { + const u32 *buf = buffer; + do { + outl(*buf++, addr); + addr += 4; + } while (--count); + } +} + static inline u32 snd_azf3328_codec_inl(const struct snd_azf3328_codec_data *codec, unsigned reg) { @@ -1124,34 +1140,54 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, static void snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec, unsigned long addr, - unsigned int count, - unsigned int size + unsigned int period_bytes, + unsigned int buffer_bytes ) { snd_azf3328_dbgcallenter(); + WARN_ONCE(period_bytes & 1, "odd period length!?\n"); + WARN_ONCE(buffer_bytes != 2 * period_bytes, + "missed our input expectations! %u vs. %u\n", + buffer_bytes, period_bytes); if (!codec->running) { /* AZF3328 uses a two buffer pointer DMA transfer approach */ - unsigned long flags, addr_area2; + unsigned long flags; /* width 32bit (prevent overflow): */ - u32 count_areas, lengths; + u32 area_length; + struct codec_setup_io { + u32 dma_start_1; + u32 dma_start_2; + u32 dma_lengths; + } __attribute__((packed)) setup_io; - count_areas = size/2; - addr_area2 = addr+count_areas; - snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n", - addr, count_areas, addr_area2, count_areas); + area_length = buffer_bytes/2; - count_areas--; /* max. index */ + setup_io.dma_start_1 = addr; + setup_io.dma_start_2 = addr+area_length; + + snd_azf3328_dbgcodec( + "setdma: buffers %08x[%u] / %08x[%u], %u, %u\n", + setup_io.dma_start_1, area_length, + setup_io.dma_start_2, area_length, + period_bytes, buffer_bytes); + + /* Hmm, are we really supposed to decrement this by 1?? + Most definitely certainly not: configuring full length does + work properly (i.e. likely better), and BTW we + violated possibly differing frame sizes with this... + + area_length--; |* max. index *| + */ /* build combined I/O buffer length word */ - lengths = (count_areas << 16) | (count_areas); + setup_io.dma_lengths = (area_length << 16) | (area_length); + spin_lock_irqsave(codec->lock, flags); - snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_1, addr); - snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_2, - addr_area2); - snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_LENGTHS, - lengths); + snd_azf3328_codec_outl_multi( + codec, IDX_IO_CODEC_DMA_START_1, &setup_io, 3 + ); spin_unlock_irqrestore(codec->lock, flags); } snd_azf3328_dbgcallleave(); -- cgit v1.2.2