1/* 2 * Patch transfer callback for Emu10k1 3 * 4 * Copyright (C) 2000 Takashi iwai <tiwai@suse.de> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20/* 21 * All the code for loading in a patch. There is very little that is 22 * chip specific here. Just the actual writing to the board. 23 */ 24 25#include "emu10k1_synth_local.h" 26 27/* 28 */ 29#define BLANK_LOOP_START 4 30#define BLANK_LOOP_END 8 31#define BLANK_LOOP_SIZE 12 32#define BLANK_HEAD_SIZE 32 33 34/* 35 * allocate a sample block and copy data from userspace 36 */ 37int 38snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp, 39 struct snd_util_memhdr *hdr, 40 const void __user *data, long count) 41{ 42 int offset; 43 int truesize, size, loopsize, blocksize; 44 int loopend, sampleend; 45 unsigned int start_addr; 46 struct snd_emu10k1 *emu; 47 48 emu = rec->hw; 49 snd_assert(sp != NULL, return -EINVAL); 50 snd_assert(hdr != NULL, return -EINVAL); 51 52 if (sp->v.size == 0) { 53 snd_printd("emu: rom font for sample %d\n", sp->v.sample); 54 return 0; 55 } 56 57 /* recalculate address offset */ 58 sp->v.end -= sp->v.start; 59 sp->v.loopstart -= sp->v.start; 60 sp->v.loopend -= sp->v.start; 61 sp->v.start = 0; 62 63 /* some samples have invalid data. the addresses are corrected in voice info */ 64 sampleend = sp->v.end; 65 if (sampleend > sp->v.size) 66 sampleend = sp->v.size; 67 loopend = sp->v.loopend; 68 if (loopend > sampleend) 69 loopend = sampleend; 70 71 /* be sure loop points start < end */ 72 if (sp->v.loopstart >= sp->v.loopend) { 73 int tmp = sp->v.loopstart; 74 sp->v.loopstart = sp->v.loopend; 75 sp->v.loopend = tmp; 76 } 77 78 /* compute true data size to be loaded */ 79 truesize = sp->v.size + BLANK_HEAD_SIZE; 80 loopsize = 0; 81 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) 82 truesize += BLANK_LOOP_SIZE; 83 84 /* try to allocate a memory block */ 85 blocksize = truesize; 86 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) 87 blocksize *= 2; 88 sp->block = snd_emu10k1_synth_alloc(emu, blocksize); 89 if (sp->block == NULL) { 90 snd_printd("emu10k1: synth malloc failed (size=%d)\n", blocksize); 91 /* not ENOMEM (for compatibility with OSS) */ 92 return -ENOSPC; 93 } 94 /* set the total size */ 95 sp->v.truesize = blocksize; 96 97 /* write blank samples at head */ 98 offset = 0; 99 size = BLANK_HEAD_SIZE; 100 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) 101 size *= 2; 102 snd_assert(offset + size <= blocksize, return -EINVAL); 103 snd_emu10k1_synth_bzero(emu, sp->block, offset, size); 104 offset += size; 105 106 /* copy start->loopend */ 107 size = loopend; 108 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) 109 size *= 2; 110 snd_assert(offset + size <= blocksize, return -EINVAL); 111 if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) { 112 snd_emu10k1_synth_free(emu, sp->block); 113 sp->block = NULL; 114 return -EFAULT; 115 } 116 offset += size; 117 data += size; 118 119 120 /* loopend -> sample end */ 121 size = sp->v.size - loopend; 122 snd_assert(size >= 0, return -EINVAL); 123 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) 124 size *= 2; 125 if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) { 126 snd_emu10k1_synth_free(emu, sp->block); 127 sp->block = NULL; 128 return -EFAULT; 129 } 130 offset += size; 131 132 /* clear rest of samples (if any) */ 133 if (offset < blocksize) 134 snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset); 135 136 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) { 137 /* if no blank loop is attached in the sample, add it */ 138 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) { 139 sp->v.loopstart = sp->v.end + BLANK_LOOP_START; 140 sp->v.loopend = sp->v.end + BLANK_LOOP_END; 141 } 142 } 143 144 145 /* recalculate offset */ 146 start_addr = BLANK_HEAD_SIZE * 2; 147 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) 148 start_addr >>= 1; 149 sp->v.start += start_addr; 150 sp->v.end += start_addr; 151 sp->v.loopstart += start_addr; 152 sp->v.loopend += start_addr; 153 154 return 0; 155} 156 157/* 158 * free a sample block 159 */ 160int 161snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp, 162 struct snd_util_memhdr *hdr) 163{ 164 struct snd_emu10k1 *emu; 165 166 emu = rec->hw; 167 snd_assert(sp != NULL, return -EINVAL); 168 snd_assert(hdr != NULL, return -EINVAL); 169 170 if (sp->block) { 171 snd_emu10k1_synth_free(emu, sp->block); 172 sp->block = NULL; 173 } 174 return 0; 175} 176