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