linux/sound/pci/emu10k1/emu10k1_patch.c
<<
>>
Prefs
   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 0 /* not supported */
  82        if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP))
  83                loopsize = sp->v.loopend - sp->v.loopstart;
  84        truesize += loopsize;
  85#endif
  86        if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)
  87                truesize += BLANK_LOOP_SIZE;
  88
  89        /* try to allocate a memory block */
  90        blocksize = truesize;
  91        if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
  92                blocksize *= 2;
  93        sp->block = snd_emu10k1_synth_alloc(emu, blocksize);
  94        if (sp->block == NULL) {
  95                snd_printd("emu10k1: synth malloc failed (size=%d)\n", blocksize);
  96                /* not ENOMEM (for compatibility with OSS) */
  97                return -ENOSPC;
  98        }
  99        /* set the total size */
 100        sp->v.truesize = blocksize;
 101
 102        /* write blank samples at head */
 103        offset = 0;
 104        size = BLANK_HEAD_SIZE;
 105        if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
 106                size *= 2;
 107        snd_assert(offset + size <= blocksize, return -EINVAL);
 108        snd_emu10k1_synth_bzero(emu, sp->block, offset, size);
 109        offset += size;
 110
 111        /* copy start->loopend */
 112        size = loopend;
 113        if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
 114                size *= 2;
 115        snd_assert(offset + size <= blocksize, return -EINVAL);
 116        if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
 117                snd_emu10k1_synth_free(emu, sp->block);
 118                sp->block = NULL;
 119                return -EFAULT;
 120        }
 121        offset += size;
 122        data += size;
 123
 124#if 0 /* not suppported yet */
 125        /* handle reverse (or bidirectional) loop */
 126        if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) {
 127                /* copy loop in reverse */
 128                if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
 129                        int woffset;
 130                        unsigned short *wblock = (unsigned short*)block;
 131                        woffset = offset / 2;
 132                        snd_assert(offset + loopsize*2 <= blocksize, return -EINVAL);
 133                        for (i = 0; i < loopsize; i++)
 134                                wblock[woffset + i] = wblock[woffset - i -1];
 135                        offset += loopsize * 2;
 136                } else {
 137                        snd_assert(offset + loopsize <= blocksize, return -EINVAL);
 138                        for (i = 0; i < loopsize; i++)
 139                                block[offset + i] = block[offset - i -1];
 140                        offset += loopsize;
 141                }
 142
 143                /* modify loop pointers */
 144                if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) {
 145                        sp->v.loopend += loopsize;
 146                } else {
 147                        sp->v.loopstart += loopsize;
 148                        sp->v.loopend += loopsize;
 149                }
 150                /* add sample pointer */
 151                sp->v.end += loopsize;
 152        }
 153#endif
 154
 155        /* loopend -> sample end */
 156        size = sp->v.size - loopend;
 157        snd_assert(size >= 0, return -EINVAL);
 158        if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
 159                size *= 2;
 160        if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
 161                snd_emu10k1_synth_free(emu, sp->block);
 162                sp->block = NULL;
 163                return -EFAULT;
 164        }
 165        offset += size;
 166
 167        /* clear rest of samples (if any) */
 168        if (offset < blocksize)
 169                snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset);
 170
 171        if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
 172                /* if no blank loop is attached in the sample, add it */
 173                if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
 174                        sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
 175                        sp->v.loopend = sp->v.end + BLANK_LOOP_END;
 176                }
 177        }
 178
 179#if 0 /* not supported yet */
 180        if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) {
 181                /* unsigned -> signed */
 182                if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
 183                        unsigned short *wblock = (unsigned short*)block;
 184                        for (i = 0; i < truesize; i++)
 185                                wblock[i] ^= 0x8000;
 186                } else {
 187                        for (i = 0; i < truesize; i++)
 188                                block[i] ^= 0x80;
 189                }
 190        }
 191#endif
 192
 193        /* recalculate offset */
 194        start_addr = BLANK_HEAD_SIZE * 2;
 195        if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
 196                start_addr >>= 1;
 197        sp->v.start += start_addr;
 198        sp->v.end += start_addr;
 199        sp->v.loopstart += start_addr;
 200        sp->v.loopend += start_addr;
 201
 202        return 0;
 203}
 204
 205/*
 206 * free a sample block
 207 */
 208int
 209snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp,
 210                        struct snd_util_memhdr *hdr)
 211{
 212        struct snd_emu10k1 *emu;
 213
 214        emu = rec->hw;
 215        snd_assert(sp != NULL, return -EINVAL);
 216        snd_assert(hdr != NULL, return -EINVAL);
 217
 218        if (sp->block) {
 219                snd_emu10k1_synth_free(emu, sp->block);
 220                sp->block = NULL;
 221        }
 222        return 0;
 223}
 224
 225