1 /* 2 * Routines for GF1 DMA control 3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 4 * 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <asm/dma.h> 23 #include <linux/slab.h> 24 #include <sound/core.h> 25 #include <sound/gus.h> 26 27 static void snd_gf1_dma_ack(struct snd_gus_card * gus) 28 { 29 unsigned long flags; 30 31 spin_lock_irqsave(&gus->reg_lock, flags); 32 snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL, 0x00); 33 snd_gf1_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL); 34 spin_unlock_irqrestore(&gus->reg_lock, flags); 35 } 36 37 static void snd_gf1_dma_program(struct snd_gus_card * gus, 38 unsigned int addr, 39 unsigned long buf_addr, 40 unsigned int count, 41 unsigned int cmd) 42 { 43 unsigned long flags; 44 unsigned int address; 45 unsigned char dma_cmd; 46 unsigned int address_high; 47 48 // snd_printk("dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n", addr, (long) buf, count); 49 50 if (gus->gf1.dma1 > 3) { 51 if (gus->gf1.enh_mode) { 52 address = addr >> 1; 53 } else { 54 if (addr & 0x1f) { 55 snd_printd("snd_gf1_dma_transfer: unaligned address (0x%x)?\n", addr); 56 return; 57 } 58 address = (addr & 0x000c0000) | ((addr & 0x0003ffff) >> 1); 59 } 60 } else { 61 address = addr; 62 } 63 64 dma_cmd = SNDRV_GF1_DMA_ENABLE | (unsigned short) cmd; 65 #if 0 66 dma_cmd |= 0x08; 67 #endif 68 if (dma_cmd & SNDRV_GF1_DMA_16BIT) { 69 count++; 70 count &= ~1; /* align */ 71 } 72 if (gus->gf1.dma1 > 3) { 73 dma_cmd |= SNDRV_GF1_DMA_WIDTH16; 74 count++; 75 count &= ~1; /* align */ 76 } 77 snd_gf1_dma_ack(gus); 78 snd_dma_program(gus->gf1.dma1, buf_addr, count, dma_cmd & SNDRV_GF1_DMA_READ ? DMA_MODE_READ : DMA_MODE_WRITE); 79 #if 0 80 snd_printk("address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n", address << 1, count, dma_cmd); 81 #endif 82 spin_lock_irqsave(&gus->reg_lock, flags); 83 if (gus->gf1.enh_mode) { 84 address_high = ((address >> 16) & 0x000000f0) | (address & 0x0000000f); 85 snd_gf1_write16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW, (unsigned short) (address >> 4)); 86 snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_HIGH, (unsigned char) address_high); 87 } else 88 snd_gf1_write16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW, (unsigned short) (address >> 4)); 89 snd_gf1_write8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL, dma_cmd); 90 spin_unlock_irqrestore(&gus->reg_lock, flags); 91 } 92 93 static struct snd_gf1_dma_block *snd_gf1_dma_next_block(struct snd_gus_card * gus) 94 { 95 struct snd_gf1_dma_block *block; 96 97 /* PCM block have bigger priority than synthesizer one */ 98 if (gus->gf1.dma_data_pcm) { 99 block = gus->gf1.dma_data_pcm; 100 if (gus->gf1.dma_data_pcm_last == block) { 101 gus->gf1.dma_data_pcm = 102 gus->gf1.dma_data_pcm_last = NULL; 103 } else { 104 gus->gf1.dma_data_pcm = block->next; 105 } 106 } else if (gus->gf1.dma_data_synth) { 107 block = gus->gf1.dma_data_synth; 108 if (gus->gf1.dma_data_synth_last == block) { 109 gus->gf1.dma_data_synth = 110 gus->gf1.dma_data_synth_last = NULL; 111 } else { 112 gus->gf1.dma_data_synth = block->next; 113 } 114 } else { 115 block = NULL; 116 } 117 if (block) { 118 gus->gf1.dma_ack = block->ack; 119 gus->gf1.dma_private_data = block->private_data; 120 } 121 return block; 122 } 123 124 125 static void snd_gf1_dma_interrupt(struct snd_gus_card * gus) 126 { 127 struct snd_gf1_dma_block *block; 128 129 snd_gf1_dma_ack(gus); 130 if (gus->gf1.dma_ack) 131 gus->gf1.dma_ack(gus, gus->gf1.dma_private_data); 132 spin_lock(&gus->dma_lock); 133 if (gus->gf1.dma_data_pcm == NULL && 134 gus->gf1.dma_data_synth == NULL) { 135 gus->gf1.dma_ack = NULL; 136 gus->gf1.dma_flags &= ~SNDRV_GF1_DMA_TRIGGER; 137 spin_unlock(&gus->dma_lock); 138 return; 139 } 140 block = snd_gf1_dma_next_block(gus); 141 spin_unlock(&gus->dma_lock); 142 snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd); 143 kfree(block); 144 #if 0 145 printk("program dma (IRQ) - addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", addr, (long) buffer, count, cmd); 146 #endif 147 } 148 149 int snd_gf1_dma_init(struct snd_gus_card * gus) 150 { 151 mutex_lock(&gus->dma_mutex); 152 gus->gf1.dma_shared++; 153 if (gus->gf1.dma_shared > 1) { 154 mutex_unlock(&gus->dma_mutex); 155 return 0; 156 } 157 gus->gf1.interrupt_handler_dma_write = snd_gf1_dma_interrupt; 158 gus->gf1.dma_data_pcm = 159 gus->gf1.dma_data_pcm_last = 160 gus->gf1.dma_data_synth = 161 gus->gf1.dma_data_synth_last = NULL; 162 mutex_unlock(&gus->dma_mutex); 163 return 0; 164 } 165 166 int snd_gf1_dma_done(struct snd_gus_card * gus) 167 { 168 struct snd_gf1_dma_block *block; 169 170 mutex_lock(&gus->dma_mutex); 171 gus->gf1.dma_shared--; 172 if (!gus->gf1.dma_shared) { 173 snd_dma_disable(gus->gf1.dma1); 174 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_DMA_WRITE); 175 snd_gf1_dma_ack(gus); 176 while ((block = gus->gf1.dma_data_pcm)) { 177 gus->gf1.dma_data_pcm = block->next; 178 kfree(block); 179 } 180 while ((block = gus->gf1.dma_data_synth)) { 181 gus->gf1.dma_data_synth = block->next; 182 kfree(block); 183 } 184 gus->gf1.dma_data_pcm_last = 185 gus->gf1.dma_data_synth_last = NULL; 186 } 187 mutex_unlock(&gus->dma_mutex); 188 return 0; 189 } 190 191 int snd_gf1_dma_transfer_block(struct snd_gus_card * gus, 192 struct snd_gf1_dma_block * __block, 193 int atomic, 194 int synth) 195 { 196 unsigned long flags; 197 struct snd_gf1_dma_block *block; 198 199 block = kmalloc(sizeof(*block), atomic ? GFP_ATOMIC : GFP_KERNEL); 200 if (block == NULL) { 201 snd_printk(KERN_ERR "gf1: DMA transfer failure; not enough memory\n"); 202 return -ENOMEM; 203 } 204 *block = *__block; 205 block->next = NULL; 206 #if 0 207 printk("addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", block->addr, (long) block->buffer, block->count, block->cmd); 208 #endif 209 #if 0 210 printk("gus->gf1.dma_data_pcm_last = 0x%lx\n", (long)gus->gf1.dma_data_pcm_last); 211 printk("gus->gf1.dma_data_pcm = 0x%lx\n", (long)gus->gf1.dma_data_pcm); 212 #endif 213 spin_lock_irqsave(&gus->dma_lock, flags); 214 if (synth) { 215 if (gus->gf1.dma_data_synth_last) { 216 gus->gf1.dma_data_synth_last->next = block; 217 gus->gf1.dma_data_synth_last = block; 218 } else { 219 gus->gf1.dma_data_synth = 220 gus->gf1.dma_data_synth_last = block; 221 } 222 } else { 223 if (gus->gf1.dma_data_pcm_last) { 224 gus->gf1.dma_data_pcm_last->next = block; 225 gus->gf1.dma_data_pcm_last = block; 226 } else { 227 gus->gf1.dma_data_pcm = 228 gus->gf1.dma_data_pcm_last = block; 229 } 230 } 231 if (!(gus->gf1.dma_flags & SNDRV_GF1_DMA_TRIGGER)) { 232 gus->gf1.dma_flags |= SNDRV_GF1_DMA_TRIGGER; 233 block = snd_gf1_dma_next_block(gus); 234 spin_unlock_irqrestore(&gus->dma_lock, flags); 235 if (block == NULL) 236 return 0; 237 snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd); 238 kfree(block); 239 return 0; 240 } 241 spin_unlock_irqrestore(&gus->dma_lock, flags); 242 return 0; 243 } 244