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