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 3 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 u8 fill; 30 u32 xor; 31 int shift; 32 int offset; 33 int truesize, size, blocksize; 34 int loop_start, loop_end, loop_size, data_end, unroll; 35 struct snd_emu10k1 *emu; 36 37 emu = rec->hw; 38 if (snd_BUG_ON(!sp || !hdr)) 39 return -EINVAL; 40 41 if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP | SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) { 42 /* should instead return -ENOTSUPP; but compatibility */ 43 dev_warn(emu->card->dev, 44 "Emu10k1 wavetable patch %d with unsupported loop feature\n", 45 sp->v.sample); 46 } 47 48 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS) { 49 shift = 0; 50 fill = 0x80; 51 xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0 : 0x80808080; 52 } else { 53 shift = 1; 54 fill = 0; 55 xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0x80008000 : 0; 56 } 57 58 /* compute true data size to be loaded */ 59 truesize = sp->v.size + BLANK_HEAD_SIZE; 60 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) { 61 truesize += BLANK_LOOP_SIZE; 62 /* if no blank loop is attached in the sample, add it */ 63 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) { 64 sp->v.loopstart = sp->v.end + BLANK_LOOP_START; 65 sp->v.loopend = sp->v.end + BLANK_LOOP_END; 66 } 67 } 68 69 loop_start = sp->v.loopstart; 70 loop_end = sp->v.loopend; 71 loop_size = loop_end - loop_start; 72 if (!loop_size) 73 return -EINVAL; 74 data_end = sp->v.end; 75 76 /* recalculate offset */ 77 sp->v.start += BLANK_HEAD_SIZE; 78 sp->v.end += BLANK_HEAD_SIZE; 79 sp->v.loopstart += BLANK_HEAD_SIZE; 80 sp->v.loopend += BLANK_HEAD_SIZE; 81 82 // Automatic pre-filling of the cache does not work in the presence 83 // of loops (*), and we don't want to fill it manually, as that is 84 // fiddly and slow. So we unroll the loop until the loop end is 85 // beyond the cache size. 86 // (*) Strictly speaking, a single iteration is supported (that's 87 // how it works when the playback engine runs), but handling this 88 // special case is not worth it. 89 unroll = 0; 90 while (sp->v.loopend < 64) { 91 truesize += loop_size; 92 sp->v.loopstart += loop_size; 93 sp->v.loopend += loop_size; 94 sp->v.end += loop_size; 95 unroll++; 96 } 97 98 /* try to allocate a memory block */ 99 blocksize = truesize << shift; 100 sp->block = snd_emu10k1_synth_alloc(emu, blocksize); 101 if (sp->block == NULL) { 102 dev_dbg(emu->card->dev, 103 "synth malloc failed (size=%d)\n", blocksize); 104 /* not ENOMEM (for compatibility with OSS) */ 105 return -ENOSPC; 106 } 107 /* set the total size */ 108 sp->v.truesize = blocksize; 109 110 /* write blank samples at head */ 111 offset = 0; 112 size = BLANK_HEAD_SIZE << shift; 113 snd_emu10k1_synth_memset(emu, sp->block, offset, size, fill); 114 offset += size; 115 116 /* copy provided samples */ 117 if (unroll && loop_end <= data_end) { 118 size = loop_end << shift; 119 if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor)) 120 goto faulty; 121 offset += size; 122 123 data += loop_start << shift; 124 while (--unroll > 0) { 125 size = loop_size << shift; 126 if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor)) 127 goto faulty; 128 offset += size; 129 } 130 131 size = (data_end - loop_start) << shift; 132 } else { 133 size = data_end << shift; 134 } 135 if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor)) 136 goto faulty; 137 offset += size; 138 139 /* clear rest of samples (if any) */ 140 if (offset < blocksize) 141 snd_emu10k1_synth_memset(emu, sp->block, offset, blocksize - offset, fill); 142 143 return 0; 144 145 faulty: 146 snd_emu10k1_synth_free(emu, sp->block); 147 sp->block = NULL; 148 return -EFAULT; 149 } 150 151 /* 152 * free a sample block 153 */ 154 int 155 snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp, 156 struct snd_util_memhdr *hdr) 157 { 158 struct snd_emu10k1 *emu; 159 160 emu = rec->hw; 161 if (snd_BUG_ON(!sp || !hdr)) 162 return -EINVAL; 163 164 if (sp->block) { 165 snd_emu10k1_synth_free(emu, sp->block); 166 sp->block = NULL; 167 } 168 return 0; 169 } 170 171