gus_wave.c 78.7 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
Linus Torvalds's avatar
Linus Torvalds committed
2
 * sound/gus_wave.c
Linus Torvalds's avatar
Linus Torvalds committed
3
 *
4
 * Driver for the Gravis UltraSound wave table synth.
Linus Torvalds's avatar
Linus Torvalds committed
5 6 7
 */
/*
 * Copyright by Hannu Savolainen 1993-1996
Linus Torvalds's avatar
Linus Torvalds committed
8
 *
9 10 11 12 13 14 15
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer. 2.
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
Linus Torvalds's avatar
Linus Torvalds committed
16
 *
17 18 19 20 21 22 23 24 25 26 27 28
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
Linus Torvalds's avatar
Linus Torvalds committed
29 30
#include <linux/config.h>

31 32

#include "sound_config.h"
Linus Torvalds's avatar
Linus Torvalds committed
33
#include <linux/ultrasound.h>
34 35
#include "gus_hw.h"

Linus Torvalds's avatar
Linus Torvalds committed
36
#if defined(CONFIG_GUS)
37

Linus Torvalds's avatar
Linus Torvalds committed
38
#define MAX_SAMPLE	150
39 40
#define MAX_PATCH	256

Linus Torvalds's avatar
Linus Torvalds committed
41 42
#define NOT_SAMPLE	0xffff

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
struct voice_info
  {
    unsigned long   orig_freq;
    unsigned long   current_freq;
    unsigned long   mode;
    int             bender;
    int             bender_range;
    int             panning;
    int             midi_volume;
    unsigned int    initial_volume;
    unsigned int    current_volume;
    int             loop_irq_mode, loop_irq_parm;
#define LMODE_FINISH		1
#define LMODE_PCM		2
#define LMODE_PCM_STOP		3
    int             volume_irq_mode, volume_irq_parm;
#define VMODE_HALT		1
#define VMODE_ENVELOPE		2
Linus Torvalds's avatar
Linus Torvalds committed
61
#define VMODE_START_NOTE	3
62 63 64 65 66

    int             env_phase;
    unsigned char   env_rate[6];
    unsigned char   env_offset[6];

Linus Torvalds's avatar
Linus Torvalds committed
67
    /*
68 69 70 71
     * Volume computation parameters for gus_adagio_vol()
     */
    int             main_vol, expression_vol, patch_vol;

Linus Torvalds's avatar
Linus Torvalds committed
72 73 74 75 76
    /* Variables for "Ultraclick" removal */
    int             dev_pending, note_pending, volume_pending, sample_pending;
    char            kill_pending;
    long            offset_pending;

77 78
  };

Linus Torvalds's avatar
Linus Torvalds committed
79 80
static struct voice_alloc_info *voice_alloc;

81 82
extern int      gus_base;
extern int      gus_irq, gus_dma;
Linus Torvalds's avatar
Linus Torvalds committed
83
extern int      gus_pnp_flag;
Linus Torvalds's avatar
Linus Torvalds committed
84
static int      gus_dma2 = -1;
Linus Torvalds's avatar
Linus Torvalds committed
85
static int      dual_dma_mode = 0;
86 87 88
static long     gus_mem_size = 0;
static long     free_mem_ptr = 0;
static int      gus_busy = 0;
Linus Torvalds's avatar
Linus Torvalds committed
89
static int      gus_no_dma = 0;
Linus Torvalds's avatar
Linus Torvalds committed
90
static int      nr_voices = 0;
91 92
static int      gus_devnum = 0;
static int      volume_base, volume_scale, volume_method;
Linus Torvalds's avatar
Linus Torvalds committed
93 94
static int      gus_recmask = SOUND_MASK_MIC;
static int      recording_active = 0;
Linus Torvalds's avatar
Linus Torvalds committed
95
static int      only_read_access = 0;
Linus Torvalds's avatar
Linus Torvalds committed
96
static int      only_8_bits = 0;
97

Linus Torvalds's avatar
Linus Torvalds committed
98 99
int             gus_wave_volume = 60;
int             gus_pcm_volume = 80;
Linus Torvalds's avatar
Linus Torvalds committed
100 101
int             have_gus_max = 0;
static int      gus_line_vol = 100, gus_mic_vol = 0;
102 103
static unsigned char mix_image = 0x00;

Linus Torvalds's avatar
Linus Torvalds committed
104 105
int             gus_timer_enabled = 0;

Linus Torvalds's avatar
Linus Torvalds committed
106
/*
Linus Torvalds's avatar
Linus Torvalds committed
107
 * Current version of this driver doesn't allow synth and PCM functions
108 109 110 111
 * at the same time. The active_device specifies the active driver
 */
static int      active_device = 0;

Linus Torvalds's avatar
Linus Torvalds committed
112 113 114
#define GUS_DEV_WAVE		1	/* Wave table synth */
#define GUS_DEV_PCM_DONE	2	/* PCM device, transfer done */
#define GUS_DEV_PCM_CONTINUE	3	/* PCM device, transfer done ch. 1/2 */
115 116 117 118 119

static int      gus_sampling_speed;
static int      gus_sampling_channels;
static int      gus_sampling_bits;

Linus Torvalds's avatar
Linus Torvalds committed
120
static wait_handle *dram_sleeper = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
121 122
static volatile struct snd_wait dram_sleep_flag =
{0};
123

Linus Torvalds's avatar
Linus Torvalds committed
124
/*
125 126
 * Variables and buffers for PCM output
 */
Linus Torvalds's avatar
Linus Torvalds committed
127
#define MAX_PCM_BUFFERS		(32*MAX_REALTIME_FACTOR)	/* Don't change */
Linus Torvalds's avatar
Linus Torvalds committed
128

Linus Torvalds's avatar
Linus Torvalds committed
129 130 131
static int      pcm_bsize, pcm_nblk, pcm_banksize;
static int      pcm_datasize[MAX_PCM_BUFFERS];
static volatile int pcm_head, pcm_tail, pcm_qlen;
132
static volatile int pcm_active;
Linus Torvalds's avatar
Linus Torvalds committed
133
static volatile int dma_active;
Linus Torvalds's avatar
Linus Torvalds committed
134
static int      pcm_opened = 0;
135 136 137 138 139 140
static int      pcm_current_dev;
static int      pcm_current_block;
static unsigned long pcm_current_buf;
static int      pcm_current_count;
static int      pcm_current_intrflag;

Linus Torvalds's avatar
Linus Torvalds committed
141
extern int     *gus_osp;
Linus Torvalds's avatar
Linus Torvalds committed
142

143 144 145 146
struct voice_info voices[32];

static int      freq_div_table[] =
{
Linus Torvalds's avatar
Linus Torvalds committed
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
  44100,			/* 14 */
  41160,			/* 15 */
  38587,			/* 16 */
  36317,			/* 17 */
  34300,			/* 18 */
  32494,			/* 19 */
  30870,			/* 20 */
  29400,			/* 21 */
  28063,			/* 22 */
  26843,			/* 23 */
  25725,			/* 24 */
  24696,			/* 25 */
  23746,			/* 26 */
  22866,			/* 27 */
  22050,			/* 28 */
  21289,			/* 29 */
  20580,			/* 30 */
  19916,			/* 31 */
  19293				/* 32 */
166 167
};

Linus Torvalds's avatar
Linus Torvalds committed
168
static struct patch_info *samples;
169 170 171
static long     sample_ptrs[MAX_SAMPLE + 1];
static int      sample_map[32];
static int      free_sample;
Linus Torvalds's avatar
Linus Torvalds committed
172
static int      mixer_type = 0;
173 174 175 176 177 178 179 180 181 182 183


static int      patch_table[MAX_PATCH];
static int      patch_map[32];

static struct synth_info gus_info =
{"Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH};

static void     gus_poke (long addr, unsigned char data);
static void     compute_and_set_volume (int voice, int volume, int ramp_time);
extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev);
Linus Torvalds's avatar
Linus Torvalds committed
184
extern unsigned short gus_linear_vol (int vol, int mainvol);
185
static void     compute_volume (int voice, int volume);
Linus Torvalds's avatar
Linus Torvalds committed
186
static void     do_volume_irq (int voice);
Linus Torvalds's avatar
Linus Torvalds committed
187
static void     set_input_volumes (void);
Linus Torvalds's avatar
Linus Torvalds committed
188
static void     gus_tmr_install (int io_base);
189

Linus Torvalds's avatar
Linus Torvalds committed
190 191
#define	INSTANT_RAMP		-1	/* Instant change. No ramping */
#define FAST_RAMP		0	/* Fastest possible ramp */
192 193 194 195 196 197 198 199 200 201 202 203 204

static void
reset_sample_memory (void)
{
  int             i;

  for (i = 0; i <= MAX_SAMPLE; i++)
    sample_ptrs[i] = -1;
  for (i = 0; i < 32; i++)
    sample_map[i] = -1;
  for (i = 0; i < 32; i++)
    patch_map[i] = -1;

Linus Torvalds's avatar
Linus Torvalds committed
205
  gus_poke (0, 0);		/* Put a silent sample to the beginning */
206 207
  gus_poke (1, 0);
  free_mem_ptr = 2;
Linus Torvalds's avatar
Linus Torvalds committed
208

209 210 211
  free_sample = 0;

  for (i = 0; i < MAX_PATCH; i++)
Linus Torvalds's avatar
Linus Torvalds committed
212
    patch_table[i] = NOT_SAMPLE;
213 214 215 216 217 218 219 220
}

void
gus_delay (void)
{
  int             i;

  for (i = 0; i < 7; i++)
Linus Torvalds's avatar
Linus Torvalds committed
221
    inb (u_DRAMIO);
222 223 224 225
}

static void
gus_poke (long addr, unsigned char data)
Linus Torvalds's avatar
Linus Torvalds committed
226
{				/* Writes a byte to the DRAM */
227 228
  unsigned long   flags;

Linus Torvalds's avatar
Linus Torvalds committed
229 230 231 232 233
  save_flags (flags);
  cli ();
  outb (0x43, u_Command);
  outb (addr & 0xff, u_DataLo);
  outb ((addr >> 8) & 0xff, u_DataHi);
234

Linus Torvalds's avatar
Linus Torvalds committed
235 236 237 238
  outb (0x44, u_Command);
  outb ((addr >> 16) & 0xff, u_DataHi);
  outb (data, u_DRAMIO);
  restore_flags (flags);
239 240 241 242
}

static unsigned char
gus_peek (long addr)
Linus Torvalds's avatar
Linus Torvalds committed
243
{				/* Reads a byte from the DRAM */
244 245 246
  unsigned long   flags;
  unsigned char   tmp;

Linus Torvalds's avatar
Linus Torvalds committed
247 248 249 250 251
  save_flags (flags);
  cli ();
  outb (0x43, u_Command);
  outb (addr & 0xff, u_DataLo);
  outb ((addr >> 8) & 0xff, u_DataHi);
252

Linus Torvalds's avatar
Linus Torvalds committed
253 254 255 256
  outb (0x44, u_Command);
  outb ((addr >> 16) & 0xff, u_DataHi);
  tmp = inb (u_DRAMIO);
  restore_flags (flags);
257 258 259 260 261

  return tmp;
}

void
Linus Torvalds's avatar
Linus Torvalds committed
262
gus_write8 (int reg, unsigned int data)
Linus Torvalds's avatar
Linus Torvalds committed
263
{				/* Writes to an indirect register (8 bit) */
264 265
  unsigned long   flags;

Linus Torvalds's avatar
Linus Torvalds committed
266 267
  save_flags (flags);
  cli ();
268

Linus Torvalds's avatar
Linus Torvalds committed
269 270
  outb (reg, u_Command);
  outb ((unsigned char) (data & 0xff), u_DataHi);
271

Linus Torvalds's avatar
Linus Torvalds committed
272
  restore_flags (flags);
273 274 275 276
}

unsigned char
gus_read8 (int reg)
Linus Torvalds's avatar
Linus Torvalds committed
277
{				/* Reads from an indirect register (8 bit). Offset 0x80. */
278 279 280
  unsigned long   flags;
  unsigned char   val;

Linus Torvalds's avatar
Linus Torvalds committed
281 282 283 284 285
  save_flags (flags);
  cli ();
  outb (reg | 0x80, u_Command);
  val = inb (u_DataHi);
  restore_flags (flags);
286 287 288 289 290 291

  return val;
}

unsigned char
gus_look8 (int reg)
Linus Torvalds's avatar
Linus Torvalds committed
292
{				/* Reads from an indirect register (8 bit). No additional offset. */
293 294 295
  unsigned long   flags;
  unsigned char   val;

Linus Torvalds's avatar
Linus Torvalds committed
296 297 298 299 300
  save_flags (flags);
  cli ();
  outb (reg, u_Command);
  val = inb (u_DataHi);
  restore_flags (flags);
301 302 303 304 305

  return val;
}

void
Linus Torvalds's avatar
Linus Torvalds committed
306
gus_write16 (int reg, unsigned int data)
Linus Torvalds's avatar
Linus Torvalds committed
307
{				/* Writes to an indirect register (16 bit) */
308 309
  unsigned long   flags;

Linus Torvalds's avatar
Linus Torvalds committed
310 311
  save_flags (flags);
  cli ();
312

Linus Torvalds's avatar
Linus Torvalds committed
313
  outb (reg, u_Command);
314

Linus Torvalds's avatar
Linus Torvalds committed
315 316
  outb ((unsigned char) (data & 0xff), u_DataLo);
  outb ((unsigned char) ((data >> 8) & 0xff), u_DataHi);
317

Linus Torvalds's avatar
Linus Torvalds committed
318
  restore_flags (flags);
319 320 321 322
}

unsigned short
gus_read16 (int reg)
Linus Torvalds's avatar
Linus Torvalds committed
323
{				/* Reads from an indirect register (16 bit). Offset 0x80. */
324 325 326
  unsigned long   flags;
  unsigned char   hi, lo;

Linus Torvalds's avatar
Linus Torvalds committed
327 328
  save_flags (flags);
  cli ();
329

Linus Torvalds's avatar
Linus Torvalds committed
330
  outb (reg | 0x80, u_Command);
331

Linus Torvalds's avatar
Linus Torvalds committed
332 333
  lo = inb (u_DataLo);
  hi = inb (u_DataHi);
334

Linus Torvalds's avatar
Linus Torvalds committed
335
  restore_flags (flags);
336 337 338 339 340 341

  return ((hi << 8) & 0xff00) | lo;
}

void
gus_write_addr (int reg, unsigned long address, int is16bit)
Linus Torvalds's avatar
Linus Torvalds committed
342
{				/* Writes an 24 bit memory address */
343
  unsigned long   hold_address;
Linus Torvalds's avatar
Linus Torvalds committed
344
  unsigned long   flags;
345

Linus Torvalds's avatar
Linus Torvalds committed
346 347
  save_flags (flags);
  cli ();
348 349
  if (is16bit)
    {
Linus Torvalds's avatar
Linus Torvalds committed
350
      /*
351 352 353 354 355 356 357 358 359 360 361
       * Special processing required for 16 bit patches
       */

      hold_address = address;
      address = address >> 1;
      address &= 0x0001ffffL;
      address |= (hold_address & 0x000c0000L);
    }

  gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
  gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
Linus Torvalds's avatar
Linus Torvalds committed
362 363 364 365
  /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */
  gus_delay ();
  gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
  gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
Linus Torvalds's avatar
Linus Torvalds committed
366
  restore_flags (flags);
367 368 369 370 371 372 373 374
}

static void
gus_select_voice (int voice)
{
  if (voice < 0 || voice > 31)
    return;

Linus Torvalds's avatar
Linus Torvalds committed
375
  outb (voice, u_Voice);
376 377 378 379 380 381 382 383 384 385
}

static void
gus_select_max_voices (int nvoices)
{
  if (nvoices < 14)
    nvoices = 14;
  if (nvoices > 32)
    nvoices = 32;

Linus Torvalds's avatar
Linus Torvalds committed
386
  voice_alloc->max_voice = nr_voices = nvoices;
387 388 389 390 391

  gus_write8 (0x0e, (nvoices - 1) | 0xc0);
}

static void
Linus Torvalds's avatar
Linus Torvalds committed
392
gus_voice_on (unsigned int mode)
393
{
Linus Torvalds's avatar
Linus Torvalds committed
394
  gus_write8 (0x00, (unsigned char) (mode & 0xfc));
395
  gus_delay ();
Linus Torvalds's avatar
Linus Torvalds committed
396
  gus_write8 (0x00, (unsigned char) (mode & 0xfc));
397 398 399 400 401 402 403 404 405
}

static void
gus_voice_off (void)
{
  gus_write8 (0x00, gus_read8 (0x00) | 0x03);
}

static void
Linus Torvalds's avatar
Linus Torvalds committed
406
gus_voice_mode (unsigned int m)
407
{
Linus Torvalds's avatar
Linus Torvalds committed
408 409
  unsigned char   mode = (unsigned char) (m & 0xff);

Linus Torvalds's avatar
Linus Torvalds committed
410 411
  gus_write8 (0x00, (gus_read8 (0x00) & 0x03) |
	      (mode & 0xfc));	/* Don't touch last two bits */
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
  gus_delay ();
  gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));
}

static void
gus_voice_freq (unsigned long freq)
{
  unsigned long   divisor = freq_div_table[nr_voices - 14];
  unsigned short  fc;

  fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor);
  fc = fc << 1;

  gus_write16 (0x01, fc);
}

static void
Linus Torvalds's avatar
Linus Torvalds committed
429
gus_voice_volume (unsigned int vol)
430
{
Linus Torvalds's avatar
Linus Torvalds committed
431
  gus_write8 (0x0d, 0x03);	/* Stop ramp before setting volume */
Linus Torvalds's avatar
Linus Torvalds committed
432
  gus_write16 (0x09, (unsigned short) (vol << 4));
433 434 435
}

static void
Linus Torvalds's avatar
Linus Torvalds committed
436
gus_voice_balance (unsigned int balance)
437
{
Linus Torvalds's avatar
Linus Torvalds committed
438
  gus_write8 (0x0c, (unsigned char) (balance & 0xff));
439 440 441
}

static void
Linus Torvalds's avatar
Linus Torvalds committed
442
gus_ramp_range (unsigned int low, unsigned int high)
443
{
Linus Torvalds's avatar
Linus Torvalds committed
444 445
  gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff));
  gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff));
446 447 448
}

static void
Linus Torvalds's avatar
Linus Torvalds committed
449
gus_ramp_rate (unsigned int scale, unsigned int rate)
450
{
Linus Torvalds's avatar
Linus Torvalds committed
451
  gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));
452 453 454
}

static void
Linus Torvalds's avatar
Linus Torvalds committed
455
gus_rampon (unsigned int m)
456
{
Linus Torvalds's avatar
Linus Torvalds committed
457
  unsigned char   mode = (unsigned char) (m & 0xff);
Linus Torvalds's avatar
Linus Torvalds committed
458

459 460 461 462 463 464
  gus_write8 (0x0d, mode & 0xfc);
  gus_delay ();
  gus_write8 (0x0d, mode & 0xfc);
}

static void
Linus Torvalds's avatar
Linus Torvalds committed
465
gus_ramp_mode (unsigned int m)
466
{
Linus Torvalds's avatar
Linus Torvalds committed
467
  unsigned char   mode = (unsigned char) (m & 0xff);
Linus Torvalds's avatar
Linus Torvalds committed
468

Linus Torvalds's avatar
Linus Torvalds committed
469 470
  gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) |
	      (mode & 0xfc));	/* Leave the last 2 bits alone */
471 472 473 474 475 476 477 478 479 480
  gus_delay ();
  gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));
}

static void
gus_rampoff (void)
{
  gus_write8 (0x0d, 0x03);
}

Linus Torvalds's avatar
Linus Torvalds committed
481 482 483 484 485 486 487 488 489 490 491 492 493 494
static void
gus_set_voice_pos (int voice, long position)
{
  int             sample_no;

  if ((sample_no = sample_map[voice]) != -1)
    if (position < samples[sample_no].len)
      if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
	voices[voice].offset_pending = position;
      else
	gus_write_addr (0x0a, sample_ptrs[sample_no] + position,
			samples[sample_no].mode & WAVE_16_BITS);
}

495 496 497 498 499
static void
gus_voice_init (int voice)
{
  unsigned long   flags;

Linus Torvalds's avatar
Linus Torvalds committed
500 501
  save_flags (flags);
  cli ();
502 503
  gus_select_voice (voice);
  gus_voice_volume (0);
Linus Torvalds's avatar
Linus Torvalds committed
504
  gus_voice_off ();
Linus Torvalds's avatar
Linus Torvalds committed
505 506 507 508
  gus_write_addr (0x0a, 0, 0);	/* Set current position to 0 */
  gus_write8 (0x00, 0x03);	/* Voice off */
  gus_write8 (0x0d, 0x03);	/* Ramping off */
  voice_alloc->map[voice] = 0;
Linus Torvalds's avatar
Linus Torvalds committed
509
  voice_alloc->alloc_times[voice] = 0;
Linus Torvalds's avatar
Linus Torvalds committed
510
  restore_flags (flags);
511

Linus Torvalds's avatar
Linus Torvalds committed
512 513 514 515 516
}

static void
gus_voice_init2 (int voice)
{
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
  voices[voice].panning = 0;
  voices[voice].mode = 0;
  voices[voice].orig_freq = 20000;
  voices[voice].current_freq = 20000;
  voices[voice].bender = 0;
  voices[voice].bender_range = 200;
  voices[voice].initial_volume = 0;
  voices[voice].current_volume = 0;
  voices[voice].loop_irq_mode = 0;
  voices[voice].loop_irq_parm = 0;
  voices[voice].volume_irq_mode = 0;
  voices[voice].volume_irq_parm = 0;
  voices[voice].env_phase = 0;
  voices[voice].main_vol = 127;
  voices[voice].patch_vol = 127;
  voices[voice].expression_vol = 127;
Linus Torvalds's avatar
Linus Torvalds committed
533
  voices[voice].sample_pending = -1;
534 535 536 537 538 539 540
}

static void
step_envelope (int voice)
{
  unsigned        vol, prev_vol, phase;
  unsigned char   rate;
Linus Torvalds's avatar
Linus Torvalds committed
541
  long int        flags;
542 543 544

  if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
    {
Linus Torvalds's avatar
Linus Torvalds committed
545 546
      save_flags (flags);
      cli ();
Linus Torvalds's avatar
Linus Torvalds committed
547
      gus_select_voice (voice);
548
      gus_rampoff ();
Linus Torvalds's avatar
Linus Torvalds committed
549
      restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
550
      return;
Linus Torvalds's avatar
Linus Torvalds committed
551
      /*
Linus Torvalds's avatar
Linus Torvalds committed
552
       * Sustain phase begins. Continue envelope after receiving note off.
553
       */
Linus Torvalds's avatar
Linus Torvalds committed
554
    }
555

Linus Torvalds's avatar
Linus Torvalds committed
556 557
  if (voices[voice].env_phase >= 5)
    {				/* Envelope finished. Shoot the voice down */
558 559 560 561 562 563 564 565 566
      gus_voice_init (voice);
      return;
    }

  prev_vol = voices[voice].current_volume;
  phase = ++voices[voice].env_phase;
  compute_volume (voice, voices[voice].midi_volume);
  vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
  rate = voices[voice].env_rate[phase];
Linus Torvalds's avatar
Linus Torvalds committed
567

Linus Torvalds's avatar
Linus Torvalds committed
568 569
  save_flags (flags);
  cli ();
Linus Torvalds's avatar
Linus Torvalds committed
570 571 572 573 574
  gus_select_voice (voice);

  gus_voice_volume (prev_vol);


Linus Torvalds's avatar
Linus Torvalds committed
575
  gus_write8 (0x06, rate);	/* Ramping rate */
576 577 578

  voices[voice].volume_irq_mode = VMODE_ENVELOPE;

Linus Torvalds's avatar
Linus Torvalds committed
579
  if (((vol - prev_vol) / 64) == 0)	/* No significant volume change */
580
    {
Linus Torvalds's avatar
Linus Torvalds committed
581
      restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
582
      step_envelope (voice);	/* Continue the envelope on the next step */
583 584 585 586 587 588 589 590
      return;
    }

  if (vol > prev_vol)
    {
      if (vol >= (4096 - 64))
	vol = 4096 - 65;
      gus_ramp_range (0, vol);
Linus Torvalds's avatar
Linus Torvalds committed
591
      gus_rampon (0x20);	/* Increasing volume, with IRQ */
592 593 594 595 596
    }
  else
    {
      if (vol <= 64)
	vol = 65;
Linus Torvalds's avatar
Linus Torvalds committed
597
      gus_ramp_range (vol, 4030);
Linus Torvalds's avatar
Linus Torvalds committed
598
      gus_rampon (0x60);	/* Decreasing volume, with IRQ */
599 600
    }
  voices[voice].current_volume = vol;
Linus Torvalds's avatar
Linus Torvalds committed
601
  restore_flags (flags);
602 603 604 605 606 607 608 609 610 611 612 613
}

static void
init_envelope (int voice)
{
  voices[voice].env_phase = -1;
  voices[voice].current_volume = 64;

  step_envelope (voice);
}

static void
Linus Torvalds's avatar
Linus Torvalds committed
614
start_release (int voice, long int flags)
615 616
{
  if (gus_read8 (0x00) & 0x03)
Linus Torvalds's avatar
Linus Torvalds committed
617
    return;			/* Voice already stopped */
618

Linus Torvalds's avatar
Linus Torvalds committed
619
  voices[voice].env_phase = 2;	/* Will be incremented by step_envelope */
620 621 622

  voices[voice].current_volume =
    voices[voice].initial_volume =
Linus Torvalds's avatar
Linus Torvalds committed
623
    gus_read16 (0x09) >> 4;	/* Get current volume */
624 625 626

  voices[voice].mode &= ~WAVE_SUSTAIN_ON;
  gus_rampoff ();
Linus Torvalds's avatar
Linus Torvalds committed
627
  restore_flags (flags);
628 629 630 631 632 633 634
  step_envelope (voice);
}

static void
gus_voice_fade (int voice)
{
  int             instr_no = sample_map[voice], is16bits;
Linus Torvalds's avatar
Linus Torvalds committed
635 636
  long int        flags;

Linus Torvalds's avatar
Linus Torvalds committed
637 638
  save_flags (flags);
  cli ();
Linus Torvalds's avatar
Linus Torvalds committed
639
  gus_select_voice (voice);
640 641 642

  if (instr_no < 0 || instr_no > MAX_SAMPLE)
    {
Linus Torvalds's avatar
Linus Torvalds committed
643 644
      gus_write8 (0x00, 0x03);	/* Hard stop */
      voice_alloc->map[voice] = 0;
Linus Torvalds's avatar
Linus Torvalds committed
645
      restore_flags (flags);
646 647 648
      return;
    }

Linus Torvalds's avatar
Linus Torvalds committed
649
  is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0;	/* 8 or 16 bits */
650 651 652

  if (voices[voice].mode & WAVE_ENVELOPES)
    {
Linus Torvalds's avatar
Linus Torvalds committed
653
      start_release (voice, flags);
654 655 656
      return;
    }

Linus Torvalds's avatar
Linus Torvalds committed
657
  /*
658 659
   * Ramp the volume down but not too quickly.
   */
Linus Torvalds's avatar
Linus Torvalds committed
660
  if ((int) (gus_read16 (0x09) >> 4) < 100)	/* Get current volume */
661 662 663 664 665 666 667
    {
      gus_voice_off ();
      gus_rampoff ();
      gus_voice_init (voice);
      return;
    }

Linus Torvalds's avatar
Linus Torvalds committed
668
  gus_ramp_range (65, 4030);
669
  gus_ramp_rate (2, 4);
Linus Torvalds's avatar
Linus Torvalds committed
670
  gus_rampon (0x40 | 0x20);	/* Down, once, with IRQ */
671
  voices[voice].volume_irq_mode = VMODE_HALT;
Linus Torvalds's avatar
Linus Torvalds committed
672
  restore_flags (flags);
673 674 675 676 677 678 679 680 681 682 683 684 685 686
}

static void
gus_reset (void)
{
  int             i;

  gus_select_max_voices (24);
  volume_base = 3071;
  volume_scale = 4;
  volume_method = VOL_METHOD_ADAGIO;

  for (i = 0; i < 32; i++)
    {
Linus Torvalds's avatar
Linus Torvalds committed
687
      gus_voice_init (i);	/* Turn voice off */
Linus Torvalds's avatar
Linus Torvalds committed
688
      gus_voice_init2 (i);
689 690
    }

Linus Torvalds's avatar
Linus Torvalds committed
691
  inb (u_Status);		/* Touch the status register */
692

Linus Torvalds's avatar
Linus Torvalds committed
693 694 695 696
  gus_look8 (0x41);		/* Clear any pending DMA IRQs */
  gus_look8 (0x49);		/* Clear any pending sample IRQs */

  gus_read8 (0x0f);		/* Clear pending IRQs */
697 698 699 700 701 702 703

}

static void
gus_initialize (void)
{
  unsigned long   flags;
Linus Torvalds's avatar
Linus Torvalds committed
704
  unsigned char   dma_image, irq_image, tmp;
705 706

  static unsigned char gus_irq_map[16] =
Linus Torvalds's avatar
Linus Torvalds committed
707
  {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7};
708 709 710 711

  static unsigned char gus_dma_map[8] =
  {0, 1, 0, 2, 0, 3, 4, 5};

Linus Torvalds's avatar
Linus Torvalds committed
712 713
  save_flags (flags);
  cli ();
Linus Torvalds's avatar
Linus Torvalds committed
714
  gus_write8 (0x4c, 0);		/* Reset GF1 */
715 716 717
  gus_delay ();
  gus_delay ();

Linus Torvalds's avatar
Linus Torvalds committed
718
  gus_write8 (0x4c, 1);		/* Release Reset */
719 720 721
  gus_delay ();
  gus_delay ();

Linus Torvalds's avatar
Linus Torvalds committed
722
  /*
723 724 725
   * Clear all interrupts
   */

Linus Torvalds's avatar
Linus Torvalds committed
726 727 728
  gus_write8 (0x41, 0);		/* DMA control */
  gus_write8 (0x45, 0);		/* Timer control */
  gus_write8 (0x49, 0);		/* Sample control */
729 730 731

  gus_select_max_voices (24);

Linus Torvalds's avatar
Linus Torvalds committed
732
  inb (u_Status);		/* Touch the status register */
Linus Torvalds's avatar
Linus Torvalds committed
733

Linus Torvalds's avatar
Linus Torvalds committed
734 735 736
  gus_look8 (0x41);		/* Clear any pending DMA IRQs */
  gus_look8 (0x49);		/* Clear any pending sample IRQs */
  gus_read8 (0x0f);		/* Clear pending IRQs */
Linus Torvalds's avatar
Linus Torvalds committed
737

Linus Torvalds's avatar
Linus Torvalds committed
738
  gus_reset ();			/* Resets all voices */
Linus Torvalds's avatar
Linus Torvalds committed
739

Linus Torvalds's avatar
Linus Torvalds committed
740 741 742
  gus_look8 (0x41);		/* Clear any pending DMA IRQs */
  gus_look8 (0x49);		/* Clear any pending sample IRQs */
  gus_read8 (0x0f);		/* Clear pending IRQs */
Linus Torvalds's avatar
Linus Torvalds committed
743

Linus Torvalds's avatar
Linus Torvalds committed
744
  gus_write8 (0x4c, 7);		/* Master reset | DAC enable | IRQ enable */
Linus Torvalds's avatar
Linus Torvalds committed
745

Linus Torvalds's avatar
Linus Torvalds committed
746
  /*
747 748 749
   * Set up for Digital ASIC
   */

Linus Torvalds's avatar
Linus Torvalds committed
750
  outb (0x05, gus_base + 0x0f);
751

Linus Torvalds's avatar
Linus Torvalds committed
752
  mix_image |= 0x02;		/* Disable line out (for a moment) */
Linus Torvalds's avatar
Linus Torvalds committed
753
  outb (mix_image, u_Mixer);
754

Linus Torvalds's avatar
Linus Torvalds committed
755
  outb (0x00, u_IRQDMAControl);
756

Linus Torvalds's avatar
Linus Torvalds committed
757
  outb (0x00, gus_base + 0x0f);
758

Linus Torvalds's avatar
Linus Torvalds committed
759
  /*
760
   * Now set up the DMA and IRQ interface
Linus Torvalds's avatar
Linus Torvalds committed
761
   *
762
   * The GUS supports two IRQs and two DMAs.
Linus Torvalds's avatar
Linus Torvalds committed
763
   *
764 765 766 767 768 769 770
   * Just one DMA channel is used. This prevents simultaneous ADC and DAC.
   * Adding this support requires significant changes to the dmabuf.c, dsp.c
   * and audio.c also.
   */

  irq_image = 0;
  tmp = gus_irq_map[gus_irq];
Linus Torvalds's avatar
Linus Torvalds committed
771
  if (!gus_pnp_flag && !tmp)
772 773
    printk ("Warning! GUS IRQ not selected\n");
  irq_image |= tmp;
Linus Torvalds's avatar
Linus Torvalds committed
774
  irq_image |= 0x40;		/* Combine IRQ1 (GF1) and IRQ2 (Midi) */
775

Linus Torvalds's avatar
Linus Torvalds committed
776
  dual_dma_mode = 1;
Linus Torvalds's avatar
Linus Torvalds committed
777
  if (gus_dma2 == gus_dma || gus_dma2 == -1)
Linus Torvalds's avatar
Linus Torvalds committed
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
    {
      dual_dma_mode = 0;
      dma_image = 0x40;		/* Combine DMA1 (DRAM) and IRQ2 (ADC) */

      tmp = gus_dma_map[gus_dma];
      if (!tmp)
	printk ("Warning! GUS DMA not selected\n");

      dma_image |= tmp;
    }
  else
    /* Setup dual DMA channel mode for GUS MAX */
    {
      dma_image = gus_dma_map[gus_dma];
      if (!dma_image)
	printk ("Warning! GUS DMA not selected\n");

Linus Torvalds's avatar
Linus Torvalds committed
795
      tmp = gus_dma_map[gus_dma2] << 3;
Linus Torvalds's avatar
Linus Torvalds committed
796 797 798 799 800 801 802 803 804
      if (!tmp)
	{
	  printk ("Warning! Invalid GUS MAX DMA\n");
	  tmp = 0x40;		/* Combine DMA channels */
	  dual_dma_mode = 0;
	}

      dma_image |= tmp;
    }
805

Linus Torvalds's avatar
Linus Torvalds committed
806
  /*
807 808 809
   * For some reason the IRQ and DMA addresses must be written twice
   */

Linus Torvalds's avatar
Linus Torvalds committed
810 811
  /*
   * Doing it first time
Linus Torvalds's avatar
Linus Torvalds committed
812
   */
813

Linus Torvalds's avatar
Linus Torvalds committed
814 815
  outb (mix_image, u_Mixer);	/* Select DMA control */
  outb (dma_image | 0x80, u_IRQDMAControl);	/* Set DMA address */
Linus Torvalds's avatar
Linus Torvalds committed
816

Linus Torvalds's avatar
Linus Torvalds committed
817 818
  outb (mix_image | 0x40, u_Mixer);	/* Select IRQ control */
  outb (irq_image, u_IRQDMAControl);	/* Set IRQ address */
Linus Torvalds's avatar
Linus Torvalds committed
819

Linus Torvalds's avatar
Linus Torvalds committed
820 821
  /*
   * Doing it second time
Linus Torvalds's avatar
Linus Torvalds committed
822
   */
823

Linus Torvalds's avatar
Linus Torvalds committed
824 825
  outb (mix_image, u_Mixer);	/* Select DMA control */
  outb (dma_image, u_IRQDMAControl);	/* Set DMA address */
Linus Torvalds's avatar
Linus Torvalds committed
826

Linus Torvalds's avatar
Linus Torvalds committed
827 828
  outb (mix_image | 0x40, u_Mixer);	/* Select IRQ control */
  outb (irq_image, u_IRQDMAControl);	/* Set IRQ address */
Linus Torvalds's avatar
Linus Torvalds committed
829

Linus Torvalds's avatar
Linus Torvalds committed
830
  gus_select_voice (0);		/* This disables writes to IRQ/DMA reg */
Linus Torvalds's avatar
Linus Torvalds committed
831

Linus Torvalds's avatar
Linus Torvalds committed
832 833
  mix_image &= ~0x02;		/* Enable line out */
  mix_image |= 0x08;		/* Enable IRQ */
Linus Torvalds's avatar
Linus Torvalds committed
834
  outb (mix_image, u_Mixer);	/*
Linus Torvalds's avatar
Linus Torvalds committed
835 836
				   * Turn mixer channels on
				   * Note! Mic in is left off.
Linus Torvalds's avatar
Linus Torvalds committed
837 838
				 */

Linus Torvalds's avatar
Linus Torvalds committed
839
  gus_select_voice (0);		/* This disables writes to IRQ/DMA reg */
Linus Torvalds's avatar
Linus Torvalds committed
840

Linus Torvalds's avatar
Linus Torvalds committed
841
  gusintr (0, NULL, NULL);	/* Serve pending interrupts */
Linus Torvalds's avatar
Linus Torvalds committed
842
  restore_flags (flags);
843 844 845 846 847
}

int
gus_wave_detect (int baseaddr)
{
Linus Torvalds's avatar
Linus Torvalds committed
848 849 850
  unsigned long   i;
  unsigned long   loc;

851 852 853 854 855 856 857 858 859 860
  gus_base = baseaddr;

  gus_write8 (0x4c, 0);		/* Reset GF1 */
  gus_delay ();
  gus_delay ();

  gus_write8 (0x4c, 1);		/* Release Reset */
  gus_delay ();
  gus_delay ();

Linus Torvalds's avatar
Linus Torvalds committed
861 862 863 864
  /* See if there is first block there.... */
  gus_poke (0L, 0xaa);
  if (gus_peek (0L) != 0xaa)
    return (0);
865

Linus Torvalds's avatar
Linus Torvalds committed
866 867 868 869 870
  /* Now zero it out so that I can check for mirroring .. */
  gus_poke (0L, 0x00);
  for (i = 1L; i < 1024L; i++)
    {
      int             n, failed;
871

Linus Torvalds's avatar
Linus Torvalds committed
872 873 874 875
      /* check for mirroring ... */
      if (gus_peek (0L) != 0)
	break;
      loc = i << 10;
876

Linus Torvalds's avatar
Linus Torvalds committed
877 878 879 880 881
      for (n = loc - 1, failed = 0; n <= loc; n++)
	{
	  gus_poke (loc, 0xaa);
	  if (gus_peek (loc) != 0xaa)
	    failed = 1;
882

Linus Torvalds's avatar
Linus Torvalds committed
883 884 885 886
	  gus_poke (loc, 0x55);
	  if (gus_peek (loc) != 0x55)
	    failed = 1;
	}
887

Linus Torvalds's avatar
Linus Torvalds committed
888 889 890 891
      if (failed)
	break;
    }
  gus_mem_size = i << 10;
892 893 894 895 896
  return 1;
}

static int
guswave_ioctl (int dev,
Linus Torvalds's avatar
Linus Torvalds committed
897
	       unsigned int cmd, caddr_t arg)
898 899 900 901 902 903
{

  switch (cmd)
    {
    case SNDCTL_SYNTH_INFO:
      gus_info.nr_voices = nr_voices;
Linus Torvalds's avatar
Linus Torvalds committed
904
      memcpy_tofs ((&((char *) arg)[0]), &gus_info, sizeof (gus_info));
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
      return 0;
      break;

    case SNDCTL_SEQ_RESETSAMPLES:
      reset_sample_memory ();
      return 0;
      break;

    case SNDCTL_SEQ_PERCMODE:
      return 0;
      break;

    case SNDCTL_SYNTH_MEMAVL:
      return gus_mem_size - free_mem_ptr - 32;

    default:
Linus Torvalds's avatar
Linus Torvalds committed
921
      return -EINVAL;
922 923 924 925 926 927 928 929 930
    }
}

static int
guswave_set_instr (int dev, int voice, int instr_no)
{
  int             sample_no;

  if (instr_no < 0 || instr_no > MAX_PATCH)
Linus Torvalds's avatar
Linus Torvalds committed
931
    return -EINVAL;
932 933

  if (voice < 0 || voice > 31)
Linus Torvalds's avatar
Linus Torvalds committed
934
    return -EINVAL;
935

Linus Torvalds's avatar
Linus Torvalds committed
936 937 938 939 940 941
  if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
    {
      voices[voice].sample_pending = instr_no;
      return 0;
    }

942 943 944
  sample_no = patch_table[instr_no];
  patch_map[voice] = -1;

Linus Torvalds's avatar
Linus Torvalds committed
945
  if (sample_no == NOT_SAMPLE)
946 947
    {
      printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
Linus Torvalds's avatar
Linus Torvalds committed
948
      return -EINVAL;		/* Patch not defined */
949 950
    }

Linus Torvalds's avatar
Linus Torvalds committed
951
  if (sample_ptrs[sample_no] == -1)	/* Sample not loaded */
952
    {
Linus Torvalds's avatar
Linus Torvalds committed
953 954
      printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n",
	      sample_no, instr_no, voice);
Linus Torvalds's avatar
Linus Torvalds committed
955
      return -EINVAL;
956 957 958 959 960 961 962 963
    }

  sample_map[voice] = sample_no;
  patch_map[voice] = instr_no;
  return 0;
}

static int
Linus Torvalds's avatar
Linus Torvalds committed
964
guswave_kill_note (int dev, int voice, int note, int velocity)
965 966 967
{
  unsigned long   flags;

Linus Torvalds's avatar
Linus Torvalds committed
968 969
  save_flags (flags);
  cli ();
Linus Torvalds's avatar
Linus Torvalds committed
970
  /* voice_alloc->map[voice] = 0xffff; */
Linus Torvalds's avatar
Linus Torvalds committed
971
  if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
Linus Torvalds's avatar
Linus Torvalds committed
972 973
    {
      voices[voice].kill_pending = 1;
Linus Torvalds's avatar
Linus Torvalds committed
974
      restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
975
    }
Linus Torvalds's avatar
Linus Torvalds committed
976 977
  else
    {
Linus Torvalds's avatar
Linus Torvalds committed
978
      restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
979 980
      gus_voice_fade (voice);
    }
981

Linus Torvalds's avatar
Linus Torvalds committed
982
  restore_flags (flags);
983 984 985 986 987 988 989 990 991 992 993 994 995 996 997
  return 0;
}

static void
guswave_aftertouch (int dev, int voice, int pressure)
{
}

static void
guswave_panning (int dev, int voice, int value)
{
  if (voice >= 0 || voice < 32)
    voices[voice].panning = value;
}

Linus Torvalds's avatar
Linus Torvalds committed
998 999 1000 1001 1002 1003 1004
static void
guswave_volume_method (int dev, int mode)
{
  if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
    volume_method = mode;
}

1005 1006 1007 1008
static void
compute_volume (int voice, int volume)
{
  if (volume < 128)
Linus Torvalds's avatar
Linus Torvalds committed
1009
    voices[voice].midi_volume = volume;
1010

Linus Torvalds's avatar
Linus Torvalds committed
1011 1012 1013 1014 1015 1016 1017 1018
  switch (volume_method)
    {
    case VOL_METHOD_ADAGIO:
      voices[voice].initial_volume =
	gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol,
			voices[voice].expression_vol,
			voices[voice].patch_vol);
      break;
1019

Linus Torvalds's avatar
Linus Torvalds committed
1020 1021 1022 1023 1024 1025 1026 1027 1028
    case VOL_METHOD_LINEAR:	/* Totally ignores patch-volume and expression */
      voices[voice].initial_volume =
	gus_linear_vol (volume, voices[voice].main_vol);
      break;

    default:
      voices[voice].initial_volume = volume_base +
	(voices[voice].midi_volume * volume_scale);
    }
1029

Linus Torvalds's avatar
Linus Torvalds committed
1030 1031
  if (voices[voice].initial_volume > 4030)
    voices[voice].initial_volume = 4030;
1032 1033 1034 1035 1036
}

static void
compute_and_set_volume (int voice, int volume, int ramp_time)
{
Linus Torvalds's avatar
Linus Torvalds committed
1037
  int             curr, target, rate;
Linus Torvalds's avatar
Linus Torvalds committed
1038
  unsigned long   flags;
Linus Torvalds's avatar
Linus Torvalds committed
1039

Linus Torvalds's avatar
Linus Torvalds committed
1040 1041 1042
  compute_volume (voice, volume);
  voices[voice].current_volume = voices[voice].initial_volume;

Linus Torvalds's avatar
Linus Torvalds committed
1043 1044
  save_flags (flags);
  cli ();
Linus Torvalds's avatar
Linus Torvalds committed
1045
  /*
Linus Torvalds's avatar
Linus Torvalds committed
1046 1047
     * CAUTION! Interrupts disabled. Enable them before returning
   */
Linus Torvalds's avatar
Linus Torvalds committed
1048

Linus Torvalds's avatar
Linus Torvalds committed
1049
  gus_select_voice (voice);
1050

Linus Torvalds's avatar
Linus Torvalds committed
1051
  curr = gus_read16 (0x09) >> 4;
1052 1053 1054 1055 1056 1057
  target = voices[voice].initial_volume;

  if (ramp_time == INSTANT_RAMP)
    {
      gus_rampoff ();
      gus_voice_volume (target);
Linus Torvalds's avatar
Linus Torvalds committed
1058
      restore_flags (flags);
1059 1060 1061 1062 1063 1064 1065 1066 1067
      return;
    }

  if (ramp_time == FAST_RAMP)
    rate = 63;
  else
    rate = 16;
  gus_ramp_rate (0, rate);

Linus Torvalds's avatar
Linus Torvalds committed
1068
  if ((target - curr) / 64 == 0)	/* Close enough to target. */
1069 1070 1071
    {
      gus_rampoff ();
      gus_voice_volume (target);
Linus Torvalds's avatar
Linus Torvalds committed
1072
      restore_flags (flags);
1073 1074 1075
      return;
    }

Linus Torvalds's avatar
Linus Torvalds committed
1076
  if (target > curr)
1077 1078 1079
    {
      if (target > (4095 - 65))
	target = 4095 - 65;
Linus Torvalds's avatar
Linus Torvalds committed
1080
      gus_ramp_range (curr, target);
Linus Torvalds's avatar
Linus Torvalds committed
1081
      gus_rampon (0x00);	/* Ramp up, once, no IRQ */
1082 1083 1084 1085 1086 1087
    }
  else
    {
      if (target < 65)
	target = 65;

Linus Torvalds's avatar
Linus Torvalds committed
1088
      gus_ramp_range (target, curr);
Linus Torvalds's avatar
Linus Torvalds committed
1089
      gus_rampon (0x40);	/* Ramp down, once, no irq */
1090
    }
Linus Torvalds's avatar
Linus Torvalds committed
1091
  restore_flags (flags);
1092 1093 1094 1095 1096 1097 1098 1099
}

static void
dynamic_volume_change (int voice)
{
  unsigned char   status;
  unsigned long   flags;

Linus Torvalds's avatar
Linus Torvalds committed
1100 1101
  save_flags (flags);
  cli ();
1102
  gus_select_voice (voice);
Linus Torvalds's avatar
Linus Torvalds committed
1103
  status = gus_read8 (0x00);	/* Get voice status */
Linus Torvalds's avatar
Linus Torvalds committed
1104
  restore_flags (flags);
1105 1106

  if (status & 0x03)
Linus Torvalds's avatar
Linus Torvalds committed
1107
    return;			/* Voice was not running */
1108 1109 1110 1111 1112 1113 1114

  if (!(voices[voice].mode & WAVE_ENVELOPES))
    {
      compute_and_set_volume (voice, voices[voice].midi_volume, 1);
      return;
    }

Linus Torvalds's avatar
Linus Torvalds committed
1115
  /*
1116 1117 1118
   * Voice is running and has envelopes.
   */

Linus Torvalds's avatar
Linus Torvalds committed
1119 1120
  save_flags (flags);
  cli ();
1121
  gus_select_voice (voice);
Linus Torvalds's avatar
Linus Torvalds committed
1122
  status = gus_read8 (0x0d);	/* Ramping status */
Linus Torvalds's avatar
Linus Torvalds committed
1123
  restore_flags (flags);
1124

Linus Torvalds's avatar
Linus Torvalds committed
1125
  if (status & 0x03)		/* Sustain phase? */
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
    {
      compute_and_set_volume (voice, voices[voice].midi_volume, 1);
      return;
    }

  if (voices[voice].env_phase < 0)
    return;

  compute_volume (voice, voices[voice].midi_volume);

}

static void
guswave_controller (int dev, int voice, int ctrl_num, int value)
{
  unsigned long   flags;
  unsigned long   freq;

  if (voice < 0 || voice > 31)
    return;

  switch (ctrl_num)
    {
    case CTRL_PITCH_BENDER:
      voices[voice].bender = value;

Linus Torvalds's avatar
Linus Torvalds committed
1152
      if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
Linus Torvalds's avatar
Linus Torvalds committed
1153
	{
Linus Torvalds's avatar
Linus Torvalds committed
1154 1155
	  freq = compute_finetune (voices[voice].orig_freq, value,
				   voices[voice].bender_range);
Linus Torvalds's avatar
Linus Torvalds committed
1156 1157
	  voices[voice].current_freq = freq;

Linus Torvalds's avatar
Linus Torvalds committed
1158 1159
	  save_flags (flags);
	  cli ();
Linus Torvalds's avatar
Linus Torvalds committed
1160 1161
	  gus_select_voice (voice);
	  gus_voice_freq (freq);
Linus Torvalds's avatar
Linus Torvalds committed
1162
	  restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
1163
	}
1164 1165 1166 1167 1168
      break;

    case CTRL_PITCH_BENDER_RANGE:
      voices[voice].bender_range = value;
      break;
Linus Torvalds's avatar
Linus Torvalds committed
1169 1170
    case CTL_EXPRESSION:
      value /= 128;
1171
    case CTRL_EXPRESSION:
Linus Torvalds's avatar
Linus Torvalds committed
1172 1173 1174 1175 1176 1177
      if (volume_method == VOL_METHOD_ADAGIO)
	{
	  voices[voice].expression_vol = value;
	  if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
	    dynamic_volume_change (voice);
	}
Linus Torvalds's avatar
Linus Torvalds committed
1178 1179 1180 1181
      break;

    case CTL_PAN:
      voices[voice].panning = (value * 2) - 128;
1182 1183
      break;

Linus Torvalds's avatar
Linus Torvalds committed
1184 1185 1186
    case CTL_MAIN_VOLUME:
      value = (value * 100) / 16383;

1187 1188
    case CTRL_MAIN_VOLUME:
      voices[voice].main_vol = value;
Linus Torvalds's avatar
Linus Torvalds committed
1189
      if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
Linus Torvalds's avatar
Linus Torvalds committed
1190
	dynamic_volume_change (voice);
1191 1192
      break;

Linus Torvalds's avatar
Linus Torvalds committed
1193
    default:
1194 1195 1196 1197 1198
      break;
    }
}

static int
Linus Torvalds's avatar
Linus Torvalds committed
1199
guswave_start_note2 (int dev, int voice, int note_num, int volume)
1200 1201 1202 1203 1204 1205 1206 1207 1208
{
  int             sample, best_sample, best_delta, delta_freq;
  int             is16bits, samplep, patch, pan;
  unsigned long   note_freq, base_note, freq, flags;
  unsigned char   mode = 0;

  if (voice < 0 || voice > 31)
    {
      printk ("GUS: Invalid voice\n");
Linus Torvalds's avatar
Linus Torvalds committed
1209
      return -EINVAL;
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
    }

  if (note_num == 255)
    {
      if (voices[voice].mode & WAVE_ENVELOPES)
	{
	  voices[voice].midi_volume = volume;
	  dynamic_volume_change (voice);
	  return 0;
	}

      compute_and_set_volume (voice, volume, 1);
      return 0;
    }

  if ((patch = patch_map[voice]) == -1)
    {
Linus Torvalds's avatar
Linus Torvalds committed
1227
      return -EINVAL;
1228 1229
    }

Linus Torvalds's avatar
Linus Torvalds committed
1230
  if ((samplep = patch_table[patch]) == NOT_SAMPLE)
1231
    {
Linus Torvalds's avatar
Linus Torvalds committed
1232
      return -EINVAL;
1233 1234 1235 1236
    }

  note_freq = note_to_freq (note_num);

Linus Torvalds's avatar
Linus Torvalds committed
1237
  /*
1238 1239 1240 1241 1242 1243 1244
   * Find a sample within a patch so that the note_freq is between low_note
   * and high_note.
   */
  sample = -1;

  best_sample = samplep;
  best_delta = 1000000;
Linus Torvalds's avatar
Linus Torvalds committed
1245
  while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1)
1246 1247 1248 1249 1250 1251 1252 1253 1254
    {
      delta_freq = note_freq - samples[samplep].base_note;
      if (delta_freq < 0)
	delta_freq = -delta_freq;
      if (delta_freq < best_delta)
	{
	  best_sample = samplep;
	  best_delta = delta_freq;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1255 1256
      if (samples[samplep].low_note <= note_freq &&
	  note_freq <= samples[samplep].high_note)
1257 1258
	sample = samplep;
      else
Linus Torvalds's avatar
Linus Torvalds committed
1259
	samplep = samples[samplep].key;		/* Link to next sample */
1260 1261 1262 1263 1264 1265 1266
    }
  if (sample == -1)
    sample = best_sample;

  if (sample == -1)
    {
      printk ("GUS: Patch %d not defined for note %d\n", patch, note_num);
Linus Torvalds's avatar
Linus Torvalds committed
1267
      return 0;			/* Should play default patch ??? */
1268 1269
    }

Linus Torvalds's avatar
Linus Torvalds committed
1270
  is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286
  voices[voice].mode = samples[sample].mode;
  voices[voice].patch_vol = samples[sample].volume;

  if (voices[voice].mode & WAVE_ENVELOPES)
    {
      int             i;

      for (i = 0; i < 6; i++)
	{
	  voices[voice].env_rate[i] = samples[sample].env_rate[i];
	  voices[voice].env_offset[i] = samples[sample].env_offset[i];
	}
    }

  sample_map[voice] = sample;

Linus Torvalds's avatar
Linus Torvalds committed
1287
  base_note = samples[sample].base_note / 100;	/* Try to avoid overflows */
1288 1289 1290 1291 1292 1293
  note_freq /= 100;

  freq = samples[sample].base_freq * note_freq / base_note;

  voices[voice].orig_freq = freq;

Linus Torvalds's avatar
Linus Torvalds committed
1294
  /*
1295 1296 1297 1298
   * Since the pitch bender may have been set before playing the note, we
   * have to calculate the bending now.
   */

Linus Torvalds's avatar
Linus Torvalds committed
1299 1300
  freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender,
			   voices[voice].bender_range);
1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311
  voices[voice].current_freq = freq;

  pan = (samples[sample].panning + voices[voice].panning) / 32;
  pan += 7;
  if (pan < 0)
    pan = 0;
  if (pan > 15)
    pan = 15;

  if (samples[sample].mode & WAVE_16_BITS)
    {
Linus Torvalds's avatar
Linus Torvalds committed
1312
      mode |= 0x04;		/* 16 bits */
1313 1314 1315 1316 1317 1318
      if ((sample_ptrs[sample] >> 18) !=
	  ((sample_ptrs[sample] + samples[sample].len) >> 18))
	printk ("GUS: Sample address error\n");
    }

  /*************************************************************************
Linus Torvalds's avatar
Linus Torvalds committed
1319 1320
   *    CAUTION!        Interrupts disabled. Don't return before enabling
   *************************************************************************/
1321

Linus Torvalds's avatar
Linus Torvalds committed
1322 1323
  save_flags (flags);
  cli ();
1324
  gus_select_voice (voice);
Linus Torvalds's avatar
Linus Torvalds committed
1325
  gus_voice_off ();
1326
  gus_rampoff ();
Linus Torvalds's avatar
Linus Torvalds committed
1327

Linus Torvalds's avatar
Linus Torvalds committed
1328
  restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
1329

1330 1331 1332 1333 1334 1335
  if (voices[voice].mode & WAVE_ENVELOPES)
    {
      compute_volume (voice, volume);
      init_envelope (voice);
    }
  else
Linus Torvalds's avatar
Linus Torvalds committed
1336 1337 1338
    {
      compute_and_set_volume (voice, volume, 0);
    }
1339

Linus Torvalds's avatar
Linus Torvalds committed
1340 1341
  save_flags (flags);
  cli ();
Linus Torvalds's avatar
Linus Torvalds committed
1342 1343
  gus_select_voice (voice);

1344
  if (samples[sample].mode & WAVE_LOOP_BACK)
Linus Torvalds's avatar
Linus Torvalds committed
1345
    gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -
Linus Torvalds's avatar
Linus Torvalds committed
1346
		    voices[voice].offset_pending, is16bits);	/* start=end */
1347
  else
Linus Torvalds's avatar
Linus Torvalds committed
1348 1349
    gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending,
		    is16bits);	/* Sample start=begin */
1350 1351 1352

  if (samples[sample].mode & WAVE_LOOPING)
    {
Linus Torvalds's avatar
Linus Torvalds committed
1353
      mode |= 0x08;
1354 1355

      if (samples[sample].mode & WAVE_BIDIR_LOOP)
Linus Torvalds's avatar
Linus Torvalds committed
1356
	mode |= 0x10;
1357 1358 1359

      if (samples[sample].mode & WAVE_LOOP_BACK)
	{
Linus Torvalds's avatar
Linus Torvalds committed
1360 1361 1362 1363
	  gus_write_addr (0x0a,
			  sample_ptrs[sample] + samples[sample].loop_end -
			  voices[voice].offset_pending, is16bits);
	  mode |= 0x40;
1364 1365
	}

Linus Torvalds's avatar
Linus Torvalds committed
1366
      gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start,
Linus Torvalds's avatar
Linus Torvalds committed
1367
		      is16bits);	/* Loop start location */
Linus Torvalds's avatar
Linus Torvalds committed
1368
      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end,
Linus Torvalds's avatar
Linus Torvalds committed
1369
		      is16bits);	/* Loop end location */
1370 1371 1372
    }
  else
    {
Linus Torvalds's avatar
Linus Torvalds committed
1373 1374
      mode |= 0x20;		/* Loop IRQ at the end */
      voices[voice].loop_irq_mode = LMODE_FINISH;	/* Ramp down at the end */
1375
      voices[voice].loop_irq_parm = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1376
      gus_write_addr (0x02, sample_ptrs[sample],
Linus Torvalds's avatar
Linus Torvalds committed
1377
		      is16bits);	/* Loop start location */
Linus Torvalds's avatar
Linus Torvalds committed
1378
      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1,
Linus Torvalds's avatar
Linus Torvalds committed
1379
		      is16bits);	/* Loop end location */
1380 1381 1382 1383
    }
  gus_voice_freq (freq);
  gus_voice_balance (pan);
  gus_voice_on (mode);
Linus Torvalds's avatar
Linus Torvalds committed
1384
  restore_flags (flags);
1385 1386 1387 1388

  return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
1389
/*
Linus Torvalds's avatar
Linus Torvalds committed
1390 1391 1392 1393
 * New guswave_start_note by Andrew J. Robinson attempts to minimize clicking
 * when the note playing on the voice is changed.  It uses volume
 * ramping.
 */
Linus Torvalds's avatar
Linus Torvalds committed
1394 1395 1396 1397 1398 1399 1400 1401

static int
guswave_start_note (int dev, int voice, int note_num, int volume)
{
  long int        flags;
  int             mode;
  int             ret_val = 0;

Linus Torvalds's avatar
Linus Torvalds committed
1402 1403
  save_flags (flags);
  cli ();
Linus Torvalds's avatar
Linus Torvalds committed
1404 1405 1406
  if (note_num == 255)
    {
      if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
Linus Torvalds's avatar
Linus Torvalds committed
1407 1408 1409
	{
	  voices[voice].volume_pending = volume;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1410
      else
Linus Torvalds's avatar
Linus Torvalds committed
1411 1412 1413
	{
	  ret_val = guswave_start_note2 (dev, voice, note_num, volume);
	}
Linus Torvalds's avatar
Linus Torvalds committed
1414 1415 1416
    }
  else
    {
Linus Torvalds's avatar
Linus Torvalds committed
1417 1418 1419
      gus_select_voice (voice);
      mode = gus_read8 (0x00);
      if (mode & 0x20)
Linus Torvalds's avatar
Linus Torvalds committed
1420
	gus_write8 (0x00, mode & 0xdf);		/* No interrupt! */
Linus Torvalds's avatar
Linus Torvalds committed
1421

Linus Torvalds's avatar
Linus Torvalds committed
1422 1423 1424 1425
      voices[voice].offset_pending = 0;
      voices[voice].kill_pending = 0;
      voices[voice].volume_irq_mode = 0;
      voices[voice].loop_irq_mode = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1426

Linus Torvalds's avatar
Linus Torvalds committed
1427 1428
      if (voices[voice].sample_pending >= 0)
	{
Linus Torvalds's avatar
Linus Torvalds committed
1429
	  restore_flags (flags);	/* Run temporarily with interrupts enabled */
Linus Torvalds's avatar
Linus Torvalds committed
1430 1431 1432
	  guswave_set_instr (voices[voice].dev_pending, voice,
			     voices[voice].sample_pending);
	  voices[voice].sample_pending = -1;
Linus Torvalds's avatar
Linus Torvalds committed
1433 1434
	  save_flags (flags);
	  cli ();
Linus Torvalds's avatar
Linus Torvalds committed
1435
	  gus_select_voice (voice);	/* Reselect the voice (just to be sure) */
Linus Torvalds's avatar
Linus Torvalds committed
1436
	}
Linus Torvalds's avatar
Linus Torvalds committed
1437

Linus Torvalds's avatar
Linus Torvalds committed
1438
      if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < 2065))
Linus Torvalds's avatar
Linus Torvalds committed
1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
	{
	  ret_val = guswave_start_note2 (dev, voice, note_num, volume);
	}
      else
	{
	  voices[voice].dev_pending = dev;
	  voices[voice].note_pending = note_num;
	  voices[voice].volume_pending = volume;
	  voices[voice].volume_irq_mode = VMODE_START_NOTE;

	  gus_rampoff ();
	  gus_ramp_range (2000, 4065);
Linus Torvalds's avatar
Linus Torvalds committed
1451
	  gus_ramp_rate (0, 63);	/* Fastest possible rate */
Linus Torvalds's avatar
Linus Torvalds committed
1452 1453 1454
	  gus_rampon (0x20 | 0x40);	/* Ramp down, once, irq */
	}
    }
Linus Torvalds's avatar
Linus Torvalds committed
1455
  restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
1456 1457 1458
  return ret_val;
}

1459 1460 1461 1462 1463 1464
static void
guswave_reset (int dev)
{
  int             i;

  for (i = 0; i < 32; i++)
Linus Torvalds's avatar
Linus Torvalds committed
1465 1466 1467 1468
    {
      gus_voice_init (i);
      gus_voice_init2 (i);
    }
1469 1470 1471 1472 1473 1474 1475 1476
}

static int
guswave_open (int dev, int mode)
{
  int             err;

  if (gus_busy)
Linus Torvalds's avatar
Linus Torvalds committed
1477
    return -EBUSY;
1478

Linus Torvalds's avatar
Linus Torvalds committed
1479
  gus_initialize ();
Linus Torvalds's avatar
Linus Torvalds committed
1480
  voice_alloc->timestamp = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1481

Linus Torvalds's avatar
Linus Torvalds committed
1482
  if ((err = DMAbuf_open_dma (gus_devnum)) < 0)
Linus Torvalds's avatar
Linus Torvalds committed
1483
    {
Linus Torvalds's avatar
Linus Torvalds committed
1484
      printk ("GUS: Loading samples without DMA\n");
Linus Torvalds's avatar
Linus Torvalds committed
1485 1486
      gus_no_dma = 1;		/* Upload samples using PIO */
    }
Linus Torvalds's avatar
Linus Torvalds committed
1487 1488
  else
    gus_no_dma = 0;
1489

Linus Torvalds's avatar
Linus Torvalds committed
1490
  dram_sleep_flag.mode = WK_NONE;
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505
  gus_busy = 1;
  active_device = GUS_DEV_WAVE;

  gus_reset ();

  return 0;
}

static void
guswave_close (int dev)
{
  gus_busy = 0;
  active_device = 0;
  gus_reset ();

Linus Torvalds's avatar
Linus Torvalds committed
1506 1507
  if (!gus_no_dma)
    DMAbuf_close_dma (gus_devnum);
1508 1509 1510
}

static int
Linus Torvalds's avatar
Linus Torvalds committed
1511
guswave_load_patch (int dev, int format, const char *addr,
1512 1513 1514 1515 1516 1517
		    int offs, int count, int pmgr_flag)
{
  struct patch_info patch;
  int             instr;
  long            sizeof_patch;

Linus Torvalds's avatar
Linus Torvalds committed
1518
  unsigned long   blk_sz, blk_end, left, src_offs, target;
1519

Linus Torvalds's avatar
Linus Torvalds committed
1520
  sizeof_patch = (long) &patch.data[0] - (long) &patch;		/* Header size */
1521 1522 1523

  if (format != GUS_PATCH)
    {
Linus Torvalds's avatar
Linus Torvalds committed
1524
      printk ("GUS Error: Invalid patch format (key) 0x%x\n", format);
Linus Torvalds's avatar
Linus Torvalds committed
1525
      return -EINVAL;
1526 1527 1528 1529 1530
    }

  if (count < sizeof_patch)
    {
      printk ("GUS Error: Patch header too short\n");
Linus Torvalds's avatar
Linus Torvalds committed
1531
      return -EINVAL;
1532 1533 1534 1535 1536 1537 1538
    }

  count -= sizeof_patch;

  if (free_sample >= MAX_SAMPLE)
    {
      printk ("GUS: Sample table full\n");
Linus Torvalds's avatar
Linus Torvalds committed
1539
      return -ENOSPC;
1540 1541
    }

Linus Torvalds's avatar
Linus Torvalds committed
1542
  /*
1543 1544 1545 1546
   * Copy the header from user space but ignore the first bytes which have
   * been transferred already.
   */

Linus Torvalds's avatar
Linus Torvalds committed
1547
  memcpy_fromfs (&((char *) &patch)[offs], &((addr)[offs]), sizeof_patch - offs);
1548 1549 1550 1551 1552 1553

  instr = patch.instr_no;

  if (instr < 0 || instr > MAX_PATCH)
    {
      printk ("GUS: Invalid patch number %d\n", instr);
Linus Torvalds's avatar
Linus Torvalds committed
1554
      return -EINVAL;
1555 1556 1557 1558
    }

  if (count < patch.len)
    {
Linus Torvalds's avatar
Linus Torvalds committed
1559
      printk ("GUS Warning: Patch record too short (%d<%d)\n",
Linus Torvalds's avatar
Linus Torvalds committed
1560
	      count, (int) patch.len);
1561 1562 1563 1564 1565
      patch.len = count;
    }

  if (patch.len <= 0 || patch.len > gus_mem_size)
    {
Linus Torvalds's avatar
Linus Torvalds committed
1566
      printk ("GUS: Invalid sample length %d\n", (int) patch.len);
Linus Torvalds's avatar
Linus Torvalds committed
1567
      return -EINVAL;
1568 1569 1570 1571 1572 1573 1574
    }

  if (patch.mode & WAVE_LOOPING)
    {
      if (patch.loop_start < 0 || patch.loop_start >= patch.len)
	{
	  printk ("GUS: Invalid loop start\n");
Linus Torvalds's avatar
Linus Torvalds committed
1575
	  return -EINVAL;
1576 1577 1578 1579 1580
	}

      if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
	{
	  printk ("GUS: Invalid loop end\n");
Linus Torvalds's avatar
Linus Torvalds committed
1581
	  return -EINVAL;
1582 1583 1584
	}
    }

Linus Torvalds's avatar
Linus Torvalds committed
1585
  free_mem_ptr = (free_mem_ptr + 31) & ~31;	/* 32 byte alignment */
1586 1587 1588 1589 1590

#define GUS_BANK_SIZE (256*1024)

  if (patch.mode & WAVE_16_BITS)
    {
Linus Torvalds's avatar
Linus Torvalds committed
1591
      /*
1592 1593 1594 1595
       * 16 bit samples must fit one 256k bank.
       */
      if (patch.len >= GUS_BANK_SIZE)
	{
Linus Torvalds's avatar
Linus Torvalds committed
1596
	  printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len);
Linus Torvalds's avatar
Linus Torvalds committed
1597
	  return -ENOSPC;
1598 1599 1600 1601 1602
	}

      if ((free_mem_ptr / GUS_BANK_SIZE) !=
	  ((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
	{
Linus Torvalds's avatar
Linus Torvalds committed
1603
	  unsigned long   tmp_mem =	/* Aling to 256K */
1604 1605 1606
	  ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;

	  if ((tmp_mem + patch.len) > gus_mem_size)
Linus Torvalds's avatar
Linus Torvalds committed
1607
	    return -ENOSPC;
1608

Linus Torvalds's avatar
Linus Torvalds committed
1609
	  free_mem_ptr = tmp_mem;	/* This leaves unusable memory */
1610 1611 1612 1613
	}
    }

  if ((free_mem_ptr + patch.len) > gus_mem_size)
Linus Torvalds's avatar
Linus Torvalds committed
1614
    return -ENOSPC;
1615 1616 1617

  sample_ptrs[free_sample] = free_mem_ptr;

Linus Torvalds's avatar
Linus Torvalds committed
1618 1619
  /*
   * Tremolo is not possible with envelopes
Linus Torvalds's avatar
Linus Torvalds committed
1620
   */
1621 1622 1623 1624 1625 1626

  if (patch.mode & WAVE_ENVELOPES)
    patch.mode &= ~WAVE_TREMOLO;

  memcpy ((char *) &samples[free_sample], &patch, sizeof_patch);

Linus Torvalds's avatar
Linus Torvalds committed
1627
  /*
1628 1629 1630 1631 1632 1633
   * Link this_one sample to the list of samples for patch 'instr'.
   */

  samples[free_sample].key = patch_table[instr];
  patch_table[instr] = free_sample;

Linus Torvalds's avatar
Linus Torvalds committed
1634
  /*
1635 1636 1637 1638 1639 1640 1641
   * Use DMA to transfer the wave data to the DRAM
   */

  left = patch.len;
  src_offs = 0;
  target = free_mem_ptr;

Linus Torvalds's avatar
Linus Torvalds committed
1642
  while (left)			/* Not completely transferred yet */
1643
    {
Linus Torvalds's avatar
Linus Torvalds committed
1644 1645 1646 1647
      /* blk_sz = audio_devs[gus_devnum]->buffsize; */
      blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use;
      if (blk_sz > left)
	blk_sz = left;
1648

Linus Torvalds's avatar
Linus Torvalds committed
1649
      /*
1650 1651
       * DMA cannot cross 256k bank boundaries. Check for that.
       */
Linus Torvalds's avatar
Linus Torvalds committed
1652
      blk_end = target + blk_sz;
1653 1654

      if ((target >> 18) != (blk_end >> 18))
Linus Torvalds's avatar
Linus Torvalds committed
1655
	{			/* Split the block */
1656 1657

	  blk_end &= ~(256 * 1024 - 1);
Linus Torvalds's avatar
Linus Torvalds committed
1658
	  blk_sz = blk_end - target;
1659 1660
	}

Linus Torvalds's avatar
Linus Torvalds committed
1661
      if (gus_pnp_flag || gus_no_dma)
Linus Torvalds's avatar
Linus Torvalds committed
1662 1663 1664 1665 1666 1667
	{
	  /*
	   * For some reason the DMA is not possible. We have to use PIO.
	   */
	  long            i;
	  unsigned char   data;
1668

Linus Torvalds's avatar
Linus Torvalds committed
1669

Linus Torvalds's avatar
Linus Torvalds committed
1670
	  for (i = 0; i < blk_sz; i++)
Linus Torvalds's avatar
Linus Torvalds committed
1671
	    {
Linus Torvalds's avatar
Linus Torvalds committed
1672
	      data = get_fs_byte (&((addr)[sizeof_patch + i]));
Linus Torvalds's avatar
Linus Torvalds committed
1673
	      if (patch.mode & WAVE_UNSIGNED)
Linus Torvalds's avatar
Linus Torvalds committed
1674

Linus Torvalds's avatar
Linus Torvalds committed
1675 1676 1677 1678 1679 1680 1681 1682 1683 1684
		if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
		  data ^= 0x80;	/* Convert to signed */
	      gus_poke (target + i, data);
	    }
	}
      else
	{
	  unsigned long   address, hold_address;
	  unsigned char   dma_command;
	  unsigned long   flags;
1685

Linus Torvalds's avatar
Linus Torvalds committed
1686 1687 1688
	  /*
	   * OK, move now. First in and then out.
	   */
1689

Linus Torvalds's avatar
Linus Torvalds committed
1690
	  memcpy_fromfs (audio_devs[gus_devnum]->dmap_out->raw_buf, &((addr)[sizeof_patch + src_offs]), blk_sz);
1691

Linus Torvalds's avatar
Linus Torvalds committed
1692 1693
	  save_flags (flags);
	  cli ();
Linus Torvalds's avatar
Linus Torvalds committed
1694 1695 1696
/******** INTERRUPTS DISABLED NOW ********/
	  gus_write8 (0x41, 0);	/* Disable GF1 DMA */
	  DMAbuf_start_dma (gus_devnum,
Linus Torvalds's avatar
Linus Torvalds committed
1697
			    audio_devs[gus_devnum]->dmap_out->raw_buf_phys,
Linus Torvalds's avatar
Linus Torvalds committed
1698
			    blk_sz, DMA_MODE_WRITE);
1699

Linus Torvalds's avatar
Linus Torvalds committed
1700 1701 1702
	  /*
	   * Set the DRAM address for the wave data
	   */
1703

Linus Torvalds's avatar
Linus Torvalds committed
1704
	  address = target;
1705

Linus Torvalds's avatar
Linus Torvalds committed
1706
	  if (audio_devs[gus_devnum]->dmachan1 > 3)
Linus Torvalds's avatar
Linus Torvalds committed
1707 1708 1709 1710 1711 1712
	    {
	      hold_address = address;
	      address = address >> 1;
	      address &= 0x0001ffffL;
	      address |= (hold_address & 0x000c0000L);
	    }
1713

Linus Torvalds's avatar
Linus Torvalds committed
1714
	  gus_write16 (0x42, (address >> 4) & 0xffff);	/* DRAM DMA address */
1715

Linus Torvalds's avatar
Linus Torvalds committed
1716 1717 1718
	  /*
	   * Start the DMA transfer
	   */
1719

Linus Torvalds's avatar
Linus Torvalds committed
1720 1721 1722 1723 1724
	  dma_command = 0x21;	/* IRQ enable, DMA start */
	  if (patch.mode & WAVE_UNSIGNED)
	    dma_command |= 0x80;	/* Invert MSB */
	  if (patch.mode & WAVE_16_BITS)
	    dma_command |= 0x40;	/* 16 bit _DATA_ */
Linus Torvalds's avatar
Linus Torvalds committed
1725
	  if (audio_devs[gus_devnum]->dmachan1 > 3)
Linus Torvalds's avatar
Linus Torvalds committed
1726
	    dma_command |= 0x04;	/* 16 bit DMA _channel_ */
1727

Linus Torvalds's avatar
Linus Torvalds committed
1728
	  gus_write8 (0x41, dma_command);	/* Lets bo luteet (=bugs) */
1729

Linus Torvalds's avatar
Linus Torvalds committed
1730 1731 1732 1733
	  /*
	   * Sleep here until the DRAM DMA done interrupt is served
	   */
	  active_device = GUS_DEV_WAVE;
1734

Linus Torvalds's avatar
Linus Torvalds committed
1735 1736 1737 1738 1739

	  {
	    unsigned long   tl;

	    if (HZ)
Linus Torvalds's avatar
Linus Torvalds committed
1740
	      current_set_timeout (tl = jiffies + (HZ));
Linus Torvalds's avatar
Linus Torvalds committed
1741
	    else
Linus Torvalds's avatar
Linus Torvalds committed
1742
	      tl = (unsigned long) -1;
Linus Torvalds's avatar
Linus Torvalds committed
1743
	    dram_sleep_flag.mode = WK_SLEEP;
Linus Torvalds's avatar
Linus Torvalds committed
1744
	    module_interruptible_sleep_on (&dram_sleeper);
Linus Torvalds's avatar
Linus Torvalds committed
1745 1746
	    if (!(dram_sleep_flag.mode & WK_WAKEUP))
	      {
Linus Torvalds's avatar
Linus Torvalds committed
1747
		if (jiffies >= tl)
Linus Torvalds's avatar
Linus Torvalds committed
1748 1749 1750 1751 1752
		  dram_sleep_flag.mode |= WK_TIMEOUT;
	      }
	    dram_sleep_flag.mode &= ~WK_SLEEP;
	  };
	  if ((dram_sleep_flag.mode & WK_TIMEOUT))
Linus Torvalds's avatar
Linus Torvalds committed
1753
	    printk ("GUS: DMA Transfer timed out\n");
Linus Torvalds's avatar
Linus Torvalds committed
1754
	  restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
1755
	}
1756

Linus Torvalds's avatar
Linus Torvalds committed
1757
      /*
1758 1759 1760
       * Now the next part
       */

Linus Torvalds's avatar
Linus Torvalds committed
1761 1762 1763
      left -= blk_sz;
      src_offs += blk_sz;
      target += blk_sz;
1764

Linus Torvalds's avatar
Linus Torvalds committed
1765
      gus_write8 (0x41, 0);	/* Stop DMA */
1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776
    }

  free_mem_ptr += patch.len;

  if (!pmgr_flag)
    pmgr_inform (dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0);
  free_sample++;
  return 0;
}

static void
Linus Torvalds's avatar
Linus Torvalds committed
1777
guswave_hw_control (int dev, unsigned char *event_rec)
1778 1779 1780
{
  int             voice, cmd;
  unsigned short  p1, p2;
Linus Torvalds's avatar
Linus Torvalds committed
1781 1782
  unsigned int    plong;
  unsigned        flags;
1783

Linus Torvalds's avatar
Linus Torvalds committed
1784 1785 1786 1787 1788
  cmd = event_rec[2];
  voice = event_rec[3];
  p1 = *(unsigned short *) &event_rec[4];
  p2 = *(unsigned short *) &event_rec[6];
  plong = *(unsigned int *) &event_rec[4];
1789

Linus Torvalds's avatar
Linus Torvalds committed
1790 1791 1792 1793
  if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
      (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
    do_volume_irq (voice);

1794 1795 1796 1797
  switch (cmd)
    {

    case _GUS_NUMVOICES:
Linus Torvalds's avatar
Linus Torvalds committed
1798 1799
      save_flags (flags);
      cli ();
1800 1801
      gus_select_voice (voice);
      gus_select_max_voices (p1);
Linus Torvalds's avatar
Linus Torvalds committed
1802
      restore_flags (flags);
1803 1804 1805 1806 1807 1808 1809
      break;

    case _GUS_VOICESAMPLE:
      guswave_set_instr (dev, voice, p1);
      break;

    case _GUS_VOICEON:
Linus Torvalds's avatar
Linus Torvalds committed
1810 1811
      save_flags (flags);
      cli ();
1812
      gus_select_voice (voice);
Linus Torvalds's avatar
Linus Torvalds committed
1813
      p1 &= ~0x20;		/* Don't allow interrupts */
1814
      gus_voice_on (p1);
Linus Torvalds's avatar
Linus Torvalds committed
1815
      restore_flags (flags);
1816 1817 1818
      break;

    case _GUS_VOICEOFF:
Linus Torvalds's avatar
Linus Torvalds committed
1819 1820
      save_flags (flags);
      cli ();
1821 1822
      gus_select_voice (voice);
      gus_voice_off ();
Linus Torvalds's avatar
Linus Torvalds committed
1823
      restore_flags (flags);
1824 1825 1826 1827 1828 1829 1830
      break;

    case _GUS_VOICEFADE:
      gus_voice_fade (voice);
      break;

    case _GUS_VOICEMODE:
Linus Torvalds's avatar
Linus Torvalds committed
1831 1832
      save_flags (flags);
      cli ();
1833
      gus_select_voice (voice);
Linus Torvalds's avatar
Linus Torvalds committed
1834
      p1 &= ~0x20;		/* Don't allow interrupts */
1835
      gus_voice_mode (p1);
Linus Torvalds's avatar
Linus Torvalds committed
1836
      restore_flags (flags);
1837 1838 1839
      break;

    case _GUS_VOICEBALA:
Linus Torvalds's avatar
Linus Torvalds committed
1840 1841
      save_flags (flags);
      cli ();
1842 1843
      gus_select_voice (voice);
      gus_voice_balance (p1);
Linus Torvalds's avatar
Linus Torvalds committed
1844
      restore_flags (flags);
1845 1846 1847
      break;

    case _GUS_VOICEFREQ:
Linus Torvalds's avatar
Linus Torvalds committed
1848 1849
      save_flags (flags);
      cli ();
1850 1851
      gus_select_voice (voice);
      gus_voice_freq (plong);
Linus Torvalds's avatar
Linus Torvalds committed
1852
      restore_flags (flags);
1853 1854 1855
      break;

    case _GUS_VOICEVOL:
Linus Torvalds's avatar
Linus Torvalds committed
1856 1857
      save_flags (flags);
      cli ();
1858 1859
      gus_select_voice (voice);
      gus_voice_volume (p1);
Linus Torvalds's avatar
Linus Torvalds committed
1860
      restore_flags (flags);
1861 1862
      break;

Linus Torvalds's avatar
Linus Torvalds committed
1863
    case _GUS_VOICEVOL2:	/* Just update the software voice level */
1864 1865 1866 1867 1868 1869
      voices[voice].initial_volume =
	voices[voice].current_volume = p1;
      break;

    case _GUS_RAMPRANGE:
      if (voices[voice].mode & WAVE_ENVELOPES)
Linus Torvalds's avatar
Linus Torvalds committed
1870
	break;			/* NO-NO */
Linus Torvalds's avatar
Linus Torvalds committed
1871 1872
      save_flags (flags);
      cli ();
1873 1874
      gus_select_voice (voice);
      gus_ramp_range (p1, p2);
Linus Torvalds's avatar
Linus Torvalds committed
1875
      restore_flags (flags);
1876 1877 1878 1879
      break;

    case _GUS_RAMPRATE:
      if (voices[voice].mode & WAVE_ENVELOPES)
Linus Torvalds's avatar
Linus Torvalds committed
1880
	break;			/* NJET-NJET */
Linus Torvalds's avatar
Linus Torvalds committed
1881 1882
      save_flags (flags);
      cli ();
1883 1884
      gus_select_voice (voice);
      gus_ramp_rate (p1, p2);
Linus Torvalds's avatar
Linus Torvalds committed
1885
      restore_flags (flags);
1886 1887 1888 1889
      break;

    case _GUS_RAMPMODE:
      if (voices[voice].mode & WAVE_ENVELOPES)
Linus Torvalds's avatar
Linus Torvalds committed
1890
	break;			/* NO-NO */
Linus Torvalds's avatar
Linus Torvalds committed
1891 1892
      save_flags (flags);
      cli ();
1893
      gus_select_voice (voice);
Linus Torvalds's avatar
Linus Torvalds committed
1894
      p1 &= ~0x20;		/* Don't allow interrupts */
1895
      gus_ramp_mode (p1);
Linus Torvalds's avatar
Linus Torvalds committed
1896
      restore_flags (flags);
1897 1898 1899 1900
      break;

    case _GUS_RAMPON:
      if (voices[voice].mode & WAVE_ENVELOPES)
Linus Torvalds's avatar
Linus Torvalds committed
1901
	break;			/* EI-EI */
Linus Torvalds's avatar
Linus Torvalds committed
1902 1903
      save_flags (flags);
      cli ();
1904
      gus_select_voice (voice);
Linus Torvalds's avatar
Linus Torvalds committed
1905
      p1 &= ~0x20;		/* Don't allow interrupts */
1906
      gus_rampon (p1);
Linus Torvalds's avatar
Linus Torvalds committed
1907
      restore_flags (flags);
1908 1909 1910 1911
      break;

    case _GUS_RAMPOFF:
      if (voices[voice].mode & WAVE_ENVELOPES)
Linus Torvalds's avatar
Linus Torvalds committed
1912
	break;			/* NEJ-NEJ */
Linus Torvalds's avatar
Linus Torvalds committed
1913 1914
      save_flags (flags);
      cli ();
1915 1916
      gus_select_voice (voice);
      gus_rampoff ();
Linus Torvalds's avatar
Linus Torvalds committed
1917
      restore_flags (flags);
1918 1919 1920 1921 1922 1923 1924
      break;

    case _GUS_VOLUME_SCALE:
      volume_base = p1;
      volume_scale = p2;
      break;

Linus Torvalds's avatar
Linus Torvalds committed
1925
    case _GUS_VOICE_POS:
Linus Torvalds's avatar
Linus Torvalds committed
1926 1927
      save_flags (flags);
      cli ();
Linus Torvalds's avatar
Linus Torvalds committed
1928 1929
      gus_select_voice (voice);
      gus_set_voice_pos (voice, plong);
Linus Torvalds's avatar
Linus Torvalds committed
1930
      restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
1931 1932
      break;

1933 1934 1935 1936 1937 1938 1939
    default:;
    }
}

static int
gus_sampling_set_speed (int speed)
{
Linus Torvalds's avatar
Linus Torvalds committed
1940

1941
  if (speed <= 0)
Linus Torvalds's avatar
Linus Torvalds committed
1942 1943 1944 1945
    speed = gus_sampling_speed;

  if (speed < 4000)
    speed = 4000;
1946 1947 1948 1949 1950

  if (speed > 44100)
    speed = 44100;

  gus_sampling_speed = speed;
Linus Torvalds's avatar
Linus Torvalds committed
1951 1952 1953 1954 1955 1956 1957 1958

  if (only_read_access)
    {
      /* Compute nearest valid recording speed  and return it */

      speed = (9878400 / (gus_sampling_speed + 2)) / 16;
      speed = (9878400 / (speed * 16)) - 2;
    }
1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983
  return speed;
}

static int
gus_sampling_set_channels (int channels)
{
  if (!channels)
    return gus_sampling_channels;
  if (channels > 2)
    channels = 2;
  if (channels < 1)
    channels = 1;
  gus_sampling_channels = channels;
  return channels;
}

static int
gus_sampling_set_bits (int bits)
{
  if (!bits)
    return gus_sampling_bits;

  if (bits != 8 && bits != 16)
    bits = 8;

Linus Torvalds's avatar
Linus Torvalds committed
1984 1985 1986
  if (only_8_bits)
    bits = 8;

1987 1988 1989 1990 1991
  gus_sampling_bits = bits;
  return bits;
}

static int
Linus Torvalds's avatar
Linus Torvalds committed
1992
gus_sampling_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
1993 1994 1995 1996 1997
{
  switch (cmd)
    {
    case SOUND_PCM_WRITE_RATE:
      if (local)
Linus Torvalds's avatar
Linus Torvalds committed
1998 1999
	return gus_sampling_set_speed ((int) arg);
      return snd_ioctl_return ((int *) arg, gus_sampling_set_speed (get_fs_long ((long *) arg)));
2000 2001 2002 2003 2004
      break;

    case SOUND_PCM_READ_RATE:
      if (local)
	return gus_sampling_speed;
Linus Torvalds's avatar
Linus Torvalds committed
2005
      return snd_ioctl_return ((int *) arg, gus_sampling_speed);
2006 2007 2008 2009
      break;

    case SNDCTL_DSP_STEREO:
      if (local)
Linus Torvalds's avatar
Linus Torvalds committed
2010 2011
	return gus_sampling_set_channels ((int) arg + 1) - 1;
      return snd_ioctl_return ((int *) arg, gus_sampling_set_channels (get_fs_long ((long *) arg) + 1) - 1);
2012 2013 2014
      break;

    case SOUND_PCM_WRITE_CHANNELS:
Linus Torvalds's avatar
Linus Torvalds committed
2015
      if (local)
Linus Torvalds's avatar
Linus Torvalds committed
2016 2017
	return gus_sampling_set_channels ((int) arg);
      return snd_ioctl_return ((int *) arg, gus_sampling_set_channels (get_fs_long ((long *) arg)));
2018 2019 2020 2021 2022
      break;

    case SOUND_PCM_READ_CHANNELS:
      if (local)
	return gus_sampling_channels;
Linus Torvalds's avatar
Linus Torvalds committed
2023
      return snd_ioctl_return ((int *) arg, gus_sampling_channels);
2024 2025
      break;

Linus Torvalds's avatar
Linus Torvalds committed
2026
    case SNDCTL_DSP_SETFMT:
2027
      if (local)
Linus Torvalds's avatar
Linus Torvalds committed
2028 2029
	return gus_sampling_set_bits ((int) arg);
      return snd_ioctl_return ((int *) arg, gus_sampling_set_bits (get_fs_long ((long *) arg)));
2030 2031 2032 2033 2034
      break;

    case SOUND_PCM_READ_BITS:
      if (local)
	return gus_sampling_bits;
Linus Torvalds's avatar
Linus Torvalds committed
2035
      return snd_ioctl_return ((int *) arg, gus_sampling_bits);
2036

Linus Torvalds's avatar
Linus Torvalds committed
2037
    case SOUND_PCM_WRITE_FILTER:	/* NOT POSSIBLE */
Linus Torvalds's avatar
Linus Torvalds committed
2038
      return snd_ioctl_return ((int *) arg, -EINVAL);
2039 2040 2041
      break;

    case SOUND_PCM_READ_FILTER:
Linus Torvalds's avatar
Linus Torvalds committed
2042
      return snd_ioctl_return ((int *) arg, -EINVAL);
2043 2044 2045
      break;

    }
Linus Torvalds's avatar
Linus Torvalds committed
2046
  return -EINVAL;
2047 2048 2049 2050 2051
}

static void
gus_sampling_reset (int dev)
{
Linus Torvalds's avatar
Linus Torvalds committed
2052 2053 2054 2055 2056
  if (recording_active)
    {
      gus_write8 (0x49, 0x00);	/* Halt recording */
      set_input_volumes ();
    }
2057 2058 2059 2060 2061 2062
}

static int
gus_sampling_open (int dev, int mode)
{
  if (gus_busy)
Linus Torvalds's avatar
Linus Torvalds committed
2063
    return -EBUSY;
2064

Linus Torvalds's avatar
Linus Torvalds committed
2065 2066
  gus_initialize ();

2067 2068 2069 2070 2071 2072 2073 2074
  gus_busy = 1;
  active_device = 0;

  gus_reset ();
  reset_sample_memory ();
  gus_select_max_voices (14);

  pcm_active = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2075
  dma_active = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2076
  pcm_opened = 1;
Linus Torvalds's avatar
Linus Torvalds committed
2077 2078 2079 2080 2081
  if (mode & OPEN_READ)
    {
      recording_active = 1;
      set_input_volumes ();
    }
Linus Torvalds's avatar
Linus Torvalds committed
2082
  only_read_access = !(mode & OPEN_WRITE);
Linus Torvalds's avatar
Linus Torvalds committed
2083 2084 2085 2086 2087
  only_8_bits = mode & OPEN_READ;
  if (only_8_bits)
    audio_devs[dev]->format_mask = AFMT_U8;
  else
    audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE;
2088 2089 2090 2091 2092 2093 2094 2095 2096

  return 0;
}

static void
gus_sampling_close (int dev)
{
  gus_reset ();
  gus_busy = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2097
  pcm_opened = 0;
2098
  active_device = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2099 2100

  if (recording_active)
Linus Torvalds's avatar
Linus Torvalds committed
2101 2102 2103 2104
    {
      gus_write8 (0x49, 0x00);	/* Halt recording */
      set_input_volumes ();
    }
Linus Torvalds's avatar
Linus Torvalds committed
2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117

  recording_active = 0;
}

static void
gus_sampling_update_volume (void)
{
  unsigned long   flags;
  int             voice;

  if (pcm_active && pcm_opened)
    for (voice = 0; voice < gus_sampling_channels; voice++)
      {
Linus Torvalds's avatar
Linus Torvalds committed
2118 2119
	save_flags (flags);
	cli ();
Linus Torvalds's avatar
Linus Torvalds committed
2120 2121 2122 2123
	gus_select_voice (voice);
	gus_rampoff ();
	gus_voice_volume (1530 + (25 * gus_pcm_volume));
	gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
Linus Torvalds's avatar
Linus Torvalds committed
2124
	restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
2125
      }
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144
}

static void
play_next_pcm_block (void)
{
  unsigned long   flags;
  int             speed = gus_sampling_speed;
  int             this_one, is16bits, chn;
  unsigned long   dram_loc;
  unsigned char   mode[2], ramp_mode[2];

  if (!pcm_qlen)
    return;

  this_one = pcm_head;

  for (chn = 0; chn < gus_sampling_channels; chn++)
    {
      mode[chn] = 0x00;
Linus Torvalds's avatar
Linus Torvalds committed
2145
      ramp_mode[chn] = 0x03;	/* Ramping and rollover off */
2146 2147 2148

      if (chn == 0)
	{
Linus Torvalds's avatar
Linus Torvalds committed
2149
	  mode[chn] |= 0x20;	/* Loop IRQ */
2150 2151 2152 2153 2154 2155
	  voices[chn].loop_irq_mode = LMODE_PCM;
	}

      if (gus_sampling_bits != 8)
	{
	  is16bits = 1;
Linus Torvalds's avatar
Linus Torvalds committed
2156
	  mode[chn] |= 0x04;	/* 16 bit data */
2157 2158 2159 2160 2161 2162 2163
	}
      else
	is16bits = 0;

      dram_loc = this_one * pcm_bsize;
      dram_loc += chn * pcm_banksize;

Linus Torvalds's avatar
Linus Torvalds committed
2164
      if (this_one == (pcm_nblk - 1))	/* Last fragment of the DRAM buffer */
2165
	{
Linus Torvalds's avatar
Linus Torvalds committed
2166
	  mode[chn] |= 0x08;	/* Enable loop */
Linus Torvalds's avatar
Linus Torvalds committed
2167
	  ramp_mode[chn] = 0x03;	/* Disable rollover bit */
2168 2169 2170 2171
	}
      else
	{
	  if (chn == 0)
Linus Torvalds's avatar
Linus Torvalds committed
2172
	    ramp_mode[chn] = 0x04;	/* Enable rollover bit */
2173 2174
	}

Linus Torvalds's avatar
Linus Torvalds committed
2175 2176
      save_flags (flags);
      cli ();
2177 2178 2179 2180
      gus_select_voice (chn);
      gus_voice_freq (speed);

      if (gus_sampling_channels == 1)
Linus Torvalds's avatar
Linus Torvalds committed
2181
	gus_voice_balance (7);	/* mono */
2182
      else if (chn == 0)
Linus Torvalds's avatar
Linus Torvalds committed
2183
	gus_voice_balance (0);	/* left */
2184
      else
Linus Torvalds's avatar
Linus Torvalds committed
2185
	gus_voice_balance (15);	/* right */
2186

Linus Torvalds's avatar
Linus Torvalds committed
2187
      if (!pcm_active)		/* Playback not already active */
2188
	{
Linus Torvalds's avatar
Linus Torvalds committed
2189
	  /*
2190 2191 2192 2193 2194 2195
	   * The playback was not started yet (or there has been a pause).
	   * Start the voice (again) and ask for a rollover irq at the end of
	   * this_one block. If this_one one is last of the buffers, use just
	   * the normal loop with irq.
	   */

Linus Torvalds's avatar
Linus Torvalds committed
2196
	  gus_voice_off ();
2197
	  gus_rampoff ();
Linus Torvalds's avatar
Linus Torvalds committed
2198 2199
	  gus_voice_volume (1530 + (25 * gus_pcm_volume));
	  gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
2200

Linus Torvalds's avatar
Linus Torvalds committed
2201 2202
	  gus_write_addr (0x0a, dram_loc, is16bits);	/* Starting position */
	  gus_write_addr (0x02, chn * pcm_banksize, is16bits);	/* Loop start */
2203 2204

	  if (chn != 0)
Linus Torvalds's avatar
Linus Torvalds committed
2205
	    gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1,
Linus Torvalds's avatar
Linus Torvalds committed
2206
			    is16bits);	/* Loop end location */
2207 2208 2209
	}

      if (chn == 0)
Linus Torvalds's avatar
Linus Torvalds committed
2210
	gus_write_addr (0x04, dram_loc + pcm_datasize[this_one] - 1,
Linus Torvalds's avatar
Linus Torvalds committed
2211
			is16bits);	/* Loop end location */
2212
      else
Linus Torvalds's avatar
Linus Torvalds committed
2213
	mode[chn] |= 0x08;	/* Enable looping */
2214 2215 2216

      if (pcm_datasize[this_one] != pcm_bsize)
	{
Linus Torvalds's avatar
Linus Torvalds committed
2217
	  /*
Linus Torvalds's avatar
Linus Torvalds committed
2218
	   * Incompletely filled block. Possibly the last one.
Linus Torvalds's avatar
Linus Torvalds committed
2219
	   */
2220 2221
	  if (chn == 0)
	    {
Linus Torvalds's avatar
Linus Torvalds committed
2222
	      mode[chn] &= ~0x08;	/* Disable looping */
Linus Torvalds's avatar
Linus Torvalds committed
2223
	      mode[chn] |= 0x20;	/* Enable IRQ at the end */
2224
	      voices[0].loop_irq_mode = LMODE_PCM_STOP;
Linus Torvalds's avatar
Linus Torvalds committed
2225
	      ramp_mode[chn] = 0x03;	/* No rollover bit */
2226 2227 2228
	    }
	  else
	    {
Linus Torvalds's avatar
Linus Torvalds committed
2229 2230 2231
	      gus_write_addr (0x04, dram_loc + pcm_datasize[this_one],
			      is16bits);	/* Loop end location */
	      mode[chn] &= ~0x08;	/* Disable looping */
2232 2233 2234
	    }
	}

Linus Torvalds's avatar
Linus Torvalds committed
2235
      restore_flags (flags);
2236 2237 2238 2239
    }

  for (chn = 0; chn < gus_sampling_channels; chn++)
    {
Linus Torvalds's avatar
Linus Torvalds committed
2240 2241
      save_flags (flags);
      cli ();
2242 2243 2244
      gus_select_voice (chn);
      gus_write8 (0x0d, ramp_mode[chn]);
      gus_voice_on (mode[chn]);
Linus Torvalds's avatar
Linus Torvalds committed
2245
      restore_flags (flags);
2246 2247 2248 2249 2250 2251 2252 2253 2254
    }

  pcm_active = 1;
}

static void
gus_transfer_output_block (int dev, unsigned long buf,
			   int total_count, int intrflag, int chn)
{
Linus Torvalds's avatar
Linus Torvalds committed
2255
  /*
2256 2257 2258
   * This routine transfers one block of audio data to the DRAM. In mono mode
   * it's called just once. When in stereo mode, this_one routine is called
   * once for both channels.
Linus Torvalds's avatar
Linus Torvalds committed
2259
   *
2260 2261 2262 2263 2264 2265 2266 2267 2268
   * The left/mono channel data is transferred to the beginning of dram and the
   * right data to the area pointed by gus_page_size.
   */

  int             this_one, count;
  unsigned long   flags;
  unsigned char   dma_command;
  unsigned long   address, hold_address;

Linus Torvalds's avatar
Linus Torvalds committed
2269 2270
  save_flags (flags);
  cli ();
2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286

  count = total_count / gus_sampling_channels;

  if (chn == 0)
    {
      if (pcm_qlen >= pcm_nblk)
	printk ("GUS Warning: PCM buffers out of sync\n");

      this_one = pcm_current_block = pcm_tail;
      pcm_qlen++;
      pcm_tail = (pcm_tail + 1) % pcm_nblk;
      pcm_datasize[this_one] = count;
    }
  else
    this_one = pcm_current_block;

Linus Torvalds's avatar
Linus Torvalds committed
2287
  gus_write8 (0x41, 0);		/* Disable GF1 DMA */
2288 2289 2290 2291 2292
  DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE);

  address = this_one * pcm_bsize;
  address += chn * pcm_banksize;

Linus Torvalds's avatar
Linus Torvalds committed
2293
  if (audio_devs[dev]->dmachan1 > 3)
2294 2295 2296 2297 2298 2299 2300
    {
      hold_address = address;
      address = address >> 1;
      address &= 0x0001ffffL;
      address |= (hold_address & 0x000c0000L);
    }

Linus Torvalds's avatar
Linus Torvalds committed
2301
  gus_write16 (0x42, (address >> 4) & 0xffff);	/* DRAM DMA address */
2302

Linus Torvalds's avatar
Linus Torvalds committed
2303
  dma_command = 0x21;		/* IRQ enable, DMA start */
2304 2305

  if (gus_sampling_bits != 8)
Linus Torvalds's avatar
Linus Torvalds committed
2306
    dma_command |= 0x40;	/* 16 bit _DATA_ */
2307
  else
Linus Torvalds's avatar
Linus Torvalds committed
2308
    dma_command |= 0x80;	/* Invert MSB */
2309

Linus Torvalds's avatar
Linus Torvalds committed
2310
  if (audio_devs[dev]->dmachan1 > 3)
Linus Torvalds's avatar
Linus Torvalds committed
2311
    dma_command |= 0x04;	/* 16 bit DMA channel */
2312

Linus Torvalds's avatar
Linus Torvalds committed
2313
  gus_write8 (0x41, dma_command);	/* Kickstart */
2314

Linus Torvalds's avatar
Linus Torvalds committed
2315
  if (chn == (gus_sampling_channels - 1))	/* Last channel */
2316
    {
Linus Torvalds's avatar
Linus Torvalds committed
2317 2318
      /*
       * Last (right or mono) channel data
Linus Torvalds's avatar
Linus Torvalds committed
2319
       */
Linus Torvalds's avatar
Linus Torvalds committed
2320
      dma_active = 1;		/* DMA started. There is a unacknowledged buffer */
2321
      active_device = GUS_DEV_PCM_DONE;
Linus Torvalds's avatar
Linus Torvalds committed
2322
      if (!pcm_active && (pcm_qlen > 0 || count < pcm_bsize))
2323 2324 2325 2326
	{
	  play_next_pcm_block ();
	}
    }
Linus Torvalds's avatar
Linus Torvalds committed
2327 2328 2329
  else
    {
      /*
Linus Torvalds's avatar
Linus Torvalds committed
2330 2331 2332
         * Left channel data. The right channel
         * is transferred after DMA interrupt
       */
Linus Torvalds's avatar
Linus Torvalds committed
2333 2334
      active_device = GUS_DEV_PCM_CONTINUE;
    }
2335

Linus Torvalds's avatar
Linus Torvalds committed
2336
  restore_flags (flags);
2337 2338 2339
}

static void
Linus Torvalds's avatar
Linus Torvalds committed
2340
gus_sampling_output_block (int dev, unsigned long buf, int total_count,
Linus Torvalds's avatar
Linus Torvalds committed
2341
			   int intrflag, int restart_dma)
2342 2343 2344 2345 2346 2347 2348 2349 2350
{
  pcm_current_buf = buf;
  pcm_current_count = total_count;
  pcm_current_intrflag = intrflag;
  pcm_current_dev = dev;
  gus_transfer_output_block (dev, buf, total_count, intrflag, 0);
}

static void
Linus Torvalds's avatar
Linus Torvalds committed
2351
gus_sampling_start_input (int dev, unsigned long buf, int count,
Linus Torvalds's avatar
Linus Torvalds committed
2352
			  int intrflag, int restart_dma)
2353 2354 2355 2356
{
  unsigned long   flags;
  unsigned char   mode;

Linus Torvalds's avatar
Linus Torvalds committed
2357 2358
  save_flags (flags);
  cli ();
2359 2360 2361

  DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);

Linus Torvalds's avatar
Linus Torvalds committed
2362
  mode = 0xa0;			/* DMA IRQ enabled, invert MSB */
2363

Linus Torvalds's avatar
Linus Torvalds committed
2364
  if (audio_devs[dev]->dmachan2 > 3)
Linus Torvalds's avatar
Linus Torvalds committed
2365
    mode |= 0x04;		/* 16 bit DMA channel */
2366
  if (gus_sampling_channels > 1)
Linus Torvalds's avatar
Linus Torvalds committed
2367 2368
    mode |= 0x02;		/* Stereo */
  mode |= 0x01;			/* DMA enable */
2369 2370 2371

  gus_write8 (0x49, mode);

Linus Torvalds's avatar
Linus Torvalds committed
2372
  restore_flags (flags);
2373 2374 2375 2376 2377 2378 2379 2380 2381
}

static int
gus_sampling_prepare_for_input (int dev, int bsize, int bcount)
{
  unsigned int    rate;

  rate = (9878400 / (gus_sampling_speed + 2)) / 16;

Linus Torvalds's avatar
Linus Torvalds committed
2382
  gus_write8 (0x48, rate & 0xff);	/* Set sampling rate */
2383 2384 2385 2386

  if (gus_sampling_bits != 8)
    {
      printk ("GUS Error: 16 bit recording not supported\n");
Linus Torvalds's avatar
Linus Torvalds committed
2387
      return -EINVAL;
2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424
    }

  return 0;
}

static int
gus_sampling_prepare_for_output (int dev, int bsize, int bcount)
{
  int             i;

  long            mem_ptr, mem_size;

  mem_ptr = 0;
  mem_size = gus_mem_size / gus_sampling_channels;

  if (mem_size > (256 * 1024))
    mem_size = 256 * 1024;

  pcm_bsize = bsize / gus_sampling_channels;
  pcm_head = pcm_tail = pcm_qlen = 0;

  pcm_nblk = MAX_PCM_BUFFERS;
  if ((pcm_bsize * pcm_nblk) > mem_size)
    pcm_nblk = mem_size / pcm_bsize;

  for (i = 0; i < pcm_nblk; i++)
    pcm_datasize[i] = 0;

  pcm_banksize = pcm_nblk * pcm_bsize;

  if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024))
    pcm_nblk--;

  return 0;
}

static int
Linus Torvalds's avatar
Linus Torvalds committed
2425
gus_local_qlen (int dev)
2426
{
Linus Torvalds's avatar
Linus Torvalds committed
2427
  return pcm_qlen;
2428 2429 2430 2431
}

static void
gus_copy_from_user (int dev, char *localbuf, int localoffs,
Linus Torvalds's avatar
Linus Torvalds committed
2432
		    const char *userbuf, int useroffs, int len)
2433 2434 2435
{
  if (gus_sampling_channels == 1)
    {
Linus Torvalds's avatar
Linus Torvalds committed
2436
      memcpy_fromfs (&localbuf[localoffs], &((userbuf)[useroffs]), len);
2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451
    }
  else if (gus_sampling_bits == 8)
    {
      int             in_left = useroffs;
      int             in_right = useroffs + 1;
      char           *out_left, *out_right;
      int             i;

      len /= 2;
      localoffs /= 2;
      out_left = &localbuf[localoffs];
      out_right = out_left + pcm_bsize;

      for (i = 0; i < len; i++)
	{
Linus Torvalds's avatar
Linus Torvalds committed
2452
	  *out_left++ = get_fs_byte (&((userbuf)[in_left]));
2453
	  in_left += 2;
Linus Torvalds's avatar
Linus Torvalds committed
2454
	  *out_right++ = get_fs_byte (&((userbuf)[in_right]));
2455 2456 2457 2458 2459
	  in_right += 2;
	}
    }
  else
    {
Linus Torvalds's avatar
Linus Torvalds committed
2460 2461
      int             in_left = useroffs;
      int             in_right = useroffs + 2;
2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472
      short          *out_left, *out_right;
      int             i;

      len /= 4;
      localoffs /= 4;

      out_left = (short *) &localbuf[localoffs];
      out_right = out_left + (pcm_bsize / 2);

      for (i = 0; i < len; i++)
	{
Linus Torvalds's avatar
Linus Torvalds committed
2473 2474 2475 2476
	  *out_left++ = get_fs_word (&((userbuf)[in_left]));
	  in_left += 4;
	  *out_right++ = get_fs_word (&((userbuf)[in_right]));
	  in_right += 4;
2477 2478 2479 2480 2481 2482 2483
	}
    }
}

static struct audio_operations gus_sampling_operations =
{
  "Gravis UltraSound",
Linus Torvalds's avatar
Linus Torvalds committed
2484
  NEEDS_RESTART,
Linus Torvalds's avatar
Linus Torvalds committed
2485 2486
  AFMT_U8 | AFMT_S16_LE,
  NULL,
Linus Torvalds's avatar
Linus Torvalds committed
2487 2488 2489 2490 2491 2492 2493 2494 2495
  gus_sampling_open,
  gus_sampling_close,
  gus_sampling_output_block,
  gus_sampling_start_input,
  gus_sampling_ioctl,
  gus_sampling_prepare_for_input,
  gus_sampling_prepare_for_output,
  gus_sampling_reset,
  gus_sampling_reset,
Linus Torvalds's avatar
Linus Torvalds committed
2496
  gus_local_qlen,
2497 2498 2499
  gus_copy_from_user
};

Linus Torvalds's avatar
Linus Torvalds committed
2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516
static void
guswave_setup_voice (int dev, int voice, int chn)
{
  struct channel_info *info =
  &synth_devs[dev]->chn_info[chn];

  guswave_set_instr (dev, voice, info->pgm_num);

  voices[voice].expression_vol =
    info->controllers[CTL_EXPRESSION];	/* Just msb */
  voices[voice].main_vol =
    (info->controllers[CTL_MAIN_VOLUME] * 100) / 128;
  voices[voice].panning =
    (info->controllers[CTL_PAN] * 2) - 128;
  voices[voice].bender = info->bender_value;
}

Linus Torvalds's avatar
Linus Torvalds committed
2517 2518 2519 2520 2521 2522 2523
static void
guswave_bender (int dev, int voice, int value)
{
  int             freq;
  unsigned long   flags;

  voices[voice].bender = value - 8192;
Linus Torvalds's avatar
Linus Torvalds committed
2524
  freq = compute_finetune (voices[voice].orig_freq, value - 8192,
Linus Torvalds's avatar
Linus Torvalds committed
2525
			   voices[voice].bender_range);
Linus Torvalds's avatar
Linus Torvalds committed
2526 2527
  voices[voice].current_freq = freq;

Linus Torvalds's avatar
Linus Torvalds committed
2528 2529
  save_flags (flags);
  cli ();
Linus Torvalds's avatar
Linus Torvalds committed
2530 2531
  gus_select_voice (voice);
  gus_voice_freq (freq);
Linus Torvalds's avatar
Linus Torvalds committed
2532
  restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
2533
}
Linus Torvalds's avatar
Linus Torvalds committed
2534

2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560
static int
guswave_patchmgr (int dev, struct patmgr_info *rec)
{
  int             i, n;

  switch (rec->command)
    {
    case PM_GET_DEVTYPE:
      rec->parm1 = PMTYPE_WAVE;
      return 0;
      break;

    case PM_GET_NRPGM:
      rec->parm1 = MAX_PATCH;
      return 0;
      break;

    case PM_GET_PGMMAP:
      rec->parm1 = MAX_PATCH;

      for (i = 0; i < MAX_PATCH; i++)
	{
	  int             ptr = patch_table[i];

	  rec->data.data8[i] = 0;

Linus Torvalds's avatar
Linus Torvalds committed
2561
	  while (ptr >= 0 && ptr < free_sample && ptr != NOT_SAMPLE)
2562 2563
	    {
	      rec->data.data8[i]++;
Linus Torvalds's avatar
Linus Torvalds committed
2564
	      ptr = samples[ptr].key;	/* Follow link */
2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575
	    }
	}
      return 0;
      break;

    case PM_GET_PGM_PATCHES:
      {
	int             ptr = patch_table[rec->parm1];

	n = 0;

Linus Torvalds's avatar
Linus Torvalds committed
2576
	while (ptr >= 0 && ptr < free_sample && ptr != NOT_SAMPLE)
2577 2578
	  {
	    rec->data.data32[n++] = ptr;
Linus Torvalds's avatar
Linus Torvalds committed
2579
	    ptr = samples[ptr].key;	/* Follow link */
2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591
	  }
      }
      rec->parm1 = n;
      return 0;
      break;

    case PM_GET_PATCH:
      {
	int             ptr = rec->parm1;
	struct patch_info *pat;

	if (ptr < 0 || ptr >= free_sample)
Linus Torvalds's avatar
Linus Torvalds committed
2592
	  return -EINVAL;
2593 2594 2595 2596 2597 2598

	memcpy (rec->data.data8, (char *) &samples[ptr],
		sizeof (struct patch_info));

	pat = (struct patch_info *) rec->data.data8;

Linus Torvalds's avatar
Linus Torvalds committed
2599 2600
	pat->key = GUS_PATCH;	/* Restore patch type */
	rec->parm1 = sample_ptrs[ptr];	/* DRAM location */
2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611
	rec->parm2 = sizeof (struct patch_info);
      }
      return 0;
      break;

    case PM_SET_PATCH:
      {
	int             ptr = rec->parm1;
	struct patch_info *pat;

	if (ptr < 0 || ptr >= free_sample)
Linus Torvalds's avatar
Linus Torvalds committed
2612
	  return -EINVAL;
2613 2614 2615

	pat = (struct patch_info *) rec->data.data8;

Linus Torvalds's avatar
Linus Torvalds committed
2616
	if (pat->len > samples[ptr].len)	/* Cannot expand sample */
Linus Torvalds's avatar
Linus Torvalds committed
2617
	  return -EINVAL;
2618

Linus Torvalds's avatar
Linus Torvalds committed
2619
	pat->key = samples[ptr].key;	/* Ensure the link is correct */
2620 2621 2622 2623 2624 2625 2626 2627 2628

	memcpy ((char *) &samples[ptr], rec->data.data8,
		sizeof (struct patch_info));

	pat->key = GUS_PATCH;
      }
      return 0;
      break;

Linus Torvalds's avatar
Linus Torvalds committed
2629
    case PM_READ_PATCH:	/* Returns a block of wave data from the DRAM */
2630 2631 2632 2633 2634 2635 2636
      {
	int             sample = rec->parm1;
	int             n;
	long            offs = rec->parm2;
	int             l = rec->parm3;

	if (sample < 0 || sample >= free_sample)
Linus Torvalds's avatar
Linus Torvalds committed
2637
	  return -EINVAL;
2638 2639

	if (offs < 0 || offs >= samples[sample].len)
Linus Torvalds's avatar
Linus Torvalds committed
2640
	  return -EINVAL;	/* Invalid offset */
2641

Linus Torvalds's avatar
Linus Torvalds committed
2642
	n = samples[sample].len - offs;		/* Num of bytes left */
2643 2644 2645 2646 2647 2648 2649 2650

	if (l > n)
	  l = n;

	if (l > sizeof (rec->data.data8))
	  l = sizeof (rec->data.data8);

	if (l <= 0)
Linus Torvalds's avatar
Linus Torvalds committed
2651 2652 2653
	  return -EINVAL;	/*
				   * Was there a bug?
				 */
2654

Linus Torvalds's avatar
Linus Torvalds committed
2655
	offs += sample_ptrs[sample];	/*
Linus Torvalds's avatar
Linus Torvalds committed
2656
					 * Begin offset + offset to DRAM
Linus Torvalds's avatar
Linus Torvalds committed
2657
					 */
2658 2659 2660

	for (n = 0; n < l; n++)
	  rec->data.data8[n] = gus_peek (offs++);
Linus Torvalds's avatar
Linus Torvalds committed
2661 2662
	rec->parm1 = n;		/*
				 * Nr of bytes copied
Linus Torvalds's avatar
Linus Torvalds committed
2663
				 */
2664 2665 2666 2667
      }
      return 0;
      break;

Linus Torvalds's avatar
Linus Torvalds committed
2668 2669
    case PM_WRITE_PATCH:	/*
				 * Writes a block of wave data to the DRAM
Linus Torvalds's avatar
Linus Torvalds committed
2670
				 */
2671 2672 2673 2674 2675 2676 2677
      {
	int             sample = rec->parm1;
	int             n;
	long            offs = rec->parm2;
	int             l = rec->parm3;

	if (sample < 0 || sample >= free_sample)
Linus Torvalds's avatar
Linus Torvalds committed
2678
	  return -EINVAL;
2679 2680

	if (offs < 0 || offs >= samples[sample].len)
Linus Torvalds's avatar
Linus Torvalds committed
2681 2682 2683
	  return -EINVAL;	/*
				   * Invalid offset
				 */
2684

Linus Torvalds's avatar
Linus Torvalds committed
2685 2686
	n = samples[sample].len - offs;		/*
						   * Nr of bytes left
Linus Torvalds's avatar
Linus Torvalds committed
2687
						 */
2688 2689 2690 2691 2692 2693 2694 2695

	if (l > n)
	  l = n;

	if (l > sizeof (rec->data.data8))
	  l = sizeof (rec->data.data8);

	if (l <= 0)
Linus Torvalds's avatar
Linus Torvalds committed
2696 2697 2698
	  return -EINVAL;	/*
				   * Was there a bug?
				 */
2699

Linus Torvalds's avatar
Linus Torvalds committed
2700
	offs += sample_ptrs[sample];	/*
Linus Torvalds's avatar
Linus Torvalds committed
2701
					 * Begin offset + offset to DRAM
Linus Torvalds's avatar
Linus Torvalds committed
2702
					 */
2703 2704 2705

	for (n = 0; n < l; n++)
	  gus_poke (offs++, rec->data.data8[n]);
Linus Torvalds's avatar
Linus Torvalds committed
2706 2707
	rec->parm1 = n;		/*
				 * Nr of bytes copied
Linus Torvalds's avatar
Linus Torvalds committed
2708
				 */
2709 2710 2711 2712 2713
      }
      return 0;
      break;

    default:
Linus Torvalds's avatar
Linus Torvalds committed
2714
      return -EINVAL;
2715 2716 2717
    }
}

Linus Torvalds's avatar
Linus Torvalds committed
2718 2719 2720
static int
guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc)
{
Linus Torvalds's avatar
Linus Torvalds committed
2721
  int             i, p, best = -1, best_time = 0x7fffffff;
Linus Torvalds's avatar
Linus Torvalds committed
2722 2723 2724

  p = alloc->ptr;
  /*
Linus Torvalds's avatar
Linus Torvalds committed
2725 2726
     * First look for a completely stopped voice
   */
Linus Torvalds's avatar
Linus Torvalds committed
2727 2728 2729 2730 2731 2732 2733 2734

  for (i = 0; i < alloc->max_voice; i++)
    {
      if (alloc->map[p] == 0)
	{
	  alloc->ptr = p;
	  return p;
	}
Linus Torvalds's avatar
Linus Torvalds committed
2735 2736 2737 2738 2739
      if (alloc->alloc_times[p] < best_time)
	{
	  best = p;
	  best_time = alloc->alloc_times[p];
	}
Linus Torvalds's avatar
Linus Torvalds committed
2740 2741 2742 2743
      p = (p + 1) % alloc->max_voice;
    }

  /*
Linus Torvalds's avatar
Linus Torvalds committed
2744 2745
     * Then look for a releasing voice
   */
Linus Torvalds's avatar
Linus Torvalds committed
2746 2747 2748 2749 2750 2751 2752 2753 2754 2755

  for (i = 0; i < alloc->max_voice; i++)
    {
      if (alloc->map[p] == 0xffff)
	{
	  alloc->ptr = p;
	  return p;
	}
      p = (p + 1) % alloc->max_voice;
    }
Linus Torvalds's avatar
Linus Torvalds committed
2756 2757 2758

  if (best >= 0)
    p = best;
Linus Torvalds's avatar
Linus Torvalds committed
2759 2760 2761 2762 2763

  alloc->ptr = p;
  return p;
}

2764 2765 2766
static struct synth_operations guswave_operations =
{
  &gus_info,
Linus Torvalds's avatar
Linus Torvalds committed
2767
  0,
2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781
  SYNTH_TYPE_SAMPLE,
  SAMPLE_TYPE_GUS,
  guswave_open,
  guswave_close,
  guswave_ioctl,
  guswave_kill_note,
  guswave_start_note,
  guswave_set_instr,
  guswave_reset,
  guswave_hw_control,
  guswave_load_patch,
  guswave_aftertouch,
  guswave_controller,
  guswave_panning,
Linus Torvalds's avatar
Linus Torvalds committed
2782
  guswave_volume_method,
Linus Torvalds's avatar
Linus Torvalds committed
2783
  guswave_patchmgr,
Linus Torvalds's avatar
Linus Torvalds committed
2784
  guswave_bender,
Linus Torvalds's avatar
Linus Torvalds committed
2785 2786
  guswave_alloc,
  guswave_setup_voice
Linus Torvalds's avatar
Linus Torvalds committed
2787 2788 2789
};

static void
Linus Torvalds's avatar
Linus Torvalds committed
2790
set_input_volumes (void)
Linus Torvalds's avatar
Linus Torvalds committed
2791
{
Linus Torvalds's avatar
Linus Torvalds committed
2792 2793
  unsigned long   flags;
  unsigned char   mask = 0xff & ~0x06;	/* Just line out enabled */
Linus Torvalds's avatar
Linus Torvalds committed
2794

Linus Torvalds's avatar
Linus Torvalds committed
2795 2796 2797
  if (have_gus_max)		/* Don't disturb GUS MAX */
    return;

Linus Torvalds's avatar
Linus Torvalds committed
2798 2799
  save_flags (flags);
  cli ();
Linus Torvalds's avatar
Linus Torvalds committed
2800

Linus Torvalds's avatar
Linus Torvalds committed
2801
  /*
Linus Torvalds's avatar
Linus Torvalds committed
2802 2803 2804 2805
   *    Enable channels having vol > 10%
   *      Note! bit 0x01 means the line in DISABLED while 0x04 means
   *            the mic in ENABLED.
   */
Linus Torvalds's avatar
Linus Torvalds committed
2806 2807 2808 2809
  if (gus_line_vol > 10)
    mask &= ~0x01;
  if (gus_mic_vol > 10)
    mask |= 0x04;
Linus Torvalds's avatar
Linus Torvalds committed
2810

Linus Torvalds's avatar
Linus Torvalds committed
2811 2812 2813
  if (recording_active)
    {
      /*
Linus Torvalds's avatar
Linus Torvalds committed
2814 2815
       *    Disable channel, if not selected for recording
       */
Linus Torvalds's avatar
Linus Torvalds committed
2816 2817 2818 2819 2820
      if (!(gus_recmask & SOUND_MASK_LINE))
	mask |= 0x01;
      if (!(gus_recmask & SOUND_MASK_MIC))
	mask &= ~0x04;
    }
Linus Torvalds's avatar
Linus Torvalds committed
2821

Linus Torvalds's avatar
Linus Torvalds committed
2822 2823
  mix_image &= ~0x07;
  mix_image |= mask & 0x07;
Linus Torvalds's avatar
Linus Torvalds committed
2824
  outb (mix_image, u_Mixer);
Linus Torvalds's avatar
Linus Torvalds committed
2825

Linus Torvalds's avatar
Linus Torvalds committed
2826
  restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
2827 2828
}

Linus Torvalds's avatar
Linus Torvalds committed
2829
int
Linus Torvalds's avatar
Linus Torvalds committed
2830
gus_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
Linus Torvalds's avatar
Linus Torvalds committed
2831 2832 2833 2834 2835
{
#define MIX_DEVS	(SOUND_MASK_MIC|SOUND_MASK_LINE| \
			 SOUND_MASK_SYNTH|SOUND_MASK_PCM)
  if (((cmd >> 8) & 0xff) == 'M')
    {
Linus Torvalds's avatar
Linus Torvalds committed
2836
      if (_IOC_DIR (cmd) & _IOC_WRITE)
Linus Torvalds's avatar
Linus Torvalds committed
2837 2838 2839
	switch (cmd & 0xff)
	  {
	  case SOUND_MIXER_RECSRC:
Linus Torvalds's avatar
Linus Torvalds committed
2840
	    gus_recmask = get_fs_long ((long *) arg) & MIX_DEVS;
Linus Torvalds's avatar
Linus Torvalds committed
2841 2842
	    if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
	      gus_recmask = SOUND_MASK_MIC;
Linus Torvalds's avatar
Linus Torvalds committed
2843
	    /* Note! Input volumes are updated during next open for recording */
Linus Torvalds's avatar
Linus Torvalds committed
2844
	    return snd_ioctl_return ((int *) arg, gus_recmask);
Linus Torvalds's avatar
Linus Torvalds committed
2845 2846 2847 2848
	    break;

	  case SOUND_MIXER_MIC:
	    {
Linus Torvalds's avatar
Linus Torvalds committed
2849
	      int             vol = get_fs_long ((long *) arg) & 0xff;
Linus Torvalds's avatar
Linus Torvalds committed
2850 2851 2852 2853 2854

	      if (vol < 0)
		vol = 0;
	      if (vol > 100)
		vol = 100;
Linus Torvalds's avatar
Linus Torvalds committed
2855
	      gus_mic_vol = vol;
Linus Torvalds's avatar
Linus Torvalds committed
2856
	      set_input_volumes ();
Linus Torvalds's avatar
Linus Torvalds committed
2857
	      return snd_ioctl_return ((int *) arg, vol | (vol << 8));
Linus Torvalds's avatar
Linus Torvalds committed
2858 2859 2860 2861 2862
	    }
	    break;

	  case SOUND_MIXER_LINE:
	    {
Linus Torvalds's avatar
Linus Torvalds committed
2863
	      int             vol = get_fs_long ((long *) arg) & 0xff;
Linus Torvalds's avatar
Linus Torvalds committed
2864 2865 2866 2867 2868

	      if (vol < 0)
		vol = 0;
	      if (vol > 100)
		vol = 100;
Linus Torvalds's avatar
Linus Torvalds committed
2869
	      gus_line_vol = vol;
Linus Torvalds's avatar
Linus Torvalds committed
2870
	      set_input_volumes ();
Linus Torvalds's avatar
Linus Torvalds committed
2871
	      return snd_ioctl_return ((int *) arg, vol | (vol << 8));
Linus Torvalds's avatar
Linus Torvalds committed
2872 2873 2874 2875
	    }
	    break;

	  case SOUND_MIXER_PCM:
Linus Torvalds's avatar
Linus Torvalds committed
2876
	    gus_pcm_volume = get_fs_long ((long *) arg) & 0xff;
Linus Torvalds's avatar
Linus Torvalds committed
2877 2878 2879 2880 2881
	    if (gus_pcm_volume < 0)
	      gus_pcm_volume = 0;
	    if (gus_pcm_volume > 100)
	      gus_pcm_volume = 100;
	    gus_sampling_update_volume ();
Linus Torvalds's avatar
Linus Torvalds committed
2882
	    return snd_ioctl_return ((int *) arg, gus_pcm_volume | (gus_pcm_volume << 8));
Linus Torvalds's avatar
Linus Torvalds committed
2883 2884 2885 2886
	    break;

	  case SOUND_MIXER_SYNTH:
	    {
Linus Torvalds's avatar
Linus Torvalds committed
2887
	      int             voice;
Linus Torvalds's avatar
Linus Torvalds committed
2888

Linus Torvalds's avatar
Linus Torvalds committed
2889
	      gus_wave_volume = get_fs_long ((long *) arg) & 0xff;
Linus Torvalds's avatar
Linus Torvalds committed
2890 2891 2892 2893 2894 2895 2896 2897

	      if (gus_wave_volume < 0)
		gus_wave_volume = 0;
	      if (gus_wave_volume > 100)
		gus_wave_volume = 100;

	      if (active_device == GUS_DEV_WAVE)
		for (voice = 0; voice < nr_voices; voice++)
Linus Torvalds's avatar
Linus Torvalds committed
2898
		  dynamic_volume_change (voice);	/* Apply the new vol */
Linus Torvalds's avatar
Linus Torvalds committed
2899

Linus Torvalds's avatar
Linus Torvalds committed
2900
	      return snd_ioctl_return ((int *) arg, gus_wave_volume | (gus_wave_volume << 8));
Linus Torvalds's avatar
Linus Torvalds committed
2901 2902 2903 2904
	    }
	    break;

	  default:
Linus Torvalds's avatar
Linus Torvalds committed
2905
	    return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
2906 2907
	  }
      else
Linus Torvalds's avatar
Linus Torvalds committed
2908 2909
	switch (cmd & 0xff)	/*
				 * Return parameters
Linus Torvalds's avatar
Linus Torvalds committed
2910 2911 2912 2913
				 */
	  {

	  case SOUND_MIXER_RECSRC:
Linus Torvalds's avatar
Linus Torvalds committed
2914
	    return snd_ioctl_return ((int *) arg, gus_recmask);
Linus Torvalds's avatar
Linus Torvalds committed
2915 2916 2917
	    break;

	  case SOUND_MIXER_DEVMASK:
Linus Torvalds's avatar
Linus Torvalds committed
2918
	    return snd_ioctl_return ((int *) arg, MIX_DEVS);
Linus Torvalds's avatar
Linus Torvalds committed
2919 2920 2921
	    break;

	  case SOUND_MIXER_STEREODEVS:
Linus Torvalds's avatar
Linus Torvalds committed
2922
	    return snd_ioctl_return ((int *) arg, 0);
Linus Torvalds's avatar
Linus Torvalds committed
2923 2924 2925
	    break;

	  case SOUND_MIXER_RECMASK:
Linus Torvalds's avatar
Linus Torvalds committed
2926
	    return snd_ioctl_return ((int *) arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
Linus Torvalds's avatar
Linus Torvalds committed
2927 2928 2929
	    break;

	  case SOUND_MIXER_CAPS:
Linus Torvalds's avatar
Linus Torvalds committed
2930
	    return snd_ioctl_return ((int *) arg, 0);
Linus Torvalds's avatar
Linus Torvalds committed
2931 2932 2933
	    break;

	  case SOUND_MIXER_MIC:
Linus Torvalds's avatar
Linus Torvalds committed
2934
	    return snd_ioctl_return ((int *) arg, gus_mic_vol | (gus_mic_vol << 8));
Linus Torvalds's avatar
Linus Torvalds committed
2935 2936 2937
	    break;

	  case SOUND_MIXER_LINE:
Linus Torvalds's avatar
Linus Torvalds committed
2938
	    return snd_ioctl_return ((int *) arg, gus_line_vol | (gus_line_vol << 8));
Linus Torvalds's avatar
Linus Torvalds committed
2939 2940 2941
	    break;

	  case SOUND_MIXER_PCM:
Linus Torvalds's avatar
Linus Torvalds committed
2942
	    return snd_ioctl_return ((int *) arg, gus_pcm_volume | (gus_pcm_volume << 8));
Linus Torvalds's avatar
Linus Torvalds committed
2943 2944 2945
	    break;

	  case SOUND_MIXER_SYNTH:
Linus Torvalds's avatar
Linus Torvalds committed
2946
	    return snd_ioctl_return ((int *) arg, gus_wave_volume | (gus_wave_volume << 8));
Linus Torvalds's avatar
Linus Torvalds committed
2947 2948 2949
	    break;

	  default:
Linus Torvalds's avatar
Linus Torvalds committed
2950
	    return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
2951 2952 2953
	  }
    }
  else
Linus Torvalds's avatar
Linus Torvalds committed
2954
    return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
2955 2956 2957 2958
}

static struct mixer_operations gus_mixer_operations =
{
Linus Torvalds's avatar
Linus Torvalds committed
2959
  "Gravis Ultrasound",
Linus Torvalds's avatar
Linus Torvalds committed
2960
  gus_default_mixer_ioctl
2961 2962
};

Linus Torvalds's avatar
Linus Torvalds committed
2963 2964 2965 2966 2967 2968 2969 2970 2971
static long
gus_default_mixer_init (long mem_start)
{
  if (num_mixers < MAX_MIXER_DEV)	/*
					 * Don't install if there is another
					 * mixer
					 */
    mixer_devs[num_mixers++] = &gus_mixer_operations;

Linus Torvalds's avatar
Linus Torvalds committed
2972 2973 2974 2975 2976 2977 2978 2979
  if (have_gus_max)
    {
/*
 *  Enable all mixer channels on the GF1 side. Otherwise recording will
 *  not be possible using GUS MAX.
 */
      mix_image &= ~0x07;
      mix_image |= 0x04;	/* All channels enabled */
Linus Torvalds's avatar
Linus Torvalds committed
2980
      outb (mix_image, u_Mixer);
Linus Torvalds's avatar
Linus Torvalds committed
2981
    }
Linus Torvalds's avatar
Linus Torvalds committed
2982 2983 2984
  return mem_start;
}

2985
long
Linus Torvalds's avatar
Linus Torvalds committed
2986
gus_wave_init (long mem_start, struct address_info *hw_config)
2987
{
Linus Torvalds's avatar
Linus Torvalds committed
2988 2989 2990 2991
  unsigned long   flags;
  unsigned char   val;
  char           *model_num = "2.4";
  int             gus_type = 0x24;	/* 2.4 */
Linus Torvalds's avatar
Linus Torvalds committed
2992 2993

  int             irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2;
Linus Torvalds's avatar
Linus Torvalds committed
2994

Linus Torvalds's avatar
Linus Torvalds committed
2995 2996 2997 2998 2999 3000
  if (!gus_pnp_flag)
    if (irq < 0 || irq > 15)
      {
	printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
	return mem_start;
      }
Linus Torvalds's avatar
Linus Torvalds committed
3001

Linus Torvalds's avatar
Linus Torvalds committed
3002
  if (dma < 0 || dma > 7 || dma == 4)
Linus Torvalds's avatar
Linus Torvalds committed
3003 3004 3005 3006 3007 3008 3009
    {
      printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma);
      return mem_start;
    }

  gus_irq = irq;
  gus_dma = dma;
Linus Torvalds's avatar
Linus Torvalds committed
3010 3011 3012 3013
  gus_dma2 = dma2;

  if (gus_dma2 == -1)
    gus_dma2 = dma;
Linus Torvalds's avatar
Linus Torvalds committed
3014

Linus Torvalds's avatar
Linus Torvalds committed
3015
  /*
Linus Torvalds's avatar
Linus Torvalds committed
3016 3017 3018 3019
     * Try to identify the GUS model.
     *
     *  Versions < 3.6 don't have the digital ASIC. Try to probe it first.
   */
Linus Torvalds's avatar
Linus Torvalds committed
3020

Linus Torvalds's avatar
Linus Torvalds committed
3021 3022 3023 3024 3025
  save_flags (flags);
  cli ();
  outb (0x20, gus_base + 0x0f);
  val = inb (gus_base + 0x0f);
  restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
3026

Linus Torvalds's avatar
Linus Torvalds committed
3027 3028 3029 3030 3031
#ifndef GUSPNP_NO_AUTODETECT
  gus_pnp_flag = (val == 1);
#endif

  if (gus_pnp_flag || (val != 0xff && (val & 0x06)))	/* Should be 0x02?? */
Linus Torvalds's avatar
Linus Torvalds committed
3032 3033
    {
      /*
Linus Torvalds's avatar
Linus Torvalds committed
3034 3035 3036
         * It has the digital ASIC so the card is at least v3.4.
         * Next try to detect the true model.
       */
Linus Torvalds's avatar
Linus Torvalds committed
3037

Linus Torvalds's avatar
Linus Torvalds committed
3038 3039 3040 3041
      if (gus_pnp_flag)		/* Hack hack hack */
	val = 10;
      else
	val = inb (u_MixSelect);
Linus Torvalds's avatar
Linus Torvalds committed
3042 3043 3044 3045 3046 3047

      /*
         * Value 255 means pre-3.7 which don't have mixer.
         * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer.
         * 10 and above is GUS MAX which has the CS4231 codec/mixer.
         *
Linus Torvalds's avatar
Linus Torvalds committed
3048
       */
Linus Torvalds's avatar
Linus Torvalds committed
3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059

      if (val == 255 || val < 5)
	{
	  model_num = "3.4";
	  gus_type = 0x34;
	}
      else if (val < 10)
	{
	  model_num = "3.7";
	  gus_type = 0x37;
	  mixer_type = ICS2101;
Linus Torvalds's avatar
Linus Torvalds committed
3060
	  request_region (u_MixSelect, 1, "GUS mixer");
Linus Torvalds's avatar
Linus Torvalds committed
3061 3062 3063 3064 3065 3066
	}
      else
	{
	  model_num = "MAX";
	  gus_type = 0x40;
	  mixer_type = CS4231;
Linus Torvalds's avatar
Linus Torvalds committed
3067
#ifdef CONFIG_GUSMAX
Linus Torvalds's avatar
Linus Torvalds committed
3068 3069 3070
	  {
	    unsigned char   max_config = 0x40;	/* Codec enable */

Linus Torvalds's avatar
Linus Torvalds committed
3071 3072 3073
	    if (gus_dma2 == -1)
	      gus_dma2 = gus_dma;

Linus Torvalds's avatar
Linus Torvalds committed
3074 3075 3076
	    if (gus_dma > 3)
	      max_config |= 0x10;	/* 16 bit capture DMA */

Linus Torvalds's avatar
Linus Torvalds committed
3077
	    if (gus_dma2 > 3)
Linus Torvalds's avatar
Linus Torvalds committed
3078
	      max_config |= 0x20;	/* 16 bit playback DMA */
Linus Torvalds's avatar
Linus Torvalds committed
3079 3080 3081

	    max_config |= (gus_base >> 4) & 0x0f;	/* Extract the X from 2X0 */

Linus Torvalds's avatar
Linus Torvalds committed
3082
	    outb (max_config, gus_base + 0x106);	/* UltraMax control */
Linus Torvalds's avatar
Linus Torvalds committed
3083 3084
	  }

Linus Torvalds's avatar
Linus Torvalds committed
3085
	  if (ad1848_detect (gus_base + 0x10c, NULL, hw_config->osp))
Linus Torvalds's avatar
Linus Torvalds committed
3086
	    {
Linus Torvalds's avatar
Linus Torvalds committed
3087

Linus Torvalds's avatar
Linus Torvalds committed
3088 3089 3090 3091 3092
	      gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
	      gus_wave_volume = 90;
	      have_gus_max = 1;
	      ad1848_init ("GUS MAX", gus_base + 0x10c,
			   -irq,
Linus Torvalds's avatar
Linus Torvalds committed
3093 3094 3095 3096
			   gus_dma2,	/* Playback DMA */
			   gus_dma,	/* Capture DMA */
			   1,	/* Share DMA channels with GF1 */
			   hw_config->osp);
Linus Torvalds's avatar
Linus Torvalds committed
3097 3098 3099
	    }
	  else
	    printk ("[Where's the CS4231?]");
Linus Torvalds's avatar
Linus Torvalds committed
3100 3101
#else
	  printk ("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n");
Linus Torvalds's avatar
Linus Torvalds committed
3102
#endif
Linus Torvalds's avatar
Linus Torvalds committed
3103 3104 3105 3106 3107
	}
    }
  else
    {
      /*
Linus Torvalds's avatar
Linus Torvalds committed
3108 3109 3110
         * ASIC not detected so the card must be 2.2 or 2.4.
         * There could still be the 16-bit/mixer daughter card.
       */
Linus Torvalds's avatar
Linus Torvalds committed
3111 3112
    }

Linus Torvalds's avatar
Linus Torvalds committed
3113 3114
  if (hw_config->name)
    {
Linus Torvalds's avatar
Linus Torvalds committed
3115 3116 3117 3118 3119
      char            tmp[20];

      strncpy (tmp, hw_config->name, 20);
      tmp[19] = 0;
      sprintf (gus_info.name, "%s (%dk)", tmp, (int) gus_mem_size / 1024);
Linus Torvalds's avatar
Linus Torvalds committed
3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134
      gus_info.name[sizeof (gus_info.name) - 1] = 0;
    }
  else
    sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);


  samples = (struct patch_info *) (sound_mem_blocks[sound_num_blocks] = kmalloc ((MAX_SAMPLE + 1) * sizeof (*samples), GFP_KERNEL));
  if (sound_num_blocks < 1024)
    sound_num_blocks++;;
  if (samples == NULL)
    {
      printk ("GUS Error: Cant allocate memory for instrument tables\n");
      return mem_start;
    }

Linus Torvalds's avatar
Linus Torvalds committed
3135
  conf_printf (gus_info.name, hw_config);
3136 3137 3138 3139

  if (num_synths >= MAX_SYNTH_DEV)
    printk ("GUS Error: Too many synthesizers\n");
  else
Linus Torvalds's avatar
Linus Torvalds committed
3140 3141 3142
    {
      voice_alloc = &guswave_operations.alloc;
      synth_devs[num_synths++] = &guswave_operations;
Linus Torvalds's avatar
Linus Torvalds committed
3143
#ifdef CONFIG_SEQUENCER
Linus Torvalds's avatar
Linus Torvalds committed
3144 3145
      gus_tmr_install (gus_base + 8);
#endif
Linus Torvalds's avatar
Linus Torvalds committed
3146
    }
3147 3148 3149 3150 3151

  reset_sample_memory ();

  gus_initialize ();

Linus Torvalds's avatar
Linus Torvalds committed
3152
  if (num_audiodevs < MAX_AUDIO_DEV)
3153
    {
Linus Torvalds's avatar
Linus Torvalds committed
3154
      audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations;
Linus Torvalds's avatar
Linus Torvalds committed
3155 3156
      audio_devs[gus_devnum]->dmachan1 = dma;
      audio_devs[gus_devnum]->dmachan2 = dma2;
Linus Torvalds's avatar
Linus Torvalds committed
3157
      audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE;
Linus Torvalds's avatar
Linus Torvalds committed
3158 3159
      if (dma2 != dma && dma2 != -1)
	audio_devs[gus_devnum]->flags |= DMA_DUPLEX;
3160 3161 3162 3163
    }
  else
    printk ("GUS: Too many PCM devices available\n");

Linus Torvalds's avatar
Linus Torvalds committed
3164
  /*
Linus Torvalds's avatar
Linus Torvalds committed
3165 3166
     *  Mixer dependent initialization.
   */
Linus Torvalds's avatar
Linus Torvalds committed
3167 3168 3169 3170

  switch (mixer_type)
    {
    case ICS2101:
Linus Torvalds's avatar
Linus Torvalds committed
3171 3172
      gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
      gus_wave_volume = 90;
Linus Torvalds's avatar
Linus Torvalds committed
3173
      request_region (u_MixSelect, 1, "GUS mixer");
Linus Torvalds's avatar
Linus Torvalds committed
3174 3175 3176
      return ics2101_mixer_init (mem_start);

    case CS4231:
Linus Torvalds's avatar
Linus Torvalds committed
3177
      /* Initialized elsewhere (ad1848.c) */
Linus Torvalds's avatar
Linus Torvalds committed
3178 3179 3180
    default:
      return gus_default_mixer_init (mem_start);
    }
3181 3182
}

Linus Torvalds's avatar
Linus Torvalds committed
3183 3184 3185
void
gus_wave_unload (void)
{
Linus Torvalds's avatar
Linus Torvalds committed
3186
#ifdef CONFIG_GUSMAX
Linus Torvalds's avatar
Linus Torvalds committed
3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202
  if (have_gus_max)
    {
      ad1848_unload (gus_base + 0x10c,
		     -gus_irq,
		     gus_dma2,	/* Playback DMA */
		     gus_dma,	/* Capture DMA */
		     1);	/* Share DMA channels with GF1 */
    }
#endif

  if (mixer_type == ICS2101)
    {
      release_region (u_MixSelect, 1);
    }
}

3203 3204 3205 3206 3207 3208 3209
static void
do_loop_irq (int voice)
{
  unsigned char   tmp;
  int             mode, parm;
  unsigned long   flags;

Linus Torvalds's avatar
Linus Torvalds committed
3210 3211
  save_flags (flags);
  cli ();
3212 3213 3214
  gus_select_voice (voice);

  tmp = gus_read8 (0x00);
Linus Torvalds's avatar
Linus Torvalds committed
3215 3216
  tmp &= ~0x20;			/*
				 * Disable wave IRQ for this_one voice
Linus Torvalds's avatar
Linus Torvalds committed
3217
				 */
3218 3219
  gus_write8 (0x00, tmp);

Linus Torvalds's avatar
Linus Torvalds committed
3220 3221 3222
  if (tmp & 0x03)		/* Voice stopped */
    voice_alloc->map[voice] = 0;

3223 3224 3225 3226 3227 3228 3229
  mode = voices[voice].loop_irq_mode;
  voices[voice].loop_irq_mode = 0;
  parm = voices[voice].loop_irq_parm;

  switch (mode)
    {

Linus Torvalds's avatar
Linus Torvalds committed
3230 3231
    case LMODE_FINISH:		/*
				 * Final loop finished, shoot volume down
Linus Torvalds's avatar
Linus Torvalds committed
3232
				 */
3233

Linus Torvalds's avatar
Linus Torvalds committed
3234 3235 3236
      if ((int) (gus_read16 (0x09) >> 4) < 100)		/*
							 * Get current volume
							 */
3237 3238 3239 3240
	{
	  gus_voice_off ();
	  gus_rampoff ();
	  gus_voice_init (voice);
Linus Torvalds's avatar
Linus Torvalds committed
3241
	  break;
3242 3243
	}
      gus_ramp_range (65, 4065);
Linus Torvalds's avatar
Linus Torvalds committed
3244 3245
      gus_ramp_rate (0, 63);	/*
				 * Fastest possible rate
Linus Torvalds's avatar
Linus Torvalds committed
3246
				 */
Linus Torvalds's avatar
Linus Torvalds committed
3247 3248
      gus_rampon (0x20 | 0x40);	/*
				 * Ramp down, once, irq
Linus Torvalds's avatar
Linus Torvalds committed
3249
				 */
3250 3251 3252 3253
      voices[voice].volume_irq_mode = VMODE_HALT;
      break;

    case LMODE_PCM_STOP:
Linus Torvalds's avatar
Linus Torvalds committed
3254
      pcm_active = 0;		/* Signal to the play_next_pcm_block routine */
3255 3256
    case LMODE_PCM:
      {
Linus Torvalds's avatar
Linus Torvalds committed
3257
	int             flag;	/* 0 or 2 */
3258 3259 3260

	pcm_qlen--;
	pcm_head = (pcm_head + 1) % pcm_nblk;
Linus Torvalds's avatar
Linus Torvalds committed
3261
	if (pcm_qlen && pcm_active)
3262 3263 3264 3265
	  {
	    play_next_pcm_block ();
	  }
	else
Linus Torvalds's avatar
Linus Torvalds committed
3266
	  {			/* Underrun. Just stop the voice */
Linus Torvalds's avatar
Linus Torvalds committed
3267 3268 3269 3270
	    gus_select_voice (0);	/* Left channel */
	    gus_voice_off ();
	    gus_rampoff ();
	    gus_select_voice (1);	/* Right channel */
3271 3272 3273 3274 3275
	    gus_voice_off ();
	    gus_rampoff ();
	    pcm_active = 0;
	  }

Linus Torvalds's avatar
Linus Torvalds committed
3276 3277 3278 3279
	/*
	   * If the queue was full before this interrupt, the DMA transfer was
	   * suspended. Let it continue now.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
3280
	if (dma_active)
3281
	  {
Linus Torvalds's avatar
Linus Torvalds committed
3282 3283 3284 3285 3286
	    if (pcm_qlen == 0)
	      flag = 1;		/* Underflow */
	    else
	      flag = 0;
	    dma_active = 0;
3287
	  }
Linus Torvalds's avatar
Linus Torvalds committed
3288 3289 3290
	else
	  flag = 2;		/* Just notify the dmabuf.c */
	DMAbuf_outputintr (gus_devnum, flag);
3291 3292 3293 3294 3295
      }
      break;

    default:;
    }
Linus Torvalds's avatar
Linus Torvalds committed
3296
  restore_flags (flags);
3297 3298 3299 3300 3301 3302 3303 3304 3305
}

static void
do_volume_irq (int voice)
{
  unsigned char   tmp;
  int             mode, parm;
  unsigned long   flags;

Linus Torvalds's avatar
Linus Torvalds committed
3306 3307
  save_flags (flags);
  cli ();
3308 3309 3310 3311

  gus_select_voice (voice);

  tmp = gus_read8 (0x0d);
Linus Torvalds's avatar
Linus Torvalds committed
3312 3313
  tmp &= ~0x20;			/*
				 * Disable volume ramp IRQ
Linus Torvalds's avatar
Linus Torvalds committed
3314
				 */
3315 3316 3317 3318 3319 3320 3321 3322
  gus_write8 (0x0d, tmp);

  mode = voices[voice].volume_irq_mode;
  voices[voice].volume_irq_mode = 0;
  parm = voices[voice].volume_irq_parm;

  switch (mode)
    {
Linus Torvalds's avatar
Linus Torvalds committed
3323 3324
    case VMODE_HALT:		/*
				 * Decay phase finished
Linus Torvalds's avatar
Linus Torvalds committed
3325
				 */
Linus Torvalds's avatar
Linus Torvalds committed
3326
      restore_flags (flags);
3327 3328 3329 3330 3331
      gus_voice_init (voice);
      break;

    case VMODE_ENVELOPE:
      gus_rampoff ();
Linus Torvalds's avatar
Linus Torvalds committed
3332
      restore_flags (flags);
3333 3334 3335
      step_envelope (voice);
      break;

Linus Torvalds's avatar
Linus Torvalds committed
3336
    case VMODE_START_NOTE:
Linus Torvalds's avatar
Linus Torvalds committed
3337
      restore_flags (flags);
Linus Torvalds's avatar
Linus Torvalds committed
3338 3339 3340
      guswave_start_note2 (voices[voice].dev_pending, voice,
		  voices[voice].note_pending, voices[voice].volume_pending);
      if (voices[voice].kill_pending)
Linus Torvalds's avatar
Linus Torvalds committed
3341 3342 3343
	guswave_kill_note (voices[voice].dev_pending, voice,
			   voices[voice].note_pending, 0);

Linus Torvalds's avatar
Linus Torvalds committed
3344
      if (voices[voice].sample_pending >= 0)
Linus Torvalds's avatar
Linus Torvalds committed
3345 3346 3347 3348 3349
	{
	  guswave_set_instr (voices[voice].dev_pending, voice,
			     voices[voice].sample_pending);
	  voices[voice].sample_pending = -1;
	}
Linus Torvalds's avatar
Linus Torvalds committed
3350 3351
      break;

3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365
    default:;
    }
}

void
gus_voice_irq (void)
{
  unsigned long   wave_ignore = 0, volume_ignore = 0;
  unsigned long   voice_bit;

  unsigned char   src, voice;

  while (1)
    {
Linus Torvalds's avatar
Linus Torvalds committed
3366 3367
      src = gus_read8 (0x0f);	/*
				 * Get source info
Linus Torvalds's avatar
Linus Torvalds committed
3368
				 */
3369 3370 3371 3372
      voice = src & 0x1f;
      src &= 0xc0;

      if (src == (0x80 | 0x40))
Linus Torvalds's avatar
Linus Torvalds committed
3373 3374
	return;			/*
				 * No interrupt
Linus Torvalds's avatar
Linus Torvalds committed
3375
				 */
3376 3377 3378

      voice_bit = 1 << voice;

Linus Torvalds's avatar
Linus Torvalds committed
3379 3380
      if (!(src & 0x80))	/*
				 * Wave IRQ pending
Linus Torvalds's avatar
Linus Torvalds committed
3381
				 */
Linus Torvalds's avatar
Linus Torvalds committed
3382
	if (!(wave_ignore & voice_bit) && (int) voice < nr_voices)	/*
Linus Torvalds's avatar
Linus Torvalds committed
3383 3384 3385
									   * Not done
									   * yet
									 */
3386 3387 3388 3389 3390
	  {
	    wave_ignore |= voice_bit;
	    do_loop_irq (voice);
	  }

Linus Torvalds's avatar
Linus Torvalds committed
3391 3392
      if (!(src & 0x40))	/*
				 * Volume IRQ pending
Linus Torvalds's avatar
Linus Torvalds committed
3393
				 */
Linus Torvalds's avatar
Linus Torvalds committed
3394
	if (!(volume_ignore & voice_bit) && (int) voice < nr_voices)	/*
Linus Torvalds's avatar
Linus Torvalds committed
3395 3396 3397
									   * Not done
									   * yet
									 */
3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409
	  {
	    volume_ignore |= voice_bit;
	    do_volume_irq (voice);
	  }
    }
}

void
guswave_dma_irq (void)
{
  unsigned char   status;

Linus Torvalds's avatar
Linus Torvalds committed
3410 3411
  status = gus_look8 (0x41);	/* Get DMA IRQ Status */
  if (status & 0x40)		/* DMA interrupt pending */
3412 3413 3414
    switch (active_device)
      {
      case GUS_DEV_WAVE:
Linus Torvalds's avatar
Linus Torvalds committed
3415 3416 3417
	if ((dram_sleep_flag.mode & WK_SLEEP))
	  {
	    dram_sleep_flag.mode = WK_WAKEUP;
Linus Torvalds's avatar
Linus Torvalds committed
3418
	    module_wake_up (&dram_sleeper);
Linus Torvalds's avatar
Linus Torvalds committed
3419
	  };
3420 3421
	break;

Linus Torvalds's avatar
Linus Torvalds committed
3422
      case GUS_DEV_PCM_CONTINUE:	/* Left channel data transferred */
3423 3424 3425 3426 3427
	gus_transfer_output_block (pcm_current_dev, pcm_current_buf,
				   pcm_current_count,
				   pcm_current_intrflag, 1);
	break;

Linus Torvalds's avatar
Linus Torvalds committed
3428
      case GUS_DEV_PCM_DONE:	/* Right or mono channel data transferred */
3429 3430
	if (pcm_qlen < pcm_nblk)
	  {
Linus Torvalds's avatar
Linus Torvalds committed
3431 3432 3433 3434 3435
	    int             flag = (1 - dma_active) * 2;	/* 0 or 2 */

	    if (pcm_qlen == 0)
	      flag = 1;		/* Underrun */
	    dma_active = 0;
Linus Torvalds's avatar
Linus Torvalds committed
3436 3437
	    if (gus_busy)
	      DMAbuf_outputintr (gus_devnum, flag);
3438 3439 3440 3441 3442 3443
	  }
	break;

      default:;
      }

Linus Torvalds's avatar
Linus Torvalds committed
3444 3445
  status = gus_look8 (0x49);	/*
				 * Get Sampling IRQ Status
Linus Torvalds's avatar
Linus Torvalds committed
3446
				 */
Linus Torvalds's avatar
Linus Torvalds committed
3447 3448
  if (status & 0x40)		/*
				 * Sampling Irq pending
Linus Torvalds's avatar
Linus Torvalds committed
3449
				 */
3450 3451 3452 3453 3454 3455
    {
      DMAbuf_inputintr (gus_devnum);
    }

}

Linus Torvalds's avatar
Linus Torvalds committed
3456
#ifdef CONFIG_SEQUENCER
Linus Torvalds's avatar
Linus Torvalds committed
3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498
/*
 * Timer stuff
 */

static volatile int select_addr, data_addr;
static volatile int curr_timer = 0;

void
gus_timer_command (unsigned int addr, unsigned int val)
{
  int             i;

  outb ((unsigned char) (addr & 0xff), select_addr);

  for (i = 0; i < 2; i++)
    inb (select_addr);

  outb ((unsigned char) (val & 0xff), data_addr);

  for (i = 0; i < 2; i++)
    inb (select_addr);
}

static void
arm_timer (int timer, unsigned int interval)
{

  curr_timer = timer;

  if (timer == 1)
    {
      gus_write8 (0x46, 256 - interval);	/* Set counter for timer 1 */
      gus_write8 (0x45, 0x04);	/* Enable timer 1 IRQ */
      gus_timer_command (0x04, 0x01);	/* Start timer 1 */
    }
  else
    {
      gus_write8 (0x47, 256 - interval);	/* Set counter for timer 2 */
      gus_write8 (0x45, 0x08);	/* Enable timer 2 IRQ */
      gus_timer_command (0x04, 0x02);	/* Start timer 2 */
    }

Linus Torvalds's avatar
Linus Torvalds committed
3499
  gus_timer_enabled = 1;
Linus Torvalds's avatar
Linus Torvalds committed
3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539
}

static unsigned int
gus_tmr_start (int dev, unsigned int usecs_per_tick)
{
  int             timer_no, resolution;
  int             divisor;

  if (usecs_per_tick > (256 * 80))
    {
      timer_no = 2;
      resolution = 320;		/* usec */
    }
  else
    {
      timer_no = 1;
      resolution = 80;		/* usec */
    }

  divisor = (usecs_per_tick + (resolution / 2)) / resolution;

  arm_timer (timer_no, divisor);

  return divisor * resolution;
}

static void
gus_tmr_disable (int dev)
{
  gus_write8 (0x45, 0);		/* Disable both timers */
  gus_timer_enabled = 0;
}

static void
gus_tmr_restart (int dev)
{
  if (curr_timer == 1)
    gus_write8 (0x45, 0x04);	/* Start timer 1 again */
  else
    gus_write8 (0x45, 0x08);	/* Start timer 2 again */
Linus Torvalds's avatar
Linus Torvalds committed
3540
  gus_timer_enabled = 1;
Linus Torvalds's avatar
Linus Torvalds committed
3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553
}

static struct sound_lowlev_timer gus_tmr =
{
  0,
  gus_tmr_start,
  gus_tmr_disable,
  gus_tmr_restart
};

static void
gus_tmr_install (int io_base)
{
Linus Torvalds's avatar
Linus Torvalds committed
3554 3555
  struct sound_lowlev_timer *tmr;

Linus Torvalds's avatar
Linus Torvalds committed
3556 3557 3558
  select_addr = io_base;
  data_addr = io_base + 1;

Linus Torvalds's avatar
Linus Torvalds committed
3559 3560 3561
  tmr = &gus_tmr;

#ifdef THIS_GETS_FIXED
Linus Torvalds's avatar
Linus Torvalds committed
3562
  sound_timer_init (&gus_tmr, "GUS");
Linus Torvalds's avatar
Linus Torvalds committed
3563
#endif
Linus Torvalds's avatar
Linus Torvalds committed
3564 3565 3566
}
#endif

3567
#endif