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