171 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Patch transfer callback for Emu10k14 *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 is9 * 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 417#define BLANK_LOOP_END 818#define BLANK_LOOP_SIZE 1219#define BLANK_HEAD_SIZE 320 21/*22 * allocate a sample block and copy data from userspace23 */24int25snd_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 presence83 // of loops (*), and we don't want to fill it manually, as that is84 // fiddly and slow. So we unroll the loop until the loop end is85 // beyond the cache size.86 // (*) Strictly speaking, a single iteration is supported (that's87 // how it works when the playback engine runs), but handling this88 // 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 145faulty:146 snd_emu10k1_synth_free(emu, sp->block);147 sp->block = NULL;148 return -EFAULT;149}150 151/*152 * free a sample block153 */154int155snd_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