Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Patch routines for the emu8000 (AWE32/64)
0004  *
0005  *  Copyright (C) 1999 Steve Ratcliffe
0006  *  Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
0007  */
0008 
0009 #include "emu8000_local.h"
0010 
0011 #include <linux/sched/signal.h>
0012 #include <linux/uaccess.h>
0013 #include <linux/moduleparam.h>
0014 
0015 static int emu8000_reset_addr;
0016 module_param(emu8000_reset_addr, int, 0444);
0017 MODULE_PARM_DESC(emu8000_reset_addr, "reset write address at each time (makes slowdown)");
0018 
0019 
0020 /*
0021  * Open up channels.
0022  */
0023 static int
0024 snd_emu8000_open_dma(struct snd_emu8000 *emu, int write)
0025 {
0026     int i;
0027 
0028     /* reserve all 30 voices for loading */
0029     for (i = 0; i < EMU8000_DRAM_VOICES; i++) {
0030         snd_emux_lock_voice(emu->emu, i);
0031         snd_emu8000_dma_chan(emu, i, write);
0032     }
0033 
0034     /* assign voice 31 and 32 to ROM */
0035     EMU8000_VTFT_WRITE(emu, 30, 0);
0036     EMU8000_PSST_WRITE(emu, 30, 0x1d8);
0037     EMU8000_CSL_WRITE(emu, 30, 0x1e0);
0038     EMU8000_CCCA_WRITE(emu, 30, 0x1d8);
0039     EMU8000_VTFT_WRITE(emu, 31, 0);
0040     EMU8000_PSST_WRITE(emu, 31, 0x1d8);
0041     EMU8000_CSL_WRITE(emu, 31, 0x1e0);
0042     EMU8000_CCCA_WRITE(emu, 31, 0x1d8);
0043 
0044     return 0;
0045 }
0046 
0047 /*
0048  * Close all dram channels.
0049  */
0050 static void
0051 snd_emu8000_close_dma(struct snd_emu8000 *emu)
0052 {
0053     int i;
0054 
0055     for (i = 0; i < EMU8000_DRAM_VOICES; i++) {
0056         snd_emu8000_dma_chan(emu, i, EMU8000_RAM_CLOSE);
0057         snd_emux_unlock_voice(emu->emu, i);
0058     }
0059 }
0060 
0061 /*
0062  */
0063 
0064 #define BLANK_LOOP_START    4
0065 #define BLANK_LOOP_END      8
0066 #define BLANK_LOOP_SIZE     12
0067 #define BLANK_HEAD_SIZE     48
0068 
0069 /*
0070  * Read a word from userland, taking care of conversions from
0071  * 8bit samples etc.
0072  */
0073 static unsigned short
0074 read_word(const void __user *buf, int offset, int mode)
0075 {
0076     unsigned short c;
0077     if (mode & SNDRV_SFNT_SAMPLE_8BITS) {
0078         unsigned char cc;
0079         get_user(cc, (unsigned char __user *)buf + offset);
0080         c = cc << 8; /* convert 8bit -> 16bit */
0081     } else {
0082 #ifdef SNDRV_LITTLE_ENDIAN
0083         get_user(c, (unsigned short __user *)buf + offset);
0084 #else
0085         unsigned short cc;
0086         get_user(cc, (unsigned short __user *)buf + offset);
0087         c = swab16(cc);
0088 #endif
0089     }
0090     if (mode & SNDRV_SFNT_SAMPLE_UNSIGNED)
0091         c ^= 0x8000; /* unsigned -> signed */
0092     return c;
0093 }
0094 
0095 /*
0096  */
0097 static void
0098 snd_emu8000_write_wait(struct snd_emu8000 *emu)
0099 {
0100     while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
0101         schedule_timeout_interruptible(1);
0102         if (signal_pending(current))
0103             break;
0104     }
0105 }
0106 
0107 /*
0108  * write sample word data
0109  *
0110  * You should not have to keep resetting the address each time
0111  * as the chip is supposed to step on the next address automatically.
0112  * It mostly does, but during writes of some samples at random it
0113  * completely loses words (every one in 16 roughly but with no
0114  * obvious pattern).
0115  *
0116  * This is therefore much slower than need be, but is at least
0117  * working.
0118  */
0119 static inline void
0120 write_word(struct snd_emu8000 *emu, int *offset, unsigned short data)
0121 {
0122     if (emu8000_reset_addr) {
0123         if (emu8000_reset_addr > 1)
0124             snd_emu8000_write_wait(emu);
0125         EMU8000_SMALW_WRITE(emu, *offset);
0126     }
0127     EMU8000_SMLD_WRITE(emu, data);
0128     *offset += 1;
0129 }
0130 
0131 /*
0132  * Write the sample to EMU800 memory.  This routine is invoked out of
0133  * the generic soundfont routines as a callback.
0134  */
0135 int
0136 snd_emu8000_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
0137                struct snd_util_memhdr *hdr,
0138                const void __user *data, long count)
0139 {
0140     int  i;
0141     int  rc;
0142     int  offset;
0143     int  truesize;
0144     int  dram_offset, dram_start;
0145     struct snd_emu8000 *emu;
0146 
0147     emu = rec->hw;
0148     if (snd_BUG_ON(!sp))
0149         return -EINVAL;
0150 
0151     if (sp->v.size == 0)
0152         return 0;
0153 
0154     /* be sure loop points start < end */
0155     if (sp->v.loopstart > sp->v.loopend)
0156         swap(sp->v.loopstart, sp->v.loopend);
0157 
0158     /* compute true data size to be loaded */
0159     truesize = sp->v.size;
0160     if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP))
0161         truesize += sp->v.loopend - sp->v.loopstart;
0162     if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)
0163         truesize += BLANK_LOOP_SIZE;
0164 
0165     sp->block = snd_util_mem_alloc(hdr, truesize * 2);
0166     if (sp->block == NULL) {
0167         /*snd_printd("EMU8000: out of memory\n");*/
0168         /* not ENOMEM (for compatibility) */
0169         return -ENOSPC;
0170     }
0171 
0172     if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS) {
0173         if (!access_ok(data, sp->v.size))
0174             return -EFAULT;
0175     } else {
0176         if (!access_ok(data, sp->v.size * 2))
0177             return -EFAULT;
0178     }
0179 
0180     /* recalculate address offset */
0181     sp->v.end -= sp->v.start;
0182     sp->v.loopstart -= sp->v.start;
0183     sp->v.loopend -= sp->v.start;
0184     sp->v.start = 0;
0185 
0186     /* dram position (in word) -- mem_offset is byte */
0187     dram_offset = EMU8000_DRAM_OFFSET + (sp->block->offset >> 1);
0188     dram_start = dram_offset;
0189 
0190     /* set the total size (store onto obsolete checksum value) */
0191     sp->v.truesize = truesize * 2; /* in bytes */
0192 
0193     snd_emux_terminate_all(emu->emu);
0194     rc = snd_emu8000_open_dma(emu, EMU8000_RAM_WRITE);
0195     if (rc)
0196         return rc;
0197 
0198     /* Set the address to start writing at */
0199     snd_emu8000_write_wait(emu);
0200     EMU8000_SMALW_WRITE(emu, dram_offset);
0201 
0202     /*snd_emu8000_init_fm(emu);*/
0203 
0204 #if 0
0205     /* first block - write 48 samples for silence */
0206     if (! sp->block->offset) {
0207         for (i = 0; i < BLANK_HEAD_SIZE; i++) {
0208             write_word(emu, &dram_offset, 0);
0209         }
0210     }
0211 #endif
0212 
0213     offset = 0;
0214     for (i = 0; i < sp->v.size; i++) {
0215         unsigned short s;
0216 
0217         s = read_word(data, offset, sp->v.mode_flags);
0218         offset++;
0219         write_word(emu, &dram_offset, s);
0220 
0221         /* we may take too long time in this loop.
0222          * so give controls back to kernel if needed.
0223          */
0224         cond_resched();
0225 
0226         if (i == sp->v.loopend &&
0227             (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)))
0228         {
0229             int looplen = sp->v.loopend - sp->v.loopstart;
0230             int k;
0231 
0232             /* copy reverse loop */
0233             for (k = 1; k <= looplen; k++) {
0234                 s = read_word(data, offset - k, sp->v.mode_flags);
0235                 write_word(emu, &dram_offset, s);
0236             }
0237             if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) {
0238                 sp->v.loopend += looplen;
0239             } else {
0240                 sp->v.loopstart += looplen;
0241                 sp->v.loopend += looplen;
0242             }
0243             sp->v.end += looplen;
0244         }
0245     }
0246 
0247     /* if no blank loop is attached in the sample, add it */
0248     if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
0249         for (i = 0; i < BLANK_LOOP_SIZE; i++) {
0250             write_word(emu, &dram_offset, 0);
0251         }
0252         if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
0253             sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
0254             sp->v.loopend = sp->v.end + BLANK_LOOP_END;
0255         }
0256     }
0257 
0258     /* add dram offset */
0259     sp->v.start += dram_start;
0260     sp->v.end += dram_start;
0261     sp->v.loopstart += dram_start;
0262     sp->v.loopend += dram_start;
0263 
0264     snd_emu8000_close_dma(emu);
0265     snd_emu8000_init_fm(emu);
0266 
0267     return 0;
0268 }
0269 
0270 /*
0271  * free a sample block
0272  */
0273 int
0274 snd_emu8000_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp,
0275             struct snd_util_memhdr *hdr)
0276 {
0277     if (sp->block) {
0278         snd_util_mem_free(hdr, sp->block);
0279         sp->block = NULL;
0280     }
0281     return 0;
0282 }
0283 
0284 
0285 /*
0286  * sample_reset callback - terminate voices
0287  */
0288 void
0289 snd_emu8000_sample_reset(struct snd_emux *rec)
0290 {
0291     snd_emux_terminate_all(rec);
0292 }