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 if (snd_BUG_ON(!sp || !hdr)) 50 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 if (offset + size > blocksize) 103 return -EINVAL; 104 snd_emu10k1_synth_bzero(emu, sp->block, offset, size); 105 offset += size; 106 107 /* copy start->loopend */ 108 size = loopend; 109 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) 110 size *= 2; 111 if (offset + size > blocksize) 112 return -EINVAL; 113 if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) { 114 snd_emu10k1_synth_free(emu, sp->block); 115 sp->block = NULL; 116 return -EFAULT; 117 } 118 offset += size; 119 data += size; 120 121 122 /* loopend -> sample end */ 123 size = sp->v.size - loopend; 124 if (size < 0) 125 return -EINVAL; 126 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) 127 size *= 2; 128 if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) { 129 snd_emu10k1_synth_free(emu, sp->block); 130 sp->block = NULL; 131 return -EFAULT; 132 } 133 offset += size; 134 135 /* clear rest of samples (if any) */ 136 if (offset < blocksize) 137 snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset); 138 139 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) { 140 /* if no blank loop is attached in the sample, add it */ 141 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) { 142 sp->v.loopstart = sp->v.end + BLANK_LOOP_START; 143 sp->v.loopend = sp->v.end + BLANK_LOOP_END; 144 } 145 } 146 147 148 /* recalculate offset */ 149 start_addr = BLANK_HEAD_SIZE * 2; 150 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) 151 start_addr >>= 1; 152 sp->v.start += start_addr; 153 sp->v.end += start_addr; 154 sp->v.loopstart += start_addr; 155 sp->v.loopend += start_addr; 156 157 return 0; 158} 159 160/* 161 * free a sample block 162 */ 163int 164snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp, 165 struct snd_util_memhdr *hdr) 166{ 167 struct snd_emu10k1 *emu; 168 169 emu = rec->hw; 170 if (snd_BUG_ON(!sp || !hdr)) 171 return -EINVAL; 172 173 if (sp->block) { 174 snd_emu10k1_synth_free(emu, sp->block); 175 sp->block = NULL; 176 } 177 return 0; 178} 179