Path: blob/master/sound/pci/emu10k1/emu10k1_patch.c
10820 views
/*1* Patch transfer callback for Emu10k12*3* Copyright (C) 2000 Takashi iwai <[email protected]>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*/19/*20* All the code for loading in a patch. There is very little that is21* chip specific here. Just the actual writing to the board.22*/2324#include "emu10k1_synth_local.h"2526/*27*/28#define BLANK_LOOP_START 429#define BLANK_LOOP_END 830#define BLANK_LOOP_SIZE 1231#define BLANK_HEAD_SIZE 323233/*34* allocate a sample block and copy data from userspace35*/36int37snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,38struct snd_util_memhdr *hdr,39const void __user *data, long count)40{41int offset;42int truesize, size, loopsize, blocksize;43int loopend, sampleend;44unsigned int start_addr;45struct snd_emu10k1 *emu;4647emu = rec->hw;48if (snd_BUG_ON(!sp || !hdr))49return -EINVAL;5051if (sp->v.size == 0) {52snd_printd("emu: rom font for sample %d\n", sp->v.sample);53return 0;54}5556/* recalculate address offset */57sp->v.end -= sp->v.start;58sp->v.loopstart -= sp->v.start;59sp->v.loopend -= sp->v.start;60sp->v.start = 0;6162/* some samples have invalid data. the addresses are corrected in voice info */63sampleend = sp->v.end;64if (sampleend > sp->v.size)65sampleend = sp->v.size;66loopend = sp->v.loopend;67if (loopend > sampleend)68loopend = sampleend;6970/* be sure loop points start < end */71if (sp->v.loopstart >= sp->v.loopend) {72int tmp = sp->v.loopstart;73sp->v.loopstart = sp->v.loopend;74sp->v.loopend = tmp;75}7677/* compute true data size to be loaded */78truesize = sp->v.size + BLANK_HEAD_SIZE;79loopsize = 0;80#if 0 /* not supported */81if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP))82loopsize = sp->v.loopend - sp->v.loopstart;83truesize += loopsize;84#endif85if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)86truesize += BLANK_LOOP_SIZE;8788/* try to allocate a memory block */89blocksize = truesize;90if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))91blocksize *= 2;92sp->block = snd_emu10k1_synth_alloc(emu, blocksize);93if (sp->block == NULL) {94snd_printd("emu10k1: synth malloc failed (size=%d)\n", blocksize);95/* not ENOMEM (for compatibility with OSS) */96return -ENOSPC;97}98/* set the total size */99sp->v.truesize = blocksize;100101/* write blank samples at head */102offset = 0;103size = BLANK_HEAD_SIZE;104if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))105size *= 2;106if (offset + size > blocksize)107return -EINVAL;108snd_emu10k1_synth_bzero(emu, sp->block, offset, size);109offset += size;110111/* copy start->loopend */112size = loopend;113if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))114size *= 2;115if (offset + size > blocksize)116return -EINVAL;117if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {118snd_emu10k1_synth_free(emu, sp->block);119sp->block = NULL;120return -EFAULT;121}122offset += size;123data += size;124125#if 0 /* not suppported yet */126/* handle reverse (or bidirectional) loop */127if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) {128/* copy loop in reverse */129if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {130int woffset;131unsigned short *wblock = (unsigned short*)block;132woffset = offset / 2;133if (offset + loopsize * 2 > blocksize)134return -EINVAL;135for (i = 0; i < loopsize; i++)136wblock[woffset + i] = wblock[woffset - i -1];137offset += loopsize * 2;138} else {139if (offset + loopsize > blocksize)140return -EINVAL;141for (i = 0; i < loopsize; i++)142block[offset + i] = block[offset - i -1];143offset += loopsize;144}145146/* modify loop pointers */147if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) {148sp->v.loopend += loopsize;149} else {150sp->v.loopstart += loopsize;151sp->v.loopend += loopsize;152}153/* add sample pointer */154sp->v.end += loopsize;155}156#endif157158/* loopend -> sample end */159size = sp->v.size - loopend;160if (size < 0)161return -EINVAL;162if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))163size *= 2;164if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {165snd_emu10k1_synth_free(emu, sp->block);166sp->block = NULL;167return -EFAULT;168}169offset += size;170171/* clear rest of samples (if any) */172if (offset < blocksize)173snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset);174175if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {176/* if no blank loop is attached in the sample, add it */177if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {178sp->v.loopstart = sp->v.end + BLANK_LOOP_START;179sp->v.loopend = sp->v.end + BLANK_LOOP_END;180}181}182183#if 0 /* not supported yet */184if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) {185/* unsigned -> signed */186if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {187unsigned short *wblock = (unsigned short*)block;188for (i = 0; i < truesize; i++)189wblock[i] ^= 0x8000;190} else {191for (i = 0; i < truesize; i++)192block[i] ^= 0x80;193}194}195#endif196197/* recalculate offset */198start_addr = BLANK_HEAD_SIZE * 2;199if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))200start_addr >>= 1;201sp->v.start += start_addr;202sp->v.end += start_addr;203sp->v.loopstart += start_addr;204sp->v.loopend += start_addr;205206return 0;207}208209/*210* free a sample block211*/212int213snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp,214struct snd_util_memhdr *hdr)215{216struct snd_emu10k1 *emu;217218emu = rec->hw;219if (snd_BUG_ON(!sp || !hdr))220return -EINVAL;221222if (sp->block) {223snd_emu10k1_synth_free(emu, sp->block);224sp->block = NULL;225}226return 0;227}228229230231