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