[funini.com] -> [kei@sodan] -> Kernel Reading

root/sound/pci/emu10k1/emu10k1_patch.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_emu10k1_sample_new
  2. snd_emu10k1_sample_free

/*
 *  Patch transfer callback for Emu10k1
 *
 *  Copyright (C) 2000 Takashi iwai <tiwai@suse.de>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */
/*
 * All the code for loading in a patch.  There is very little that is
 * chip specific here.  Just the actual writing to the board.
 */

#include "emu10k1_synth_local.h"

/*
 */
#define BLANK_LOOP_START        4
#define BLANK_LOOP_END          8
#define BLANK_LOOP_SIZE         12
#define BLANK_HEAD_SIZE         32

/*
 * allocate a sample block and copy data from userspace
 */
int
snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
                       struct snd_util_memhdr *hdr,
                       const void __user *data, long count)
{
        int offset;
        int truesize, size, loopsize, blocksize;
        int loopend, sampleend;
        unsigned int start_addr;
        struct snd_emu10k1 *emu;

        emu = rec->hw;
        if (snd_BUG_ON(!sp || !hdr))
                return -EINVAL;

        if (sp->v.size == 0) {
                snd_printd("emu: rom font for sample %d\n", sp->v.sample);
                return 0;
        }

        /* recalculate address offset */
        sp->v.end -= sp->v.start;
        sp->v.loopstart -= sp->v.start;
        sp->v.loopend -= sp->v.start;
        sp->v.start = 0;

        /* some samples have invalid data.  the addresses are corrected in voice info */
        sampleend = sp->v.end;
        if (sampleend > sp->v.size)
                sampleend = sp->v.size;
        loopend = sp->v.loopend;
        if (loopend > sampleend)
                loopend = sampleend;

        /* be sure loop points start < end */
        if (sp->v.loopstart >= sp->v.loopend) {
                int tmp = sp->v.loopstart;
                sp->v.loopstart = sp->v.loopend;
                sp->v.loopend = tmp;
        }

        /* compute true data size to be loaded */
        truesize = sp->v.size + BLANK_HEAD_SIZE;
        loopsize = 0;
#if 0 /* not supported */
        if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP))
                loopsize = sp->v.loopend - sp->v.loopstart;
        truesize += loopsize;
#endif
        if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)
                truesize += BLANK_LOOP_SIZE;

        /* try to allocate a memory block */
        blocksize = truesize;
        if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
                blocksize *= 2;
        sp->block = snd_emu10k1_synth_alloc(emu, blocksize);
        if (sp->block == NULL) {
                snd_printd("emu10k1: synth malloc failed (size=%d)\n", blocksize);
                /* not ENOMEM (for compatibility with OSS) */
                return -ENOSPC;
        }
        /* set the total size */
        sp->v.truesize = blocksize;

        /* write blank samples at head */
        offset = 0;
        size = BLANK_HEAD_SIZE;
        if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
                size *= 2;
        if (offset + size > blocksize)
                return -EINVAL;
        snd_emu10k1_synth_bzero(emu, sp->block, offset, size);
        offset += size;

        /* copy start->loopend */
        size = loopend;
        if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
                size *= 2;
        if (offset + size > blocksize)
                return -EINVAL;
        if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
                snd_emu10k1_synth_free(emu, sp->block);
                sp->block = NULL;
                return -EFAULT;
        }
        offset += size;
        data += size;

#if 0 /* not suppported yet */
        /* handle reverse (or bidirectional) loop */
        if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) {
                /* copy loop in reverse */
                if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
                        int woffset;
                        unsigned short *wblock = (unsigned short*)block;
                        woffset = offset / 2;
                        if (offset + loopsize * 2 > blocksize)
                                return -EINVAL;
                        for (i = 0; i < loopsize; i++)
                                wblock[woffset + i] = wblock[woffset - i -1];
                        offset += loopsize * 2;
                } else {
                        if (offset + loopsize > blocksize)
                                return -EINVAL;
                        for (i = 0; i < loopsize; i++)
                                block[offset + i] = block[offset - i -1];
                        offset += loopsize;
                }

                /* modify loop pointers */
                if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) {
                        sp->v.loopend += loopsize;
                } else {
                        sp->v.loopstart += loopsize;
                        sp->v.loopend += loopsize;
                }
                /* add sample pointer */
                sp->v.end += loopsize;
        }
#endif

        /* loopend -> sample end */
        size = sp->v.size - loopend;
        if (size < 0)
                return -EINVAL;
        if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
                size *= 2;
        if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
                snd_emu10k1_synth_free(emu, sp->block);
                sp->block = NULL;
                return -EFAULT;
        }
        offset += size;

        /* clear rest of samples (if any) */
        if (offset < blocksize)
                snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset);

        if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
                /* if no blank loop is attached in the sample, add it */
                if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
                        sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
                        sp->v.loopend = sp->v.end + BLANK_LOOP_END;
                }
        }

#if 0 /* not supported yet */
        if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) {
                /* unsigned -> signed */
                if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
                        unsigned short *wblock = (unsigned short*)block;
                        for (i = 0; i < truesize; i++)
                                wblock[i] ^= 0x8000;
                } else {
                        for (i = 0; i < truesize; i++)
                                block[i] ^= 0x80;
                }
        }
#endif

        /* recalculate offset */
        start_addr = BLANK_HEAD_SIZE * 2;
        if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
                start_addr >>= 1;
        sp->v.start += start_addr;
        sp->v.end += start_addr;
        sp->v.loopstart += start_addr;
        sp->v.loopend += start_addr;

        return 0;
}

/*
 * free a sample block
 */
int
snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp,
                        struct snd_util_memhdr *hdr)
{
        struct snd_emu10k1 *emu;

        emu = rec->hw;
        if (snd_BUG_ON(!sp || !hdr))
                return -EINVAL;

        if (sp->block) {
                snd_emu10k1_synth_free(emu, sp->block);
                sp->block = NULL;
        }
        return 0;
}


/* [<][>][^][v][top][bottom][index][help] */

[funini.com] -> [kei@sodan] -> Kernel Reading