Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Patch transfer callback for Emu10k1
0004  *
0005  *  Copyright (C) 2000 Takashi iwai <tiwai@suse.de>
0006  */
0007 /*
0008  * All the code for loading in a patch.  There is very little that is
0009  * chip specific here.  Just the actual writing to the board.
0010  */
0011 
0012 #include "emu10k1_synth_local.h"
0013 
0014 /*
0015  */
0016 #define BLANK_LOOP_START    4
0017 #define BLANK_LOOP_END      8
0018 #define BLANK_LOOP_SIZE     12
0019 #define BLANK_HEAD_SIZE     32
0020 
0021 /*
0022  * allocate a sample block and copy data from userspace
0023  */
0024 int
0025 snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
0026                struct snd_util_memhdr *hdr,
0027                const void __user *data, long count)
0028 {
0029     int offset;
0030     int truesize, size, blocksize;
0031     __maybe_unused int loopsize;
0032     int loopend, sampleend;
0033     unsigned int start_addr;
0034     struct snd_emu10k1 *emu;
0035 
0036     emu = rec->hw;
0037     if (snd_BUG_ON(!sp || !hdr))
0038         return -EINVAL;
0039 
0040     if (sp->v.size == 0) {
0041         dev_dbg(emu->card->dev,
0042             "emu: rom font for sample %d\n", sp->v.sample);
0043         return 0;
0044     }
0045 
0046     /* recalculate address offset */
0047     sp->v.end -= sp->v.start;
0048     sp->v.loopstart -= sp->v.start;
0049     sp->v.loopend -= sp->v.start;
0050     sp->v.start = 0;
0051 
0052     /* some samples have invalid data.  the addresses are corrected in voice info */
0053     sampleend = sp->v.end;
0054     if (sampleend > sp->v.size)
0055         sampleend = sp->v.size;
0056     loopend = sp->v.loopend;
0057     if (loopend > sampleend)
0058         loopend = sampleend;
0059 
0060     /* be sure loop points start < end */
0061     if (sp->v.loopstart >= sp->v.loopend)
0062         swap(sp->v.loopstart, sp->v.loopend);
0063 
0064     /* compute true data size to be loaded */
0065     truesize = sp->v.size + BLANK_HEAD_SIZE;
0066     loopsize = 0;
0067 #if 0 /* not supported */
0068     if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP))
0069         loopsize = sp->v.loopend - sp->v.loopstart;
0070     truesize += loopsize;
0071 #endif
0072     if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)
0073         truesize += BLANK_LOOP_SIZE;
0074 
0075     /* try to allocate a memory block */
0076     blocksize = truesize;
0077     if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
0078         blocksize *= 2;
0079     sp->block = snd_emu10k1_synth_alloc(emu, blocksize);
0080     if (sp->block == NULL) {
0081         dev_dbg(emu->card->dev,
0082             "synth malloc failed (size=%d)\n", blocksize);
0083         /* not ENOMEM (for compatibility with OSS) */
0084         return -ENOSPC;
0085     }
0086     /* set the total size */
0087     sp->v.truesize = blocksize;
0088 
0089     /* write blank samples at head */
0090     offset = 0;
0091     size = BLANK_HEAD_SIZE;
0092     if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
0093         size *= 2;
0094     if (offset + size > blocksize)
0095         return -EINVAL;
0096     snd_emu10k1_synth_bzero(emu, sp->block, offset, size);
0097     offset += size;
0098 
0099     /* copy start->loopend */
0100     size = loopend;
0101     if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
0102         size *= 2;
0103     if (offset + size > blocksize)
0104         return -EINVAL;
0105     if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
0106         snd_emu10k1_synth_free(emu, sp->block);
0107         sp->block = NULL;
0108         return -EFAULT;
0109     }
0110     offset += size;
0111     data += size;
0112 
0113 #if 0 /* not supported yet */
0114     /* handle reverse (or bidirectional) loop */
0115     if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) {
0116         /* copy loop in reverse */
0117         if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
0118             int woffset;
0119             unsigned short *wblock = (unsigned short*)block;
0120             woffset = offset / 2;
0121             if (offset + loopsize * 2 > blocksize)
0122                 return -EINVAL;
0123             for (i = 0; i < loopsize; i++)
0124                 wblock[woffset + i] = wblock[woffset - i -1];
0125             offset += loopsize * 2;
0126         } else {
0127             if (offset + loopsize > blocksize)
0128                 return -EINVAL;
0129             for (i = 0; i < loopsize; i++)
0130                 block[offset + i] = block[offset - i -1];
0131             offset += loopsize;
0132         }
0133 
0134         /* modify loop pointers */
0135         if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) {
0136             sp->v.loopend += loopsize;
0137         } else {
0138             sp->v.loopstart += loopsize;
0139             sp->v.loopend += loopsize;
0140         }
0141         /* add sample pointer */
0142         sp->v.end += loopsize;
0143     }
0144 #endif
0145 
0146     /* loopend -> sample end */
0147     size = sp->v.size - loopend;
0148     if (size < 0)
0149         return -EINVAL;
0150     if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
0151         size *= 2;
0152     if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
0153         snd_emu10k1_synth_free(emu, sp->block);
0154         sp->block = NULL;
0155         return -EFAULT;
0156     }
0157     offset += size;
0158 
0159     /* clear rest of samples (if any) */
0160     if (offset < blocksize)
0161         snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset);
0162 
0163     if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
0164         /* if no blank loop is attached in the sample, add it */
0165         if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
0166             sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
0167             sp->v.loopend = sp->v.end + BLANK_LOOP_END;
0168         }
0169     }
0170 
0171 #if 0 /* not supported yet */
0172     if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) {
0173         /* unsigned -> signed */
0174         if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
0175             unsigned short *wblock = (unsigned short*)block;
0176             for (i = 0; i < truesize; i++)
0177                 wblock[i] ^= 0x8000;
0178         } else {
0179             for (i = 0; i < truesize; i++)
0180                 block[i] ^= 0x80;
0181         }
0182     }
0183 #endif
0184 
0185     /* recalculate offset */
0186     start_addr = BLANK_HEAD_SIZE * 2;
0187     if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
0188         start_addr >>= 1;
0189     sp->v.start += start_addr;
0190     sp->v.end += start_addr;
0191     sp->v.loopstart += start_addr;
0192     sp->v.loopend += start_addr;
0193 
0194     return 0;
0195 }
0196 
0197 /*
0198  * free a sample block
0199  */
0200 int
0201 snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp,
0202             struct snd_util_memhdr *hdr)
0203 {
0204     struct snd_emu10k1 *emu;
0205 
0206     emu = rec->hw;
0207     if (snd_BUG_ON(!sp || !hdr))
0208         return -EINVAL;
0209 
0210     if (sp->block) {
0211         snd_emu10k1_synth_free(emu, sp->block);
0212         sp->block = NULL;
0213     }
0214     return 0;
0215 }
0216