1 /* 2 * Patch transfer callback for Emu10k1 3 * 4 * Copyright (C) 2000 Takashi iwai <tiwai@suse.de> 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 * All the code for loading in a patch. There is very little that is 22 * chip specific here. Just the actual writing to the board. 23 */ 24 25 #include "emu10k1_synth_local.h" 26 27 /* 28 */ 29 #define BLANK_LOOP_START 4 30 #define BLANK_LOOP_END 8 31 #define BLANK_LOOP_SIZE 12 32 #define BLANK_HEAD_SIZE 32 33 34 /* 35 * allocate a sample block and copy data from userspace 36 */ 37 int 38 snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp, 39 struct snd_util_memhdr *hdr, 40 const void __user *data, long count) 41 { 42 int offset; 43 int truesize, size, loopsize, blocksize; 44 int loopend, sampleend; 45 unsigned int start_addr; 46 struct snd_emu10k1 *emu; 47 48 emu = rec->hw; 49 snd_assert(sp != NULL, return -EINVAL); 50 snd_assert(hdr != NULL, return -EINVAL); 51 52 if (sp->v.size == 0) { 53 snd_printd("emu: rom font for sample %d\n", sp->v.sample); 54 return 0; 55 } 56 57 /* recalculate address offset */ 58 sp->v.end -= sp->v.start; 59 sp->v.loopstart -= sp->v.start; 60 sp->v.loopend -= sp->v.start; 61 sp->v.start = 0; 62 63 /* some samples have invalid data. the addresses are corrected in voice info */ 64 sampleend = sp->v.end; 65 if (sampleend > sp->v.size) 66 sampleend = sp->v.size; 67 loopend = sp->v.loopend; 68 if (loopend > sampleend) 69 loopend = sampleend; 70 71 /* be sure loop points start < end */ 72 if (sp->v.loopstart >= sp->v.loopend) { 73 int tmp = sp->v.loopstart; 74 sp->v.loopstart = sp->v.loopend; 75 sp->v.loopend = tmp; 76 } 77 78 /* compute true data size to be loaded */ 79 truesize = sp->v.size + BLANK_HEAD_SIZE; 80 loopsize = 0; 81 #if 0 /* not supported */ 82 if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) 83 loopsize = sp->v.loopend - sp->v.loopstart; 84 truesize += loopsize; 85 #endif 86 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) 87 truesize += BLANK_LOOP_SIZE; 88 89 /* try to allocate a memory block */ 90 blocksize = truesize; 91 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) 92 blocksize *= 2; 93 sp->block = snd_emu10k1_synth_alloc(emu, blocksize); 94 if (sp->block == NULL) { 95 snd_printd("emu10k1: synth malloc failed (size=%d)\n", blocksize); 96 /* not ENOMEM (for compatibility with OSS) */ 97 return -ENOSPC; 98 } 99 /* set the total size */ 100 sp->v.truesize = blocksize; 101 102 /* write blank samples at head */ 103 offset = 0; 104 size = BLANK_HEAD_SIZE; 105 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) 106 size *= 2; 107 snd_assert(offset + size <= blocksize, return -EINVAL); 108 snd_emu10k1_synth_bzero(emu, sp->block, offset, size); 109 offset += size; 110 111 /* copy start->loopend */ 112 size = loopend; 113 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) 114 size *= 2; 115 snd_assert(offset + size <= blocksize, return -EINVAL); 116 if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) { 117 snd_emu10k1_synth_free(emu, sp->block); 118 sp->block = NULL; 119 return -EFAULT; 120 } 121 offset += size; 122 data += size; 123 124 #if 0 /* not suppported yet */ 125 /* handle reverse (or bidirectional) loop */ 126 if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) { 127 /* copy loop in reverse */ 128 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) { 129 int woffset; 130 unsigned short *wblock = (unsigned short*)block; 131 woffset = offset / 2; 132 snd_assert(offset + loopsize*2 <= blocksize, return -EINVAL); 133 for (i = 0; i < loopsize; i++) 134 wblock[woffset + i] = wblock[woffset - i -1]; 135 offset += loopsize * 2; 136 } else { 137 snd_assert(offset + loopsize <= blocksize, return -EINVAL); 138 for (i = 0; i < loopsize; i++) 139 block[offset + i] = block[offset - i -1]; 140 offset += loopsize; 141 } 142 143 /* modify loop pointers */ 144 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) { 145 sp->v.loopend += loopsize; 146 } else { 147 sp->v.loopstart += loopsize; 148 sp->v.loopend += loopsize; 149 } 150 /* add sample pointer */ 151 sp->v.end += loopsize; 152 } 153 #endif 154 155 /* loopend -> sample end */ 156 size = sp->v.size - loopend; 157 snd_assert(size >= 0, return -EINVAL); 158 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) 159 size *= 2; 160 if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) { 161 snd_emu10k1_synth_free(emu, sp->block); 162 sp->block = NULL; 163 return -EFAULT; 164 } 165 offset += size; 166 167 /* clear rest of samples (if any) */ 168 if (offset < blocksize) 169 snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset); 170 171 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) { 172 /* if no blank loop is attached in the sample, add it */ 173 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) { 174 sp->v.loopstart = sp->v.end + BLANK_LOOP_START; 175 sp->v.loopend = sp->v.end + BLANK_LOOP_END; 176 } 177 } 178 179 #if 0 /* not supported yet */ 180 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) { 181 /* unsigned -> signed */ 182 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) { 183 unsigned short *wblock = (unsigned short*)block; 184 for (i = 0; i < truesize; i++) 185 wblock[i] ^= 0x8000; 186 } else { 187 for (i = 0; i < truesize; i++) 188 block[i] ^= 0x80; 189 } 190 } 191 #endif 192 193 /* recalculate offset */ 194 start_addr = BLANK_HEAD_SIZE * 2; 195 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) 196 start_addr >>= 1; 197 sp->v.start += start_addr; 198 sp->v.end += start_addr; 199 sp->v.loopstart += start_addr; 200 sp->v.loopend += start_addr; 201 202 return 0; 203 } 204 205 /* 206 * free a sample block 207 */ 208 int 209 snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp, 210 struct snd_util_memhdr *hdr) 211 { 212 struct snd_emu10k1 *emu; 213 214 emu = rec->hw; 215 snd_assert(sp != NULL, return -EINVAL); 216 snd_assert(hdr != NULL, return -EINVAL); 217 218 if (sp->block) { 219 snd_emu10k1_synth_free(emu, sp->block); 220 sp->block = NULL; 221 } 222 return 0; 223 } 224 225