root/sound/isa/sb/emu8000_patch.c

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

DEFINITIONS

This source file includes following definitions.
  1. snd_emu8000_open_dma
  2. snd_emu8000_close_dma
  3. read_word
  4. snd_emu8000_write_wait
  5. write_word
  6. snd_emu8000_sample_new
  7. snd_emu8000_sample_free
  8. snd_emu8000_sample_reset

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Patch routines for the emu8000 (AWE32/64)
   4  *
   5  *  Copyright (C) 1999 Steve Ratcliffe
   6  *  Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
   7  */
   8 
   9 #include "emu8000_local.h"
  10 
  11 #include <linux/sched/signal.h>
  12 #include <linux/uaccess.h>
  13 #include <linux/moduleparam.h>
  14 
  15 static int emu8000_reset_addr;
  16 module_param(emu8000_reset_addr, int, 0444);
  17 MODULE_PARM_DESC(emu8000_reset_addr, "reset write address at each time (makes slowdown)");
  18 
  19 
  20 /*
  21  * Open up channels.
  22  */
  23 static int
  24 snd_emu8000_open_dma(struct snd_emu8000 *emu, int write)
  25 {
  26         int i;
  27 
  28         /* reserve all 30 voices for loading */
  29         for (i = 0; i < EMU8000_DRAM_VOICES; i++) {
  30                 snd_emux_lock_voice(emu->emu, i);
  31                 snd_emu8000_dma_chan(emu, i, write);
  32         }
  33 
  34         /* assign voice 31 and 32 to ROM */
  35         EMU8000_VTFT_WRITE(emu, 30, 0);
  36         EMU8000_PSST_WRITE(emu, 30, 0x1d8);
  37         EMU8000_CSL_WRITE(emu, 30, 0x1e0);
  38         EMU8000_CCCA_WRITE(emu, 30, 0x1d8);
  39         EMU8000_VTFT_WRITE(emu, 31, 0);
  40         EMU8000_PSST_WRITE(emu, 31, 0x1d8);
  41         EMU8000_CSL_WRITE(emu, 31, 0x1e0);
  42         EMU8000_CCCA_WRITE(emu, 31, 0x1d8);
  43 
  44         return 0;
  45 }
  46 
  47 /*
  48  * Close all dram channels.
  49  */
  50 static void
  51 snd_emu8000_close_dma(struct snd_emu8000 *emu)
  52 {
  53         int i;
  54 
  55         for (i = 0; i < EMU8000_DRAM_VOICES; i++) {
  56                 snd_emu8000_dma_chan(emu, i, EMU8000_RAM_CLOSE);
  57                 snd_emux_unlock_voice(emu->emu, i);
  58         }
  59 }
  60 
  61 /*
  62  */
  63 
  64 #define BLANK_LOOP_START        4
  65 #define BLANK_LOOP_END          8
  66 #define BLANK_LOOP_SIZE         12
  67 #define BLANK_HEAD_SIZE         48
  68 
  69 /*
  70  * Read a word from userland, taking care of conversions from
  71  * 8bit samples etc.
  72  */
  73 static unsigned short
  74 read_word(const void __user *buf, int offset, int mode)
  75 {
  76         unsigned short c;
  77         if (mode & SNDRV_SFNT_SAMPLE_8BITS) {
  78                 unsigned char cc;
  79                 get_user(cc, (unsigned char __user *)buf + offset);
  80                 c = cc << 8; /* convert 8bit -> 16bit */
  81         } else {
  82 #ifdef SNDRV_LITTLE_ENDIAN
  83                 get_user(c, (unsigned short __user *)buf + offset);
  84 #else
  85                 unsigned short cc;
  86                 get_user(cc, (unsigned short __user *)buf + offset);
  87                 c = swab16(cc);
  88 #endif
  89         }
  90         if (mode & SNDRV_SFNT_SAMPLE_UNSIGNED)
  91                 c ^= 0x8000; /* unsigned -> signed */
  92         return c;
  93 }
  94 
  95 /*
  96  */
  97 static void
  98 snd_emu8000_write_wait(struct snd_emu8000 *emu)
  99 {
 100         while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
 101                 schedule_timeout_interruptible(1);
 102                 if (signal_pending(current))
 103                         break;
 104         }
 105 }
 106 
 107 /*
 108  * write sample word data
 109  *
 110  * You should not have to keep resetting the address each time
 111  * as the chip is supposed to step on the next address automatically.
 112  * It mostly does, but during writes of some samples at random it
 113  * completely loses words (every one in 16 roughly but with no
 114  * obvious pattern).
 115  *
 116  * This is therefore much slower than need be, but is at least
 117  * working.
 118  */
 119 static inline void
 120 write_word(struct snd_emu8000 *emu, int *offset, unsigned short data)
 121 {
 122         if (emu8000_reset_addr) {
 123                 if (emu8000_reset_addr > 1)
 124                         snd_emu8000_write_wait(emu);
 125                 EMU8000_SMALW_WRITE(emu, *offset);
 126         }
 127         EMU8000_SMLD_WRITE(emu, data);
 128         *offset += 1;
 129 }
 130 
 131 /*
 132  * Write the sample to EMU800 memory.  This routine is invoked out of
 133  * the generic soundfont routines as a callback.
 134  */
 135 int
 136 snd_emu8000_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 137                        struct snd_util_memhdr *hdr,
 138                        const void __user *data, long count)
 139 {
 140         int  i;
 141         int  rc;
 142         int  offset;
 143         int  truesize;
 144         int  dram_offset, dram_start;
 145         struct snd_emu8000 *emu;
 146 
 147         emu = rec->hw;
 148         if (snd_BUG_ON(!sp))
 149                 return -EINVAL;
 150 
 151         if (sp->v.size == 0)
 152                 return 0;
 153 
 154         /* be sure loop points start < end */
 155         if (sp->v.loopstart > sp->v.loopend)
 156                 swap(sp->v.loopstart, sp->v.loopend);
 157 
 158         /* compute true data size to be loaded */
 159         truesize = sp->v.size;
 160         if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP))
 161                 truesize += sp->v.loopend - sp->v.loopstart;
 162         if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)
 163                 truesize += BLANK_LOOP_SIZE;
 164 
 165         sp->block = snd_util_mem_alloc(hdr, truesize * 2);
 166         if (sp->block == NULL) {
 167                 /*snd_printd("EMU8000: out of memory\n");*/
 168                 /* not ENOMEM (for compatibility) */
 169                 return -ENOSPC;
 170         }
 171 
 172         if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS) {
 173                 if (!access_ok(data, sp->v.size))
 174                         return -EFAULT;
 175         } else {
 176                 if (!access_ok(data, sp->v.size * 2))
 177                         return -EFAULT;
 178         }
 179 
 180         /* recalculate address offset */
 181         sp->v.end -= sp->v.start;
 182         sp->v.loopstart -= sp->v.start;
 183         sp->v.loopend -= sp->v.start;
 184         sp->v.start = 0;
 185 
 186         /* dram position (in word) -- mem_offset is byte */
 187         dram_offset = EMU8000_DRAM_OFFSET + (sp->block->offset >> 1);
 188         dram_start = dram_offset;
 189 
 190         /* set the total size (store onto obsolete checksum value) */
 191         sp->v.truesize = truesize * 2; /* in bytes */
 192 
 193         snd_emux_terminate_all(emu->emu);
 194         if ((rc = snd_emu8000_open_dma(emu, EMU8000_RAM_WRITE)) != 0)
 195                 return rc;
 196 
 197         /* Set the address to start writing at */
 198         snd_emu8000_write_wait(emu);
 199         EMU8000_SMALW_WRITE(emu, dram_offset);
 200 
 201         /*snd_emu8000_init_fm(emu);*/
 202 
 203 #if 0
 204         /* first block - write 48 samples for silence */
 205         if (! sp->block->offset) {
 206                 for (i = 0; i < BLANK_HEAD_SIZE; i++) {
 207                         write_word(emu, &dram_offset, 0);
 208                 }
 209         }
 210 #endif
 211 
 212         offset = 0;
 213         for (i = 0; i < sp->v.size; i++) {
 214                 unsigned short s;
 215 
 216                 s = read_word(data, offset, sp->v.mode_flags);
 217                 offset++;
 218                 write_word(emu, &dram_offset, s);
 219 
 220                 /* we may take too long time in this loop.
 221                  * so give controls back to kernel if needed.
 222                  */
 223                 cond_resched();
 224 
 225                 if (i == sp->v.loopend &&
 226                     (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)))
 227                 {
 228                         int looplen = sp->v.loopend - sp->v.loopstart;
 229                         int k;
 230 
 231                         /* copy reverse loop */
 232                         for (k = 1; k <= looplen; k++) {
 233                                 s = read_word(data, offset - k, sp->v.mode_flags);
 234                                 write_word(emu, &dram_offset, s);
 235                         }
 236                         if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) {
 237                                 sp->v.loopend += looplen;
 238                         } else {
 239                                 sp->v.loopstart += looplen;
 240                                 sp->v.loopend += looplen;
 241                         }
 242                         sp->v.end += looplen;
 243                 }
 244         }
 245 
 246         /* if no blank loop is attached in the sample, add it */
 247         if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
 248                 for (i = 0; i < BLANK_LOOP_SIZE; i++) {
 249                         write_word(emu, &dram_offset, 0);
 250                 }
 251                 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
 252                         sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
 253                         sp->v.loopend = sp->v.end + BLANK_LOOP_END;
 254                 }
 255         }
 256 
 257         /* add dram offset */
 258         sp->v.start += dram_start;
 259         sp->v.end += dram_start;
 260         sp->v.loopstart += dram_start;
 261         sp->v.loopend += dram_start;
 262 
 263         snd_emu8000_close_dma(emu);
 264         snd_emu8000_init_fm(emu);
 265 
 266         return 0;
 267 }
 268 
 269 /*
 270  * free a sample block
 271  */
 272 int
 273 snd_emu8000_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp,
 274                         struct snd_util_memhdr *hdr)
 275 {
 276         if (sp->block) {
 277                 snd_util_mem_free(hdr, sp->block);
 278                 sp->block = NULL;
 279         }
 280         return 0;
 281 }
 282 
 283 
 284 /*
 285  * sample_reset callback - terminate voices
 286  */
 287 void
 288 snd_emu8000_sample_reset(struct snd_emux *rec)
 289 {
 290         snd_emux_terminate_all(rec);
 291 }

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