aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/azt3328.c
diff options
context:
space:
mode:
authorAndreas Mohr <andi@lisas.de>2010-12-27 15:17:35 -0500
committerTakashi Iwai <tiwai@suse.de>2011-01-02 05:11:38 -0500
commit689c69120ea3c8db069e11a7065ceffee90d0460 (patch)
tree8900047e2c2612df60d763de78e9b430ee96b59e /sound/pci/azt3328.c
parentda237f35a8a503fb8893fb3b9d0622a991bcebef (diff)
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 <andi@lisas.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/azt3328.c')
-rw-r--r--sound/pci/azt3328.c66
1 files changed, 51 insertions, 15 deletions
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 @@
175 175
176#include <asm/io.h> 176#include <asm/io.h>
177#include <linux/init.h> 177#include <linux/init.h>
178#include <linux/bug.h> /* WARN_ONCE */
178#include <linux/pci.h> 179#include <linux/pci.h>
179#include <linux/delay.h> 180#include <linux/delay.h>
180#include <linux/slab.h> 181#include <linux/slab.h>
@@ -421,6 +422,21 @@ snd_azf3328_codec_outl(const struct snd_azf3328_codec_data *codec,
421 outl(value, codec->io_base + reg); 422 outl(value, codec->io_base + reg);
422} 423}
423 424
425static inline void
426snd_azf3328_codec_outl_multi(const struct snd_azf3328_codec_data *codec,
427 unsigned reg, const void *buffer, int count
428)
429{
430 unsigned long addr = codec->io_base + reg;
431 if (count) {
432 const u32 *buf = buffer;
433 do {
434 outl(*buf++, addr);
435 addr += 4;
436 } while (--count);
437 }
438}
439
424static inline u32 440static inline u32
425snd_azf3328_codec_inl(const struct snd_azf3328_codec_data *codec, unsigned reg) 441snd_azf3328_codec_inl(const struct snd_azf3328_codec_data *codec, unsigned reg)
426{ 442{
@@ -1124,34 +1140,54 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip,
1124static void 1140static void
1125snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec, 1141snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec,
1126 unsigned long addr, 1142 unsigned long addr,
1127 unsigned int count, 1143 unsigned int period_bytes,
1128 unsigned int size 1144 unsigned int buffer_bytes
1129) 1145)
1130{ 1146{
1131 snd_azf3328_dbgcallenter(); 1147 snd_azf3328_dbgcallenter();
1148 WARN_ONCE(period_bytes & 1, "odd period length!?\n");
1149 WARN_ONCE(buffer_bytes != 2 * period_bytes,
1150 "missed our input expectations! %u vs. %u\n",
1151 buffer_bytes, period_bytes);
1132 if (!codec->running) { 1152 if (!codec->running) {
1133 /* AZF3328 uses a two buffer pointer DMA transfer approach */ 1153 /* AZF3328 uses a two buffer pointer DMA transfer approach */
1134 1154
1135 unsigned long flags, addr_area2; 1155 unsigned long flags;
1136 1156
1137 /* width 32bit (prevent overflow): */ 1157 /* width 32bit (prevent overflow): */
1138 u32 count_areas, lengths; 1158 u32 area_length;
1159 struct codec_setup_io {
1160 u32 dma_start_1;
1161 u32 dma_start_2;
1162 u32 dma_lengths;
1163 } __attribute__((packed)) setup_io;
1139 1164
1140 count_areas = size/2; 1165 area_length = buffer_bytes/2;
1141 addr_area2 = addr+count_areas;
1142 snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n",
1143 addr, count_areas, addr_area2, count_areas);
1144 1166
1145 count_areas--; /* max. index */ 1167 setup_io.dma_start_1 = addr;
1168 setup_io.dma_start_2 = addr+area_length;
1169
1170 snd_azf3328_dbgcodec(
1171 "setdma: buffers %08x[%u] / %08x[%u], %u, %u\n",
1172 setup_io.dma_start_1, area_length,
1173 setup_io.dma_start_2, area_length,
1174 period_bytes, buffer_bytes);
1175
1176 /* Hmm, are we really supposed to decrement this by 1??
1177 Most definitely certainly not: configuring full length does
1178 work properly (i.e. likely better), and BTW we
1179 violated possibly differing frame sizes with this...
1180
1181 area_length--; |* max. index *|
1182 */
1146 1183
1147 /* build combined I/O buffer length word */ 1184 /* build combined I/O buffer length word */
1148 lengths = (count_areas << 16) | (count_areas); 1185 setup_io.dma_lengths = (area_length << 16) | (area_length);
1186
1149 spin_lock_irqsave(codec->lock, flags); 1187 spin_lock_irqsave(codec->lock, flags);
1150 snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_1, addr); 1188 snd_azf3328_codec_outl_multi(
1151 snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_2, 1189 codec, IDX_IO_CODEC_DMA_START_1, &setup_io, 3
1152 addr_area2); 1190 );
1153 snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_LENGTHS,
1154 lengths);
1155 spin_unlock_irqrestore(codec->lock, flags); 1191 spin_unlock_irqrestore(codec->lock, flags);
1156 } 1192 }
1157 snd_azf3328_dbgcallleave(); 1193 snd_azf3328_dbgcallleave();